diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C
index e8c2915f1388ac6adb33308df8383e528cec41a3..beba23a4da5f01e3bcfa84cf953ced9e9d43a3da 100644
--- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C
+++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C
@@ -58,6 +58,7 @@ Description
 #include "globalIndex.H"
 #include "IOmanip.H"
 #include "decompositionModel.H"
+#include "fvMeshTools.H"
 
 using namespace Foam;
 
@@ -813,6 +814,7 @@ int main(int argc, char *argv[])
         readScalar(meshDict.lookup("mergeTolerance"))
     );
 
+    const Switch keepPatches(meshDict.lookupOrDefault("keepPatches", false));
 
 
     // Read decomposePar dictionary
@@ -1517,6 +1519,12 @@ int main(int argc, char *argv[])
             motionDict
         );
 
+        // Remove zero sized patches originating from faceZones
+        if (!keepPatches && !wantSnap && !wantLayers)
+        {
+            fvMeshTools::removeEmptyPatches(mesh, true);
+        }
+
         writeMesh
         (
             "Refined mesh",
@@ -1559,6 +1567,12 @@ int main(int argc, char *argv[])
             snapParams
         );
 
+        // Remove zero sized patches originating from faceZones
+        if (!keepPatches && !wantLayers)
+        {
+            fvMeshTools::removeEmptyPatches(mesh, true);
+        }
+
         writeMesh
         (
             "Snapped mesh",
@@ -1609,6 +1623,12 @@ int main(int argc, char *argv[])
             distributor
         );
 
+        // Remove zero sized patches originating from faceZones
+        if (!keepPatches)
+        {
+            fvMeshTools::removeEmptyPatches(mesh, true);
+        }
+
         writeMesh
         (
             "Layer mesh",
@@ -1622,6 +1642,7 @@ int main(int argc, char *argv[])
     }
 
 
+
     {
         // Check final mesh
         Info<< "Checking final mesh ..." << endl;
diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict
index 5a8508d151ec16293278ecca79cabe0339d42515..506a68786b9c4a4b55d7dff724397196dffca076 100644
--- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict
+++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict
@@ -296,8 +296,18 @@ castellatedMeshControls
         locationInMesh (5 0.28 0.43);
 
         // Whether any faceZones (as specified in the refinementSurfaces)
-        // are only on the boundary of corresponding cellZones or also allow
-        // free-standing zone faces. Not used if there are no faceZones.
+        // are only on the boundary of corresponding cellZones.
+        // Not used if there are no faceZones. The behaviour has changed
+        // with respect to previous versions:
+        //  true  : all intersections with surface are put in faceZone
+        //          (same behaviour as before)
+        //  false : depending on the type of surface intersected:
+        //      - if intersecting surface has faceZone only (so no cellZone)
+        //        leave in faceZone (so behave as if set to true) (= changed
+        //        behaviour)
+        //      - if intersecting surface has faceZone and cellZone
+        //        remove if inbetween same cellZone or if on boundary
+        //        (same behaviour as before)
         allowFreeStandingZoneFaces true;
 
 
diff --git a/src/dynamicMesh/fvMeshTools/fvMeshTools.C b/src/dynamicMesh/fvMeshTools/fvMeshTools.C
index ecbe00325d73bcf6032465a864b8f973195d4b3d..df8aaccdb4b027bd179017e8ec72207606cfd8b8 100644
--- a/src/dynamicMesh/fvMeshTools/fvMeshTools.C
+++ b/src/dynamicMesh/fvMeshTools/fvMeshTools.C
@@ -355,6 +355,69 @@ void Foam::fvMeshTools::reorderPatches
 }
 
 
+Foam::labelList Foam::fvMeshTools::removeEmptyPatches
+(
+    fvMesh& mesh,
+    const bool validBoundary
+)
+{
+    const polyBoundaryMesh& pbm = mesh.boundaryMesh();
+
+    labelList newToOld(pbm.size());
+    labelList oldToNew(pbm.size(), -1);
+    label newI = 0;
+
+
+    // Assumes all non-coupled boundaries are on all processors!
+    forAll(pbm, patchI)
+    {
+        const polyPatch& pp = pbm[patchI];
+
+        if (!isA<processorPolyPatch>(pp))
+        {
+            label nFaces = pp.size();
+            if (validBoundary)
+            {
+                reduce(nFaces, sumOp<label>());
+            }
+
+            if (nFaces > 0)
+            {
+                newToOld[newI] = patchI;
+                oldToNew[patchI] = newI++;
+            }
+        }
+    }
+
+    // Same for processor patches (but need no reduction)
+    forAll(pbm, patchI)
+    {
+        const polyPatch& pp = pbm[patchI];
+
+        if (isA<processorPolyPatch>(pp) && pp.size())
+        {
+            newToOld[newI] = patchI;
+            oldToNew[patchI] = newI++;
+        }
+    }
+
+    newToOld.setSize(newI);
+
+    // Move all deleteable patches to the end
+    forAll(oldToNew, patchI)
+    {
+        if (oldToNew[patchI] == -1)
+        {
+            oldToNew[patchI] = newI++;
+        }
+    }
+
+    reorderPatches(mesh, oldToNew, newToOld.size(), validBoundary);
+
+    return newToOld;
+}
+
+
 Foam::autoPtr<Foam::fvMesh> Foam::fvMeshTools::newMesh
 (
     const IOobject& io,
diff --git a/src/dynamicMesh/fvMeshTools/fvMeshTools.H b/src/dynamicMesh/fvMeshTools/fvMeshTools.H
index e458425d0b2870db96ece3e047c1b27a1e4a871f..37b368961c52ff790a4615c05e070cbf14465110 100644
--- a/src/dynamicMesh/fvMeshTools/fvMeshTools.H
+++ b/src/dynamicMesh/fvMeshTools/fvMeshTools.H
@@ -113,7 +113,7 @@ public:
     static void zeroPatchFields(fvMesh& mesh, const label patchI);
 
     //- Reorder and remove trailing patches. If validBoundary call is parallel
-    //  synced and all add the same patch with same settings
+    //  synced
     static void reorderPatches
     (
         fvMesh&,
@@ -122,6 +122,11 @@ public:
         const bool validBoundary
     );
 
+    //- Remove zero sized patches. All but processor patches are
+    //  assumed to be present on all processors (so size will be reduced
+    //  if validBoundary). Return map from new
+    //  to old patches
+    static labelList removeEmptyPatches(fvMesh&, const bool validBoundary);
 
     //- Read mesh or create dummy mesh (0 cells, >0 patches). Works in two
     //  modes according to masterOnlyReading:
@@ -133,7 +138,6 @@ public:
         const IOobject& io,
         const bool masterOnlyReading
     );
-
 };
 
 
diff --git a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.C b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.C
index f5bfcc5f7524e887ea04fe855481dce91a56614d..0a93e1e4a8a69ce9f235dd7fb0bd726007335465 100644
--- a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.C
+++ b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/refinementParameters/refinementParameters.C
@@ -74,14 +74,7 @@ Foam::refinementParameters::refinementParameters(const dictionary& dict)
     if (dict.readIfPresent("locationInMesh", locationInMesh))
     {
         locationsInMesh_.append(locationInMesh);
-        zonesInMesh_.append("noneIfNotSet");// special name for no cellZone
-
-        if (dict.found("locationsInMesh"))
-        {
-            FatalIOErrorInFunction(dict)
-                << "Cannot both specify 'locationInMesh' and 'locationsInMesh'"
-                << exit(FatalIOError);
-        }
+        zonesInMesh_.append("none");    // special name for no cellZone
     }
 
     List<Tuple2<point, word> > pointsToZone;
@@ -95,6 +88,10 @@ Foam::refinementParameters::refinementParameters(const dictionary& dict)
         {
             locationsInMesh_[nZones] = pointsToZone[i].first();
             zonesInMesh_[nZones] = pointsToZone[i].second();
+            if (zonesInMesh_[nZones] == word::null)
+            {
+                zonesInMesh_[nZones] = "none";
+            }
             nZones++;
         }
     }
@@ -152,12 +149,7 @@ Foam::labelList Foam::refinementParameters::addCellZonesToMesh
     labelList zoneIDs(zonesInMesh_.size(), -1);
     forAll(zonesInMesh_, i)
     {
-        if
-        (
-            zonesInMesh_[i] != word::null
-         && zonesInMesh_[i] != "none"
-         && zonesInMesh_[i] != "noneIfNotSet"
-        )
+        if (zonesInMesh_[i] != word::null && zonesInMesh_[i] != "none")
         {
             zoneIDs[i] = surfaceZonesInfo::addCellZone
             (
@@ -242,8 +234,8 @@ Foam::labelList Foam::refinementParameters::zonedLocations
     {
         if
         (
-            zonesInMesh[i] == word::null
-        ||  zonesInMesh[i] != "noneIfNotSet"
+            zonesInMesh[i] != word::null
+         && zonesInMesh[i] != "none"
         )
         {
             indices.append(i);
@@ -264,8 +256,8 @@ Foam::labelList Foam::refinementParameters::unzonedLocations
     {
         if
         (
-            zonesInMesh[i] != word::null
-        &&  zonesInMesh[i] == "noneIfNotSet"
+            zonesInMesh[i] == word::null
+         || zonesInMesh[i] == "none"
         )
         {
             indices.append(i);
diff --git a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H
index 706a130b1539ce0f8e4fd4f4dd9a14f37565dfd5..9b375b1b89f4364f150f9327b344ab3646f5a65d 100644
--- a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H
+++ b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H
@@ -507,7 +507,6 @@ private:
             void getIntersections
             (
                 const labelList& surfacesToTest,
-                const labelList& neiLevel,
                 const pointField& neiCc,
                 const labelList& testFaces,
 
@@ -515,7 +514,19 @@ private:
                 labelList& globalRegion2
             ) const;
 
-            //- Determine patches for baffles on all intersected unnamed faces
+            //- Calculate intersections on zoned faces. Return per face -1
+            // or the index of the surface and the orientation w.r.t. surface
+            void getIntersections
+            (
+                const labelList& surfacesToTest,
+                const pointField& neiCc,
+                const labelList& testFaces,
+
+                labelList& namedSurfaceIndex,
+                PackedBoolList& posOrientation
+            ) const;
+
+            //- Determine patches for baffles
             void getBafflePatches
             (
                 const labelList& globalToMasterPatch,
@@ -635,13 +646,13 @@ private:
                 labelList& cellToZone
             ) const;
 
-            //- Finds zone per cell for cells inside named surfaces that have
-            //  an inside point specified.
+            //- Finds zone per cell for cells inside region for which name
+            //  is specified.
             void findCellZoneInsideWalk
             (
-                const labelList& locationSurfaces,
-                const labelList& namedSurfaceIndex,
-                const labelList& surfaceToCellZone,
+                const pointField& locationsInMesh,
+                const labelList& zonesInMesh,
+                const labelList& blockedFace, // per face -1 or some index >= 0
                 labelList& cellToZone
             ) const;
 
@@ -650,8 +661,8 @@ private:
             void findCellZoneInsideWalk
             (
                 const pointField& locationsInMesh,
-                const wordList& regionsInMesh,
-                const labelList& blockedFace, // per face -1 or some index >= 0
+                const wordList& zoneNamesInMesh,
+                const labelList& faceToZone, // per face -1 or some index >= 0
                 labelList& cellToZone
             ) const;
 
@@ -670,6 +681,7 @@ private:
             void findCellZoneTopo
             (
                 const pointField& locationsInMesh,
+                const labelList& allSurfaceIndex,
                 const labelList& namedSurfaceIndex,
                 const labelList& surfaceToCellZone,
                 labelList& cellToZone
@@ -679,10 +691,23 @@ private:
             //  - clear out any blocked faces inbetween same cell zone.
             void makeConsistentFaceIndex
             (
+                const labelList& zoneToNamedSurface,
                 const labelList& cellToZone,
                 labelList& namedSurfaceIndex
             ) const;
 
+            //- Calculate cellZone allocation
+            void zonify
+            (
+                const bool allowFreeStandingZoneFaces,
+                const pointField& locationsInMesh,
+                const wordList& zonesInMesh,
+
+                labelList& cellToZone,
+                labelList& namedSurfaceIndex,
+                PackedBoolList& posOrientation
+            ) const;
+
             //- Put cells into cellZone, faces into faceZone
             void zonify
             (
diff --git a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C
index 6fe484ac27c877787b19feeb9e348a4c8a41c4c2..7d350c4e683b2b16da68236192af67710c7be63d 100644
--- a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C
+++ b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C
@@ -51,6 +51,9 @@ License
 #include "IOmanip.H"
 #include "refinementParameters.H"
 
+#include "zeroGradientFvPatchFields.H"
+#include "volFields.H"
+
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 Foam::label Foam::meshRefinement::createBaffle
@@ -169,7 +172,6 @@ Foam::label Foam::meshRefinement::createBaffle
 void Foam::meshRefinement::getIntersections
 (
     const labelList& surfacesToTest,
-    const labelList& neiLevel,
     const pointField& neiCc,
     const labelList& testFaces,
 
@@ -211,7 +213,7 @@ void Foam::meshRefinement::getIntersections
         calcCellCellRays
         (
             neiCc,
-            neiLevel,
+            labelList(neiCc.size(), -1),
             testFaces,
             start,
             end,
@@ -222,6 +224,7 @@ void Foam::meshRefinement::getIntersections
 
     // Do test for intersections
     // ~~~~~~~~~~~~~~~~~~~~~~~~~
+
     labelList surface1;
     List<pointIndexHit> hit1;
     labelList region1;
@@ -290,136 +293,133 @@ void Foam::meshRefinement::getBafflePatches
     labelList& neiPatch
 ) const
 {
-    // Check all unnamed surfaces
+    // 1. Determine cell zones
+    // ~~~~~~~~~~~~~~~~~~~~~~~
+    // Note that this does not determine the surface that was intersected
+    // so that is done in step 2 below.
 
+    labelList cellToZone;
     {
-        const labelList testFaces(intersectedFaces());
-
-        labelList globalRegion1;
-        labelList globalRegion2;
-        getIntersections
+        labelList namedSurfaceIndex;
+        PackedBoolList posOrientation;
+        zonify
         (
-            surfaceZonesInfo::getUnnamedSurfaces(surfaces_.surfZones()),
-            neiLevel,
-            neiCc,
-            testFaces,
-            globalRegion1,
-            globalRegion2
+            true,               // allowFreeStandingZoneFaces
+            locationsInMesh,
+            zonesInMesh,
+
+            cellToZone,
+            namedSurfaceIndex,
+            posOrientation
         );
 
-        ownPatch.setSize(mesh_.nFaces());
-        ownPatch = -1;
-        neiPatch.setSize(mesh_.nFaces());
-        neiPatch = -1;
-        forAll(testFaces, i)
+
+        // Some stats
+        if (debug)
         {
-            label faceI = testFaces[i];
-            if (globalRegion1[faceI] != -1)
+            label nZones = gMax(cellToZone)+1;
+
+            label nUnvisited = 0;
+            label nBackgroundCells = 0;
+            labelList nZoneCells(nZones, 0);
+            forAll(cellToZone, cellI)
             {
-                ownPatch[faceI] = globalToMasterPatch[globalRegion1[faceI]];
+                label zoneI = cellToZone[cellI];
+                if (zoneI >= 0)
+                {
+                    nZoneCells[zoneI]++;
+                }
+                else if (zoneI == -1)
+                {
+                    nBackgroundCells++;
+                }
+                else if (zoneI == -2)
+                {
+                    nUnvisited++;
+                }
+                else
+                {
+                    FatalErrorIn("meshRefinement::getBafflePatches()")
+                        << "problem" << exit(FatalError);
+                }
             }
-            if (globalRegion2[faceI] != -1)
+            reduce(nUnvisited, sumOp<label>());
+            reduce(nBackgroundCells, sumOp<label>());
+            forAll(nZoneCells, zoneI)
             {
-                neiPatch[faceI] = globalToMasterPatch[globalRegion2[faceI]];
+                reduce(nZoneCells[zoneI], sumOp<label>());
             }
+            Info<< "nUnvisited      :" << nUnvisited << endl;
+            Info<< "nBackgroundCells:" << nBackgroundCells << endl;
+            Info<< "nZoneCells      :" << nZoneCells << endl;
         }
     }
 
 
-    if (locationsInMesh.size() > 1)
-    {
-        // Now we need to filter out any possible intersections between
-        // multiple regions. Only the faces on the outside of all
-        // regions are candidates for baffling.
-        // For this we need to go to per-cell information
-
-        labelList cellToZone(mesh_.nCells(), -2);
-
-
-        // Closed surfaces with cellZone specified.
-        const labelList closedNamedSurfaces
-        (
-            surfaceZonesInfo::getClosedNamedSurfaces
-            (
-                surfaces_.surfZones(),
-                surfaces_.geometry(),
-                surfaces_.surfaces()
-            )
-        );
-
-        if (closedNamedSurfaces.size())
-        {
-            Info<< "Found " << closedNamedSurfaces.size()
-                << " closed, named surfaces. Assigning cells in/outside"
-                << " these surfaces to the corresponding cellZone."
-                << nl << endl;
+    // 2. Check intersections of all unnamed surfaces
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-            findCellZoneGeometric
-            (
-                neiCc,
-                closedNamedSurfaces,    // indices of closed surfaces
-                ownPatch,               // per face patch
-                labelList(mesh_.boundaryMesh().size(), 0),// cellZone per patch
+    const labelList testFaces(intersectedFaces());
 
-                cellToZone
-            );
-        }
+    labelList globalRegion1;
+    labelList globalRegion2;
+    getIntersections
+    (
+        surfaceZonesInfo::getUnnamedSurfaces(surfaces_.surfZones()),
+        neiCc,
+        testFaces,
+        globalRegion1,
+        globalRegion2
+    );
 
-        // Locations in mesh - walk
-        findCellZoneInsideWalk
-        (
-            locationsInMesh,
-            zonesInMesh,
-            ownPatch,   // per face -1 or some index >= 0
-            cellToZone
-        );
 
+    labelList neiCellZone;
+    syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone);
 
-        // Now we will still have some -2 in cellToZone on parts that
-        // are unreachable from the locationsInMesh or named surfaces. We only
-        // want to keep the interfaces to these cellZones.
 
+    // 3. Baffle all boundary faces
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    // Baffle all boundary faces except those on outside of unvisited cells
+    // (cellToZone = -2)
+    // Use patch according to globalRegion1,2
+    // Note: the behaviour is slightly different from version3.0 and earlier
+    //       in that it will not create baffles which are outside the meshed
+    //       domain. On a medium testcase (motorBike tutorial geometry) this
+    //       selects about 20 cells less (out of 120000). These cells are where
+    //       there might e.g. be a single cell which is fully unreachable.
+
+    ownPatch.setSize(mesh_.nFaces());
+    ownPatch = -1;
+    neiPatch.setSize(mesh_.nFaces());
+    neiPatch = -1;
+    forAll(testFaces, i)
+    {
+        label faceI = testFaces[i];
+        label ownZone = cellToZone[mesh_.faceOwner()[faceI]];
+        label neiZone = -1;
 
-        labelList neiCellZone;
-        syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone);
+        if (mesh_.isInternalFace(faceI))
+        {
+            neiZone = cellToZone[mesh_.faceNeighbour()[faceI]];
+        }
+        else
+        {
+            neiZone = neiCellZone[faceI-mesh_.nInternalFaces()];
+        }
 
-        // Only keep baffles where one of the sides has an unset cellToZone (-2)
-        for (label faceI=0; faceI < mesh_.nInternalFaces(); faceI++)
+        if (ownZone != -2 || neiZone != -2)
         {
-            if (ownPatch[faceI] != -1 || neiPatch[faceI] != -1)
+            if (globalRegion1[faceI] != -1)
             {
-                label ownZone = cellToZone[mesh_.faceOwner()[faceI]];
-                label neiZone = cellToZone[mesh_.faceNeighbour()[faceI]];
-
-                if (ownZone != -2 && neiZone != -2)
-                {
-                    ownPatch[faceI] = -1;
-                    neiPatch[faceI] = -1;
-                }
+                ownPatch[faceI] = globalToMasterPatch[globalRegion1[faceI]];
             }
-        }
-        for
-        (
-            label faceI = mesh_.nInternalFaces();
-            faceI < mesh_.nFaces();
-            faceI++
-        )
-        {
-            if (ownPatch[faceI] != -1 || neiPatch[faceI] != -1)
+            if (globalRegion2[faceI] != -1)
             {
-                label ownZone = cellToZone[mesh_.faceOwner()[faceI]];
-                label neiZone = neiCellZone[faceI-mesh_.nInternalFaces()];
-
-                if (ownZone != -2 && neiZone != -2)
-                {
-                    ownPatch[faceI] = -1;
-                    neiPatch[faceI] = -1;
-                }
+                neiPatch[faceI] = globalToMasterPatch[globalRegion2[faceI]];
             }
         }
     }
 
-
     // No need to parallel sync since intersection data (surfaceIndex_ etc.)
     // already guaranteed to be synced...
     // However:
@@ -1417,12 +1417,19 @@ void Foam::meshRefinement::findCellZoneGeometric
 
     forAll(insideSurfaces, cellI)
     {
-        if (cellToZone[cellI] == -2)
-        {
-            label surfI = insideSurfaces[cellI];
+        label surfI = insideSurfaces[cellI];
 
-            if (surfI != -1)
+        if (surfI != -1)
+        {
+            if (cellToZone[cellI] == -2)
+            {
+                cellToZone[cellI] = surfaceToCellZone[surfI];
+            }
+            else if (cellToZone[cellI] == -1)
             {
+                // ? Allow named surface to override background zone (-1)
+                // This is used in the multiRegionHeater tutorial where the
+                // locationInMesh is inside a named surface.
                 cellToZone[cellI] = surfaceToCellZone[surfI];
             }
         }
@@ -1548,7 +1555,9 @@ void Foam::meshRefinement::findCellZoneGeometric
 
         if (namedSurfaceIndex[faceI] == -1 && (ownZone != neiZone))
         {
-            // Give face the zone of min cell zone
+            // Give face the zone of min cell zone (but only if the
+            // cellZone originated from a closed, named surface)
+
             label minZone;
             if (ownZone == -1)
             {
@@ -1563,7 +1572,13 @@ void Foam::meshRefinement::findCellZoneGeometric
                 minZone = min(ownZone, neiZone);
             }
 
-            namedSurfaceIndex[faceI] = findIndex(surfaceToCellZone, minZone);
+            // Make sure the cellZone originated from a closed surface
+            label geomSurfI = findIndex(surfaceToCellZone, minZone);
+
+            if (geomSurfI != -1)
+            {
+                namedSurfaceIndex[faceI] = geomSurfI;
+            }
         }
     }
 
@@ -1601,11 +1616,13 @@ void Foam::meshRefinement::findCellZoneGeometric
                         minZone = min(ownZone, neiZone);
                     }
 
-                    namedSurfaceIndex[faceI] = findIndex
-                    (
-                        surfaceToCellZone,
-                        minZone
-                    );
+                    // Make sure the cellZone originated from a closed surface
+                    label geomSurfI = findIndex(surfaceToCellZone, minZone);
+
+                    if (geomSurfI != -1)
+                    {
+                        namedSurfaceIndex[faceI] = geomSurfI;
+                    }
                 }
             }
         }
@@ -1616,103 +1633,10 @@ void Foam::meshRefinement::findCellZoneGeometric
 }
 
 
-void Foam::meshRefinement::findCellZoneInsideWalk
-(
-    const labelList& locationSurfaces,  // indices of surfaces with inside point
-    const labelList& namedSurfaceIndex, // per face index of named surface
-    const labelList& surfaceToCellZone, // cell zone index per surface
-
-    labelList& cellToZone
-) const
-{
-    // Analyse regions. Reuse regionsplit
-    boolList blockedFace(mesh_.nFaces());
-    //selectSeparatedCoupledFaces(blockedFace);
-
-    forAll(namedSurfaceIndex, faceI)
-    {
-        if (namedSurfaceIndex[faceI] == -1)
-        {
-            blockedFace[faceI] = false;
-        }
-        else
-        {
-            blockedFace[faceI] = true;
-        }
-    }
-    // No need to sync since namedSurfaceIndex already is synced
-
-    // Set region per cell based on walking
-    regionSplit cellRegion(mesh_, blockedFace);
-    blockedFace.clear();
-
-
-    // Force calculation of face decomposition (used in findCell)
-    (void)mesh_.tetBasePtIs();
-
-    const PtrList<surfaceZonesInfo>& surfZones = surfaces_.surfZones();
-
-    // For all locationSurface find the cell
-    forAll(locationSurfaces, i)
-    {
-        label surfI = locationSurfaces[i];
-
-        const point& insidePoint = surfZones[surfI].zoneInsidePoint();
-
-        // Find the region containing the insidePoint
-        label keepRegionI = findRegion
-        (
-            mesh_,
-            cellRegion,
-            mergeDistance_*vector(1,1,1),
-            insidePoint
-        );
-
-        Info<< "For surface " << surfaces_.names()[surfI]
-            << " found point " << insidePoint
-            << " in global region " << keepRegionI
-            << " out of " << cellRegion.nRegions() << " regions." << endl;
-
-        if (keepRegionI == -1)
-        {
-            FatalErrorInFunction
-                << "Point " << insidePoint
-                << " is not inside the mesh." << nl
-                << "Bounding box of the mesh:" << mesh_.bounds()
-                << exit(FatalError);
-        }
-
-        // Set all cells with this region
-        forAll(cellRegion, cellI)
-        {
-            if (cellRegion[cellI] == keepRegionI)
-            {
-                if (cellToZone[cellI] == -2)
-                {
-                    cellToZone[cellI] = surfaceToCellZone[surfI];
-                }
-                else if (cellToZone[cellI] != surfaceToCellZone[surfI])
-                {
-                    WarningInFunction
-                        << "Cell " << cellI
-                        << " at " << mesh_.cellCentres()[cellI]
-                        << " is inside surface " << surfaces_.names()[surfI]
-                        << " but already marked as being in zone "
-                        << cellToZone[cellI] << endl
-                        << "This can happen if your surfaces are not"
-                        << " (sufficiently) closed."
-                        << endl;
-                }
-            }
-        }
-    }
-}
-
-
 void Foam::meshRefinement::findCellZoneInsideWalk
 (
     const pointField& locationsInMesh,
-    const wordList& zonesInMesh,
+    const labelList& zonesInMesh,
     const labelList& faceToZone, // per face -1 or some index >= 0
 
     labelList& cellToZone
@@ -1733,7 +1657,7 @@ void Foam::meshRefinement::findCellZoneInsideWalk
             blockedFace[faceI] = true;
         }
     }
-    // No need to sync since blockedFace already is synced
+    // No need to sync since faceToZone already is synced
 
     // Set region per cell based on walking
     regionSplit cellRegion(mesh_, blockedFace);
@@ -1752,7 +1676,7 @@ void Foam::meshRefinement::findCellZoneInsideWalk
     {
         // Get location and index of zone ("none" for cellZone -1)
         const point& insidePoint = locationsInMesh[i];
-        label zoneID = mesh_.cellZones().findZoneID(zonesInMesh[i]);
+        label zoneID = zonesInMesh[i];
 
         // Find the region containing the insidePoint
         label keepRegionI = findRegion
@@ -1763,7 +1687,12 @@ void Foam::meshRefinement::findCellZoneInsideWalk
             insidePoint
         );
 
-        Info<< "For cellZone " << zonesInMesh[i]
+        Info<< "For cellZone "
+            <<  (
+                    zoneID == -1
+                  ? "none"
+                  : mesh_.cellZones()[zoneID].name()
+                )
             << " found point " << insidePoint
             << " in global region " << keepRegionI
             << " out of " << cellRegion.nRegions() << " regions." << endl;
@@ -1803,7 +1732,12 @@ void Foam::meshRefinement::findCellZoneInsideWalk
                         WarningInFunction
                             << "Cell " << cellI
                             << " at " << mesh_.cellCentres()[cellI]
-                            << " is inside cellZone " << zonesInMesh[i]
+                            << " is inside cellZone "
+                            <<  (
+                                    zoneID == -1
+                                  ? "none"
+                                  : mesh_.cellZones()[zoneID].name()
+                                )
                             << " from locationInMesh " << insidePoint
                             << " but already marked as being in zone "
                             << mesh_.cellZones()[cellToZone[cellI]].name()
@@ -1817,54 +1751,32 @@ void Foam::meshRefinement::findCellZoneInsideWalk
             }
         }
     }
+}
 
 
-    // Check if any unassigned regions
-    label nUnzoned = 0;
-    forAll(regionToZone, regionI)
-    {
-        if (regionToZone[regionI] == -2)
-        {
-            // region that has not been assigned a cellZone
-            nUnzoned++;
-        }
-    }
-
-    if (nUnzoned > 0)
-    {
-        Info<< "Detected " << nUnzoned << " regions in the mesh that do"
-            << " not have a locationInMesh." << nl
-            << "Per unzoned region displaying a single cell centre:" << endl;
-
-        // Determine single location per unzoned region
-        pointField regionToLocation
-        (
-            regionToZone.size(),
-            point(GREAT, GREAT, GREAT)
-        );
-        forAll(cellRegion, cellI)
-        {
-            label regionI = cellRegion[cellI];
-            if (regionToZone[regionI] == -2)
-            {
-                const point& cc = mesh_.cellCentres()[cellI];
-                minMagSqrEqOp<point>()(regionToLocation[regionI], cc);
-            }
-        }
+void Foam::meshRefinement::findCellZoneInsideWalk
+(
+    const pointField& locationsInMesh,
+    const wordList& zoneNamesInMesh,
+    const labelList& faceToZone,    // per face -1 or some index >= 0
 
-        Pstream::listCombineGather(regionToLocation, minMagSqrEqOp<point>());
-        Pstream::listCombineScatter(regionToLocation);
+    labelList& cellToZone
+) const
+{
+    const cellZoneMesh& czs = mesh_.cellZones();
 
-        forAll(regionToZone, regionI)
-        {
-            if (regionToZone[regionI] == -2)
-            {
-                Info<< '\t' << regionI
-                    << '\t' << regionToLocation[regionI] << endl;
-            }
-        }
-        Info<< endl;
+    labelList zoneIDs(zoneNamesInMesh.size());
+    forAll(zoneNamesInMesh, i)
+    {
+        zoneIDs[i] = czs.findZoneID(zoneNamesInMesh[i]);
     }
+    findCellZoneInsideWalk
+    (
+        locationsInMesh,
+        zoneIDs,
+        faceToZone,
+        cellToZone
+    );
 }
 
 
@@ -1929,6 +1841,7 @@ bool Foam::meshRefinement::calcRegionToZone
 void Foam::meshRefinement::findCellZoneTopo
 (
     const pointField& locationsInMesh,
+    const labelList& allSurfaceIndex,
     const labelList& namedSurfaceIndex,
     const labelList& surfaceToCellZone,
     labelList& cellToZone
@@ -1942,9 +1855,9 @@ void Foam::meshRefinement::findCellZoneTopo
     // Analyse regions. Reuse regionsplit
     boolList blockedFace(mesh_.nFaces());
 
-    forAll(namedSurfaceIndex, faceI)
+    forAll(allSurfaceIndex, faceI)
     {
-        if (namedSurfaceIndex[faceI] == -1)
+        if (allSurfaceIndex[faceI] == -1)
         {
             blockedFace[faceI] = false;
         }
@@ -1970,12 +1883,21 @@ void Foam::meshRefinement::findCellZoneTopo
     // Note: could be improved to count number of cells per region.
     forAll(cellToZone, cellI)
     {
-        if (cellToZone[cellI] != -2)
+        label regionI = cellRegion[cellI];
+        if (cellToZone[cellI] != -2 && regionToCellZone[regionI] == -2)
         {
-            regionToCellZone[cellRegion[cellI]] = cellToZone[cellI];
+            regionToCellZone[regionI] = cellToZone[cellI];
         }
     }
 
+    // Synchronise regionToCellZone.
+    // Note:
+    // - region numbers are identical on all processors
+    // - keepRegion is identical ,,
+    // - cellZones are identical ,,
+    Pstream::listCombineGather(regionToCellZone, maxEqOp<label>());
+    Pstream::listCombineScatter(regionToCellZone);
+
 
     // Find the region containing the keepPoint
     forAll(locationsInMesh, i)
@@ -2002,7 +1924,10 @@ void Foam::meshRefinement::findCellZoneTopo
                 << exit(FatalError);
         }
 
-        // Mark default region with zone -1.
+        // Mark default region with zone -1. Note that all regions should
+        // already be matched to a cellZone through the loop over cellToZone.
+        // This is just to mop up any remaining regions. Not sure whether
+        // this is needed?
         if (regionToCellZone[keepRegionI] == -2)
         {
             regionToCellZone[keepRegionI] = -1;
@@ -2096,18 +2021,6 @@ void Foam::meshRefinement::findCellZoneTopo
     }
 
 
-    forAll(regionToCellZone, regionI)
-    {
-        label zoneI = regionToCellZone[regionI];
-
-        if (zoneI ==  -2)
-        {
-            FatalErrorInFunction
-                << "For region " << regionI << " haven't set cell zone."
-                << exit(FatalError);
-        }
-    }
-
     if (debug)
     {
         forAll(regionToCellZone, regionI)
@@ -2121,17 +2034,30 @@ void Foam::meshRefinement::findCellZoneTopo
     // Rework into cellToZone
     forAll(cellToZone, cellI)
     {
-        cellToZone[cellI] = regionToCellZone[cellRegion[cellI]];
+        label regionI = cellRegion[cellI];
+        if (cellToZone[cellI] == -2 && regionToCellZone[regionI] != -2)
+        {
+            cellToZone[cellI] = regionToCellZone[regionI];
+        }
     }
 }
 
 
 void Foam::meshRefinement::makeConsistentFaceIndex
 (
+    const labelList& surfaceMap,
     const labelList& cellToZone,
-    labelList& faceToZone
+    labelList& namedSurfaceIndex
 ) const
 {
+    // Make namedSurfaceIndex consistent with cellToZone - clear out any
+    // blocked faces inbetween same cell zone (or background (=-1))
+    // Do not do this for surfaces relating to 'pure' faceZones i.e.
+    // faceZones without a cellZone. Note that we cannot check here
+    // for different cellZones on either side but no namedSurfaceIndex
+    // since cellZones can now originate from locationsInMesh as well
+    // (instead of only through named surfaces)
+
     const labelList& faceOwner = mesh_.faceOwner();
     const labelList& faceNeighbour = mesh_.faceNeighbour();
 
@@ -2140,17 +2066,14 @@ void Foam::meshRefinement::makeConsistentFaceIndex
         label ownZone = cellToZone[faceOwner[faceI]];
         label neiZone = cellToZone[faceNeighbour[faceI]];
 
-        if (ownZone == neiZone && faceToZone[faceI] != -1)
-        {
-            faceToZone[faceI] = -1;
-        }
-        else if (ownZone != neiZone && faceToZone[faceI] == -1)
+        if
+        (
+            ownZone == neiZone
+         && namedSurfaceIndex[faceI] != -1
+         && surfaceMap[namedSurfaceIndex[faceI]] == -1
+        )
         {
-            FatalErrorInFunction
-                << "Different cell zones on either side of face " << faceI
-                << " at " << mesh_.faceCentres()[faceI]
-                << " but face not marked with a surface."
-                << abort(FatalError);
+            namedSurfaceIndex[faceI] = -1;
         }
     }
 
@@ -2174,17 +2097,14 @@ void Foam::meshRefinement::makeConsistentFaceIndex
                 label ownZone = cellToZone[faceOwner[faceI]];
                 label neiZone = neiCellZone[faceI-mesh_.nInternalFaces()];
 
-                if (ownZone == neiZone && faceToZone[faceI] != -1)
-                {
-                    faceToZone[faceI] = -1;
-                }
-                else if (ownZone != neiZone && faceToZone[faceI] == -1)
+                if
+                (
+                    ownZone == neiZone
+                 && namedSurfaceIndex[faceI] != -1
+                 && surfaceMap[namedSurfaceIndex[faceI]] == -1
+                )
                 {
-                    FatalErrorInFunction
-                        << "Different cell zones on either side of face "
-                        << faceI << " at " << mesh_.faceCentres()[faceI]
-                        << " but face not marked with a surface."
-                        << abort(FatalError);
+                    namedSurfaceIndex[faceI] = -1;
                 }
             }
         }
@@ -2194,27 +2114,430 @@ void Foam::meshRefinement::makeConsistentFaceIndex
             forAll(pp, i)
             {
                 label faceI = pp.start()+i;
-                faceToZone[faceI] = -1;
+
+                if
+                (
+                    namedSurfaceIndex[faceI] != -1
+                 && surfaceMap[namedSurfaceIndex[faceI]] == -1
+                )
+                {
+                    namedSurfaceIndex[faceI] = -1;
+                }
             }
         }
     }
 }
 
 
-void Foam::meshRefinement::handleSnapProblems
+void Foam::meshRefinement::getIntersections
 (
-    const snapParameters& snapParams,
-    const bool useTopologicalSnapDetection,
-    const bool removeEdgeConnectedCells,
-    const scalarField& perpendicularAngle,
-    const dictionary& motionDict,
-    Time& runTime,
-    const labelList& globalToMasterPatch,
-    const labelList& globalToSlavePatch
-)
-{
-    Info<< nl
-        << "Introducing baffles to block off problem cells" << nl
+    const labelList& surfacesToTest,
+    const pointField& neiCc,
+    const labelList& testFaces,
+
+    labelList& namedSurfaceIndex,
+    PackedBoolList& posOrientation
+) const
+{
+    const pointField& cellCentres = mesh_.cellCentres();
+    const labelList& faceOwner = mesh_.faceOwner();
+    const labelList& faceNeighbour = mesh_.faceNeighbour();
+
+    namedSurfaceIndex.setSize(mesh_.nFaces());
+    namedSurfaceIndex = -1;
+
+    posOrientation.setSize(mesh_.nFaces());
+    posOrientation = false;
+
+    // Statistics: number of faces per faceZone
+    labelList nSurfFaces(surfaces_.surfZones().size(), 0);
+
+    // Collect segments
+    // ~~~~~~~~~~~~~~~~
+
+    pointField start(testFaces.size());
+    pointField end(testFaces.size());
+
+    forAll(testFaces, i)
+    {
+        label faceI = testFaces[i];
+
+        if (mesh_.isInternalFace(faceI))
+        {
+            start[i] = cellCentres[faceOwner[faceI]];
+            end[i] = cellCentres[faceNeighbour[faceI]];
+        }
+        else
+        {
+            start[i] = cellCentres[faceOwner[faceI]];
+            end[i] = neiCc[faceI-mesh_.nInternalFaces()];
+        }
+    }
+
+    // Extend segments a bit
+    {
+        const vectorField smallVec(ROOTSMALL*(end-start));
+        start -= smallVec;
+        end += smallVec;
+    }
+
+
+    // Do test for intersections
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~
+    // Note that we intersect all intersected faces again. Could reuse
+    // the information already in surfaceIndex_.
+
+    labelList surface1;
+    List<pointIndexHit> hit1;
+    vectorField normal1;
+    labelList surface2;
+    List<pointIndexHit> hit2;
+    vectorField normal2;
+    {
+        labelList region1;
+        labelList region2;
+        surfaces_.findNearestIntersection
+        (
+            surfacesToTest,
+            start,
+            end,
+
+            surface1,
+            hit1,
+            region1,
+            normal1,
+
+            surface2,
+            hit2,
+            region2,
+            normal2
+        );
+    }
+
+    forAll(testFaces, i)
+    {
+        label faceI = testFaces[i];
+        const vector& area = mesh_.faceAreas()[faceI];
+
+        if (surface1[i] != -1)
+        {
+            // If both hit should probably choose 'nearest'
+            if
+            (
+                surface2[i] != -1
+             && (
+                    magSqr(hit2[i].hitPoint())
+                  < magSqr(hit1[i].hitPoint())
+                )
+            )
+            {
+                namedSurfaceIndex[faceI] = surface2[i];
+                posOrientation[faceI] = ((area&normal2[i]) > 0);
+                nSurfFaces[surface2[i]]++;
+            }
+            else
+            {
+                namedSurfaceIndex[faceI] = surface1[i];
+                posOrientation[faceI] = ((area&normal1[i]) > 0);
+                nSurfFaces[surface1[i]]++;
+            }
+        }
+        else if (surface2[i] != -1)
+        {
+            namedSurfaceIndex[faceI] = surface2[i];
+            posOrientation[faceI] = ((area&normal2[i]) > 0);
+            nSurfFaces[surface2[i]]++;
+        }
+    }
+
+
+    // surfaceIndex might 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
+    // and the other is not this might give problems so sync.
+    syncTools::syncFaceList
+    (
+        mesh_,
+        namedSurfaceIndex,
+        maxEqOp<label>()
+    );
+
+    // Print a bit
+    if (debug)
+    {
+        forAll(nSurfFaces, surfI)
+        {
+            Pout<< "Surface:"
+                << surfaces_.names()[surfI]
+                << "  nZoneFaces:" << nSurfFaces[surfI] << nl;
+        }
+        Pout<< endl;
+    }
+}
+
+
+void Foam::meshRefinement::zonify
+(
+    const bool allowFreeStandingZoneFaces,
+    const pointField& locationsInMesh,
+    const wordList& zonesInMesh,
+
+    labelList& cellToZone,
+    labelList& namedSurfaceIndex,
+    PackedBoolList& posOrientation
+) const
+{
+    // Determine zones for cells and faces
+    // cellToZone:
+    // -2  : unset
+    // -1  : not in any zone (zone 'none' or background zone)
+    // >=0 : zoneID
+    // namedSurfaceIndex, posOrientation:
+    // -1  : face not intersected by named surface
+    // >=0 : index of named surface
+    //       (and posOrientation: surface normal v.s. face normal)
+
+    const PtrList<surfaceZonesInfo>& surfZones = surfaces_.surfZones();
+
+    // Swap neighbouring cell centres and cell level
+    labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
+    pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
+    calcNeighbourData(neiLevel, neiCc);
+
+
+    labelList namedSurfaces(surfaceZonesInfo::getNamedSurfaces(surfZones));
+
+    // Get map from surface to cellZone (or -1)
+    labelList surfaceToCellZone;
+    if (namedSurfaces.size())
+    {
+        // Get/add cellZones corresponding to surface names
+        surfaceToCellZone = surfaceZonesInfo::addCellZonesToMesh
+        (
+            surfZones,
+            namedSurfaces,
+            mesh_
+        );
+    }
+
+
+    cellToZone.setSize(mesh_.nCells());
+    cellToZone = -2;
+
+    namedSurfaceIndex.clear();
+    posOrientation.clear();
+
+
+
+    // 1. Test all (unnamed & named) surfaces
+
+    labelList globalRegion1;
+    labelList globalRegion2;
+    getIntersections
+    (
+        identity(surfaces_.surfaces().size()),  // surfacesToTest,
+        neiCc,
+        intersectedFaces(),     // testFaces
+        globalRegion1,
+        globalRegion2
+    );
+
+    if (namedSurfaces.size())
+    {
+        getIntersections
+        (
+            namedSurfaces,
+            neiCc,
+            intersectedFaces(),
+            namedSurfaceIndex,
+            posOrientation
+        );
+    }
+
+
+    // 2. Walk from locationsInMesh. Hard set cellZones.
+
+    if (locationsInMesh.size())
+    {
+        Info<< "Setting cellZones according to locationsInMesh:" << endl;
+
+        labelList locationsZoneIDs(zonesInMesh.size(), -1);
+        forAll(locationsInMesh, i)
+        {
+            const word& name = zonesInMesh[i];
+
+            Info<< "Location : " << locationsInMesh[i] << nl
+                << "    cellZone : " << name << endl;
+
+            if (name != "none")
+            {
+                label zoneID = mesh_.cellZones().findZoneID(name);
+                if (zoneID == -1)
+                {
+                    FatalErrorIn("meshRefinement::zonify(..)") << "problem"
+                        << abort(FatalError);
+                }
+                locationsZoneIDs[i] = zoneID;
+            }
+        }
+        Info<< endl;
+
+
+        // Assign cellZone according to seed points
+        findCellZoneInsideWalk
+        (
+            locationsInMesh,    // locations
+            locationsZoneIDs,   // index of cellZone (or -1)
+            globalRegion1,      // per face -1 (unblocked) or >= 0 (blocked)
+
+            cellToZone
+        );
+    }
+
+
+    // 3. Mark named-surfaces-with-insidePoint. Hard set cellZones.
+
+    labelList locationSurfaces
+    (
+        surfaceZonesInfo::getInsidePointNamedSurfaces(surfZones)
+    );
+
+    if (locationSurfaces.size())
+    {
+        Info<< "Found " << locationSurfaces.size()
+            << " named surfaces with a provided inside point."
+            << " Assigning cells inside these surfaces"
+            << " to the corresponding cellZone."
+            << nl << endl;
+
+        // Collect per surface the -insidePoint -cellZone
+        pointField insidePoints(locationSurfaces.size());
+        labelList insidePointCellZoneIDs(locationSurfaces.size(), -1);
+        forAll(locationSurfaces, i)
+        {
+            label surfI = locationSurfaces[i];
+            insidePoints[i] = surfZones[surfI].zoneInsidePoint();
+
+            const word& name = surfZones[surfI].cellZoneName();
+            if (name != "none")
+            {
+                label zoneID = mesh_.cellZones().findZoneID(name);
+                if (zoneID == -1)
+                {
+                    FatalErrorIn("meshRefinement::zonify(..)") << "problem"
+                        << abort(FatalError);
+                }
+                insidePointCellZoneIDs[i] = zoneID;
+            }
+        }
+
+        findCellZoneInsideWalk
+        (
+            insidePoints,           // locations
+            insidePointCellZoneIDs, // index of cellZone
+            globalRegion1,          // per face -1 (unblocked) or >= 0 (blocked)
+            cellToZone
+        );
+    }
+
+
+    // 4. Mark named-surfaces-with-geometric faces. Do geometric test. Soft set
+    // cellZones. Correct through making consistent.
+
+    // Closed surfaces with cellZone specified.
+    labelList closedNamedSurfaces
+    (
+        surfaceZonesInfo::getClosedNamedSurfaces
+        (
+            surfZones,
+            surfaces_.geometry(),
+            surfaces_.surfaces()
+        )
+    );
+
+    if (closedNamedSurfaces.size())
+    {
+        Info<< "Found " << closedNamedSurfaces.size()
+            << " closed, named surfaces. Assigning cells in/outside"
+            << " these surfaces to the corresponding cellZone."
+            << nl << endl;
+
+        findCellZoneGeometric
+        (
+            neiCc,
+            closedNamedSurfaces,    // indices of closed surfaces
+            namedSurfaceIndex,      // per face index of named surface
+            surfaceToCellZone,      // cell zone index per surface
+
+            cellToZone
+        );
+    }
+
+
+    // 5. Find any unassigned regions (from regionSplit)
+
+    if (namedSurfaces.size())
+    {
+        Info<< "Walking from known cellZones; crossing a faceZone "
+            << "face changes cellZone" << nl << endl;
+
+        findCellZoneTopo
+        (
+            pointField(0),
+            globalRegion1,      // To split up cells
+            namedSurfaceIndex,  // Step across named surfaces to propagate
+            surfaceToCellZone,
+            cellToZone
+        );
+
+        // Make sure namedSurfaceIndex is unset inbetween same cell zones.
+        if (!allowFreeStandingZoneFaces)
+        {
+            Info<< "Only keeping zone faces inbetween different cellZones."
+                << nl << endl;
+
+            // Surfaces with faceZone but no cellZone
+            labelList standaloneNamedSurfaces
+            (
+                surfaceZonesInfo::getStandaloneNamedSurfaces
+                (
+                    surfZones
+                )
+            );
+
+            // Construct map from surface index to index in
+            // standaloneNamedSurfaces (or -1)
+            labelList surfaceMap(surfZones.size(), -1);
+            forAll(standaloneNamedSurfaces, i)
+            {
+                surfaceMap[standaloneNamedSurfaces[i]] = i;
+            }
+
+            makeConsistentFaceIndex
+            (
+                surfaceMap,
+                cellToZone,
+                namedSurfaceIndex
+            );
+        }
+    }
+}
+
+
+void Foam::meshRefinement::handleSnapProblems
+(
+    const snapParameters& snapParams,
+    const bool useTopologicalSnapDetection,
+    const bool removeEdgeConnectedCells,
+    const scalarField& perpendicularAngle,
+    const dictionary& motionDict,
+    Time& runTime,
+    const labelList& globalToMasterPatch,
+    const labelList& globalToSlavePatch
+)
+{
+    Info<< nl
+        << "Introducing baffles to block off problem cells" << nl
         << "----------------------------------------------" << nl
         << endl;
 
@@ -3796,10 +4119,13 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
     wordPairHashTable& zonesToFaceZone
 )
 {
-    const pointField& cellCentres = mesh_.cellCentres();
-    const labelList& faceOwner = mesh_.faceOwner();
-    const labelList& faceNeighbour = mesh_.faceNeighbour();
+    if (locationsInMesh.size() != zonesInMesh.size())
+    {
+        FatalErrorIn("zonify(..)") << "problem" << abort(FatalError);
+    }
+
     const polyBoundaryMesh& patches = mesh_.boundaryMesh();
+    const PtrList<surfaceZonesInfo>& surfZones = surfaces_.surfZones();
 
 
     // Swap neighbouring cell centres and cell level
@@ -3808,77 +4134,12 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
     calcNeighbourData(neiLevel, neiCc);
 
 
-
-    // Put the cells into the correct zone
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    // Zone per cell:
-    // -2 : unset
-    // -1 : not in any zone (zone 'none')
-    // >=0: zoneID
-    labelList cellToZone(mesh_.nCells(), -2);
-
-
-    // Add from locationsInMesh
-    // ~~~~~~~~~~~~~~~~~~~~~~~~
-
-    // Filter out keepPoints
-    labelList zonedIndices(refinementParameters::zonedLocations(zonesInMesh));
-
-    if (zonedIndices.size())
-    {
-        // Explicitly provided locations and their cellZone. Determine all
-        // blocked faces and do walking. Updates cellToZone.
-
-        Info<< "Setting cellZones according to locationsInMesh:" << endl;
-        //forAll(locationsInMesh, regionI)
-        forAll(zonedIndices, j)
-        {
-            label regionI = zonedIndices[j];
-            Info<< "Location : " << locationsInMesh[regionI] << nl
-                << "    cellZone : " << zonesInMesh[regionI] << endl;
-        }
-        Info<< endl;
-
-        // Test all (unnamed & named) surfaces
-        labelList globalRegion1;
-        labelList globalRegion2;
-        getIntersections
-        (
-            identity(surfaces_.surfaces().size()),  // surfacesToTest,
-            neiLevel,
-            neiCc,
-            intersectedFaces(),     // testFaces
-            globalRegion1,
-            globalRegion2
-        );
-
-        // Assign cellZone according to seed points
-        findCellZoneInsideWalk
-        (
-            pointField(locationsInMesh, zonedIndices),       // locations
-            UIndirectList<word>(zonesInMesh, zonedIndices)(),// name of region
-            globalRegion1,          // per face -1 (unblocked) or >= 0 (blocked)
-            cellToZone
-        );
-    }
-
-
-
-    // Mark faces intersecting zoned surfaces
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    const PtrList<surfaceZonesInfo>& surfZones = surfaces_.surfZones();
+    // Add any faceZones, cellZones originating from surface to the mesh
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    labelList surfaceToCellZone;
+    labelList surfaceToFaceZone;
 
     labelList namedSurfaces(surfaceZonesInfo::getNamedSurfaces(surfZones));
-
-
-    //- Face face orientation of zone (only from those intersecting named
-    //  surfaces)
-    PackedBoolList posOrientation(mesh_.nFaces());
-    //- Per face index of faceZone or -1
-    labelList faceToZone(mesh_.nFaces(), -1);
-
     if (namedSurfaces.size())
     {
         Info<< "Setting cellZones according to named surfaces:" << endl;
@@ -3892,312 +4153,100 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
         }
         Info<< endl;
 
-
         // Add zones to mesh
-        labelList surfaceToFaceZone =
-            surfaceZonesInfo::addFaceZonesToMesh
-            (
-                surfZones,
-                namedSurfaces,
-                mesh_
-            );
-
-        labelList surfaceToCellZone =
-            surfaceZonesInfo::addCellZonesToMesh
-            (
-                surfZones,
-                namedSurfaces,
-                mesh_
-            );
-
-
-
-
-        // Like surfaceIndex_ but only for named surfaces.
-        labelList namedSurfaceIndex(mesh_.nFaces(), -1);
-
-        {
-            // Statistics: number of faces per faceZone
-            labelList nSurfFaces(surfZones.size(), 0);
-
-            // 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 (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 faceI = testFaces[i];
-
-                if (mesh_.isInternalFace(faceI))
-                {
-                    start[i] = cellCentres[faceOwner[faceI]];
-                    end[i] = cellCentres[faceNeighbour[faceI]];
-                }
-                else
-                {
-                    start[i] = cellCentres[faceOwner[faceI]];
-                    end[i] = neiCc[faceI-mesh_.nInternalFaces()];
-                }
-            }
-
-            // Extend segments a bit
-            {
-                const vectorField smallVec(ROOTSMALL*(end-start));
-                start -= smallVec;
-                end += smallVec;
-            }
-
-
-            // Do test for intersections
-            // ~~~~~~~~~~~~~~~~~~~~~~~~~
-            // Note that we intersect all intersected faces again. Could reuse
-            // the information already in surfaceIndex_.
-
-            labelList surface1;
-            List<pointIndexHit> hit1;
-            vectorField normal1;
-            labelList surface2;
-            List<pointIndexHit> hit2;
-            vectorField normal2;
-            {
-                labelList region1;
-                labelList region2;
-                surfaces_.findNearestIntersection
-                (
-                    namedSurfaces,
-                    start,
-                    end,
-
-                    surface1,
-                    hit1,
-                    region1,
-                    normal1,
-
-                    surface2,
-                    hit2,
-                    region2,
-                    normal2
-                );
-            }
-
-            forAll(testFaces, i)
-            {
-                label faceI = testFaces[i];
-                const vector& area = mesh_.faceAreas()[faceI];
-
-                if (surface1[i] != -1)
-                {
-                    // If both hit should probably choose 'nearest'
-                    if
-                    (
-                        surface2[i] != -1
-                     && (
-                            magSqr(hit2[i].hitPoint())
-                          < magSqr(hit1[i].hitPoint())
-                        )
-                    )
-                    {
-                        namedSurfaceIndex[faceI] = surface2[i];
-                        posOrientation[faceI] = ((area&normal2[i]) > 0);
-                        nSurfFaces[surface2[i]]++;
-                    }
-                    else
-                    {
-                        namedSurfaceIndex[faceI] = surface1[i];
-                        posOrientation[faceI] = ((area&normal1[i]) > 0);
-                        nSurfFaces[surface1[i]]++;
-                    }
-                }
-                else if (surface2[i] != -1)
-                {
-                    namedSurfaceIndex[faceI] = surface2[i];
-                    posOrientation[faceI] = ((area&normal2[i]) > 0);
-                    nSurfFaces[surface2[i]]++;
-                }
-            }
-
-
-            // surfaceIndex might 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
-            // and the other is not this might give problems so sync.
-            syncTools::syncFaceList
-            (
-                mesh_,
-                namedSurfaceIndex,
-                maxEqOp<label>()
-            );
-
-            // Print a bit
-            if (debug)
-            {
-                forAll(nSurfFaces, surfI)
-                {
-                    Pout<< "Surface:"
-                        << surfaces_.names()[surfI]
-                        << "  nZoneFaces:" << nSurfFaces[surfI] << nl;
-                }
-                Pout<< endl;
-            }
-        }
-
-
-        // Now we have for all faces the intersection with a named surfaces (or
-        // -1). Use this information to set zone of cells
-
-        // Set using geometric test
-        // ~~~~~~~~~~~~~~~~~~~~~~~~
-
-        // Closed surfaces with cellZone specified.
-        labelList closedNamedSurfaces
+        surfaceToCellZone = surfaceZonesInfo::addCellZonesToMesh
         (
-            surfaceZonesInfo::getClosedNamedSurfaces
-            (
-                surfZones,
-                surfaces_.geometry(),
-                surfaces_.surfaces()
-            )
+            surfZones,
+            namedSurfaces,
+            mesh_
         );
-
-        if (closedNamedSurfaces.size())
-        {
-            Info<< "Found " << closedNamedSurfaces.size()
-                << " closed, named surfaces. Assigning cells in/outside"
-                << " these surfaces to the corresponding cellZone."
-                << nl << endl;
-
-            findCellZoneGeometric
-            (
-                neiCc,
-                closedNamedSurfaces,    // indices of closed surfaces
-                namedSurfaceIndex,      // per face index of named surface
-                surfaceToCellZone,      // cell zone index per surface
-
-                cellToZone
-            );
-        }
-
-
-        // Set using provided locations
-        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-        labelList locationSurfaces
+        surfaceToFaceZone = surfaceZonesInfo::addFaceZonesToMesh
         (
-            surfaceZonesInfo::getInsidePointNamedSurfaces(surfZones)
+            surfZones,
+            namedSurfaces,
+            mesh_
         );
+    }
 
-        if (locationSurfaces.size())
-        {
-            Info<< "Found " << locationSurfaces.size()
-                << " named surfaces with a provided inside point."
-                << " Assigning cells inside these surfaces"
-                << " to the corresponding cellZone."
-                << nl << endl;
-
-            findCellZoneInsideWalk
-            (
-                locationSurfaces,       // indices of closed surfaces
-                namedSurfaceIndex,      // per face index of named surface
-                surfaceToCellZone,      // cell zone index per surface
-
-                cellToZone
-            );
-        }
 
 
-        // Set using walking
-        // ~~~~~~~~~~~~~~~~~
+    // Put the cells into the correct zone
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-        Info<< "Walking from " << locationsInMesh.size()
-            << " locations-in-mesh "
-            << " to assign cellZones "
-            << "- crossing a faceZone face changes cellZone" << nl << endl;
+    // Zone per cell:
+    // -2 : unset
+    // -1 : not in any zone (zone 'none')
+    // >=0: zoneID
+    // namedSurfaceIndex:
+    // -1  : face not intersecting a named surface
+    // >=0 : index of named surface
+    labelList cellToZone;
+    labelList namedSurfaceIndex;
+    PackedBoolList posOrientation;
+    zonify
+    (
+        allowFreeStandingZoneFaces,
+        locationsInMesh,
+        zonesInMesh,
 
-        labelList zoneIDs(refinementParameters::unzonedLocations(zonesInMesh));
+        cellToZone,
+        namedSurfaceIndex,
+        posOrientation
+    );
 
-        findCellZoneTopo
-        (
-            pointField(locationsInMesh, zoneIDs),
-            namedSurfaceIndex,
-            surfaceToCellZone,
 
-            cellToZone
-        );
+    // Convert namedSurfaceIndex (index of named surfaces) to
+    // actual faceZone index
 
+    //- Per face index of faceZone or -1
+    labelList faceToZone(mesh_.nFaces(), -1);
 
-        // Make sure namedSurfaceIndex is unset inbetween same cell zones.
-        if (!allowFreeStandingZoneFaces)
+    forAll(namedSurfaceIndex, faceI)
+    {
+        label surfI = namedSurfaceIndex[faceI];
+        if (surfI != -1)
         {
-            Info<< "Only keeping zone faces inbetween different cellZones."
-                << nl << endl;
-
-            makeConsistentFaceIndex(cellToZone, namedSurfaceIndex);
+            faceToZone[faceI] = surfaceToFaceZone[surfI];
         }
+    }
 
 
-        // Convert namedSurfaceIndex (index of named surfaces) to
-        // actual faceZone index
+    if (debug&MESH)
+    {
+        const_cast<Time&>(mesh_.time())++;
+        Pout<< "Writing cell zone allocation on mesh to time "
+            << timeName() << endl;
+        write
+        (
+            debugType(debug),
+            writeType(writeLevel() | WRITEMESH),
+            mesh_.time().path()/"cellToZone"
+        );
+        volScalarField volCellToZone
+        (
+            IOobject
+            (
+                "cellToZone",
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE,
+                false
+            ),
+            mesh_,
+            dimensionedScalar("zero", dimless, 0),
+            zeroGradientFvPatchScalarField::typeName
+        );
 
-        forAll(namedSurfaceIndex, faceI)
+        forAll(cellToZone, cellI)
         {
-            label surfI = namedSurfaceIndex[faceI];
-            if (surfI != -1)
-            {
-                faceToZone[faceI] = surfaceToFaceZone[surfI];
-            }
+            volCellToZone[cellI] = cellToZone[cellI];
         }
+        volCellToZone.write();
     }
 
 
 
-    //if (debug&MESH)
-    //{
-    //    const_cast<Time&>(mesh_.time())++;
-    //    Pout<< "Writing mesh to time " << timeName() << endl;
-    //    write
-    //    (
-    //        debugType(debug),
-    //        writeType(writeLevel() | WRITEMESH),
-    //        mesh_.time().path()/"cellToZone"
-    //    );
-    //    volScalarField volCellToZone
-    //    (
-    //        IOobject
-    //        (
-    //            "cellToZone",
-    //            mesh_.time().timeName(),
-    //            mesh_,
-    //            IOobject::NO_READ,
-    //            IOobject::AUTO_WRITE,
-    //            false
-    //        ),
-    //        mesh_,
-    //        dimensionedScalar("zero", dimless, 0),
-    //        zeroGradientFvPatchScalarField::typeName
-    //    );
-    //
-    //    forAll(cellToZone, cellI)
-    //    {
-    //        volCellToZone[cellI] = cellToZone[cellI];
-    //    }
-    //    volCellToZone.write();
-    //}
-
-
-
     // Allocate and assign faceZones from cellZones
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -4208,7 +4257,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::zonify
 
         for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
         {
-            if (faceToZone[faceI] == -1)
+            if (faceToZone[faceI] == -1)    // Not named surface
             {
                 // Face not yet in a faceZone. (it might already have been
                 // done so by a 'named' surface). Check if inbetween different
diff --git a/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/surfaceZonesInfo.C b/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/surfaceZonesInfo.C
index 1962ced8b3ba68157aa126800b4f7b1608b35dad..7021d0cf4522ab1871260b144bb3c9c2dbf9da36 100644
--- a/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/surfaceZonesInfo.C
+++ b/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/surfaceZonesInfo.C
@@ -226,6 +226,32 @@ Foam::labelList Foam::surfaceZonesInfo::getNamedSurfaces
 }
 
 
+Foam::labelList Foam::surfaceZonesInfo::getStandaloneNamedSurfaces
+(
+    const PtrList<surfaceZonesInfo>& surfList
+)
+{
+   labelList namedSurfaces(surfList.size());
+
+    label namedI = 0;
+    forAll(surfList, surfI)
+    {
+        if
+        (
+            surfList.set(surfI)
+        &&  surfList[surfI].faceZoneName().size()
+        && !surfList[surfI].cellZoneName().size()
+        )
+        {
+            namedSurfaces[namedI++] = surfI;
+        }
+    }
+    namedSurfaces.setSize(namedI);
+
+    return namedSurfaces;
+}
+
+
 Foam::labelList Foam::surfaceZonesInfo::getClosedNamedSurfaces
 (
     const PtrList<surfaceZonesInfo>& surfList,
diff --git a/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/surfaceZonesInfo.H b/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/surfaceZonesInfo.H
index 3b5a73c3f5c3c5778b2fa17565eaeca5f34f2444..a6af0f24113f74154cbf7b0dd73f9833a77c9e61 100644
--- a/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/surfaceZonesInfo.H
+++ b/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/surfaceZonesInfo.H
@@ -191,6 +191,12 @@ public:
                 const PtrList<surfaceZonesInfo>& surfList
             );
 
+            //- Get indices of named surfaces without a cellZone
+            static labelList getStandaloneNamedSurfaces
+            (
+                const PtrList<surfaceZonesInfo>& surfList
+            );
+
             //- Get indices of surfaces with a cellZone that are closed and
             //  have 'inside' or 'outside' selection.
             static labelList getClosedNamedSurfaces