diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict
index ea073cd9f070647735f623262a850d4be8f4d220..6b40b2ab5eba9c6509b7ab297b5d027b723c4631 100644
--- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict
+++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict
@@ -244,8 +244,17 @@ castellatedMeshControls
         }
         //sphere.stl
         //{
-        //    mode distance;
-        //    levels ((1.0 5) (2.0 3));
+        //    mode inside;
+        //    levels ((1.0 4));
+        //    // Optional override of uniform refinement level such
+        //    //  that in small gaps we're getting more cells.
+        //    //  The specification is
+        //    //  - numGapCells : minimum number of cells in the gap
+        //    //  - minLevel    : min refinement level at which to kick in
+        //    //  - maxLevel    : upper refinement level
+        //    // All three settings can be overridden on a surface by
+        //    // surface basis in the refinementSurfaces section.
+        //    gapLevel (<numGapCells> <minLevel> <maxlevel>);
         //}
     }
 
diff --git a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H
index e952af9fd60e00aa5aaaa26b08ce694b6ce2c4af..19f8a03fbdbb218569129d90ccb9784fbca73b4c 100644
--- a/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H
+++ b/src/mesh/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H
@@ -109,6 +109,7 @@ class autoRefineDriver
         label bigGapOnlyRefine
         (
             const refinementParameters& refineParams,
+            const bool spreadGapSize,
             const label maxIter
         );
 
diff --git a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H
index b2cbbd983f22d4d8de36ffdd8edc7ea6314bd278..2e71d97579a4feeedd3851e923dec8284eb22525 100644
--- a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H
+++ b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinement.H
@@ -55,6 +55,7 @@ SourceFiles
 #include "wordPairHashTable.H"
 #include "surfaceZonesInfo.H"
 #include "volumeType.H"
+#include "DynamicField.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -353,8 +354,23 @@ private:
                 label& nRefine
             ) const;
 
-            //- Generate single ray for cell to detect gap
-            bool generateRay
+            //- Generate single ray from nearPoint in direction of nearNormal
+            label generateRays
+            (
+                const point& nearPoint,
+                const vector& nearNormal,
+                const FixedList<label, 3>& gapInfo,
+                const volumeType& mode,
+
+                const label cLevel,
+
+                DynamicField<point>& start,
+                DynamicField<point>& end
+            ) const;
+
+            //- Generate pairs of rays through cell centre
+            //  Each ray pair has start, end, and expected gap size
+            label generateRays
             (
                 const bool useSurfaceNormal,
 
@@ -366,10 +382,13 @@ private:
                 const point& cc,
                 const label cLevel,
 
-                point& start,
-                point& end,
-                point& start2,
-                point& end2
+                DynamicField<point>& start,
+                DynamicField<point>& end,
+                DynamicField<scalar>& gapSize,
+
+                DynamicField<point>& start2,
+                DynamicField<point>& end2,
+                DynamicField<scalar>& gapSize2
             ) const;
 
             //- Select candidate cells (cells inside a shell with gapLevel
@@ -400,9 +419,12 @@ private:
             label markInternalGapRefinement
             (
                 const scalar planarCos,
+                const bool spreadGapSize,
                 const label nAllowRefine,
                 labelList& refineCell,
-                label& nRefine
+                label& nRefine,
+                labelList& numGapCells,
+                scalarField& gapSize
             ) const;
 
             //- Refine cells containing small gaps
@@ -958,6 +980,7 @@ public:
                 const bool smallFeatureRefinement,
                 const bool gapRefinement,
                 const bool bigGapRefinement,
+                const bool spreadGapSize,
                 const label maxGlobalCells,
                 const label maxLocalCells
             ) const;
diff --git a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementGapRefine.C b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementGapRefine.C
index 62a285928c128659b52964cd70621f37b96d3e2c..cd9cd153db11a604643e76d3da5f598c86139003 100644
--- a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementGapRefine.C
+++ b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementGapRefine.C
@@ -28,11 +28,14 @@ License
 #include "refinementSurfaces.H"
 #include "refinementFeatures.H"
 #include "shellSurfaces.H"
-#include "OBJstream.H"
 #include "triSurfaceMesh.H"
 #include "treeDataCell.H"
 #include "searchableSurfaces.H"
 #include "DynamicField.H"
+#include "transportData.H"
+#include "FaceCellWave.H"
+#include "volFields.H"
+#include "zeroGradientFvPatchFields.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -71,17 +74,18 @@ Foam::label Foam::meshRefinement::markSurfaceGapRefinement
 
         pointField start(testFaces.size());
         pointField end(testFaces.size());
-        labelList minLevel(testFaces.size());
-
-        calcCellCellRays
-        (
-            neiCc,
-            neiLevel,
-            testFaces,
-            start,
-            end,
-            minLevel
-        );
+        {
+            labelList minLevel(testFaces.size());
+            calcCellCellRays
+            (
+                neiCc,
+                neiLevel,
+                testFaces,
+                start,
+                end,
+                minLevel
+            );
+        }
 
 
         // Collect cells to test for inside/outside in shell
@@ -134,24 +138,21 @@ Foam::label Foam::meshRefinement::markSurfaceGapRefinement
         }
 
 
-        //OBJstream str(mesh_.time().timePath()/"markSurfaceRefinement.obj");
-        //Info<< "Dumping rays to " << str.name( ) << endl;
-
         const List<FixedList<label, 3> >& extendedGapLevel =
             surfaces_.extendedGapLevel();
         const List<volumeType>& extendedGapMode =
             surfaces_.extendedGapMode();
 
-        labelList surface1;
-        List<pointIndexHit> hit1;
-        labelList region1;
-        vectorField normal1;
+        labelList ccSurface1;
+        List<pointIndexHit> ccHit1;
+        labelList ccRegion1;
+        vectorField ccNormal1;
 
         {
-            labelList surface2;
-            List<pointIndexHit> hit2;
-            labelList region2;
-            vectorField normal2;
+            labelList ccSurface2;
+            List<pointIndexHit> ccHit2;
+            labelList ccRegion2;
+            vectorField ccNormal2;
 
             surfaces_.findNearestIntersection
             (
@@ -159,38 +160,43 @@ Foam::label Foam::meshRefinement::markSurfaceGapRefinement
                 start,
                 end,
 
-                surface1,
-                hit1,
-                region1,
-                normal1,
+                ccSurface1,
+                ccHit1,
+                ccRegion1,
+                ccNormal1,
 
-                surface2,
-                hit2,
-                region2,
-                normal2
+                ccSurface2,
+                ccHit2,
+                ccRegion2,
+                ccNormal2
             );
         }
 
+        start.clear();
+        end.clear();
+
+        DynamicField<point> rayStart(2*ccSurface1.size());
+        DynamicField<point> rayEnd(2*ccSurface1.size());
+        DynamicField<scalar> gapSize(2*ccSurface1.size());
 
-        start.setSize(2*surface1.size());
-        end.setSize(2*surface1.size());
-        labelList map(2*surface1.size());
-        pointField start2(2*surface1.size());
-        pointField end2(2*surface1.size());
-        labelList cellMap(2*surface1.size());
+        DynamicField<point> rayStart2(2*ccSurface1.size());
+        DynamicField<point> rayEnd2(2*ccSurface1.size());
+        DynamicField<scalar> gapSize2(2*ccSurface1.size());
 
-        label compactI = 0;
+        DynamicList<label> cellMap(2*ccSurface1.size());
+        DynamicList<label> compactMap(2*ccSurface1.size());
 
-        forAll(surface1, i)
+        forAll(ccSurface1, i)
         {
-            label surfI = surface1[i];
+            label surfI = ccSurface1[i];
 
             if (surfI != -1)
             {
-                label globalRegionI = surfaces_.globalRegion(surfI, region1[i]);
+                label globalRegionI =
+                    surfaces_.globalRegion(surfI, ccRegion1[i]);
 
                 label faceI = testFaces[i];
-                const point& surfPt = hit1[i].hitPoint();
+                const point& surfPt = ccHit1[i].hitPoint();
 
                 label own = mesh_.faceOwner()[faceI];
                 if (cellToCompact[own] != -1)
@@ -210,26 +216,28 @@ Foam::label Foam::meshRefinement::markSurfaceGapRefinement
                     );
 
                     const point& cc = cellCentres[own];
-                    bool okRay = generateRay
+                    label nRays = generateRays
                     (
                         false,
                         surfPt,
-                        normal1[i],
+                        ccNormal1[i],
                         gapInfo,
                         gapMode,
-                        surfPt+((cc-surfPt)&normal1[i])*normal1[i],
+                        surfPt+((cc-surfPt)&ccNormal1[i])*ccNormal1[i],
                         cellLevel[own],
 
-                        start[compactI],
-                        end[compactI],
-                        start2[compactI],
-                        end2[compactI]
-                    );
-                    cellMap[compactI] = own;
+                        rayStart,
+                        rayEnd,
+                        gapSize,
 
-                    if (okRay)
+                        rayStart2,
+                        rayEnd2,
+                        gapSize2
+                    );
+                    for (label j = 0; j < nRays; j++)
                     {
-                        map[compactI++] = i;
+                        cellMap.append(own);
+                        compactMap.append(i);
                     }
                 }
                 if (mesh_.isInternalFace(faceI))
@@ -252,31 +260,37 @@ Foam::label Foam::meshRefinement::markSurfaceGapRefinement
                         );
 
                         const point& cc = cellCentres[nei];
-                        bool okRay = generateRay
+                        label nRays = generateRays
                         (
                             false,
                             surfPt,
-                            normal1[i],
+                            ccNormal1[i],
                             gapInfo,
                             gapMode,
-                            surfPt+((cc-surfPt)&normal1[i])*normal1[i],
+                            surfPt+((cc-surfPt)&ccNormal1[i])*ccNormal1[i],
                             cellLevel[nei],
 
-                            start[compactI],
-                            end[compactI],
-                            start2[compactI],
-                            end2[compactI]
-                        );
-                        cellMap[compactI] = nei;
+                            rayStart,
+                            rayEnd,
+                            gapSize,
 
-                        if (okRay)
+                            rayStart2,
+                            rayEnd2,
+                            gapSize2
+                        );
+                        for (label j = 0; j < nRays; j++)
                         {
-                            map[compactI++] = i;
+                            cellMap.append(nei);
+                            compactMap.append(i);
                         }
                     }
                 }
                 else
                 {
+                    // Note: on coupled face. What cell are we going to
+                    // refine? We've got the neighbouring cell centre
+                    // and level but we cannot mark it for refinement on
+                    // this side...
                     label bFaceI = faceI - mesh_.nInternalFaces();
 
                     if (bFaceToCompact[bFaceI] != -1)
@@ -296,99 +310,103 @@ Foam::label Foam::meshRefinement::markSurfaceGapRefinement
                         );
 
                         const point& cc = neiCc[bFaceI];
-                        bool okRay = generateRay
+                        label nRays = generateRays
                         (
                             false,
                             surfPt,
-                            normal1[i],
+                            ccNormal1[i],
                             gapInfo,
                             gapMode,
-                            surfPt+((cc-surfPt)&normal1[i])*normal1[i],
+                            surfPt+((cc-surfPt)&ccNormal1[i])*ccNormal1[i],
                             neiLevel[bFaceI],
 
-                            start[compactI],
-                            end[compactI],
-                            start2[compactI],
-                            end2[compactI]
-                        );
-                        cellMap[compactI] = -1;
+                            rayStart,
+                            rayEnd,
+                            gapSize,
 
-                        if (okRay)
+                            rayStart2,
+                            rayEnd2,
+                            gapSize2
+                        );
+                        for (label j = 0; j < nRays; j++)
                         {
-                            map[compactI++] = i;
+                            cellMap.append(-1); // See above.
+                            compactMap.append(i);
                         }
                     }
                 }
             }
         }
 
-        //Info<< "Retesting " << returnReduce(compactI, sumOp<label>())
-        //    << " out of " << returnReduce(start.size(), sumOp<label>())
-        //    << endl;
-
-        start.setSize(compactI);
-        end.setSize(compactI);
-        start2.setSize(compactI);
-        end2.setSize(compactI);
-        map.setSize(compactI);
-        cellMap.setSize(compactI);
-
-        testFaces = UIndirectList<label>(testFaces, map)();
-        minLevel = UIndirectList<label>(minLevel, map)();
-        surface1.clear();
-        hit1.clear();
-        region1.clear();
-        normal1 = UIndirectList<vector>(normal1, map)();
-
-        // Do intersections in first direction
-        labelList surfaceHit;
-        vectorField surfaceNormal;
+        Info<< "Shooting " << returnReduce(rayStart.size(), sumOp<label>())
+            << " rays from " << returnReduce(testFaces.size(), sumOp<label>())
+            << " intersected faces" << endl;
+
+        rayStart.shrink();
+        rayEnd.shrink();
+        gapSize.shrink();
+
+        rayStart2.shrink();
+        rayEnd2.shrink();
+        gapSize2.shrink();
+
+        cellMap.shrink();
+        compactMap.shrink();
+
+        testFaces.clear();
+        ccSurface1.clear();
+        ccHit1.clear();
+        ccRegion1.clear();
+        ccNormal1 = UIndirectList<vector>(ccNormal1, compactMap)();
+
+
+        // Do intersections in pairs
+        labelList surf1;
+        List<pointIndexHit> hit1;
+        vectorField normal1;
         surfaces_.findNearestIntersection
         (
-            start,
-            end,
-            surfaceHit,
-            surfaceNormal
+            rayStart,
+            rayEnd,
+            surf1,
+            hit1,
+            normal1
         );
-        {
-            // Do intersections in second direction and merge
-            labelList surfaceHit2;
-            vectorField surfaceNormal2;
-            surfaces_.findNearestIntersection
-            (
-                start2,
-                end2,
-                surfaceHit2,
-                surfaceNormal2
-            );
-            forAll(surfaceHit, i)
-            {
-                if (surfaceHit[i] == -1 && surfaceHit2[i] != -1)
-                {
-                    surfaceHit[i] = surfaceHit2[i];
-                    surfaceNormal[i] = surfaceNormal2[i];
-                }
-            }
-        }
 
+        labelList surf2;
+        List<pointIndexHit> hit2;
+        vectorField normal2;
+        surfaces_.findNearestIntersection
+        (
+            rayStart2,
+            rayEnd2,
+            surf2,
+            hit2,
+            normal2
+        );
 
-        forAll(surfaceHit, i)
+        forAll(surf1, i)
         {
-            label surfI = surfaceHit[i];
-
-            if (surfI != -1)
+            if (surf1[i] != -1 && surf2[i] != -1)
             {
                 // Found intersection with surface. Check opposite normal.
-
                 label cellI = cellMap[i];
 
-                if (cellI != -1 && mag(normal1[i]&surfaceNormal[i]) > planarCos)
+                if
+                (
+                    cellI != -1
+                 && (mag(normal1[i]&normal2[i]) > planarCos)
+                 && (
+                        magSqr(hit1[i].hitPoint()-hit2[i].hitPoint())
+                      < Foam::sqr(gapSize[i])
+                    )
+                )
                 {
                     if
                     (
                        !markForRefine
                         (
-                            surfI,
+                            surf1[i],
                             nAllowRefine,
                             refineCell[cellI],
                             nRefine
@@ -415,84 +433,6 @@ Foam::label Foam::meshRefinement::markSurfaceGapRefinement
 }
 
 
-//Foam::labelList Foam::meshRefinement::extractHits
-//(
-//    const List<pointIndexHit>& info
-//)
-//{
-//    labelList compactMap(info.size());
-//    label compactI = 0;
-//    forAll(info, i)
-//    {
-//        if (info[i].hit())
-//        {
-//            compactMap[compactI++] = i;
-//        }
-//    }
-//    compactMap.setSize(compactI);
-//    return compactMap;
-//}
-//
-//
-//void Foam::meshRefinement::mergeHits
-//(
-//    const pointField& samples,
-//    const List<pointIndexHit>& extraInfo,
-//    List<pointIndexHit>& info
-//)
-//{
-//    if (extraInfo.size() != info.size())
-//    {
-//        FatalErrorIn
-//        (
-//            "meshRefinement::mergeHits(const List<pointIndexHit>&"
-//            ", List<pointIndexHit>& info)"
-//        )   << "Sizes differ " << extraInfo.size() << ' ' << info.size()
-//            << exit(FatalError);
-//    }
-//
-//    // Merge oppositeInfo2 into oppositeInfo
-//    forAll(extraInfo, i)
-//    {
-//        if (!info[i].hit())
-//        {
-//            if (extraInfo[i].hit())
-//            {
-//                info[i] = extraInfo[i];
-//            }
-//        }
-//        else if (extraInfo[i].hit())
-//        {
-//            const point& nearPt = samples[i];   //nearInfo[i].hitPoint();
-//
-//            scalar d = magSqr(info[i].hitPoint()-nearPt);
-//            scalar d2 = magSqr(extraInfo[i].hitPoint()-nearPt);
-//
-//            if (d2 < d)
-//            {
-//                info[i] = extraInfo[i];
-//            }
-//        }
-//    }
-//}
-//
-//
-//Foam::tmp<Foam::pointField> Foam::meshRefinement::extractPoints
-//(
-//    const List<pointIndexHit>& info
-//)
-//{
-//    tmp<pointField> tfld(new pointField(info.size()));
-//    pointField& fld = tfld();
-//
-//    forAll(info, i)
-//    {
-//        fld[i] = info[i].rawPoint();
-//    }
-//    return tfld;
-//}
-//
-//
 //Foam::meshRefinement::findNearestOppositeOp::findNearestOppositeOp
 //(
 //    const indexedOctree<treeDataTriSurface>& tree,
@@ -730,7 +670,58 @@ Foam::label Foam::meshRefinement::markSurfaceGapRefinement
 //}
 
 
-bool Foam::meshRefinement::generateRay
+Foam::label Foam::meshRefinement::generateRays
+(
+    const point& nearPoint,
+    const vector& nearNormal,
+    const FixedList<label, 3>& gapInfo,
+    const volumeType& mode,
+
+    const label cLevel,
+
+    DynamicField<point>& start,
+    DynamicField<point>& end
+) const
+{
+    label nOldRays = start.size();
+
+    if (cLevel >= gapInfo[1] && cLevel < gapInfo[2])
+    {
+        scalar cellSize = meshCutter_.level0EdgeLength()/pow(2, cLevel);
+
+        // Calculate gap size
+        scalar nearGap = gapInfo[0]*cellSize;
+
+        const vector& n = nearNormal;
+
+        // Situation 'C' above: cell too close. Use surface
+        // -normal and -point to shoot rays
+
+        if (mode == volumeType::OUTSIDE)
+        {
+            start.append(nearPoint+1e-6*n);
+            end.append(nearPoint+nearGap*n);
+        }
+        else if (mode == volumeType::INSIDE)
+        {
+            start.append(nearPoint-1e-6*n);
+            end.append(nearPoint-nearGap*n);
+        }
+        else if (mode == volumeType::MIXED)
+        {
+            start.append(nearPoint+1e-6*n);
+            end.append(nearPoint+nearGap*n);
+
+            start.append(nearPoint-1e-6*n);
+            end.append(nearPoint-nearGap*n);
+        }
+    }
+
+    return start.size()-nOldRays;
+}
+
+
+Foam::label Foam::meshRefinement::generateRays
 (
     const bool useSurfaceNormal,
 
@@ -742,10 +733,13 @@ bool Foam::meshRefinement::generateRay
     const point& cc,
     const label cLevel,
 
-    point& start,
-    point& end,
-    point& start2,
-    point& end2
+    DynamicField<point>& start,
+    DynamicField<point>& end,
+    DynamicField<scalar>& gapSize,
+
+    DynamicField<point>& start2,
+    DynamicField<point>& end2,
+    DynamicField<scalar>& gapSize2
 ) const
 {
     // We want to handle the following cases:
@@ -805,7 +799,7 @@ bool Foam::meshRefinement::generateRay
     //   magV < 0.5cellSize)
     // - or otherwise if on the correct side
 
-    bool okRay = false;
+    label nOldRays = start.size();
 
     if (cLevel >= gapInfo[1] && cLevel < gapInfo[2])
     {
@@ -823,36 +817,52 @@ bool Foam::meshRefinement::generateRay
             const vector& n = nearNormal;
 
             // Situation 'C' above: cell too close. Use surface
-            // normal to shoot rays
+            // -normal and -point to shoot rays
 
             if (mode == volumeType::OUTSIDE)
             {
-                start = nearPoint+1e-6*n;
-                end = nearPoint+nearGap*n;
-                // Small second vector just to make sure to
-                // refine cell
-                start2 = nearPoint-1e-6*n;
-                end2 = nearPoint-0.5*cellSize*n;
+                start.append(nearPoint+1e-6*n);
+                end.append(nearPoint+nearGap*n);
+                gapSize.append(nearGap);
+                // Second vector so we get pairs of intersections
+                start2.append(nearPoint+1e-6*n);
+                end2.append(nearPoint-1e-6*n);
+                gapSize2.append(gapSize.last());
             }
             else if (mode == volumeType::INSIDE)
             {
-                start = nearPoint-1e-6*n;
-                end = nearPoint-nearGap*n;
-                // Small second vector just to make sure to
-                // refine cell
-                start2 = nearPoint+1e-6*n;
-                end2 = nearPoint+0.5*cellSize*n;
+                start.append(nearPoint-1e-6*n);
+                end.append(nearPoint-nearGap*n);
+                gapSize.append(nearGap);
+                // Second vector so we get pairs of intersections
+                start2.append(nearPoint-1e-6*n);
+                end2.append(nearPoint+1e-6*n);
+                gapSize2.append(gapSize.last());
             }
             else if (mode == volumeType::MIXED)
             {
-                start = nearPoint+1e-6*n;
-                end = nearPoint+nearGap*n;
-
-                start2 = nearPoint-1e-6*n;
-                end2 = nearPoint-nearGap*n;
+                // Do both rays:
+                // Outside
+                {
+                    start.append(nearPoint+1e-6*n);
+                    end.append(nearPoint+nearGap*n);
+                    gapSize.append(nearGap);
+                    // Second vector so we get pairs of intersections
+                    start2.append(nearPoint+1e-6*n);
+                    end2.append(nearPoint-1e-6*n);
+                    gapSize2.append(gapSize.last());
+                }
+                // Inside
+                {
+                    start.append(nearPoint-1e-6*n);
+                    end.append(nearPoint-nearGap*n);
+                    gapSize.append(nearGap);
+                    // Second vector so we get pairs of intersections
+                    start2.append(nearPoint-1e-6*n);
+                    end2.append(nearPoint+1e-6*n);
+                    gapSize2.append(gapSize.last());
+                }
             }
-
-            okRay = true;
         }
         else
         {
@@ -871,117 +881,53 @@ bool Foam::meshRefinement::generateRay
              || (mode == volumeType::INSIDE && s < -SMALL)
             )
             {
-                // Use vector through cell centre
-                vector n(v/(magV+ROOTVSMALL));
-
-                start = nearPoint+1e-6*n;
-                end = nearPoint+nearGap*n;
-                // Dummy second vector
-                start2 = start;
-                end2 = start2;
-
-                okRay = true;
+                //// Use vector through cell centre
+                //vector n(v/(magV+ROOTVSMALL));
+                //
+                //start.append(cc);
+                //end.append(cc+nearGap*n);
+                //gapSize.append(nearGap);
+                //
+                //start2.append(cc);
+                //end2.append(cc-nearGap*n);
+                //gapSize2.append(nearGap);
+
+
+                // Shoot some rays through the cell centre
+                // X-direction:
+                start.append(cc);
+                end.append(cc+nearGap*vector(1, 0, 0));
+                gapSize.append(nearGap);
+
+                start2.append(cc);
+                end2.append(cc-nearGap*vector(1, 0, 0));
+                gapSize2.append(nearGap);
+
+                // Y-direction:
+                start.append(cc);
+                end.append(cc+nearGap*vector(0, 1, 0));
+                gapSize.append(nearGap);
+
+                start2.append(cc);
+                end2.append(cc-nearGap*vector(0, 1, 0));
+                gapSize2.append(nearGap);
+
+                // Z-direction:
+                start.append(cc);
+                end.append(cc+nearGap*vector(0, 0, 1));
+                gapSize.append(nearGap);
+
+                start2.append(cc);
+                end2.append(cc-nearGap*vector(0, 0, 1));
+                gapSize2.append(nearGap);
             }
         }
     }
 
-    return okRay;
+    return start.size()-nOldRays;
 }
 
 
-//void Foam::meshRefinement::shootRays
-//(
-//    const label surfI,
-//    labelList& nearMap,
-//    scalarField& nearGap,
-//    List<pointIndexHit>& nearInfo,
-//    List<pointIndexHit>& oppositeInfo
-//) const
-//{
-//    const labelList& cellLevel = meshCutter_.cellLevel();
-//    const scalar edge0Len = meshCutter_.level0EdgeLength();
-//
-//    const labelList& surfaceIndices = surfaces_.surfaces();
-//    const List<FixedList<label, 3> >& extendedGapLevel =
-//        surfaces_.extendedGapLevel();
-//    const List<volumeType>& extendedGapMode = surfaces_.extendedGapMode();
-//
-//
-//    label geomI = surfaceIndices[surfI];
-//    const searchableSurface& geom = surfaces_.geometry()[geomI];
-//
-//
-//    // Normals for ray shooting and inside/outside detection
-//    vectorField nearNormal;
-//    geom.getNormal(nearInfo, nearNormal);
-//    // Regions
-//    labelList nearRegion;
-//    geom.getRegion(nearInfo, nearRegion);
-//
-//    labelList map(nearInfo.size());
-//
-//    pointField start(nearInfo.size());
-//    pointField end(nearInfo.size());
-//    pointField start2(nearInfo.size());
-//    pointField end2(nearInfo.size());
-//
-//    label compactI = 0;
-//    forAll(nearInfo, i)
-//    {
-//        label globalRegionI =
-//            surfaces_.globalRegion(surfI, nearRegion[i]);
-//
-//        label cellI = nearMap[i];
-//        label cLevel = cellLevel[cellI];
-//        scalar cellSize = edge0Len/pow(2, cLevel);
-//
-//        // Update gap size
-//        nearGap[i] = extendedGapLevel[globalRegionI][0]*cellSize;
-//
-//        // Construct one or two rays to test for oppositeness
-//        bool okRay = generateRay
-//        (
-//            false,
-//            nearInfo[i].hitPoint(),
-//            nearNormal[i],
-//            extendedGapLevel[globalRegionI],
-//            extendedGapMode[globalRegionI],
-//
-//            cellCentres[cellI],
-//            cellLevel[cellI],
-//
-//            start[compactI],
-//            end[compactI],
-//            start2[compactI],
-//            end2[compactI]
-//        );
-//        if (okRay)
-//        {
-//            map[compactI++] = i;
-//        }
-//    }
-//
-//    Info<< "Selected " << returnReduce(compactI, sumOp<label>())
-//        << " hits on the correct side out of "
-//        << returnReduce(map.size(), sumOp<label>()) << endl;
-//    map.setSize(compactI);
-//    start.setSize(compactI);
-//    end.setSize(compactI);
-//    start2.setSize(compactI);
-//    end2.setSize(compactI);
-//
-//    nearMap = UIndirectList<label>(nearMap, map)();
-//    nearGap = UIndirectList<scalar>(nearGap, map)();
-//    nearInfo = UIndirectList<pointIndexHit>(nearInfo, map)();
-//
-//    geom.findLineAny(start, end, oppositeInfo);
-//
-//    List<pointIndexHit> oppositeInfo2;
-//    geom.findLineAny(start2, end2, oppositeInfo2);
-//    mergeHits(extractPoints(nearInfo), oppositeInfo2, oppositeInfo);
-//}
-
-
 void Foam::meshRefinement::selectGapCandidates
 (
     const labelList& refineCell,
@@ -1081,12 +1027,20 @@ void Foam::meshRefinement::mergeGapInfo
 Foam::label Foam::meshRefinement::markInternalGapRefinement
 (
     const scalar planarCos,
+    const bool spreadGapSize,
     const label nAllowRefine,
 
     labelList& refineCell,
-    label& nRefine
+    label& nRefine,
+    labelList& numGapCells,
+    scalarField& detectedGapSize
 ) const
 {
+    detectedGapSize.setSize(mesh_.nCells());
+    detectedGapSize = GREAT;
+    numGapCells.setSize(mesh_.nCells());
+    numGapCells = -1;
+
     const labelList& cellLevel = meshCutter_.cellLevel();
     const pointField& cellCentres = mesh_.cellCentres();
     const scalar edge0Len = meshCutter_.level0EdgeLength();
@@ -1116,7 +1070,6 @@ Foam::label Foam::meshRefinement::markInternalGapRefinement
             shellGapMode
         );
 
-
         // Find nearest point and normal on the surfaces
         List<pointIndexHit> nearInfo;
         vectorField nearNormal;
@@ -1147,13 +1100,16 @@ Foam::label Foam::meshRefinement::markInternalGapRefinement
 
 
 
-        labelList map(nearInfo.size());
-        pointField start(nearInfo.size());
-        pointField end(nearInfo.size());
-        pointField start2(nearInfo.size());
-        pointField end2(nearInfo.size());
+        DynamicList<label> map(nearInfo.size());
+        DynamicField<point> rayStart(nearInfo.size());
+        DynamicField<point> rayEnd(nearInfo.size());
+        DynamicField<scalar> gapSize(nearInfo.size());
+
+        DynamicField<point> rayStart2(nearInfo.size());
+        DynamicField<point> rayEnd2(nearInfo.size());
+        DynamicField<scalar> gapSize2(nearInfo.size());
 
-        label compactI = 0;
+        label nTestCells = 0;
 
         forAll(nearInfo, i)
         {
@@ -1178,9 +1134,16 @@ Foam::label Foam::meshRefinement::markInternalGapRefinement
                     gapMode
                 );
 
+                // Store wanted number of cells in gap
+                label cellI = cellMap[i];
+                label cLevel = cellLevel[cellI];
+                if (cLevel >= gapInfo[1] && cLevel < gapInfo[2])
+                {
+                    numGapCells[cellI] = max(numGapCells[cellI], gapInfo[0]);
+                }
 
-                // Construct one or two rays to test for oppositeness
-                bool okRay = generateRay
+                // Construct one or more rays to test for oppositeness
+                label nRays = generateRays
                 (
                     false,
                     nearInfo[i].hitPoint(),
@@ -1188,29 +1151,39 @@ Foam::label Foam::meshRefinement::markInternalGapRefinement
                     gapInfo,
                     gapMode,
 
-                    cellCentres[cellMap[i]],
-                    cellLevel[cellMap[i]],
+                    cellCentres[cellI],
+                    cLevel,
 
-                    start[compactI],
-                    end[compactI],
-                    start2[compactI],
-                    end2[compactI]
+                    rayStart,
+                    rayEnd,
+                    gapSize,
+
+                    rayStart2,
+                    rayEnd2,
+                    gapSize2
                 );
-                if (okRay)
+                if (nRays > 0)
                 {
-                    map[compactI++] = i;
+                    nTestCells++;
+                    for (label j = 0; j < nRays; j++)
+                    {
+                        map.append(i);
+                    }
                 }
             }
         }
 
-        Info<< "Selected " << returnReduce(compactI, sumOp<label>())
+        Info<< "Selected " << returnReduce(nTestCells, sumOp<label>())
             << " cells for testing out of "
             << mesh_.globalData().nTotalCells() << endl;
-        map.setSize(compactI);
-        start.setSize(compactI);
-        end.setSize(compactI);
-        start2.setSize(compactI);
-        end2.setSize(compactI);
+        map.shrink();
+        rayStart.shrink();
+        rayEnd.shrink();
+        gapSize.shrink();
+
+        rayStart2.shrink();
+        rayEnd2.shrink();
+        gapSize2.shrink();
 
         cellMap = UIndirectList<label>(cellMap, map)();
         nearNormal = UIndirectList<vector>(nearNormal, map)();
@@ -1221,64 +1194,191 @@ Foam::label Foam::meshRefinement::markInternalGapRefinement
         nearRegion.clear();
 
 
-        // Do intersections in first direction
-        labelList surfaceHit;
-        vectorField surfaceNormal;
+        // Do intersections in pairs
+        labelList surf1;
+        List<pointIndexHit> hit1;
+        vectorField normal1;
         surfaces_.findNearestIntersection
         (
-            start,
-            end,
-            surfaceHit,
-            surfaceNormal
+            rayStart,
+            rayEnd,
+            surf1,
+            hit1,
+            normal1
         );
+
+        labelList surf2;
+        List<pointIndexHit> hit2;
+        vectorField normal2;
+        surfaces_.findNearestIntersection
+        (
+            rayStart2,
+            rayEnd2,
+            surf2,
+            hit2,
+            normal2
+        );
+
+        // Extract cell based gap size
+        forAll(surf1, i)
         {
-            // Do intersections in second direction and merge
-            labelList surfaceHit2;
-            vectorField surfaceNormal2;
-            surfaces_.findNearestIntersection
-            (
-                start2,
-                end2,
-                surfaceHit2,
-                surfaceNormal2
-            );
-            forAll(surfaceHit, i)
+            if (surf1[i] != -1 && surf2[i] != -1)
             {
-                if (surfaceHit[i] == -1 && surfaceHit2[i] != -1)
+                // Found intersections with surface. Check for
+                // - small gap
+                // - coplanar normals
+
+                label cellI = cellMap[i];
+
+                scalar d2 = magSqr(hit1[i].hitPoint()-hit2[i].hitPoint());
+
+                if
+                (
+                    cellI != -1
+                 && (mag(normal1[i]&normal2[i]) > planarCos)
+                 && (d2 < Foam::sqr(gapSize[i]))
+                )
                 {
-                    surfaceHit[i] = surfaceHit2[i];
-                    surfaceNormal[i] = surfaceNormal2[i];
+                    detectedGapSize[cellI] = min
+                    (
+                        detectedGapSize[cellI],
+                        Foam::sqrt(d2)
+                    );
                 }
             }
         }
 
-
-        forAll(surfaceHit, i)
+        // Spread it
+        if (spreadGapSize)
         {
-            label surfI = surfaceHit[i];
+            // Field on cells and faces
+            List<transportData> cellData(mesh_.nCells());
+            List<transportData> faceData(mesh_.nFaces());
+
+            // Start of walk
+            const pointField& faceCentres = mesh_.faceCentres();
 
-            if (surfI != -1 && mag(nearNormal[i]&surfaceNormal[i]) > planarCos)
+            DynamicList<label> frontFaces(mesh_.nFaces());
+            DynamicList<transportData> frontData(mesh_.nFaces());
+            for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
             {
-                // Found intersection with surface. Check opposite normal.
+                label own = mesh_.faceOwner()[faceI];
+                label nei = mesh_.faceNeighbour()[faceI];
 
-                label cellI = cellMap[i];
+                scalar minSize = min
+                (
+                    detectedGapSize[own],
+                    detectedGapSize[nei]
+                );
 
+                if (minSize < GREAT)
+                {
+                    frontFaces.append(faceI);
+                    frontData.append
+                    (
+                        transportData
+                        (
+                            faceCentres[faceI],
+                            minSize,
+                            0.0
+                        )
+                    );
+                }
+            }
+            for
+            (
+                label faceI = mesh_.nInternalFaces();
+                faceI < mesh_.nFaces();
+                faceI++
+            )
+            {
+                label own = mesh_.faceOwner()[faceI];
+
+                if (detectedGapSize[own] < GREAT)
+                {
+                    frontFaces.append(faceI);
+                    frontData.append
+                    (
+                        transportData
+                        (
+                            faceCentres[faceI],
+                            detectedGapSize[own],
+                            0.0
+                        )
+                    );
+                }
+            }
+
+            Info<< "Selected "
+                << returnReduce(frontFaces.size(), sumOp<label>())
+                << " faces for spreading gap size out of "
+                << mesh_.globalData().nTotalFaces() << endl;
+
+
+            FaceCellWave<transportData> deltaCalc
+            (
+                mesh_,
+                frontFaces,
+                frontData,
+                faceData,
+                cellData,
+                mesh_.globalData().nTotalCells()+1
+            );
+
+
+            forAll(cellMap, i)
+            {
+                label cellI = cellMap[i];
                 if
                 (
-                   !markForRefine
-                    (
-                        surfI,
-                        nAllowRefine,
-                        refineCell[cellI],
-                        nRefine
-                    )
+                    cellI != -1
+                 && cellData[cellI].valid(deltaCalc.data())
+                 && numGapCells[cellI] != -1
                 )
                 {
-                    break;
+                    // Update transported gap size
+                    detectedGapSize[cellI] = min
+                    (
+                        detectedGapSize[cellI],
+                        cellData[cellI].data()
+                    );
+                }
+            }
+        }
+
+
+        // Use it
+        forAll(cellMap, i)
+        {
+            label cellI = cellMap[i];
+
+            if (cellI != -1 && numGapCells[cellI] != -1)
+            {
+                // Needed gap size
+                label cLevel = cellLevel[cellI];
+                scalar cellSize = meshCutter_.level0EdgeLength()/pow(2, cLevel);
+                scalar neededGapSize = numGapCells[cellI]*cellSize;
+
+                if (neededGapSize > detectedGapSize[cellI])
+                {
+                    if
+                    (
+                       !markForRefine
+                        (
+                            123,
+                            nAllowRefine,
+                            refineCell[cellI],
+                            nRefine
+                        )
+                    )
+                    {
+                        break;
+                    }
                 }
             }
         }
 
+
         if
         (
             returnReduce(nRefine, sumOp<label>())
@@ -1305,8 +1405,6 @@ Foam::label Foam::meshRefinement::markSmallFeatureRefinement
 ) const
 {
     const labelList& cellLevel = meshCutter_.cellLevel();
-    const pointField& cellCentres = mesh_.cellCentres();
-
     const labelList& surfaceIndices = surfaces_.surfaces();
     const List<FixedList<label, 3> >& extendedGapLevel =
         surfaces_.extendedGapLevel();
@@ -1376,14 +1474,14 @@ Foam::label Foam::meshRefinement::markSmallFeatureRefinement
         );
 
 
-        labelList map(ctrs.size());
-        labelList cellMap(ctrs.size());
-        label compactI = 0;
+        DynamicList<label> map(ctrs.size());
+        DynamicList<label> cellMap(ctrs.size());
 
-        pointField start(ctrs.size());
-        pointField end(ctrs.size());
-        pointField start2(ctrs.size());
-        pointField end2(ctrs.size());
+        DynamicField<point> rayStart(ctrs.size());
+        DynamicField<point> rayEnd(ctrs.size());
+        DynamicField<scalar> gapSize(ctrs.size());
+
+        label nTestCells = 0;
 
         forAll(ctrs, i)
         {
@@ -1422,40 +1520,39 @@ Foam::label Foam::meshRefinement::markSmallFeatureRefinement
                     // Note that we always want to use the surface normal
                     // and not the vector from cell centre to surface point
 
-                    bool okRay = generateRay
+                    label nRays = generateRays
                     (
-                        true,               // always use surface normal
                         ctrs[i],
                         normal[i],
                         gapInfo,
                         gapMode,
 
-                        cellCentres[cellI],
                         cellLevel[cellI],
 
-                        start[compactI],
-                        end[compactI],
-                        start2[compactI],
-                        end2[compactI]
+                        rayStart,
+                        rayEnd
                     );
-                    if (okRay)
+
+                    if (nRays > 0)
                     {
-                        cellMap[compactI] = cellI;
-                        map[compactI++] = i;
+                        nTestCells++;
+                        for (label j = 0; j < nRays; j++)
+                        {
+                            cellMap.append(cellI);
+                            map.append(i);
+                        }
                     }
                 }
             }
         }
 
-        Info<< "Selected " << returnReduce(compactI, sumOp<label>())
+        Info<< "Selected " << returnReduce(nTestCells, sumOp<label>())
             << " cells containing triangle centres out of "
             << mesh_.globalData().nTotalCells() << endl;
-        map.setSize(compactI);
-        cellMap.setSize(compactI);
-        start.setSize(compactI);
-        end.setSize(compactI);
-        start2.setSize(compactI);
-        end2.setSize(compactI);
+        map.shrink();
+        cellMap.shrink();
+        rayStart.shrink();
+        rayEnd.shrink();
 
         ctrs.clear();
         region.clear();
@@ -1463,70 +1560,49 @@ Foam::label Foam::meshRefinement::markSmallFeatureRefinement
         shellGapMode.clear();
         normal = UIndirectList<vector>(normal, map)();
 
-
-        // Do intersections in first direction.
-        // Note passing in of -1 for cell level such that it does not
-        // discard surfaces with level 0. (since can be overridden with
-        // gap level)
+        // Do intersections.
         labelList surfaceHit;
         vectorField surfaceNormal;
         surfaces_.findNearestIntersection
         (
-            start,
-            end,
+            rayStart,
+            rayEnd,
             surfaceHit,
             surfaceNormal
         );
-        {
-            // Do intersections in second direction and merge
-            labelList surfaceHit2;
-            vectorField surfaceNormal2;
-            surfaces_.findNearestIntersection
-            (
-                start2,
-                end2,
-                surfaceHit2,
-                surfaceNormal2
-            );
-            forAll(surfaceHit, i)
-            {
-                if (surfaceHit[i] == -1 && surfaceHit2[i] != -1)
-                {
-                    surfaceHit[i] = surfaceHit2[i];
-                    surfaceNormal[i] = surfaceNormal2[i];
-                }
-            }
-        }
 
 
-        label nGaps = 0;
+        label nOldRefine = 0;
+
 
         forAll(surfaceHit, i)
         {
-            label surfI = surfaceHit[i];
-
-            if (surfI != -1 && mag(normal[i]&surfaceNormal[i]) > planarCos)
+            if (surfaceHit[i] != -1) // && surf2[i] != -1)
             {
-                nGaps++;
+                // Found intersection with surface. Check coplanar normals.
+                label cellI = cellMap[i];
 
-                if
-                (
-                   !markForRefine
+                if (mag(normal[i]&surfaceNormal[i]) > planarCos)
+                {
+                    if
                     (
-                        surfI,
-                        nAllowRefine,
-                        refineCell[cellMap[i]],
-                        nRefine
+                       !markForRefine
+                        (
+                            surfaceHit[i],
+                            nAllowRefine,
+                            refineCell[cellI],
+                            nRefine
+                        )
                     )
-                )
-                {
-                    break;
+                    {
+                        break;
+                    }
                 }
             }
         }
 
         Info<< "For surface " << geom.name() << " found "
-            << returnReduce(nGaps, sumOp<label>())
+            << returnReduce(nRefine-nOldRefine, sumOp<label>())
             << " cells in small gaps" << endl;
 
         if
diff --git a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C
index 8429a3c1175334cae79260499d718e9277757dba..4ffa1248f8e509d01551962475f990dcf8222479 100644
--- a/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C
+++ b/src/mesh/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C
@@ -2055,6 +2055,7 @@ Foam::labelList Foam::meshRefinement::refineCandidates
     const bool smallFeatureRefinement,
     const bool gapRefinement,
     const bool bigGapRefinement,
+    const bool spreadGapSize,
     const label maxGlobalCells,
     const label maxLocalCells
 ) const
@@ -2290,12 +2291,18 @@ Foam::labelList Foam::meshRefinement::refineCandidates
         {
             // Refine based on gap information provided by shell and nearest
             // surface
+            labelList numGapCells;
+            scalarField gapSize;
             label nGap = markInternalGapRefinement
             (
                 planarCos,
+                spreadGapSize,
                 nAllowRefine,
+
                 refineCell,
-                nRefine
+                nRefine,
+                numGapCells,
+                gapSize
             );
             Info<< "Marked for refinement due to opposite surfaces"
                 << "             "
diff --git a/src/mesh/autoMesh/autoHexMesh/meshRefinement/transportData.H b/src/mesh/autoMesh/autoHexMesh/meshRefinement/transportData.H
new file mode 100644
index 0000000000000000000000000000000000000000..f601d7e315a9c5ab8b579c28620c3f62ad24749d
--- /dev/null
+++ b/src/mesh/autoMesh/autoHexMesh/meshRefinement/transportData.H
@@ -0,0 +1,156 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2015 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 3 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, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::transportData
+
+Description
+    Holds information (coordinate and distance). Walks out 0.5*distance.
+
+SourceFiles
+    transportDataI.H
+    transportData.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef transportData_H
+#define transportData_H
+
+#include "wallPointData.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+class polyMesh;
+class hexRef8;
+
+/*---------------------------------------------------------------------------*\
+                           Class transportData Declaration
+\*---------------------------------------------------------------------------*/
+
+class transportData
+:
+    public wallPointData<scalar>
+{
+private:
+
+    // Private Member Functions
+
+        //- Evaluate distance to point. Update distSqr, origin from whomever
+        //  is nearer pt. Return true if w2 is closer to point,
+        //  false otherwise.
+        template<class TrackingData>
+        inline bool update
+        (
+            const point&,
+            const transportData& w2,
+            const scalar tol,
+            TrackingData& td
+        );
+
+public:
+
+    // Constructors
+
+        //- Construct null
+        inline transportData();
+
+        //- Construct from origin, gapSize, distance
+        inline transportData
+        (
+            const point& origin,
+            const scalar gapSize,
+            const scalar distSqr
+        );
+
+
+    // Member Functions
+
+        // Needed by FaceCellWave
+
+            //- Influence of neighbouring face.
+            //  Calls update(...) with cellCentre of cellI
+            template<class TrackingData>
+            inline bool updateCell
+            (
+                const polyMesh& mesh,
+                const label thisCellI,
+                const label neighbourFaceI,
+                const transportData& neighbourWallInfo,
+                const scalar tol,
+                TrackingData& td
+            );
+
+            //- Influence of neighbouring cell.
+            //  Calls update(...) with faceCentre of faceI
+            template<class TrackingData>
+            inline bool updateFace
+            (
+                const polyMesh& mesh,
+                const label thisFaceI,
+                const label neighbourCellI,
+                const transportData& neighbourWallInfo,
+                const scalar tol,
+                TrackingData& td
+            );
+
+            //- Influence of different value on same face.
+            //  Merge new and old info.
+            //  Calls update(...) with faceCentre of faceI
+            template<class TrackingData>
+            inline bool updateFace
+            (
+                const polyMesh& mesh,
+                const label thisFaceI,
+                const transportData& neighbourWallInfo,
+                const scalar tol,
+                TrackingData& td
+            );
+};
+
+
+//- Data associated with transportData type is same as underlying
+template<>
+inline bool contiguous<transportData>()
+{
+    return contiguous<wallPointData<scalar> >();
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "transportDataI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/mesh/autoMesh/autoHexMesh/meshRefinement/transportDataI.H b/src/mesh/autoMesh/autoHexMesh/meshRefinement/transportDataI.H
new file mode 100644
index 0000000000000000000000000000000000000000..16b497f4c0bad19b0cfe945e495a2f7922a49745
--- /dev/null
+++ b/src/mesh/autoMesh/autoHexMesh/meshRefinement/transportDataI.H
@@ -0,0 +1,165 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2015 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 3 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, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "polyMesh.H"
+#include "transform.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+// Update this with w2 if w2 nearer to pt.
+template<class TrackingData>
+inline bool Foam::transportData::update
+(
+    const point& pt,
+    const transportData& w2,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    scalar dist2 = magSqr(pt - w2.origin());
+
+    if (valid(td))
+    {
+        scalar diff = distSqr() - dist2;
+
+        if (diff < 0)
+        {
+            // Already nearer to pt
+            return false;
+        }
+
+        if ((diff < SMALL) || ((distSqr() > SMALL) && (diff/distSqr() < tol)))
+        {
+            // Don't propagate small changes
+            return false;
+        }
+    }
+
+    // Either *this is not yet valid or w2 is closer
+    {
+        // current not yet set so use any value
+        distSqr() = dist2;
+        origin() = w2.origin();
+        data() = w2.data();
+
+        if (distSqr() > sqr(0.25*data()))
+        {
+            // No need to transport gap data since too far away
+            return false;
+        }
+
+        return true;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+inline Foam::transportData::transportData()
+:
+    wallPointData<scalar>()
+{}
+
+
+inline Foam::transportData::transportData
+(
+    const point& origin,
+    const scalar gapSize,
+    const scalar distSqr
+)
+:
+    wallPointData<scalar>(origin, gapSize, distSqr)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class TrackingData>
+inline bool Foam::transportData::updateCell
+(
+    const polyMesh& mesh,
+    const label cellI,
+    const label,
+    const transportData& neighbourWallInfo,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    const vectorField& cellCentres = mesh.primitiveMesh::cellCentres();
+
+    bool updated = update
+    (
+        cellCentres[cellI],
+        neighbourWallInfo,
+        tol,
+        td
+    );
+
+    return updated;
+}
+
+
+template<class TrackingData>
+inline bool Foam::transportData::updateFace
+(
+    const polyMesh& mesh,
+    const label thisFaceI,
+    const label neighbourCellI,
+    const transportData& neighbourWallInfo,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    return update
+    (
+        mesh.faceCentres()[thisFaceI],
+        neighbourWallInfo,
+        tol,
+        td
+    );
+}
+
+
+template<class TrackingData>
+inline bool Foam::transportData::updateFace
+(
+    const polyMesh& mesh,
+    const label thisFaceI,
+    const transportData& neighbourWallInfo,
+    const scalar tol,
+    TrackingData& td
+)
+{
+    return update
+    (
+        mesh.faceCentres()[thisFaceI],
+        neighbourWallInfo,
+        tol,
+        td
+    );
+}
+
+
+// ************************************************************************* //
diff --git a/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C b/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C
index 6f36ce59041f6d1dcecee87e8cd2b4bc3cbd3751..b6fb43d98aba6842658e5636adeb1a70e05e1bc9 100644
--- a/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C
+++ b/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C
@@ -1373,6 +1373,56 @@ void Foam::refinementSurfaces::findNearestIntersection
 }
 
 
+void Foam::refinementSurfaces::findNearestIntersection
+(
+    const pointField& start,
+    const pointField& end,
+
+    labelList& surface1,
+    List<pointIndexHit>& hitInfo1,
+    vectorField& normal1
+) const
+{
+    // 1. intersection from start to end
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    // Initialize arguments
+    surface1.setSize(start.size());
+    surface1 = -1;
+    hitInfo1.setSize(start.size());
+    hitInfo1 = pointIndexHit();
+    normal1.setSize(start.size());
+    normal1 = vector::zero;
+
+    // Current end of segment to test.
+    pointField nearest(end);
+    // Work array
+    List<pointIndexHit> nearestInfo(start.size());
+    labelList region;
+    vectorField normal;
+
+    forAll(surfaces_, surfI)
+    {
+        const searchableSurface& geom = allGeometry_[surfaces_[surfI]];
+
+        // See if any intersection between start and current nearest
+        geom.findLine(start, nearest, nearestInfo);
+        geom.getNormal(nearestInfo, normal);
+
+        forAll(nearestInfo, pointI)
+        {
+            if (nearestInfo[pointI].hit())
+            {
+                surface1[pointI] = surfI;
+                hitInfo1[pointI] = nearestInfo[pointI];
+                normal1[pointI] = normal[pointI];
+                nearest[pointI] = nearestInfo[pointI].hitPoint();
+            }
+        }
+    }
+}
+
+
 void Foam::refinementSurfaces::findAnyIntersection
 (
     const pointField& start,
diff --git a/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H b/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H
index 72f20c17773bdd7d1637c0d9975acf14dd10b524..7e2bcdf946e70966b2be58b47079275078f6d847 100644
--- a/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H
+++ b/src/mesh/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H
@@ -350,6 +350,16 @@ public:
                 vectorField& normal
             ) const;
 
+            //- Find nearest (to start only) intersection of edge
+            void findNearestIntersection
+            (
+                const pointField& start,
+                const pointField& end,
+                labelList& surfaces,
+                List<pointIndexHit>&,
+                vectorField& normal
+            ) const;
+
             //- Used for debugging only: find intersection of edge.
             void findAnyIntersection
             (