diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.C
index 7a3152b494e0c0824e1ae7576f3edff7c6ed947e..0438fa276d330d60e92368e907f317adc2e59947 100644
--- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.C
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.C
@@ -223,10 +223,10 @@ Foam::autoHexMeshDriver::autoHexMeshDriver
             (
                 IOobject
                 (
-                    "abc",                      // dummy name
-                    mesh_.time().timeName(),    // directory
-                    "triSurface",               // instance
-                    mesh_.time(),               // registry
+                    "abc",                                      // dummy name
+                    mesh_.time().findInstance("triSurface", word::null),// inst
+                    "triSurface",                               // local
+                    mesh_.time(),                               // registry
                     IOobject::MUST_READ,
                     IOobject::NO_WRITE
                 ),
diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C
index e53c4e041a9b204b259ce65f53acfd32a5e345c1..e891cf761c7e452fa5003016cb4d92b868312997 100644
--- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C
@@ -77,10 +77,11 @@ Foam::label Foam::autoRefineDriver::readFeatureEdges
             (
                 IOobject
                 (
-                    featFileName,           // name
-                    mesh.time().constant(), // directory
-                    "triSurface",           // instance
-                    mesh.time(),            // registry
+                    featFileName,                       // name
+                    mesh.time().findInstance("triSurface", featFileName),
+                                                        // instance
+                    "triSurface",                       // local
+                    mesh.time(),                        // registry
                     IOobject::MUST_READ,
                     IOobject::NO_WRITE,
                     false
diff --git a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C
index 2566a66e219e0656633fb64787fd5268bd15e468..a626103cd1af105355aee538164e09ed9250a102 100644
--- a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C
+++ b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C
@@ -522,8 +522,8 @@ void Foam::refinementSurfaces::setMinLevelFields
                     IOobject
                     (
                         "minLevel",
-                        triMesh.objectRegistry::time().constant(),// directory
-                        "triSurface",               // instance
+                        triMesh.objectRegistry::time().timeName(),  // instance
+                        "triSurface",                               // local
                         triMesh,
                         IOobject::NO_READ,
                         IOobject::AUTO_WRITE
diff --git a/src/meshTools/Make/options b/src/meshTools/Make/options
index ef1033b0e8e02532fad69152efae5ae8342f046a..d550c78e4c260fc31774360f5c72203ff1da6969 100644
--- a/src/meshTools/Make/options
+++ b/src/meshTools/Make/options
@@ -1,7 +1,9 @@
 EXE_INC = \
     -I$(LIB_SRC)/triSurface/lnInclude \
+    -I$(LIB_SRC)/decompositionAgglomeration/decompositionMethods/lnInclude \
     -I$(LIB_SRC)/lagrangian/basic/lnInclude
 
 LIB_LIBS = \
     -ltriSurface \
+    -ldecompositionMethods \
     -llagrangian
diff --git a/src/meshTools/searchableSurface/distributedTriSurfaceMesh.C b/src/meshTools/searchableSurface/distributedTriSurfaceMesh.C
index 0f44333b6ee94313ac77d73f93a2597d4d6a9295..06020467036039319af49714caa501e7d74ae6b5 100644
--- a/src/meshTools/searchableSurface/distributedTriSurfaceMesh.C
+++ b/src/meshTools/searchableSurface/distributedTriSurfaceMesh.C
@@ -31,38 +31,56 @@ License
 #include "triangleFuncs.H"
 #include "matchPoints.H"
 #include "globalIndex.H"
-#include "PackedBoolList.H"
 #include "Time.H"
 
+#include "IFstream.H"
+#include "decompositionMethod.H"
+#include "vectorList.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
 namespace Foam
 {
-    defineTypeNameAndDebug(distributedTriSurfaceMesh, 0);
-    addToRunTimeSelectionTable
-    (
-        searchableSurface,
-        distributedTriSurfaceMesh,
-        dict
-    );
 
-    scalar distributedTriSurfaceMesh::mergeDist_ = SMALL;
+defineTypeNameAndDebug(distributedTriSurfaceMesh, 0);
+addToRunTimeSelectionTable(searchableSurface, distributedTriSurfaceMesh, dict);
+
 }
 
 
+template<>
+const char*
+Foam::NamedEnum<Foam::distributedTriSurfaceMesh::distributionType, 3>::names[] =
+{
+    "follow",
+    "independent",
+    "frozen"
+};
+
+const Foam::NamedEnum<Foam::distributedTriSurfaceMesh::distributionType, 3>
+    Foam::distributedTriSurfaceMesh::distributionTypeNames_;
+
+
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 // Read my additional data from the dictionary
 bool Foam::distributedTriSurfaceMesh::read()
 {
-    // Get bb of all domains
+    // Get bb of all domains.
     procBb_.setSize(Pstream::nProcs());
 
     procBb_[Pstream::myProcNo()] = List<treeBoundBox>(dict_.lookup("bounds"));
     Pstream::gatherList(procBb_);
     Pstream::scatterList(procBb_);
 
+    // Distribution type
+    distType_ = distributionTypeNames_.read(dict_.lookup("distributionType"));
+
+    if (dict_.found("mergeDistance"))
+    {
+        dict_.lookup("mergeDistance") >> mergeDist_;
+    }
+
     return true;
 }
 
@@ -86,7 +104,69 @@ bool Foam::distributedTriSurfaceMesh::isLocal
 }
 
 
-void Foam::distributedTriSurfaceMesh::splitSegment
+//void Foam::distributedTriSurfaceMesh::splitSegment
+//(
+//    const label segmentI,
+//    const point& start,
+//    const point& end,
+//    const treeBoundBox& bb,
+//
+//    DynamicList<segment>& allSegments,
+//    DynamicList<label>& allSegmentMap,
+//    DynamicList<label> sendMap
+//) const
+//{
+//    // Work points
+//    point clipPt0, clipPt1;
+//
+//    if (bb.contains(start))
+//    {
+//        // start within, trim end to bb
+//        bool clipped = bb.intersects(end, start, clipPt0);
+//
+//        if (clipped)
+//        {
+//            // segment from start to clippedStart passes
+//            // through proc.
+//            sendMap[procI].append(allSegments.size());
+//            allSegmentMap.append(segmentI);
+//            allSegments.append(segment(start, clipPt0));
+//        }
+//    }
+//    else if (bb.contains(end))
+//    {
+//        // end within, trim start to bb
+//        bool clipped = bb.intersects(start, end, clipPt0);
+//
+//        if (clipped)
+//        {
+//            sendMap[procI].append(allSegments.size());
+//            allSegmentMap.append(segmentI);
+//            allSegments.append(segment(clipPt0, end));
+//        }
+//    }
+//    else
+//    {
+//        // trim both
+//        bool clippedStart = bb.intersects(start, end, clipPt0);
+//
+//        if (clippedStart)
+//        {
+//            bool clippedEnd = bb.intersects(end, clipPt0, clipPt1);
+//
+//            if (clippedEnd)
+//            {
+//                // middle part of segment passes through proc.
+//                sendMap[procI].append(allSegments.size());
+//                allSegmentMap.append(segmentI);
+//                allSegments.append(segment(clipPt0, clipPt1));
+//            }
+//        }
+//    }
+//}
+
+
+void Foam::distributedTriSurfaceMesh::distributeSegment
 (
     const label segmentI,
     const point& start,
@@ -98,7 +178,7 @@ void Foam::distributedTriSurfaceMesh::splitSegment
 ) const
 {
     // Work points
-    point clipPt0, clipPt1;
+    point clipPt;
 
 
     // 1. Fully local already handled outside. Note: retest is cheap.
@@ -108,9 +188,9 @@ void Foam::distributedTriSurfaceMesh::splitSegment
     }
 
 
-    // 2. Check if fully inside other processor. Rare occurrence
+    // 2. If fully inside one other processor, then only need to send
+    // to that one processor even if it intersects another. Rare occurrence
     // but cheap to test.
-
     forAll(procBb_, procI)
     {
         if (procI != Pstream::myProcNo())
@@ -119,8 +199,6 @@ void Foam::distributedTriSurfaceMesh::splitSegment
 
             if (isLocal(bbs, start, end))
             {
-                //Pout<< "    Completely remote segment:"
-                //    << start << end << " on proc:" << procI << endl;
                 sendMap[procI].append(allSegments.size());
                 allSegmentMap.append(segmentI);
                 allSegments.append(segment(start, end));
@@ -130,7 +208,8 @@ void Foam::distributedTriSurfaceMesh::splitSegment
     }
 
 
-    // 3. Not contained in single processor. Clip against proc bbs.
+    // 3. If not contained in single processor send to all intersecting
+    // processors.
     forAll(procBb_, procI)
     {
         const List<treeBoundBox>& bbs = procBb_[procI];
@@ -139,67 +218,37 @@ void Foam::distributedTriSurfaceMesh::splitSegment
         {
             const treeBoundBox& bb = bbs[bbI];
 
-            if (bb.contains(start))
-            {
-                // start within, trim end to bb
-                bool clipped = bb.intersects(end, start, clipPt0);
+            // Scheme a: any processor that intersects the segment gets
+            // the segment.
 
-                if (clipped)
-                {
-                    //Pout<< "    Start of segment:"
-                    //    << start << end << " clips proc:" << procI
-                    //    << " at " << clipPt0 << endl;
-                    // segment from start to clippedStart passes
-                    // through proc.
-                    sendMap[procI].append(allSegments.size());
-                    allSegmentMap.append(segmentI);
-                    allSegments.append(segment(start, clipPt0));
-                }
-            }
-            else if (bb.contains(end))
+            if (bb.intersects(start, end, clipPt))
             {
-                // end within, trim start to bb
-                bool clipped = bb.intersects(start, end, clipPt0);
-
-                if (clipped)
-                {
-                    //Pout<< "    End of segment:"
-                    //    << start << end << " clips proc:" << procI
-                    //    << " at " << clipPt0 << endl;
-                    sendMap[procI].append(allSegments.size());
-                    allSegmentMap.append(segmentI);
-                    allSegments.append(segment(clipPt0, end));
-                }
+                sendMap[procI].append(allSegments.size());
+                allSegmentMap.append(segmentI);
+                allSegments.append(segment(start, end));
             }
-            else
-            {
-                // trim both
-                bool clippedStart = bb.intersects(start, end, clipPt0);
 
-                if (clippedStart)
-                {
-                    bool clippedEnd = bb.intersects(end, clipPt0, clipPt1);
-
-                    if (clippedEnd)
-                    {
-                        //Pout<< "    Middle of segment:"
-                        //    << start << end << " clips proc:" << procI
-                        //    << " at " << clipPt0 << clipPt1 << endl;
-                        // middle part of segment passes through
-                        // proc.
-                        sendMap[procI].append(allSegments.size());
-                        allSegmentMap.append(segmentI);
-                        allSegments.append(segment(clipPt0, clipPt1));
-                    }
-                }
-            }
+            // Alternative: any processor only gets clipped bit of
+            // segment. This gives small problems with additional
+            // truncation errors.
+            //splitSegment
+            //(
+            //    segmentI,
+            //    start,
+            //    end,
+            //    bb,
+            //
+            //    allSegments,
+            //    allSegmentMap,
+            //   sendMap[procI]
+            //);
         }
     }
 }
 
 
 Foam::autoPtr<Foam::mapDistribute>
-Foam::distributedTriSurfaceMesh::constructSegments
+Foam::distributedTriSurfaceMesh::distributeSegments
 (
     const pointField& start,
     const pointField& end,
@@ -227,7 +276,7 @@ Foam::distributedTriSurfaceMesh::constructSegments
 
         forAll(start, segmentI)
         {
-            splitSegment
+            distributeSegment
             (
                 segmentI,
                 start[segmentI],
@@ -243,11 +292,12 @@ Foam::distributedTriSurfaceMesh::constructSegments
         sendMap.setSize(Pstream::nProcs());
         forAll(sendMap, procI)
         {
+            dynSendMap[procI].shrink();
             sendMap[procI].transfer(dynSendMap[procI]);
         }
 
-        allSegments.transfer(dynAllSegments);
-        allSegmentMap.transfer(dynAllSegmentMap);
+        allSegments.transfer(dynAllSegments.shrink());
+        allSegmentMap.transfer(dynAllSegmentMap.shrink());
     }
 
 
@@ -371,7 +421,7 @@ void Foam::distributedTriSurfaceMesh::findLine
 
         const autoPtr<mapDistribute> mapPtr
         (
-            constructSegments
+            distributeSegments
             (
                 start,
                 end,
@@ -707,12 +757,13 @@ Foam::distributedTriSurfaceMesh::calcLocalQueries
         sendMap.setSize(Pstream::nProcs());
         forAll(sendMap, procI)
         {
+            dynSendMap[procI].shrink();
             sendMap[procI].transfer(dynSendMap[procI]);
         }
 
-        allCentres.transfer(dynAllCentres);
-        allRadiusSqr.transfer(dynAllRadiusSqr);
-        allSegmentMap.transfer(dynAllSegmentMap);
+        allCentres.transfer(dynAllCentres.shrink());
+        allRadiusSqr.transfer(dynAllRadiusSqr.shrink());
+        allSegmentMap.transfer(dynAllSegmentMap.shrink());
     }
 
 
@@ -766,6 +817,102 @@ Foam::distributedTriSurfaceMesh::calcLocalQueries
 }
 
 
+// Find bounding boxes that guarantee a more or less uniform distribution
+// of triangles. Decomposition in here is only used to get the bounding
+// boxes, actual decomposition is done later on.
+// Returns a per processor a list of bounding boxes that most accurately
+// describe the shape. For now just a single bounding box per processor but
+// optimisation might be to determine a better fitting shape.
+Foam::List<Foam::List<Foam::treeBoundBox> >
+Foam::distributedTriSurfaceMesh::independentlyDistributedBbs
+(
+    const triSurface& s
+)
+{
+    if (!decomposer_.valid())
+    {
+        // Use current decomposer.
+        // Note: or always use hierarchical?
+        IOdictionary decomposeDict
+        (
+            IOobject
+            (
+                "decomposeParDict",
+                searchableSurface::time().system(),
+                searchableSurface::time(),
+                IOobject::MUST_READ,
+                IOobject::NO_WRITE,
+                false
+            )
+        );
+        decomposer_ = decompositionMethod::New(decomposeDict);
+
+        if (!decomposer_().parallelAware())
+        {
+            FatalErrorIn
+            (
+                "distributedTriSurfaceMesh::independentlyDistributedBbs"
+                "(const triSurface&)"
+            )   << "The decomposition method " << decomposer_().typeName
+                << " does not decompose in parallel."
+                << " Please choose one that does." << exit(FatalError);
+        }
+    }
+
+    // Do decomposition according to triangle centre
+    pointField triCentres(s.size());
+    forAll (s, triI)
+    {
+        triCentres[triI] = s[triI].centre(s.points());
+    }
+
+    // Do the actual decomposition
+    labelList distribution(decomposer_->decompose(triCentres));
+
+    // Find bounding box for all triangles on new distribution.
+
+    // Initialise to inverted box (VGREAT, -VGREAT)
+    List<List<treeBoundBox> > bbs(Pstream::nProcs());
+    forAll(bbs, procI)
+    {
+        bbs[procI].setSize(1);
+        //bbs[procI][0] = boundBox::invertedBox;
+        bbs[procI][0].min() = point( VGREAT,  VGREAT,  VGREAT);
+        bbs[procI][0].max() = point(-VGREAT, -VGREAT, -VGREAT); 
+    }
+
+    forAll (s, triI)
+    {
+        point& bbMin = bbs[distribution[triI]][0].min();
+        point& bbMax = bbs[distribution[triI]][0].max();
+
+        const labelledTri& f = s[triI];
+        const point& p0 = s.points()[f[0]];
+        const point& p1 = s.points()[f[1]];
+        const point& p2 = s.points()[f[2]];
+
+        bbMin = min(bbMin, p0);
+        bbMin = min(bbMin, p1);
+        bbMin = min(bbMin, p2);
+
+        bbMax = max(bbMax, p0);
+        bbMax = max(bbMax, p1);
+        bbMax = max(bbMax, p2);
+    }
+
+    // Now combine for all processors and convert to correct format.
+    forAll(bbs, procI)
+    {
+        forAll(bbs[procI], i)
+        {
+            reduce(bbs[procI][i].min(), minOp<point>());
+            reduce(bbs[procI][i].max(), maxOp<point>());
+        }
+    }
+    return bbs;
+}
+
+
 void Foam::distributedTriSurfaceMesh::calcBounds
 (
     boundBox& bb,
@@ -775,10 +922,12 @@ void Foam::distributedTriSurfaceMesh::calcBounds
     // Unfortunately nPoints constructs meshPoints() so do compact version
     // ourselves
 
-    PackedBoolList pointIsUsed(points().size());
+    PackedList<1> pointIsUsed(points().size());
+    pointIsUsed = 0U;
 
     nPoints = 0;
-    bb = boundBox::invertedBox;
+    bb.min() = point(VGREAT, VGREAT, VGREAT);
+    bb.max() = point(-VGREAT, -VGREAT, -VGREAT);
 
     const triSurface& s = static_cast<const triSurface&>(*this);
 
@@ -1198,17 +1347,30 @@ Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh(const IOobject& io)
 :
     triSurfaceMesh(io),
+//    triSurfaceMesh
+//    (
+//        IOobject
+//        (
+//            io.name(),
+//            io.db().time().findInstanceDir(io.local()),
+//            io.local(),
+//            io.db(),
+//            io.readOpt(),
+//            io.writeOpt(),
+//            io.registerObject()
+//        )
+//    ),
     dict_
     (
         IOobject
         (
-            io.name() + "Dict",
-            io.instance(),
-            io.local(),
-            io.db(),
-            io.readOpt(),
-            io.writeOpt(),
-            io.registerObject()
+            searchableSurface::name() + "Dict",
+            searchableSurface::instance(),
+            searchableSurface::local(),
+            searchableSurface::db(),
+            searchableSurface::readOpt(),
+            searchableSurface::writeOpt(),
+            searchableSurface::registerObject()
         )
     )
 {
@@ -1223,17 +1385,31 @@ Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
 )
 :
     triSurfaceMesh(io, dict),
+//    triSurfaceMesh
+//    (
+//        IOobject
+//        (
+//            io.name(),
+//            io.db().time().findInstanceDir(io.local()),
+//            io.local(),
+//            io.db(),
+//            io.readOpt(),
+//            io.writeOpt(),
+//            io.registerObject()
+//        ),
+//        dict
+//    ),
     dict_
     (
         IOobject
         (
-            io.name() + "Dict",
-            io.instance(),
-            io.local(),
-            io.db(),
-            io.readOpt(),
-            io.writeOpt(),
-            io.registerObject()
+            searchableSurface::name() + "Dict",
+            searchableSurface::instance(),
+            searchableSurface::local(),
+            searchableSurface::db(),
+            searchableSurface::readOpt(),
+            searchableSurface::writeOpt(),
+            searchableSurface::registerObject()
         )
     )
 {
@@ -1260,7 +1436,7 @@ void Foam::distributedTriSurfaceMesh::clearOut()
 
 const Foam::globalIndex& Foam::distributedTriSurfaceMesh::globalTris() const
 {
-    if (globalTris_.empty())
+    if (!globalTris_.valid())
     {
         globalTris_.reset(new globalIndex(triSurface::size()));
     }
@@ -1855,6 +2031,18 @@ Foam::triSurface Foam::distributedTriSurfaceMesh::overlappingSurface
     // Determine what triangles to keep.
     boolList includedFace(s.size(), false);
 
+    // Create a slightly larger bounding box.
+    List<treeBoundBox> bbsX(bbs.size());
+    const scalar eps = 1.0e-4;
+    forAll(bbs, i)
+    {
+        const point mid = 0.5*(bbs[i].min() + bbs[i].max());
+        const vector halfSpan = (1.0+eps)*(bbs[i].max() - mid);
+
+        bbsX[i].min() = mid - halfSpan;
+        bbsX[i].max() = mid + halfSpan;
+    }
+
     forAll(s, triI)
     {
         const labelledTri& f = s[triI];
@@ -1862,7 +2050,7 @@ Foam::triSurface Foam::distributedTriSurfaceMesh::overlappingSurface
         const point& p1 = s.points()[f[1]];
         const point& p2 = s.points()[f[2]];
 
-        if (overlaps(bbs, p0, p1, p2))
+        if (overlaps(bbsX, p0, p1, p2))
         {
             includedFace[triI] = true;
         }
@@ -1880,17 +2068,37 @@ void Foam::distributedTriSurfaceMesh::distribute
     autoPtr<mapDistribute>& pointMap
 )
 {
-    // Get bb of all domains
+    // Get bbs of all domains
+    // ~~~~~~~~~~~~~~~~~~~~~~
+
     {
         List<List<treeBoundBox> > newProcBb(Pstream::nProcs());
-        newProcBb[Pstream::myProcNo()].setSize(bbs.size());
-        forAll(bbs, i)
+
+        switch(distType_)
         {
-            newProcBb[Pstream::myProcNo()][i] = bbs[i];
-        }
-        Pstream::gatherList(newProcBb);
-        Pstream::scatterList(newProcBb);
+            case FOLLOW:
+                newProcBb[Pstream::myProcNo()].setSize(bbs.size());
+                forAll(bbs, i)
+                {
+                    newProcBb[Pstream::myProcNo()][i] = bbs[i];
+                }
+                Pstream::gatherList(newProcBb);
+                Pstream::scatterList(newProcBb);
+            break;
 
+            case INDEPENDENT:
+                newProcBb = independentlyDistributedBbs(*this);
+            break;
+
+            case FROZEN:
+                return;
+            break;
+
+            default:
+                FatalErrorIn("distributedTriSurfaceMesh::distribute(..)")
+                    << "Unsupported distribution type." << exit(FatalError);
+            break;
+        }
 
         //if (debug)
         //{
@@ -1931,6 +2139,9 @@ void Foam::distributedTriSurfaceMesh::distribute
     }
 
 
+    // Use procBbs to determine which faces go where
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
     labelListList faceSendMap(Pstream::nProcs());
     labelListList pointSendMap(Pstream::nProcs());
 
diff --git a/src/meshTools/searchableSurface/distributedTriSurfaceMesh.H b/src/meshTools/searchableSurface/distributedTriSurfaceMesh.H
index e7b7b6fb2f1a10d7c450138a1816603418542d51..733cd24891e21befee9e9318fa301180bc3f8966 100644
--- a/src/meshTools/searchableSurface/distributedTriSurfaceMesh.H
+++ b/src/meshTools/searchableSurface/distributedTriSurfaceMesh.H
@@ -26,7 +26,20 @@ Class
     Foam::distributedTriSurfaceMesh
 
 Description
-    IOoject and searching on triSurface
+    IOoject and searching on distributed triSurface. All processor hold
+    (possibly overlapping) part of the overall surface. All queries are
+    distributed to the processor that can answer it and the result sent back.
+
+    Can work in three modes:
+    - follow : makes sure each processor has all the triangles inside the
+    externally provided bounding box (usually the mesh bounding box).
+    Guarantees minimum amount of communication since mesh-local queries
+    should be answerable without any comms.
+    - independent : surface is decomposed according to the triangle centres
+    so the decomposition might be radically different from the mesh
+    decomposition. Guarantees best memory balance but at the expense of
+    more communication.
+    - frozen : no change
 
 SourceFiles
     distributedTriSurfaceMesh.C
@@ -47,6 +60,7 @@ namespace Foam
 {
 
 class mapDistribute;
+class decompositionMethod;
 
 // Typedefs
 typedef Pair<point> segment;
@@ -62,12 +76,26 @@ class distributedTriSurfaceMesh
 :
     public triSurfaceMesh
 {
-private:
+public:
 
     // Static data
 
+        enum distributionType
+        {
+            FOLLOW = 0,
+            INDEPENDENT = 1,
+            FROZEN = 2
+        };
+
+        static const NamedEnum<distributionType, 3> distributionTypeNames_;
+
+private:
+
         //- Merging distance
-        static scalar mergeDist_;
+        scalar mergeDist_;
+
+        //- Decomposition used when independently decomposing surface.
+        autoPtr<decompositionMethod> decomposer_;
 
 
     // Private member data
@@ -81,6 +109,9 @@ private:
         //- Global triangle numbering
         mutable autoPtr<globalIndex> globalTris_;
 
+        //- The distribution type.
+        distributionType distType_;
+
 
     // Private Member Functions
 
@@ -100,8 +131,22 @@ private:
             );
 
             //- Split segment into subsegments overlapping the processor
+            //  bounding box.
+            //void Foam::distributedTriSurfaceMesh::splitSegment
+            //(
+            //    const label segmentI,
+            //    const point& start,
+            //    const point& end,
+            //    const treeBoundBox& bb,
+            //
+            //    DynamicList<segment>& allSegments,
+            //    DynamicList<label>& allSegmentMap,
+            //    DynamicList<label> sendMap
+            //) const
+
+            //- Distribute segments into overlapping processor
             //  bounding boxes. Sort per processor.
-            void splitSegment
+            void distributeSegment
             (
                 const label,
                 const point& start,
@@ -114,7 +159,7 @@ private:
 
             //- Divide edges into local and remote segments. Construct map to
             //  distribute and collect data.
-            autoPtr<mapDistribute> constructSegments
+            autoPtr<mapDistribute> distributeSegments
             (
                 const pointField& start,
                 const pointField& end,
@@ -167,6 +212,12 @@ private:
 
         // Surface redistribution
 
+            //- Finds new bounds based on an indepedent decomposition.
+            List<List<treeBoundBox> > independentlyDistributedBbs
+            (
+                const triSurface&
+            );
+
             //- Calculate surface bounding box
             void calcBounds(boundBox& bb, label& nPoints) const;
 
@@ -287,32 +338,6 @@ public:
 
     // Member Functions
 
-        //- Return merge distance
-        static scalar mergeDist()
-        {
-            return mergeDist_;
-        }
-
-        //- Set the merge distance, returning the previous value
-        static scalar setMergeDist(const scalar t)
-        {
-            if (t < -VSMALL)
-            {
-                FatalErrorIn
-                (
-                    "scalar distributedTriSurfaceMesh::setMergeDist"
-                    "(const scalar t)"
-                )   << "Negative merge distance tolerance. This is not allowed."
-                    << abort(FatalError);
-            }
-
-            scalar oldTol = mergeDist_;
-            mergeDist_ = t;
-
-            return oldTol;
-        }
-
-
         //- Triangle indexing (demand driven)
         const globalIndex& globalTris() const;
 
diff --git a/src/meshTools/searchableSurface/searchableSurfaces.C b/src/meshTools/searchableSurface/searchableSurfaces.C
index 70cdbe5465e042774e3f1693ce0e0e782e07d1f7..46c968f15369b62c8f47abe05d5fcad7eb8449cd 100644
--- a/src/meshTools/searchableSurface/searchableSurfaces.C
+++ b/src/meshTools/searchableSurface/searchableSurfaces.C
@@ -27,6 +27,7 @@ License
 #include "searchableSurfaces.H"
 #include "searchableSurfacesQueries.H"
 #include "ListOps.H"
+#include "Time.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -186,6 +187,14 @@ Foam::searchableSurfaces::searchableSurfaces
         // their object name. Maybe have stlTriSurfaceMesh which appends .stl
         // when reading/writing?
         namedIO().rename(key);  // names_[surfI]
+        if (namedIO().local() != word::null)
+        {
+            namedIO().instance() = namedIO().time().findInstance
+            (
+                namedIO().local(),
+                namedIO().name()
+            );
+        }
 
         // Create and hook surface
         set