diff --git a/src/autoMesh/Make/files b/src/autoMesh/Make/files
index c562ee5c6de5bbb273ba95decce1e88dc70eda2e..1c763a316c9c8148ab2bca1b887b9646121d53ae 100644
--- a/src/autoMesh/Make/files
+++ b/src/autoMesh/Make/files
@@ -1,15 +1,21 @@
 autoHexMesh             = autoHexMesh
+autoHexMeshDriver       = $(autoHexMesh)/autoHexMeshDriver
+
+$(autoHexMeshDriver)/autoHexMeshDriver.C
+$(autoHexMeshDriver)/autoHexMeshDriverLayers.C
+$(autoHexMeshDriver)/autoHexMeshDriverShrink.C
+$(autoHexMeshDriver)/autoHexMeshDriverSnap.C
+$(autoHexMeshDriver)/layerParameters/layerParameters.C
+$(autoHexMeshDriver)/refinementParameters/refinementParameters.C
+$(autoHexMeshDriver)/snapParameters/snapParameters.C
+$(autoHexMeshDriver)/pointData/pointData.C
 
-$(autoHexMesh)/autoHexMeshDriver/autoHexMeshDriver.C
-$(autoHexMesh)/autoHexMeshDriver/autoHexMeshDriverLayers.C
-$(autoHexMesh)/autoHexMeshDriver/autoHexMeshDriverShrink.C
-$(autoHexMesh)/autoHexMeshDriver/autoHexMeshDriverSnap.C
-$(autoHexMesh)/autoHexMeshDriver/pointData/pointData.C
 $(autoHexMesh)/meshRefinement/meshRefinementBaffles.C
 $(autoHexMesh)/meshRefinement/meshRefinement.C
 $(autoHexMesh)/meshRefinement/meshRefinementMerge.C
 $(autoHexMesh)/meshRefinement/meshRefinementRefine.C
 $(autoHexMesh)/refinementSurfaces/refinementSurfaces.C
+$(autoHexMesh)/shellSurfaces/shellSurfaces.C
 $(autoHexMesh)/trackedParticle/trackedParticle.C
 $(autoHexMesh)/trackedParticle/trackedParticleCloud.C
 
diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.C
index a15b4220324da337c72f24b4003735a255f20ede..94c217ebcc94f0997cff83626c1ec2aa81dd9f40 100644
--- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.C
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.C
@@ -35,6 +35,9 @@ License
 #include "syncTools.H"
 #include "motionSmoother.H"
 #include "pointMesh.H"
+#include "refinementParameters.H"
+#include "snapParameters.H"
+#include "layerParameters.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -60,7 +63,8 @@ Foam::scalar Foam::autoHexMeshDriver::getMergeDistance(const scalar mergeTol)
        -scalar(IOstream::defaultPrecision())
     );
 
-    Info<< "Overall mesh bounding box  : " << meshBb << nl
+    Info<< nl
+        << "Overall mesh bounding box  : " << meshBb << nl
         << "Relative tolerance         : " << mergeTol << nl
         << "Absolute matching distance : " << mergeDist << nl
         << endl;
@@ -82,110 +86,59 @@ Foam::scalar Foam::autoHexMeshDriver::getMergeDistance(const scalar mergeTol)
 }
 
 
-// Return per keeppoint -1 or the local cell label the point is in. Guaranteed
-// to be only on one processor.
-Foam::labelList Foam::autoHexMeshDriver::findCells(const pointField& keepPoints)
- const
-{
-    // Global calculation engine
-    globalIndex globalCells(mesh_.nCells());
-
-    // Cell label per point
-    labelList cellLabels(keepPoints.size());
-
-    forAll(keepPoints, i)
-    {
-        const point& keepPoint = keepPoints[i];
-
-        label localCellI = mesh_.findCell(keepPoint);
-
-        label globalCellI = -1;
-
-        if (localCellI != -1)
-        {
-            Pout<< "Found point " << keepPoint << " in cell " << localCellI
-                << " on processor " << Pstream::myProcNo() << endl;
-            globalCellI = globalCells.toGlobal(localCellI);
-        }
-
-        reduce(globalCellI, maxOp<label>());
-
-        if (globalCellI == -1)
-        {
-            FatalErrorIn
-            (
-                "autoHexMeshDriver::findCells(const pointField&) const"
-            )   << "Point " << keepPoint << " is not inside the mesh." << nl
-                << "Bounding box of the mesh:" << mesh_.bounds()
-                << exit(FatalError);
-        }
-
-        if (globalCells.isLocal(globalCellI))
-        {
-            cellLabels[i] = localCellI;
-        }
-        else
-        {
-            cellLabels[i] = -1;
-        }
-    }
-    return cellLabels;
-}
-
-
-// Specifically orient using a calculated point outside
-void Foam::autoHexMeshDriver::orientOutside(PtrList<searchableSurface>& shells)
-{
-    // Determine outside point.
-    boundBox overallBb
-    (
-        point(GREAT, GREAT, GREAT),
-        point(-GREAT, -GREAT, -GREAT)
-    );
-
-    bool hasSurface = false;
-
-    forAll(shells, shellI)
-    {
-        if (isA<triSurfaceMesh>(shells[shellI]))
-        {
-            const triSurfaceMesh& shell =
-                refCast<const triSurfaceMesh>(shells[shellI]);
-
-            hasSurface = true;
-
-            boundBox shellBb(shell.localPoints(), false);
-
-            overallBb.min() = min(overallBb.min(), shellBb.min());
-            overallBb.max() = max(overallBb.max(), shellBb.max());
-        }
-    }
-
-    if (hasSurface)
-    {
-        const point outsidePt(2*overallBb.max() - overallBb.min());
-
-        //Info<< "Using point " << outsidePt << " to orient shells" << endl;
-
-        forAll(shells, shellI)
-        {
-            if (isA<triSurfaceMesh>(shells[shellI]))
-            {
-                triSurfaceMesh& shell = refCast<triSurfaceMesh>(shells[shellI]);
-
-                if (!refinementSurfaces::isSurfaceClosed(shell))
-                {
-                    FatalErrorIn("orientOutside(PtrList<searchableSurface>&)")
-                        << "Refinement shell "
-                        << shell.searchableSurface::name()
-                        << " is not closed." << exit(FatalError);
-                }
-
-                refinementSurfaces::orientSurface(outsidePt, shell);
-            }
-        }
-    }
-}
+//// Specifically orient using a calculated point outside
+//void Foam::autoHexMeshDriver::orientOutside(PtrList<searchableSurface>& shells)
+//{
+//    // Determine outside point.
+//    boundBox overallBb
+//    (
+//        point(GREAT, GREAT, GREAT),
+//        point(-GREAT, -GREAT, -GREAT)
+//    );
+//
+//    bool hasSurface = false;
+//
+//    forAll(shells, shellI)
+//    {
+//        if (isA<triSurfaceMesh>(shells[shellI]))
+//        {
+//            const triSurfaceMesh& shell =
+//                refCast<const triSurfaceMesh>(shells[shellI]);
+//
+//            hasSurface = true;
+//
+//            boundBox shellBb(shell.localPoints(), false);
+//
+//            overallBb.min() = min(overallBb.min(), shellBb.min());
+//            overallBb.max() = max(overallBb.max(), shellBb.max());
+//        }
+//    }
+//
+//    if (hasSurface)
+//    {
+//        const point outsidePt(2*overallBb.max() - overallBb.min());
+//
+//        //Info<< "Using point " << outsidePt << " to orient shells" << endl;
+//
+//        forAll(shells, shellI)
+//        {
+//            if (isA<triSurfaceMesh>(shells[shellI]))
+//            {
+//                triSurfaceMesh& shell = refCast<triSurfaceMesh>(shells[shellI]);
+//
+//                if (!refinementSurfaces::isSurfaceClosed(shell))
+//                {
+//                    FatalErrorIn("orientOutside(PtrList<searchableSurface>&)")
+//                        << "Refinement shell "
+//                        << shell.searchableSurface::name()
+//                        << " is not closed." << exit(FatalError);
+//                }
+//
+//                refinementSurfaces::orientSurface(outsidePt, shell);
+//            }
+//        }
+//    }
+//}
 
 
 // Check that face zones are synced
@@ -286,324 +239,394 @@ void Foam::autoHexMeshDriver::checkCoupledFaceZones() const
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-// Construct from components
-Foam::autoHexMeshDriver::autoHexMeshDriver
-(
-    fvMesh& mesh,
-    const dictionary& dict,
-    const dictionary& decomposeDict
-)
-:
-    mesh_(mesh),
-    dict_(dict),
-    debug_(readLabel(dict_.lookup("debug"))),
-    maxGlobalCells_(readLabel(dict_.lookup("cellLimit"))),
-    maxLocalCells_(readLabel(dict_.lookup("procCellLimit"))),
-    minRefineCells_(readLabel(dict_.lookup("minimumRefine"))),
-    curvature_(readScalar(dict_.lookup("curvature"))),
-    nBufferLayers_(readLabel(dict_.lookup("nBufferLayers"))),
-    keepPoints_(dict_.lookup("keepPoints")),
-    mergeDist_(getMergeDistance(readScalar(dict_.lookup("mergeTolerance"))))
-{
-    if (debug_ > 0)
-    {
-        meshRefinement::debug = debug_;
-        autoHexMeshDriver::debug = debug_;
-    }
-
-    Info<< "Overall cell limit                         : " << maxGlobalCells_
-        << endl;
-    Info<< "Per processor cell limit                   : " << maxLocalCells_
-        << endl;
-    Info<< "Minimum number of cells to refine          : " << minRefineCells_
-        << endl;
-    Info<< "Curvature                                  : " << curvature_
-        << nl << endl;
-    Info<< "Layers between different refinement levels : " << nBufferLayers_
-        << endl;
-
-    // Check keepPoints are sensible
-    findCells(keepPoints_);
-
-
-    // Read refinement shells
-    // ~~~~~~~~~~~~~~~~~~~~~~
-
-    {
-        Info<< "Reading refinement shells." << endl;
-
-        PtrList<dictionary> shellDicts(dict_.lookup("refinementShells"));
-
-        shells_.setSize(shellDicts.size());
-        shellLevels_.setSize(shellDicts.size());
-        shellRefineInside_.setSize(shellDicts.size());
-
-        forAll(shellDicts, i)
-        {
-            const dictionary& dict = shellDicts[i];
-
-            shells_.set
-            (
-                i,
-                searchableSurface::New
-                (
-                    dict.lookup("type"),
-                    dict.lookup("name"),
-                    mesh_.time(),
-                    dict
-                )
-            );
-            shellLevels_[i] = readLabel(dict.lookup("level"));
-            shellRefineInside_[i] = Switch(dict.lookup("refineInside"));
-
-            if (shellRefineInside_[i])
-            {
-                Info<< "Refinement level " << shellLevels_[i]
-                    << " for all cells inside " << shells_[i].name() << endl;
-            }
-            else
-            {
-                Info<< "Refinement level " << shellLevels_[i]
-                    << " for all cells outside " << shells_[i].name() << endl;
-            }
-        }
-
-        Info<< "Read refinement shells in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
-
-        // Orient shell surfaces before any searching is done.
-        Info<< "Orienting triSurface shells so point far away is outside."
-            << endl;
-        orientOutside(shells_);
-        Info<< "Oriented shells in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
-    }
-
-
-    // Read refinement surfaces
-    // ~~~~~~~~~~~~~~~~~~~~~~~~
-
-    {
-        Info<< "Reading surfaces and constructing search trees." << endl;
-
-        surfacesPtr_.reset
-        (
-            new refinementSurfaces
-            (
-                IOobject
-                (
-                    "",                                 // dummy name
-                    mesh_.time().constant(),            // directory
-                    "triSurface",                       // instance
-                    mesh_.time(),                       // registry
-                    IOobject::MUST_READ,
-                    IOobject::NO_WRITE
-                ),
-                dict_.lookup("surfaces")
-            )
-        );
-        Info<< "Read surfaces in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
-
-        // Orient surfaces (if they're closed) before any searching is done.
-        Info<< "Orienting (closed) surfaces so keepPoint is outside." << endl;
-        forAll(surfaces(), i)
-        {
-            if (refinementSurfaces::isSurfaceClosed(surfaces()[i]))
-            {
-                refinementSurfaces::orientSurface
-                (
-                    keepPoints_[0],
-                    surfacesPtr_()[i]
-                );
-            }
-        }
-        Info<< "Oriented closed surfaces in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
-
-        Info<< "Setting refinement level of surface to be consistent"
-            << " with shells." << endl;
-        surfacesPtr_().setMinLevelFields
-        (
-            shells_,
-            shellLevels_,
-            shellRefineInside_
-        );
-        Info<< "Checked shell refinement in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
-    }
-
-    // Check faceZones are synchronised
-    checkCoupledFaceZones();
-
-
-    // Add all the surface regions as patches
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    {
-        Info<< nl
-            << "Adding patches for surface regions" << nl
-            << "----------------------------------" << nl
-            << endl;
-
-        // From global region number to mesh patch.
-        globalToPatch_.setSize(surfaces().nRegions(), -1);
-
-        Info<< "Patch\tRegion" << nl
-            << "-----\t------"
-            << endl;
-
-        forAll(surfaces(), surfI)
-        {
-            const triSurfaceMesh& s = surfaces()[surfI];
-
-            Info<< surfaces().names()[surfI] << ':' << nl << nl;
-
-            const geometricSurfacePatchList& regions = s.patches();
-
-            labelList nTrisPerRegion(surfaces().countRegions(s));
-
-            forAll(regions, i)
-            {
-                if (nTrisPerRegion[i] > 0)
-                {
-                    label globalRegionI = surfaces().globalRegion(surfI, i);
-
-                    // Use optionally specified patch type and name
-                    word patchType = surfaces().patchType()[globalRegionI];
-                    if (patchType == "")
-                    {
-                        patchType = wallPolyPatch::typeName;
-                    }
-
-                    word patchName = surfaces().patchName()[globalRegionI];
-                    if (patchName == "")
-                    {
-                        patchName =
-                            surfaces().names()[surfI]
-                          + '_'
-                          + regions[i].name();
-                    }
-
-                    label patchI = meshRefinement::addPatch
-                    (
-                        mesh,
-                        patchName,
-                        patchType
-                    );
-
-                    Info<< patchI << '\t' << regions[i].name() << nl;
-
-                    globalToPatch_[globalRegionI] = patchI;
-                }
-            }
-
-            Info<< nl;
-        }
-        Info<< "Added patches in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
-    }
-
-
-    //// Add cyclics for any named faceZones
-    //// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    //// (these cyclics are used later on to temporarily put the faceZones
-    ////  in when snapping)
-    //
-    //labelList namedSurfaces(surfaces().getNamedSurfaces());
-    //if (namedSurfaces.size() > 0)
-    //{
-    //    Info<< nl
-    //        << "Introducing cyclics for faceZones" << nl
-    //        << "---------------------------------" << nl
-    //        << endl;
-    //
-    //    // From surface to cyclic patch
-    //    surfaceToCyclicPatch_.setSize(surfaces().size(), -1);
-    //
-    //    Info<< "Patch\tZone" << nl
-    //        << "----\t-----"
-    //        << endl;
-    //
-    //    forAll(namedSurfaces, i)
-    //    {
-    //        label surfI = namedSurfaces[i];
-    //
-    //        surfaceToCyclicPatch_[surfI] = meshRefinement::addPatch
-    //        (
-    //            mesh,
-    //            surfaces().faceZoneNames()[surfI],
-    //            cyclicPolyPatch::typeName
-    //        );
-    //
-    //        Info<< surfaceToCyclicPatch_[surfI] << '\t'
-    //            << surfaces().faceZoneNames()[surfI] << nl << endl;
-    //    }
-    //    Info<< "Added cyclic patches in = "
-    //        << mesh_.time().cpuTimeIncrement() << " s" << endl;
-    //}
-
-
-    // Parallel
-    // ~~~~~~~~
-
-    {
-        // Decomposition
-        decomposerPtr_ = decompositionMethod::New
-        (
-            decomposeDict,
-            mesh_
-        );
-        decompositionMethod& decomposer = decomposerPtr_();
-
-
-        if (Pstream::parRun() && !decomposer.parallelAware())
-        {
-            FatalErrorIn("autoHexMeshDriver::autoHexMeshDriver(const IOobject&, fvMesh&)")
-                << "You have selected decomposition method "
-                << decomposer.typeName
-                << " which is not parallel aware." << endl
-                << "Please select one that is (parMetis, hierarchical)"
-                << exit(FatalError);
-        }
-
-        // Mesh distribution engine (uses tolerance to reconstruct meshes)
-        distributorPtr_.reset(new fvMeshDistribute(mesh_, mergeDist_));
-    }
-
-
-    // Refinement engine
-    // ~~~~~~~~~~~~~~~~~
-
-    {
-        Info<< nl
-            << "Determining initial surface intersections" << nl
-            << "-----------------------------------------" << nl
-            << endl;
-
-        // Main refinement engine
-        meshRefinerPtr_.reset
-        (
-            new meshRefinement
-            (
-                mesh,
-                mergeDist_,         // tolerance used in sorting coordinates
-                surfaces()
-            )
-        );
-        Info<< "Calculated surface intersections in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
-
-        // Some stats
-        meshRefinerPtr_().printMeshInfo(debug_, "Initial mesh");
-
-        meshRefinerPtr_().write
-        (
-            debug_&meshRefinement::OBJINTERSECTIONS,
-            mesh_.time().path()/mesh_.time().timeName()
-        );
-    }
-}
+//// Construct from components
+//Foam::autoHexMeshDriver::autoHexMeshDriver
+//(
+//    fvMesh& mesh,
+//    const dictionary& dict,
+//    const dictionary& decomposeDict
+//)
+//:
+//    mesh_(mesh),
+//    dict_(dict),
+//    debug_(readLabel(dict_.lookup("debug"))),
+//    mergeDist_(getMergeDistance(readScalar(dict_.lookup("mergeTolerance"))))
+//{
+//    if (debug_ > 0)
+//    {
+//        meshRefinement::debug = debug_;
+//        autoHexMeshDriver::debug = debug_;
+//    }
+//
+//    refinementParameters refineParams(dict);
+//
+//    Info<< "Overall cell limit                         : "
+//        << refineParams.maxGlobalCells() << endl;
+//    Info<< "Per processor cell limit                   : "
+//        << refineParams.maxLocalCells() << endl;
+//    Info<< "Minimum number of cells to refine          : "
+//        << refineParams.minRefineCells() << endl;
+//    Info<< "Curvature                                  : "
+//        << refineParams.curvature() << nl << endl;
+//    Info<< "Layers between different refinement levels : "
+//        << refineParams.nBufferLayers() << endl;
+//
+////XXXXX
+//    PtrList<dictionary> shellsDict(dict_.lookup("refinementShells"));
+//
+//    PtrList<dictionary> surfacesDict(dict_.lookup("surfaces"));
+//
+//
+//    // Read geometry
+//    // ~~~~~~~~~~~~~
+//
+//    {
+//        Info<< "Reading all geometry." << endl;
+//
+//        // Construct dictionary with all shells and all refinement surfaces
+//        dictionary geometryDict;
+//
+//        forAll(shellsDict, shellI)
+//        {
+//            dictionary shellDict = shellsDict[shellI];
+//            const word name(shellDict.lookup("name"));
+//            shellDict.remove("name");
+//            shellDict.remove("level");
+//            shellDict.remove("refineInside");
+//            geometryDict.add(name, shellDict);
+//        }
+//
+//        forAll(surfacesDict, surfI)
+//        {
+//            dictionary surfDict = surfacesDict[shellI];
+//            const word name(string::validate<word>(surfDict.lookup("file")));
+//            surfDict.remove("file");
+//            if (!surfDict.found("name"))
+//            {
+//                surfDict.add("name", name);
+//            }
+//            geometryDict.add(name, iter());
+//        }
+//
+//        allGeometryPtr_.reset
+//        (
+//            new searchableSurfaces
+//            (
+//                IOobject
+//                (
+//                    "abc",                      // dummy name
+//                    mesh_.time().constant(),    // directory
+//                    "triSurface",               // instance
+//                    mesh_.time(),               // registry
+//                    IOobject::MUST_READ,
+//                    IOobject::NO_WRITE
+//                ),
+//                geometryDict
+//            )
+//        );
+//
+//        Info<< "Read geometry in = "
+//            << mesh_.time().cpuTimeIncrement() << " s" << nl << endl;
+//    }
+//
+//
+//    // Read refinement surfaces
+//    // ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+//    {
+//        Info<< "Reading surfaces and constructing search trees." << endl;
+//
+//        surfacesPtr_.reset
+//        (
+//            new refinementSurfaces
+//            (
+//                allGeometryPtr_(),
+//                surfacesDict
+//            )
+//        );
+//        Info<< "Read surfaces in = "
+//            << mesh_.time().cpuTimeIncrement() << " s" << endl;
+//    }
+//
+//    // Read refinement shells
+//    // ~~~~~~~~~~~~~~~~~~~~~~
+//
+//    {
+//        Info<< "Reading refinement shells." << endl;
+//
+//        PtrList<dictionary> shellDicts(dict_.lookup("refinementShells"));
+//
+//        shells_.setSize(shellDicts.size());
+//        shellLevels_.setSize(shellDicts.size());
+//        shellRefineInside_.setSize(shellDicts.size());
+//
+//        forAll(shellDicts, i)
+//        {
+//            const dictionary& dict = shellDicts[i];
+//
+//            shells_.set
+//            (
+//                i,
+//                searchableSurface::New
+//                (
+//                    dict.lookup("type"),
+//                    dict.lookup("name"),
+//                    mesh_.time(),
+//                    dict
+//                )
+//            );
+//            shellLevels_[i] = readLabel(dict.lookup("level"));
+//            shellRefineInside_[i] = Switch(dict.lookup("refineInside"));
+//
+//            if (shellRefineInside_[i])
+//            {
+//                Info<< "Refinement level " << shellLevels_[i]
+//                    << " for all cells inside " << shells_[i].name() << endl;
+//            }
+//            else
+//            {
+//                Info<< "Refinement level " << shellLevels_[i]
+//                    << " for all cells outside " << shells_[i].name() << endl;
+//            }
+//        }
+//
+//        Info<< "Read refinement shells in = "
+//            << mesh_.time().cpuTimeIncrement() << " s" << endl;
+//
+//        // Orient shell surfaces before any searching is done.
+//        Info<< "Orienting triSurface shells so point far away is outside."
+//            << endl;
+//        orientOutside(shells_);
+//        Info<< "Oriented shells in = "
+//            << mesh_.time().cpuTimeIncrement() << " s" << endl;
+//    }
+//
+//
+//    // Read refinement surfaces
+//    // ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+//    {
+//        Info<< "Reading surfaces and constructing search trees." << endl;
+//
+//        surfacesPtr_.reset
+//        (
+//            new refinementSurfaces
+//            (
+//                IOobject
+//                (
+//                    "",                                 // dummy name
+//                    mesh_.time().constant(),            // directory
+//                    "triSurface",                       // instance
+//                    mesh_.time(),                       // registry
+//                    IOobject::MUST_READ,
+//                    IOobject::NO_WRITE
+//                ),
+//                dict_.lookup("surfaces")
+//            )
+//        );
+//        Info<< "Read surfaces in = "
+//            << mesh_.time().cpuTimeIncrement() << " s" << endl;
+//
+//        // Orient surfaces (if they're closed) before any searching is done.
+//        Info<< "Orienting (closed) surfaces so keepPoint is outside." << endl;
+//        forAll(surfaces(), i)
+//        {
+//            if (refinementSurfaces::isSurfaceClosed(surfaces()[i]))
+//            {
+//                refinementSurfaces::orientSurface
+//                (
+//                    keepPoints_[0],
+//                    surfacesPtr_()[i]
+//                );
+//            }
+//        }
+//        Info<< "Oriented closed surfaces in = "
+//            << mesh_.time().cpuTimeIncrement() << " s" << endl;
+//
+//        Info<< "Setting refinement level of surface to be consistent"
+//            << " with shells." << endl;
+//        surfacesPtr_().setMinLevelFields
+//        (
+//            shells_,
+//            shellLevels_,
+//            shellRefineInside_
+//        );
+//        Info<< "Checked shell refinement in = "
+//            << mesh_.time().cpuTimeIncrement() << " s" << endl;
+//    }
+//
+//    // Check faceZones are synchronised
+//    checkCoupledFaceZones();
+//
+//
+//    // Add all the surface regions as patches
+//    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+//    {
+//        Info<< nl
+//            << "Adding patches for surface regions" << nl
+//            << "----------------------------------" << nl
+//            << endl;
+//
+//        // From global region number to mesh patch.
+//        globalToPatch_.setSize(surfaces().nRegions(), -1);
+//
+//        Info<< "Patch\tRegion" << nl
+//            << "-----\t------"
+//            << endl;
+//
+//        forAll(surfaces(), surfI)
+//        {
+//            const triSurfaceMesh& s = surfaces()[surfI];
+//
+//            Info<< surfaces().names()[surfI] << ':' << nl << nl;
+//
+//            const geometricSurfacePatchList& regions = s.patches();
+//
+//            labelList nTrisPerRegion(surfaces().countRegions(s));
+//
+//            forAll(regions, i)
+//            {
+//                if (nTrisPerRegion[i] > 0)
+//                {
+//                    label globalRegionI = surfaces().globalRegion(surfI, i);
+//
+//                    // Use optionally specified patch type and name
+//                    word patchType = surfaces().patchType()[globalRegionI];
+//                    if (patchType == "")
+//                    {
+//                        patchType = wallPolyPatch::typeName;
+//                    }
+//
+//                    word patchName = surfaces().patchName()[globalRegionI];
+//                    if (patchName == "")
+//                    {
+//                        patchName =
+//                            surfaces().names()[surfI]
+//                          + '_'
+//                          + regions[i].name();
+//                    }
+//
+//                    label patchI = meshRefinement::addPatch
+//                    (
+//                        mesh,
+//                        patchName,
+//                        patchType
+//                    );
+//
+//                    Info<< patchI << '\t' << regions[i].name() << nl;
+//
+//                    globalToPatch_[globalRegionI] = patchI;
+//                }
+//            }
+//
+//            Info<< nl;
+//        }
+//        Info<< "Added patches in = "
+//            << mesh_.time().cpuTimeIncrement() << " s" << endl;
+//    }
+//
+//
+//    //// Add cyclics for any named faceZones
+//    //// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//    //// (these cyclics are used later on to temporarily put the faceZones
+//    ////  in when snapping)
+//    //
+//    //labelList namedSurfaces(surfaces().getNamedSurfaces());
+//    //if (namedSurfaces.size() > 0)
+//    //{
+//    //    Info<< nl
+//    //        << "Introducing cyclics for faceZones" << nl
+//    //        << "---------------------------------" << nl
+//    //        << endl;
+//    //
+//    //    // From surface to cyclic patch
+//    //    surfaceToCyclicPatch_.setSize(surfaces().size(), -1);
+//    //
+//    //    Info<< "Patch\tZone" << nl
+//    //        << "----\t-----"
+//    //        << endl;
+//    //
+//    //    forAll(namedSurfaces, i)
+//    //    {
+//    //        label surfI = namedSurfaces[i];
+//    //
+//    //        surfaceToCyclicPatch_[surfI] = meshRefinement::addPatch
+//    //        (
+//    //            mesh,
+//    //            surfaces().faceZoneNames()[surfI],
+//    //            cyclicPolyPatch::typeName
+//    //        );
+//    //
+//    //        Info<< surfaceToCyclicPatch_[surfI] << '\t'
+//    //            << surfaces().faceZoneNames()[surfI] << nl << endl;
+//    //    }
+//    //    Info<< "Added cyclic patches in = "
+//    //        << mesh_.time().cpuTimeIncrement() << " s" << endl;
+//    //}
+//
+//
+//    // Parallel
+//    // ~~~~~~~~
+//
+//    {
+//        // Decomposition
+//        decomposerPtr_ = decompositionMethod::New
+//        (
+//            decomposeDict,
+//            mesh_
+//        );
+//        decompositionMethod& decomposer = decomposerPtr_();
+//
+//
+//        if (Pstream::parRun() && !decomposer.parallelAware())
+//        {
+//            FatalErrorIn("autoHexMeshDriver::autoHexMeshDriver"
+//                "(const IOobject&, fvMesh&)")
+//                << "You have selected decomposition method "
+//                << decomposer.typeName
+//                << " which is not parallel aware." << endl
+//                << "Please select one that is (parMetis, hierarchical)"
+//                << exit(FatalError);
+//        }
+//
+//        // Mesh distribution engine (uses tolerance to reconstruct meshes)
+//        distributorPtr_.reset(new fvMeshDistribute(mesh_, mergeDist_));
+//    }
+//
+//
+//    // Refinement engine
+//    // ~~~~~~~~~~~~~~~~~
+//
+//    {
+//        Info<< nl
+//            << "Determining initial surface intersections" << nl
+//            << "-----------------------------------------" << nl
+//            << endl;
+//
+//        // Main refinement engine
+//        meshRefinerPtr_.reset
+//        (
+//            new meshRefinement
+//            (
+//                mesh,
+//                mergeDist_,         // tolerance used in sorting coordinates
+//                surfaces()
+//            )
+//        );
+//        Info<< "Calculated surface intersections in = "
+//            << mesh_.time().cpuTimeIncrement() << " s" << endl;
+//
+//        // Some stats
+//        meshRefinerPtr_().printMeshInfo(debug_, "Initial mesh");
+//
+//        meshRefinerPtr_().write
+//        (
+//            debug_&meshRefinement::OBJINTERSECTIONS,
+//            mesh_.time().path()/mesh_.time().timeName()
+//        );
+//    }
+//}
 
 
 // Construct from separate dictionaries.
@@ -611,6 +634,7 @@ Foam::autoHexMeshDriver::autoHexMeshDriver
 (
     fvMesh& mesh,
     const dictionary& controlDict,
+    const dictionary& geometryDict,
     const dictionary& refineDict,
     const dictionary& decomposeDict
 )
@@ -618,15 +642,9 @@ Foam::autoHexMeshDriver::autoHexMeshDriver
     mesh_(mesh),
     dict_(controlDict),
     debug_(readLabel(controlDict.lookup("debug"))),
-    maxGlobalCells_(readLabel(refineDict.lookup("cellLimit"))),
-    maxLocalCells_(readLabel(refineDict.lookup("procCellLimit"))),
-    minRefineCells_(readLabel(refineDict.lookup("minimumRefine"))),
-    curvature_(readScalar(refineDict.lookup("curvature"))),
-    nBufferLayers_(readLabel(refineDict.lookup("nBufferLayers"))),
-    keepPoints_(refineDict.lookup("keepPoints")),
     mergeDist_
     (
-        getMergeDistance(readScalar(refineDict.lookup("mergeTolerance")))
+        getMergeDistance(readScalar(controlDict.lookup("mergeTolerance")))
     )
 {
     if (debug_ > 0)
@@ -635,127 +653,69 @@ Foam::autoHexMeshDriver::autoHexMeshDriver
         autoHexMeshDriver::debug = debug_;
     }
 
-    Info<< "Overall cell limit                         : " << maxGlobalCells_
-        << endl;
-    Info<< "Per processor cell limit                   : " << maxLocalCells_
-        << endl;
-    Info<< "Minimum number of cells to refine          : " << minRefineCells_
-        << endl;
-    Info<< "Curvature                                  : " << curvature_
-        << nl << endl;
-    Info<< "Layers between different refinement levels : " << nBufferLayers_
-        << endl;
-
-    // Check keepPoints are sensible
-    findCells(keepPoints_);
-
-
-    // Read refinement shells
-    // ~~~~~~~~~~~~~~~~~~~~~~
-
-    {
-        Info<< "Reading refinement shells." << endl;
-
-        PtrList<dictionary> shellDicts(refineDict.lookup("refinementShells"));
-
-        shells_.setSize(shellDicts.size());
-        shellLevels_.setSize(shellDicts.size());
-        shellRefineInside_.setSize(shellDicts.size());
+    // Read geometry
+    // ~~~~~~~~~~~~~
 
-        forAll(shellDicts, i)
-        {
-            const dictionary& dict = shellDicts[i];
-
-            shells_.set
+    Info<< "Reading all geometry." << endl;
+    allGeometryPtr_.reset
+    (
+        new searchableSurfaces
+        (
+            IOobject
             (
-                i,
-                searchableSurface::New
-                (
-                    dict.lookup("type"),
-                    dict.lookup("name"),
-                    mesh_.time(),
-                    dict
-                )
-            );
-            shellLevels_[i] = readLabel(dict.lookup("level"));
-            shellRefineInside_[i] = Switch(dict.lookup("refineInside"));
-
-            if (shellRefineInside_[i])
-            {
-                Info<< "Refinement level " << shellLevels_[i]
-                    << " for all cells inside " << shells_[i].name() << endl;
-            }
-            else
-            {
-                Info<< "Refinement level " << shellLevels_[i]
-                    << " for all cells outside " << shells_[i].name() << endl;
-            }
-        }
-
-        Info<< "Read refinement shells in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
-
-        // Orient shell surfaces before any searching is done.
-        Info<< "Orienting triSurface shells so point far away is outside."
-            << endl;
-        orientOutside(shells_);
-        Info<< "Oriented shells in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
-    }
+                "abc",                      // dummy name
+                mesh_.time().constant(),    // directory
+                "triSurface",               // instance
+                mesh_.time(),               // registry
+                IOobject::MUST_READ,
+                IOobject::NO_WRITE
+            ),
+            geometryDict
+        )
+    );
+    Info<< "Read geometry in = "
+        << mesh_.time().cpuTimeIncrement() << " s" << nl << endl;
 
 
     // Read refinement surfaces
     // ~~~~~~~~~~~~~~~~~~~~~~~~
 
-    {
-        Info<< "Reading surfaces and constructing search trees." << endl;
-
-        surfacesPtr_.reset
+    Info<< "Reading refinement surfaces." << endl;
+    surfacesPtr_.reset
+    (
+        new refinementSurfaces
         (
-            new refinementSurfaces
-            (
-                IOobject
-                (
-                    "",                                 // dummy name
-                    mesh_.time().constant(),            // directory
-                    "triSurface",                       // instance
-                    mesh_.time(),                       // registry
-                    IOobject::MUST_READ,
-                    IOobject::NO_WRITE
-                ),
-                refineDict.lookup("surfaces")
-            )
-        );
-        Info<< "Read surfaces in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
+            allGeometryPtr_(),
+            refineDict.subDict("refinementSurfaces")
+        )
+    );
+    Info<< "Read refinement surfaces in = "
+        << mesh_.time().cpuTimeIncrement() << " s" << nl << endl;
 
-        // Orient surfaces (if they're closed) before any searching is done.
-        Info<< "Orienting (closed) surfaces so keepPoint is outside." << endl;
-        forAll(surfaces(), i)
-        {
-            if (refinementSurfaces::isSurfaceClosed(surfaces()[i]))
-            {
-                refinementSurfaces::orientSurface
-                (
-                    keepPoints_[0],
-                    surfacesPtr_()[i]
-                );
-            }
-        }
-        Info<< "Oriented closed surfaces in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
 
-        Info<< "Setting refinement level of surface to be consistent"
-            << " with shells." << endl;
-        surfacesPtr_().setMinLevelFields
+    // Read refinement shells
+    // ~~~~~~~~~~~~~~~~~~~~~~
+
+    Info<< "Reading refinement shells." << endl;
+    shellsPtr_.reset
+    (
+        new shellSurfaces
         (
-            shells_,
-            shellLevels_,
-            shellRefineInside_
-        );
-        Info<< "Checked shell refinement in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
-    }
+            allGeometryPtr_(),
+            refineDict.subDict("refinementRegions")
+        )
+    );
+    Info<< "Read refinement shells in = "
+        << mesh_.time().cpuTimeIncrement() << " s" << nl << endl;
+
+
+    Info<< "Setting refinement level of surface to be consistent"
+        << " with shells." << endl;
+    surfacesPtr_().setMinLevelFields(shells());
+    Info<< "Checked shell refinement in = "
+        << mesh_.time().cpuTimeIncrement() << " s" << nl << endl;
+
+
 
     // Check faceZones are synchronised
     checkCoupledFaceZones();
@@ -777,38 +737,41 @@ Foam::autoHexMeshDriver::autoHexMeshDriver
             << "-----\t------"
             << endl;
 
-        forAll(surfaces(), surfI)
+        const labelList& surfaceGeometry = surfaces().surfaces();
+        forAll(surfaceGeometry, surfI)
         {
-            const triSurfaceMesh& s = surfaces()[surfI];
+            label geomI = surfaceGeometry[surfI];
 
-            Info<< surfaces().names()[surfI] << ':' << nl << nl;
+            const wordList& regNames = allGeometryPtr_().regionNames()[geomI];
 
-            const geometricSurfacePatchList& regions = s.patches();
+            Info<< surfaces().names()[surfI] << ':' << nl << nl;
 
-            labelList nTrisPerRegion(surfaces().countRegions(s));
+            //const triSurfaceMesh& s = surfaces()[surfI];
+            //const geometricSurfacePatchList& regions = s.patches();
+            //labelList nTrisPerRegion(surfaces().countRegions(s));
 
-            forAll(regions, i)
+            forAll(regNames, i)
             {
-                if (nTrisPerRegion[i] > 0)
-                {
+                //if (nTrisPerRegion[i] > 0)
+                //{
                     label patchI = meshRefinement::addPatch
                     (
                         mesh,
                         //s.searchableSurface::name() + '_' + regions[i].name(),
-                        surfaces().names()[surfI] + '_' + regions[i].name(),
+                        regNames[i],
                         wallPolyPatch::typeName
                     );
 
-                    Info<< patchI << '\t' << regions[i].name() << nl;
+                    Info<< patchI << '\t' << regNames[i] << nl;
 
                     globalToPatch_[surfaces().globalRegion(surfI, i)] = patchI;
-                }
+                //}
             }
 
             Info<< nl;
         }
         Info<< "Added patches in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
+            << mesh_.time().cpuTimeIncrement() << " s" << nl << endl;
     }
 
     // Parallel
@@ -855,11 +818,12 @@ Foam::autoHexMeshDriver::autoHexMeshDriver
             (
                 mesh,
                 mergeDist_,         // tolerance used in sorting coordinates
-                surfaces()
+                surfaces(),         // for surface intersection refinement
+                shells()            // for volume (inside/outside) refinement
             )
         );
         Info<< "Calculated surface intersections in = "
-            << mesh_.time().cpuTimeIncrement() << " s" << endl;
+            << mesh_.time().cpuTimeIncrement() << " s" << nl << endl;
 
         // Some stats
         meshRefinerPtr_().printMeshInfo(debug_, "Initial mesh");
@@ -920,7 +884,7 @@ Foam::label Foam::autoHexMeshDriver::readFeatureEdges
     }
 
     Info<< "Read feature lines in = "
-        << mesh_.time().cpuTimeIncrement() << " s" << endl;
+        << mesh_.time().cpuTimeIncrement() << " s" << nl << endl;
 
     return featureMeshes_.size();
 }
@@ -928,6 +892,7 @@ Foam::label Foam::autoHexMeshDriver::readFeatureEdges
 
 Foam::label Foam::autoHexMeshDriver::featureEdgeRefine
 (
+    const refinementParameters& refineParams,
     const PtrList<dictionary>& featDicts,
     const label maxIter,
     const label minRefine
@@ -953,23 +918,18 @@ Foam::label Foam::autoHexMeshDriver::featureEdgeRefine
             (
                 meshRefiner.refineCandidates
                 (
-                    keepPoints_[0],     // For now only use one.
-                    globalToPatch_,
-                    curvature_,
+                    refineParams.keepPoints()[0],    // For now only use one.
+                    refineParams.curvature(),
 
                     featureMeshes_,
                     featureLevels_,
 
-                    shells_,
-                    shellLevels_,
-                    shellRefineInside_,
-
                     true,               // featureRefinement
                     false,              // internalRefinement
                     false,              // surfaceRefinement
                     false,              // curvatureRefinement
-                    maxGlobalCells_,
-                    maxLocalCells_
+                    refineParams.maxGlobalCells(),
+                    refineParams.maxLocalCells()
                 )
             );
             labelList cellsToRefine
@@ -1018,7 +978,11 @@ Foam::label Foam::autoHexMeshDriver::featureEdgeRefine
 }
 
 
-Foam::label Foam::autoHexMeshDriver::surfaceOnlyRefine(const label maxIter)
+Foam::label Foam::autoHexMeshDriver::surfaceOnlyRefine
+(
+    const refinementParameters& refineParams,
+    const label maxIter
+)
 {
     meshRefinement& meshRefiner = meshRefinerPtr_();
 
@@ -1044,23 +1008,18 @@ Foam::label Foam::autoHexMeshDriver::surfaceOnlyRefine(const label maxIter)
         (
             meshRefiner.refineCandidates
             (
-                keepPoints_[0],
-                globalToPatch_,
-                curvature_,
+                refineParams.keepPoints()[0],
+                refineParams.curvature(),
 
                 featureMeshes_,
                 featureLevels_,
 
-                shells_,
-                shellLevels_,
-                shellRefineInside_,
-
                 false,              // featureRefinement
                 false,              // internalRefinement
                 true,               // surfaceRefinement
                 true,               // curvatureRefinement
-                maxGlobalCells_,
-                maxLocalCells_
+                refineParams.maxGlobalCells(),
+                refineParams.maxLocalCells()
             )
         );
         labelList cellsToRefine
@@ -1089,7 +1048,7 @@ Foam::label Foam::autoHexMeshDriver::surfaceOnlyRefine(const label maxIter)
             nCellsToRefine == 0
          || (
                 iter >= overallMaxLevel
-             && nCellsToRefine <= minRefineCells_
+             && nCellsToRefine <= refineParams.minRefineCells()
             )
         )
         {
@@ -1116,7 +1075,11 @@ Foam::label Foam::autoHexMeshDriver::surfaceOnlyRefine(const label maxIter)
 }
 
 
-void Foam::autoHexMeshDriver::removeInsideCells(const label nBufferLayers)
+void Foam::autoHexMeshDriver::removeInsideCells
+(
+    const refinementParameters& refineParams,
+    const label nBufferLayers
+)
 {
 
     meshRefinement& meshRefiner = meshRefinerPtr_();
@@ -1135,7 +1098,7 @@ void Foam::autoHexMeshDriver::removeInsideCells(const label nBufferLayers)
     (
         nBufferLayers,                  // nBufferLayers
         globalToPatch_,
-        keepPoints_[0]
+        refineParams.keepPoints()[0]
     );
 
     if (debug_)
@@ -1149,7 +1112,11 @@ void Foam::autoHexMeshDriver::removeInsideCells(const label nBufferLayers)
 }
 
 
-Foam::label Foam::autoHexMeshDriver::shellRefine(const label maxIter)
+Foam::label Foam::autoHexMeshDriver::shellRefine
+(
+    const refinementParameters& refineParams,
+    const label maxIter
+)
 {
     meshRefinement& meshRefiner = meshRefinerPtr_();
 
@@ -1170,15 +1137,7 @@ Foam::label Foam::autoHexMeshDriver::shellRefine(const label maxIter)
     // Determine the maximum refinement level over all volume refinement
     // regions. This determines the minumum number of shell refinement
     // iterations.
-    label overallMaxShellLevel;
-    if (shellLevels_.size() == 0)
-    {
-        overallMaxShellLevel = 0;
-    }
-    else
-    {
-        overallMaxShellLevel = max(shellLevels_);
-    }
+    label overallMaxShellLevel = shells().maxLevel();
 
     label iter;
     for (iter = 0; iter < maxIter; iter++)
@@ -1192,23 +1151,18 @@ Foam::label Foam::autoHexMeshDriver::shellRefine(const label maxIter)
         (
             meshRefiner.refineCandidates
             (
-                keepPoints_[0],
-                globalToPatch_,
-                curvature_,
+                refineParams.keepPoints()[0],
+                refineParams.curvature(),
 
                 featureMeshes_,
                 featureLevels_,
 
-                shells_,
-                shellLevels_,
-                shellRefineInside_,
-
                 false,              // featureRefinement
                 true,               // internalRefinement
                 false,              // surfaceRefinement
                 false,              // curvatureRefinement
-                maxGlobalCells_,
-                maxLocalCells_
+                refineParams.maxGlobalCells(),
+                refineParams.maxLocalCells()
             )
         );
 
@@ -1232,16 +1186,16 @@ Foam::label Foam::autoHexMeshDriver::shellRefine(const label maxIter)
             findIndices(meshRefiner.userFaceData()[0].second(), 0)
         );
 
-        Info<< "Collected boundary faces : "
-            << returnReduce(bFaces.size(), sumOp<label>()) << endl;
+        //Info<< "Collected boundary faces : "
+        //    << returnReduce(bFaces.size(), sumOp<label>()) << endl;
 
         labelList cellsToRefine;
 
-        if (nBufferLayers_ <= 2)
+        if (refineParams.nBufferLayers() <= 2)
         {
             cellsToRefine = meshRefiner.meshCutter().consistentSlowRefinement
             (
-                nBufferLayers_,
+                refineParams.nBufferLayers(),
                 candidateCells,                 // cells to refine
                 bFaces,                         // faces for nBufferLayers
                 1,                              // point difference
@@ -1252,7 +1206,7 @@ Foam::label Foam::autoHexMeshDriver::shellRefine(const label maxIter)
         {
             cellsToRefine = meshRefiner.meshCutter().consistentSlowRefinement2
             (
-                nBufferLayers_,
+                refineParams.nBufferLayers(),
                 candidateCells,                 // cells to refine
                 bFaces                          // faces for nBufferLayers
             );
@@ -1276,7 +1230,7 @@ Foam::label Foam::autoHexMeshDriver::shellRefine(const label maxIter)
             nCellsToRefine == 0
          || (
                 iter >= overallMaxShellLevel
-             && nCellsToRefine <= minRefineCells_
+             && nCellsToRefine <= refineParams.minRefineCells()
             )
         )
         {
@@ -1305,7 +1259,11 @@ Foam::label Foam::autoHexMeshDriver::shellRefine(const label maxIter)
 }
 
 
-void Foam::autoHexMeshDriver::baffleAndSplitMesh(const bool handleSnapProblems)
+void Foam::autoHexMeshDriver::baffleAndSplitMesh
+(
+    const refinementParameters& refineParams,
+    const bool handleSnapProblems
+)
 {
     meshRefinement& meshRefiner = meshRefinerPtr_();
 
@@ -1323,12 +1281,15 @@ void Foam::autoHexMeshDriver::baffleAndSplitMesh(const bool handleSnapProblems)
         !handleSnapProblems,            // merge free standing baffles?
         const_cast<Time&>(mesh_.time()),
         globalToPatch_,
-        keepPoints_[0]
+        refineParams.keepPoints()[0]
     );
 }
 
 
-void Foam::autoHexMeshDriver::zonify()
+void Foam::autoHexMeshDriver::zonify
+(
+    const refinementParameters& refineParams
+)
 {
     // Mesh is at its finest. Do zoning
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1351,7 +1312,7 @@ void Foam::autoHexMeshDriver::zonify()
             const_cast<Time&>(mesh_.time())++;
         }
 
-        meshRefiner.zonify(keepPoints_[0]);
+        meshRefiner.zonify(refineParams.keepPoints()[0]);
 
         if (debug_)
         {
@@ -1372,6 +1333,7 @@ void Foam::autoHexMeshDriver::zonify()
 
 void Foam::autoHexMeshDriver::splitAndMergeBaffles
 (
+    const refinementParameters& refineParams,
     const bool handleSnapProblems
 )
 {
@@ -1394,7 +1356,7 @@ void Foam::autoHexMeshDriver::splitAndMergeBaffles
         false,                  // merge free standing baffles?
         const_cast<Time&>(mesh_.time()),
         globalToPatch_,
-        keepPoints_[0]
+        refineParams.keepPoints()[0]
     );
 
     if (debug_)
@@ -1447,7 +1409,10 @@ void Foam::autoHexMeshDriver::splitAndMergeBaffles
 }
 
 
-void Foam::autoHexMeshDriver::mergePatchFaces()
+void Foam::autoHexMeshDriver::mergePatchFaces
+(
+    const refinementParameters& refineParams
+)
 {
     Info<< nl
         << "Merge refined boundary faces" << nl
@@ -1536,8 +1501,8 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::autoHexMeshDriver::balance
                 const wordList& fzNames = surfaces().faceZoneNames();
                 const faceZoneMesh& fZones = mesh_.faceZones();
 
-                // Get faces whose owner and neighbour should stay together, i.e.
-                // they are not 'blocked'.
+                // Get faces whose owner and neighbour should stay together,
+                // i.e. they are not 'blocked'.
 
                 label nZoned = 0;
 
@@ -1655,11 +1620,18 @@ void Foam::autoHexMeshDriver::doRefine
 
     const_cast<Time&>(mesh_.time())++;
 
+    // Get all the refinement specific params
+    refinementParameters refineParams(refineDict);
+
+    // Check that all the keep points are inside the mesh.
+    refineParams.findCells(mesh_);
+
     PtrList<dictionary> featDicts(refineDict.lookup("features"));
 
     // Refine around feature edges
     featureEdgeRefine
     (
+        refineParams,
         featDicts,
         100,    // maxIter
         0       // min cells to refine
@@ -1668,34 +1640,37 @@ void Foam::autoHexMeshDriver::doRefine
     // Refine based on surface
     surfaceOnlyRefine
     (
+        refineParams,
         100     // maxIter
     );
 
     // Remove cells (a certain distance) beyond surface intersections
     removeInsideCells
     (
+        refineParams,
         1       // nBufferLayers
     );
 
     // Internal mesh refinement
     shellRefine
     (
+        refineParams,
         100    // maxIter
     );
 
     // Introduce baffles at surface intersections
-    baffleAndSplitMesh(prepareForSnapping);
+    baffleAndSplitMesh(refineParams, prepareForSnapping);
 
     // Mesh is at its finest. Do optional zoning.
-    zonify();
+    zonify(refineParams);
 
     // Pull baffles apart
-    splitAndMergeBaffles(prepareForSnapping);
+    splitAndMergeBaffles(refineParams, prepareForSnapping);
 
     // Do something about cells with refined faces on the boundary
     if (prepareForSnapping)
     {
-        mergePatchFaces();
+        mergePatchFaces(refineParams);
     }
 
     // Do final balancing. Keep zoned faces on one processor.
@@ -1719,6 +1694,9 @@ void Foam::autoHexMeshDriver::doSnap
 
     const_cast<Time&>(mesh_.time())++;
 
+    // Get all the snapping specific params
+    snapParameters snapParams(snapDict);
+
     // Get the labels of added patches.
     labelList adaptPatchIDs(getSurfacePatches());
 
@@ -1739,7 +1717,7 @@ void Foam::autoHexMeshDriver::doSnap
         indirectPrimitivePatch& pp = ppPtr();
 
         // Distance to attact to nearest feature on surface
-        const scalarField snapDist(calcSnapDistance(snapDict, pp));
+        const scalarField snapDist(calcSnapDistance(snapParams, pp));
 
 
         // Construct iterative mesh mover.
@@ -1777,17 +1755,17 @@ void Foam::autoHexMeshDriver::doSnap
             << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl;
 
         // Pre-smooth patch vertices (so before determining nearest)
-        preSmoothPatch(snapDict, nInitErrors, baffles, meshMover);
+        preSmoothPatch(snapParams, nInitErrors, baffles, meshMover);
 
         // Calculate displacement at every patch point. Insert into
         // meshMover.
         calcNearestSurface(snapDist, meshMover);
 
         // Get smoothly varying internal displacement field.
-        smoothDisplacement(snapDict, meshMover);
+        smoothDisplacement(snapParams, meshMover);
 
         // Apply internal displacement to mesh.
-        scaleMesh(snapDict, nInitErrors, baffles, meshMover);
+        scaleMesh(snapParams, nInitErrors, baffles, meshMover);
     }
 
     // Merge any introduced baffles.
@@ -1811,22 +1789,24 @@ void Foam::autoHexMeshDriver::doLayers
 
     const_cast<Time&>(mesh_.time())++;
 
+    // Get all the layer specific params
+    layerParameters layerParams(shrinkDict, mesh_.boundaryMesh());
+
     Info<< "Using mesh parameters " << motionDict << nl << endl;
 
     // Merge coplanar boundary faces
-    mergePatchFacesUndo(shrinkDict, motionDict);
+    mergePatchFacesUndo(layerParams, motionDict);
 
-    // Per global region the number of layers (0 if no layer)
-    const labelList& numLayers = surfaces().numLayers();
+    // Per patch the number of layers (0 if no layer)
+    const labelList& numLayers = layerParams.numLayers();
 
     // Patches that need to get a layer
     DynamicList<label> patchIDs(numLayers.size());
     label nFacesWithLayers = 0;
-    forAll(numLayers, region)
+    forAll(numLayers, patchI)
     {
-        if (numLayers[region] > 0 && globalToPatch()[region] != -1)
+        if (numLayers[patchI] > 0)
         {
-            label patchI = globalToPatch()[region];
             patchIDs.append(patchI);
             nFacesWithLayers += mesh_.boundaryMesh()[patchI].size();
         }
@@ -1882,7 +1862,7 @@ void Foam::autoHexMeshDriver::doLayers
                 << endl;
 
             // Do all topo changes
-            addLayers(shrinkDict, motionDict, nInitErrors, meshMover);
+            addLayers(layerParams, motionDict, nInitErrors, meshMover);
         }
 
         // Write mesh.
diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.H
index 28a4845b9a81090d778dd8df172844fc53a7aaf5..06d377a2778a89faf535f30933aab0f85fad94b0 100644
--- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.H
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriver.H
@@ -49,8 +49,9 @@ SourceFiles
 #include "wallPoint.H"
 #include "indirectPrimitivePatch.H"
 #include "featureEdgeMesh.H"
-#include "searchableSurface.H"
+#include "searchableSurfaces.H"
 #include "refinementSurfaces.H"
+#include "shellSurfaces.H"
 #include "meshRefinement.H"
 #include "decompositionMethod.H"
 #include "fvMeshDistribute.H"
@@ -70,6 +71,9 @@ class pointData;
 class faceSet;
 class addPatchCellLayer;
 class mapDistributePolyMesh;
+class snapParameters;
+class layerParameters;
+class refinementParameters;
 
 /*---------------------------------------------------------------------------*\
                            Class autoHexMeshDriver Declaration
@@ -79,15 +83,13 @@ class autoHexMeshDriver
 {
     // Static data members
 
-        //- Default angle for faces to be convcave
-        static const scalar defaultConcaveAngle;
-
         //- Extrusion controls
         enum extrudeMode
         {
             NOEXTRUDE,      /*!< Do not extrude. No layers added. */
             EXTRUDE,        /*!< Extrude */
-            EXTRUDEREMOVE   /*!< Extrude but afterwards remove added faces locally */
+            EXTRUDEREMOVE   /*!< Extrude but afterwards remove added */
+                            /*!< faces locally */
         };
 
 
@@ -141,42 +143,24 @@ class autoHexMeshDriver
         //- Debug level
         const label debug_;
 
-        //- Total number of cells
-        const label maxGlobalCells_;
-
-        //- Per processor max number of cells
-        const label maxLocalCells_;
-
-        //- When to stop refining
-        const label minRefineCells_;
-
-        //- Curvature
-        const scalar curvature_;
-
-        //- Number of layers between different refinement levels
-        const label nBufferLayers_;
-
-        //- Areas to keep
-        const pointField keepPoints_;
-
         //- Merge distance
         const scalar mergeDist_;
 
 
+        // Refinement only
+
+            //- Explicit features
+            PtrList<featureEdgeMesh> featureMeshes_;
+            //- Per feature the refinement level
+            labelList featureLevels_;
 
-        //- Explicit features
-        PtrList<featureEdgeMesh> featureMeshes_;
-        //- Per feature the refinement level
-        labelList featureLevels_;
+        //- All surface based geometry
+        autoPtr<searchableSurfaces> allGeometryPtr_;
 
-        //- Shells
-        PtrList<searchableSurface> shells_;
-        //- Per shell the refinement level
-        labelList shellLevels_;
-        //- Per shell whether to refine inside or outside
-        boolList shellRefineInside_;
+        //- Shells (geometry for inside/outside refinement)
+        autoPtr<shellSurfaces> shellsPtr_;
 
-        //- Surfaces with refinement levels built-in
+        //- Surfaces (geometry for intersection based refinement)
         autoPtr<refinementSurfaces> surfacesPtr_;
 
         //- Per refinement surface region the patch
@@ -200,10 +184,6 @@ class autoHexMeshDriver
             //- Calculate merge distance. Check against writing tolerance.
             scalar getMergeDistance(const scalar mergeTol) const;
 
-            // Return per keeppoint -1 or the local cell label the point is in.
-            // Guaranteed to be only on one processor.
-            labelList findCells(const pointField&) const;
-
             static void orientOutside(PtrList<searchableSurface>&);
 
             //- Read feature edges
@@ -371,6 +351,7 @@ class autoHexMeshDriver
                 //  layers per surface.
                 void setNumLayers
                 (
+                    const labelList& patchToNLayers,
                     const labelList& patchIDs,
                     const indirectPrimitivePatch& pp,
                     pointField& patchDisp,
@@ -390,17 +371,22 @@ class autoHexMeshDriver
                 //- Calculate pointwise wanted and minimum thickness.
                 //  thickness: wanted thickness
                 //  minthickness: when to give up and not extrude
+                //  Gets per patch parameters and determine pp pointwise
+                //  parameters.
                 void calculateLayerThickness
                 (
-                    const scalar expansionRatio,
-                    const scalar finalLayerRatio,
-                    const scalar relMinThickness,
                     const indirectPrimitivePatch& pp,
+                    const labelList& patchIDs,
+                    const scalarField& patchExpansionRatio,
+                    const scalarField& patchFinalLayerRatio,
+                    const scalarField& patchRelMinThickness,
                     const labelList& cellLevel,
                     const labelList& patchNLayers,
                     const scalar edge0Len,
+
                     scalarField& thickness,
-                    scalarField& minThickness
+                    scalarField& minThickness,
+                    scalarField& expansionRatio
                 ) const;
 
 
@@ -638,13 +624,13 @@ public:
 
     // Constructors
 
-        //- Construct from dictionary and mesh to modify
-        autoHexMeshDriver
-        (
-            fvMesh& mesh,
-            const dictionary& meshDict,
-            const dictionary& decomposeDict
-        );
+//        //- Construct from dictionary and mesh to modify
+//        autoHexMeshDriver
+//        (
+//            fvMesh& mesh,
+//            const dictionary& meshDict,
+//            const dictionary& decomposeDict
+//        );
 
         //- Alternative constructor from top-level controldictionary and
         //  refinement specific dictionary
@@ -652,6 +638,7 @@ public:
         (
             fvMesh& mesh,
             const dictionary& controlDict,
+            const dictionary& geometryDict,
             const dictionary& refineDict,
             const dictionary& decomposeDict
         );
@@ -677,6 +664,12 @@ public:
                 return surfacesPtr_();
             }
 
+            //- Surfaces to volume refinement on
+            const shellSurfaces& shells() const
+            {
+                return shellsPtr_();
+            }
+
             //- Per refinementsurface, per region the patch
             const labelList& globalToPatch() const
             {
@@ -689,32 +682,53 @@ public:
             //- Refine around explicit feature edges
             label featureEdgeRefine
             (
+                const refinementParameters& refineParams,
                 const PtrList<dictionary>& featDicts,
                 const label maxIter,
                 const label minRefine
             );
 
             //- Refine at surface intersections
-            label surfaceOnlyRefine(const label maxIter);
+            label surfaceOnlyRefine
+            (
+                const refinementParameters& refineParams,
+                const label maxIter
+            );
 
             //- Remove cells not reachable from keep points
-            void removeInsideCells(const label nBufferLayers);
+            void removeInsideCells
+            (    
+                const refinementParameters& refineParams,
+                const label nBufferLayers
+            );
 
             //- Refine volume regions (interior of shells)
-            label shellRefine(const label maxIter);
+            label shellRefine
+            (
+                const refinementParameters& refineParams,
+                const label maxIter
+            );
 
             //- Introduce baffles; remove unreachable mesh parts
             //  handleSnapProblems : whether to remove free floating cells
-            void baffleAndSplitMesh(const bool handleSnapProblems);
+            void baffleAndSplitMesh
+            (
+                const refinementParameters& refineParams,
+                const bool handleSnapProblems
+            );
 
             //- Move cells to zones
-            void zonify();
+            void zonify(const refinementParameters&);
 
             //- Split and recombine baffles to get rid of single face baffles.
-            void splitAndMergeBaffles(const bool handleSnapProblems);
+            void splitAndMergeBaffles
+            (
+                const refinementParameters& refineParams,
+                const bool handleSnapProblems
+            );
 
             //- Merge multiple boundary faces on single cell
-            void mergePatchFaces();
+            void mergePatchFaces(const refinementParameters&);
 
             //- Redecompose according to cell count
             //  keepZoneFaces : find all faceZones from zoned surfaces and keep
@@ -742,7 +756,7 @@ public:
             //- Calculate edge length per patch point.
             scalarField calcSnapDistance
             (
-                const dictionary& snapDict,
+                const snapParameters& snapParams,
                 const indirectPrimitivePatch&
             ) const;
 
@@ -753,12 +767,19 @@ public:
             //  of surface points (on castellated mesh) w.r.t. surface.
             void preSmoothPatch
             (
-                const dictionary& snapDict,
+                const snapParameters& snapParams,
                 const label nInitErrors,
                 const List<labelPair>& baffles,
                 motionSmoother&
             ) const;
 
+            //- Get points both on patch and facezone.
+            labelList getZoneSurfacePoints
+            (
+                const indirectPrimitivePatch&,
+                const word& zoneName
+            ) const;
+
             //- Per patch point calculate point on nearest surface. Set as
             //  boundary conditions of motionSmoother displacement field. Return
             //  displacement of patch points.
@@ -771,7 +792,7 @@ public:
             //- Smooth the displacement field to the internal.
             void smoothDisplacement
             (
-                const dictionary& snapDict,
+                const snapParameters& snapParams,
                 motionSmoother&
             ) const;
 
@@ -779,7 +800,7 @@ public:
             //  locally relax the displacement.
             void scaleMesh
             (
-                const dictionary& snapDict,
+                const snapParameters& snapParams,
                 const label nInitErrors,
                 const List<labelPair>& baffles,
                 motionSmoother&
@@ -791,7 +812,7 @@ public:
             //- Merge patch faces on same cell.
             void mergePatchFacesUndo
             (
-                const dictionary& shrinkDict,
+                const layerParameters& layerParams,
                 const dictionary& motionDict
             );
 
@@ -801,7 +822,7 @@ public:
             //- Add cell layers
             void addLayers
             (
-                const dictionary& shrinkDict,
+                const layerParameters& layerParams,
                 const dictionary& motionDict,
                 const label nAllowableErrors,
                 motionSmoother&
diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverLayers.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverLayers.C
index 0615d504765172caa43557661955fb7b88cd09f7..3ebf41390cbb3c52986e2b41bdb4e8647b06ee3e 100644
--- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverLayers.C
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverLayers.C
@@ -27,7 +27,6 @@ Description
 
 \*----------------------------------------------------------------------------*/
 
-#include "ListOps.H"
 #include "autoHexMeshDriver.H"
 #include "fvMesh.H"
 #include "Time.H"
@@ -43,11 +42,8 @@ Description
 #include "mapPolyMesh.H"
 #include "addPatchCellLayer.H"
 #include "mapDistributePolyMesh.H"
-
-// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
-
-const Foam::scalar Foam::autoHexMeshDriver::defaultConcaveAngle = 90;
-
+#include "OFstream.H"
+#include "layerParameters.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -1191,6 +1187,7 @@ void Foam::autoHexMeshDriver::handleWarpedFaces
 // No extrusion on faces with differing number of layers for points
 void Foam::autoHexMeshDriver::setNumLayers
 (
+    const labelList& patchToNLayers,
     const labelList& patchIDs,
     const indirectPrimitivePatch& pp,
     pointField& patchDisp,
@@ -1201,18 +1198,6 @@ void Foam::autoHexMeshDriver::setNumLayers
     Info<< nl << "Handling points with inconsistent layer specification ..."
         << endl;
 
-    const labelList& nSurfLayers = surfaces().numLayers();
-
-    // Build map from patch to layers
-    Map<label> patchToNLayers(nSurfLayers.size());
-    forAll(nSurfLayers, region)
-    {
-        if (globalToPatch_[region] != -1)
-        {
-            patchToNLayers.insert(globalToPatch_[region], nSurfLayers[region]);
-        }
-    }
-
     // Get for every point (really only nessecary on patch external points)
     // the max and min of any patch faces using it.
     labelList maxLayers(patchNLayers.size(), labelMin);
@@ -1257,7 +1242,7 @@ void Foam::autoHexMeshDriver::setNumLayers
     // Unmark any point with different min and max
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    label nConflicts = 0;
+    //label nConflicts = 0;
 
     forAll(maxLayers, i)
     {
@@ -1294,11 +1279,11 @@ void Foam::autoHexMeshDriver::setNumLayers
         }
     }
 
-    reduce(nConflicts, sumOp<label>());
-
-    Info<< "Set displacement to zero for " << nConflicts
-        << " points due to points being on multiple regions"
-        << " with inconsistent nLayers specification." << endl;
+    //reduce(nConflicts, sumOp<label>());
+    //
+    //Info<< "Set displacement to zero for " << nConflicts
+    //    << " points due to points being on multiple regions"
+    //    << " with inconsistent nLayers specification." << endl;
 }
 
 
@@ -1369,60 +1354,138 @@ void Foam::autoHexMeshDriver::growNoExtrusion
 }
 
 
-
-// Calculate pointwise wanted and minimum thickness.
-// thickness: wanted thickness per point
 void Foam::autoHexMeshDriver::calculateLayerThickness
 (
-    const scalar expansionRatio,
-    const scalar finalLayerRatio,
-    const scalar relMinThickness,
     const indirectPrimitivePatch& pp,
+    const labelList& patchIDs,
+    const scalarField& patchExpansionRatio,
+    const scalarField& patchFinalLayerRatio,
+    const scalarField& patchRelMinThickness,
     const labelList& cellLevel,
     const labelList& patchNLayers,
     const scalar edge0Len,
+
     scalarField& thickness,
-    scalarField& minThickness
+    scalarField& minThickness,
+    scalarField& expansionRatio
 ) const
 {
-    if (relMinThickness < 0 || relMinThickness > 2)
+    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
+
+    if (min(patchRelMinThickness) < 0 || max(patchRelMinThickness) > 2)
     {
         FatalErrorIn("calculateLayerThickness(..)")
             << "Thickness should be factor of local undistorted cell size."
             << " Valid values are [0..2]." << nl
-            << " minThickness:" << relMinThickness
+            << " minThickness:" << patchRelMinThickness
             << exit(FatalError);
     }
 
-    thickness.setSize(pp.nPoints());
-    minThickness.setSize(pp.nPoints());
 
     // Per point the max cell level of connected cells
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
     labelList maxPointLevel(pp.nPoints(), labelMin);
 
-    forAll(pp, i)
     {
-        label ownLevel = cellLevel[mesh_.faceOwner()[pp.addressing()[i]]];
+        forAll(pp, i)
+        {
+            label ownLevel = cellLevel[mesh_.faceOwner()[pp.addressing()[i]]];
 
-        const face& f = pp.localFaces()[i];
+            const face& f = pp.localFaces()[i];
 
-        forAll(f, fp)
+            forAll(f, fp)
+            {
+                maxPointLevel[f[fp]] = max(maxPointLevel[f[fp]], ownLevel);
+            }
+        }
+
+        syncTools::syncPointList
+        (
+            mesh_,
+            pp.meshPoints(),
+            maxPointLevel,
+            maxEqOp<label>(),
+            labelMin,           // null value
+            false               // no separation
+        );
+    }
+
+
+    // Rework patch-wise layer parameters into minimum per point
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    expansionRatio.setSize(pp.nPoints());
+    expansionRatio = GREAT;
+    scalarField finalLayerRatio(pp.nPoints(), GREAT);
+    scalarField relMinThickness(pp.nPoints(), GREAT);
+
+    {
+        forAll(patchIDs, i)
         {
-            maxPointLevel[f[fp]] = max(maxPointLevel[f[fp]], ownLevel);
+            label patchI = patchIDs[i];
+
+            const labelList& meshPoints = patches[patchI].meshPoints();
+
+            forAll(meshPoints, patchPointI)
+            {
+                label ppPointI = pp.meshPointMap()[meshPoints[patchPointI]];
+
+                expansionRatio[ppPointI] = min
+                (
+                    expansionRatio[ppPointI],
+                    patchExpansionRatio[patchI]
+                );
+                finalLayerRatio[ppPointI] = min
+                (
+                    finalLayerRatio[ppPointI],
+                    patchFinalLayerRatio[patchI]
+                );
+                relMinThickness[ppPointI] = min
+                (
+                    relMinThickness[ppPointI],
+                    patchRelMinThickness[patchI]
+                );
+            }
         }
+
+        syncTools::syncPointList
+        (
+            mesh_,
+            pp.meshPoints(),
+            expansionRatio,
+            minEqOp<scalar>(),
+            GREAT,              // null value
+            false               // no separation
+        );
+        syncTools::syncPointList
+        (
+            mesh_,
+            pp.meshPoints(),
+            finalLayerRatio,
+            minEqOp<scalar>(),
+            GREAT,              // null value
+            false               // no separation
+        );
+        syncTools::syncPointList
+        (
+            mesh_,
+            pp.meshPoints(),
+            relMinThickness,
+            minEqOp<scalar>(),
+            GREAT,              // null value
+            false               // no separation
+        );
     }
 
-    syncTools::syncPointList
-    (
-        mesh_,
-        pp.meshPoints(),
-        maxPointLevel,
-        maxEqOp<label>(),
-        labelMin,           // null value
-        false               // no separation
-    );
 
 
+    // Per mesh point the expansion parameters
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    thickness.setSize(pp.nPoints());
+    minThickness.setSize(pp.nPoints());
+
     forAll(maxPointLevel, pointI)
     {
         // Find undistorted edge size for this level.
@@ -1430,19 +1493,24 @@ void Foam::autoHexMeshDriver::calculateLayerThickness
 
         // Calculate layer thickness based on expansion ratio
         // and final layer height
-        if (expansionRatio == 1)
+        if (expansionRatio[pointI] == 1)
         {
-            thickness[pointI] = finalLayerRatio*patchNLayers[pointI]*edgeLen;
-            minThickness[pointI] = relMinThickness*edgeLen;
+            thickness[pointI] =
+                finalLayerRatio[pointI]
+              * patchNLayers[pointI]
+              * edgeLen;
+            minThickness[pointI] = relMinThickness[pointI]*edgeLen;
         }
         else
         {
-            scalar invExpansion = 1.0 / expansionRatio;
+            scalar invExpansion = 1.0 / expansionRatio[pointI];
             label nLay = patchNLayers[pointI];
-            thickness[pointI] = finalLayerRatio*edgeLen
-                * (1.0 - pow(invExpansion, nLay))
-                / (1.0 - invExpansion);
-            minThickness[pointI] = relMinThickness*edgeLen;
+            thickness[pointI] =
+                finalLayerRatio[pointI]
+              * edgeLen
+              * (1.0 - pow(invExpansion, nLay))
+              / (1.0 - invExpansion);
+            minThickness[pointI] = relMinThickness[pointI]*edgeLen;
         }
     }
 
@@ -2309,31 +2377,34 @@ void Foam::autoHexMeshDriver::getLayerCellsFaces
 
 void Foam::autoHexMeshDriver::mergePatchFacesUndo
 (
-    const dictionary& shrinkDict,
+    const layerParameters& layerParams,
     const dictionary& motionDict
 )
 {
-    const scalar featureAngle(readScalar(shrinkDict.lookup("featureAngle")));
-    scalar minCos = Foam::cos(featureAngle*mathematicalConstant::pi/180.0);
-
-    scalar concaveAngle = defaultConcaveAngle;
+    scalar minCos = Foam::cos
+    (
+        layerParams.featureAngle()
+      * mathematicalConstant::pi/180.0
+    );
 
-    if (shrinkDict.found("concaveAngle"))
-    {
-        concaveAngle = readScalar(shrinkDict.lookup("concaveAngle"));
-    }
-    scalar concaveCos = Foam::cos(concaveAngle*mathematicalConstant::pi/180.0);
+    scalar concaveCos = Foam::cos
+    (
+        layerParams.concaveAngle()
+      * mathematicalConstant::pi/180.0
+    );
 
     Info<< nl
         << "Merging all faces of a cell" << nl
         << "---------------------------" << nl
         << "    - which are on the same patch" << nl
-        << "    - which make an angle < " << featureAngle << " degrees"
+        << "    - which make an angle < " << layerParams.featureAngle()
+        << " degrees"
         << nl
         << "      (cos:" << minCos << ')' << nl
         << "    - as long as the resulting face doesn't become concave"
         << " by more than "
-        << concaveAngle << " degrees (0=straight, 180=fully concave)" << nl
+        << layerParams.concaveAngle()
+        << " degrees (0=straight, 180=fully concave)" << nl
         << endl;
 
     label nChanged = mergePatchFacesUndo(minCos, concaveCos, motionDict);
@@ -2344,80 +2415,18 @@ void Foam::autoHexMeshDriver::mergePatchFacesUndo
 
 void Foam::autoHexMeshDriver::addLayers
 (
-    const dictionary& shrinkDict,
+    const layerParameters& layerParams,
     const dictionary& motionDict,
     const label nAllowableErrors,
     motionSmoother& meshMover
 )
 {
-    // Read some more dictionary settings
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    // Min thickness per cell
-    const scalar relMinThickness(readScalar(shrinkDict.lookup("minThickness")));
-
-    // Warped faces recoginition
-    const scalar maxFaceThicknessRatio
-    (
-        readScalar(shrinkDict.lookup("maxFaceThicknessRatio"))
-    );
-    const scalar featureAngle(readScalar(shrinkDict.lookup("featureAngle")));
-
-    // Feature angle
-    const scalar minCos = Foam::cos(featureAngle*mathematicalConstant::pi/180.);
-
-    // Number of layers for to grow non-extrusion region by
-    const label nGrow(readLabel(shrinkDict.lookup("nGrow")));
-
-    //const label nSmoothDisp(readLabel(shrinkDict.lookup("nSmoothDispl")));
-    // Snapping iterations
-    const label nSnap(readLabel(shrinkDict.lookup("nSnap")));
-
-    // Mesh termination and medial axis smoothing quantities
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    const scalar minCosLayerTermination =
-        Foam::cos(0.5*featureAngle*mathematicalConstant::pi/180.);
-    const scalar expansionRatio
-    (
-        readScalar(shrinkDict.lookup("expansionRatio"))
-    );
-    const scalar finalLayerRatio
-    (
-        readScalar(shrinkDict.lookup("finalLayerRatio"))
-    );
-    const label nBufferCellsNoExtrude
-    (
-        readLabel(shrinkDict.lookup("nBufferCellsNoExtrude"))
-    );
-    const label nSmoothSurfaceNormals
-    (
-        readLabel(shrinkDict.lookup("nSmoothSurfaceNormals"))
-    );
-    const label nSmoothNormals(readLabel(shrinkDict.lookup("nSmoothNormals")));
-    const label nSmoothThickness
-    (
-        readLabel(shrinkDict.lookup("nSmoothThickness"))
-    );
-    const scalar maxThicknessToMedialRatio
-    (
-        readScalar(shrinkDict.lookup("maxThicknessToMedialRatio"))
-    );
-
-    // Medial axis setup
-
-    const scalar minMedianAxisAngle
-    (
-        readScalar(shrinkDict.lookup("minMedianAxisAngle"))
-    );
-    const scalar minMedianAxisAngleCos =
-        Foam::cos(minMedianAxisAngle*mathematicalConstant::pi/180.);
-
-
-    // Precalculate mesh edge labels for patch edges
     const indirectPrimitivePatch& pp = meshMover.patch();
     const labelList& meshPoints = pp.meshPoints();
 
+    // Precalculate mesh edge labels for patch edges
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
     labelList meshEdges(pp.nEdges());
     forAll(pp.edges(), edgeI)
     {
@@ -2449,8 +2458,9 @@ void Foam::autoHexMeshDriver::addLayers
 
     setNumLayers
     (
-        meshMover.adaptPatchIDs(),
-        pp,
+        layerParams.numLayers(),    // per patch the num layers
+        meshMover.adaptPatchIDs(),  // patches that are being moved
+        pp,                         // indirectpatch for all faces moving
 
         patchDisp,
         patchNLayers,
@@ -2477,7 +2487,7 @@ void Foam::autoHexMeshDriver::addLayers
     (
         pp,
         meshEdges,
-        minCos,
+        layerParams.featureAngle()*mathematicalConstant::pi/180.0,
 
         patchDisp,
         patchNLayers,
@@ -2494,7 +2504,7 @@ void Foam::autoHexMeshDriver::addLayers
     handleWarpedFaces
     (
         pp,
-        maxFaceThicknessRatio,
+        layerParams.maxFaceThicknessRatio(),
         edge0Len,
         cellLevel,
 
@@ -2517,7 +2527,7 @@ void Foam::autoHexMeshDriver::addLayers
 
 
     // Grow out region of non-extrusion
-    for (label i = 0; i < nGrow; i++)
+    for (label i = 0; i < layerParams.nGrow(); i++)
     {
         growNoExtrusion
         (
@@ -2528,21 +2538,24 @@ void Foam::autoHexMeshDriver::addLayers
         );
     }
 
-    // Determine point-wise layer thickness
+    // Determine (wanted) point-wise layer thickness and expansion ratio
     scalarField thickness(pp.nPoints());
     scalarField minThickness(pp.nPoints());
+    scalarField expansionRatio(pp.nPoints());
     calculateLayerThickness
     (
-        expansionRatio,
-        finalLayerRatio,
-        relMinThickness,
         pp,
+        meshMover.adaptPatchIDs(),
+        layerParams.expansionRatio(),
+        layerParams.finalLayerRatio(),
+        layerParams.minThickness(),
         cellLevel,
         patchNLayers,
         edge0Len,
 
         thickness,
-        minThickness
+        minThickness,
+        expansionRatio
     );
 
     // Calculate wall to medial axis distance for smoothing displacement
@@ -2602,9 +2615,9 @@ void Foam::autoHexMeshDriver::addLayers
     medialAxisSmoothingInfo
     (
         meshMover,
-        nSmoothNormals,
-        nSmoothSurfaceNormals,
-        minMedianAxisAngleCos,
+        layerParams.nSmoothNormals(),
+        layerParams.nSmoothSurfaceNormals(),
+        layerParams.minMedianAxisAngleCos(),
 
         dispVec,
         medialRatio,
@@ -2657,8 +2670,8 @@ void Foam::autoHexMeshDriver::addLayers
             //    debug,
             //    meshMover,
             //    -patchDisp,     // Shrink in opposite direction of addedPoints
-            //    nSmoothDisp,
-            //    nSnap
+            //    layerParams.nSmoothDisp(),
+            //    layerParams.nSnap()
             //);
 
             // Medial axis based shrinking
@@ -2666,11 +2679,11 @@ void Foam::autoHexMeshDriver::addLayers
             (
                 meshMover,
 
-                nSmoothThickness,
-                maxThicknessToMedialRatio,
+                layerParams.nSmoothThickness(),
+                layerParams.maxThicknessToMedialRatio(),
                 nAllowableErrors,
-                nSnap,
-                minCosLayerTermination,
+                layerParams.nSnap(),
+                layerParams.layerTerminationCos(),
 
                 thickness,
                 minThickness,
@@ -2735,7 +2748,7 @@ void Foam::autoHexMeshDriver::addLayers
             meshMover,
             patchNLayers,
             extrudeStatus,
-            nBufferCellsNoExtrude,
+            layerParams.nBufferCellsNoExtrude(),
             nPatchPointLayers,
             nPatchFaceLayers
         );
@@ -2747,7 +2760,7 @@ void Foam::autoHexMeshDriver::addLayers
         {
             if (patchNLayers[i] > 0)
             {
-                if (expansionRatio == 1.0)
+                if (expansionRatio[i] == 1.0)
                 {
                     firstDisp[i] = patchDisp[i]/nPatchPointLayers[i];
                 }
@@ -2755,15 +2768,15 @@ void Foam::autoHexMeshDriver::addLayers
                 {
                     label nLay = nPatchPointLayers[i];
                     scalar h =
-                        pow(expansionRatio,nLay - 1)
-                      * (mag(patchDisp[i])*(1.0 - expansionRatio))
-                      / (1.0 - pow(expansionRatio, nLay));
+                        pow(expansionRatio[i], nLay - 1)
+                      * (mag(patchDisp[i])*(1.0 - expansionRatio[i]))
+                      / (1.0 - pow(expansionRatio[i], nLay));
                     firstDisp[i] = h/mag(patchDisp[i])*patchDisp[i];
                 }
             }
         }
 
-        scalar invExpansionRatio = 1.0 / expansionRatio;
+        scalarField invExpansionRatio = 1.0 / expansionRatio;
 
         // Add topo regardless of whether extrudeStatus is extruderemove.
         // Not add layer if patchDisp is zero.
diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverSnap.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverSnap.C
index d4c72ea4dadfef698cf8ab40debe7e6b2dbed864..8e074cd05e2506da9f76c2fa877cbda00ce1246e 100644
--- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverSnap.C
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoHexMeshDriverSnap.C
@@ -37,6 +37,7 @@ Description
 #include "pointEdgePoint.H"
 #include "PointEdgeWave.H"
 #include "mergePoints.H"
+#include "snapParameters.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -95,8 +96,7 @@ Foam::Map<Foam::label> Foam::autoHexMeshDriver::getZoneBafflePatches
             label patchI = globalToPatch_[surfaces().globalRegion(surfI, 0)];
 
             Info<< "For surface "
-                << surfaces()[surfI].IOobject::name()
-                //<< surfaces().names()[surfI]
+                << surfaces().names()[surfI]
                 << " found faceZone " << fZone.name()
                 << " and patch " << mesh_.boundaryMesh()[patchI].name()
                 << endl;
@@ -712,8 +712,8 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::autoHexMeshDriver::createZoneBaffles
             if (debug_)
             {
                 const_cast<Time&>(mesh_.time())++;
-                Pout<< "Writing baffled mesh to time " << mesh_.time().timeName()
-                    << endl;
+                Pout<< "Writing baffled mesh to time "
+                    << mesh_.time().timeName() << endl;
                 mesh_.write();
             }
         }
@@ -755,14 +755,10 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::autoHexMeshDriver::mergeZoneBaffles
 
 Foam::scalarField Foam::autoHexMeshDriver::calcSnapDistance
 (
-    const dictionary& snapDict,
+    const snapParameters& snapParams,
     const indirectPrimitivePatch& pp
 ) const
 {
-    // When to snap
-    scalar snapTol(readScalar(snapDict.lookup("snapTol")));
-
-
     const edgeList& edges = pp.edges();
     const labelListList& pointEdges = pp.pointEdges();
     const pointField& localPoints = pp.localPoints();
@@ -793,7 +789,7 @@ Foam::scalarField Foam::autoHexMeshDriver::calcSnapDistance
         false               // no separation
     );
 
-    return snapTol*maxEdgeLen;
+    return snapParams.snapTol()*maxEdgeLen;
 }
 
 
@@ -801,7 +797,7 @@ Foam::scalarField Foam::autoHexMeshDriver::calcSnapDistance
 Foam::labelList Foam::autoHexMeshDriver::getSurfacePatches() const
 {
     // Set of patches originating from surface
-    labelHashSet surfacePatchSet(surfaces().size());
+    labelHashSet surfacePatchSet(globalToPatch_.size());
 
     forAll(globalToPatch_, i)
     {
@@ -826,21 +822,21 @@ Foam::labelList Foam::autoHexMeshDriver::getSurfacePatches() const
 
 void Foam::autoHexMeshDriver::preSmoothPatch
 (
-    const dictionary& snapDict,
+    const snapParameters& snapParams,
     const label nInitErrors,
     const List<labelPair>& baffles,
     motionSmoother& meshMover
 ) const
 {
-    // Smoothing iterations
-    label nSmoothPatch(readLabel(snapDict.lookup("nSmoothPatch")));
-    // Snapping iterations
-    label nSnap(readLabel(snapDict.lookup("nSnap")));
-
     labelList checkFaces;
 
     Info<< "Smoothing patch points ..." << endl;
-    for (label smoothIter = 0; smoothIter < nSmoothPatch; smoothIter++)
+    for
+    (
+        label smoothIter = 0;
+        smoothIter < snapParams.nSmoothPatch();
+        smoothIter++
+    )
     {
         Info<< "Smoothing iteration " << smoothIter << endl;
         checkFaces.setSize(mesh_.nFaces());
@@ -857,11 +853,11 @@ void Foam::autoHexMeshDriver::preSmoothPatch
 
         scalar oldErrorReduction = -1;
 
-        for (label snapIter = 0; snapIter < 2*nSnap; snapIter++)
+        for (label snapIter = 0; snapIter < 2*snapParams.nSnap(); snapIter++)
         {
             Info<< nl << "Scaling iteration " << snapIter << endl;
 
-            if (snapIter == nSnap)
+            if (snapIter == snapParams.nSnap())
             {
                 Info<< "Displacement scaling for error reduction set to 0."
                     << endl;
@@ -901,6 +897,56 @@ void Foam::autoHexMeshDriver::preSmoothPatch
 }
 
 
+// Get (pp-local) indices of points that are both on zone and on patched surface
+Foam::labelList Foam::autoHexMeshDriver::getZoneSurfacePoints
+(
+    const indirectPrimitivePatch& pp,
+    const word& zoneName
+) const
+{
+    label zoneI = mesh_.faceZones().findZoneID(zoneName);
+
+    if (zoneI == -1)
+    {
+        FatalErrorIn
+        (
+            "autoHexMeshDriver::getZoneSurfacePoints"
+            "(const indirectPrimitivePatch&, const word&)"
+        )   << "Cannot find zone " << zoneName
+            << exit(FatalError);
+    }
+
+    const faceZone& fZone = mesh_.faceZones()[zoneI];
+
+
+    // Could use PrimitivePatch & localFaces to extract points but might just
+    // as well do it ourselves.
+
+    boolList pointOnZone(pp.nPoints(), false);
+
+    forAll(fZone, i)
+    {
+        const face& f = mesh_.faces()[fZone[i]];
+
+        forAll(f, fp)
+        {
+            label meshPointI = f[fp];
+
+            Map<label>::const_iterator iter =
+                pp.meshPointMap().find(meshPointI);
+
+            if (iter != pp.meshPointMap().end())
+            {
+                label pointI = iter();
+                pointOnZone[pointI] = true;
+            }
+        }
+    }
+
+    return findIndices(pointOnZone, true);
+}
+
+
 Foam::vectorField Foam::autoHexMeshDriver::calcNearestSurface
 (
     const scalarField& snapDist,
@@ -925,33 +971,40 @@ Foam::vectorField Foam::autoHexMeshDriver::calcNearestSurface
     // 1. All points to non-interface surfaces
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    forAll(localPoints, pointI)
     {
-        pointIndexHit pHit;
-
-        label surfI = surfaces().findNearest
+        List<pointIndexHit> hitInfo;
+        labelList hitSurface;
+        surfaces().findNearest
         (
             unzonedSurfaces,
-            localPoints[pointI],
-            sqr(4*snapDist[pointI]),            // sqr of attract distance
-            pHit
+            localPoints,
+            sqr(4*snapDist),        // sqr of attract distance
+            hitSurface,
+            hitInfo
         );
 
-        if (surfI != -1)
+        forAll(hitInfo, pointI)
         {
-            patchDisp[pointI] = pHit.hitPoint() - localPoints[pointI];
+            if (hitInfo[pointI].hit())
+            {
+                patchDisp[pointI] =
+                    hitInfo[pointI].hitPoint()
+                  - localPoints[pointI];
+            }
+            //else
+            //{
+            //   WarningIn("autoHexMeshDriver::calcNearestSurface(..)")
+            //        << "For point:" << pointI
+            //        << " coordinate:" << localPoints[pointI]
+            //        << " did not find any surface within:"
+            //        << 4*snapDist[pointI]
+            //        << " meter." << endl;
+            //}
         }
-        //else
-        //{
-        //   WarningIn("autoHexMeshDriver::calcNearestSurface(..)")
-        //        << "For point:" << pointI
-        //        << " coordinate:" << localPoints[pointI]
-        //        << " did not find any surface within:" << 4*snapDist[pointI]
-        //        << " meter." << endl;
-        //}
     }
 
 
+
     // 2. All points on zones to their respective surface
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -964,50 +1017,50 @@ Foam::vectorField Foam::autoHexMeshDriver::calcNearestSurface
 
         const labelList surfacesToTest(1, zoneSurfI);
 
-        label zoneI = mesh_.faceZones().findZoneID(faceZoneNames[zoneSurfI]);
-
-        const faceZone& fZone = mesh_.faceZones()[zoneI];
+        // Get indices of points both on faceZone and on pp.
+        labelList zonePointIndices
+        (
+            getZoneSurfacePoints
+            (
+                pp,
+                faceZoneNames[zoneSurfI]
+            )
+        );
 
-        forAll(fZone, i)
+        pointField zonePoints(zonePointIndices.size());
+        forAll(zonePointIndices, i)
         {
-            const face& f = mesh_.faces()[fZone[i]];
-
-            forAll(f, fp)
-            {
-                label meshPointI = f[fp];
-
-                Map<label>::const_iterator iter =
-                    pp.meshPointMap().find(meshPointI);
-
-                if (iter != pp.meshPointMap().end())
-                {
-                    label pointI = iter();
-
-                    pointIndexHit pHit;
+            zonePoints[i] = localPoints[zonePointIndices[i]];
+        }
 
-                    label surfI = surfaces().findNearest
-                    (
-                        surfacesToTest,
-                        localPoints[pointI],
-                        sqr(4*snapDist[pointI]),    // sqr of attract distance
-                        pHit
-                    );
+        // Find nearest for points both on faceZone and pp.
+        List<pointIndexHit> hitInfo;
+        labelList hitSurface;
+        surfaces().findNearest
+        (
+            labelList(1, zoneSurfI),
+            zonePoints,
+            sqr(4*snapDist),
+            hitSurface,
+            hitInfo
+        );
 
-                    if (surfI != -1)
-                    {
-                        patchDisp[pointI] =
-                            pHit.hitPoint() - localPoints[pointI];
-                    }
-                    else
-                    {
-                        WarningIn("autoHexMeshDriver::calcNearestSurface(..)")
-                            << "For point:" << pointI
-                            << " coordinate:" << localPoints[pointI]
-                            << " did not find any surface within:"
-                            << 4*snapDist[pointI]
-                            << " meter." << endl;
-                    }
-                }
+        forAll(hitInfo, pointI)
+        {
+            if (hitInfo[pointI].hit())
+            {
+                patchDisp[pointI] =
+                    hitInfo[pointI].hitPoint()
+                  - localPoints[pointI];
+            }
+            else
+            {
+                WarningIn("autoHexMeshDriver::calcNearestSurface(..)")
+                    << "For point:" << pointI
+                    << " coordinate:" << localPoints[pointI]
+                    << " did not find any surface within:"
+                    << 4*snapDist[pointI]
+                    << " meter." << endl;
             }
         }
     }
@@ -1078,7 +1131,7 @@ Foam::vectorField Foam::autoHexMeshDriver::calcNearestSurface
 
 void Foam::autoHexMeshDriver::smoothDisplacement
 (
-    const dictionary& snapDict,
+    const snapParameters& snapParams,
     motionSmoother& meshMover
 ) const
 {
@@ -1087,9 +1140,6 @@ void Foam::autoHexMeshDriver::smoothDisplacement
 
     Info<< "Smoothing displacement ..." << endl;
 
-    // Smoothing iterations
-    label nSmoothDisp(readLabel(snapDict.lookup("nSmoothDispl")));
-
     // Set edge diffusivity as inverse of distance to patch
     scalarField edgeGamma(1.0/(edgePatchDist(pMesh, pp) + SMALL));
     //scalarField edgeGamma(mesh_.nEdges(), 1.0);
@@ -1098,7 +1148,7 @@ void Foam::autoHexMeshDriver::smoothDisplacement
     // Get displacement field
     pointVectorField& disp = meshMover.displacement();
 
-    for (label iter = 0; iter < nSmoothDisp; iter++)
+    for (label iter = 0; iter < snapParams.nSmoothDispl(); iter++)
     {
         if ((iter % 10) == 0)
         {
@@ -1140,16 +1190,12 @@ void Foam::autoHexMeshDriver::smoothDisplacement
 
 void Foam::autoHexMeshDriver::scaleMesh
 (
-    const dictionary& snapDict,
+    const snapParameters& snapParams,
     const label nInitErrors,
     const List<labelPair>& baffles,
     motionSmoother& meshMover
 )
 {
-    // Snapping iterations
-    label nSnap(readLabel(snapDict.lookup("nSnap")));
-
-
     // Relax displacement until correct mesh
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     labelList checkFaces(identity(mesh_.nFaces()));
@@ -1157,11 +1203,11 @@ void Foam::autoHexMeshDriver::scaleMesh
     scalar oldErrorReduction = -1;
 
     Info<< "Moving mesh ..." << endl;
-    for (label iter = 0; iter < 2*nSnap; iter++)
+    for (label iter = 0; iter < 2*snapParams.nSnap(); iter++)
     {
         Info<< nl << "Iteration " << iter << endl;
 
-        if (iter == nSnap)
+        if (iter == snapParams.nSnap())
         {
             Info<< "Displacement scaling for error reduction set to 0." << endl;
             oldErrorReduction = meshMover.setErrorReduction(0.0);
diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C
new file mode 100644
index 0000000000000000000000000000000000000000..1d3a18714a0510dc70a15f85eb1e26df440f4eba
--- /dev/null
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C
@@ -0,0 +1,213 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "layerParameters.H"
+#include "polyBoundaryMesh.H"
+#include "mathematicalConstants.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+const Foam::scalar Foam::layerParameters::defaultConcaveAngle = 90;
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Construct from dictionary
+Foam::layerParameters::layerParameters
+(
+    const dictionary& dict,
+    const labelList& numLayers
+)
+:
+    numLayers_(numLayers),
+    expansionRatio_
+    (
+        numLayers_.size(),
+        readScalar(dict.lookup("expansionRatio"))
+    ),
+    finalLayerRatio_
+    (
+        numLayers_.size(),
+        readScalar(dict.lookup("finalLayerRatio"))
+    ),
+    minThickness_
+    (
+        numLayers_.size(),
+        readScalar(dict.lookup("minThickness"))
+    ),
+    featureAngle_(readScalar(dict.lookup("featureAngle"))),
+    concaveAngle_
+    (
+        dict.found("concaveAngle")
+      ? readScalar(dict.lookup("concaveAngle"))
+      : defaultConcaveAngle
+    ),
+    nGrow_(readLabel(dict.lookup("nGrow"))),
+    nSmoothSurfaceNormals_
+    (
+        readLabel(dict.lookup("nSmoothSurfaceNormals"))
+    ),
+    nSmoothNormals_(readLabel(dict.lookup("nSmoothNormals"))),
+    nSmoothThickness_(readLabel(dict.lookup("nSmoothThickness"))),
+    maxFaceThicknessRatio_
+    (
+        readScalar(dict.lookup("maxFaceThicknessRatio"))
+    ),
+    layerTerminationCos_
+    (
+        Foam::cos
+        (
+            0.5
+          * featureAngle_
+          * mathematicalConstant::pi/180.
+        )
+    ),
+    maxThicknessToMedialRatio_
+    (
+        readScalar(dict.lookup("maxThicknessToMedialRatio"))
+    ),
+    minMedianAxisAngleCos_
+    (
+        Foam::cos(readScalar(dict.lookup("minMedianAxisAngle")))
+      * mathematicalConstant::pi/180.
+    ),
+    nBufferCellsNoExtrude_
+    (
+        readLabel(dict.lookup("nBufferCellsNoExtrude"))
+    ),
+    nSnap_(readLabel(dict.lookup("nSnap")))
+{}
+
+
+// Construct from dictionary
+Foam::layerParameters::layerParameters
+(
+    const dictionary& dict,
+    const polyBoundaryMesh& boundaryMesh
+)
+:
+    numLayers_(boundaryMesh.size(), 0),
+    expansionRatio_
+    (
+        boundaryMesh.size(),
+        readScalar(dict.lookup("expansionRatio"))
+    ),
+    finalLayerRatio_
+    (
+        boundaryMesh.size(),
+        readScalar(dict.lookup("finalLayerRatio"))
+    ),
+    minThickness_
+    (
+        boundaryMesh.size(),
+        readScalar(dict.lookup("minThickness"))
+    ),
+    featureAngle_(readScalar(dict.lookup("featureAngle"))),
+    concaveAngle_
+    (
+        dict.found("concaveAngle")
+      ? readScalar(dict.lookup("concaveAngle"))
+      : defaultConcaveAngle
+    ),
+    nGrow_(readLabel(dict.lookup("nGrow"))),
+    nSmoothSurfaceNormals_
+    (
+        readLabel(dict.lookup("nSmoothSurfaceNormals"))
+    ),
+    nSmoothNormals_(readLabel(dict.lookup("nSmoothNormals"))),
+    nSmoothThickness_(readLabel(dict.lookup("nSmoothThickness"))),
+    maxFaceThicknessRatio_
+    (
+        readScalar(dict.lookup("maxFaceThicknessRatio"))
+    ),
+    layerTerminationCos_
+    (
+        Foam::cos
+        (
+            0.5
+          * featureAngle_
+          * mathematicalConstant::pi/180.
+        )
+    ),
+    maxThicknessToMedialRatio_
+    (
+        readScalar(dict.lookup("maxThicknessToMedialRatio"))
+    ),
+    minMedianAxisAngleCos_
+    (
+        Foam::cos(readScalar(dict.lookup("minMedianAxisAngle")))
+      * mathematicalConstant::pi/180.
+    ),
+    nBufferCellsNoExtrude_
+    (
+        readLabel(dict.lookup("nBufferCellsNoExtrude"))
+    ),
+    nSnap_(readLabel(dict.lookup("nRelaxIter")))
+{
+    const dictionary& layersDict = dict.subDict("layers");
+
+    forAllConstIter(dictionary, layersDict, iter)
+    {
+        const word& key = iter().keyword();
+
+        if (layersDict.isDict(key))
+        {
+            label patchI = boundaryMesh.findPatchID(key);
+
+            if (patchI == -1)
+            {
+                FatalErrorIn
+                (
+                    "layerParameters::layerParameters"
+                    "(const dictionary&, const polyBoundaryMesh&)"
+                )   << "Specified illegal patch " << key
+                    << " in layer dictionary." << endl
+                    << "Valid patch names are " << boundaryMesh.names()
+                    << exit(FatalError);
+            }
+
+            const dictionary& layerDict = layersDict.subDict(key);
+
+            numLayers_[patchI] =
+                readLabel(layerDict.lookup("nSurfaceLayers"));
+
+            //- Patch-wise layer parameters disabled for now. Just remove
+            //  settings in initialiser list and uncomment below.
+            //expansionRatio_[patchI] =
+            //    readScalar(layerDict.lookup("expansionRatio"));
+            //finalLayerRatio_[patchI] =
+            //    readScalar(layerDict.lookup("finalLayerRatio"));
+            //minThickness_[patchI] =
+            //    readScalar(layerDict.lookup("minThickness"));
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+
+// ************************************************************************* //
diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.H
new file mode 100644
index 0000000000000000000000000000000000000000..9c16e271161f31320b5347adaac64a8aec6fb4ba
--- /dev/null
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.H
@@ -0,0 +1,246 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::layerParameters
+
+Description
+    Simple container to keep together layer specific information.
+
+SourceFiles
+    layerParameters.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef layerParameters_H
+#define layerParameters_H
+
+#include "dictionary.H"
+#include "scalarField.H"
+#include "labelList.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Class forward declarations
+class polyBoundaryMesh;
+
+/*---------------------------------------------------------------------------*\
+                           Class layerParameters Declaration
+\*---------------------------------------------------------------------------*/
+
+class layerParameters
+{
+    // Static data members
+
+        //- Default angle for faces to be convcave
+        static const scalar defaultConcaveAngle;
+
+
+    // Private data
+
+        // Per patch (not region!) information
+
+            //- How many layers to add.
+            labelList numLayers_;
+
+            scalarField expansionRatio_;
+
+            //- Wanted thickness of final added cell layer. If multiple layers
+            //  is the thickness of the layer furthest away from the wall.
+            //  Relative to undistorted size of cell outside layer.
+            scalarField finalLayerRatio_;
+
+            //- Minimum thickness of cell layer. If for any reason layer
+            //  cannot be above minThickness do not add layer.
+            //  Relative to undistorted size of cell outside layer.
+            scalarField minThickness_;
+
+
+        scalar featureAngle_;
+
+        scalar concaveAngle_;
+
+        label nGrow_;
+
+        label nSmoothSurfaceNormals_;
+
+        label nSmoothNormals_;
+
+        label nSmoothThickness_;
+
+        scalar maxFaceThicknessRatio_;
+
+        scalar layerTerminationCos_;
+
+        scalar maxThicknessToMedialRatio_;
+
+        scalar minMedianAxisAngleCos_;
+
+        label nBufferCellsNoExtrude_;
+
+        label nSnap_;
+
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        layerParameters(const layerParameters&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const layerParameters&);
+
+
+public:
+
+    // Constructors
+
+        //- Construct from dictionary - old syntax
+        layerParameters(const dictionary& dict, const labelList& numLayers);
+
+        //- Construct from dictionary - new syntax
+        layerParameters(const dictionary& dict, const polyBoundaryMesh&);
+
+
+    // Member Functions
+
+        // Access
+
+            // Per patch information
+
+                //- How many layers to add.
+                const labelList& numLayers() const
+                {
+                    return numLayers_;
+                }
+
+                // Expansion factor for layer mesh
+                const scalarField& expansionRatio() const
+                {
+                    return expansionRatio_;
+                }
+
+                //- Wanted thickness of final added cell layer. If multiple
+                //  layers
+                //  is the thickness of the layer furthest away from the wall.
+                //  Relative to undistorted size of cell outside layer.
+                const scalarField& finalLayerRatio() const
+                {
+                    return finalLayerRatio_;
+                }
+
+                //- Minimum thickness of cell layer. If for any reason layer
+                //  cannot be above minThickness do not add layer.
+                //  Relative to undistorted size of cell outside layer.
+                const scalarField& minThickness() const
+                {
+                    return minThickness_;
+                }
+
+
+            scalar featureAngle() const
+            {
+                return featureAngle_;
+            }
+
+            scalar concaveAngle() const
+            {
+                return concaveAngle_;
+            }
+
+            //- If points get not extruded do nGrow layers of connected faces
+            //  that are not grown. Is used to not do layers at all close to
+            //  features.
+            label nGrow() const
+            {
+                return nGrow_;
+            }
+
+            // Number of smoothing iterations of surface normals 
+            label nSmoothSurfaceNormals() const
+            {
+                return nSmoothSurfaceNormals_;
+            }
+
+            // Number of smoothing iterations of interior mesh movement
+            // direction  
+            label nSmoothNormals() const
+            {
+                return nSmoothNormals_;
+            }
+
+            // Smooth layer thickness over surface patches
+            label nSmoothThickness() const
+            {
+                return nSmoothThickness_;
+            }
+
+            // Stop layer growth on highly warped cells 
+            scalar maxFaceThicknessRatio() const
+            {
+                return maxFaceThicknessRatio_;
+            }
+
+            scalar layerTerminationCos() const
+            {
+                return layerTerminationCos_;
+            }
+
+            // Reduce layer growth where ratio thickness to medial 
+            // distance is large 
+            scalar maxThicknessToMedialRatio() const
+            {
+                return maxThicknessToMedialRatio_;
+            }
+
+            // Angle used to pick up medial axis points
+            scalar minMedianAxisAngleCos() const
+            {
+                return minMedianAxisAngleCos_;
+            }
+
+            // Create buffer region for new layer terminations
+            label nBufferCellsNoExtrude() const
+            {
+                return nBufferCellsNoExtrude_;
+            }
+
+            label nSnap() const
+            {
+                return nSnap_;
+            }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.C
new file mode 100644
index 0000000000000000000000000000000000000000..7912279e017eefb0d30f3a56af5a7526d112abf3
--- /dev/null
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.C
@@ -0,0 +1,123 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "refinementParameters.H"
+#include "mathematicalConstants.H"
+#include "polyMesh.H"
+#include "globalIndex.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Construct from dictionary
+Foam::refinementParameters::refinementParameters
+(
+    const dictionary& dict,
+    const label dummy
+)
+:
+    maxGlobalCells_(readLabel(dict.lookup("cellLimit"))),
+    maxLocalCells_(readLabel(dict.lookup("procCellLimit"))),
+    minRefineCells_(readLabel(dict.lookup("minimumRefine"))),
+    curvature_(readScalar(dict.lookup("curvature"))),
+    nBufferLayers_(readLabel(dict.lookup("nBufferLayers"))),
+    keepPoints_(dict.lookup("keepPoints"))
+{}
+
+
+Foam::refinementParameters::refinementParameters(const dictionary& dict)
+:
+    maxGlobalCells_(readLabel(dict.lookup("maxGlobalCells"))),
+    maxLocalCells_(readLabel(dict.lookup("maxLocalCells"))),
+    minRefineCells_(readLabel(dict.lookup("minRefinementCells"))),
+    nBufferLayers_(readLabel(dict.lookup("nCellsBetweenLevels"))),
+    keepPoints_(pointField(1, dict.lookup("locationInMesh")))
+{
+    scalar featAngle(readScalar(dict.lookup("resolveFeatureAngle")));
+
+    if (featAngle < 0 || featAngle > 180)
+    {
+        curvature_ = -GREAT;
+    }
+    else
+    {
+        curvature_ = Foam::cos(featAngle*mathematicalConstant::pi/180.0);
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::labelList Foam::refinementParameters::findCells(const polyMesh& mesh)
+ const
+{
+    // Global calculation engine
+    globalIndex globalCells(mesh.nCells());
+
+    // Cell label per point
+    labelList cellLabels(keepPoints_.size());
+
+    forAll(keepPoints_, i)
+    {
+        const point& keepPoint = keepPoints_[i];
+
+        label localCellI = mesh.findCell(keepPoint);
+
+        label globalCellI = -1;
+
+        if (localCellI != -1)
+        {
+            Pout<< "Found point " << keepPoint << " in cell " << localCellI
+                << " on processor " << Pstream::myProcNo() << endl;
+            globalCellI = globalCells.toGlobal(localCellI);
+        }
+
+        reduce(globalCellI, maxOp<label>());
+
+        if (globalCellI == -1)
+        {
+            FatalErrorIn
+            (
+                "refinementParameters::findCells(const polyMesh&) const"
+            )   << "Point " << keepPoint
+                << " is not inside the mesh or on a face or edge." << nl
+                << "Bounding box of the mesh:" << mesh.bounds()
+                << exit(FatalError);
+        }
+
+        if (globalCells.isLocal(globalCellI))
+        {
+            cellLabels[i] = localCellI;
+        }
+        else
+        {
+            cellLabels[i] = -1;
+        }
+    }
+    return cellLabels;
+}
+
+
+// ************************************************************************* //
diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.H
new file mode 100644
index 0000000000000000000000000000000000000000..25b97af0346fa6afb41d8e90297502a69493232d
--- /dev/null
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.H
@@ -0,0 +1,154 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::refinementParameters
+
+Description
+    Simple container to keep together refinement specific information.
+
+SourceFiles
+    refinementParameters.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef refinementParameters_H
+#define refinementParameters_H
+
+#include "dictionary.H"
+#include "pointField.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Class forward declarations
+class polyMesh;
+
+/*---------------------------------------------------------------------------*\
+                           Class refinementParameters Declaration
+\*---------------------------------------------------------------------------*/
+
+class refinementParameters
+{
+    // Private data
+
+        //- Total number of cells
+        const label maxGlobalCells_;
+
+        //- Per processor max number of cells
+        const label maxLocalCells_;
+
+        //- When to stop refining
+        const label minRefineCells_;
+
+        //- Curvature
+        scalar curvature_;
+
+        //- Number of layers between different refinement levels
+        const label nBufferLayers_;
+
+        //- Areas to keep
+        const pointField keepPoints_;
+
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        refinementParameters(const refinementParameters&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const refinementParameters&);
+
+
+public:
+
+    // Constructors
+
+        //- Construct from dictionary - old syntax
+        refinementParameters(const dictionary& dict, const label dummy);
+
+        //- Construct from dictionary - new syntax
+        refinementParameters(const dictionary& dict);
+
+
+    // Member Functions
+
+        // Access
+
+            //- Total number of cells
+            label maxGlobalCells() const
+            {
+                return maxGlobalCells_;
+            }
+
+            //- Per processor max number of cells
+            label maxLocalCells() const
+            {
+                return maxLocalCells_;
+            }
+
+            //- When to stop refining
+            label minRefineCells() const
+            {
+                return minRefineCells_;
+            }
+
+            //- Curvature
+            scalar curvature() const
+            {
+                return curvature_;
+            }
+
+            //- Number of layers between different refinement levels
+            label nBufferLayers() const
+            {
+                return nBufferLayers_;
+            }
+
+            //- Areas to keep
+            const pointField& keepPoints() const
+            {
+                return keepPoints_;
+            }
+
+
+        // Other
+
+            //- Checks that cells are in mesh. Returns cells they are in.
+            labelList findCells(const polyMesh&) const;
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/snapParameters/snapParameters.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/snapParameters/snapParameters.C
new file mode 100644
index 0000000000000000000000000000000000000000..253826c38fddfdb52c106951353469ee46f21c3c
--- /dev/null
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/snapParameters/snapParameters.C
@@ -0,0 +1,54 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "snapParameters.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Construct from dictionary
+Foam::snapParameters::snapParameters(const dictionary& dict, const label dummy)
+:
+    nSmoothPatch_(readLabel(dict.lookup("nSmoothPatch"))),
+    snapTol_(readScalar(dict.lookup("snapTol"))),
+    nSmoothDispl_(readLabel(dict.lookup("nSmoothDispl"))),
+    nSnap_(readLabel(dict.lookup("nSnap")))
+{}
+
+
+// Construct from dictionary
+Foam::snapParameters::snapParameters(const dictionary& dict)
+:
+    nSmoothPatch_(readLabel(dict.lookup("nSmoothPatch"))),
+    snapTol_(readScalar(dict.lookup("tolerance"))),
+    nSmoothDispl_(readLabel(dict.lookup("nSolveIter"))),
+    nSnap_(readLabel(dict.lookup("nRelaxIter")))
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+
+// ************************************************************************* //
diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/snapParameters/snapParameters.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/snapParameters/snapParameters.H
new file mode 100644
index 0000000000000000000000000000000000000000..2a173578b0c5e336e8fe888d2b63c35b8346287c
--- /dev/null
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/snapParameters/snapParameters.H
@@ -0,0 +1,129 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::snapParameters
+
+Description
+    Simple container to keep together snap specific information.
+
+SourceFiles
+    snapParameters.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef snapParameters_H
+#define snapParameters_H
+
+#include "dictionary.H"
+#include "scalar.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Class forward declarations
+
+/*---------------------------------------------------------------------------*\
+                           Class snapParameters Declaration
+\*---------------------------------------------------------------------------*/
+
+class snapParameters
+{
+    // Private data
+
+        const label nSmoothPatch_;
+
+        const scalar snapTol_;
+
+        const label nSmoothDispl_;
+
+        const label nSnap_;
+
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        snapParameters(const snapParameters&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const snapParameters&);
+
+
+public:
+
+    // Constructors
+
+        //- Construct from dictionary - old syntax
+        snapParameters(const dictionary& dict, const label dummy);
+
+        //- Construct from dictionary - new syntax
+        snapParameters(const dictionary& dict);
+
+
+    // Member Functions
+
+        // Access
+
+            //- Number of patch smoothing iterations before finding
+            //  correspondence to surface
+            label nSmoothPatch() const
+            {
+                return nSmoothPatch_;
+            }
+
+            //- Relative distance for points to be attracted by surface
+            //  feature point
+            //  or edge. True distance is this factor times local
+            //  maximum edge length.
+            scalar snapTol() const
+            {
+                return snapTol_;
+            }
+
+            //- Number of mesh displacement smoothing iterations.
+            label nSmoothDispl() const
+            {
+                return nSmoothDispl_;
+            }
+
+            //- Maximum number of snapping relaxation iterations. Should stop
+            //  before upon reaching a correct mesh.
+            label nSnap() const
+            {
+                return nSnap_;
+            }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C
index 8b9869ad57f0b28b9cf0a8a7df5ce2940ead8d73..a60e7758da89da4ce2da8b00b86515e1225f8195 100644
--- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C
+++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C
@@ -24,9 +24,7 @@ License
 
 \*----------------------------------------------------------------------------*/
 
-#include "Pstream.H"
 #include "meshRefinement.H"
-
 #include "volMesh.H"
 #include "volFields.H"
 #include "surfaceMesh.H"
@@ -34,7 +32,6 @@ License
 #include "Time.H"
 #include "refinementHistory.H"
 #include "refinementSurfaces.H"
-#include "cellSet.H"
 #include "decompositionMethod.H"
 #include "regionSplit.H"
 #include "fvMeshDistribute.H"
@@ -50,8 +47,9 @@ License
 #include "globalPointPatchFields.H"
 #include "calculatedPointPatchFields.H"
 #include "processorPointPatch.H"
-#include "featureEdgeMesh.H"
 #include "globalIndex.H"
+#include "meshTools.H"
+#include "OFstream.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -117,90 +115,6 @@ void Foam::meshRefinement::calcNeighbourData
 }
 
 
-//void Foam::meshRefinement::calcCanonicalBoundaryData
-//(
-//    labelList& leftLevel,
-//    pointField& leftCc,
-//    labelList& rightLevel,
-//    pointField& rightCc
-//)  const
-//{
-//    const labelList& cellLevel = meshCutter_.cellLevel();
-//    const pointField& cellCentres = mesh_.cellCentres();
-//    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
-//
-//    // Get boundary face centre and level. Coupled aware.
-//    calcNeighbourData(rightLevel, rightCc);
-//
-//    // Get owner face centre and level. Canonical sort for coupled faces.
-//    forAll(patches, patchI)
-//    {
-//        const polyPatch& pp = patches[patchI];
-//
-//        const unallocLabelList& faceCells = pp.faceCells();
-//        const vectorField::subField faceCentres = pp.faceCentres();
-//
-//        if (isA<processorPolyPatch>(pp))
-//        {
-//            const processorPolyPatch& procPp =
-//                refCast<const processorPolyPatch>(patches[patchI]);
-//
-//            label bFaceI = pp.start()-mesh_.nInternalFaces();
-//            forAll(faceCells, i)
-//            {
-//                leftLevel[bFaceI] = cellLevel[faceCells[i]];
-//                leftCc[bFaceI] = cellCentres[faceCells[i]];
-//                bFaceI++;
-//            }
-//
-//            // Swap if on neighbour so both sides have same values
-//            if (!procPp.owner())
-//            {
-//                forAll(leftLevel, i)
-//                {
-//                    Swap(leftLevel[i], rightLevel[i]);
-//                    Swap(leftCc[i], rightCc[i]);
-//                }
-//            }
-//        }
-//        else if (isA<cyclicPolyPatch>(pp))
-//        {
-//            const processorPolyPatch& cycPp =
-//                refCast<const processorPolyPatch>(patches[patchI]);
-//
-//            label bFaceI = pp.start()-mesh_.nInternalFaces();
-//            forAll(faceCells, i)
-//            {
-//                leftLevel[bFaceI] = cellLevel[faceCells[i]];
-//                leftCc[bFaceI] = cellCentres[faceCells[i]];
-//                bFaceI++;
-//            }
-//
-//            // First half has data in normal order: owner in leftLevel,leftCc
-//            // and coupled data in rightLevel, rightCc. Second half has it
-//            // swapped:
-//            bFaceI = pp.start()+cycPp.size()/2-mesh_.nInternalFaces();
-//            for (label i = 0; i < cycPp.size()/2; i++)
-//            {
-//                Swap(leftLevel[bFaceI], rightLevel[bFaceI]);
-//                Swap(leftCc[bFaceI], rightCc[bFaceI]);
-//                bFaceI++;
-//            }
-//        }
-//        else
-//        {
-//            label bFaceI = pp.start()-mesh_.nInternalFaces();
-//            forAll(faceCells, i)
-//            {
-//                leftLevel[bFaceI] = cellLevel[faceCells[i]];
-//                leftCc[bFaceI] = cellCentres[faceCells[i]];
-//                bFaceI++;
-//            }
-//        }
-//    }
-//}
-
-
 // Find intersections of edges (given by their two endpoints) with surfaces.
 // Returns first intersection if there are more than one.
 void Foam::meshRefinement::updateIntersections(const labelList& changedFaces)
@@ -220,33 +134,46 @@ void Foam::meshRefinement::updateIntersections(const labelList& changedFaces)
     pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
     calcNeighbourData(neiLevel, neiCc);
 
+    // Collect segments we want to test for
+    pointField start(changedFaces.size());
+    pointField end(changedFaces.size());
+
     forAll(changedFaces, i)
     {
         label faceI = changedFaces[i];
         label own = mesh_.faceOwner()[faceI];
 
-        pointIndexHit surfaceHitInfo;
-
+        start[i] = cellCentres[own];
         if (mesh_.isInternalFace(faceI))
         {
-            surfaceIndex_[faceI] = surfaces_.findAnyIntersection
-            (
-                cellCentres[own],
-                cellCentres[mesh_.faceNeighbour()[faceI]],
-                surfaceHitInfo
-            );
+            end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
         }
         else
         {
-            surfaceIndex_[faceI] = surfaces_.findAnyIntersection
-            (
-                cellCentres[own],
-                neiCc[faceI-mesh_.nInternalFaces()],
-                surfaceHitInfo
-            );
+            end[i] = neiCc[faceI-mesh_.nInternalFaces()];
         }
     }
 
+    // Do tests in one go
+    labelList surfaceHit;
+    {
+        labelList surfaceLevel;
+        surfaces_.findHigherIntersection
+        (
+            start,
+            end,
+            labelList(start.size(), -1),    // accept any intersection
+            surfaceHit,
+            surfaceLevel
+        );
+    }
+
+    // Keep just surface hit
+    forAll(surfaceHit, i)
+    {
+        surfaceIndex_[changedFaces[i]] = surfaceHit[i];
+    }
+
     // Make sure both sides have same information. This should be
     // case in general since same vectors but just to make sure.
     syncTools::syncFaceList(mesh_, surfaceIndex_, maxEqOp<label>(), false);
@@ -305,67 +232,72 @@ void Foam::meshRefinement::checkData()
     }
     // Check meshRefinement
     {
-        for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
-        {
-            label own = mesh_.faceOwner()[faceI];
-            label nei = mesh_.faceNeighbour()[faceI];
-            const point& ownCc = mesh_.cellCentres()[own];
-            const point& neiCc = mesh_.cellCentres()[nei];
-
-            pointIndexHit surfaceHitInfo;
-            label surfI = surfaces_.findAnyIntersection
-            (
-                ownCc,
-                neiCc,
-                surfaceHitInfo
-            );
-
-            if (surfI != surfaceIndex_[faceI])
-            {
-                WarningIn("meshRefinement::checkData()")
-                    << "Internal face:" << faceI
-                    << " fc:" << mesh_.faceCentres()[faceI]
-                    << " cached surfaceIndex_:" << surfaceIndex_[faceI]
-                    << " current:" << surfI
-                    << " ownCc:" << ownCc << " neiCc:" << neiCc
-                    << endl;
-            }
-        }
-
         // Get boundary face centre and level. Coupled aware.
         labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
         pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
         calcNeighbourData(neiLevel, neiCc);
 
-        for
-        (
-            label faceI = mesh_.nInternalFaces();
-            faceI < mesh_.nFaces();
-            faceI++
-        )
+        // Collect segments we want to test for
+        pointField start(mesh_.nFaces());
+        pointField end(mesh_.nFaces());
+
+        forAll(start, faceI)
         {
-            label own = mesh_.faceOwner()[faceI];
-            const point& ownCc = mesh_.cellCentres()[own];
+            start[faceI] = mesh_.cellCentres()[mesh_.faceOwner()[faceI]];
 
-            pointIndexHit surfaceHitInfo;
-            label surfI = surfaces_.findAnyIntersection
+            if (mesh_.isInternalFace(faceI))
+            {
+                end[faceI] = mesh_.cellCentres()[mesh_.faceNeighbour()[faceI]];
+            }
+            else
+            {
+                end[faceI] = neiCc[faceI-mesh_.nInternalFaces()];
+            }
+        }
+
+        // Do tests in one go
+        labelList surfaceHit;
+        {
+            labelList surfaceLevel;
+            surfaces_.findHigherIntersection
             (
-                ownCc,
-                neiCc[faceI-mesh_.nInternalFaces()],
-                surfaceHitInfo
+                start,
+                end,
+                labelList(start.size(), -1),    // accept any intersection
+                surfaceHit,
+                surfaceLevel
             );
+        }
 
-            if (surfI != surfaceIndex_[faceI])
+        // Check
+        forAll(surfaceHit, faceI)
+        {
+            if (surfaceHit[faceI] != surfaceIndex_[faceI])
             {
-                WarningIn("meshRefinement::checkData()")
-                    << "Boundary face:" << faceI
-                    << " patch:" << mesh_.boundaryMesh().whichPatch(faceI)
-                    << " fc:" << mesh_.faceCentres()[faceI]
-                    << " cached surfaceIndex_:" << surfaceIndex_[faceI]
-                    << " current:" << surfI
-                    << " ownCc:" << ownCc
-                    << " neiCc:" << neiCc[faceI-mesh_.nInternalFaces()]
-                    << endl;
+                if (mesh_.isInternalFace(faceI))
+                {
+                    WarningIn("meshRefinement::checkData()")
+                        << "Internal face:" << faceI
+                        << " fc:" << mesh_.faceCentres()[faceI]
+                        << " cached surfaceIndex_:" << surfaceIndex_[faceI]
+                        << " current:" << surfaceHit[faceI]
+                        << " ownCc:"
+                        << mesh_.cellCentres()[mesh_.faceOwner()[faceI]]
+                        << " neiCc:"
+                        << mesh_.cellCentres()[mesh_.faceNeighbour()[faceI]]
+                        << endl;
+                }
+                else
+                {
+                    WarningIn("meshRefinement::checkData()")
+                        << "Boundary face:" << faceI
+                        << " fc:" << mesh_.faceCentres()[faceI]
+                        << " cached surfaceIndex_:" << surfaceIndex_[faceI]
+                        << " current:" << surfaceHit[faceI]
+                        << " ownCc:"
+                        << mesh_.cellCentres()[mesh_.faceOwner()[faceI]]
+                        << endl;
+                }
             }
         }
     }
@@ -492,283 +424,6 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::doRemoveCells
 }
 
 
-// Get which are inside any closed surface. Note that all closed surfaces
-// will have already been oriented to have keepPoint outside.
-Foam::labelList Foam::meshRefinement::getInsideCells
-(
-    const word& postfix
-) const
-{
-    const pointField& points = mesh_.points();
-
-    // This test can be done in various ways. The ultimate is the intersection
-    // of any edge of the mesh with any surface and intersection of any edge
-    // of any surface of the mesh with any mesh face.
-    // For now:
-    // - none of the edges of a cell intersects any surface
-    // - any point of the cell is inside.
-
-
-    // Is point inside any closed surface?
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    PackedList<1> pointIsInside;
-    label nPointInside = surfaces_.markInsidePoints
-    (
-       points,
-       pointIsInside
-    );
-
-    if (debug)
-    {
-        Pout<< "getInsideCells : Points internal to closed surfaces :"
-            << " local:" << nPointInside
-            << " global:" << returnReduce(nPointInside, sumOp<label>())
-            << endl;
-    }
-
-
-    // Find cells with all points inside closed surface
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    PackedList<1> cellIsInside(mesh_.nCells(), 1u);
-    label nCellInside = mesh_.nCells();
-
-    // Unmark cells with any point outside
-    forAll(points, pointI)
-    {
-        if (pointIsInside.get(pointI) == 0u)
-        {
-            // Outside point. Unmark cells.
-            const labelList& pCells = mesh_.pointCells()[pointI];
-
-            forAll(pCells, i)
-            {
-                label cellI = pCells[i];
-
-                if (cellIsInside.get(cellI) == 1u)
-                {
-                    cellIsInside.set(cellI, 0u);
-                    nCellInside--;
-                }
-            }
-        }
-    }
-
-    label totNCellInside = nCellInside;
-    reduce(totNCellInside, sumOp<label>());
-    if (debug)
-    {
-        Pout<< "getInsideCells : Cells using inside points only :"
-            << " local:" << nCellInside << " global:" << totNCellInside
-            << endl;
-    }
-
-    // Filter any cells with cc-cc edge intersection
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    const cellList& cells = mesh_.cells();
-
-    cellSet insidePoints(mesh_, "insidePoints_"+postfix, mesh_.nCells()/100);
-    cellSet insidePointsButCut
-    (
-        mesh_,
-        "insidePointsButCut_"+postfix,
-        mesh_.nCells()/100
-    );
-
-    forAll(cells, cellI)
-    {
-        if (cellIsInside.get(cellI) == 1u)
-        {
-            insidePoints.insert(cellI);
-
-            const cell& cFaces = cells[cellI];
-
-            forAll(cFaces, i)
-            {
-                if (surfaceIndex_[cFaces[i]] != -1)
-                {
-                    cellIsInside.set(cellI, 0u);
-                    nCellInside--;
-
-                    insidePointsButCut.insert(cellI);
-
-                    break;
-                }
-            }
-        }
-    }
-
-    if (debug)
-    {
-        Pout<< "getInsideCells : cells with all points inside : "
-            << insidePoints.objectPath() << endl;
-        insidePoints.write();
-        Pout<< "getInsideCells : cells with all points inside"
-            << " but intersecting (cc) surface : "
-            << insidePointsButCut.objectPath() << endl;
-        insidePointsButCut.write();
-    }
-
-    totNCellInside = nCellInside;
-    reduce(totNCellInside, sumOp<label>());
-    if (debug)
-    {
-        Pout<< "getInsideCells : After filtering cc-cc intersections :"
-            << " local:" << nCellInside << " global:" << totNCellInside
-            << endl;
-    }
-
-
-    // Filter cells with any normal edge intersection
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    cellSet insidePointsButEdge
-    (
-        mesh_,
-        "insidePointsButEdge_"+postfix,
-        mesh_.nCells()/100
-    );
-
-    const labelListList& edgeCells = mesh_.edgeCells();
-
-    forAll(edgeCells, edgeI)
-    {
-        const labelList& eCells = edgeCells[edgeI];
-
-        // Does edge use any inside cells? Prefilter since edge intersection
-        // test expensive.
-        bool edgeHasInsideCells = false;
-
-        forAll(eCells, i)
-        {
-            if (cellIsInside.get(eCells[i]) == 1u)
-            {
-                edgeHasInsideCells = true;
-                break;
-            }
-        }
-
-        if (edgeHasInsideCells)
-        {
-            const edge& e = mesh_.edges()[edgeI];
-
-            // Find any pierces of surface by mesh edge.
-            pointIndexHit hit;
-            label surfI = surfaces().findHigherIntersection
-            (
-                points[e[0]],
-                points[e[1]],
-                -1,                     // minimum level.
-                hit
-            );
-
-            if (surfI != -1)
-            {
-                // This edge intersects some surface. Unmark all cells
-                // using this edge.
-
-                forAll(eCells, i)
-                {
-                    if (cellIsInside.get(eCells[i]) == 1u)
-                    {
-                        cellIsInside.set(eCells[i], 0u);
-                        nCellInside--;
-
-                        insidePointsButEdge.insert(eCells[i]);
-                    }
-                }
-            }
-        }
-    }
-
-    if (debug)
-    {
-        Pout<< "getInsideCells : cells with all points inside"
-            << " but intersecting (edges) surface : "
-            << insidePointsButEdge.objectPath() << endl;
-        insidePointsButEdge.write();
-    }
-
-    totNCellInside = nCellInside;
-    reduce(totNCellInside, sumOp<label>());
-    if (debug)
-    {
-        Pout<< "getInsideCells : After filtering edge interesections :"
-            << " local:" << nCellInside << " global:" << totNCellInside
-            << endl;
-    }
-
-
-    // Collect cells
-    // ~~~~~~~~~~~~~
-
-    DynamicList<label> cellsToRemove(nCellInside);
-
-    forAll(cellIsInside, cellI)
-    {
-        if (cellIsInside.get(cellI) == 1u)
-        {
-            cellsToRemove.append(cellI);
-        }
-    }
-    return cellsToRemove.shrink();
-}
-
-
-// Do all to remove inside cells
-Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::removeInsideCells
-(
-    const string& msg,
-    const label exposedPatchI
-)
-{
-    labelList insideCells
-    (
-        getInsideCells
-        (
-            string::validate<word>(msg)
-        )
-    );
-
-    Info<< "Removing inside cells : "
-        << returnReduce(insideCells.size(), sumOp<label>())
-        << '.' << endl;
-
-    removeCells cellRemover(mesh_);
-
-    labelList exposedFaces(cellRemover.getExposedFaces(insideCells));
-
-    // Debug check
-    forAll(exposedFaces, i)
-    {
-        label faceI = exposedFaces[i];
-
-        if (surfaceIndex_[faceI] != -1)
-        {
-            FatalErrorIn
-            (
-                "removeInsideCells"
-                "(const label, const string&, const label)"
-            )   << "Face:" << faceI
-                << " fc:" << mesh_.faceCentres()[faceI]
-                << " is actually cutting the surface and should never have been"
-                << " included in the cells to remove."
-                << abort(FatalError);
-        }
-    }
-
-    return doRemoveCells
-    (
-        insideCells,
-        exposedFaces,
-        labelList(exposedFaces.size(), exposedPatchI),
-        cellRemover
-    );
-}
-
-
 // Determine for multi-processor regions the lowest numbered cell on the lowest
 // numbered processor.
 void Foam::meshRefinement::getRegionMaster
@@ -835,12 +490,14 @@ Foam::meshRefinement::meshRefinement
 (
     fvMesh& mesh,
     const scalar tol,
-    const refinementSurfaces& surfaces
+    const refinementSurfaces& surfaces,
+    const shellSurfaces& shells
 )
 :
     mesh_(mesh),
     tol_(tol),
     surfaces_(surfaces),
+    shells_(shells),
     meshCutter_
     (
         mesh,
@@ -926,109 +583,6 @@ Foam::label Foam::meshRefinement::countHits() const
 }
 
 
-//// Determine distribution to keep baffles together
-//Foam::labelList Foam::meshRefinement::decomposePreserveBaffles
-//(
-//    decompositionMethod& decomposer
-//) const
-//{
-//    // Find duplicate faces
-//    labelList duplicateFace
-//    (
-//        localPointRegion::findDuplicateFaces
-//        (
-//            mesh_,
-//            identity(mesh_.nFaces()-mesh_.nInternalFaces())
-//          + mesh_.nInternalFaces()
-//        )
-//    );
-//
-//
-//    // Agglomerate cells on both sides of duplicate face pair
-//
-//    const pointField& cellCentres = mesh_.cellCentres();
-//    const labelList& faceOwner = mesh_.faceOwner();
-//
-//    labelList toAgglom(mesh_.nCells(), -1);
-//    pointField agglomCellCentres(mesh_.nCells());
-//    labelList nAgglomCellCentres(mesh_.nCells(), 0);
-//
-//    label agglomI = 0;
-//
-//    // Do all baffle cells
-//    forAll(duplicateFace, i)
-//    {
-//        if (duplicateFace[i] != -1)
-//        {
-//            label own = faceOwner[i+mesh_.nInternalFaces()];
-//            label otherOwn =
-//                faceOwner[duplicateFace[i]+mesh_.nInternalFaces()];
-//
-//            if (toAgglom[own] == -1 && toAgglom[otherOwn] == -1)
-//            {
-//                // Allocate new agglomeration
-//                agglomCellCentres[agglomI] =
-//                    cellCentres[own]
-//                  + cellCentres[otherOwn];
-//                nAgglomCellCentres[agglomI] = 2;
-//                toAgglom[own] = agglomI;
-//                toAgglom[otherOwn] = agglomI;
-//                agglomI++;
-//            }
-//            else if (toAgglom[own] != -1)
-//            {
-//                // Owner already part of agglomeration. Add otherOwn to it.
-//                label destAgglom = toAgglom[own];
-//                agglomCellCentres[destAgglom] += cellCentres[otherOwn];
-//                nAgglomCellCentres[destAgglom]++;
-//                toAgglom[otherOwn] = destAgglom;
-//            }
-//            else if (toAgglom[otherOwn] != -1)
-//            {
-//                // otherOwn already part of agglomeration. Add own to it.
-//                label destAgglom = toAgglom[otherOwn];
-//                agglomCellCentres[destAgglom] += cellCentres[own];
-//                nAgglomCellCentres[destAgglom]++;
-//                toAgglom[own] = destAgglom;
-//            }
-//        }
-//    }
-//
-//    // Do all other cells
-//    forAll(toAgglom, cellI)
-//    {
-//        if (toAgglom[cellI] == -1)
-//        {
-//            agglomCellCentres[agglomI] = cellCentres[cellI];
-//            nAgglomCellCentres[agglomI] = 1;
-//            toAgglom[cellI] = agglomI;
-//            agglomI++;
-//        }
-//    }
-//
-//    // Average
-//    agglomCellCentres.setSize(agglomI);
-//
-//    forAll(agglomCellCentres, i)
-//    {
-//        agglomCellCentres[i] /= nAgglomCellCentres[i];
-//    }
-//
-//    // Decompose based on agglomerated cell centres
-//    labelList agglomDistribution(decomposer.decompose(agglomCellCentres));
-//
-//    // Rework back into decomposition for original mesh_
-//    labelList distribution(mesh_.nCells());
-//
-//    forAll(toAgglom, cellI)
-//    {
-//        distribution[cellI] = agglomDistribution[toAgglom[cellI]];
-//    }
-//
-//    return distribution;
-//}
-
-
 // Determine distribution to move connected regions onto one processor.
 Foam::labelList Foam::meshRefinement::decomposeCombineRegions
 (
@@ -1213,9 +767,8 @@ Foam::labelList Foam::meshRefinement::intersectedPoints
 
             forAll(f, fp)
             {
-                if (isBoundaryPoint.get(f[fp]) == 0u)
+                if (isBoundaryPoint.set(f[fp], 1u))
                 {
-                    isBoundaryPoint.set(f[fp], 1u);
                     nBoundaryPoints++;
                 }
             }
@@ -1239,9 +792,7 @@ Foam::labelList Foam::meshRefinement::intersectedPoints
     //
     //            forAll(f, fp)
     //            {
-    //                if (isBoundaryPoint.get(f[fp]) == 0u)
-    //                {
-    //                    isBoundaryPoint.set(f[fp], 1u);
+    //                if (isBoundaryPoint.set(f[fp], 1u))
     //                    nBoundaryPoints++;
     //                }
     //            }
@@ -1910,53 +1461,56 @@ void Foam::meshRefinement::dumpIntersections(const fileName& prefix) const
             << " Writing cellcentre-cellcentre intersections to file "
             << str.name() << endl;
 
-        // Internal faces
-        for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
-        {
-            if (surfaceIndex_[faceI] != -1)
-            {
-                const point& ownCc = cellCentres[mesh_.faceOwner()[faceI]];
-                const point& neiCc = cellCentres[mesh_.faceNeighbour()[faceI]];
 
-                // Re-intersect to get position
-                pointIndexHit surfaceHitInfo;
-                surfaces_.findAnyIntersection(ownCc, neiCc, surfaceHitInfo);
-
-                meshTools::writeOBJ(str, ownCc);
-                vertI++;
-                meshTools::writeOBJ(str, surfaceHitInfo.hitPoint());
-                vertI++;
-                meshTools::writeOBJ(str, neiCc);
-                vertI++;
-                str << "l " << vertI-2 << ' ' << vertI-1 << nl
-                    << "l " << vertI-1 << ' ' << vertI << nl;
-            }
-        }
-
-        // Boundary faces
+        // Redo all intersections
+        // ~~~~~~~~~~~~~~~~~~~~~~
 
         // Get boundary face centre and level. Coupled aware.
         labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
         pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
         calcNeighbourData(neiLevel, neiCc);
 
-        forAll(neiCc, i)
+        labelList intersectionFaces(intersectedFaces());
+
+        // Collect segments we want to test for
+        pointField start(intersectionFaces.size());
+        pointField end(intersectionFaces.size());
+
+        forAll(intersectionFaces, i)
         {
-            label faceI = i + mesh_.nInternalFaces();
+            label faceI = intersectionFaces[i];
+            start[i] = cellCentres[mesh_.faceOwner()[faceI]];
 
-            if (surfaceIndex_[faceI] != -1)
+            if (mesh_.isInternalFace(faceI))
+            {
+                end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
+            }
+            else
             {
-                const point& ownCc = cellCentres[mesh_.faceOwner()[faceI]];
+                end[i] = neiCc[faceI-mesh_.nInternalFaces()];
+            }
+        }
 
-                // Re-intersect to get position
-                pointIndexHit surfaceHitInfo;
-                surfaces_.findAnyIntersection(ownCc, neiCc[i], surfaceHitInfo);
+        // Do tests in one go
+        labelList surfaceHit;
+        List<pointIndexHit> surfaceHitInfo;
+        surfaces_.findAnyIntersection
+        (
+            start,
+            end,
+            surfaceHit,
+            surfaceHitInfo
+        );
 
-                meshTools::writeOBJ(str, ownCc);
+        forAll(intersectionFaces, i)
+        {
+            if (surfaceHit[i] != -1)
+            {
+                meshTools::writeOBJ(str, start[i]);
                 vertI++;
-                meshTools::writeOBJ(str, surfaceHitInfo.hitPoint());
+                meshTools::writeOBJ(str, surfaceHitInfo[i].hitPoint());
                 vertI++;
-                meshTools::writeOBJ(str, neiCc[i]);
+                meshTools::writeOBJ(str, end[i]);
                 vertI++;
                 str << "l " << vertI-2 << ' ' << vertI-1 << nl
                     << "l " << vertI-1 << ' ' << vertI << nl;
@@ -1996,13 +1550,4 @@ void Foam::meshRefinement::write
 }
 
 
-// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
-
-
-// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
-
-
-// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
-
-
 // ************************************************************************* //
diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H
index 78fed5349306a3f57daf6a6fe10d17f4c84cbc30..e8e633bfef02cd7acbfcf7bcaa4418cb5d5bcd20 100644
--- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H
+++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H
@@ -30,7 +30,7 @@ Description
     (static) surfaces.
 
     Maintains
-    - per face any intersections of this edge with any of the surfaces
+    - per face any intersections of the cc-cc segment with any of the surfaces
 
 SourceFiles
     meshRefinement.C
@@ -62,6 +62,7 @@ class fvMesh;
 class mapDistributePolyMesh;
 class decompositionMethod;
 class refinementSurfaces;
+class shellSurfaces;
 class removeCells;
 class featureEdgeMesh;
 class fvMeshDistribute;
@@ -107,8 +108,12 @@ private:
         //- tolerance used for sorting coordinates (used in 'less' routine)
         const scalar tol_;
 
+        //- All surface-intersection interaction
         const refinementSurfaces& surfaces_;
 
+        //- All shell-refinement interaction
+        const shellSurfaces& shells_;
+
         //- refinement engine
         hexRef8 meshCutter_;
 
@@ -229,14 +234,18 @@ private:
             //- Mark cells for refinement-shells based refinement.
             label markInternalRefinement
             (
-                const PtrList<searchableSurface>&,
-                const labelList& shellLevels,
-                const boolList& shellRefineInside,
                 const label nAllowRefine,
                 labelList& refineCell,
                 label& nRefine
             ) const;
 
+            //- Collect faces that are intersected and whose neighbours aren't
+            //  yet marked  for refinement.
+            labelList getRefineCandidateFaces
+            (
+                const labelList& refineCell
+            ) const;
+
             //- Mark cells for surface intersection based refinement.
             label markSurfaceRefinement
             (
@@ -252,17 +261,13 @@ private:
             //  regions.
             bool checkCurvature
             (
-                const labelList& globalToPatch,
                 const scalar curvature,
-                const bool markDifferingRegions,
                 const label nAllowRefine,
-                const label newSurfI,
-                const label newTriI,
+                const label surfaceLevel,
+                const vector& surfaceNormal,
                 const label cellI,
-
-                label& maxCellSurfI,
-                label& maxCellTriI,
-
+                label& cellMaxLevel,
+                vector& cellMaxNormal,
                 labelList& refineCell,
                 label& nRefine
             ) const;
@@ -273,9 +278,7 @@ private:
             //  (markDifferingRegions)
             label markSurfaceCurvatureRefinement
             (
-                const labelList& globalToPatch,
                 const scalar curvature,
-                const bool markDifferingRegions,
                 const label nAllowRefine,
                 const labelList& neiLevel,
                 const pointField& neiCc,
@@ -381,7 +384,8 @@ public:
         (
             fvMesh& mesh,
             const scalar tol,
-            const refinementSurfaces&
+            const refinementSurfaces&,
+            const shellSurfaces&
         );
 
 
@@ -482,22 +486,18 @@ public:
                 const labelList& adaptPatchIDs
             );
 
+
         // Refinement
 
             //- Calculate list of cells to refine.
             labelList refineCandidates
             (
                 const point& keepPoint,
-                const labelList& globalToPatch,
                 const scalar curvature,
 
                 const PtrList<featureEdgeMesh>& featureMeshes,
                 const labelList& featureLevels,
 
-                const PtrList<searchableSurface>&,
-                const labelList& shellLevels,
-                const boolList& shellRefineInside,
-
                 const bool featureRefinement,
                 const bool internalRefinement,
                 const bool surfaceRefinement,
diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C
index 17eaaeaa275cce90b0802adcef1712f934a4c154..c9c2d14c1306b16c67eee7cdc9e3436c44f92b06 100644
--- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C
+++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C
@@ -249,7 +249,7 @@ void Foam::meshRefinement::getBafflePatches
             if (debug)
             {
                 Pout<< "getBafflePatches : Not baffling surface "
-                    << surfaces_[surfI].searchableSurface::name() << endl;
+                    << surfaces_.names()[surfI] << endl;
             }
         }
         else
@@ -264,69 +264,95 @@ void Foam::meshRefinement::getBafflePatches
     neiPatch.setSize(mesh_.nFaces());
     neiPatch = -1;
 
-    forAll(surfaceIndex_, faceI)
+
+    // Collect candidate faces
+    // ~~~~~~~~~~~~~~~~~~~~~~~
+
+    labelList testFaces(intersectedFaces());
+
+    // Collect segments
+    // ~~~~~~~~~~~~~~~~
+
+    pointField start(testFaces.size());
+    pointField end(testFaces.size());
+
+    forAll(testFaces, i)
     {
-        if (surfaceIndex_[faceI] != -1)
-        {
-            // Edge between owner and neighbour of face pierces a surface.
-            // Do closer inspection to find nearest intersection on both sides.
+        label faceI = testFaces[i];
 
-            label own = mesh_.faceOwner()[faceI];
+        label own = mesh_.faceOwner()[faceI];
 
-            // Cc of neighbouring cell
-            point end
-            (
-                mesh_.isInternalFace(faceI)
-              ? cellCentres[mesh_.faceNeighbour()[faceI]]
-              : neiCc[faceI-mesh_.nInternalFaces()]
-            );
+        if (mesh_.isInternalFace(faceI))
+        {
+            start[i] = cellCentres[own];
+            end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
+        }
+        else
+        {
+            start[i] = cellCentres[own];
+            end[i] = neiCc[faceI-mesh_.nInternalFaces()];
+        }
+    }
 
-            label surface1, surface2;
-            pointIndexHit hit1, hit2;
-            surfaces_.findNearestIntersection
-            (
-                surfacesToBaffle,
-                cellCentres[own],
-                end,
 
-                surface1,
-                hit1,
-                surface2,
-                hit2
-            );
+    // Do test for intersections
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~
+    labelList surface1;
+    List<pointIndexHit> hit1;
+    labelList region1;
+    labelList surface2;
+    List<pointIndexHit> hit2;
+    labelList region2;
+    surfaces_.findNearestIntersection
+    (
+        surfacesToBaffle,
+        start,
+        end,
 
-            if (hit1.hit() && hit2.hit())
-            {
-                if (str.valid())
-                {
-                    meshTools::writeOBJ(str(), cellCentres[own]);
-                    vertI++;
-                    meshTools::writeOBJ(str(), hit1.rawPoint());
-                    vertI++;
-                    meshTools::writeOBJ(str(), hit2.rawPoint());
-                    vertI++;
-                    meshTools::writeOBJ(str(), end);
-                    vertI++;
-                    str()<< "l " << vertI-3 << ' ' << vertI-2 << nl;
-                    str()<< "l " << vertI-2 << ' ' << vertI-1 << nl;
-                    str()<< "l " << vertI-1 << ' ' << vertI << nl;
-                }
+        surface1,
+        hit1,
+        region1,
 
+        surface2,
+        hit2,
+        region2
+    );
 
-                // Pick up the patches
-                ownPatch[faceI] = globalToPatch
-                [
-                    surfaces_.triangleRegion(surface1, hit1.index())
-                ];
-                neiPatch[faceI] = globalToPatch
-                [
-                    surfaces_.triangleRegion(surface2, hit2.index())
-                ];
+    forAll(testFaces, i)
+    {
+        label faceI = testFaces[i];
 
-                if (ownPatch[faceI] == -1 || neiPatch[faceI] == -1)
-                {
-                    FatalErrorIn("getBafflePatches()") << abort(FatalError);
-                }
+        if (hit1[i].hit() && hit2[i].hit())
+        {
+            if (str.valid())
+            {
+                meshTools::writeOBJ(str(), start[i]);
+                vertI++;
+                meshTools::writeOBJ(str(), hit1[i].rawPoint());
+                vertI++;
+                meshTools::writeOBJ(str(), hit2[i].rawPoint());
+                vertI++;
+                meshTools::writeOBJ(str(), end[i]);
+                vertI++;
+                str()<< "l " << vertI-3 << ' ' << vertI-2 << nl;
+                str()<< "l " << vertI-2 << ' ' << vertI-1 << nl;
+                str()<< "l " << vertI-1 << ' ' << vertI << nl;
+            }
+
+            // Pick up the patches
+            ownPatch[faceI] = globalToPatch
+            [
+                surfaces_.globalRegion(surface1[i], region1[i])
+            ];
+            neiPatch[faceI] = globalToPatch
+            [
+                surfaces_.globalRegion(surface2[i], region2[i])
+            ];
+
+            if (ownPatch[faceI] == -1 || neiPatch[faceI] == -1)
+            {
+                FatalErrorIn("getBafflePatches(..)")
+                    << "problem." << abort(FatalError);
             }
         }
     }
@@ -1203,15 +1229,20 @@ void Foam::meshRefinement::findCellZoneGeometric
     const labelList& faceOwner = mesh_.faceOwner();
     const labelList& faceNeighbour = mesh_.faceNeighbour();
 
-    forAll(cellToZone, cellI)
+    // Check if cell centre is inside
+    labelList insideSurfaces;
+    surfaces_.findInside
+    (
+        closedNamedSurfaces,
+        cellCentres,
+        insideSurfaces
+    );
+
+    forAll(insideSurfaces, cellI)
     {
         if (cellToZone[cellI] == -2)
         {
-            label surfI = surfaces_.insideZone
-            (
-                closedNamedSurfaces,
-                cellCentres[cellI]
-            );
+            label surfI = insideSurfaces[cellI];
 
             if (surfI != -1)
             {
@@ -1223,6 +1254,32 @@ void Foam::meshRefinement::findCellZoneGeometric
 
     // Some cells with cell centres close to surface might have
     // had been put into wrong surface. Recheck with perturbed cell centre.
+
+
+    // 1. Collect points
+
+    // Count points to test.
+    label nCandidates = 0;
+    forAll(namedSurfaceIndex, faceI)
+    {
+        label surfI = namedSurfaceIndex[faceI];
+
+        if (surfI != -1)
+        {
+            if (mesh_.isInternalFace(faceI))
+            {
+                nCandidates += 2;
+            }
+            else
+            {
+                nCandidates += 1;
+            }
+        }
+    }
+
+    // Collect points.
+    pointField candidatePoints(nCandidates);
+    nCandidates = 0;
     forAll(namedSurfaceIndex, faceI)
     {
         label surfI = namedSurfaceIndex[faceI];
@@ -1236,55 +1293,65 @@ void Foam::meshRefinement::findCellZoneGeometric
             {
                 label nei = faceNeighbour[faceI];
                 const point& neiCc = cellCentres[nei];
-
+                // Perturbed cc
                 const vector d = 1E-4*(neiCc - ownCc);
+                candidatePoints[nCandidates++] = ownCc-d;
+                candidatePoints[nCandidates++] = neiCc+d;
+            }
+            else
+            {
+                const point& neiFc = mesh_.faceCentres()[faceI];
+                // Perturbed cc
+                const vector d = 1E-4*(neiFc - ownCc);
+                candidatePoints[nCandidates++] = ownCc-d;
+            }
+        }
+    }
 
-                // Test perturbed owner
-                {
-                    label ownSurfI = surfaces_.insideZone
-                    (
-                        closedNamedSurfaces,
-                        ownCc-d
-                    );
 
-                    if (ownSurfI != -1)
-                    {
-                        cellToZone[own] = surfaceToCellZone[ownSurfI];
-                    }
+    // 2. Test points for inside
+
+    surfaces_.findInside
+    (
+        closedNamedSurfaces,
+        candidatePoints,
+        insideSurfaces
+    );
+
+
+    // 3. Update zone information
+
+    nCandidates = 0;
+    forAll(namedSurfaceIndex, faceI)
+    {
+        label surfI = namedSurfaceIndex[faceI];
+
+        if (surfI != -1)
+        {
+            label own = faceOwner[faceI];
+
+            if (mesh_.isInternalFace(faceI))
+            {
+                label ownSurfI = insideSurfaces[nCandidates++];
+                if (ownSurfI != -1)
+                {
+                    cellToZone[own] = surfaceToCellZone[ownSurfI];
                 }
 
-                // Test perturbed neighbour
+                label neiSurfI = insideSurfaces[nCandidates++];
+                if (neiSurfI != -1)
                 {
-                    label neiSurfI = surfaces_.insideZone
-                    (
-                        closedNamedSurfaces,
-                        neiCc+d
-                    );
+                    label nei = faceNeighbour[faceI];
 
-                    if (neiSurfI != -1)
-                    {
-                        cellToZone[nei] = surfaceToCellZone[neiSurfI];
-                    }
+                    cellToZone[nei] = surfaceToCellZone[neiSurfI];
                 }
             }
             else
             {
-                const point& neiCc = mesh_.faceCentres()[faceI];
-
-                const vector d = 1E-4*(neiCc - ownCc);
-
-                // Test perturbed owner
+                label ownSurfI = insideSurfaces[nCandidates++];
+                if (ownSurfI != -1)
                 {
-                    label ownSurfI = surfaces_.insideZone
-                    (
-                        closedNamedSurfaces,
-                        ownCc-d
-                    );
-
-                    if (ownSurfI != -1)
-                    {
-                        cellToZone[own] = surfaceToCellZone[ownSurfI];
-                    }
+                    cellToZone[own] = surfaceToCellZone[ownSurfI];
                 }
             }
         }
@@ -2291,7 +2358,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
 
         isNamedSurface[surfI] = true;
 
-        Info<< "Surface : " << surfaces_[surfI].searchableSurface::name() << nl
+        Info<< "Surface : " << surfaces_.names()[surfI] << nl
             << "    faceZone : " << faceZoneNames[surfI] << nl
             << "    cellZone : " << cellZoneNames[surfI] << endl;
     }
@@ -2329,7 +2396,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
 
             if (debug)
             {
-                Pout<< "Faces on " << surfaces_[surfI].searchableSurface::name()
+                Pout<< "Faces on " << surfaces_.names()[surfI]
                     << " will go into faceZone " << zoneI << endl;
             }
             surfaceToFaceZone[surfI] = zoneI;
@@ -2387,8 +2454,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
 
             if (debug)
             {
-                Pout<< "Cells inside "
-                    << surfaces_[surfI].searchableSurface::name()
+                Pout<< "Cells inside " << surfaces_.names()[surfI]
                     << " will go into cellZone " << zoneI << endl;
             }
             surfaceToCellZone[surfI] = zoneI;
@@ -2444,78 +2510,83 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
         // Note: for all internal faces? internal + coupled?
         // Since zonify is run after baffling the surfaceIndex_ on baffles is
         // not synchronised across both baffle faces. Fortunately we don't
-        // do zonify baffle faces anyway.
-        forAll(surfaceIndex_, faceI)
+        // do zonify baffle faces anyway (they are normal boundary faces).
+
+        // Collect candidate faces
+        // ~~~~~~~~~~~~~~~~~~~~~~~
+
+        labelList testFaces(intersectedFaces());
+
+        // Collect segments
+        // ~~~~~~~~~~~~~~~~
+
+        pointField start(testFaces.size());
+        pointField end(testFaces.size());
+
+        forAll(testFaces, i)
         {
-            label surfI = surfaceIndex_[faceI];
+            label faceI = testFaces[i];
 
-            if
-            (
-                surfI != -1
-             && (
-                    mesh_.isInternalFace(faceI)
-                 || patches[patches.whichPatch(faceI)].coupled()
-                )
-            )
+            label own = mesh_.faceOwner()[faceI];
+
+            if (mesh_.isInternalFace(faceI))
             {
-                if (isNamedSurface[surfI])
-                {
-                    namedSurfaceIndex[faceI] = surfI;
-                    nSurfFaces[surfI]++;
-                }
-                else
-                {
-                    // Test more accurately for whether intersection is at
-                    // zoneable surface
+                start[i] = cellCentres[own];
+                end[i] = cellCentres[mesh_.faceNeighbour()[faceI]];
+            }
+            else
+            {
+                start[i] = cellCentres[own];
+                end[i] = neiCc[faceI-mesh_.nInternalFaces()];
+            }
+        }
 
-                    label surface1, surface2;
-                    pointIndexHit hit1, hit2;
 
-                    if (mesh_.isInternalFace(faceI))
-                    {
-                        surfaces_.findNearestIntersection
-                        (
-                            namedSurfaces,
-                            cellCentres[faceOwner[faceI]],
-                            cellCentres[faceNeighbour[faceI]],
-
-                            surface1,
-                            hit1,
-                            surface2,
-                            hit2
-                        );
-                    }
-                    else
-                    {
-                        surfaces_.findNearestIntersection
-                        (
-                            namedSurfaces,
-                            cellCentres[faceOwner[faceI]],
-                            neiCc[faceI-mesh_.nInternalFaces()],
-
-                            surface1,
-                            hit1,
-                            surface2,
-                            hit2
-                        );
-                    }
+        // Do test for intersections
+        // ~~~~~~~~~~~~~~~~~~~~~~~~~
+        // Note that we intersect all intersected faces again. Could reuse
+        // the information already in surfaceIndex_.
 
-                    if (hit1.hit())
-                    {
-                        // If both hit should probably choose nearest. For
-                        // later.
-                        namedSurfaceIndex[faceI] = surface1;
-                        nSurfFaces[surface1]++;
-                    }
-                    else if (hit2.hit())
-                    {
-                        namedSurfaceIndex[faceI] = surface2;
-                        nSurfFaces[surface2]++;
-                    }
-                }
+        labelList surface1;
+        labelList surface2;
+        {
+            List<pointIndexHit> hit1;
+            labelList region1;
+            List<pointIndexHit> hit2;
+            labelList region2;
+            surfaces_.findNearestIntersection
+            (
+                namedSurfaces,
+                start,
+                end,
+
+                surface1,
+                hit1,
+                region1,
+                surface2,
+                hit2,
+                region2
+            );
+        }
+
+        forAll(testFaces, i)
+        {
+            label faceI = testFaces[i];
+
+            if (surface1[i] != -1)
+            {
+                // If both hit should probably choose nearest. For later.
+                namedSurfaceIndex[faceI] = surface1[i];
+                nSurfFaces[surface1[i]]++;
+            }
+            else if (surface2[i] != -1)
+            {
+                namedSurfaceIndex[faceI] = surface2[i];
+                nSurfFaces[surface2[i]]++;
             }
         }
 
+
         // surfaceIndex migh have different surfaces on both sides if
         // there happen to be a (obviously thin) surface with different
         // regions between the cell centres. If one is on a named surface
@@ -2534,7 +2605,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
             forAll(nSurfFaces, surfI)
             {
                 Pout<< "Surface:"
-                    << surfaces_[surfI].searchableSurface::name()
+                    << surfaces_.names()[surfI]
                     << "  nZoneFaces:" << nSurfFaces[surfI] << nl;
             }
             Pout<< endl;
@@ -2591,7 +2662,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
                     (
                         mesh_.faces()[faceI],           // modified face
                         faceI,                          // label of face
-                        faceOwner[faceI],              // owner
+                        faceOwner[faceI],               // owner
                         -1,                             // neighbour
                         false,                          // face flip
                         patchI,                         // patch for face
@@ -2609,20 +2680,8 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
     // Put the cells into the correct zone
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    labelList closedNamedSurfaces(namedSurfaces.size());
-    label nClosed = 0;
-
-    forAll(namedSurfaces, i)
-    {
-        label surfI = namedSurfaces[i];
-
-        if (surfaces_.closed()[surfI])
-        {
-            closedNamedSurfaces[nClosed++] = surfI;
-        }
-    }
-    closedNamedSurfaces.setSize(nClosed);
-
+    // Closed surfaces with cellZone specified.
+    labelList closedNamedSurfaces(surfaces_.getClosedNamedSurfaces());
 
     // Zone per cell:
     // -2 : unset
@@ -2704,13 +2763,4 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
 }
 
 
-// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
-
-
-// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
-
-
-// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
-
-
 // ************************************************************************* //
diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementMerge.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementMerge.C
index 14c3304979b41030960405291825a04bdcfe79c4..d8ddb69bcece7841e39e71751245cc21efd5d5ee 100644
--- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementMerge.C
+++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementMerge.C
@@ -30,15 +30,9 @@ License
 #include "removePoints.H"
 
 
-// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
-
-
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 // Merge faces that are in-line.
@@ -244,13 +238,4 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::mergeEdges
 }
 
 
-// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
-
-
-// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
-
-
-// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
-
-
 // ************************************************************************* //
diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C
index bc65921bf5aa74179e90972f61eba7c71b831228..9a5f6cf63379293e884c8c74fa59fa48b981c203 100644
--- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C
+++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C
@@ -29,6 +29,7 @@ License
 #include "syncTools.H"
 #include "Time.H"
 #include "refinementSurfaces.H"
+#include "shellSurfaces.H"
 #include "faceSet.H"
 #include "decompositionMethod.H"
 #include "fvMeshDistribute.H"
@@ -37,9 +38,6 @@ License
 #include "featureEdgeMesh.H"
 #include "Cloud.H"
 
-// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
-
-
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 // Get faces (on the new mesh) that have in some way been affected by the
@@ -369,7 +367,7 @@ Foam::label Foam::meshRefinement::markFeatureRefinement
             {
                 label edgeI = pEdges[i];
 
-                if (featureEdgeVisited[featI].get(edgeI) == 0)
+                if (featureEdgeVisited[featI].set(edgeI, 1u))
                 {
                     // Unvisited edge. Make the particle go to the other point
                     // on the edge.
@@ -377,7 +375,6 @@ Foam::label Foam::meshRefinement::markFeatureRefinement
                     const edge& e = featureMesh.edges()[edgeI];
                     label otherPointI = e.otherVertex(pointI);
 
-                    featureEdgeVisited[featI].set(edgeI, 1u);
                     tp.end() = featureMesh.points()[otherPointI];
                     tp.j() = otherPointI;
                     keepParticle = true;
@@ -438,6 +435,15 @@ Foam::label Foam::meshRefinement::markFeatureRefinement
         }
     }
 
+    if
+    (
+        returnReduce(nRefine, sumOp<label>())
+      > returnReduce(nAllowRefine, sumOp<label>())
+    )
+    {
+        Info<< "Reached refinement limit." << endl;
+    }
+
     return returnReduce(nRefine-oldNRefine,  sumOp<label>());
 }
 
@@ -445,9 +451,6 @@ Foam::label Foam::meshRefinement::markFeatureRefinement
 // Mark cells for non-surface intersection based refinement.
 Foam::label Foam::meshRefinement::markInternalRefinement
 (
-    const PtrList<searchableSurface>& shells,
-    const labelList& shellLevels,
-    const boolList& shellRefineInside,
     const label nAllowRefine,
 
     labelList& refineCell,
@@ -457,94 +460,113 @@ Foam::label Foam::meshRefinement::markInternalRefinement
     const labelList& cellLevel = meshCutter_.cellLevel();
     const pointField& cellCentres = mesh_.cellCentres();
 
-
     label oldNRefine = nRefine;
 
-    // Number of cells marked for refinement per shell.
-    labelList nCellsPerShell(shells.size(), 0);
+    // Collect cells to test
+    pointField testCc(cellLevel.size()-nRefine);
+    labelList testLevels(cellLevel.size()-nRefine);
+    label testI = 0;
 
     forAll(cellLevel, cellI)
     {
         if (refineCell[cellI] == -1)
         {
-            // Cell not marked for refinement. Check if inside any shell
-            // with higher refinement level than cell currently has.
+            testCc[testI] = cellCentres[cellI];
+            testLevels[testI] = cellLevel[cellI];
+            testI++;
+        }
+    }
 
-            bool reachedLimit = false;
+    // Do test to see whether cells is inside/outside shell with higher level
+    labelList maxLevel;
+    shells_.findHigherLevel(testCc, testLevels, maxLevel);
 
-            forAll(shells, shellI)
+    // Mark for refinement. Note that we didn't store the original cellID so
+    // now just reloop in same order.
+    testI = 0;
+    forAll(cellLevel, cellI)
+    {
+        if (refineCell[cellI] == -1)
+        {
+            if (maxLevel[testI] > testLevels[testI])
             {
-                // Cached inside-outside from tree
-                searchableSurface::volumeType t =
-                    shells[shellI].getVolumeType(cellCentres[cellI]);
-
-                //// Uncached inside-outside from treeData
-                //label t = shells[shellI].shapes().getVolumeType
-                //    (
-                //        shells[shellI],
-                //        cellCentres[cellI]
-                //    );
-
-                // Which side of shell is to be refined
-                searchableSurface::volumeType refSide =
+                bool reachedLimit = !markForRefine
                 (
-                    shellRefineInside[shellI]
-                  ? searchableSurface::INSIDE
-                  : searchableSurface::OUTSIDE
+                    maxLevel[testI],    // mark with any positive value
+                    nAllowRefine,
+                    refineCell[cellI],
+                    nRefine
                 );
 
-                if (t == refSide && cellLevel[cellI] < shellLevels[shellI])
+                if (reachedLimit)
                 {
-                    // Cell is inside shell with higher refinement level. Mark
-                    // for refinement.
-
-                    reachedLimit = !markForRefine
-                    (
-                        labelMax,
-                        nAllowRefine,
-                        refineCell[cellI],
-                        nRefine
-                    );
-
-                    if (reachedLimit)
-                    {
-                        if (debug)
-                        {
-                            Pout<< "Stopped refining internal cells"
-                                << " since reaching my cell limit of "
-                                << mesh_.nCells()+7*nRefine << endl;
-                        }
-                        break;
-                    }
-                    else
+                    if (debug)
                     {
-                        // Cell successfully marked for refinement
-                        nCellsPerShell[shellI]++;
+                        Pout<< "Stopped refining internal cells"
+                            << " since reaching my cell limit of "
+                            << mesh_.nCells()+7*nRefine << endl;
                     }
+                    break;
                 }
             }
-
-            if (reachedLimit)
-            {
-                break;
-            }
+            testI++;
         }
     }
 
-    Pstream::listCombineGather(nCellsPerShell, plusEqOp<label>());
-    Pstream::listCombineScatter(nCellsPerShell);
-
-    Info<< "Marked for refinement per shell :" << endl;
-    forAll(nCellsPerShell, shellI)
+    if
+    (
+        returnReduce(nRefine, sumOp<label>())
+      > returnReduce(nAllowRefine, sumOp<label>())
+    )
     {
-        Info<< "    shell:" << shellI << " nCells:" << nCellsPerShell[shellI]
-            << nl;
+        Info<< "Reached refinement limit." << endl;
     }
 
     return returnReduce(nRefine-oldNRefine, sumOp<label>());
 }
 
 
+// Collect faces that are intersected and whose neighbours aren't yet marked
+// for refinement.
+Foam::labelList Foam::meshRefinement::getRefineCandidateFaces
+(
+    const labelList& refineCell
+) const
+{
+    labelList testFaces(mesh_.nCells());
+
+    label nTest = 0;
+
+    forAll(surfaceIndex_, faceI)
+    {
+        if (surfaceIndex_[faceI] != -1)
+        {
+            label own = mesh_.faceOwner()[faceI];
+
+            if (mesh_.isInternalFace(faceI))
+            {
+                label nei = mesh_.faceNeighbour()[faceI];
+
+                if (refineCell[own] == -1 || refineCell[nei] == -1)
+                {
+                    testFaces[nTest++] = faceI;
+                }
+            }
+            else
+            {
+                if (refineCell[own] == -1)
+                {
+                    testFaces[nTest++] = faceI;
+                }
+            }
+        }
+    }
+    testFaces.setSize(nTest);
+
+    return testFaces;
+}
+
+
 // Mark cells for surface intersection based refinement.
 Foam::label Foam::meshRefinement::markSurfaceRefinement
 (
@@ -564,156 +586,149 @@ Foam::label Foam::meshRefinement::markSurfaceRefinement
     // Use cached surfaceIndex_ to detect if any intersection. If so
     // re-intersect to determine level wanted.
 
-    label faceI;
-    for (faceI = 0; faceI < surfaceIndex_.size(); faceI++)
+    // Collect candidate faces
+    // ~~~~~~~~~~~~~~~~~~~~~~~
+
+    labelList testFaces(getRefineCandidateFaces(refineCell));
+
+    // Collect segments
+    // ~~~~~~~~~~~~~~~~
+
+    pointField start(testFaces.size());
+    pointField end(testFaces.size());
+    labelList minLevel(testFaces.size());
+
+    forAll(testFaces, i)
     {
-        if (surfaceIndex_[faceI] != -1)
+        label faceI = testFaces[i];
+
+        label own = mesh_.faceOwner()[faceI];
+
+        if (mesh_.isInternalFace(faceI))
         {
-            label own = mesh_.faceOwner()[faceI];
+            label nei = mesh_.faceNeighbour()[faceI];
 
-            if (mesh_.isInternalFace(faceI))
-            {
-                label nei = mesh_.faceNeighbour()[faceI];
+            start[i] = cellCentres[own];
+            end[i] = cellCentres[nei];
+            minLevel[i] = min(cellLevel[own], cellLevel[nei]);
+        }
+        else
+        {
+            label bFaceI = faceI - mesh_.nInternalFaces();
 
-                // Test if not both sides already marked for refinement.
-                if (refineCell[own] == -1 || refineCell[nei] == -1)
-                {
-                    pointIndexHit hit;
-                    label surfI = surfaces_.findHigherIntersection
-                    (
-                        cellCentres[own],
-                        cellCentres[nei],
-                        min(cellLevel[own], cellLevel[nei]),
-                        hit
-                    );
+            start[i] = cellCentres[own];
+            end[i] = neiCc[bFaceI];
+            minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]);
+        }
+    }
 
-                    if (surfI != -1)
-                    {
-                        // Found intersection with surface with higher wanted
-                        // refinement. Mark cell for refining.
-                        // Note: could do optimization here and only refine the
-                        // side of the face the intersection actually goes
-                        // through.
-                        // This would require us though to find all
-                        // intersections
-                        // first instead of now only the first higher one. Also
-                        // would need the exact intersection of face with cc-cc
-                        // connection?
-
-                        label surfaceMinLevel =
-                            surfaces_.minLevelField(surfI)[hit.index()];
-
-                        if (surfaceMinLevel > cellLevel[own])
-                        {
-                            // Owner needs refining
-                            if
-                            (
-                               !markForRefine
-                                (
-                                    surfI,
-                                    nAllowRefine,
-                                    refineCell[own],
-                                    nRefine
-                                )
-                            )
-                            {
-                                break;
-                            }
-                        }
 
-                        if (surfaceMinLevel > cellLevel[nei])
-                        {
-                            // Neighbour needs refining
-                            if
-                            (
-                               !markForRefine
-                                (
-                                    surfI,
-                                    nAllowRefine,
-                                    refineCell[nei],
-                                    nRefine
-                                )
-                            )
-                            {
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-            else if (refineCell[own] == -1)
-            {
-                // boundary face with unmarked owner
+    // Do test for higher intersections
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    labelList surfaceHit;
+    labelList surfaceMinLevel;
+    surfaces_.findHigherIntersection
+    (
+        start,
+        end,
+        minLevel,
+
+        surfaceHit,
+        surfaceMinLevel
+    );
+
+
+    // Mark cells for refinement
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    forAll(testFaces, i)
+    {
+        label faceI = testFaces[i];
+
+        label surfI = surfaceHit[i];
 
-                label bFaceI = faceI - mesh_.nInternalFaces();
+        if (surfI != -1)
+        {
+            // Found intersection with surface with higher wanted
+            // refinement. Check if the level field on that surface
+            // specifies an even higher level. Note:this is weird. Should
+            // do the check with the surfaceMinLevel whilst intersecting the
+            // surfaces?
+
+            label own = mesh_.faceOwner()[faceI];
 
-                pointIndexHit hit;
-                label surfI = surfaces_.findHigherIntersection
+            if (surfaceMinLevel[i] > cellLevel[own])
+            {
+                // Owner needs refining
+                if
                 (
-                    cellCentres[own],
-                    neiCc[bFaceI],
-                    min(cellLevel[own], neiLevel[bFaceI]),
-                    hit
-                );
+                   !markForRefine
+                    (
+                        surfI,
+                        nAllowRefine,
+                        refineCell[own],
+                        nRefine
+                    )
+                )
+                {
+                    break;
+                }
+            }
 
-                if (surfI != -1)
+            if (mesh_.isInternalFace(faceI))
+            {
+                label nei = mesh_.faceNeighbour()[faceI];
+                if (surfaceMinLevel[i] > cellLevel[nei])
                 {
-                    // Make sure it is my side that wants refinement.
-                    label surfaceMinLevel =
-                        surfaces_.minLevelField(surfI)[hit.index()];
-                   
-                    if (surfaceMinLevel > cellLevel[own])
-                    {
-                        if
+                    // Neighbour needs refining
+                    if
+                    (
+                       !markForRefine
                         (
-                           !markForRefine
-                            (
-                                surfI,
-                                nAllowRefine,
-                                refineCell[own],
-                                nRefine
-                            )
+                            surfI,
+                            nAllowRefine,
+                            refineCell[nei],
+                            nRefine
                         )
-                        {
-                            break;
-                        }
+                    )
+                    {
+                        break;
                     }
                 }
             }
         }
     }
 
-    if (faceI < surfaceIndex_.size())
+    if
+    (
+        returnReduce(nRefine, sumOp<label>())
+      > returnReduce(nAllowRefine, sumOp<label>())
+    )
     {
-        if (debug)
-        {
-            Pout<< "Stopped refining since reaching my cell limit of "
-                << mesh_.nCells()+7*nRefine << endl;
-        }
+        Info<< "Reached refinement limit." << endl;
     }
 
     return returnReduce(nRefine-oldNRefine, sumOp<label>());
 }
 
 
-// Given intersection of (face of) cell by newSurfI, newTriI, check whether
-// it needs to be refined. Updates maxCellSurf, maxCellTri and
-// refineCell,nRefine if it decides to refine the cell. Returns false
-// if the nRefine limit has been reached, true otherwise.
+// Checks if multiple intersections of a cell (by a surface with a higher
+// max than the cell level) and if so if the normals at these intersections
+// make a large angle.
+// Returns false if the nRefine limit has been reached, true otherwise.
 bool Foam::meshRefinement::checkCurvature
 (
-    const labelList& globalToPatch,
     const scalar curvature,
-    const bool markDifferingRegions,
     const label nAllowRefine,
 
-    const label newSurfI,
-    const label newTriI,
+    const label surfaceLevel,   // current intersection max level
+    const vector& surfaceNormal,// current intersection normal
 
     const label cellI,
 
-    label& maxCellSurfI,
-    label& maxCellTriI,
+    label& cellMaxLevel,        // cached max surface level for this cell
+    vector& cellMaxNormal,      // cached surface normal for this cell
 
     labelList& refineCell,
     label& nRefine
@@ -721,59 +736,35 @@ bool Foam::meshRefinement::checkCurvature
 {
     const labelList& cellLevel = meshCutter_.cellLevel();
 
-    if (maxCellSurfI == -1)
-    {
-        // First visit of cell. Store
-        maxCellSurfI = newSurfI;
-        maxCellTriI = newTriI;
-    }
-    else
+    // Test if surface applicable
+    if (surfaceLevel > cellLevel[cellI])
     {
-        // Second or more visit.
-        label cellRegion = surfaces_.triangleRegion(maxCellSurfI, maxCellTriI);
-        label newRegion = surfaces_.triangleRegion(newSurfI, newTriI);
-
-        // Update max
-        label maxLevel = surfaces_.maxLevel()[cellRegion];
-
-        if (surfaces_.maxLevel()[newRegion] > maxLevel)
+        if (cellMaxLevel == -1)
         {
-            maxCellSurfI = newSurfI;
-            maxCellTriI = newTriI;
-            maxLevel = surfaces_.maxLevel()[newRegion];
+            // First visit of cell. Store
+            cellMaxLevel = surfaceLevel;
+            cellMaxNormal = surfaceNormal;
         }
-
-
-        // Check if cell is candidate for refinement
-        if (cellLevel[cellI] < maxLevel)
+        else
         {
-            // Test 1: different regions
-            if (markDifferingRegions && cellRegion != newRegion)
+            // Second or more visit. Check curvature.
+            if ((cellMaxNormal & surfaceNormal) < curvature)
             {
                 return markForRefine
                 (
-                    globalToPatch[newRegion],   // mark with non-neg number.
+                    surfaceLevel,   // mark with any non-neg number.
                     nAllowRefine,
                     refineCell[cellI],
                     nRefine
                 );
             }
 
-            // Test 2: different normals
-            const vector& cellN =
-                surfaces_[maxCellSurfI].faceNormals()[maxCellTriI];
-            const vector& newN =
-                surfaces_[newSurfI].faceNormals()[newTriI];
-
-            if ((cellN & newN) < curvature)
+            // Set normal to that of highest surface. Not really necessary
+            // over here but we reuse cellMax info when doing coupled faces.
+            if (surfaceLevel > cellMaxLevel)
             {
-                return markForRefine
-                (
-                    globalToPatch[newRegion],   // mark with non-neg number.
-                    nAllowRefine,
-                    refineCell[cellI],
-                    nRefine
-                );
+                cellMaxLevel = surfaceLevel;
+                cellMaxNormal = surfaceNormal;
             }
         }
     }
@@ -786,9 +777,7 @@ bool Foam::meshRefinement::checkCurvature
 // Mark cells for surface curvature based refinement.
 Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
 (
-    const labelList& globalToPatch,
     const scalar curvature,
-    const bool markDifferingRegions,
     const label nAllowRefine,
     const labelList& neiLevel,
     const pointField& neiCc,
@@ -802,107 +791,117 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
 
     label oldNRefine = nRefine;
 
-    // 1. Any cell on more than one surface gets refined (if its current level
-    // is <= max of the surface max level)
-
-    // 2. Any cell on only one surface with a neighbour on a different surface
-    // gets refined (if its current level etc.)
+    // 1. local test: any cell on more than one surface gets refined
+    // (if its current level is < max of the surface max level)
 
+    // 2. 'global' test: any cell on only one surface with a neighbour
+    // on a different surface gets refined (if its current level etc.)
 
 
-    // Index of surface with the max maxLevel and the actual triangle
-    // on the surface. We store these and not e.g. global region so we can get
-    // at:
-    //  - global region
-    //  - global patch
-    //  - face normal
-    labelList cellMaxSurface(mesh_.nCells(), -1);
-    labelList cellMaxTriangle(mesh_.nCells(), -1);
+    // Collect candidate faces (i.e. intersecting any surface and
+    // owner/neighbour not yet refined.
+    labelList testFaces(getRefineCandidateFaces(refineCell));
 
-    // 1.
+    // Collect segments
+    pointField start(testFaces.size());
+    pointField end(testFaces.size());
+    labelList minLevel(testFaces.size());
 
-    forAll(surfaceIndex_, faceI)
+    forAll(testFaces, i)
     {
-        if (surfaceIndex_[faceI] != -1)
+        label faceI = testFaces[i];
+
+        label own = mesh_.faceOwner()[faceI];
+
+        if (mesh_.isInternalFace(faceI))
         {
-            label own = mesh_.faceOwner()[faceI];
+            label nei = mesh_.faceNeighbour()[faceI];
 
-            // There is an intersection. Do more accurate test to get all
-            // intersections
-            labelList surfaceIndices;
-            List<pointIndexHit> hits;
+            start[i] = cellCentres[own];
+            end[i] = cellCentres[nei];
+            minLevel[i] = min(cellLevel[own], cellLevel[nei]);
+        }
+        else
+        {
+            label bFaceI = faceI - mesh_.nInternalFaces();
 
-            if (mesh_.isInternalFace(faceI))
-            {
-                label nei = mesh_.faceNeighbour()[faceI];
+            start[i] = cellCentres[own];
+            end[i] = neiCc[bFaceI];
+            minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]);
+        }
+    }
 
-                surfaces_.findAllIntersections
-                (
-                    cellCentres[own],
-                    cellCentres[nei],
-                    surfaceIndices,
-                    hits
-                );
-            }
-            else
-            {
-                label bFaceI = faceI - mesh_.nInternalFaces();
+    // Test for all intersections (with surfaces of higher max level than
+    // minLevel) and cache per cell the max surface level and the local normal
+    // on that surface.
+    labelList cellMaxLevel(mesh_.nCells(), -1);
+    vectorField cellMaxNormal(mesh_.nCells());
 
-                surfaces_.findAllIntersections
-                (
-                    cellCentres[own],
-                    neiCc[bFaceI],
-                    surfaceIndices,
-                    hits
-                );
-            }
+    {
+        // Per segment the normals of the surfaces
+        List<vectorList> surfaceNormal;
+        // Per segment the list of levels of the surfaces
+        labelListList surfaceLevel;
 
+        surfaces_.findAllHigherIntersections
+        (
+            start,
+            end,
+            minLevel,           // max level of surface has to be bigger
+                                // than min level of neighbouring cells
+            surfaceNormal,
+            surfaceLevel
+        );
+        // Clear out unnecessary data
+        start.clear();
+        end.clear();
+        minLevel.clear();
 
-            // See if intersection adds any new information to the owner or
-            // neighbour cell.
+        // Extract per cell information on the surface with the highest max
+        forAll(testFaces, i)
+        {
+            label faceI = testFaces[i];
+            label own = mesh_.faceOwner()[faceI];
 
-            forAll(surfaceIndices, i)
-            {
-                label surfI = surfaceIndices[i];
-                label triI = hits[i].index();
+            const vectorList& fNormals = surfaceNormal[i];
+            const labelList& fLevels = surfaceLevel[i];
 
+            forAll(fLevels, hitI)
+            {
                 checkCurvature
                 (
-                    globalToPatch,
                     curvature,
-                    markDifferingRegions,
                     nAllowRefine,
 
-                    surfI,
-                    triI,
+                    fLevels[hitI],
+                    fNormals[hitI],
 
                     own,
-
-                    cellMaxSurface[own],
-                    cellMaxTriangle[own],
+                    cellMaxLevel[own],
+                    cellMaxNormal[own],
 
                     refineCell,
                     nRefine
                 );
+            }
 
-                if (mesh_.isInternalFace(faceI))
-                {
-                    label nei = mesh_.faceNeighbour()[faceI];
+            if (mesh_.isInternalFace(faceI))
+            {
+                label nei = mesh_.faceNeighbour()[faceI];
 
+                forAll(fLevels, hitI)
+                {
                     checkCurvature
                     (
-                        globalToPatch,
                         curvature,
-                        markDifferingRegions,
                         nAllowRefine,
 
-                        surfI,
-                        triI,
+                        fLevels[hitI],
+                        fNormals[hitI],
 
                         nei,
-
-                        cellMaxSurface[nei],
-                        cellMaxTriangle[nei],
+                        cellMaxLevel[nei],
+                        cellMaxNormal[nei],
 
                         refineCell,
                         nRefine
@@ -910,93 +909,46 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
                 }
             }
         }
-
-        if (nRefine > nAllowRefine)
-        {
-            if (debug)
-            {
-                Pout<< "Stopped refining since reaching my cell limit of "
-                    << mesh_.nCells()+7*nRefine << endl;
-            }
-            break;
-        }
     }
 
     // 2. Find out a measure of surface curvature and region edges.
     // Send over surface region and surface normal to neighbour cell.
 
-    // global region
-    labelList ownRegion(mesh_.nFaces(), -1);
-    labelList neiRegion(mesh_.nFaces(), -1);
-    // local normal at hit
-    vectorField ownNormal(mesh_.nFaces(), vector::zero);
-    vectorField neiNormal(mesh_.nFaces(), vector::zero);
-
-    // Internal faces
-    for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
-    {
-        label own = mesh_.faceOwner()[faceI];
-
-        if (cellMaxSurface[own] != -1)
-        {
-            label surfI = cellMaxSurface[own];
-            label triI = cellMaxTriangle[own];
-
-            ownRegion[faceI] = surfaces_.triangleRegion(surfI, triI);
-            ownNormal[faceI] = surfaces_[surfI].faceNormals()[triI];
-        }
-
-        label nei = mesh_.faceNeighbour()[faceI];
+    labelList neiBndMaxLevel(mesh_.nFaces()-mesh_.nInternalFaces());
+    vectorField neiBndMaxNormal(mesh_.nFaces()-mesh_.nInternalFaces());
 
-        if (cellMaxSurface[nei] != -1)
-        {
-            label surfI = cellMaxSurface[nei];
-            label triI = cellMaxTriangle[nei];
-
-            neiRegion[faceI] = surfaces_.triangleRegion(surfI, triI);
-            neiNormal[faceI] = surfaces_[surfI].faceNormals()[triI];
-        }
-    }
-    // Boundary faces
     for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
     {
+        label bFaceI = faceI-mesh_.nInternalFaces();
         label own = mesh_.faceOwner()[faceI];
 
-        if (cellMaxSurface[own] != -1)
-        {
-            label surfI = cellMaxSurface[own];
-            label triI = cellMaxTriangle[own];
-
-            ownRegion[faceI] = surfaces_.triangleRegion(surfI, triI);
-            ownNormal[faceI] = surfaces_[surfI].faceNormals()[triI];
-
-            neiRegion[faceI] = ownRegion[faceI];
-            neiNormal[faceI] = ownNormal[faceI];
-        }
+        neiBndMaxLevel[bFaceI] = cellMaxLevel[own];
+        neiBndMaxNormal[bFaceI] = cellMaxNormal[own];
     }
+    syncTools::swapBoundaryFaceList(mesh_, neiBndMaxLevel, false);
+    syncTools::swapBoundaryFaceList(mesh_, neiBndMaxNormal, false);
 
-    syncTools::swapFaceList(mesh_, neiRegion, false);
-    syncTools::swapFaceList(mesh_, neiNormal, false);
+    // Loop over all faces. Could only be checkFaces.. except if they're coupled
 
-    for (label faceI = 0; faceI < mesh_.nFaces(); faceI++)
+    // Internal faces
+    for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
     {
-        if (ownRegion[faceI] != -1 && neiRegion[faceI] != -1)
+        label own = mesh_.faceOwner()[faceI];
+        label nei = mesh_.faceNeighbour()[faceI];
+
+        if (cellMaxLevel[own] != -1 && cellMaxLevel[nei] != -1)
         {
-            if
-            (
-                (markDifferingRegions && (ownRegion[faceI] != neiRegion[faceI]))
-             || ((ownNormal[faceI] & neiNormal[faceI]) < curvature)
-            )
+            // Have valid data on both sides. Check curvature.
+            if ((cellMaxNormal[own] & cellMaxNormal[nei]) < curvature)
             {
-                label own = mesh_.faceOwner()[faceI];
-
-                if (cellLevel[own] < surfaces_.maxLevel()[ownRegion[faceI]])
+                // See which side to refine
+                if (cellLevel[own] < cellMaxLevel[own])
                 {
                     if
                     (
                         !markForRefine
                         (
-                            globalToPatch[ownRegion[faceI]],
+                            cellMaxLevel[own],
                             nAllowRefine,
                             refineCell[own],
                             nRefine
@@ -1011,46 +963,77 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
                         }
                         break;
                     }
-
                 }
 
-                if (mesh_.isInternalFace(faceI))
+                if (cellLevel[nei] < cellMaxLevel[nei])
                 {
-                    label nei = mesh_.faceNeighbour()[faceI];
-
-                    if (cellLevel[nei] < surfaces_.maxLevel()[neiRegion[faceI]])
-                    {
-                        if
+                    if
+                    (
+                        !markForRefine
                         (
-                            !markForRefine
-                            (
-                                globalToPatch[neiRegion[faceI]],
-                                nAllowRefine,
-
-                                refineCell[nei],
-                                nRefine
-                            )
+                            cellMaxLevel[nei],
+                            nAllowRefine,
+                            refineCell[nei],
+                            nRefine
                         )
+                    )
+                    {
+                        if (debug)
                         {
-                            if (debug)
-                            {
-                                Pout<< "Stopped refining since reaching my cell"
-                                    << " limit of " << mesh_.nCells()+7*nRefine
-                                    << endl;
-                            }
-                            break;
+                            Pout<< "Stopped refining since reaching my cell"
+                                << " limit of " << mesh_.nCells()+7*nRefine
+                                << endl;
                         }
+                        break;
                     }
                 }
             }
         }
     }
+    // Boundary faces
+    for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
+    {
+        label own = mesh_.faceOwner()[faceI];
+        label bFaceI = faceI - mesh_.nInternalFaces();
 
+        if (cellLevel[own] < cellMaxLevel[own] && neiBndMaxLevel[bFaceI] != -1)
+        {
+            // Have valid data on both sides. Check curvature.
+            if ((cellMaxNormal[own] & neiBndMaxNormal[bFaceI]) < curvature)
+            {
+                if
+                (
+                    !markForRefine
+                    (
+                        cellMaxLevel[own],
+                        nAllowRefine,
+                        refineCell[own],
+                        nRefine
+                    )
+                )
+                {
+                    if (debug)
+                    {
+                        Pout<< "Stopped refining since reaching my cell"
+                            << " limit of " << mesh_.nCells()+7*nRefine
+                            << endl;
+                    }
+                    break;
+                }
+            }
+        }
+    }
 
-    return returnReduce(nRefine-oldNRefine, sumOp<label>());
-    label totNRefined = returnReduce(totNRefined, sumOp<label>());
+    if
+    (
+        returnReduce(nRefine, sumOp<label>())
+      > returnReduce(nAllowRefine, sumOp<label>())
+    )
+    {
+        Info<< "Reached refinement limit." << endl;
+    }
 
-    return totNRefined;
+    return returnReduce(nRefine-oldNRefine, sumOp<label>());
 }
 
 
@@ -1064,16 +1047,11 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
 Foam::labelList Foam::meshRefinement::refineCandidates
 (
     const point& keepPoint,
-    const labelList& globalToPatch,
     const scalar curvature,
 
     const PtrList<featureEdgeMesh>& featureMeshes,
     const labelList& featureLevels,
 
-    const PtrList<searchableSurface>& shells,
-    const labelList& shellLevels,
-    const boolList& shellRefineInside,
-
     const bool featureRefinement,
     const bool internalRefinement,
     const bool surfaceRefinement,
@@ -1086,7 +1064,12 @@ Foam::labelList Foam::meshRefinement::refineCandidates
 
     labelList cellsToRefine;
 
-    if (totNCells < maxGlobalCells)
+    if (totNCells >= maxGlobalCells)
+    {
+        Info<< "No cells marked for refinement since reached limit "
+            << maxGlobalCells << '.' << endl;
+    }
+    else
     {
         // Every cell I refine adds 7 cells. Estimate the number of cells
         // I am allowed to refine.
@@ -1151,9 +1134,6 @@ Foam::labelList Foam::meshRefinement::refineCandidates
         {
             label nShell = markInternalRefinement
             (
-                shells,
-                shellLevels,
-                shellRefineInside,
                 nAllowRefine,
 
                 refineCell,
@@ -1184,13 +1164,11 @@ Foam::labelList Foam::meshRefinement::refineCandidates
         // Refinement based on curvature of surface
         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-        if (curvatureRefinement)
+        if (curvatureRefinement && (curvature >= -1 && curvature <= 1))
         {
             label nCurv = markSurfaceCurvatureRefinement
             (
-                globalToPatch,
                 curvature,
-                false,              // do not refine at multiple regions
                 nAllowRefine,
                 neiLevel,
                 neiCc,
@@ -1287,28 +1265,6 @@ Foam::autoPtr<Foam::mapDistributePolyMesh>
     printMeshInfo(debug, "After refinement " + msg);
 
 
-    //// Remove cells which are inside closed surfaces
-    //// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    //
-    //if (findIndex(surfaces.closed(), true) != -1)
-    //{
-    //    Info<< "Removing cells fully inside closed surfaces."
-    //        << endl;
-    //    removeInsideCells
-    //    (
-    //        msg,               // refinement iteration for statistics only
-    //        exposedFacesPatch  // patch to use for exposed internal faces
-    //    );
-    //    Info<< "Removed inside cells in = "
-    //        << mesh_.time().cpuTimeIncrement() << " s" << endl;
-    //    if (debug)
-    //    {
-    //       // test all is still synced across proc patches
-    //       checkData();
-    //    }
-    //}
-
-
     // Load balancing
     // ~~~~~~~~~~~~~~
 
diff --git a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C
index 83816314a7cdc674876b41d03f47239bd831b171..ce09e597e2480c80f1583778639ff7899aac5b57 100644
--- a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C
+++ b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C
@@ -27,25 +27,17 @@ License
 #include "refinementSurfaces.H"
 #include "orientedSurface.H"
 #include "Time.H"
-#include "searchableSurface.H"
+#include "searchableSurfaces.H"
+#include "shellSurfaces.H"
+#include "triSurfaceMesh.H"
+#include "labelPair.H"
+#include "searchableSurfacesQueries.H"
+
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
-// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-Foam::fileNameList Foam::refinementSurfaces::extractFileNames
-(
-    const PtrList<dictionary>& surfaceDicts
-)
-{
-    fileNameList surfaceFileNames(surfaceDicts.size());
-
-    forAll(surfaceDicts, i)
-    {
-        surfaceFileNames[i] = fileName(surfaceDicts[i].lookup("file"));
-    }
-    return surfaceFileNames;
-}
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
@@ -53,13 +45,13 @@ Foam::fileNameList Foam::refinementSurfaces::extractFileNames
 // Construct from components
 Foam::refinementSurfaces::refinementSurfaces
 (
-    const IOobject& io,
+    const searchableSurfaces& allGeometry,
     const PtrList<dictionary>& surfaceDicts
 )
 :
-    triSurfaceMeshes(io, extractFileNames(surfaceDicts)),
+    allGeometry_(allGeometry),
+    surfaces_(surfaceDicts.size()),
     names_(surfaceDicts.size()),
-    closed_(surfaceDicts.size(), true),
     faceZoneNames_(surfaceDicts.size()),
     cellZoneNames_(surfaceDicts.size()),
     zoneInside_(surfaceDicts.size()),
@@ -67,29 +59,25 @@ Foam::refinementSurfaces::refinementSurfaces
 {
     labelList globalMinLevel(surfaceDicts.size(), 0);
     labelList globalMaxLevel(surfaceDicts.size(), 0);
-    List<HashTable<label> > regionMinLevel(surfaceDicts.size());
-    List<HashTable<label> > regionMaxLevel(surfaceDicts.size());
+    List<Map<label> > regionMinLevel(surfaceDicts.size());
+    List<Map<label> > regionMaxLevel(surfaceDicts.size());
 
-    labelList globalSurfLayers(surfaceDicts.size());
-    List<HashTable<label> > regionSurfLayers(surfaceDicts.size());
-
-    wordList globalPatchType(surfaceDicts.size());
-    List<HashTable<word> > regionPatchType(surfaceDicts.size());
-    List<HashTable<word> > regionPatchName(surfaceDicts.size());
+    //wordList globalPatchType(surfaceDicts.size());
+    //List<HashTable<word> > regionPatchType(surfaceDicts.size());
+    //List<HashTable<word> > regionPatchName(surfaceDicts.size());
 
     forAll(surfaceDicts, surfI)
     {
         const dictionary& dict = surfaceDicts[surfI];
 
-        names_[surfI] = word(dict.lookup("name"));
+        dict.lookup("name") >> names_[surfI];
+
+        surfaces_[surfI] = allGeometry_.findSurfaceID(names_[surfI]);
 
         // Global refinement level
         globalMinLevel[surfI] = readLabel(dict.lookup("minRefinementLevel"));
         globalMaxLevel[surfI] = readLabel(dict.lookup("maxRefinementLevel"));
 
-        // Global number of layers
-        globalSurfLayers[surfI] = readLabel(dict.lookup("surfaceLayers"));
-
         // Global zone names per surface
         if (dict.found("faceZone"))
         {
@@ -98,50 +86,62 @@ Foam::refinementSurfaces::refinementSurfaces
             dict.lookup("zoneInside") >> zoneInside_[surfI];
         }
 
-        // Global patch name per surface
-        if (dict.found("patchType"))
-        {
-            dict.lookup("patchType") >> globalPatchType[surfI];
-        }
+        //// Global patch name per surface
+        //if (dict.found("patchType"))
+        //{
+        //    dict.lookup("patchType") >> globalPatchType[surfI];
+        //}
 
 
         if (dict.found("regions"))
         {
             PtrList<dictionary> regionDicts(dict.lookup("regions"));
 
+            const wordList& regionNames =
+                allGeometry_[surfaces_[surfI]].regions();
+
             forAll(regionDicts, dictI)
             {
                 const dictionary& regionDict = regionDicts[dictI];
 
                 const word regionName(regionDict.lookup("name"));
-                label min = readLabel(regionDict.lookup("minRefinementLevel"));
-                label max = readLabel(regionDict.lookup("maxRefinementLevel"));
 
-                regionMinLevel[surfI].insert(regionName, min);
-                regionMaxLevel[surfI].insert(regionName, max);
+                label regionI = findIndex(regionNames, regionName);
 
-                label nLayers = readLabel(regionDict.lookup("surfaceLayers"));
-                regionSurfLayers[surfI].insert(regionName, nLayers);
-
-                if (regionDict.found("patchType"))
+                if (regionI == -1)
                 {
-                    regionPatchType[surfI].insert
+                    FatalErrorIn
                     (
-                        regionName,
-                        regionDict.lookup("patchType")
-                    );
-                    regionPatchName[surfI].insert
+                        "refinementSurfaces::refinementSurfaces"
+                        "(const IOobject&, const PtrList<dictionary>&)"
+                    )   << "No region called " << regionName << " on surface "
+                        << allGeometry_[surfaces_[surfI]].name() << endl
+                        << "Valid regions are " << regionNames
+                        << exit(FatalError);
+                }
+
+
+                label min = readLabel(regionDict.lookup("minRefinementLevel"));
+                label max = readLabel(regionDict.lookup("maxRefinementLevel"));
+
+                bool hasInserted = regionMinLevel[surfI].insert(regionI, min);
+                if (!hasInserted)
+                {
+                    FatalErrorIn
                     (
-                        regionName,
-                        regionDict.lookup("patchName")
-                    );
+                        "refinementSurfaces::refinementSurfaces"
+                        "(const IOobject&, const PtrList<dictionary>&)"
+                    )   << "Duplicate region name " << regionName
+                        << " on surface " << names_[surfI]
+                        << exit(FatalError);
                 }
+                regionMaxLevel[surfI].insert(regionI, max);
             }
         }
     }
 
 
-    // Check for duplicate surface or region names
+    // Check for duplicate surface names
     {
         HashTable<label> surfaceNames(names_.size());
 
@@ -158,57 +158,173 @@ Foam::refinementSurfaces::refinementSurfaces
                     << surfaceNames[names_[surfI]]
                     << exit(FatalError);
             }
+        }
+    }
+
+    // Calculate local to global region offset
+    label nRegions = 0;
+
+    forAll(surfaceDicts, surfI)
+    {
+        regionOffset_[surfI] = nRegions;
+
+        nRegions += allGeometry_[surfaces_[surfI]].regions().size();
+    }
+
+    // Rework surface specific information into information per global region
+    minLevel_.setSize(nRegions);
+    minLevel_ = 0;
+    maxLevel_.setSize(nRegions);
+    maxLevel_ = 0;
+    //patchName_.setSize(nRegions);
+    //patchType_.setSize(nRegions);
+
+    forAll(surfaceDicts, surfI)
+    {
+        label nRegions = allGeometry_[surfaces_[surfI]].regions().size();
+
+        // Initialise to global (i.e. per surface)
+        for (label i = 0; i < nRegions; i++)
+        {
+            minLevel_[regionOffset_[surfI] + i] = globalMinLevel[surfI];
+            maxLevel_[regionOffset_[surfI] + i] = globalMaxLevel[surfI];
+        }
 
-            // Check for duplicate region names
-            const geometricSurfacePatchList& patches =
-                operator[](surfI).patches();
+        // Overwrite with region specific information
+        forAllConstIter(Map<label>, regionMinLevel[surfI], iter)
+        {
+            label globalRegionI = regionOffset_[surfI] + iter.key();
 
-            HashTable<label> regionNames(patches.size());
-            forAll(patches, i)
+            minLevel_[globalRegionI] = iter();
+            maxLevel_[globalRegionI] = regionMaxLevel[surfI][iter.key()];
+
+            // Check validity
+            if
+            (
+                minLevel_[globalRegionI] < 0
+             || maxLevel_[globalRegionI] < minLevel_[globalRegionI]
+            )
             {
-                if (!regionNames.insert(patches[i].name(), i))
-                {
-                    FatalErrorIn
-                    (
-                        "refinementSurfaces::refinementSurfaces"
-                        "(const IOobject&, const PtrList<dictionary>&)"
-                    )   << "Duplicate region name " << patches[i].name()
-                        << " on surface " << names_[surfI] << endl
-                        << "Previous occurrence of region at index "
-                        << regionNames[patches[i].name()]
-                        << exit(FatalError);
-                }
+                FatalErrorIn
+                (
+                    "refinementSurfaces::refinementSurfaces"
+                    "(const IOobject&, const PtrList<dictionary>&)"
+                )   << "Illegal level or layer specification for surface "
+                    << names_[surfI]
+                    << " : minLevel:" << minLevel_[globalRegionI]
+                    << " maxLevel:" << maxLevel_[globalRegionI]
+                    << exit(FatalError);
             }
         }
+
+        //// Optional patch names and patch types
+        //forAllConstIter(HashTable<word>, regionPatchName[surfI], iter)
+        //{
+        //    label regionI = findIndex(regionNames, iter.key());
+        //    label globalRegionI = regionOffset_[surfI] + regionI;
+        //
+        //    patchName_[globalRegionI] = iter();
+        //    patchType_[globalRegionI] = regionPatchType[surfI][iter.key()];
+        //}
     }
+}
+
 
+Foam::refinementSurfaces::refinementSurfaces
+(
+    const searchableSurfaces& allGeometry,
+    const dictionary& surfacesDict
+)
+:
+    allGeometry_(allGeometry),
+    surfaces_(surfacesDict.size()),
+    names_(surfacesDict.size()),
+    faceZoneNames_(surfacesDict.size()),
+    cellZoneNames_(surfacesDict.size()),
+    zoneInside_(surfacesDict.size()),
+    regionOffset_(surfacesDict.size())
+{
+    labelList globalMinLevel(surfacesDict.size(), 0);
+    labelList globalMaxLevel(surfacesDict.size(), 0);
+    List<Map<label> > regionMinLevel(surfacesDict.size());
+    List<Map<label> > regionMaxLevel(surfacesDict.size());
 
-    // Calculate closedness
-    forAll(closed_, surfI)
+    label surfI = 0;
+    forAllConstIter(dictionary, surfacesDict, iter)
     {
-        const triSurface& s = operator[](surfI);
+        names_[surfI] = iter().keyword();
+
+        surfaces_[surfI] = allGeometry_.findSurfaceID(names_[surfI]);
 
-        const labelListList& edgeFaces = s.edgeFaces();
+        if (surfaces_[surfI] == -1)
+        {
+            FatalErrorIn
+            (
+                "refinementSurfaces::refinementSurfaces"
+                "(const searchableSurfaces&, const dictionary>&"
+            )   << "No surface called " << iter().keyword() << endl
+                << "Valid surfaces are " << allGeometry_.names()
+                << exit(FatalError);
+        }
+        const dictionary& dict = surfacesDict.subDict(iter().keyword());
+
+        const labelPair refLevel(dict.lookup("level"));
+        globalMinLevel[surfI] = refLevel[0];
+        globalMaxLevel[surfI] = refLevel[1];
+
+        // Global zone names per surface
+        if (dict.found("faceZone"))
+        {
+            dict.lookup("faceZone") >> faceZoneNames_[surfI];
+            dict.lookup("cellZone") >> cellZoneNames_[surfI];
+            dict.lookup("zoneInside") >> zoneInside_[surfI];
+        }
 
-        forAll(edgeFaces, edgeI)
+        if (dict.found("regions"))
         {
-            if (edgeFaces[edgeI].size() != 2)
+            const dictionary& regionsDict = dict.subDict("regions");
+            const wordList& regionNames =
+                allGeometry_[surfaces_[surfI]].regions();
+
+            forAllConstIter(dictionary, regionsDict, iter)
             {
-                closed_[surfI] = false;
-                break;
+                const word& key = iter().keyword();
+
+                if (regionsDict.isDict(key))
+                {
+                    // Get the dictionary for region iter.keyword()
+                    const dictionary& regionDict = regionsDict.subDict(key);
+
+                    label regionI = findIndex(regionNames, key);
+                    if (regionI == -1)
+                    {
+                        FatalErrorIn
+                        (
+                            "refinementSurfaces::refinementSurfaces"
+                            "(const searchableSurfaces&, const dictionary>&"
+                        )   << "No region called " << key << " on surface "
+                            << allGeometry_[surfaces_[surfI]].name() << endl
+                            << "Valid regions are " << regionNames
+                            << exit(FatalError);
+                    }
+
+                    const labelPair refLevel(regionDict.lookup("level"));
+
+                    regionMinLevel[surfI].insert(regionI, refLevel[0]);
+                    regionMaxLevel[surfI].insert(regionI, refLevel[1]);
+                }
             }
         }
+        surfI++;
     }
 
-
     // Calculate local to global region offset
     label nRegions = 0;
 
-    forAll(surfaceDicts, surfI)
+    forAll(surfacesDict, surfI)
     {
         regionOffset_[surfI] = nRegions;
-
-        nRegions += operator[](surfI).patches().size();
+        nRegions += allGeometry_[surfaces_[surfI]].regions().size();
     }
 
     // Rework surface specific information into information per global region
@@ -216,92 +332,52 @@ Foam::refinementSurfaces::refinementSurfaces
     minLevel_ = 0;
     maxLevel_.setSize(nRegions);
     maxLevel_ = 0;
-    numLayers_.setSize(nRegions);
-    numLayers_ = 0;
-    patchName_.setSize(nRegions);
-    patchType_.setSize(nRegions);
 
-    forAll(surfaceDicts, surfI)
+
+    forAll(globalMinLevel, surfI)
     {
-        const geometricSurfacePatchList& regions = operator[](surfI).patches();
+        label nRegions = allGeometry_[surfaces_[surfI]].regions().size();
 
         // Initialise to global (i.e. per surface)
-        forAll(regions, i)
+        for (label i = 0; i < nRegions; i++)
         {
             minLevel_[regionOffset_[surfI] + i] = globalMinLevel[surfI];
             maxLevel_[regionOffset_[surfI] + i] = globalMaxLevel[surfI];
-            numLayers_[regionOffset_[surfI] + i] = globalSurfLayers[surfI];
-            patchType_[regionOffset_[surfI] + i] = globalPatchType[surfI];
-        }
-
-        // Get the region names
-        wordList regionNames(regions.size());
-        forAll(regions, regionI)
-        {
-            regionNames[regionI] = regions[regionI].name();
         }
 
         // Overwrite with region specific information
-        forAllConstIter(HashTable<label>, regionMinLevel[surfI], iter)
+        forAllConstIter(Map<label>, regionMinLevel[surfI], iter)
         {
-            // Find the local region number.
-            label regionI = findIndex(regionNames, iter.key());
-
-            if (regionI == -1)
-            {
-                FatalErrorIn
-                (
-                    "refinementSurfaces::refinementSurfaces"
-                    "(const IOobject&, const PtrList<dictionary>&)"
-                )   << "Cannot find region " << iter.key()
-                    << " in surface " << names_[surfI]
-                    << " which has regions " << regionNames
-                    << abort(FatalError);
-            }
-
-            label globalRegionI = regionOffset_[surfI] + regionI;
+            label globalRegionI = regionOffset_[surfI] + iter.key();
 
             minLevel_[globalRegionI] = iter();
             maxLevel_[globalRegionI] = regionMaxLevel[surfI][iter.key()];
-            numLayers_[globalRegionI] = regionSurfLayers[surfI][iter.key()];
 
             // Check validity
             if
             (
                 minLevel_[globalRegionI] < 0
              || maxLevel_[globalRegionI] < minLevel_[globalRegionI]
-             || numLayers_[globalRegionI] < 0
             )
             {
                 FatalErrorIn
                 (
                     "refinementSurfaces::refinementSurfaces"
-                    "(const IOobject&, const PtrList<dictionary>&)"
+                    "(const searchableSurfaces&, const dictionary>&"
                 )   << "Illegal level or layer specification for surface "
                     << names_[surfI]
                     << " : minLevel:" << minLevel_[globalRegionI]
                     << " maxLevel:" << maxLevel_[globalRegionI]
-                    << " numLayers:" << numLayers_[globalRegionI]
                     << exit(FatalError);
             }
         }
-
-        // Optional patch names and patch types
-        forAllConstIter(HashTable<word>, regionPatchName[surfI], iter)
-        {
-            label regionI = findIndex(regionNames, iter.key());
-            label globalRegionI = regionOffset_[surfI] + regionI;
-
-            patchName_[globalRegionI] = iter();
-            patchType_[globalRegionI] = regionPatchType[surfI][iter.key()];
-        }
     }
 }
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-//- Get indices of named surfaces (surfaces with cellZoneNam)
+// Get indices of named surfaces (surfaces with cellZoneName)
 Foam::labelList Foam::refinementSurfaces::getNamedSurfaces() const
 {
    labelList namedSurfaces(cellZoneNames_.size());
@@ -320,16 +396,26 @@ Foam::labelList Foam::refinementSurfaces::getNamedSurfaces() const
 }
 
 
-bool Foam::refinementSurfaces::isSurfaceClosed(const triSurface& s)
+// Get indices of closed named surfaces
+Foam::labelList Foam::refinementSurfaces::getClosedNamedSurfaces() const
 {
-    if (s.nEdges() == s.nInternalEdges())
-    {
-        return true;
-    }
-    else
+    labelList named(getNamedSurfaces());
+
+    labelList closed(named.size());
+    label closedI = 0;
+
+    forAll(named, i)
     {
-        return false;
+        label surfI = named[i];
+
+        if (allGeometry_[surfaces_[surfI]].hasVolumeType())
+        {
+            closed[closedI++] = surfI;
+        }
     }
+    closed.setSize(closedI);
+
+    return closed;
 }
 
 
@@ -373,238 +459,475 @@ Foam::labelList Foam::refinementSurfaces::countRegions(const triSurface& s)
 }
 
 
-// Find intersections of edge. Return -1 or first surface with higher minLevel
-// number.
-Foam::label Foam::refinementSurfaces::findHigherIntersection
+// Precalculate the refinement level for every element of the searchable
+// surface. This is currently hardcoded for triSurfaceMesh only.
+void Foam::refinementSurfaces::setMinLevelFields
 (
-    const point& start,
-    const point& end,
-    const label currentLevel,   // current cell refinement level
-
-    pointIndexHit& hit
-) const
+    const shellSurfaces& shells
+)
 {
-    forAll(*this, surfI)
+    minLevelFields_.setSize(surfaces_.size());
+
+    forAll(surfaces_, surfI)
     {
-        hit = operator[](surfI).findLineAny(start, end);
+        const searchableSurface& geom = allGeometry_[surfaces_[surfI]];
 
-        if (hit.hit())
+        if (isA<triSurfaceMesh>(geom))
         {
-            if (currentLevel == -1)
+            const triSurfaceMesh& triMesh = refCast<const triSurfaceMesh>(geom);
+
+            minLevelFields_.set
+            (
+                surfI,
+                new triSurfaceLabelField
+                (
+                    IOobject
+                    (
+                        triMesh.searchableSurface::name(),
+                        triMesh.objectRegistry::time().constant(),// directory
+                        "triSurface",               // instance
+                        triMesh,
+                        IOobject::NO_READ,
+                        IOobject::AUTO_WRITE,
+                        false
+                    ),
+                    triMesh,
+                    dimless
+                )
+            );
+            triSurfaceLabelField& minLevelField = minLevelFields_[surfI];
+
+            const triSurface& s = static_cast<const triSurface&>(triMesh);
+
+            // Initialise fields to region wise minLevel
+            forAll(s, triI)
             {
-                // Return any.
-                return surfI;
+                minLevelField[triI] = minLevel(surfI, s[triI].region());
             }
-            else
+
+            // Find out if triangle inside shell with higher level
+            pointField fc(s.size());
+            forAll(s, triI)
             {
-                //const triSurface& s = trees()[surfI].shapes().surface();
-                //label region = globalRegion(surfI, s[hit.index()].region());
-                //if (minLevel_[region] > currentLevel)
-                if (minLevelFields_[surfI][hit.index()] > currentLevel)
-                {
-                    return surfI;
-                }
+                fc[triI] = s[triI].centre(s.points());
+            }
+            // What level does shell want to refine fc to?
+            labelList shellLevel;
+            shells.findHigherLevel(fc, minLevelField, shellLevel);
+
+            forAll(minLevelField, triI)
+            {
+                minLevelField[triI] = max
+                (
+                    minLevelField[triI],
+                    shellLevel[triI]
+                );
             }
         }
     }
-
-    hit.setMiss();
-
-    return -1;
 }
 
 
-// Find intersection with max of edge. Return -1 or the surface
-// with the highest maxLevel above currentLevel
-Foam::label Foam::refinementSurfaces::findHighestIntersection
+// Find intersections of edge. Return -1 or first surface with higher minLevel
+// number.
+void Foam::refinementSurfaces::findHigherIntersection
 (
-    const point& start,
-    const point& end,
-    const label currentLevel,   // current cell refinement level
+    const pointField& start,
+    const pointField& end,
+    const labelList& currentLevel,   // current cell refinement level
 
-    pointIndexHit& maxHit
+    labelList& surfaces,
+    labelList& surfaceLevel
 ) const
 {
-    // surface with highest maxlevel
-    label maxSurface = -1;
-    // maxLevel of maxSurface
-    label maxLevel = currentLevel;
+    surfaces.setSize(start.size());
+    surfaces = -1;
+    surfaceLevel.setSize(start.size());
+    surfaceLevel = -1;
+
+    if (surfaces_.size() == 0)
+    {
+        return;
+    }
+
+    // Work arrays
+    labelList hitMap(identity(start.size()));
+    pointField p0(start);
+    pointField p1(end);
+    List<pointIndexHit> hitInfo(start.size());
 
-    forAll(*this, surfI)
+
+    forAll(surfaces_, surfI)
     {
-        pointIndexHit hit = operator[](surfI).findLineAny(start, end);
+        allGeometry_[surfaces_[surfI]].findLineAny(p0, p1, hitInfo);
 
-        if (hit.hit())
+        // Copy all hits into arguments, continue with misses
+        label newI = 0;
+        forAll(hitInfo, hitI)
         {
-            const triSurface& s = operator[](surfI);
+            // Get the minLevel for the point
+            label minLocalLevel = -1;
+
+            if (hitInfo[hitI].hit())
+            {
+                // Check if minLevelField for this surface.
+                if
+                (
+                    minLevelFields_.set(surfI)
+                 && minLevelFields_[surfI].size() > 0
+                )
+                {
+                    minLocalLevel =
+                        minLevelFields_[surfI][hitInfo[hitI].index()];
+                }
+                else
+                {
+                    // Use the min level for the surface instead. Assume
+                    // single region 0. 
+                    minLocalLevel = minLevel(surfI, 0);
+                }
+            }
 
-            label region = globalRegion(surfI, s[hit.index()].region());
+            label pointI = hitMap[hitI];
 
-            if (maxLevel_[region] > maxLevel)
+            if (minLocalLevel > currentLevel[pointI])
+            {
+                surfaces[pointI] = surfI;
+                surfaceLevel[pointI] = minLocalLevel;
+            }
+            else
             {
-                maxSurface = surfI;
-                maxLevel = maxLevel_[region];
-                maxHit = hit;
+                if (hitI != newI)
+                {
+                    hitMap[newI] = hitMap[hitI];
+                    p0[newI] = p0[hitI];
+                    p1[newI] = p1[hitI];
+                }
+                newI++;
             }
         }
-    }
 
-    if (maxSurface == -1)
-    {
-        // maxLevel unchanged. No interesting surface hit.
-        maxHit.setMiss();
-    }
+        // All done? Note that this decision should be synchronised
+        if (newI == 0)
+        {
+            break;
+        }
 
-    return maxSurface;
+        // Trim and continue
+        hitMap.setSize(newI);
+        p0.setSize(newI);
+        p1.setSize(newI);
+        hitInfo.setSize(newI);
+    }
 }
 
 
-Foam::label Foam::refinementSurfaces::insideZone
+void Foam::refinementSurfaces::findAllHigherIntersections
 (
-    const labelList& surfaces,
-    const point& pt
+    const pointField& start,
+    const pointField& end,
+    const labelList& currentLevel,   // current cell refinement level
+
+    List<vectorList>& surfaceNormal,
+    labelListList& surfaceLevel
 ) const
 {
-    forAll(surfaces, i)
+    surfaceLevel.setSize(start.size());
+    surfaceNormal.setSize(start.size());
+
+    if (surfaces_.size() == 0)
     {
-        label surfI = surfaces[i];
+        return;
+    }
+
+    // Work arrays
+    List<List<pointIndexHit> > hitInfo;
+    labelList pRegions;
+    vectorField pNormals;
+
+    forAll(surfaces_, surfI)
+    {
+        allGeometry_[surfaces_[surfI]].findLineAll(start, end, hitInfo);
 
-        if (closed_[surfI])
+        forAll(hitInfo, pointI)
         {
-            const triSurfaceMesh& s = operator[](surfI);
+            const List<pointIndexHit>& pHits = hitInfo[pointI];
+            allGeometry_[surfaces_[surfI]].getRegion(pHits, pRegions);
+            allGeometry_[surfaces_[surfI]].getNormal(pHits, pNormals);
 
-            triSurfaceMesh::volumeType t = s.getVolumeType(pt);
+            // Extract those hits that are on higher levelled surfaces.
+            // Note: should move extraction of region, normal outside of loop
+            // below for if getRegion/getNormal have high overhead.
 
-            if
-            (
-                (t == triSurfaceMesh::INSIDE && zoneInside_[surfI])
-             || (t == triSurfaceMesh::OUTSIDE && !zoneInside_[surfI])
-            )
+            forAll(pHits, pHitI)
             {
-                return surfI;
+                label region = globalRegion(surfI, pRegions[pHitI]);
+
+                if (maxLevel_[region] > currentLevel[pointI])
+                {
+                    // Append to pointI info
+                    label sz = surfaceNormal[pointI].size();
+                    surfaceNormal[pointI].setSize(sz+1);
+                    surfaceNormal[pointI][sz] = pNormals[pHitI];
+
+                    surfaceLevel[pointI].setSize(sz+1);
+                    surfaceLevel[pointI][sz] = maxLevel_[region];
+                }
             }
         }
     }
-    return -1;
 }
 
 
-Foam::label Foam::refinementSurfaces::markInsidePoints
+void Foam::refinementSurfaces::findNearestIntersection
 (
-    const pointField& points,
-    PackedList<1>& isInside
+    const labelList& surfacesToTest,
+    const pointField& start,
+    const pointField& end,
+
+    labelList& surface1,
+    List<pointIndexHit>& hit1,
+    labelList& region1,
+    labelList& surface2,
+    List<pointIndexHit>& hit2,
+    labelList& region2
 ) const
 {
-    isInside.setSize(points.size());
-    isInside = 0u;
+    // 1. intersection from start to end
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    // Initialize arguments
+    surface1.setSize(start.size());
+    surface1 = -1;
+    hit1.setSize(start.size());
+    region1.setSize(start.size());
+
+    // Current end of segment to test.
+    pointField nearest(end);
+    // Work array
+    List<pointIndexHit> nearestInfo(start.size());
+    labelList region;
+
+    forAll(surfacesToTest, testI)
+    {
+        label surfI = surfacesToTest[testI];
 
-    label nPointInside = 0;
+        // See if any intersection between start and current nearest
+        allGeometry_[surfaces_[surfI]].findLine
+        (
+            start,
+            nearest,
+            nearestInfo
+        );
+        allGeometry_[surfaces_[surfI]].getRegion
+        (
+            nearestInfo,
+            region
+        );
 
-    forAll(points, pointI)
-    {
-        forAll(*this, surfI)
+        forAll(nearestInfo, pointI)
         {
-            if (closed()[surfI])
+            if (nearestInfo[pointI].hit())
             {
-                const triSurfaceMesh& s = operator[](surfI);
-
-                triSurfaceMesh::volumeType t = s.getVolumeType(points[pointI]);
-
-                if (t == triSurfaceMesh::INSIDE)
-                {
-                    isInside.set(pointI, 1u);
-                    nPointInside++;
-                    break;
-                }
+                hit1[pointI] = nearestInfo[pointI];
+                surface1[pointI] = surfI;
+                region1[pointI] = region[pointI];
+                nearest[pointI] = hit1[pointI].hitPoint();
             }
         }
     }
 
-    return nPointInside;
-}
 
+    // 2. intersection from end to last intersection
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-void Foam::refinementSurfaces::setMinLevelFields
-(
-    const PtrList<searchableSurface>& shells,
-    const labelList& shellLevels,
-    const boolList& shellRefineInside
-)
-{
-    typedef Foam::DimensionedField<label, triSurfaceGeoMesh>
-        triSurfaceLabelField;
+    // Find the nearest intersection from end to start. Note that we initialize
+    // to the first intersection (if any).
+    surface2 = surface1;
+    hit2 = hit1;
+    region2 = region1;
 
-    minLevelFields_.setSize(size());
+    // Set current end of segment to test.
+    forAll(nearest, pointI)
+    {
+        if (hit1[pointI].hit())
+        {
+            nearest[pointI] = hit1[pointI].hitPoint();
+        }
+        else
+        {
+            // Disable testing by setting to end.
+            nearest[pointI] = end[pointI];
+        }
+    }
 
-    forAll(*this, surfI)
+    forAll(surfacesToTest, testI)
     {
-        const triSurfaceMesh& surfMesh = operator[](surfI);
+        label surfI = surfacesToTest[testI];
 
-        minLevelFields_.set
+        // See if any intersection between end and current nearest
+        allGeometry_[surfaces_[surfI]].findLine
         (
-            surfI,
-            new triSurfaceLabelField
-            (
-                IOobject
-                (
-                    surfMesh.IOobject::name(),
-                    surfMesh.time().constant(), // directory
-                    "triSurface",               // instance
-                    surfMesh,
-                    IOobject::NO_READ,
-                    IOobject::AUTO_WRITE,
-                    false
-                ),
-                surfMesh,
-                dimless
-            )
+            end,
+            nearest,
+            nearestInfo
+        );
+        allGeometry_[surfaces_[surfI]].getRegion
+        (
+            nearestInfo,
+            region
         );
+
+        forAll(nearestInfo, pointI)
+        {
+            if (nearestInfo[pointI].hit())
+            {
+                hit2[pointI] = nearestInfo[pointI];
+                surface2[pointI] = surfI;
+                region2[pointI] = region[pointI];
+                nearest[pointI] = hit2[pointI].hitPoint();
+            }
+        }
     }
+}
 
-    // Initialise fields to region wise minLevel
-    forAll(*this, surfI)
-    {
-        const triSurface& s = operator[](surfI);
 
-        triSurfaceLabelField& minLevelField = minLevelFields_[surfI];
+void Foam::refinementSurfaces::findAnyIntersection
+(
+    const pointField& start,
+    const pointField& end,
+
+    labelList& hitSurface,
+    List<pointIndexHit>& hitInfo
+) const
+{
+    searchableSurfacesQueries::findAnyIntersection
+    (
+        allGeometry_,
+        surfaces_,
+        start,
+        end,
+        hitSurface,
+        hitInfo
+    );
+}
+
 
-        forAll(s, i)
+void Foam::refinementSurfaces::findNearest
+(
+    const labelList& surfacesToTest,
+    const pointField& samples,
+    const  scalarField& nearestDistSqr,
+    labelList& hitSurface,
+    List<pointIndexHit>& hitInfo
+) const
+{
+    labelList geometries(IndirectList<label>(surfaces_, surfacesToTest));
+
+    // Do the tests. Note that findNearest returns index in geometries.
+    searchableSurfacesQueries::findNearest
+    (
+        allGeometry_,
+        geometries,
+        samples,
+        nearestDistSqr,
+        hitSurface,
+        hitInfo
+    );
+
+    // Rework the hitSurface to be surface (i.e. index into surfaces_)
+    forAll(hitSurface, pointI)
+    {
+        if (hitSurface[pointI] != -1)
         {
-            minLevelField[i] = minLevel_[globalRegion(surfI, s[i].region())];
+            hitSurface[pointI] = surfacesToTest[hitSurface[pointI]];
         }
     }
+}
+
 
-    // Adapt for triangles inside shells
-    forAll(*this, surfI)
+//// Find intersection with max of edge. Return -1 or the surface
+//// with the highest maxLevel above currentLevel
+//Foam::label Foam::refinementSurfaces::findHighestIntersection
+//(
+//    const point& start,
+//    const point& end,
+//    const label currentLevel,   // current cell refinement level
+//
+//    pointIndexHit& maxHit
+//) const
+//{
+//    // surface with highest maxlevel
+//    label maxSurface = -1;
+//    // maxLevel of maxSurface
+//    label maxLevel = currentLevel;
+//
+//    forAll(*this, surfI)
+//    {
+//        pointIndexHit hit = operator[](surfI).findLineAny(start, end);
+//
+//        if (hit.hit())
+//        {
+//            const triSurface& s = operator[](surfI);
+//
+//            label region = globalRegion(surfI, s[hit.index()].region());
+//
+//            if (maxLevel_[region] > maxLevel)
+//            {
+//                maxSurface = surfI;
+//                maxLevel = maxLevel_[region];
+//                maxHit = hit;
+//            }
+//        }
+//    }
+//
+//    if (maxSurface == -1)
+//    {
+//        // maxLevel unchanged. No interesting surface hit.
+//        maxHit.setMiss();
+//    }
+//
+//    return maxSurface;
+//}
+
+
+void Foam::refinementSurfaces::findInside
+(
+    const labelList& testSurfaces,
+    const pointField& pt,
+    labelList& insideSurfaces
+) const
+{
+    insideSurfaces.setSize(pt.size());
+    insideSurfaces = -1;
+
+    forAll(testSurfaces, i)
     {
-        const triSurface& s = operator[](surfI);
-        triSurfaceLabelField& minLevelField = minLevelFields_[surfI];
+        label surfI = testSurfaces[i];
 
-        forAll(s, i)
+        if (allGeometry_[surfaces_[surfI]].hasVolumeType())
         {
-            point fc = s[i].centre(s.points());
+            List<searchableSurface::volumeType> volType;
+            allGeometry_[surfaces_[surfI]].getVolumeType(pt, volType);
 
-            forAll(shells, shellI)
+            forAll(volType, pointI)
             {
-                // Which side of shell is to be refined
-                searchableSurface::volumeType refSide =
-                (
-                    shellRefineInside[shellI]
-                  ? searchableSurface::INSIDE
-                  : searchableSurface::OUTSIDE
-                );
-
-                // Find whether point is inside or outside shell
-                searchableSurface::volumeType t =
-                    shells[shellI].getVolumeType(fc);
-
-                if (t == refSide)
+                if (insideSurfaces[pointI] == -1)
                 {
-                    minLevelField[i] = max
+                    if
                     (
-                        minLevelField[i],
-                        shellLevels[shellI]
-                    );
+                        (
+                            volType[pointI] == triSurfaceMesh::INSIDE
+                         && zoneInside_[surfI]
+                        )
+                     || (
+                            volType[pointI] == triSurfaceMesh::OUTSIDE
+                         && !zoneInside_[surfI]
+                        )
+                    )
+                    {
+                        insideSurfaces[pointI] = surfI;
+                    }
                 }
             }
         }
diff --git a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H
index dc5bd0adfb6122f66f61830575c5aedf6c2c8d25..b7cbc91696f25f7e800d4d17596fa53fb55e55fb 100644
--- a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H
+++ b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H
@@ -38,34 +38,38 @@ SourceFiles
 #ifndef refinementSurfaces_H
 #define refinementSurfaces_H
 
-#include "triSurfaceMeshes.H"
 #include "PackedList.H"
 #include "triSurfaceGeoMesh.H"
 #include "triSurfaceFields.H"
+#include "vectorList.H"
+#include "pointIndexHit.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
 
-class searchableSurface;
+class searchableSurfaces;
+class shellSurfaces;
+class triSurfaceMesh;
 
 /*---------------------------------------------------------------------------*\
                            Class refinementSurfaces Declaration
 \*---------------------------------------------------------------------------*/
 
 class refinementSurfaces
-:
-    public triSurfaceMeshes
 {
     // Private data
 
+        //- Reference to all geometry.
+        const searchableSurfaces& allGeometry_;
+
+        //- Indices of surfaces that are refinement ones
+        labelList surfaces_;
+
         //- Surface name (word)
         wordList names_;
 
-        //- Per surface whether is closed
-        boolList closed_;
-
         //- Per 'interface' surface : name of faceZone to put faces into
         wordList faceZoneNames_;
 
@@ -86,24 +90,12 @@ class refinementSurfaces
         //- From global region number to refinement level
         labelList maxLevel_;
 
-        //- From global region number to added layers
-        labelList numLayers_;
-
-        //- From global region number to patch name
-        wordList patchName_;
-
-        //- From global region number to patch name
-        wordList patchType_;
-
-
         //- Per surface refinement level adapted for shells.
         PtrList<triSurfaceLabelField> minLevelFields_;
 
 
     // Private Member Functions
 
-        static fileNameList extractFileNames(const PtrList<dictionary>&);
-
         //- Disallow default bitwise copy construct
         refinementSurfaces(const refinementSurfaces&);
 
@@ -115,28 +107,34 @@ public:
 
     // Constructors
 
-        //- Construct from directory (io.instance()) and dictionaries
+        //- Construct from surfaces and dictionaries
         refinementSurfaces
         (
-            const IOobject& io,
+            const searchableSurfaces& allGeometry,
             const PtrList<dictionary>&
         );
 
+        //- Construct from surfaces and dictionary
+        refinementSurfaces
+        (
+            const searchableSurfaces& allGeometry,
+            const dictionary&
+        );
+
 
     // Member Functions
 
         // Access
 
-            //- Names of surfaces
-            const wordList& names() const
+            const labelList& surfaces() const
             {
-                return names_;
+                return surfaces_;
             }
 
-            //- Per surface whether is closed
-            const boolList& closed() const
+            //- Names of surfaces
+            const wordList& names() const
             {
-                return closed_;
+                return names_;
             }
 
             //- Per 'interface' surface : name of faceZone to put faces into
@@ -151,15 +149,11 @@ public:
                 return cellZoneNames_;
             }
 
-            //- Per 'interface' surface : if closed: zonify cells inside surface
-            const boolList& zoneInside() const
-            {
-                return zoneInside_;
-            }
-
             //- Get indices of named surfaces (surfaces with cellZoneName)
             labelList getNamedSurfaces() const;
 
+            //- Get indices of closed named surfaces
+            labelList getClosedNamedSurfaces() const;
 
             //- From local region number to global region number
             const labelList& regionOffset() const
@@ -179,24 +173,6 @@ public:
                 return maxLevel_;
             }
 
-            //- From global region number to added layers
-            const labelList& numLayers() const
-            {
-                return numLayers_;
-            }
-
-            //- From global region number to patch name. Patchnames can be empty
-            const wordList& patchName() const
-            {
-                return patchName_;
-            }
-
-            //- From global region number to patch name
-            const wordList& patchType() const
-            {
-                return patchType_;
-            }
-
 
         // Helper
 
@@ -206,14 +182,6 @@ public:
                 return regionOffset_[surfI]+regionI;
             }
 
-            //- From triangle on surface to global region
-            label triangleRegion(const label surfI, const label triI) const
-            {
-                const triSurface& s = operator[](surfI);
-
-                return globalRegion(surfI, s[triI].region());
-            }
-
             //- Min level for surface and region on surface
             label minLevel(const label surfI, const label regionI) const
             {
@@ -231,23 +199,12 @@ public:
                 return minLevel_.size();
             }
 
-            //- Minlevel updated for refinement shells
-            const triSurfaceLabelField& minLevelField(const label surfI) const
-            {
-                return minLevelFields_[surfI];
-            }
-
             //- Calculate minLevelFields
             void setMinLevelFields
             (
-                const PtrList<searchableSurface>& shells,
-                const labelList& shellLevels,
-                const boolList& shellRefineInside
+                const shellSurfaces& shells
             );
 
-            //- Helper: is surface closed?
-            static bool isSurfaceClosed(const triSurface&);
-
             //- Helper: orient (closed only) surfaces so keepPoint is outside.
             static void orientSurface
             (
@@ -263,36 +220,71 @@ public:
 
             //- Find intersection of edge. Return -1 or first surface
             //  with higher (than currentLevel) minlevel.
-            //  Return surface number and hit info.
-            label findHigherIntersection
+            //  Return surface number and level.
+            void findHigherIntersection
             (
-                const point& start,
-                const point& end,
-                const label currentLevel,   // current cell refinement level
-                pointIndexHit&
+                const pointField& start,
+                const pointField& end,
+                const labelList& currentLevel,  // current cell refinement level
+
+                labelList& surfaces,
+                labelList& surfaceLevel
             ) const;
 
-            //- Find intersection with max level. Return -1 or the surface
-            //  with the highest maxLevel above currentLevel
-            label findHighestIntersection
+            //- Find all intersections of edge. Unsorted order.
+            void findAllHigherIntersections
             (
-                const point& start,
-                const point& end,
-                const label currentLevel,   // current cell refinement level
-                pointIndexHit&
+                const pointField& start,
+                const pointField& end,
+                const labelList& currentLevel,  // current cell refinement level
+
+                List<vectorList>& surfaceNormal,
+                labelListList& surfaceLevel
             ) const;
 
-            //- Detect if a point is 'inside' (depending on zoneInside flag) a
-            //  zoneable surface. Returns -1 if not, returns first surface it
-            //  is.
-            label insideZone(const labelList& surfaces, const point& pt) const;
+            //- Find intersection nearest to the endpoints. surface1,2 are
+            //  not indices into surfacesToTest but refinement surface indices.
+            void findNearestIntersection
+            (
+                const labelList& surfacesToTest,
+                const pointField& start,
+                const pointField& end,
+
+                labelList& surface1,
+                List<pointIndexHit>& hit1,
+                labelList& region1,
+                labelList& surface2,
+                List<pointIndexHit>& hit2,
+                labelList& region2
+            ) const;
 
+            //- Used for debugging only: find intersection of edge.
+            void findAnyIntersection
+            (
+                const pointField& start,
+                const pointField& end,
+                labelList& surfaces,
+                List<pointIndexHit>&
+            ) const;
 
-            //- Mark for all points whether it is inside any closed surface
-            //  Return number of inside points.
-            label markInsidePoints(const pointField&, PackedList<1>& isInside)
-             const;
+            //- Find nearest point on surfaces.
+            void findNearest
+            (
+                const labelList& surfacesToTest,
+                const pointField& samples,
+                const scalarField& nearestDistSqr,
+                labelList& surfaces,
+                List<pointIndexHit>&
+            ) const;
 
+            //- Detect if a point is 'inside' (closed) surfaces.
+            //  Returns -1 if not, returns first surface it is.
+            void findInside
+            (
+                const labelList& surfacesToTest,
+                const pointField& pt,
+                labelList& insideSurfaces
+            ) const;
 };
 
 
diff --git a/src/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.C b/src/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.C
new file mode 100644
index 0000000000000000000000000000000000000000..fe64ea81c3d86d8f57b661ac0b24c4d694d76696
--- /dev/null
+++ b/src/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.C
@@ -0,0 +1,465 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "searchableSurface.H"
+#include "shellSurfaces.H"
+#include "boundBox.H"
+#include "triSurfaceMesh.H"
+#include "refinementSurfaces.H"
+#include "searchableSurfaces.H"
+#include "pointIndexHit.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+
+namespace Foam
+{
+
+template<>
+const char*
+NamedEnum<shellSurfaces::refineMode, 3>::
+names[] =
+{
+    "inside",
+    "outside",
+    "distance"
+};
+
+const NamedEnum<shellSurfaces::refineMode, 3> shellSurfaces::refineModeNames_;
+
+} // End namespace Foam
+
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::shellSurfaces::setAndCheckLevels
+(
+    const scalar shellI,
+    const List<Tuple2<scalar, label> >& distLevels
+)
+{
+    if (modes_[shellI] != DISTANCE && distLevels.size() != 1)
+    {
+        FatalErrorIn
+        (
+            "shellSurfaces::shellSurfaces"
+            "(const searchableSurfaces&, const dictionary&)"
+        )   << "For refinement mode "
+            << refineModeNames_[modes_[shellI]]
+            << " specify only one distance+level."
+            << " (its distance gets discarded)"
+            << exit(FatalError);
+    }
+    // Extract information into separate distance and level
+    distances_[shellI].setSize(distLevels.size());
+    levels_[shellI].setSize(distLevels.size());
+
+    forAll(distLevels, j)
+    {
+        distances_[shellI][j] = distLevels[j].first();
+        levels_[shellI][j] = distLevels[j].second();
+
+        // Check in incremental order
+        if (j > 0)
+        {
+            if
+            (
+                (distances_[shellI][j] <= distances_[shellI][j-1])
+             || (levels_[shellI][j] > levels_[shellI][j-1])
+            )
+            {
+                FatalErrorIn
+                (
+                    "shellSurfaces::shellSurfaces"
+                    "(const searchableSurfaces&, const dictionary&)"
+                )   << "For refinement mode "
+                    << refineModeNames_[modes_[shellI]]
+                    << " : Refinement should be specified in order"
+                    << " of increasing distance"
+                    << " (and decreasing refinement level)." << endl
+                    << "Distance:" << distances_[shellI][j]
+                    << " refinementLevel:" << levels_[shellI][j]
+                    << exit(FatalError);
+            }
+        }
+    }
+
+    const searchableSurface& shell = allGeometry_[shells_[shellI]];
+
+    if (modes_[shellI] == DISTANCE)
+    {
+        Info<< "Refinement level according to distance to "
+            << shell.name() << endl;
+        forAll(levels_[shellI], j)
+        {
+            Info<< "    level " << levels_[shellI][j]
+                << " for all cells within " << distances_[shellI][j]
+                << " meter." << endl;
+        }
+    }
+    else
+    {
+        if (!allGeometry_[shells_[shellI]].hasVolumeType())
+        {
+            FatalErrorIn
+            (
+                "shellSurfaces::shellSurfaces"
+                "(const searchableSurfaces&"
+                ", const PtrList<dictionary>&)"
+            )   << "Shell " << shell.name()
+                << " does not support testing for "
+                << refineModeNames_[modes_[shellI]] << endl
+                << "Probably it is not closed."
+                << exit(FatalError);
+        }
+
+        if (modes_[shellI] == INSIDE)
+        {
+            Info<< "Refinement level " << levels_[shellI][0]
+                << " for all cells inside " << shell.name() << endl;
+        }
+        else
+        {
+            Info<< "Refinement level " << levels_[shellI][0]
+                << " for all cells outside " << shell.name() << endl;
+        }
+    }
+}
+
+
+// Specifically orient triSurfaces using a calculated point outside.
+// Done since quite often triSurfaces not of consistent orientation which
+// is (currently) necessary for sideness calculation
+void Foam::shellSurfaces::orient()
+{
+    // Determine outside point.
+    boundBox overallBb
+    (
+        point(GREAT, GREAT, GREAT),
+        point(-GREAT, -GREAT, -GREAT)
+    );
+
+    bool hasSurface = false;
+
+    forAll(shells_, shellI)
+    {
+        const searchableSurface& s = allGeometry_[shells_[shellI]];
+
+        if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s))
+        {
+            const triSurfaceMesh& shell = refCast<const triSurfaceMesh>(s);
+
+            if (shell.triSurface::size() > 0)
+            {
+                const pointField& points = shell.points();
+
+                hasSurface = true;
+
+                boundBox shellBb(points[0], points[0]);
+                // Assume surface is compact!
+                for (label i = 0; i < points.size(); i++)
+                {
+                    const point& pt = points[i];
+                    shellBb.min() = min(shellBb.min(), pt);
+                    shellBb.max() = max(shellBb.max(), pt);
+                }
+
+                overallBb.min() = min(overallBb.min(), shellBb.min());
+                overallBb.max() = max(overallBb.max(), shellBb.max());
+            }
+        }
+    }
+
+    if (hasSurface)
+    {
+        const point outsidePt(2*overallBb.max() - overallBb.min());
+
+        //Info<< "Using point " << outsidePt << " to orient shells" << endl;
+
+        forAll(shells_, shellI)
+        {
+            const searchableSurface& s = allGeometry_[shells_[shellI]];
+
+            if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s))
+            {
+                triSurfaceMesh& shell = const_cast<triSurfaceMesh&>
+                (
+                    refCast<const triSurfaceMesh>(s)
+                );
+
+                refinementSurfaces::orientSurface(outsidePt, shell);
+            }
+        }
+    }
+}
+
+
+// Find maximum level of a shell.
+void Foam::shellSurfaces::findHigherLevel
+(
+    const pointField& pt,
+    const label shellI,
+    labelList& maxLevel
+) const
+{
+    const labelList& levels = levels_[shellI];
+
+    if (modes_[shellI] == DISTANCE)
+    {
+        // Distance mode.
+
+        const scalarField& distances = distances_[shellI];
+
+        // Collect all those points that have a current maxLevel less than
+        // (any of) the shell. Also collect the furthest distance allowable
+        // to any shell with a higher level.
+
+        pointField candidates(pt.size());
+        labelList candidateMap(pt.size());
+        scalarField candidateDistSqr(pt.size());
+        label candidateI = 0;
+
+        forAll(maxLevel, pointI)
+        {
+            forAllReverse(levels, levelI)
+            {
+                if (levels[levelI] > maxLevel[pointI])
+                {
+                    candidates[candidateI] = pt[pointI];
+                    candidateMap[candidateI] = pointI;
+                    candidateDistSqr[candidateI] = sqr(distances[levelI]);
+                    candidateI++;
+                    break;
+                }
+            }
+        }
+        candidates.setSize(candidateI);
+        candidateMap.setSize(candidateI);
+        candidateDistSqr.setSize(candidateI);
+
+        // Do the expensive nearest test only for the candidate points.
+        List<pointIndexHit> nearInfo;
+        allGeometry_[shells_[shellI]].findNearest
+        (
+            candidates,
+            candidateDistSqr,
+            nearInfo
+        );
+
+        // Update maxLevel
+        forAll(nearInfo, candidateI)
+        {
+            if (nearInfo[candidateI].hit())
+            {
+                // Check which level it actually is in.
+                label minDistI = findLower
+                (
+                    distances,
+                    mag(nearInfo[candidateI].hitPoint()-candidates[candidateI])
+                );
+
+                label pointI = candidateMap[candidateI];
+
+                // pt is inbetween shell[minDistI] and shell[minDistI+1]
+                maxLevel[pointI] = levels[minDistI+1];
+            }
+        }
+    }
+    else
+    {
+        // Inside/outside mode
+
+        // Collect all those points that have a current maxLevel less than the
+        // shell.
+
+        pointField candidates(pt.size());
+        labelList candidateMap(pt.size());
+        label candidateI = 0;
+
+        forAll(maxLevel, pointI)
+        {
+            if (levels[0] > maxLevel[pointI])
+            {
+                candidates[candidateI] = pt[pointI];
+                candidateMap[candidateI] = pointI;
+                candidateI++;
+            }
+        }
+        candidates.setSize(candidateI);
+        candidateMap.setSize(candidateI);
+
+        // Do the expensive nearest test only for the candidate points.
+        List<searchableSurface::volumeType> volType;
+        allGeometry_[shells_[shellI]].getVolumeType(candidates, volType);
+
+        forAll(volType, i)
+        {
+            label pointI = candidateMap[i];
+
+            if
+            (
+                (
+                    modes_[shellI] == INSIDE
+                 && volType[i] == searchableSurface::INSIDE
+                )
+             || (
+                    modes_[shellI] == OUTSIDE
+                 && volType[i] == searchableSurface::OUTSIDE
+                )
+            )
+            {
+                maxLevel[pointI] = levels[0];
+            }
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::shellSurfaces::shellSurfaces
+(
+    const searchableSurfaces& allGeometry,
+    const PtrList<dictionary>& shellDicts
+)
+:
+    allGeometry_(allGeometry)
+{
+    shells_.setSize(shellDicts.size());
+    modes_.setSize(shellDicts.size());
+    distances_.setSize(shellDicts.size());
+    levels_.setSize(shellDicts.size());
+
+    forAll(shellDicts, shellI)
+    {
+        const dictionary& dict = shellDicts[shellI];
+        const word name = dict.lookup("name");
+        const word type = dict.lookup("type");
+
+        shells_[shellI] = allGeometry_.findSurfaceID(name);
+
+        if (shells_[shellI] == -1)
+        {
+            FatalErrorIn
+            (
+                "shellSurfaces::shellSurfaces"
+                "(const searchableSurfaces&, const PtrList<dictionary>&)"
+            )   << "No surface called " << name << endl
+                << "Valid surfaces are " << allGeometry_.names()
+                << exit(FatalError);
+        }
+
+        modes_[shellI] = refineModeNames_.read(dict.lookup("refineMode"));
+
+        // Read pairs of distance+level
+        setAndCheckLevels(shellI, dict.lookup("levels"));
+    }
+
+    // Orient shell surfaces before any searching is done. Note that this
+    // only needs to be done for inside or outside. Orienting surfaces
+    // constructs lots of addressing which we want to avoid.
+    orient();
+}
+
+
+Foam::shellSurfaces::shellSurfaces
+(
+    const searchableSurfaces& allGeometry,
+    const dictionary& shellsDict
+)
+:
+    allGeometry_(allGeometry)
+{
+    shells_.setSize(shellsDict.size());
+    modes_.setSize(shellsDict.size());
+    distances_.setSize(shellsDict.size());
+    levels_.setSize(shellsDict.size());
+
+    label shellI = 0;
+    forAllConstIter(dictionary, shellsDict, iter)
+    {
+        shells_[shellI] = allGeometry_.findSurfaceID(iter().keyword());
+
+        if (shells_[shellI] == -1)
+        {
+            FatalErrorIn
+            (
+                "shellSurfaces::shellSurfaces"
+                "(const searchableSurfaces&, const dictionary>&"
+            )   << "No surface called " << iter().keyword() << endl
+                << "Valid surfaces are " << allGeometry_.names()
+                << exit(FatalError);
+        }
+        const dictionary& dict = shellsDict.subDict(iter().keyword());
+
+        modes_[shellI] = refineModeNames_.read(dict.lookup("mode"));
+
+        // Read pairs of distance+level
+        setAndCheckLevels(shellI, dict.lookup("levels"));
+
+        shellI++;
+    }
+
+    // Orient shell surfaces before any searching is done. Note that this
+    // only needs to be done for inside or outside. Orienting surfaces
+    // constructs lots of addressing which we want to avoid.
+    orient();
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+// Highest shell level
+Foam::label Foam::shellSurfaces::maxLevel() const
+{
+    label overallMax = 0;
+    forAll(levels_, shellI)
+    {
+        overallMax = max(overallMax, max(levels_[shellI]));
+    }
+    return overallMax;
+}
+
+
+void Foam::shellSurfaces::findHigherLevel
+(
+    const pointField& pt,
+    const labelList& ptLevel,
+    labelList& maxLevel
+) const
+{
+    // Maximum level of any shell. Start off with level of point.
+    maxLevel = ptLevel;
+
+    forAll(shells_, shellI)
+    {
+        findHigherLevel(pt, shellI, maxLevel);
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.H b/src/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.H
new file mode 100644
index 0000000000000000000000000000000000000000..b996e98e8972f76544c73d032babc2a73ffd5778
--- /dev/null
+++ b/src/autoMesh/autoHexMesh/shellSurfaces/shellSurfaces.H
@@ -0,0 +1,182 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    shellSurfaces
+
+Description
+    Encapsulates queries for volume refinement ('refine all cells within
+    shell').
+
+SourceFiles
+    shellSurfaces.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef shellSurfaces_H
+#define shellSurfaces_H
+
+#include "searchableSurface.H"
+#include "Tuple2.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+class searchableSurfaces;
+
+/*---------------------------------------------------------------------------*\
+                           Class shellSurfaces Declaration
+\*---------------------------------------------------------------------------*/
+
+class shellSurfaces
+{
+public:
+
+    // Public data types
+
+        //- Volume refinement controls
+        enum refineMode
+        {
+            INSIDE,         // Refine all inside shell
+            OUTSIDE,        // ,,         outside
+            DISTANCE        // Refine based on distance to shell
+        };
+
+
+private:
+
+    // Private data
+
+        //- Reference to all geometry.
+        const searchableSurfaces& allGeometry_;
+
+        //- Indices of surfaces that are shells
+        labelList shells_;
+
+        //- Per shell whether to refine inside or outside
+        List<refineMode> modes_;
+
+        //- Per shell the list of ranges
+        List<scalarField> distances_;
+
+        //- Per shell per distance the refinement level
+        labelListList levels_;
+
+
+    // Private data
+
+        //- refineMode names
+        static const NamedEnum<refineMode, 3> refineModeNames_;
+
+
+    // Private Member Functions
+
+        //- Helper function for initialisation.
+        void setAndCheckLevels
+        (
+            const scalar shellI,
+            const List<Tuple2<scalar, label> >&
+        );
+
+        void orient();
+
+        void findHigherLevel
+        (
+            const pointField& pt,
+            const label shellI,
+            labelList& maxLevel
+        ) const;
+
+public:
+
+    // Constructors
+
+        //- Construct from components
+        shellSurfaces
+        (
+            const searchableSurfaces& allGeometry,
+            const labelList& shells,
+            const List<refineMode>& modes,
+            const List<scalarField>& distances,
+            const labelListList& levels
+        );
+
+        //- Construct from geometry and dictionaries
+        shellSurfaces
+        (
+            const searchableSurfaces& allGeometry,
+            const PtrList<dictionary>& shellDicts
+        );
+
+        //- Construct from geometry and dictionary
+        shellSurfaces
+        (
+            const searchableSurfaces& allGeometry,
+            const dictionary& shellsDict
+        );
+
+
+    // Member Functions
+
+        // Access
+
+            //const List<scalarField>& distances() const
+            //{
+            //    return distances_;
+            //}
+            //
+            ////- Per shell per distance the refinement level
+            //const labelListList& levels() const
+            //{
+            //    return levels_;
+            //}
+
+
+        // Query
+
+            //- Highest shell level
+            label maxLevel() const;
+
+            //- Find shell level higher than ptLevel
+            void findHigherLevel
+            (
+                const pointField& pt,
+                const labelList& ptLevel,
+                labelList& maxLevel
+            ) const;
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/autoMesh/autoHexMesh/trackedParticle/ExactParticle.C b/src/autoMesh/autoHexMesh/trackedParticle/ExactParticle.C
index 508143aaf9729a6ccd63648325f06bacc16fa353..cebb6597c217c15bdcdf5a9780e7dfe365b5f787 100644
--- a/src/autoMesh/autoHexMesh/trackedParticle/ExactParticle.C
+++ b/src/autoMesh/autoHexMesh/trackedParticle/ExactParticle.C
@@ -256,7 +256,7 @@ Foam::Ostream& Foam::operator<<
     const ExactParticle<ParticleType>& p
 )
 {
-    return operator<<(os, static_cast<Particle<ParticleType> >(p));
+    return operator<<(os, static_cast<const Particle<ParticleType>&>(p));
 }
 
 
diff --git a/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.C b/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.C
index c1c0e4f316edb9801cf722a14e11417bb5afade5..0742fd44b50fd83ec1c3f03b563e08c17a6f0e6e 100644
--- a/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.C
+++ b/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.C
@@ -553,7 +553,7 @@ Foam::labelListList Foam::addPatchCellLayer::addedCells() const
 
 void Foam::addPatchCellLayer::setRefinement
 (
-    const scalar expansionRatio,
+    const scalarField& expansionRatio,
     const indirectPrimitivePatch& pp,
     const labelList& nFaceLayers,
     const labelList& nPointLayers,
@@ -885,7 +885,7 @@ void Foam::addPatchCellLayer::setRefinement
 
                 addedPoints_[patchPointI][i] = addedVertI;
 
-                disp *= expansionRatio;
+                disp *= expansionRatio[patchPointI];
             }
         }
     }
diff --git a/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.H b/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.H
index 0e47acb7eaeec67dbdec4334e19b0cc337db57b8..0b5caaba86f8d2b84c6f1605809ecb5925937d0b 100644
--- a/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.H
+++ b/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.H
@@ -305,7 +305,7 @@ public:
             //        (instead of e.g. from patch faces)
            void setRefinement
            (
-               const scalar expansionRatio,
+               const scalarField& expansionRatio,
                const indirectPrimitivePatch& pp,
                const labelList& nFaceLayers,
                const labelList& nPointLayers,
@@ -325,7 +325,7 @@ public:
             {
                 setRefinement
                 (
-                    1.0,            // expansion ration
+                    scalarField(pp.nPoints(), 1.0), // expansion ration
                     pp,
                     labelList(pp.size(), nLayers),
                     labelList(pp.nPoints(), nLayers),
diff --git a/src/meshTools/Make/files b/src/meshTools/Make/files
index 3a3d2aff830ff305ddb6e6057dc244bcfa7e93f6..90f9de250e298142d18b889e8be63a8bf86dac96 100644
--- a/src/meshTools/Make/files
+++ b/src/meshTools/Make/files
@@ -53,6 +53,14 @@ indexedOctree/treeDataFace.C
 indexedOctree/treeDataPoint.C
 indexedOctree/treeDataTriSurface.C
 
+searchableSurface = searchableSurface
+$(searchableSurface)/searchableBox.C
+$(searchableSurface)/searchableSphere.C
+$(searchableSurface)/searchableSurface.C
+$(searchableSurface)/searchableSurfaces.C
+$(searchableSurface)/searchableSurfacesQueries.C
+$(searchableSurface)/triSurfaceMesh.C
+
 topoSets = sets/topoSets
 $(topoSets)/cellSet.C
 $(topoSets)/topoSet.C
@@ -117,20 +125,10 @@ $(intersectedSurface)/intersectedSurface.C
 $(intersectedSurface)/edgeSurface.C
 
 triSurface/triSurfaceSearch/triSurfaceSearch.C
-
 triSurface/octreeData/octreeDataTriSurface.C
 triSurface/octreeData/octreeDataTriSurfaceTreeLeaf.C
-
 triSurface/triangleFuncs/triangleFuncs.C
-
-triSurface/searchableSurface/searchableSurface.C
-triSurface/searchableSurface/triSurfaceMesh.C
-triSurface/searchableSurface/searchableBox.C
-
 triSurface/surfaceFeatures/surfaceFeatures.C
-
-triSurface/triSurfaceMeshes/triSurfaceMeshes.C
-
 triSurface/triSurfaceTools/triSurfaceTools.C
 triSurface/triSurfaceTools/geompack/geompack.C
 
diff --git a/src/meshTools/searchableSurface/searchableBox.C b/src/meshTools/searchableSurface/searchableBox.C
new file mode 100644
index 0000000000000000000000000000000000000000..be3969d6f4061569bb73103f2c7e9a93ba82d339
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableBox.C
@@ -0,0 +1,541 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "searchableBox.H"
+#include "addToRunTimeSelectionTable.H"
+#include "SortableList.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+defineTypeNameAndDebug(searchableBox, 0);
+addToRunTimeSelectionTable(searchableSurface, searchableBox, dict);
+
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::searchableBox::projectOntoCoordPlane
+(
+    const direction dir,
+    const point& planePt,
+    pointIndexHit& info
+) const
+{
+    // Set point
+    info.rawPoint()[dir] = planePt[dir];
+    // Set face
+    if (planePt[dir] == min()[dir])
+    {
+        info.setIndex(dir*2);
+    }
+    else if (planePt[dir] == max()[dir])
+    {
+        info.setIndex(dir*2+1);
+    }
+    else
+    {
+        FatalErrorIn("searchableBox::projectOntoCoordPlane(..)")
+            << "Point on plane " << planePt
+            << " is not on coordinate " << min()[dir]
+            << " nor " << max()[dir] << abort(FatalError);
+    }
+}
+
+
+// Returns miss or hit with face (0..5) and region(always 0)
+Foam::pointIndexHit Foam::searchableBox::findNearest
+(
+    const point& bbMid,
+    const point& sample,
+    const scalar nearestDistSqr
+) const
+{
+    // Point can be inside or outside. For every component direction can be
+    // left of min, right of max or inbetween.
+    // - outside points: project first one x plane (either min().x()
+    // or max().x()), then onto y plane and finally z. You should be left
+    // with intersection point
+    // - inside point: find nearest side (compare to mid point). Project onto
+    //   that.
+
+    // The face is set to the last projected face.
+
+
+    // Outside point projected onto cube. Assume faces 0..5.
+    pointIndexHit info(true, sample, -1);
+    bool outside = false;
+
+    // (for internal points) per direction what nearest cube side is
+    point near;
+
+    for (direction dir = 0; dir < vector::nComponents; dir++)
+    {
+        if (info.rawPoint()[dir] < min()[dir])
+        {
+            projectOntoCoordPlane(dir, min(), info);
+            outside = true;
+        }
+        else if (info.rawPoint()[dir] > max()[dir])
+        {
+            projectOntoCoordPlane(dir, max(), info);
+            outside = true;
+        }
+        else if (info.rawPoint()[dir] > bbMid[dir])
+        {
+            near[dir] = max()[dir];
+        }
+        else
+        {
+            near[dir] = min()[dir];
+        }
+    }
+
+
+    // For outside points the info will be correct now. Handle inside points
+    // using the three near distances. Project onto the nearest plane.
+    if (!outside)
+    {
+        vector dist(cmptMag(info.rawPoint() - near));
+
+        if (dist.x() < dist.y())
+        {
+            if (dist.x() < dist.z())
+            {
+                // Project onto x plane
+                projectOntoCoordPlane(vector::X, near, info);
+            }
+            else
+            {
+                projectOntoCoordPlane(vector::Z, near, info);
+            }
+        }
+        else
+        {
+            if (dist.y() < dist.z())
+            {
+                projectOntoCoordPlane(vector::Y, near, info);
+            }
+            else
+            {
+                projectOntoCoordPlane(vector::Z, near, info);
+            }
+        }
+    }
+
+
+    // Check if outside. Optimisation: could do some checks on distance already
+    // on components above
+    if (magSqr(info.rawPoint() - sample) > nearestDistSqr)
+    {
+        info.setMiss();
+        info.setIndex(-1);
+    }
+
+    return info;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::searchableBox::searchableBox
+(
+    const IOobject& io,
+    const treeBoundBox& bb
+)
+:
+    searchableSurface(io),
+    treeBoundBox(bb)
+{}
+
+
+Foam::searchableBox::searchableBox
+(
+    const IOobject& io,
+    const dictionary& dict
+)
+:
+    searchableSurface(io),
+    treeBoundBox(dict.lookup("min"), dict.lookup("max"))
+{}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::searchableBox::~searchableBox()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+const Foam::wordList& Foam::searchableBox::regions() const
+{
+    if (regions_.size() == 0)
+    {
+        regions_.setSize(1);
+        regions_[0] = "region0";
+    }
+    return regions_;
+}
+
+
+Foam::pointIndexHit Foam::searchableBox::findNearest
+(
+    const point& sample,
+    const scalar nearestDistSqr
+) const
+{
+    return findNearest(mid(), sample, nearestDistSqr);
+}
+
+
+Foam::pointIndexHit Foam::searchableBox::findNearestOnEdge
+(
+    const point& sample,
+    const scalar nearestDistSqr
+) const
+{
+    const point bbMid(mid());
+
+    // Outside point projected onto cube. Assume faces 0..5.
+    pointIndexHit info(true, sample, -1);
+    bool outside = false;
+
+    // (for internal points) per direction what nearest cube side is
+    point near;
+
+    for (direction dir = 0; dir < vector::nComponents; dir++)
+    {
+        if (info.rawPoint()[dir] < min()[dir])
+        {
+            projectOntoCoordPlane(dir, min(), info);
+            outside = true;
+        }
+        else if (info.rawPoint()[dir] > max()[dir])
+        {
+            projectOntoCoordPlane(dir, max(), info);
+            outside = true;
+        }
+        else if (info.rawPoint()[dir] > bbMid[dir])
+        {
+            near[dir] = max()[dir];
+        }
+        else
+        {
+            near[dir] = min()[dir];
+        }
+    }
+
+
+    // For outside points the info will be correct now. Handle inside points
+    // using the three near distances. Project onto the nearest two planes.
+    if (!outside)
+    {
+        // Get the per-component distance to nearest wall
+        vector dist(cmptMag(info.rawPoint() - near));
+
+        SortableList<scalar> sortedDist(3);
+        sortedDist[0] = dist[0];
+        sortedDist[1] = dist[1];
+        sortedDist[2] = dist[2];
+        sortedDist.sort();
+
+        // Project onto nearest
+        projectOntoCoordPlane(sortedDist.indices()[0], near, info);
+        // Project onto second nearest
+        projectOntoCoordPlane(sortedDist.indices()[1], near, info);
+    }
+
+
+    // Check if outside. Optimisation: could do some checks on distance already
+    // on components above
+    if (magSqr(info.rawPoint() - sample) > nearestDistSqr)
+    {
+        info.setMiss();
+        info.setIndex(-1);
+    }
+
+    return info;
+}
+
+
+Foam::pointIndexHit Foam::searchableBox::findNearest
+(
+    const linePointRef& ln,
+    treeBoundBox& tightest,
+    point& linePoint
+) const
+{
+    notImplemented
+    (
+        "searchableBox::findNearest"
+        "(const linePointRef&, treeBoundBox&, point&)"
+    );
+    return pointIndexHit();
+}
+
+
+Foam::pointIndexHit Foam::searchableBox::findLine
+(
+    const point& start,
+    const point& end
+) const
+{
+    pointIndexHit info(false, start, -1);
+
+    bool foundInter;
+
+    if (posBits(start) == 0)
+    {
+        if (posBits(end) == 0)
+        {
+            // Both start and end inside.
+            foundInter = false;
+        }
+        else
+        {
+            // end is outside. Clip to bounding box.
+            foundInter = intersects(end, start, info.rawPoint());
+        }
+    }
+    else
+    {
+        // start is outside. Clip to bounding box.
+        foundInter = intersects(start, end, info.rawPoint());
+    }
+
+
+    // Classify point
+    if (foundInter)
+    {
+        info.setHit();
+
+        for (direction dir = 0; dir < vector::nComponents; dir++)
+        {
+            if (info.rawPoint()[dir] == min()[dir])
+            {
+                info.setIndex(2*dir);
+                break;
+            }
+            else if (info.rawPoint()[dir] == max()[dir])
+            {
+                info.setIndex(2*dir+1);
+                break;
+            }
+        }
+
+        if (info.index() == -1)
+        {
+            FatalErrorIn("searchableBox::findLine(const point&, const point&)")
+                << "point " << info.rawPoint()
+                << " on segment " << start << end
+                << " should be on face of " << *this
+                << " but it isn't." << abort(FatalError);
+        }
+    }
+
+    return info;
+}
+
+
+Foam::pointIndexHit Foam::searchableBox::findLineAny
+(
+    const point& start,
+    const point& end
+) const
+{
+    return findLine(start, end);
+}
+
+
+void Foam::searchableBox::findNearest
+(
+    const pointField& samples,
+    const scalarField& nearestDistSqr,
+    List<pointIndexHit>& info
+) const
+{
+    info.setSize(samples.size());
+
+    const point bbMid(mid());
+
+    forAll(samples, i)
+    {
+        info[i] = findNearest(bbMid, samples[i], nearestDistSqr[i]);
+    }
+}
+
+
+void Foam::searchableBox::findLine
+(
+    const pointField& start,
+    const pointField& end,
+    List<pointIndexHit>& info
+) const
+{
+    info.setSize(start.size());
+
+    forAll(start, i)
+    {
+        info[i] = findLine(start[i], end[i]);
+    }
+}
+
+
+void Foam::searchableBox::findLineAny
+(
+    const pointField& start,
+    const pointField& end,
+    List<pointIndexHit>& info
+) const
+{
+    info.setSize(start.size());
+
+    forAll(start, i)
+    {
+        info[i] = findLineAny(start[i], end[i]);
+    }
+}
+
+
+void Foam::searchableBox::findLineAll
+(
+    const pointField& start,
+    const pointField& end,
+    List<List<pointIndexHit> >& info
+) const
+{
+    info.setSize(start.size());
+
+    // Work array
+    DynamicList<pointIndexHit, 1, 1> hits;
+
+    // Tolerances
+    const vectorField dirVec(end-start);
+    const scalarField magSqrDirVec(magSqr(dirVec));
+    const vectorField smallVec
+    (
+        Foam::sqrt(SMALL)*dirVec
+      + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
+    );
+
+    forAll(start, pointI)
+    {
+        hits.clear();
+
+        // Current starting point of ray.
+        point pt = start[pointI];
+
+        while (true)
+        {
+            // See if any intersection between pt and end
+            pointIndexHit inter = findLine(pt, end[pointI]);
+
+            if (!inter.hit())
+            {
+                break;
+            }
+            hits.append(inter);
+
+            pt = inter.hitPoint() + smallVec[pointI];
+
+            if (((pt-start[pointI])&dirVec[pointI]) > magSqrDirVec[pointI])
+            {
+                // Adding smallVec has taken us beyond end
+                break;
+            }
+        }
+
+        hits.shrink();
+        info[pointI].transfer(hits);
+        hits.clear();
+    }
+}
+
+
+void Foam::searchableBox::getRegion
+(
+    const List<pointIndexHit>& info,
+    labelList& region
+) const
+{
+    region.setSize(info.size());
+    region = 0;
+}
+
+
+void Foam::searchableBox::getNormal
+(
+    const List<pointIndexHit>& info,
+    vectorField& normal
+) const
+{
+    normal.setSize(info.size());
+    normal = vector::zero;
+
+    forAll(info, i)
+    {
+        if (info[i].hit())
+        {
+            normal[i] = treeBoundBox::faceNormals[info[i].index()];
+        }
+        else
+        {
+            // Set to what?
+        }
+    }
+}
+
+
+void Foam::searchableBox::getVolumeType
+(
+    const pointField& points,
+    List<volumeType>& volType
+) const
+{
+    volType.setSize(points.size());
+    volType = INSIDE;
+
+    forAll(points, pointI)
+    {
+        const point& pt = points[pointI];
+
+        for (direction dir = 0; dir < vector::nComponents; dir++)
+        {
+            if (pt[dir] < min()[dir] || pt[dir] > max()[dir])
+            {
+                volType[pointI] = OUTSIDE;
+                break;
+            }
+        }
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurface/searchableBox.H b/src/meshTools/searchableSurface/searchableBox.H
new file mode 100644
index 0000000000000000000000000000000000000000..f606f83e1ef77f7184e9dfa6220aa92715d199e6
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableBox.H
@@ -0,0 +1,249 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::searchableBox
+
+Description
+    Searching on bounding box
+
+SourceFiles
+    searchableBox.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef searchableBox_H
+#define searchableBox_H
+
+#include "searchableSurface.H"
+#include "treeBoundBox.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+
+/*---------------------------------------------------------------------------*\
+                           Class searchableBox Declaration
+\*---------------------------------------------------------------------------*/
+
+class searchableBox
+:
+    public searchableSurface,
+    public treeBoundBox
+{
+private:
+
+    // Private Member Data
+
+        mutable wordList regions_;
+
+
+    // Private Member Functions
+
+        //- Project onto component dir of planePt and update index() (=face)
+        void projectOntoCoordPlane
+        (
+            const direction dir,
+            const point& planePt,
+            pointIndexHit& info
+        ) const;
+
+        //- Returns miss or hit with face (0..5)
+        pointIndexHit findNearest
+        (
+            const point& bbMid,
+            const point& sample,
+            const scalar nearestDistSqr
+        ) const;
+
+
+        //- Disallow default bitwise copy construct
+        searchableBox(const searchableBox&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const searchableBox&);
+
+
+public:
+
+    //- Runtime type information
+    TypeName("searchableBox");
+
+
+    // Constructors
+
+        //- Construct from components
+        searchableBox(const IOobject& io, const treeBoundBox& bb);
+
+        //- Construct from dictionary (used by searchableSurface)
+        searchableBox
+        (
+            const IOobject& io,
+            const dictionary& dict
+        );
+
+    // Destructor
+
+        virtual ~searchableBox();
+
+
+    // Member Functions
+
+        virtual const wordList& regions() const;
+
+        //- Whether supports volume type below
+        virtual bool hasVolumeType() const
+        {
+            return true;
+        }
+
+
+        // Single point queries.
+
+            //- Calculate nearest point on surface. Returns
+            //  - bool : any point found nearer than nearestDistSqr
+            //  - label: relevant index in surface (=face 0..5)
+            //  - point: actual nearest point found
+            pointIndexHit findNearest
+            (
+                const point& sample,
+                const scalar nearestDistSqr
+            ) const;
+
+            //- Calculate nearest point on edge. Returns
+            //  - bool : any point found nearer than nearestDistSqr
+            //  - label: relevant index in surface(=?)
+            //  - point: actual nearest point found
+            pointIndexHit findNearestOnEdge
+            (
+                const point& sample,
+                const scalar nearestDistSqr
+            ) const;
+
+            //- Find nearest to segment. Returns
+            //  - bool : any point found?
+            //  - label: relevant index in shapes (=face 0..5)
+            //  - point: actual nearest point found
+            //  sets:
+            //  - tightest  : bounding box
+            //  - linePoint : corresponding nearest point on line
+            pointIndexHit findNearest
+            (
+                const linePointRef& ln,
+                treeBoundBox& tightest,
+                point& linePoint
+            ) const;
+
+            //- Find nearest intersection of line between start and end.
+            pointIndexHit findLine
+            (
+                const point& start,
+                const point& end
+            ) const;
+
+            //- Find any intersection of line between start and end.
+            pointIndexHit findLineAny
+            (
+                const point& start,
+                const point& end
+            ) const;
+
+
+        // Multiple point queries.
+
+            virtual void findNearest
+            (
+                const pointField& sample,
+                const scalarField& nearestDistSqr,
+                List<pointIndexHit>&
+            ) const;
+
+            virtual void findLine
+            (
+                const pointField& start,
+                const pointField& end,
+                List<pointIndexHit>&
+            ) const;
+
+            virtual void findLineAny
+            (
+                const pointField& start,
+                const pointField& end,
+                List<pointIndexHit>&
+            ) const;
+
+            //- Get all intersections in order from start to end.
+            virtual void findLineAll
+            (
+                const pointField& start,
+                const pointField& end,
+                List<List<pointIndexHit> >&
+            ) const;
+
+            //- From a set of points and indices get the region
+            virtual void getRegion
+            (
+                const List<pointIndexHit>&,
+                labelList& region
+            ) const;
+
+            //- From a set of points and indices get the normal
+            virtual void getNormal
+            (
+                const List<pointIndexHit>&,
+                vectorField& normal
+            ) const;
+
+            //- Determine type (inside/outside/mixed) for point. unknown if
+            //  cannot be determined (e.g. non-manifold surface)
+            virtual void getVolumeType
+            (
+                const pointField&,
+                List<volumeType>&
+            ) const;
+
+
+        // regIOobject implementation
+
+            bool writeData(Ostream&) const
+            {
+                notImplemented("searchableBox::writeData(Ostream&) const");
+                return false;
+            }
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurface/searchableSphere.C b/src/meshTools/searchableSurface/searchableSphere.C
new file mode 100644
index 0000000000000000000000000000000000000000..eb16e2731887040f7adc57c89d05b6f82146fbc2
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableSphere.C
@@ -0,0 +1,328 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "searchableSphere.H"
+#include "addToRunTimeSelectionTable.H"
+#include "SortableList.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+defineTypeNameAndDebug(searchableSphere, 0);
+addToRunTimeSelectionTable(searchableSurface, searchableSphere, dict);
+
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::pointIndexHit Foam::searchableSphere::findNearest
+(
+    const point& sample,
+    const scalar nearestDistSqr
+) const
+{
+    pointIndexHit info(false, sample, -1);
+
+    const vector n(sample-centre_);
+    scalar magN = mag(n);
+
+    if (nearestDistSqr > sqr(magN-radius_))
+    {
+        info.rawPoint() = centre_ + n/magN*radius_;
+        info.setHit();
+        info.setIndex(0);
+    }
+
+    return info;
+}
+
+
+// From Graphics Gems - intersection of sphere with ray
+void Foam::searchableSphere::findLineAll
+(
+    const point& start,
+    const point& end,
+    pointIndexHit& near,
+    pointIndexHit& far
+) const
+{
+    near.setMiss();
+    far.setMiss();
+
+    vector dir(end-start);
+    scalar magSqrDir = magSqr(dir);
+
+    if (magSqrDir > ROOTVSMALL)
+    {
+        const vector toCentre(centre_-start);
+        scalar magSqrToCentre = magSqr(toCentre);
+
+        dir /= Foam::sqrt(magSqrDir);
+
+        scalar v = (toCentre & dir);
+
+        scalar disc = sqr(radius_) - (magSqrToCentre - sqr(v));
+
+        if (disc >= 0)
+        {
+            scalar d = Foam::sqrt(disc);
+
+            scalar nearParam = v-d;
+
+            if (nearParam >= 0 && sqr(nearParam) <= magSqrDir)
+            {
+                near.setHit();
+                near.setPoint(start + nearParam*dir);
+                near.setIndex(0);
+            }
+
+            scalar farParam = v+d;
+
+            if (farParam >= 0 && sqr(farParam) <= magSqrDir)
+            {
+                far.setHit();
+                far.setPoint(start + farParam*dir);
+                far.setIndex(0);
+            }
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::searchableSphere::searchableSphere
+(
+    const IOobject& io,
+    const point& centre,
+    const scalar radius
+)
+:
+    searchableSurface(io),
+    centre_(centre),
+    radius_(radius)
+{}
+
+
+Foam::searchableSphere::searchableSphere
+(
+    const IOobject& io,
+    const dictionary& dict
+)
+:
+    searchableSurface(io),
+    centre_(dict.lookup("centre")),
+    radius_(readScalar(dict.lookup("radius")))
+{}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::searchableSphere::~searchableSphere()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+const Foam::wordList& Foam::searchableSphere::regions() const
+{
+    if (regions_.size() == 0)
+    {
+        regions_.setSize(1);
+        regions_[0] = "region0";
+    }
+    return regions_;
+}
+
+
+
+void Foam::searchableSphere::findNearest
+(
+    const pointField& samples,
+    const scalarField& nearestDistSqr,
+    List<pointIndexHit>& info
+) const
+{
+    info.setSize(samples.size());
+
+    forAll(samples, i)
+    {
+        info[i] = findNearest(samples[i], nearestDistSqr[i]);
+    }
+}
+
+
+void Foam::searchableSphere::findLine
+(
+    const pointField& start,
+    const pointField& end,
+    List<pointIndexHit>& info
+) const
+{
+    info.setSize(start.size());
+
+    pointIndexHit b;
+
+    forAll(start, i)
+    {
+        // Pick nearest intersection. If none intersected take second one.
+        findLineAll(start[i], end[i], info[i], b);
+        if (!info[i].hit() && b.hit())
+        {
+            info[i] = b;
+        }
+    }
+}
+
+
+void Foam::searchableSphere::findLineAny
+(
+    const pointField& start,
+    const pointField& end,
+    List<pointIndexHit>& info
+) const
+{
+    info.setSize(start.size());
+
+    pointIndexHit b;
+
+    forAll(start, i)
+    {
+        // Discard far intersection
+        findLineAll(start[i], end[i], info[i], b);
+        if (!info[i].hit() && b.hit())
+        {
+            info[i] = b;
+        }
+    }
+}
+
+
+void Foam::searchableSphere::findLineAll
+(
+    const pointField& start,
+    const pointField& end,
+    List<List<pointIndexHit> >& info
+) const
+{
+    info.setSize(start.size());
+
+    pointIndexHit near, far;
+
+    forAll(start, i)
+    {
+        findLineAll(start[i], end[i], near, far);
+
+        if (near.hit())
+        {
+            if (far.hit())
+            {
+                info[i].setSize(2);
+                info[i][0] = near;
+                info[i][1] = far;
+            }
+            else
+            {
+                info[i].setSize(1);
+                info[i][0] = near;
+            }
+        }
+        else
+        {
+            if (far.hit())
+            {
+                info[i].setSize(1);
+                info[i][0] = far;
+            }
+        }
+    }
+}
+
+
+void Foam::searchableSphere::getRegion
+(
+    const List<pointIndexHit>& info,
+    labelList& region
+) const
+{
+    region.setSize(info.size());
+    region = 0;
+}
+
+
+void Foam::searchableSphere::getNormal
+(
+    const List<pointIndexHit>& info,
+    vectorField& normal
+) const
+{
+    normal.setSize(info.size());
+    normal = vector::zero;
+
+    forAll(info, i)
+    {
+        if (info[i].hit())
+        {
+            normal[i] = info[i].hitPoint() - centre_;
+            normal[i] /= mag(normal[i]);
+        }
+        else
+        {
+            // Set to what?
+        }
+    }
+}
+
+
+void Foam::searchableSphere::getVolumeType
+(
+    const pointField& points,
+    List<volumeType>& volType
+) const
+{
+    volType.setSize(points.size());
+    volType = INSIDE;
+
+    forAll(points, pointI)
+    {
+        const point& pt = points[pointI];
+
+        if (magSqr(pt - centre_) <= sqr(radius_))
+        {
+            volType[pointI] = INSIDE;
+        }
+        else
+        {
+            volType[pointI] = OUTSIDE;
+        }
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurface/searchableSphere.H b/src/meshTools/searchableSurface/searchableSphere.H
new file mode 100644
index 0000000000000000000000000000000000000000..7b3f4856ac72d1a1d1da3cc32e79d2b3ce93385a
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableSphere.H
@@ -0,0 +1,204 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::searchableSphere
+
+Description
+    Searching on sphere
+
+SourceFiles
+    searchableSphere.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef searchableSphere_H
+#define searchableSphere_H
+
+#include "searchableSurface.H"
+#include "treeBoundBox.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+
+/*---------------------------------------------------------------------------*\
+                           Class searchableSphere Declaration
+\*---------------------------------------------------------------------------*/
+
+class searchableSphere
+:
+    public searchableSurface
+{
+private:
+
+    // Private Member Data
+
+        //- Centre point
+        const point centre_;
+
+        //- Radius squared
+        const scalar radius_;
+
+        //- Names of regions
+        mutable wordList regions_;
+
+
+    // Private Member Functions
+
+        //- Find nearest point on sphere.
+        pointIndexHit findNearest
+        (
+            const point& sample,
+            const scalar nearestDistSqr
+        ) const;
+
+        //- Find intersection with sphere
+        void findLineAll
+        (
+            const point& start,
+            const point& end,
+            pointIndexHit& near,
+            pointIndexHit& far
+        ) const;
+
+
+        //- Disallow default bitwise copy construct
+        searchableSphere(const searchableSphere&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const searchableSphere&);
+
+
+public:
+
+    //- Runtime type information
+    TypeName("searchableSphere");
+
+
+    // Constructors
+
+        //- Construct from components
+        searchableSphere(const IOobject& io, const point&, const scalar radius);
+
+        //- Construct from dictionary (used by searchableSurface)
+        searchableSphere
+        (
+            const IOobject& io,
+            const dictionary& dict
+        );
+
+    // Destructor
+
+        virtual ~searchableSphere();
+
+
+    // Member Functions
+
+        virtual const wordList& regions() const;
+
+        //- Whether supports volume type below
+        virtual bool hasVolumeType() const
+        {
+            return true;
+        }
+
+
+        // Multiple point queries.
+
+            virtual void findNearest
+            (
+                const pointField& sample,
+                const scalarField& nearestDistSqr,
+                List<pointIndexHit>&
+            ) const;
+
+            virtual void findLine
+            (
+                const pointField& start,
+                const pointField& end,
+                List<pointIndexHit>&
+            ) const;
+
+            virtual void findLineAny
+            (
+                const pointField& start,
+                const pointField& end,
+                List<pointIndexHit>&
+            ) const;
+
+            //- Get all intersections in order from start to end.
+            virtual void findLineAll
+            (
+                const pointField& start,
+                const pointField& end,
+                List<List<pointIndexHit> >&
+            ) const;
+
+            //- From a set of points and indices get the region
+            virtual void getRegion
+            (
+                const List<pointIndexHit>&,
+                labelList& region
+            ) const;
+
+            //- From a set of points and indices get the normal
+            virtual void getNormal
+            (
+                const List<pointIndexHit>&,
+                vectorField& normal
+            ) const;
+
+            //- Determine type (inside/outside/mixed) for point. unknown if
+            //  cannot be determined (e.g. non-manifold surface)
+            virtual void getVolumeType
+            (
+                const pointField&,
+                List<volumeType>&
+            ) const;
+
+
+        // regIOobject implementation
+
+            bool writeData(Ostream&) const
+            {
+                notImplemented("searchableSphere::writeData(Ostream&) const");
+                return false;
+            }
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/triSurface/searchableSurface/searchableSurface.C b/src/meshTools/searchableSurface/searchableSurface.C
similarity index 65%
rename from src/meshTools/triSurface/searchableSurface/searchableSurface.C
rename to src/meshTools/searchableSurface/searchableSurface.C
index 11996e75341d3cdae108fb2bd57b65089e90f287..9e6cffa315de7720e11d0ce5cf8706a8fa3f5688 100644
--- a/src/meshTools/triSurface/searchableSurface/searchableSurface.C
+++ b/src/meshTools/searchableSurface/searchableSurface.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -34,15 +34,13 @@ namespace Foam
 
 defineTypeNameAndDebug(searchableSurface, 0);
 defineRunTimeSelectionTable(searchableSurface, dict);
-//defineRunTimeSelectionTable(searchableSurface, istream);
 
 
 // Construct named object from dictionary
 autoPtr<searchableSurface> searchableSurface::New
 (
     const word& searchableSurfaceType,
-    const word& name,
-    const objectRegistry& obj,
+    const IOobject& io,
     const dictionary& dict
 )
 {
@@ -55,7 +53,7 @@ autoPtr<searchableSurface> searchableSurface::New
         FatalErrorIn
         (
             "searchableSurface::New(const word&, const word&"
-            ", const objectRegistry&, const dictionary&)"
+            ", const IOobject&, const dictionary&)"
         )   << "Unknown searchableSurface type " << searchableSurfaceType
             << endl << endl
             << "Valid searchableSurface types : " << endl
@@ -63,44 +61,15 @@ autoPtr<searchableSurface> searchableSurface::New
             << exit(FatalError);
     }
 
-    return autoPtr<searchableSurface>(cstrIter()(name, obj, dict));
+    return autoPtr<searchableSurface>(cstrIter()(io, dict));
 }
 
 
-//// Construct named object from Istream
-//autoPtr<searchableSurface> searchableSurface::New
-//(
-//    const word& searchableSurfaceType,
-//    const objectRegistry& obj,
-//    Istream& is
-//)
-//{
-//    istreamConstructorTable::iterator cstrIter =
-//        istreamConstructorTablePtr_
-//            ->find(searchableSurfaceType);
-//
-//    if (cstrIter == istreamConstructorTablePtr_->end())
-//    {
-//        FatalErrorIn
-//        (
-//            "searchableSurface::New(const word&, const objectRegistry&"
-//            ", Istream&)"
-//        )   << "Unknown searchableSurface type " << searchableSurfaceType
-//            << endl << endl
-//            << "Valid searchableSurface types : " << endl
-//            << istreamConstructorTablePtr_->toc()
-//            << exit(FatalError);
-//    }
-//
-//    return autoPtr<searchableSurface>(cstrIter()(obj, is));
-//}
-
-
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::searchableSurface::searchableSurface(const word& name)
+Foam::searchableSurface::searchableSurface(const IOobject& io)
 :
-    name_(name)
+    regIOobject(io)
 {}
 
 
diff --git a/src/meshTools/searchableSurface/searchableSurface.H b/src/meshTools/searchableSurface/searchableSurface.H
new file mode 100644
index 0000000000000000000000000000000000000000..43e008ca50421b03393f688f1407ea9655e7cf70
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableSurface.H
@@ -0,0 +1,322 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::searchableSurface
+
+Description
+    Base class of (analytical or triangulated) surface.
+    Encapsulates all the search routines. WIP.
+
+    Information returned is usually a pointIndexHit:
+    - bool  : was intersection/nearest found?
+    - point : intersection point or nearest point
+    - index : unique index on surface (e.g. triangle for triSurfaceMesh)
+
+SourceFiles
+    searchableSurface.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef searchableSurface_H
+#define searchableSurface_H
+
+#include "pointField.H"
+#include "typeInfo.H"
+#include "runTimeSelectionTables.H"
+#include "pointIndexHit.H"
+#include "linePointRef.H"
+#include "objectRegistry.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+class objectRegistry;
+class treeBoundBox;
+
+/*---------------------------------------------------------------------------*\
+                           Class searchableSurface Declaration
+\*---------------------------------------------------------------------------*/
+
+class searchableSurface
+:
+    public regIOobject
+{
+public:
+
+    // Data types
+
+        //- volume types
+        enum volumeType
+        {
+            UNKNOWN = 0,
+            MIXED = 1,      // not used. only here to maintain consistency with
+                            // indexedOctree volumeType.
+            INSIDE = 2,
+            OUTSIDE = 3
+        };
+
+private:
+
+    // Private data
+
+        const word name_;
+
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        searchableSurface(const searchableSurface&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const searchableSurface&);
+
+
+public:
+
+    //- Runtime type information
+    TypeName("searchableSurface");
+
+    // Declare run-time constructor selection table
+
+        // For the dictionary constructor
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            searchableSurface,
+            dict,
+            (
+                const IOobject& io,
+                const dictionary& dict
+            ),
+            (io, dict)
+        );
+
+
+        //- Class used for the read-construction of
+        //  PtrLists of searchableSurface.
+        class iNew
+        {
+            IOobject& io_;
+
+        public:
+
+            iNew(IOobject& io)
+            :
+                io_(io)
+            {}
+
+            autoPtr<searchableSurface> operator()(Istream& is) const
+            {
+                word surfaceType(is);
+                word readName(is);
+                dictionary dict(is);
+
+                autoPtr<IOobject> namedIO(io_.clone());
+                namedIO().rename(readName);
+                return searchableSurface::New(surfaceType, namedIO(), dict);
+            }
+        };
+
+
+    // Constructors
+
+        searchableSurface(const IOobject& io);
+
+        //- Clone
+        virtual autoPtr<searchableSurface> clone() const
+        {
+            notImplemented("autoPtr<searchableSurface> clone() const");
+            return autoPtr<searchableSurface>(NULL);
+        }
+
+
+    // Selectors
+
+        //- Return a reference to the selected searchableSurface
+        static autoPtr<searchableSurface> New
+        (
+            const word& surfaceType,
+            const IOobject& io,
+            const dictionary& dict
+        );
+
+
+    // Destructor
+
+        virtual ~searchableSurface();
+
+
+    // Member Functions
+
+
+        //- Names of regions.
+        virtual const wordList& regions() const = 0;
+
+        //- Whether supports volume type below.
+        virtual bool hasVolumeType() const = 0;
+
+
+        // Single point queries.
+
+            ////- Calculate nearest point on surface. Returns
+            ////  - bool : any point found nearer than nearestDistSqr
+            ////  - label: relevant index in surface
+            ////  - label: region in surface
+            ////  - point: actual nearest point found
+            //virtual pointIndexHit findNearest
+            //(
+            //    const point& sample,
+            //    const scalar nearestDistSqr
+            //) const = 0;
+            //
+            ////- Calculate nearest point on edge. Returns
+            ////  - bool : any point found nearer than nearestDistSqr
+            ////  - label: relevant index in surface
+            ////  - label: region in surface
+            ////  - point: actual nearest point found
+            //virtual pointIndexHit findNearestOnEdge
+            //(
+            //    const point& sample,
+            //    const scalar nearestDistSqr
+            //) const = 0;
+            //
+            ////- Find nearest to segment. Returns
+            ////  - bool : any point found?
+            ////  - label: relevant index in shapes
+            ////  - label: region in surface
+            ////  - point: actual nearest point found
+            ////  sets:
+            ////  - tightest  : bounding box
+            ////  - linePoint : corresponding nearest point on line
+            //virtual pointIndexHit findNearest
+            //(
+            //    const linePointRef& ln,
+            //    treeBoundBox& tightest,
+            //    point& linePoint
+            //) const = 0;
+            //
+            ////- Find nearest intersection of line between start and end.
+            //virtual pointIndexHit findLine
+            //(
+            //    const point& start,
+            //    const point& end
+            //) const = 0;
+            //
+            ////- Find any intersection of line between start and end.
+            //virtual pointIndexHit findLineAny
+            //(
+            //    const point& start,
+            //    const point& end
+            //) const = 0;
+
+
+        // Multiple point queries. When surface is distributed the index
+        // should be a global index. Not done yet.
+
+            virtual void findNearest
+            (
+                const pointField& sample,
+                const scalarField& nearestDistSqr,
+                List<pointIndexHit>&
+            ) const = 0;
+
+            //- Find first intersection on segment from start to end.
+            //  Note: searchableSurfacesQueries expects no
+            //  intersection to be found if start==end. Is problem?
+            virtual void findLine
+            (
+                const pointField& start,
+                const pointField& end,
+                List<pointIndexHit>&
+            ) const = 0;
+
+            //- Return any intersection on segment from start to end.
+            virtual void findLineAny
+            (
+                const pointField& start,
+                const pointField& end,
+                List<pointIndexHit>&
+            ) const = 0;
+
+            //- Get all intersections in order from start to end.
+            virtual void findLineAll
+            (
+                const pointField& start,
+                const pointField& end,
+                List<List<pointIndexHit> >&
+            ) const = 0;
+
+            //- From a set of points and indices get the region
+            virtual void getRegion
+            (
+                const List<pointIndexHit>&,
+                labelList& region
+            ) const = 0;
+
+            //- From a set of points and indices get the normal
+            virtual void getNormal
+            (
+                const List<pointIndexHit>&,
+                vectorField& normal
+            ) const = 0;
+
+            //- Determine type (inside/outside) for point. unknown if
+            //  cannot be determined (e.g. non-manifold surface)
+            virtual void getVolumeType
+            (
+                const pointField&,
+                List<volumeType>&
+            ) const = 0;
+
+
+        // Other
+
+            ////- Get bounding box.
+            //const boundBox& bounds() const = 0;
+
+            ////- Set bounding box.
+            //void setBounds
+            //(
+            //    const boundBox&,
+            //    autoPtr<mapDistribute>& faceMap,
+            //    autoPtr<mapDistribute>& pointMap
+            //) = 0;
+
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurface/searchableSurfaces.C b/src/meshTools/searchableSurface/searchableSurfaces.C
new file mode 100644
index 0000000000000000000000000000000000000000..8fbb4678e77f300f18ce39bee1d6781c134f6141
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableSurfaces.C
@@ -0,0 +1,355 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*----------------------------------------------------------------------------*/
+
+#include "searchableSurfaces.H"
+#include "searchableSurfacesQueries.H"
+#include "ListOps.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+defineTypeNameAndDebug(searchableSurfaces, 0);
+
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+// Construct with length.
+Foam::searchableSurfaces::searchableSurfaces(const label size)
+:
+    PtrList<searchableSurface>(size),
+    regionNames_(size),
+    allSurfaces_(identity(size))
+{}
+
+
+//Foam::searchableSurfaces::searchableSurfaces
+//(
+//    const IOobject& io,
+//    const PtrList<dictionary>& dicts
+//)
+//:
+//    PtrList<searchableSurface>(dicts.size()),
+//    regionNames_(dicts.size()),
+//    allSurfaces_(identity(dicts.size()))
+//{
+//    forAll(dicts, surfI)
+//    {
+//        const dictionary& dict = dicts[surfI];
+//
+//        // Make IOobject with correct name
+//        autoPtr<IOobject> namedIO(io.clone());
+//        namedIO().rename(dict.lookup("name"));
+//
+//        // Create and hook surface
+//        set
+//        (
+//            surfI,
+//            searchableSurface::New
+//            (
+//                dict.lookup("type"),
+//                namedIO(),
+//                dict
+//            )
+//        );
+//        const searchableSurface& s = operator[](surfI);
+//
+//        // Construct default region names by prepending surface name
+//        // to region name.
+//        const wordList& localNames = s.regions();
+//
+//        wordList globalNames(localNames.size());
+//        forAll(localNames, regionI)
+//        {
+//            globalNames[regionI] = s.name() + '_' + localNames[regionI];
+//        }
+//
+//        // See if dictionary provides any global region names.
+//        if (dict.found("regions"))
+//        {
+//            const dictionary& regionsDict = dict.subDict("regions");
+//
+//            forAllConstIter(dictionary, regionsDict, iter)
+//            {
+//                const word& key = iter().keyword();
+//
+//                if (regionsDict.isDict(key))
+//                {
+//                    // Get the dictionary for region iter.key()
+//                    const dictionary& regionDict = regionsDict.subDict(key);
+//
+//                    label index = findIndex(localNames, key);
+//
+//                    if (index == -1)
+//                    {
+//                        FatalErrorIn
+//                        (
+//                            "searchableSurfaces::searchableSurfaces"
+//                            "( const IOobject&, const dictionary&)"
+//                        )   << "Unknown region name " << key
+//                            << " for surface " << s.name() << endl
+//                            << "Valid region names are " << localNames
+//                            << exit(FatalError);
+//                    }
+//
+//                    globalNames[index] = word(regionDict.lookup("name"));
+//                }
+//            }
+//        }
+//
+//        // Now globalNames contains the names of the regions.
+//        Info<< "Surface:" << s.name() << " has regions:"
+//            << endl;
+//        forAll(globalNames, regionI)
+//        {
+//            Info<< "    " << globalNames[regionI] << endl;
+//        }
+//
+//        // Create reverse lookup
+//        forAll(globalNames, regionI)
+//        {
+//            regionNames_.insert
+//            (
+//                globalNames[regionI],
+//                labelPair(surfI, regionI)
+//            );
+//        }
+//    }
+//}
+
+
+Foam::searchableSurfaces::searchableSurfaces
+(
+    const IOobject& io,
+    const dictionary& topDict
+)
+:
+    PtrList<searchableSurface>(topDict.size()),
+    names_(topDict.size()),
+    regionNames_(topDict.size()),
+    allSurfaces_(identity(topDict.size()))
+{
+    label surfI = 0;
+    forAllConstIter(dictionary, topDict, iter)
+    {
+        const word& key = iter().keyword();
+
+        if (!topDict.isDict(key))
+        {
+            FatalErrorIn
+            (
+                "searchableSurfaces::searchableSurfaces"
+                "( const IOobject&, const dictionary&)"
+            )   << "Found non-dictionary entry " << iter()
+                << " in top-level dictionary " << topDict
+                << exit(FatalError);
+        }
+
+        const dictionary& dict = topDict.subDict(key);
+
+        names_[surfI] = key;
+
+        if (dict.found("name"))
+        {
+            dict.lookup("name") >> names_[surfI];
+        }
+
+
+        // Make IOobject with correct name
+        autoPtr<IOobject> namedIO(io.clone());
+        // Note: we would like to e.g. register triSurface 'sphere.stl' as
+        // 'sphere'. Unfortunately
+        // no support for having object read from different location than
+        // their object name. Maybe have stlTriSurfaceMesh which appends .stl
+        // when reading/writing?
+        namedIO().rename(key);  // names_[surfI]
+
+        // Create and hook surface
+        set
+        (
+            surfI,
+            searchableSurface::New
+            (
+                dict.lookup("type"),
+                namedIO(),
+                dict
+            )
+        );
+        const searchableSurface& s = operator[](surfI);
+
+        // Construct default region names by prepending surface name
+        // to region name.
+        const wordList& localNames = s.regions();
+
+        wordList& rNames = regionNames_[surfI];
+        rNames.setSize(localNames.size());
+
+        forAll(localNames, regionI)
+        {
+            rNames[regionI] = names_[surfI] + '_' + localNames[regionI];
+        }
+
+        // See if dictionary provides any global region names.
+        if (dict.found("regions"))
+        {
+            const dictionary& regionsDict = dict.subDict("regions");
+
+            forAllConstIter(dictionary, regionsDict, iter)
+            {
+                const word& key = iter().keyword();
+
+                if (regionsDict.isDict(key))
+                {
+                    // Get the dictionary for region iter.keyword()
+                    const dictionary& regionDict = regionsDict.subDict(key);
+
+                    label index = findIndex(localNames, key);
+
+                    if (index == -1)
+                    {
+                        FatalErrorIn
+                        (
+                            "searchableSurfaces::searchableSurfaces"
+                            "( const IOobject&, const dictionary&)"
+                        )   << "Unknown region name " << key
+                            << " for surface " << s.name() << endl
+                            << "Valid region names are " << localNames
+                            << exit(FatalError);
+                    }
+
+                    rNames[index] = word(regionDict.lookup("name"));
+                }
+            }
+        }
+
+        surfI++;
+    }
+
+    // Trim (not really necessary since we don't allow non-dictionary entries)
+    PtrList<searchableSurface>::setSize(surfI);
+    names_.setSize(surfI);
+    regionNames_.setSize(surfI);
+    allSurfaces_.setSize(surfI);
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::label Foam::searchableSurfaces::findSurfaceID(const word& wantedName)
+ const
+{
+    return findIndex(names_, wantedName);
+}
+
+
+// Find any intersection
+void Foam::searchableSurfaces::findAnyIntersection
+(
+    const pointField& start,
+    const pointField& end,
+    labelList& hitSurfaces,
+    List<pointIndexHit>& hitInfo
+) const
+{
+    searchableSurfacesQueries::findAnyIntersection
+    (
+        *this,
+        allSurfaces_,
+        start,
+        end,
+        hitSurfaces,
+        hitInfo
+    );
+}
+
+
+// Find intersections of edge nearest to both endpoints.
+void Foam::searchableSurfaces::findAllIntersections
+(
+    const pointField& start,
+    const pointField& end,
+    labelListList& hitSurfaces,
+    List<List<pointIndexHit> >& hitInfo
+) const
+{
+    searchableSurfacesQueries::findAllIntersections
+    (
+        *this,
+        allSurfaces_,
+        start,
+        end,
+        hitSurfaces,
+        hitInfo
+    );
+}
+
+
+// Find nearest. Return -1 or nearest point
+void Foam::searchableSurfaces::findNearest
+(
+    const pointField& samples,
+    const scalarField& nearestDistSqr,
+    labelList& nearestSurfaces,
+    List<pointIndexHit>& nearestInfo
+) const
+{
+    return searchableSurfacesQueries::findNearest
+    (
+        *this,
+        allSurfaces_,
+        samples,
+        nearestDistSqr,
+        nearestSurfaces,
+        nearestInfo
+    );
+}
+
+
+//- Calculate point which is on a set of surfaces.
+Foam::pointIndexHit Foam::searchableSurfaces::facesIntersection
+(
+    const scalar initDistSqr,
+    const scalar convergenceDistSqr,
+    const point& start
+) const
+{
+    return searchableSurfacesQueries::facesIntersection
+    (
+        *this,
+        allSurfaces_,
+        initDistSqr,
+        convergenceDistSqr,
+        start
+    );
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurface/searchableSurfaces.H b/src/meshTools/searchableSurface/searchableSurfaces.H
new file mode 100644
index 0000000000000000000000000000000000000000..acb02572e635e36774be6483ad21f498a8b2c3ae
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableSurfaces.H
@@ -0,0 +1,187 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::searchableSurfaces
+
+Description
+    Container for searchableSurfaces.
+
+SourceFiles
+    searchableSurfaces.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef searchableSurfaces_H
+#define searchableSurfaces_H
+
+#include "searchableSurface.H"
+#include "labelPair.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+
+/*---------------------------------------------------------------------------*\
+                           Class searchableSurfaces Declaration
+\*---------------------------------------------------------------------------*/
+
+class searchableSurfaces
+:
+    public PtrList<searchableSurface>
+{
+    // Private data
+
+        //- Surface names
+        wordList names_;
+
+        //- Region names per surface
+        List<wordList> regionNames_;
+
+        ////- From global region name to surface and region on surface
+        //HashTable<labelPair> regionNames_;
+
+        //- Indices of all surfaces. Precalculated and stored.
+        labelList allSurfaces_;
+
+
+        //- Disallow default bitwise copy construct
+        searchableSurfaces(const searchableSurfaces&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const searchableSurfaces&);
+
+
+public:
+
+    ClassName("searchableSurfaces");
+
+    // Constructors
+
+        //- Construct with length specified. Fill later.
+        explicit searchableSurfaces(const label);
+
+
+        ////- Construct from list of dictionaries
+        //searchableSurfaces(const IOobject&, const PtrList<dictionary>&);
+
+        //- Construct from dictionary
+        searchableSurfaces(const IOobject&, const dictionary&);
+
+
+    // Member Functions
+
+        const wordList& names() const
+        {
+            return names_;
+        }
+        wordList& names()
+        {
+            return names_;
+        }
+
+        const List<wordList>& regionNames() const
+        {
+            return regionNames_;
+        }
+        List<wordList>& regionNames()
+        {
+            return regionNames_;
+        }
+
+
+        ////- If adding surfaces 'by hand'
+        //HashTable<labelPair>& regionNames()
+        //{
+        //    return regionNames_;
+        //}
+        ////- Get surface and region for a name
+        //const labelPair& surfaceRegion(const word& globalRegion) const
+        //{
+        //    return regionNames_[globalRegion];
+        //}
+
+        //- Find index of surface. Return -1 if not found.
+        label findSurfaceID(const word& name) const;
+
+
+        // Multiple point queries.
+
+            //- Find any intersection. Return hit point information and
+            //  surface number. If multiple surfaces hit the first surface
+            //  is returned, not necessarily the nearest (to start).
+            void findAnyIntersection
+            (
+                const pointField& start,
+                const pointField& end,
+                labelList& surfaces,
+                List<pointIndexHit>&
+            ) const;
+
+            //- Find all intersections in order from start to end. Returns for
+            //  every hit the surface and the hit info.
+            void findAllIntersections
+            (
+                const pointField& start,
+                const pointField& end,
+                labelListList& surfaces,
+                List<List<pointIndexHit> >& surfaceHits
+            ) const;
+
+            //- Find nearest. Return -1 (and a miss()) or surface and nearest
+            //  point.
+            void findNearest
+            (
+                const pointField&,
+                const scalarField& nearestDistSqr,
+                labelList& surfaces,
+                List<pointIndexHit>&
+            ) const;
+
+
+        // Single point queries
+
+            //- Calculate point which is on a set of surfaces.
+            pointIndexHit facesIntersection
+            (
+                const scalar initialDistSqr,
+                const scalar convergenceDistSqr,
+                const point& start
+            ) const;
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurface/searchableSurfacesQueries.C b/src/meshTools/searchableSurface/searchableSurfacesQueries.C
new file mode 100644
index 0000000000000000000000000000000000000000..7d7c6c2c1b09de2d59cadb67fc0f3e86b9118b41
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableSurfacesQueries.C
@@ -0,0 +1,822 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*----------------------------------------------------------------------------*/
+
+#include "searchableSurfacesQueries.H"
+#include "SortableList.H"
+#include "OFstream.H"
+#include "meshTools.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+defineTypeNameAndDebug(searchableSurfacesQueries, 0);
+
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::pointIndexHit Foam::searchableSurfacesQueries::tempFindNearest
+(
+    const searchableSurface& surf,
+    const point& pt,
+    const scalar initDistSqr
+)
+{
+    pointField onePoint(1, pt);
+    scalarField oneDist(1, initDistSqr);
+    List<pointIndexHit> oneHit(1);
+    surf.findNearest(onePoint, oneDist, oneHit);
+    return oneHit[0];
+}
+
+
+// Calculate sum of distance to surfaces.
+Foam::scalar Foam::searchableSurfacesQueries::sumDistSqr
+(
+    const PtrList<searchableSurface>& allSurfaces,
+    const labelList& surfacesToTest,
+    const scalar initDistSqr,
+    const point& pt
+)
+{
+    scalar sum = 0;
+
+    forAll(surfacesToTest, testI)
+    {
+        label surfI = surfacesToTest[testI];
+
+        pointIndexHit hit
+        (
+            tempFindNearest(allSurfaces[surfI], pt, initDistSqr)
+        );
+
+        // Note: make it fall over if not hit.
+        sum += magSqr(hit.hitPoint()-pt);
+    }
+    return sum;
+}
+
+
+// Reflects the point furthest away around the triangle centre by a factor fac.
+// (triangle centre is the average of all points but the ihi. pSum is running
+//  sum of all points)
+Foam::scalar Foam::searchableSurfacesQueries::tryMorphTet
+(
+    const PtrList<searchableSurface>& allSurfaces,
+    const labelList& surfacesToTest,
+    const scalar initDistSqr,
+    List<vector>& p,
+    List<scalar>& y,
+    vector& pSum,
+    const label ihi,
+    const scalar fac
+)
+{
+    scalar fac1 = (1.0-fac)/vector::nComponents;
+    scalar fac2 = fac1-fac;
+
+    vector ptry = pSum*fac1-p[ihi]*fac2;
+
+    scalar ytry = sumDistSqr(allSurfaces, surfacesToTest, initDistSqr, ptry);
+
+    if (ytry < y[ihi])
+    {
+        y[ihi] = ytry;
+        pSum += ptry - p[ihi];
+        p[ihi] = ptry;
+    }
+    return ytry;
+}
+
+
+bool Foam::searchableSurfacesQueries::morphTet
+(
+    const PtrList<searchableSurface>& allSurfaces,
+    const labelList& surfacesToTest,
+    const scalar initDistSqr,
+    const scalar convergenceDistSqr,
+    const label maxIter,
+    List<vector>& p,
+    List<scalar>& y
+)
+{
+    vector pSum = sum(p);
+
+    autoPtr<OFstream> str;
+    label vertI = 0;
+    if (debug)
+    {
+        wordList names(surfacesToTest.size());
+        forAll(surfacesToTest, i)
+        {
+            names[i] = allSurfaces[surfacesToTest[i]].name();
+        }
+        Pout<< "searchableSurfacesQueries::morphTet : intersection of "
+            << names << " starting from points:" << p << endl;
+        str.reset(new OFstream("track.obj"));
+        meshTools::writeOBJ(str(), p[0]);
+        vertI++;
+    }
+
+    for (label iter = 0; iter < maxIter; iter++)
+    {
+        // Get the indices of highest, second-highest and lowest values.
+        label ihi, inhi, ilo;
+        {
+            SortableList<scalar> sortedY(y);
+            ilo = sortedY.indices()[0];
+            ihi = sortedY.indices()[sortedY.size()-1];
+            inhi = sortedY.indices()[sortedY.size()-2];
+        }
+
+        if (debug)
+        {
+            Pout<< "Iteration:" << iter
+                << " lowest:" << y[ilo] << " highest:" << y[ihi]
+                << " points:" << p << endl;
+
+            meshTools::writeOBJ(str(), p[ilo]);
+            vertI++;
+            str()<< "l " << vertI-1 << ' ' << vertI << nl;
+        }
+
+        if (y[ihi] < convergenceDistSqr)
+        {
+            // Get point on 0th surface.
+            Swap(p[0], p[ilo]);
+            Swap(y[0], y[ilo]);
+            return true;
+        }
+
+        // Reflection: point furthest away gets reflected.
+        scalar ytry = tryMorphTet
+        (
+            allSurfaces,
+            surfacesToTest,
+            10*y[ihi],             // search box.
+            p,
+            y,
+            pSum,
+            ihi,
+            -1.0
+        );
+
+        if (ytry <= y[ilo])
+        {
+            // If in right direction (y lower) expand by two.
+            ytry = tryMorphTet
+            (
+                allSurfaces,
+                surfacesToTest,
+                10*y[ihi],
+                p,
+                y,
+                pSum,
+                ihi,
+                2.0
+            );
+        }
+        else if (ytry >= y[inhi])
+        {
+            // If inside tet try contraction.
+
+            scalar ysave = y[ihi];
+
+            ytry = tryMorphTet
+            (
+                allSurfaces,
+                surfacesToTest,
+                10*y[ihi],
+                p,
+                y,
+                pSum,
+                ihi,
+                0.5
+            );
+
+            if (ytry >= ysave)
+            {
+                // Contract around lowest point.
+                forAll(p, i)
+                {
+                    if (i != ilo)
+                    {
+                        p[i] = 0.5*(p[i] + p[ilo]);
+                        y[i] = sumDistSqr
+                        (
+                            allSurfaces,
+                            surfacesToTest,
+                            y[ihi],
+                            p[i]
+                        );
+                    }
+                }
+                pSum = sum(p);
+            }
+        }
+    }
+
+    if (debug)
+    {
+        meshTools::writeOBJ(str(), p[0]);
+        vertI++;
+        str()<< "l " << vertI-1 << ' ' << vertI << nl;
+    }
+
+    // Failure to converge. Return best guess so far.
+    label ilo = findMin(y);
+    Swap(p[0], p[ilo]);
+    Swap(y[0], y[ilo]);
+    return false;
+}
+
+
+//// Get all intersections (in order) for single surface.
+//void Foam::searchableSurfacesQueries::findAllIntersections
+//(
+//    const searchableSurface& s,
+//    const pointField& start,
+//    const pointField& end,
+//    const vectorField& smallVec,
+//    List<List<pointIndexHit> >& surfaceHitInfo
+//)
+//{
+//    surfaceHitInfo.setSize(start.size());
+//
+//    // Current start point of vector
+//    pointField p0(start);
+//
+//    List<pointIndexHit> intersectInfo(start.size());
+//
+//    // For test whether finished doing vector.
+//    const vectorField dirVec(end-start);
+//    const scalarField magSqrDirVec(magSqr(dirVec));
+//
+//    while (true)
+//    {
+//        // Find first intersection. Synced.
+//        s.findLine(p0, end, intersectInfo);
+//
+//        label nHits = 0;
+//
+//        forAll(intersectInfo, i)
+//        {
+//            if (intersectInfo[i].hit())
+//            {
+//                nHits++;
+//
+//                label sz = surfaceHitInfo[i].size();
+//                surfaceHitInfo[i].setSize(sz+1);
+//                surfaceHitInfo[i][sz] = intersectInfo[i];
+//
+//                p0[i] = intersectInfo[i].hitPoint() + smallVec[i];
+//
+//                // If beyond endpoint set to endpoint so as not to pick up
+//                // any intersections. Could instead just filter out hits.
+//                if (((p0[i]-start[i])&dirVec[i]) > magSqrDirVec[i])
+//                {
+//                    p0[i] = end[i];
+//                }
+//            }
+//            else
+//            {
+//                // Set to endpoint to stop intersection test. See above.
+//                p0[i] = end[i];
+//            }
+//        }
+//
+//        // returnReduce(nHits) ?
+//        if (nHits == 0)
+//        {
+//            break;
+//        }
+//    }
+//}
+
+
+// Given current set of hits (allSurfaces, allInfo) merge in those coming from
+// surface surfI.
+void Foam::searchableSurfacesQueries::mergeHits
+(
+    const point& start,
+    const scalar mergeDist,
+
+    const label testI,                          // index of surface
+    const List<pointIndexHit>& surfHits,  // hits on surface
+
+    labelList& allSurfaces,
+    List<pointIndexHit>& allInfo,
+    scalarList& allDistSqr
+)
+{
+    // Precalculate distances
+    scalarList surfDistSqr(surfHits.size());
+    forAll(surfHits, i)
+    {
+        surfDistSqr[i] = magSqr(surfHits[i].hitPoint()-start);
+    }
+
+    forAll(surfDistSqr, i)
+    {
+        label index = findLower(allDistSqr, surfDistSqr[i]);
+
+        // Check if equal to lower.
+        if
+        (
+            index >= 0
+         && (mag(allDistSqr[index]-surfDistSqr[i]) < mergeDist)
+        )
+        {
+            // Same. Do not count.
+            //Pout<< "point:" << surfHits[i].hitPoint()
+            //    << " considered same as:" << allInfo[index].hitPoint()
+            //    << " within tol:" << mergeDist
+            //    << endl;
+        }
+        else
+        {
+            // Check if equal to higher
+            label next = index+1;
+            if
+            (
+                next < allDistSqr.size()
+             && (mag(allDistSqr[next]-surfDistSqr[i]) < mergeDist)
+            )
+            {
+                //Pout<< "point:" << surfHits[i].hitPoint()
+                //    << " considered same as:" << allInfo[next].hitPoint()
+                //    << " within tol:" << mergeDist
+                //    << endl;
+            }
+            else
+            {
+                // Insert after index
+                label sz = allSurfaces.size();
+                allSurfaces.setSize(sz+1);
+                allInfo.setSize(allSurfaces.size());
+                allDistSqr.setSize(allSurfaces.size());
+                // Make space.
+                for (label j = sz-1; j > index; --j)
+                {
+                    allSurfaces[j+1] = allSurfaces[j];
+                    allInfo[j+1] = allInfo[j];
+                    allDistSqr[j+1] = allDistSqr[j];
+                }
+                // Insert new value
+                allSurfaces[index+1] = testI;
+                allInfo[index+1] = surfHits[i];
+                allDistSqr[index+1] = surfDistSqr[i];
+            }
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+// Find any intersection
+void Foam::searchableSurfacesQueries::findAnyIntersection
+(
+    const PtrList<searchableSurface>& allSurfaces,
+    const labelList& surfacesToTest,
+    const pointField& start,
+    const pointField& end,
+    labelList& hitSurfaces,
+    List<pointIndexHit>& hitInfo
+)
+{
+    hitSurfaces.setSize(start.size());
+    hitSurfaces = -1;
+    hitInfo.setSize(start.size());
+
+    // Work arrays
+    labelList hitMap(identity(start.size()));
+    pointField p0(start);
+    pointField p1(end);
+    List<pointIndexHit> intersectInfo(start.size());
+
+    forAll(surfacesToTest, testI)
+    {
+        // Do synchronised call to all surfaces.
+        allSurfaces[surfacesToTest[testI]].findLineAny(p0, p1, intersectInfo);
+
+        // Copy all hits into arguments, continue with misses
+        label newI = 0;
+        forAll(intersectInfo, i)
+        {
+            if (intersectInfo[i].hit())
+            {
+                hitInfo[hitMap[i]] = intersectInfo[i];
+                hitSurfaces[hitMap[i]] = testI;
+            }
+            else
+            {
+                if (i != newI)
+                {
+                    hitMap[newI] = hitMap[i];
+                    p0[newI] = p0[i];
+                    p1[newI] = p1[i];
+                }
+                newI++;
+            }
+        }
+
+        // All done? Note that this decision should be synchronised
+        if (newI == 0)
+        {
+            break;
+        }
+
+        // Trim and continue
+        hitMap.setSize(newI);
+        p0.setSize(newI);
+        p1.setSize(newI);
+        intersectInfo.setSize(newI);
+    }
+}
+
+
+void Foam::searchableSurfacesQueries::findAllIntersections
+(
+    const PtrList<searchableSurface>& allSurfaces,
+    const labelList& surfacesToTest,
+    const pointField& start,
+    const pointField& end,
+    labelListList& hitSurfaces,
+    List<List<pointIndexHit> >& hitInfo
+)
+{
+    // Note: maybe move the single-surface all intersections test into
+    // searchable surface? Some of the tolerance issues might be
+    // lessened.
+
+    // 2. Currently calling searchableSurface::findLine with start==end
+    //    is expected to find no intersection. Problem if it does.
+
+    hitSurfaces.setSize(start.size());
+    hitInfo.setSize(start.size());
+
+    if (surfacesToTest.size() == 0)
+    {
+        return;
+    }
+
+    // Test first surface
+    allSurfaces[surfacesToTest[0]].findLineAll(start, end, hitInfo);
+
+    // Set hitSurfaces and distance
+    List<scalarList> hitDistSqr(hitInfo.size());
+    forAll(hitInfo, pointI)
+    {
+        const List<pointIndexHit>& pHits = hitInfo[pointI];
+
+        labelList& pSurfaces = hitSurfaces[pointI];
+        pSurfaces.setSize(pHits.size());
+        pSurfaces = 0;
+
+        scalarList& pDistSqr = hitDistSqr[pointI];
+        pDistSqr.setSize(pHits.size());
+        forAll(pHits, i)
+        {
+            pDistSqr[i] = magSqr(pHits[i].hitPoint() - start[pointI]);
+        }
+    }
+
+
+    if (surfacesToTest.size() > 1)
+    {
+        // Small vector to increment start vector by to find next intersection
+        // along line. Constant factor added to make sure that start==end still
+        // ends iteration in findAllIntersections. Also SMALL is just slightly
+        // too small.
+        const vectorField smallVec
+        (
+            1E2*SMALL*(end-start)
+          + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
+        );
+
+        // Tolerance used to check whether points are equal. Note: used to
+        // compare distance^2. Note that we use the maximum possible tolerance
+        // (reached at intersections close to the end point)
+        const scalarField mergeDist(2*mag(smallVec)*mag(end-start));
+
+        // Test the other surfaces and merge (according to distance from start).
+        for (label testI = 1; testI < surfacesToTest.size(); testI++)
+        {
+            List<List<pointIndexHit> > surfHits;
+            allSurfaces[surfacesToTest[testI]].findLineAll
+            (
+                start,
+                end,
+                surfHits
+            );
+
+            forAll(surfHits, pointI)
+            {
+                mergeHits
+                (
+                    start[pointI],          // Current segment
+                    mergeDist[pointI],
+
+                    testI,                  // Surface and its hits
+                    surfHits[pointI],
+
+                    hitSurfaces[pointI],    // Merge into overall hit info
+                    hitInfo[pointI],
+                    hitDistSqr[pointI]
+                );
+            }
+        }
+    }
+}
+
+
+//// Find intersections of edge nearest to both endpoints.
+//void Foam::searchableSurfacesQueries::findNearestIntersection
+//(
+//    const PtrList<searchableSurface>& allSurfaces,
+//    const labelList& surfacesToTest,
+//    const pointField& start,
+//    const pointField& end,
+//
+//    labelList& surface1,
+//    List<pointIndexHit>& hit1,
+//    labelList& surface2,
+//    List<pointIndexHit>& hit2
+//)
+//{
+//    // 1. intersection from start to end
+//    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+//    // Initialize arguments
+//    surface1.setSize(start.size());
+//    surface1 = -1;
+//    hit1.setSize(start.size());
+//
+//    // Current end of segment to test.
+//    pointField nearest(end);
+//    // Work array
+//    List<pointIndexHit> nearestInfo(start.size());
+//
+//    forAll(surfacesToTest, testI)
+//    {
+//        // See if any intersection between start and current nearest
+//        allSurfaces[surfacesToTest[testI]].findLine
+//        (
+//            start,
+//            nearest,
+//            nearestInfo
+//        );
+//
+//        forAll(nearestInfo, pointI)
+//        {
+//            if (nearestInfo[pointI].hit())
+//            {
+//                hit1[pointI] = nearestInfo[pointI];
+//                surface1[pointI] = testI;
+//                nearest[pointI] = hit1[pointI].hitPoint();
+//            }
+//        }
+//    }
+//
+//
+//    // 2. intersection from end to last intersection
+//    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+//    // Find the nearest intersection from end to start. Note that we
+//    // initialize to the first intersection (if any).
+//    surface2 = surface1;
+//    hit2 = hit1;
+//
+//    // Set current end of segment to test.
+//    forAll(nearest, pointI)
+//    {
+//        if (hit1[pointI].hit())
+//        {
+//            nearest[pointI] = hit1[pointI].hitPoint();
+//        }
+//        else
+//        {
+//            // Disable testing by setting to end.
+//            nearest[pointI] = end[pointI];
+//        }
+//    }
+//
+//    forAll(surfacesToTest, testI)
+//    {
+//        // See if any intersection between end and current nearest
+//        allSurfaces[surfacesToTest[i]].findLine(end, nearest, nearestInfo);
+//
+//        forAll(nearestInfo, pointI)
+//        {
+//            if (nearestInfo[pointI].hit())
+//            {
+//                hit2[pointI] = nearestInfo[pointI];
+//                surface2[pointI] = testI;
+//                nearest[pointI] = hit2[pointI].hitPoint();
+//            }
+//        }
+//    }
+//}
+
+
+// Find nearest. Return -1 or nearest point
+void Foam::searchableSurfacesQueries::findNearest
+(
+    const PtrList<searchableSurface>& allSurfaces,
+    const labelList& surfacesToTest,
+    const pointField& samples,
+    const scalarField& nearestDistSqr,
+    labelList& nearestSurfaces,
+    List<pointIndexHit>& nearestInfo
+)
+{
+    // Initialise
+    nearestSurfaces.setSize(samples.size());
+    nearestSurfaces = -1;
+    nearestInfo.setSize(samples.size());
+
+    // Work arrays
+    scalarField minDistSqr(nearestDistSqr);
+    List<pointIndexHit> hitInfo(samples.size());
+
+    forAll(surfacesToTest, testI)
+    {
+        allSurfaces[surfacesToTest[testI]].findNearest
+        (   
+            samples,
+            minDistSqr,
+            hitInfo
+        );
+
+        // Update minDistSqr and arguments
+        forAll(hitInfo, pointI)
+        {
+            if (hitInfo[pointI].hit())
+            {
+                minDistSqr[pointI] = magSqr
+                (   
+                    hitInfo[pointI].hitPoint()
+                  - samples[pointI]
+                );
+                nearestInfo[pointI] = hitInfo[pointI];
+                nearestSurfaces[pointI] = testI;
+            }
+        }
+    }
+}
+
+
+//- Calculate point which is on a set of surfaces.
+Foam::pointIndexHit Foam::searchableSurfacesQueries::facesIntersection
+(
+    const PtrList<searchableSurface>& allSurfaces,
+    const labelList& surfacesToTest,
+    const scalar initDistSqr,
+    const scalar convergenceDistSqr,
+    const point& start
+)
+{
+    // Get four starting points. Take these as the projection of the
+    // starting point onto the surfaces and the mid point
+    List<point> nearest(surfacesToTest.size()+1);
+
+    point sumNearest = vector::zero;
+
+    forAll(surfacesToTest, i)
+    {
+        pointIndexHit hit
+        (
+            tempFindNearest(allSurfaces[surfacesToTest[i]], start, initDistSqr)
+        );
+
+        if (hit.hit())
+        {
+            nearest[i] = hit.hitPoint();
+            sumNearest += nearest[i];
+        }
+        else
+        {
+            FatalErrorIn
+            (
+                "searchableSurfacesQueries::facesIntersection"
+                "(const labelList&, const scalar, const scalar, const point&)"
+            )   << "Did not find point within distance "
+                << initDistSqr << " of starting point " << start
+                << " on surface "
+                << allSurfaces[surfacesToTest[i]].IOobject::name()
+                << abort(FatalError);
+        }
+    }
+
+    nearest[nearest.size()-1] = sumNearest / surfacesToTest.size();
+
+
+    // Get the sum of distances (initial evaluation)
+    List<scalar> nearestDist(nearest.size());
+
+    forAll(nearestDist, i)
+    {
+        nearestDist[i] = sumDistSqr
+        (
+            allSurfaces,
+            surfacesToTest,
+            initDistSqr,
+            nearest[i]
+        );
+    }
+
+
+    //- Downhill Simplex method
+
+    bool converged = morphTet
+    (
+        allSurfaces,
+        surfacesToTest,
+        initDistSqr,
+        convergenceDistSqr,
+        2000,
+        nearest,
+        nearestDist
+    );
+
+
+    pointIndexHit intersection;
+
+    if (converged)
+    {
+        // Project nearest onto 0th surface.
+        intersection = tempFindNearest
+        (
+            allSurfaces[surfacesToTest[0]],
+            nearest[0],
+            nearestDist[0]
+        );
+    }
+
+    //if (!intersection.hit())
+    //{
+    //    // Restart
+    //    scalar smallDist = Foam::sqr(convergenceDistSqr);
+    //    nearest[0] = intersection.hitPoint();
+    //    nearest[1] = nearest[0];
+    //    nearest[1].x() += smallDist;
+    //    nearest[2] = nearest[0];
+    //    nearest[2].y() += smallDist;
+    //    nearest[3] = nearest[0];
+    //    nearest[3].z() += smallDist;
+    //
+    //    forAll(nearestDist, i)
+    //    {
+    //        nearestDist[i] = sumDistSqr
+    //        (
+    //            surfacesToTest,
+    //            initDistSqr,
+    //            nearest[i]
+    //        );
+    //    }
+    //
+    //    intersection = morphTet
+    //    (
+    //        allSurfaces,
+    //        surfacesToTest,
+    //        initDistSqr,
+    //        convergenceDistSqr,
+    //        1000,
+    //        nearest,
+    //        nearestDist
+    //    );
+    //}
+
+    return intersection;
+}
+
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurface/searchableSurfacesQueries.H b/src/meshTools/searchableSurface/searchableSurfacesQueries.H
new file mode 100644
index 0000000000000000000000000000000000000000..dcb84050a6f56bbf6399262c55650ea7196d0eb2
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableSurfacesQueries.H
@@ -0,0 +1,198 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::searchableSurfacesQueries
+
+Description
+    A collection of tools for searchableSurfaces.
+
+SourceFiles
+    searchableSurfacesQueries.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef searchableSurfacesQueries_H
+#define searchableSurfacesQueries_H
+
+#include "searchableSurface.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+class plane;
+
+/*---------------------------------------------------------------------------*\
+                           Class searchableSurfacesQueries Declaration
+\*---------------------------------------------------------------------------*/
+
+class searchableSurfacesQueries
+{
+    // Private data
+
+    // Private Member Functions
+
+        //- Temporary wrapper around findNearest. Used in facesIntersection only
+        static pointIndexHit tempFindNearest
+        (
+            const searchableSurface&,
+            const point& pt,
+            const scalar initDistSqr
+        );
+
+        //- Calculate sum of distances to nearest point on surfaces. Is used
+        //  in minimisation to find intersection. Returns sum of (square of)
+        //  distances to the surfaces.
+        static scalar sumDistSqr
+        (
+            const PtrList<searchableSurface>&,
+            const labelList& surfacesToTest,
+            const scalar initialDistSqr,    // search box
+            const point& pt
+        );
+
+        //- Takes the tet (points p) and reflects the point with the
+        //  highest value around the centre (pSum). Checks if it gets closer
+        //  and updates p, y if so.
+        static scalar tryMorphTet
+        (
+            const PtrList<searchableSurface>&,
+            const labelList& surfacesToTest,
+            const scalar initialDistSqr,
+            List<vector>& p,
+            List<scalar>& y,
+            vector& pSum,
+            const label ihi,
+            const scalar fac
+        );
+
+        //- Downhill simplex method: find the point with min cumulative
+        //  distance to all surfaces. Does so by morphing a tet (points p).
+        //  Returns the point on the 0th surface or hit if not reached within
+        //  maxIters iterations.
+        static bool morphTet
+        (
+            const PtrList<searchableSurface>&,
+            const labelList& surfacesToTest,
+            const scalar initialDistSqr,
+            const scalar convergenceDistSqr,
+            const label maxIter,
+            List<vector>& p,
+            List<scalar>& y
+        );
+
+        //static void findAllIntersections
+        //(
+        //    const searchableSurface& s,
+        //    const pointField& start,
+        //    const pointField& end,
+        //    const vectorField& smallVec,
+        //    List<List<pointIndexHit> >&
+        //);
+
+        static void mergeHits
+        (
+            const point& start,
+            const scalar mergeDist,
+
+            const label surfI,
+            const List<pointIndexHit>& surfHits,
+
+            labelList& allSurfaces,
+            List<pointIndexHit>& allInfo,
+            scalarList& allDistSqr
+        );
+
+public:
+
+    // Declare name of the class and its debug switch
+    ClassName("searchableSurfacesQueries");
+
+
+        // Multiple point queries.
+
+            //- Find any intersection. Return hit point information and
+            //  index in surfacesToTest. If multiple surfaces hit the first
+            //  surface is returned, not necessarily the nearest (to start).
+            static void findAnyIntersection
+            (
+                const PtrList<searchableSurface>&,
+                const labelList& surfacesToTest,
+                const pointField& start,
+                const pointField& end,
+                labelList& surfaces,
+                List<pointIndexHit>&
+            );
+
+            //- Find all intersections in order from start to end. Returns for
+            //  every hit the index in surfacesToTest and the hit info.
+            static void findAllIntersections
+            (
+                const PtrList<searchableSurface>&,
+                const labelList& surfacesToTest,
+                const pointField& start,
+                const pointField& end,
+                labelListList& surfaces,
+                List<List<pointIndexHit> >& surfaceHits
+            );
+
+            //- Find nearest. Return -1 (and a miss()) or surface and nearest
+            //  point.
+            static void findNearest
+            (
+                const PtrList<searchableSurface>&,
+                const labelList& surfacesToTest,
+                const pointField&,
+                const scalarField& nearestDistSqr,
+                labelList& surfaces,
+                List<pointIndexHit>&
+            );
+
+
+        // Single point queries
+
+            //- Calculate point which is on a set of surfaces. WIP.
+            static pointIndexHit facesIntersection
+            (
+                const PtrList<searchableSurface>& allSurfaces,
+                const labelList& surfacesToTest,
+                const scalar initDistSqr,
+                const scalar convergenceDistSqr,
+                const point& start
+            );
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurface/triSurfaceMesh.C b/src/meshTools/searchableSurface/triSurfaceMesh.C
new file mode 100644
index 0000000000000000000000000000000000000000..526646c01460b5d6ec4014efb316cb2bd44104a1
--- /dev/null
+++ b/src/meshTools/searchableSurface/triSurfaceMesh.C
@@ -0,0 +1,552 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "triSurfaceMesh.H"
+#include "Random.H"
+#include "addToRunTimeSelectionTable.H"
+#include "EdgeMap.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+defineTypeNameAndDebug(triSurfaceMesh, 0);
+addToRunTimeSelectionTable(searchableSurface, triSurfaceMesh, dict);
+
+}
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+//- Check file existence
+const Foam::fileName& Foam::triSurfaceMesh::checkFile
+(
+    const fileName& fName,
+    const fileName& objectName
+)
+{
+    if (fName == fileName::null)
+    {
+        FatalErrorIn
+        (
+            "triSurfaceMesh::checkFile(const fileName&, const fileName&)"
+        )   << "Cannot find triSurfaceMesh starting from "
+            << objectName << exit(FatalError);
+    }
+    return fName;
+}
+
+
+bool Foam::triSurfaceMesh::isSurfaceClosed() const
+{
+    // Construct pointFaces. Let's hope surface has compact point
+    // numbering ...
+    labelListList pointFaces;
+    invertManyToMany(points().size(), *this, pointFaces);
+
+    // Loop over all faces surrounding point. Count edges emanating from point.
+    // Every edge should be used by two faces exactly.
+    // To prevent doing work twice per edge only look at edges to higher
+    // point
+    EdgeMap<label> facesPerEdge(100);
+    forAll(pointFaces, pointI)
+    {
+        const labelList& pFaces = pointFaces[pointI];
+
+        facesPerEdge.clear();
+        forAll(pFaces, i)
+        {
+            const labelledTri& f = triSurface::operator[](pFaces[i]);
+            label fp = findIndex(f, pointI);
+
+            // Forward edge
+            {
+                label p1 = f[f.fcIndex(fp)];
+
+                if (p1 > pointI)
+                {
+                    const edge e(pointI, p1);
+                    EdgeMap<label>::iterator eFnd = facesPerEdge.find(e);
+                    if (eFnd != facesPerEdge.end())
+                    {
+                        if (eFnd() == 2)
+                        {
+                            return false;
+                        }
+                        eFnd()++;
+                    }
+                    else
+                    {
+                        facesPerEdge.insert(e, 1);
+                    }
+                }
+            }
+            // Reverse edge
+            {
+                label p1 = f[f.rcIndex(fp)];
+
+                if (p1 > pointI)
+                {
+                    const edge e(pointI, p1);
+                    EdgeMap<label>::iterator eFnd = facesPerEdge.find(e);
+                    if (eFnd != facesPerEdge.end())
+                    {
+                        if (eFnd() == 2)
+                        {
+                            return false;
+                        }
+                        eFnd()++;
+                    }
+                    else
+                    {
+                        facesPerEdge.insert(e, 1);
+                    }
+                }
+            }
+        }
+
+        // Check for any edges used only once.
+        forAllConstIter(EdgeMap<label>, facesPerEdge, iter)
+        {
+            if (iter() != 2)
+            {
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io, const triSurface& s)
+:
+    searchableSurface(io),
+    objectRegistry(io),
+    triSurface(s),
+    surfaceClosed_(-1)
+{}
+
+
+Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io)
+:
+    searchableSurface(io),
+    objectRegistry(io),
+    triSurface
+    (
+        checkFile
+        (
+            searchableSurface::filePath(),
+            searchableSurface::objectPath()
+        )
+    ),
+    surfaceClosed_(-1)
+{}
+
+
+Foam::triSurfaceMesh::triSurfaceMesh
+(
+    const IOobject& io,
+    const dictionary& dict
+)
+:
+    searchableSurface(io),
+    objectRegistry(io),
+    triSurface
+    (
+        checkFile
+        (
+            searchableSurface::filePath(),
+            searchableSurface::objectPath()
+        )
+    ),
+    surfaceClosed_(-1)
+{}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::triSurfaceMesh::~triSurfaceMesh()
+{
+    clearOut();
+}
+
+
+void Foam::triSurfaceMesh::clearOut()
+{
+    tree_.clear();
+    edgeTree_.clear();
+    triSurface::clearOut();
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::triSurfaceMesh::movePoints(const pointField& newPoints)
+{
+    tree_.clear();
+    edgeTree_.clear();
+    triSurface::movePoints(newPoints);
+}
+
+
+const Foam::indexedOctree<Foam::treeDataTriSurface>&
+    Foam::triSurfaceMesh::tree() const
+{
+    if (!tree_.valid())
+    {
+        treeBoundBox bb(points(), meshPoints());
+
+        // Random number generator. Bit dodgy since not exactly random ;-)
+        Random rndGen(65431);
+
+        tree_.reset
+        (
+            new indexedOctree<treeDataTriSurface>
+            (
+                treeDataTriSurface(*this),
+                bb.extend(rndGen, 1E-3),    // slightly randomize bb
+                10,     // maxLevel
+                10,     // leafsize
+                3.0     // duplicity
+            )
+        );
+    }
+
+    return tree_();
+}
+
+
+const Foam::indexedOctree<Foam::treeDataEdge>&
+    Foam::triSurfaceMesh::edgeTree() const
+{
+    if (!edgeTree_.valid())
+    {
+        treeBoundBox bb(localPoints());
+
+        // Boundary edges
+        labelList bEdges
+        (
+            identity
+            (
+                nEdges()
+               -nInternalEdges()
+            )
+          + nInternalEdges()
+        );
+
+        // Random number generator. Bit dodgy since not exactly random ;-)
+        Random rndGen(65431);
+
+        edgeTree_.reset
+        (
+            new indexedOctree<treeDataEdge>
+            (
+                treeDataEdge
+                (
+                    false,          // cachebb
+                    edges(),        // edges
+                    localPoints(),  // points
+                    bEdges          // selected edges
+                ),
+                bb.extend(rndGen, 1E-3),    // slightly randomize bb
+                8,      // maxLevel
+                10,     // leafsize
+                3.0     // duplicity
+            )
+        );
+    }
+    return edgeTree_();
+}
+
+
+const Foam::wordList& Foam::triSurfaceMesh::regions() const
+{
+    if (regions_.size() == 0)
+    {
+        regions_.setSize(patches().size());
+        forAll(regions_, regionI)
+        {
+            regions_[regionI] = patches()[regionI].name();
+        }
+    }
+    return regions_;
+}
+
+
+//Foam::pointIndexHit Foam::triSurfaceMesh::findNearest
+//(
+//    const point& sample,
+//    const scalar nearestDistSqr
+//) const
+//{
+//    return tree().findNearest(sample, nearestDistSqr);
+//}
+//
+//
+//Foam::pointIndexHit Foam::triSurfaceMesh::findNearestOnEdge
+//(
+//    const point& sample,
+//    const scalar nearestDistSqr
+//) const
+//{
+//    return = edgeTree().findNearest(sample, nearestDistSqr);
+//}
+//
+//
+//Foam::pointIndexHit Foam::triSurfaceMesh::findNearest
+//(
+//    const linePointRef& ln,
+//    treeBoundBox& tightest,
+//    point& linePoint
+//) const
+//{
+//    return tree().findNearest(ln, tightest, linePoint);
+//}
+//
+//
+//Foam::pointIndexHit Foam::triSurfaceMesh::findLine
+//(
+//    const point& start,
+//    const point& end
+//) const
+//{
+//    return tree().findLine(start, end);
+//}
+//
+//
+//Foam::pointIndexHit Foam::triSurfaceMesh::findLineAny
+//(
+//    const point& start,
+//    const point& end
+//) const
+//{
+//    return tree().findLineAny(start, end);
+//}
+
+
+// Find out if surface is closed.
+bool Foam::triSurfaceMesh::hasVolumeType() const
+{
+    if (surfaceClosed_ == -1)
+    {
+        if (isSurfaceClosed())
+        {
+            surfaceClosed_ = 1;
+        }
+        else
+        {
+            surfaceClosed_ = 0;
+        }
+    }
+
+    return surfaceClosed_ == 1;
+}
+
+
+void Foam::triSurfaceMesh::findNearest
+(
+    const pointField& samples,
+    const scalarField& nearestDistSqr,
+    List<pointIndexHit>& info
+) const
+{
+    const indexedOctree<treeDataTriSurface>& octree = tree();
+
+    info.setSize(samples.size());
+
+    forAll(samples, i)
+    {
+        static_cast<pointIndexHit&>(info[i]) =
+            octree.findNearest(samples[i], nearestDistSqr[i]);
+    }
+}
+
+
+void Foam::triSurfaceMesh::findLine
+(
+    const pointField& start,
+    const pointField& end,
+    List<pointIndexHit>& info
+) const
+{
+    const indexedOctree<treeDataTriSurface>& octree = tree();
+
+    info.setSize(start.size());
+
+    forAll(start, i)
+    {
+        static_cast<pointIndexHit&>(info[i]) = octree.findLine
+        (
+            start[i],
+            end[i]
+        );
+    }
+}
+
+
+void Foam::triSurfaceMesh::findLineAny
+(
+    const pointField& start,
+    const pointField& end,
+    List<pointIndexHit>& info
+) const
+{
+    const indexedOctree<treeDataTriSurface>& octree = tree();
+
+    info.setSize(start.size());
+
+    forAll(start, i)
+    {
+        static_cast<pointIndexHit&>(info[i]) =
+            octree.findLineAny(start[i], end[i]);
+    }
+}
+
+
+void Foam::triSurfaceMesh::findLineAll
+(
+    const pointField& start,
+    const pointField& end,
+    List<List<pointIndexHit> >& info
+) const
+{
+    const indexedOctree<treeDataTriSurface>& octree = tree();
+
+    info.setSize(start.size());
+
+    // Work array
+    DynamicList<pointIndexHit, 1, 1> hits;
+
+    // Tolerances
+    const vectorField dirVec(end-start);
+    const scalarField magSqrDirVec(magSqr(dirVec));
+    const vectorField smallVec
+    (
+        Foam::sqrt(SMALL)*dirVec
+      + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
+    );
+
+    forAll(start, pointI)
+    {
+        hits.clear();
+
+        // Current starting point of ray.
+        point pt = start[pointI];
+
+        while (true)
+        {
+            // See if any intersection between pt and end
+            pointIndexHit inter = octree.findLine(pt, end[pointI]);
+
+            if (!inter.hit())
+            {
+                break;
+            }
+            hits.append(inter);
+
+            pt = inter.hitPoint() + smallVec[pointI];
+
+            if (((pt-start[pointI])&dirVec[pointI]) > magSqrDirVec[pointI])
+            {
+                // Adding smallVec has taken us beyond end
+                break;
+            }
+        }
+
+        hits.shrink();
+        info[pointI].transfer(hits);
+        hits.clear();
+    }
+}
+
+
+void Foam::triSurfaceMesh::getRegion
+(
+    const List<pointIndexHit>& info,
+    labelList& region
+) const
+{
+    region.setSize(info.size());
+    forAll(info, i)
+    {
+        if (info[i].hit())
+        {
+            region[i] = triSurface::operator[](info[i].index()).region();
+        }
+        else
+        {
+            region[i] = -1;
+        }
+    }
+}
+
+
+void Foam::triSurfaceMesh::getNormal
+(
+    const List<pointIndexHit>& info,
+    vectorField& normal
+) const
+{
+    normal.setSize(info.size());
+
+    forAll(info, i)
+    {
+        if (info[i].hit())
+        {
+            normal[i] = faceNormals()[info[i].index()];
+        }
+        else
+        {
+            // Set to what?
+            normal[i] = vector::zero;
+        }
+    }
+}
+
+
+void Foam::triSurfaceMesh::getVolumeType
+(
+    const pointField& points,
+    List<volumeType>& volType
+) const
+{
+    volType.setSize(points.size());
+
+    forAll(points, pointI)
+    {
+        const point& pt = points[pointI];
+
+        // - use cached volume type per each tree node
+        // - cheat conversion since same values
+        volType[pointI] = static_cast<volumeType>(tree().getVolumeType(pt));
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/triSurface/searchableSurface/triSurfaceMesh.H b/src/meshTools/searchableSurface/triSurfaceMesh.H
similarity index 64%
rename from src/meshTools/triSurface/searchableSurface/triSurfaceMesh.H
rename to src/meshTools/searchableSurface/triSurfaceMesh.H
index 453b4daa6127456e0077e03568b8688212d6bb3a..1b9fa0c945838efc572700f15515aa51592c72b6 100644
--- a/src/meshTools/triSurface/searchableSurface/triSurfaceMesh.H
+++ b/src/meshTools/searchableSurface/triSurfaceMesh.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -54,7 +54,7 @@ namespace Foam
 class triSurfaceMesh
 :
     public searchableSurface,
-    public objectRegistry,
+    public objectRegistry,      // so we can store fields
     public triSurface
 {
 private:
@@ -67,6 +67,12 @@ private:
         //- Search tree for boundary edges.
         mutable autoPtr<indexedOctree<treeDataEdge> > edgeTree_;
 
+        //- Names of regions
+        mutable wordList regions_;
+
+        //- Is surface closed
+        mutable label surfaceClosed_;
+
     // Private Member Functions
 
         //- Check file existence
@@ -76,6 +82,10 @@ private:
             const fileName& objectName
         );
 
+        //- Check whether surface is closed without calculating any permanent
+        //  addressing.
+        bool isSurfaceClosed() const;
+
         //- Disallow default bitwise copy construct
         triSurfaceMesh(const triSurfaceMesh&);
 
@@ -97,11 +107,10 @@ public:
         //- Construct read
         triSurfaceMesh(const IOobject& io);
 
-        //- Construct as searchableSurface
+        //- Construct from dictionary (used by searchableSurface)
         triSurfaceMesh
         (
-            const word& name,
-            const objectRegistry& obj,
+            const IOobject& io,
             const dictionary& dict
         );
 
@@ -128,57 +137,73 @@ public:
 
         // searchableSurface implementation
 
-            //- Calculate nearest point on surface. Returns
-            //  - bool : any point found nearer than nearestDistSqr
-            //  - label: relevant index in surface
-            //  - point: actual nearest point found
-            virtual pointIndexHit findNearest
+            virtual const wordList& regions() const;
+
+            //- Whether supports volume type below. I.e. whether is closed.
+            virtual bool hasVolumeType() const;
+
+
+        // Multiple point queries.
+
+            virtual void findNearest
             (
-                const point& sample,
-                const scalar nearestDistSqr
+                const pointField& sample,
+                const scalarField& nearestDistSqr,
+                List<pointIndexHit>&
             ) const;
 
-            //- Calculate nearest point on edge. Returns
-            //  - bool : any point found nearer than nearestDistSqr
-            //  - label: relevant index in surface
-            //  - point: actual nearest point found
-            virtual pointIndexHit findNearestOnEdge
+            virtual void findLine
             (
-                const point& sample,
-                const scalar nearestDistSqr
+                const pointField& start,
+                const pointField& end,
+                List<pointIndexHit>&
             ) const;
 
-            //- Find nearest to line. Returns
-            //  - bool : any point found?
-            //  - label: relevant index in shapes
-            //  - point: actual nearest point found
-            //  sets:
-            //  - tightest  : bounding box
-            //  - linePoint : corresponding nearest point on line
-            virtual pointIndexHit findNearest
+            virtual void findLineAny
             (
-                const linePointRef& ln,
-                treeBoundBox& tightest,
-                point& linePoint
+                const pointField& start,
+                const pointField& end,
+                List<pointIndexHit>&
             ) const;
 
-            //- Find nearest intersection of line between start and end.
-            virtual pointIndexHit findLine
+            //- Get all intersections in order from start to end.
+            virtual void findLineAll
             (
-                const point& start,
-                const point& end
+                const pointField& start,
+                const pointField& end,
+                List<List<pointIndexHit> >&
             ) const;
 
-            //- Find any intersection of line between start and end.
-            virtual pointIndexHit findLineAny
+            //- From a set of points and indices get the region
+            virtual void getRegion
             (
-                const point& start,
-                const point& end
+                const List<pointIndexHit>&,
+                labelList& region
+            ) const;
+
+            //- From a set of points and indices get the normal
+            virtual void getNormal
+            (
+                const List<pointIndexHit>&,
+                vectorField& normal
             ) const;
 
             //- Determine type (inside/outside/mixed) for point. unknown if
             //  cannot be determined (e.g. non-manifold surface)
-            virtual volumeType getVolumeType(const point&) const;
+            virtual void getVolumeType
+            (
+                const pointField&,
+                List<volumeType>&
+            ) const;
+
+
+        // regIOobject implementation
+
+            bool writeData(Ostream&) const
+            {
+                notImplemented("triSurfaceMesh::writeData(Ostream&) const");
+                return false;
+            }
 
 };
 
diff --git a/src/meshTools/triSurface/searchableSurface/searchableBox.C b/src/meshTools/triSurface/searchableSurface/searchableBox.C
deleted file mode 100644
index 77e48c3a8ee80f863675c3a4bb22e68fcc13dc30..0000000000000000000000000000000000000000
--- a/src/meshTools/triSurface/searchableSurface/searchableBox.C
+++ /dev/null
@@ -1,247 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by the
-    Free Software Foundation; either version 2 of the License, or (at your
-    option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM; if not, write to the Free Software Foundation,
-    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-\*---------------------------------------------------------------------------*/
-
-#include "searchableBox.H"
-#include "addToRunTimeSelectionTable.H"
-
-// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-defineTypeNameAndDebug(searchableBox, 0);
-addToRunTimeSelectionTable(searchableSurface, searchableBox, dict);
-
-}
-
-// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::searchableBox::searchableBox
-(
-    const word& name,
-    const treeBoundBox& bb
-)
-:
-    searchableSurface(name),
-    treeBoundBox(bb)
-{}
-
-
-Foam::searchableBox::searchableBox
-(
-    const word& name,
-    const objectRegistry& obj,
-    const dictionary& dict
-)
-:
-    searchableSurface(name),
-    treeBoundBox(dict.lookup("min"), dict.lookup("max"))
-{}
-
-
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::searchableBox::~searchableBox()
-{}
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-Foam::pointIndexHit Foam::searchableBox::findNearest
-(
-    const point& sample,
-    const scalar nearestDistSqr
-) const
-{
-    // Point can be inside or outside. For every component direction can be
-    // left of min, right of max or inbetween.
-    // - outside points: project first one x plane (either min().x()
-    // or max().x()), then onto y plane and finally z. You should be left
-    // with intersection point
-    // - inside point: find nearest side (compare to mid point). Pick any
-    // one of three points.
-
-    const point bbMid(mid());
-
-    // Outside point projected onto cube
-    point interPt(sample);
-    bool outside = false;
-
-    // (for internal points) Per direction what nearest cube side is
-    point near;
-
-    for (direction dir = 0; dir < vector::nComponents; dir++)
-    {
-        if (interPt[dir] < min()[dir])
-        {
-            interPt[dir] = min()[dir];
-            outside = true;
-        }
-        else if (interPt[dir] > max()[dir])
-        {
-            interPt[dir] = max()[dir];
-            outside = true;
-        }
-        else if (interPt[dir] > bbMid[dir])
-        {
-            near[dir] = max()[dir];
-        }
-        else
-        {
-            near[dir] = min()[dir];
-        }
-    }
-
-
-    // For outside points the interPt will be correct now. Handle inside points
-    // using the three near distances. Project onto the nearest plane.
-    if (!outside)
-    {
-        vector dist(cmptMag(interPt - near));
-
-        if (dist.x() < dist.y())
-        {
-            if (dist.x() < dist.z())
-            {
-                interPt.x() = near.x();
-            }
-            else
-            {
-                interPt.z() = near.z();
-            }
-        }
-        else
-        {
-            if (dist.y() < dist.z())
-            {
-                interPt.y() = near.y();
-            }
-            else
-            {
-                interPt.z() = near.z();
-            }
-        }
-    }
-
-    return pointIndexHit(true, interPt, 0);
-}
-
-
-Foam::pointIndexHit Foam::searchableBox::findNearestOnEdge
-(
-    const point& sample,
-    const scalar nearestDistSqr
-) const
-{
-    const point bbMid(mid());
-
-    point interPt(sample);
-
-    for (direction dir = 0; dir < vector::nComponents; dir++)
-    {
-        // Project onto left or right depending on mid
-        if (interPt[dir] > bbMid[dir])
-        {
-            interPt[dir] = max()[dir];
-        }
-        else
-        {
-            interPt[dir] = min()[dir];
-        }
-    }
-
-    return pointIndexHit(true, interPt, 0);
-}
-
-
-Foam::pointIndexHit Foam::searchableBox::findNearest
-(
-    const linePointRef& ln,
-    treeBoundBox& tightest,
-    point& linePoint
-) const
-{
-    notImplemented
-    (
-        "searchableBox::findNearest"
-        "(const linePointRef&, treeBoundBox&, point&)"
-    );
-    return pointIndexHit();
-}
-
-
-Foam::pointIndexHit Foam::searchableBox::findLine
-(
-    const point& start,
-    const point& end
-) const
-{
-    point intPt;
-    bool foundInter = intersects(start, end, intPt);
-
-    return pointIndexHit(foundInter, intPt, 0);
-}
-
-
-Foam::pointIndexHit Foam::searchableBox::findLineAny
-(
-    const point& start,
-    const point& end
-) const
-{
-    return findLine(start, end);
-}
-
-
-Foam::searchableSurface::volumeType Foam::searchableBox::getVolumeType
-(
-    const point& pt
-) const
-{
-    for (direction dir = 0; dir < vector::nComponents; dir++)
-    {
-        if (pt[dir] < min()[dir] || pt[dir] > max()[dir])
-        {
-            return OUTSIDE;
-        }
-    }
-
-    return INSIDE;
-}
-
-
-// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
-
-
-// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
-
-
-// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
-
-
-// ************************************************************************* //
diff --git a/src/meshTools/triSurface/searchableSurface/searchableBox.H b/src/meshTools/triSurface/searchableSurface/searchableBox.H
deleted file mode 100644
index 4a347af46a9761629d4c2985392e0043320ce340..0000000000000000000000000000000000000000
--- a/src/meshTools/triSurface/searchableSurface/searchableBox.H
+++ /dev/null
@@ -1,161 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by the
-    Free Software Foundation; either version 2 of the License, or (at your
-    option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM; if not, write to the Free Software Foundation,
-    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-Class
-    Foam::searchableBox
-
-Description
-    Searching on bounding box
-
-SourceFiles
-    searchableBox.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef searchableBox_H
-#define searchableBox_H
-
-#include "searchableSurface.H"
-#include "treeBoundBox.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-// Forward declaration of classes
-
-/*---------------------------------------------------------------------------*\
-                           Class searchableBox Declaration
-\*---------------------------------------------------------------------------*/
-
-class searchableBox
-:
-    public searchableSurface,
-    public treeBoundBox
-{
-private:
-
-    // Private member data
-
-
-    // Private Member Functions
-
-        //- Disallow default bitwise copy construct
-        searchableBox(const searchableBox&);
-
-        //- Disallow default bitwise assignment
-        void operator=(const searchableBox&);
-
-
-public:
-
-    //- Runtime type information
-    TypeName("searchableBox");
-
-
-    // Constructors
-
-        //- Construct from components
-        searchableBox(const word& name, const treeBoundBox& bb);
-
-        searchableBox
-        (
-            const word& name,
-            const objectRegistry& obj,
-            const dictionary& dict
-        );
-
-    // Destructor
-
-        virtual ~searchableBox();
-
-
-    // Member Functions
-
-        //- Calculate nearest point on surface. Returns
-        //  - bool : any point found nearer than nearestDistSqr
-        //  - label: relevant index in surface
-        //  - point: actual nearest point found
-        virtual pointIndexHit findNearest
-        (
-            const point& sample,
-            const scalar nearestDistSqr
-        ) const;
-
-        //- Calculate nearest point on edge. Returns
-        //  - bool : any point found nearer than nearestDistSqr
-        //  - label: relevant index in surface
-        //  - point: actual nearest point found
-        virtual pointIndexHit findNearestOnEdge
-        (
-            const point& sample,
-            const scalar nearestDistSqr
-        ) const;
-
-        //- Find nearest to line. Returns
-        //  - bool : any point found?
-        //  - label: relevant index in shapes
-        //  - point: actual nearest point found
-        //  sets:
-        //  - tightest  : bounding box
-        //  - linePoint : corresponding nearest point on line
-        virtual pointIndexHit findNearest
-        (
-            const linePointRef& ln,
-            treeBoundBox& tightest,
-            point& linePoint
-        ) const;
-
-        //- Find nearest intersection of line between start and end.
-        virtual pointIndexHit findLine
-        (
-            const point& start,
-            const point& end
-        ) const;
-
-        //- Find any intersection of line between start and end.
-        virtual pointIndexHit findLineAny
-        (
-            const point& start,
-            const point& end
-        ) const;
-
-        //- Determine type (inside/outside/mixed) for point. unknown if
-        //  cannot be determined (e.g. non-manifold surface)
-        virtual volumeType getVolumeType(const point&) const;
-
-
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/src/meshTools/triSurface/searchableSurface/searchableSurface.H b/src/meshTools/triSurface/searchableSurface/searchableSurface.H
deleted file mode 100644
index 83f7aaf929cd706ce97ae11560f2804c346018bd..0000000000000000000000000000000000000000
--- a/src/meshTools/triSurface/searchableSurface/searchableSurface.H
+++ /dev/null
@@ -1,257 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by the
-    Free Software Foundation; either version 2 of the License, or (at your
-    option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM; if not, write to the Free Software Foundation,
-    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-Class
-    Foam::searchableSurface
-
-Description
-    Base class of (analytical or triangulated) surface.
-    Encapsulates all the search routines.
-
-SourceFiles
-    searchableSurface.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef searchableSurface_H
-#define searchableSurface_H
-
-#include "pointField.H"
-#include "typeInfo.H"
-#include "runTimeSelectionTables.H"
-#include "pointIndexHit.H"
-#include "linePointRef.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-// Forward declaration of classes
-class objectRegistry;
-class treeBoundBox;
-
-/*---------------------------------------------------------------------------*\
-                           Class searchableSurface Declaration
-\*---------------------------------------------------------------------------*/
-
-class searchableSurface
-{
-public:
-
-    // Data types
-
-        //- volume types
-        enum volumeType
-        {
-            UNKNOWN = 0,
-            MIXED = 1,
-            INSIDE = 2,
-            OUTSIDE = 3
-        };
-
-private:
-
-    // Private data
-
-        const word name_;
-
-
-    // Private Member Functions
-
-        //- Disallow default bitwise copy construct
-        searchableSurface(const searchableSurface&);
-
-        //- Disallow default bitwise assignment
-        void operator=(const searchableSurface&);
-
-
-public:
-
-    //- Runtime type information
-    TypeName("searchableSurface");
-
-    // Declare run-time constructor selection table
-
-        // For the dictionary constructor
-        declareRunTimeSelectionTable
-        (
-            autoPtr,
-            searchableSurface,
-            dict,
-            (
-                const word& name,
-                const objectRegistry& obj,
-                const dictionary& dict
-            ),
-            (name, obj, dict)
-        );
-
-        //// For the Istream constructor
-        //declareRunTimeSelectionTable
-        //(
-        //    autoPtr,
-        //    searchableSurface,
-        //    istream,
-        //    (
-        //        const objectRegistry& obj,
-        //        Istream& is
-        //    ),
-        //    (obj, is)
-        //);
-
-
-        //- Class used for the read-construction of
-        //  PtrLists of searchableSurface
-        class iNew
-        {
-            const objectRegistry& obj_;
-
-        public:
-
-            iNew(const objectRegistry& obj)
-            :
-                obj_(obj)
-            {}
-
-            autoPtr<searchableSurface> operator()(Istream& is) const
-            {
-                word surfaceType(is);
-                word name(is);
-                dictionary dict(is);
-                return searchableSurface::New(surfaceType, name, obj_, dict);
-            }
-        };
-
-
-    // Constructors
-
-        searchableSurface(const word& name);
-
-        //- Clone
-        virtual autoPtr<searchableSurface> clone() const
-        {
-            notImplemented("autoPtr<searchableSurface> clone() const");
-            return autoPtr<searchableSurface>(NULL);
-        }
-
-
-    // Selectors
-
-        //- Return a reference to the selected searchableSurface
-        static autoPtr<searchableSurface> New
-        (
-            const word& surfaceType,
-            const word& name,
-            const objectRegistry& obj,
-            const dictionary& dict
-        );
-
-        ////- Return a reference to the selected searchableSurface
-        //static autoPtr<searchableSurface> New
-        //(
-        //    const word& surfaceType,
-        //    const objectRegistry& obj,
-        //    Istream& is
-        //);
-
-
-    // Destructor
-
-        virtual ~searchableSurface();
-
-
-    // Member Functions
-
-        //- Return name
-        const word& name() const
-        {
-            return name_;
-        }
-
-        //- Calculate nearest point on surface. Returns
-        //  - bool : any point found nearer than nearestDistSqr
-        //  - label: relevant index in surface
-        //  - point: actual nearest point found
-        virtual pointIndexHit findNearest
-        (
-            const point& sample,
-            const scalar nearestDistSqr
-        ) const = 0;
-
-        //- Calculate nearest point on edge. Returns
-        //  - bool : any point found nearer than nearestDistSqr
-        //  - label: relevant index in surface
-        //  - point: actual nearest point found
-        virtual pointIndexHit findNearestOnEdge
-        (
-            const point& sample,
-            const scalar nearestDistSqr
-        ) const = 0;
-
-        //- Find nearest to segment. Returns
-        //  - bool : any point found?
-        //  - label: relevant index in shapes
-        //  - point: actual nearest point found
-        //  sets:
-        //  - tightest  : bounding box
-        //  - linePoint : corresponding nearest point on line
-        virtual pointIndexHit findNearest
-        (
-            const linePointRef& ln,
-            treeBoundBox& tightest,
-            point& linePoint
-        ) const = 0;
-
-        //- Find nearest intersection of line between start and end.
-        virtual pointIndexHit findLine
-        (
-            const point& start,
-            const point& end
-        ) const = 0;
-
-        //- Find any intersection of line between start and end.
-        virtual pointIndexHit findLineAny
-        (
-            const point& start,
-            const point& end
-        ) const = 0;
-
-        //- Determine type (inside/outside/mixed) for point. unknown if
-        //  cannot be determined (e.g. non-manifold surface)
-        virtual volumeType getVolumeType(const point&) const = 0;
-
-
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/src/meshTools/triSurface/searchableSurface/triSurfaceMesh.C b/src/meshTools/triSurface/searchableSurface/triSurfaceMesh.C
deleted file mode 100644
index ec17352f99c0b27c3edaad00648b2b8eb290ac41..0000000000000000000000000000000000000000
--- a/src/meshTools/triSurface/searchableSurface/triSurfaceMesh.C
+++ /dev/null
@@ -1,271 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by the
-    Free Software Foundation; either version 2 of the License, or (at your
-    option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM; if not, write to the Free Software Foundation,
-    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-\*---------------------------------------------------------------------------*/
-
-#include "triSurfaceMesh.H"
-#include "Random.H"
-#include "addToRunTimeSelectionTable.H"
-
-// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-defineTypeNameAndDebug(triSurfaceMesh, 0);
-addToRunTimeSelectionTable(searchableSurface, triSurfaceMesh, dict);
-
-}
-
-// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
-
-//- Check file existence
-const Foam::fileName& Foam::triSurfaceMesh::checkFile
-(
-    const fileName& fName,
-    const fileName& objectName
-)
-{
-    if (fName == fileName::null)
-    {
-        FatalErrorIn
-        (
-            "triSurfaceMesh::checkFile(const fileName&, const fileName&)"
-        )   << "Cannot find triSurfaceMesh starting from "
-            << objectName << exit(FatalError);
-    }
-    return fName;
-}
-
-
-const Foam::indexedOctree<Foam::treeDataTriSurface>&
-    Foam::triSurfaceMesh::tree() const
-{
-    if (!tree_.valid())
-    {
-        treeBoundBox bb(points(), meshPoints());
-
-        // Random number generator. Bit dodgy since not exactly random ;-)
-        Random rndGen(65431);
-
-        tree_.reset
-        (
-            new indexedOctree<treeDataTriSurface>
-            (
-                treeDataTriSurface(*this),
-                bb.extend(rndGen, 1E-3),    // slightly randomize bb
-                8,      // maxLevel
-                10,     // leafsize
-                3.0     // duplicity
-            )
-        );
-    }
-
-    return tree_();
-}
-
-
-const Foam::indexedOctree<Foam::treeDataEdge>&
-    Foam::triSurfaceMesh::edgeTree() const
-{
-    if (!edgeTree_.valid())
-    {
-        treeBoundBox bb(localPoints());
-
-        // Boundary edges
-        labelList bEdges
-        (
-            identity
-            (
-                nEdges()
-               -nInternalEdges()
-            )
-          + nInternalEdges()
-        );
-
-        // Random number generator. Bit dodgy since not exactly random ;-)
-        Random rndGen(65431);
-
-        edgeTree_.reset
-        (
-            new indexedOctree<treeDataEdge>
-            (
-                treeDataEdge
-                (
-                    false,          // cachebb
-                    edges(),        // edges
-                    localPoints(),  // points
-                    bEdges          // selected edges
-                ),
-                bb.extend(rndGen, 1E-3),    // slightly randomize bb
-                8,      // maxLevel
-                10,     // leafsize
-                3.0     // duplicity
-            )
-        );
-    }
-    return edgeTree_();
-}
-
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-//- Construct from triangles, patches, points.
-Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io, const triSurface& s)
-:
-    searchableSurface(io.name()),
-    objectRegistry(io),
-    triSurface(s)
-{}
-
-
-Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io)
-:
-    searchableSurface(io.name()),
-    objectRegistry(io),
-    triSurface(checkFile(filePath(), objectPath()))
-{}
-
-
-Foam::triSurfaceMesh::triSurfaceMesh
-(
-    const word& name,
-    const objectRegistry& obj,
-    const dictionary& dict
-)
-:
-    searchableSurface(name),
-    objectRegistry
-    (
-        IOobject
-        (
-            name,
-            "constant",
-            "triSurface",
-            obj,
-            IOobject::MUST_READ,
-            IOobject::NO_WRITE
-        )
-    ),
-    triSurface(checkFile(filePath(), objectPath()))
-{}
-
-
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::triSurfaceMesh::~triSurfaceMesh()
-{}
-
-
-void Foam::triSurfaceMesh::clearOut()
-{
-    tree_.clear();
-    edgeTree_.clear();
-    triSurface::clearOut();
-}
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-void Foam::triSurfaceMesh::movePoints(const pointField& newPoints)
-{
-    tree_.clear();
-    edgeTree_.clear();
-    triSurface::movePoints(newPoints);    
-}
-
-
-Foam::pointIndexHit Foam::triSurfaceMesh::findNearest
-(
-    const point& sample,
-    const scalar nearestDistSqr
-) const
-{
-    return tree().findNearest(sample, nearestDistSqr);
-}
-
-
-Foam::pointIndexHit Foam::triSurfaceMesh::findNearestOnEdge
-(
-    const point& sample,
-    const scalar nearestDistSqr
-) const
-{
-    return edgeTree().findNearest(sample, nearestDistSqr);
-}
-
-
-Foam::pointIndexHit Foam::triSurfaceMesh::findNearest
-(
-    const linePointRef& ln,
-    treeBoundBox& tightest,
-    point& linePoint
-) const
-{
-    return tree().findNearest(ln, tightest, linePoint);
-}
-
-
-Foam::pointIndexHit Foam::triSurfaceMesh::findLine
-(
-    const point& start,
-    const point& end
-) const
-{
-    return tree().findLine(start, end);
-}
-
-
-Foam::pointIndexHit Foam::triSurfaceMesh::findLineAny
-(
-    const point& start,
-    const point& end
-) const
-{
-    return tree().findLineAny(start, end);
-}
-
-
-Foam::searchableSurface::volumeType
- Foam::triSurfaceMesh::getVolumeType
-(
-    const point& pt
-) const
-{
-    // - use cached volume type per each tree node
-    // - cheat conversion since same values
-    return static_cast<volumeType>(tree().getVolumeType(pt));
-}
-
-
-// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
-
-
-// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
-
-
-// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
-
-
-// ************************************************************************* //
diff --git a/src/meshTools/triSurface/triSurfaceMeshes/triSurfaceMeshes.C b/src/meshTools/triSurface/triSurfaceMeshes/triSurfaceMeshes.C
deleted file mode 100644
index e96c61885437063e78de33697f102120c08673fc..0000000000000000000000000000000000000000
--- a/src/meshTools/triSurface/triSurfaceMeshes/triSurfaceMeshes.C
+++ /dev/null
@@ -1,916 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by the
-    Free Software Foundation; either version 2 of the License, or (at your
-    option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM; if not, write to the Free Software Foundation,
-    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-\*----------------------------------------------------------------------------*/
-
-#include "triSurfaceMeshes.H"
-#include "Random.H"
-#include "Time.H"
-#include "SortableList.H"
-#include "IOmanip.H"
-#include "plane.H"
-#include "SortableList.H"
-#include "triSurfaceTools.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-defineTypeNameAndDebug(triSurfaceMeshes, 0);
-
-}
-
-
-// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
-
-// Calculate sum of distance to surfaces.
-Foam::scalar Foam::triSurfaceMeshes::sumDistSqr
-(
-    const labelList& surfacesToTest,
-    const scalar initDistSqr,
-    const point& pt
-) const
-{
-    scalar sum = 0;
-
-    forAll(surfacesToTest, i)
-    {
-        label surfI = surfacesToTest[i];
-
-        pointIndexHit hit(operator[](surfI).findNearest(pt, initDistSqr));
-
-        // Note: make it fall over if not hit.
-        sum += magSqr(hit.hitPoint()-pt);
-    }
-    return sum;
-}
-
-
-// Reflects the point furthest away around the triangle centre by a factor fac.
-// (triangle centre is the average of all points but the ihi. pSum is running
-//  sum of all points)
-Foam::scalar Foam::triSurfaceMeshes::tryMorphTet
-(
-    const labelList& surfacesToTest,
-    const scalar initDistSqr,
-    List<vector>& p,
-    List<scalar>& y,
-    vector& pSum,
-    const label ihi,
-    const scalar fac
-) const
-{
-    scalar fac1 = (1.0-fac)/vector::nComponents;
-    scalar fac2 = fac1-fac;
-
-    vector ptry = pSum*fac1-p[ihi]*fac2;
-
-    scalar ytry = sumDistSqr(surfacesToTest, initDistSqr, ptry);
-
-    if (ytry < y[ihi])
-    {
-        y[ihi] = ytry;
-        pSum += ptry - p[ihi];
-        p[ihi] = ptry;
-    }
-    return ytry;
-}
-
-
-bool Foam::triSurfaceMeshes::morphTet
-(
-    const labelList& surfacesToTest,
-    const scalar initDistSqr,
-    const scalar convergenceDistSqr,
-    const label maxIter,
-    List<vector>& p,
-    List<scalar>& y
-) const
-{
-    vector pSum = sum(p);
-
-    autoPtr<OFstream> str;
-    label vertI = 0;
-    if (debug)
-    {
-        Pout<< "triSurfaceMeshes::morphTet : intersection of "
-            << IndirectList<fileName>(names(), surfacesToTest)()
-            << " starting from points:" << p << endl;
-        str.reset(new OFstream("track.obj"));
-        meshTools::writeOBJ(str(), p[0]);
-        vertI++;
-    }
-
-    for (label iter = 0; iter < maxIter; iter++)
-    {
-        // Get the indices of highest, second-highest and lowest values.
-        label ihi, inhi, ilo;
-        {
-            SortableList<scalar> sortedY(y);
-            ilo = sortedY.indices()[0];
-            ihi = sortedY.indices()[sortedY.size()-1];
-            inhi = sortedY.indices()[sortedY.size()-2];
-        }
-
-        if (debug)
-        {
-            Pout<< "Iteration:" << iter
-                << " lowest:" << y[ilo] << " highest:" << y[ihi]
-                << " points:" << p << endl;
-
-            meshTools::writeOBJ(str(), p[ilo]);
-            vertI++;
-            str()<< "l " << vertI-1 << ' ' << vertI << nl;
-        }
-
-        if (y[ihi] < convergenceDistSqr)
-        {
-            // Get point on 0th surface.
-            Swap(p[0], p[ilo]);
-            Swap(y[0], y[ilo]);
-            return true;
-        }
-
-        // Reflection: point furthest away gets reflected.
-        scalar ytry = tryMorphTet
-        (
-            surfacesToTest,
-            10*y[ihi],             // search box.
-            p,
-            y,
-            pSum,
-            ihi,
-            -1.0
-        );
-
-        if (ytry <= y[ilo])
-        {
-            // If in right direction (y lower) expand by two.
-            ytry = tryMorphTet(surfacesToTest, 10*y[ihi], p, y, pSum, ihi, 2.0);
-        }
-        else if (ytry >= y[inhi])
-        {
-            // If inside tet try contraction.
-
-            scalar ysave = y[ihi];
-
-            ytry = tryMorphTet(surfacesToTest, 10*y[ihi], p, y, pSum, ihi, 0.5);
-
-            if (ytry >= ysave)
-            {
-                // Contract around lowest point.
-                forAll(p, i)
-                {
-                    if (i != ilo)
-                    {
-                        p[i] = 0.5*(p[i] + p[ilo]);
-                        y[i] = sumDistSqr(surfacesToTest, y[ihi], p[i]);
-                    }
-                }
-                pSum = sum(p);
-            }
-        }
-    }
-
-    if (debug)
-    {
-        meshTools::writeOBJ(str(), p[0]);
-        vertI++;
-        str()<< "l " << vertI-1 << ' ' << vertI << nl;
-    }
-
-    // Failure to converge. Return best guess so far.
-    label ilo = findMin(y);
-    Swap(p[0], p[ilo]);
-    Swap(y[0], y[ilo]);
-    return false;
-}
-
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-// Construct from components
-Foam::triSurfaceMeshes::triSurfaceMeshes
-(
-    const IOobject& io,
-    const fileNameList& names
-)
-:
-    PtrList<triSurfaceMesh>(names.size()),
-    allSurfaces_(identity(names.size()))
-{
-    forAll(names, i)
-    {
-        autoPtr<IOobject> surfaceIO = io.clone();
-        surfaceIO().rename(names[i]);
-
-        Info<< "Loading surface " << surfaceIO().name() << endl;
-
-        //fileName fullPath = surfaceIO().filePath();
-        //
-        //if (fullPath.size() == 0)
-        //{
-        //    FatalErrorIn
-        //    (
-        //        "triSurfaceMeshes::triSurfaceMeshes"
-        //        "(const IOobject&, const fileNameList&)"
-        //    )   << "Cannot load surface " << surfaceIO().name()
-        //        << " starting from path " << surfaceIO().path()
-        //        << exit(FatalError);
-        //}
-
-        set(i, new triSurfaceMesh(surfaceIO()));
-
-        if (Pstream::master())
-        {
-            string oldPrefix(Pout.prefix());
-            Pout.prefix() += "    ";
-            operator[](i).writeStats(Pout);
-            Pout.prefix() = oldPrefix;
-        }
-    }
-}
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-Foam::fileNameList Foam::triSurfaceMeshes::allNames(const IOobject& io)
-{
-    return readDir(io.path(), fileName::FILE);
-}
-
-
-Foam::fileNameList Foam::triSurfaceMeshes::names() const
-{
-    fileNameList surfNames(size());
-
-    forAll(surfNames, surfI)
-    {
-        surfNames[surfI] = operator[](surfI).IOobject::name();
-    }
-    return surfNames;
-}
-
-
-// Find any intersection
-Foam::label Foam::triSurfaceMeshes::findAnyIntersection
-(
-    const labelList& surfaces,
-    const point& start,
-    const point& end,
-    pointIndexHit& hitInfo
-) const
-{
-    forAll(surfaces, i)
-    {
-        label surfI = surfaces[i];
-
-        hitInfo = operator[](surfI).findLineAny(start, end);
-
-        if (hitInfo.hit())
-        {
-            return surfI;
-        }
-    }
-    return -1;
-}
-
-
-Foam::label Foam::triSurfaceMeshes::findAnyIntersection
-(
-    const point& start,
-    const point& end,
-    pointIndexHit& hitInfo
-) const
-{
-    return findAnyIntersection
-    (
-        allSurfaces_,
-        start,
-        end,
-        hitInfo
-    );
-}
-
-
-// Find intersections of edge nearest to both endpoints.
-void Foam::triSurfaceMeshes::findAllIntersections
-(
-    const labelList& surfaces,
-    const point& start,
-    const point& end,
-
-    labelList& surfacesIndex,
-    List<pointIndexHit>& surfaceHitInfo
-) const
-{
-    DynamicList<label> hitSurfaces(surfaces.size());
-    DynamicList<pointIndexHit> hitInfos(surfaces.size());
-    DynamicList<scalar> hitDistSqr(surfaces.size());
-
-    const vector dirVec(end-start);
-    const scalar magSqrDirVec(magSqr(dirVec));
-    const vector smallVec(Foam::sqrt(SMALL)*dirVec);
-
-    forAll(surfaces, i)
-    {
-        label surfI = surfaces[i];
-
-        // Current starting point of ray.
-        point pt = start;
-
-        while (true)
-        {
-            // See if any intersection between pt and end
-            pointIndexHit inter = operator[](surfI).findLine(pt, end);
-
-            if (!inter.hit())
-            {
-                break;
-            }
-            hitSurfaces.append(surfI);
-            hitInfos.append(inter);
-            hitDistSqr.append(magSqr(inter.hitPoint() - start));
-
-            pt = inter.hitPoint() + smallVec;
-
-            if (((pt-start)&dirVec) > magSqrDirVec)
-            {
-                // Adding smallVec has taken us beyond end
-                break;
-            }
-        }
-    }
-    surfacesIndex.setSize(hitSurfaces.size());
-    surfaceHitInfo.setSize(hitSurfaces.size());
-
-    if (hitSurfaces.size() > 0)
-    {
-        // Sort and transfer to arguments
-
-        hitSurfaces.shrink();
-        hitInfos.shrink();
-        hitDistSqr.shrink();
-
-        // Sort from start to end.
-        SortableList<scalar> sortedDist(hitDistSqr);
-
-        forAll(sortedDist.indices(), newPos)
-        {
-            label oldPos = sortedDist.indices()[newPos];
-            surfacesIndex[newPos] = hitSurfaces[oldPos];
-            surfaceHitInfo[newPos] = hitInfos[oldPos];
-        }
-    }
-}
-
-
-void Foam::triSurfaceMeshes::findAllIntersections
-(
-    const point& start,
-    const point& end,
-
-    labelList& surfacesIndex,
-    List<pointIndexHit>& surfaceHitInfo
-) const
-{
-    findAllIntersections
-    (
-        allSurfaces_,
-        start,
-        end,
-        surfacesIndex,
-        surfaceHitInfo
-    );
-}
-
-
-// Find intersections of edge nearest to both endpoints.
-void Foam::triSurfaceMeshes::findNearestIntersection
-(
-    const labelList& surfaces,
-    const point& start,
-    const point& end,
-
-    label& surface1,
-    pointIndexHit& hit1,
-    label& surface2,
-    pointIndexHit& hit2
-) const
-{
-    surface1 = -1;
-    // Initialize to endpoint
-    hit1 = pointIndexHit(false, end, -1);
-
-    forAll(surfaces, i)
-    {
-        label surfI = surfaces[i];
-
-        if (hit1.rawPoint() == start)
-        {
-            break;
-        }
-
-        // See if any intersection between start and current nearest
-        pointIndexHit inter = operator[](surfI).findLine
-        (
-            start,
-            hit1.rawPoint()
-        );
-
-        if (inter.hit())
-        {
-            hit1 = inter;
-            surface1 = surfI;
-        }
-    }
-
-
-    // Find the nearest intersection from end to start. Note that we initialize
-    // to the first intersection (if any).
-    surface2 = surface1;
-    hit2 = pointIndexHit(hit1);
-
-    if (hit1.hit())
-    {
-        // Test from the end side.
-        forAll(surfaces, i)
-        {
-            label surfI = surfaces[i];
-
-            if (hit2.rawPoint() == end)
-            {
-                break;
-            }
-
-            // See if any intersection between end and current nearest
-            pointIndexHit inter = operator[](surfI).findLine
-            (
-                end,
-                hit2.rawPoint()
-            );
-
-            if (inter.hit())
-            {
-                hit2 = inter;
-                surface2 = surfI;
-            }
-        }
-    }
-}
-
-
-void Foam::triSurfaceMeshes::findNearestIntersection
-(
-    const point& start,
-    const point& end,
-
-    label& surface1,
-    pointIndexHit& hit1,
-    label& surface2,
-    pointIndexHit& hit2
-) const
-{
-    findNearestIntersection
-    (
-        allSurfaces_,
-        start,
-        end,
-        surface1,
-        hit1,
-        surface2,
-        hit2
-    );
-}
-
-
-// Find nearest. Return -1 or nearest point
-Foam::label Foam::triSurfaceMeshes::findNearest
-(
-    const labelList& surfaces,
-    const point& pt,
-    const scalar nearestDistSqr,
-    pointIndexHit& nearestHit
-) const
-{
-    // nearest surface
-    label minSurface = -1;
-    scalar minDistSqr = Foam::sqr(GREAT);
-
-    forAll(surfaces, i)
-    {
-        label surfI = surfaces[i];
-
-        pointIndexHit hit
-        (
-            operator[](surfI).findNearest(pt, nearestDistSqr)
-        );
-
-        if (hit.hit())
-        {
-            scalar distSqr = magSqr(hit.hitPoint()-pt);
-
-            if (distSqr < minDistSqr)
-            {
-                minDistSqr = distSqr;
-                minSurface = surfI;
-                nearestHit = hit;
-            }
-        }
-    }
-
-    if (minSurface == -1)
-    {
-        // maxLevel unchanged. No interesting surface hit.
-        nearestHit.setMiss();
-    }
-
-    return minSurface;
-}
-
-
-// Find nearest. Return -1 or nearest point
-Foam::label Foam::triSurfaceMeshes::findNearest
-(
-    const point& pt,
-    const scalar nearestDistSqr,
-    pointIndexHit& nearestHit
-) const
-{
-    return findNearest
-    (
-        allSurfaces_,
-        pt,
-        nearestDistSqr,
-        nearestHit
-    );
-}
-
-
-Foam::label Foam::triSurfaceMeshes::findNearestAndClassify
-(
-    const labelList& surfacesToTest,
-    const point& pt,
-    const scalar nearestDistSqr,
-    surfaceLocation& nearest
-) const
-{
-    pointIndexHit nearestInfo;
-    label surfI = findNearest
-    (
-        surfacesToTest,
-        pt,
-        nearestDistSqr,
-        nearestInfo
-    );
-
-    if (surfI != -1)
-    {
-        nearest = triSurfaceTools::classify
-        (
-            operator[](surfI),
-            nearestInfo.index(),        // triangle
-            nearestInfo.rawPoint()      // point on edge/inside triangle
-        );
-    }
-
-    return surfI;
-}
-
-
-//- Calculate point which is on a set of surfaces.
-Foam::surfaceLocation Foam::triSurfaceMeshes::facesIntersectionTrack
-(
-    const labelList& surfacesToTest,
-    const scalar initialDistSqr,
-    const scalar convergenceDistSqr,
-    const point& start
-) const
-{
-    autoPtr<OFstream> str;
-    label vertI = 0;
-
-    if (debug)
-    {
-        str.reset(new OFstream("track.obj"));
-    }
-
-    surfaceLocation current
-    (
-        pointIndexHit
-        (
-            false,
-            start,
-            -1
-        ),
-        triPointRef::NONE,
-        -1
-    );
-
-    // Dump start point
-    if (str.valid())
-    {
-        Pout<< "Starting at " << current.info()
-            << " written as point " << vertI
-            << endl;
-        meshTools::writeOBJ(str(), current.rawPoint());
-        vertI++;
-    }
-
-    // Now slide current along all faces until it settles
-    label iter = 0;
-
-    const label maxIter = 10;
-
-    for (; iter < maxIter; iter++)
-    {
-        // - store old position
-        // - slide it along all faces
-        // - if it hasn't changed position exit loop
-
-        if (debug)
-        {
-            Pout<< endl
-                << "Iteration " << iter << endl
-                << "-----------" << endl;
-        }
-
-        point oldCurrent = current.rawPoint();
-
-        forAll(surfacesToTest, i)
-        {
-            label surfI = surfacesToTest[i];
-
-            // Project pt onto surf
-            // ~~~~~~~~~~~~~~~~~~~~
-            point copy(current.rawPoint()); // need to work on copy
-            if
-            (
-                findNearestAndClassify
-                (
-                    labelList(1, surfI),
-                    copy,
-                    initialDistSqr,             // initialDistSqr
-                    current
-                )
-             == -1
-            )
-            {
-                FatalErrorIn("triSurfaceMeshes::facesIntersectionTrack(..)")
-                    << "Did not find a point on surface " << surfI
-                    << " which is within sqrt(" << initialDistSqr
-                    << ") of " << copy
-                    << abort(FatalError);
-            }
-
-
-            if (debug)
-            {
-                Pout<< "Nearest onto surface " << surfI
-                    << ' ' << operator[](surfI).IOobject::name() << " : "
-                    << current.info() << " written as point " << vertI
-                    << endl;
-            }
-
-            // Dump current
-            if (str.valid())
-            {
-                meshTools::writeOBJ(str(), current.rawPoint());
-                vertI++;
-                str()<< "l " << vertI-1 << ' ' << vertI << nl;
-            }
-
-            // Find corresponding point on next surface
-            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-            label nextSurfI = surfacesToTest[surfacesToTest.fcIndex(i)];
-
-            surfaceLocation next;
-            findNearestAndClassify
-            (
-                labelList(1, nextSurfI),
-                point(current.rawPoint()),
-                initialDistSqr,                 // initialDistSqr
-                next
-            );
-
-            // Since next is on a different surface we cannot compare
-            // indices (like in snapToEnd) so make sure this does not
-            // happen.
-            next.elementType() = triPointRef::NONE;
-            next.setIndex(-123);
-
-            if (debug)
-            {
-                Pout<< "Nearest onto next surface " << nextSurfI
-                    << ' ' << operator[](nextSurfI).IOobject::name() << " : "
-                    << next.info() << endl;
-            }
-
-            if
-            (
-                magSqr(current.rawPoint() - next.rawPoint())
-              > convergenceDistSqr
-            )
-            {
-                // Track from current to next
-                // ~~~~~~~~~~~~~~~~~~~~~~~~~~
-                //vector n = current.normal(surfaces[surfI]);
-
-                current = triSurfaceTools::trackToEdge
-                (
-                    operator[](surfI),
-                    current,
-                    next,
-                    plane(start, current.rawPoint(), next.rawPoint())
-                );
-
-                if (debug)
-                {
-                    Pout<< "Sliding along surface "
-                        << surfI << ' ' << operator[](surfI).IOobject::name()
-                        << " in direction of "
-                        << nextSurfI << ' '
-                        << operator[](nextSurfI).IOobject::name()
-                        << " stopped at " << current.info()
-                        << " written as point " << vertI << endl;
-                }
-                if (str.valid())
-                {
-                    meshTools::writeOBJ(str(), current.rawPoint());
-                    vertI++;
-                    str()<< "l " << vertI-1 << ' ' << vertI << nl;
-                }
-            }
-        }
-
-        scalar distSqr = magSqr(oldCurrent - current.rawPoint());
-
-        if (debug)
-        {
-            Pout<< "distSqr:" << distSqr
-                << " convergenceDistSqr:" << convergenceDistSqr << endl;
-        }
-
-        if (distSqr < convergenceDistSqr)
-        {
-            break;
-        }
-    }
-
-    if (iter == maxIter)
-    {
-        FatalErrorIn("triSurfaceMeshes::facesIntersectionTrack(..)")
-            << "Did not converge in " << iter
-            << " iterations to find a point which is on surfaces "
-            << IndirectList<fileName>(names(), surfacesToTest)() << nl
-            << "Start point:" << start << nl
-            << "Current nearest:" << current.info() << nl
-            << "Please check that your surfaces actually intersect and"
-            << " that the starting point is close to the intersection point."
-            << abort(FatalError);
-    }
-
-    return current;
-}
-
-
-//- Calculate point which is on a set of surfaces.
-Foam::pointIndexHit Foam::triSurfaceMeshes::facesIntersection
-(
-    const labelList& surfacesToTest,
-    const scalar initDistSqr,
-    const scalar convergenceDistSqr,
-    const point& start
-) const
-{
-    // Get four starting points. Take these as the projection of the
-    // starting point onto the surfaces and the mid point
-    List<point> nearest(surfacesToTest.size()+1);
-
-    point sumNearest = vector::zero;
-
-    forAll(surfacesToTest, i)
-    {
-        label surfI = surfacesToTest[i];
-
-        pointIndexHit hit
-        (
-            operator[](surfI).findNearest(start, initDistSqr)
-        );
-
-        if (hit.hit())
-        {
-            nearest[i] = hit.hitPoint();
-            sumNearest += nearest[i];
-        }
-        else
-        {
-            FatalErrorIn
-            (
-                "triSurfaceMeshes::facesIntersection"
-                "(const labelList&, const scalar, const scalar, const point&)"
-            )   << "Did not find point within distance "
-                << initDistSqr << " of starting point " << start
-                << " on surface " << operator[](surfI).IOobject::name()
-                << abort(FatalError);
-        }
-    }
-
-    nearest[nearest.size()-1] = sumNearest / surfacesToTest.size();
-
-
-    // Get the sum of distances (initial evaluation)
-    List<scalar> nearestDist(nearest.size());
-
-    forAll(nearestDist, i)
-    {
-        nearestDist[i] = sumDistSqr(surfacesToTest, initDistSqr, nearest[i]);
-    }
-
-
-    //- Downhill Simplex method
-
-    bool converged = morphTet
-    (
-        surfacesToTest,
-        initDistSqr,
-        convergenceDistSqr,
-        2000,
-        nearest,
-        nearestDist
-    );
-
-
-    pointIndexHit intersection;
-
-    if (converged)
-    {
-        // Project nearest onto 0th surface.
-        intersection = operator[](surfacesToTest[0]).findNearest
-        (
-            nearest[0],
-            nearestDist[0]
-        );
-    }
-
-    //if (!intersection.hit())
-    //{
-    //    // Restart
-    //    scalar smallDist = Foam::sqr(convergenceDistSqr);
-    //    nearest[0] = intersection.hitPoint();
-    //    nearest[1] = nearest[0];
-    //    nearest[1].x() += smallDist;
-    //    nearest[2] = nearest[0];
-    //    nearest[2].y() += smallDist;
-    //    nearest[3] = nearest[0];
-    //    nearest[3].z() += smallDist;
-    //
-    //    forAll(nearestDist, i)
-    //    {
-    //        nearestDist[i] = sumDistSqr
-    //        (
-    //            surfacesToTest,
-    //            initDistSqr,
-    //            nearest[i]
-    //        );
-    //    }
-    //
-    //    intersection = morphTet
-    //    (
-    //        surfacesToTest,
-    //        initDistSqr,
-    //        convergenceDistSqr,
-    //        1000,
-    //        nearest,
-    //        nearestDist
-    //    );
-    //}
-
-    return intersection;
-}
-
-
-
-// ************************************************************************* //
diff --git a/src/meshTools/triSurface/triSurfaceMeshes/triSurfaceMeshes.H b/src/meshTools/triSurface/triSurfaceMeshes/triSurfaceMeshes.H
deleted file mode 100644
index 4269dba6a7bb4593adb7bc39d009e7d4fde7a38b..0000000000000000000000000000000000000000
--- a/src/meshTools/triSurface/triSurfaceMeshes/triSurfaceMeshes.H
+++ /dev/null
@@ -1,261 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by the
-    Free Software Foundation; either version 2 of the License, or (at your
-    option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM; if not, write to the Free Software Foundation,
-    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-Class
-    Foam::triSurfaceMeshes
-
-Description
-    Container for triSurfaces read from files.
-
-SourceFiles
-    triSurfaceMeshes.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef triSurfaceMeshes_H
-#define triSurfaceMeshes_H
-
-#include "triSurfaceMesh.H"
-#include "fileNameList.H"
-#include "treeDataTriSurface.H"
-#include "indexedOctree.H"
-#include "surfaceLocation.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-// Forward declaration of classes
-class plane;
-
-/*---------------------------------------------------------------------------*\
-                           Class triSurfaceMeshes Declaration
-\*---------------------------------------------------------------------------*/
-
-class triSurfaceMeshes
-:
-    public PtrList<triSurfaceMesh>
-{
-    // Private data
-
-        //- Indices of all surfaces. Precalculated and stored.
-        const labelList allSurfaces_;
-
-
-    // Private Member Functions
-
-        //- Calculate sum of distances to nearest point on surfaces. Is used
-        //  in minimisation to find intersection. Returns sum of (square of)
-        // distances to the surfaces.
-        scalar sumDistSqr
-        (
-            const labelList& surfacesToTest,
-            const scalar initialDistSqr,    // search box
-            const point& pt
-        ) const;
-
-        //- Takes the tet (points p) and reflects the point with the
-        //  highest value around the centre (pSum). Checks if it gets closer
-        //  and updates p, y if so.
-        scalar tryMorphTet
-        (
-            const labelList& surfacesToTest,
-            const scalar initialDistSqr,
-            List<vector>& p,
-            List<scalar>& y,
-            vector& pSum,
-            const label ihi,
-            const scalar fac
-        ) const;
-
-        //- Downhill simplex method: find the point with min cumulative
-        //  distance to all surfaces. Does so by morphing a tet (points p).
-        //  Returns the point on the 0th surface or hit if not reached within
-        //  maxIters iterations.
-        bool morphTet
-        (
-            const labelList& surfacesToTest,
-            const scalar initialDistSqr,
-            const scalar convergenceDistSqr,
-            const label maxIter,
-            List<vector>& p,
-            List<scalar>& y
-        ) const;
-
-        //- Disallow default bitwise copy construct
-        triSurfaceMeshes(const triSurfaceMeshes&);
-
-        //- Disallow default bitwise assignment
-        void operator=(const triSurfaceMeshes&);
-
-
-public:
-
-    ClassName("triSurfaceMeshes");
-
-    // Constructors
-
-        //- Construct from directory (io.instance()) and list of local filenames
-        triSurfaceMeshes(const IOobject& io, const fileNameList&);
-
-
-    // Member Functions
-
-        //- Get all surfaces in directory
-        static fileNameList allNames(const IOobject&);
-
-        //- Get names of surfaces
-        fileNameList names() const;
-
-
-        //- Find any intersection. Return hit point information and surface
-        //  number
-        label findAnyIntersection
-        (
-            const labelList& surfacesToTest,
-            const point& start,
-            const point& end,
-            pointIndexHit&
-        ) const;
-
-        label findAnyIntersection
-        (
-            const point& start,
-            const point& end,
-            pointIndexHit&
-        ) const;
-
-
-        //- Find all intersections in order from start to end. Returns for
-        //  every hit the surface and the hit info.
-        void findAllIntersections
-        (
-            const labelList& surfacesToTest,
-            const point& start,
-            const point& end,
-            labelList& surfaces,
-            List<pointIndexHit>& surfaceHits
-        ) const;
-
-        void findAllIntersections
-        (
-            const point& start,
-            const point& end,
-            labelList& surfaces,
-            List<pointIndexHit>& surfaceHits
-        ) const;
-
-
-        //- Find intersections of edge nearest to both endpoints.
-        void findNearestIntersection
-        (
-            const labelList& surfacesToTest,
-            const point& start,
-            const point& end,
-
-            label& surface1,        // surface index
-            pointIndexHit& hit1,    // hit point information
-            label& surface2,
-            pointIndexHit& hit2
-        ) const;
-
-        void findNearestIntersection
-        (
-            const point& start,
-            const point& end,
-
-            label& surface1,        // surface index
-            pointIndexHit& hit1,    // hit point information
-            label& surface2,
-            pointIndexHit& hit2
-        ) const;
-
-
-        //- Find nearest. Return -1 (and a miss()) or surface and nearest point.
-        label findNearest
-        (
-            const labelList& surfacesToTest,
-            const point&,
-            const scalar nearestDistSqr,
-            pointIndexHit&
-        ) const;
-
-        label findNearest
-        (
-            const point&,
-            const scalar nearestDistSqr,
-            pointIndexHit&
-        ) const;
-
-
-        //- Find nearest point (like findNearest) but also return whether
-        //  point is on edge or on point. Returns -1 if not found
-        //  (within nearestDistSqr) on any of the surfaces.
-        //  Returns surfaceLocation
-        //  - hit : nearest point is inside triangle
-        //  - elementType : none, edge  or point
-        //  - index       : triI, edgeI or localPointI
-        label findNearestAndClassify
-        (
-            const labelList& surfacesToTest,
-            const point& pt,
-            const scalar nearestDistSqr,
-            surfaceLocation& nearest
-        ) const;
-
-        //- Calculate point which is on a set of surfaces. Takes
-        //  - initialDistSqr : search dimensions to find point on surface
-        //  - convergenceDistSqr : when point is converged
-        // Will bomb out if no stable point reached after certain number
-        // of iterations.
-        surfaceLocation facesIntersectionTrack
-        (
-            const labelList& surfacesToTest,
-            const scalar initialDistSqr,
-            const scalar convergenceDistSqr,
-            const point& start
-        ) const;
-
-        //- Calculate point which is on a set of surfaces.
-        pointIndexHit facesIntersection
-        (
-            const labelList& surfacesToTest,
-            const scalar initialDistSqr,
-            const scalar convergenceDistSqr,
-            const point& start
-        ) const;
-
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //