diff --git a/.gitignore b/.gitignore
index 96c3093b718b9a8ee6d711583018ae836555158a..150288aae2555094adff1f866bb0e4e950f07c9f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,7 +55,7 @@ doc/[Dd]oxygen/man
 # ignore .timeStamp in the main directory
 /.timeStamp
 
-# ignore .ebrowse in the main directory
-/.ebrowse
+# ignore .tags in the main directory
+/.tags
 
 # end-of-file
diff --git a/applications/solvers/incompressible/simpleFoam/Make/options b/applications/solvers/incompressible/simpleFoam/Make/options
index 61091811bf04fd0547f08d2b4cd5c3c9385d4d6d..1223bdd06f48178f0b2eee8032d29c936634f328 100644
--- a/applications/solvers/incompressible/simpleFoam/Make/options
+++ b/applications/solvers/incompressible/simpleFoam/Make/options
@@ -8,5 +8,4 @@ EXE_INC = \
 EXE_LIBS = \
     -lincompressibleRASModels \
     -lincompressibleTransportModels \
-    -lfiniteVolume \
-    -lmeshTools
+    -lfiniteVolume
diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict
index 43d550f4068b72c6967430b49c0c63ac1516bc99..58f324160e8c66aa5e253cd1a725ff0351b0493d 100644
--- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict
+++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict
@@ -316,6 +316,11 @@ meshQualityControls
     //must be >0 for Fluent compatibility
     minTriangleTwist -1;
 
+    //- if >0 : preserve single cells with all points on the surface if the
+    //  resulting volume after snapping is larger than minVolFraction times old
+    //  volume. If <0 : delete always.
+    minVolFraction 0.1;
+
 
     // Advanced
 
diff --git a/applications/utilities/mesh/manipulation/checkMesh/checkGeometry.C b/applications/utilities/mesh/manipulation/checkMesh/checkGeometry.C
index 52f23658a84b947d3e9fbeaf2a51a0bf85bcebff..0adcd309275da4ae41ebb2274a2a29d68e23cb4a 100644
--- a/applications/utilities/mesh/manipulation/checkMesh/checkGeometry.C
+++ b/applications/utilities/mesh/manipulation/checkMesh/checkGeometry.C
@@ -23,16 +23,13 @@ Foam::label Foam::checkGeometry(const polyMesh& mesh, const bool allGeometry)
     scalar minDistSqr = magSqr(1e-6 * globalBb.span());
 
     // Non-empty directions
-    const Vector<label> validDirs = (mesh.directions() + Vector<label>::one)/2;
+    const Vector<label> validDirs = (mesh.geometricD() + Vector<label>::one)/2;
+    Info<< "    Mesh (non-empty, non-wedge) directions " << validDirs << endl;
 
-    Info<< "    Mesh (non-empty) directions " << validDirs << endl;
+    const Vector<label> solDirs = (mesh.solutionD() + Vector<label>::one)/2;
+    Info<< "    Mesh (non-empty) directions " << solDirs << endl;
 
-    scalar nGeomDims = mesh.nGeometricD();
-
-    Info<< "    Mesh (non-empty, non-wedge) dimensions "
-        << nGeomDims << endl;
-
-    if (nGeomDims < 3)
+    if (mesh.nGeometricD() < 3)
     {
         pointSet nonAlignedPoints(mesh, "nonAlignedEdges", mesh.nPoints()/100);
 
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/PV3FoamReader_SM.xml b/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/PV3FoamReader_SM.xml
index 644b794a44637c0e3af84fd2bc62f07252dd28d0..ef25ac03786e43e5dd407cd7ef992d6b1c3b91b4 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/PV3FoamReader_SM.xml
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/PV3FoamReader_SM.xml
@@ -30,16 +30,16 @@
 
     <!-- Global settings -->
 
-    <!-- Extrapolate Walls check-box -->
+    <!-- Extrapolate Patches check-box -->
     <IntVectorProperty
-      name="ExtrapolateWalls"
-      command="SetExtrapolateWalls"
+      name="ExtrapolatePatches"
+      command="SetExtrapolatePatches"
       number_of_elements="1"
       default_values="0"
       animateable="0">
       <BooleanDomain name="bool"/>
       <Documentation>
-        Extrapolate internalField to wall and empty patches
+        Extrapolate internalField to non-constraint patches
       </Documentation>
     </IntVectorProperty>
 
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/vtkPV3FoamReader.cxx b/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/vtkPV3FoamReader.cxx
index 8fc518d745edaa19bd0107bcc391c94d6c9bbbb8..c16a43deaef9c5a619a2fb3c06fcd01a3cbce4c5 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/vtkPV3FoamReader.cxx
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/vtkPV3FoamReader.cxx
@@ -64,7 +64,7 @@ vtkPV3FoamReader::vtkPV3FoamReader()
 
     CacheMesh = 1;
 
-    ExtrapolateWalls = 0;
+    ExtrapolatePatches = 0;
     IncludeSets = 0;
     IncludeZones = 0;
     ShowPatchNames = 0;
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/vtkPV3FoamReader.h b/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/vtkPV3FoamReader.h
index fde87527de29c134526ee73c72909d1bd0fed8d9..bc21cd8ce816978129720a4822454c455897780d 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/vtkPV3FoamReader.h
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/vtkPV3FoamReader.h
@@ -65,9 +65,9 @@ public:
     vtkGetMacro(CacheMesh, int);
 
     // Description:
-    // FOAM extrapolate internal values onto the walls
-    vtkSetMacro(ExtrapolateWalls, int);
-    vtkGetMacro(ExtrapolateWalls, int);
+    // FOAM extrapolate internal values onto the patches
+    vtkSetMacro(ExtrapolatePatches, int);
+    vtkGetMacro(ExtrapolatePatches, int);
 
     // FOAM read sets control
     vtkSetMacro(IncludeSets, int);
@@ -183,7 +183,7 @@ private:
     int TimeStepRange[2];
     int CacheMesh;
 
-    int ExtrapolateWalls;
+    int ExtrapolatePatches;
     int IncludeSets;
     int IncludeZones;
     int ShowPatchNames;
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.C b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.C
index 7a8fd89e9ed1529b86acfcf3c82f67a11dd474fd..0ed3d53185000a439edbb5654bc2a300fbf1f3a0 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.C
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.C
@@ -659,29 +659,55 @@ void Foam::vtkPV3Foam::addPatchNames(vtkRenderer* renderer)
         }
     }
 
+    // Count number of zones we're actually going to display. This is truncated
+    // to a max per patch
+
+    const label MAXPATCHZONES = 20;
+
+    label displayZoneI = 0;
+
+    forAll(pbMesh, patchI)
+    {
+        displayZoneI += min(MAXPATCHZONES, nZones[patchI]);
+    }
+
+
     zoneCentre.shrink();
 
     if (debug)
     {
         Info<< "patch zone centres = " << zoneCentre << nl
+            << "displayed zone centres = " << displayZoneI << nl
             << "zones per patch = " << nZones << endl;
     }
 
     // Set the size of the patch labels to max number of zones
-    patchTextActorsPtrs_.setSize(zoneCentre.size());
+    patchTextActorsPtrs_.setSize(displayZoneI);
 
     if (debug)
     {
         Info<< "constructing patch labels" << endl;
     }
 
+    // Actor index
+    displayZoneI = 0;
+
+    // Index in zone centres
     label globalZoneI = 0;
+
     forAll(pbMesh, patchI)
     {
         const polyPatch& pp = pbMesh[patchI];
 
         // Only selected patches will have a non-zero number of zones
-        for (label i=0; i<nZones[patchI]; i++)
+        label nDisplayZones = min(MAXPATCHZONES, nZones[patchI]);
+        label increment = 1;
+        if (nZones[patchI] >= MAXPATCHZONES)
+        {
+            increment = nZones[patchI]/MAXPATCHZONES;
+        }
+
+        for (label i = 0; i < nDisplayZones; i++)
         {
             if (debug)
             {
@@ -719,14 +745,15 @@ void Foam::vtkPV3Foam::addPatchNames(vtkRenderer* renderer)
 
             // Maintain a list of text labels added so that they can be
             // removed later
-            patchTextActorsPtrs_[globalZoneI] = txt;
+            patchTextActorsPtrs_[displayZoneI] = txt;
 
-            globalZoneI++;
+            globalZoneI += increment;
+            displayZoneI++;
         }
     }
 
     // Resize the patch names list to the actual number of patch names added
-    patchTextActorsPtrs_.setSize(globalZoneI);
+    patchTextActorsPtrs_.setSize(displayZoneI);
 
     if (debug)
     {
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamVolFields.H b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamVolFields.H
index f217d1a8890afa67b7f71d3856d2290282e07753..6c8d32f4702c54810b59c1e63f867513a62365f9 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamVolFields.H
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamVolFields.H
@@ -132,8 +132,8 @@ void Foam::vtkPV3Foam::convertVolFields
                 isType<emptyFvPatchField<Type> >(ptf)
              ||
                 (
-                    typeid(patches[patchId]) == typeid(wallPolyPatch)
-                 && reader_->GetExtrapolateWalls()
+                    reader_->GetExtrapolatePatches()
+                && !polyPatch::constraintType(patches[patchId].type())
                 )
             )
             {
diff --git a/bin/foamEbrowse b/bin/foamEbrowse
index e303a772643c8b9f74fa5bc60bc565e110a90a20..66fafc1e2b1b46f5384ca1c78f309fb1b785559d 100755
--- a/bin/foamEbrowse
+++ b/bin/foamEbrowse
@@ -27,26 +27,27 @@
 #     foamEbrowse
 #
 # Description
-#     Build the Ebrowse database for all the .C and .H files
+#     Build the Ebrowse database for all the .H and .C files
 #
 #------------------------------------------------------------------------------
-headersFile=${TMPDIR:-/tmp}/headersFile.$$
 sourcesFile=${TMPDIR:-/tmp}/sourcesFile.$$
 
 if [ $# -ne 0 ]; then
    echo "Usage : ${0##*/}"
    echo ""
-   echo "Build the Ebrowse dadbase for all the .C and .H files"
+   echo "Build the Ebrowse dadbase for all the .H and .C files"
    echo ""
    exit 1
 fi
 
 # Clean up on termination and on Ctrl-C
-trap 'rm -f $headersFile $sourcesFile 2>/dev/null; exit 0' EXIT TERM INT
+trap 'rm -f $sourcesFile 2>/dev/null; exit 0' EXIT TERM INT
 
 cd $WM_PROJECT_DIR
-find -H . -name "*.H" | fgrep -v lnInclude > $headersFile
-find -H . -name "*.C" | fgrep -v lnInclude > $sourcesFile
-ebrowse --files=$headersFile --files=$sourcesFile --output-file=.ebrowse
+mkdir .tags 2>/dev/null
+cd .tags
+
+find -H .. \( -name "*.[HC]" -not -name "lnInclude" -not -name "Doxygen" \) -print > $sourcesFile
+ebrowse --files=$sourcesFile --output-file=ebrowse
 
 #------------------------------------------------------------------------------
diff --git a/bin/foamTags b/bin/foamTags
new file mode 100755
index 0000000000000000000000000000000000000000..1cfd186f52b1b32e1d9d8c77fce0d44e5218d507
--- /dev/null
+++ b/bin/foamTags
@@ -0,0 +1,56 @@
+#!/bin/sh
+#------------------------------------------------------------------------------
+# =========                 |
+# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+#  \\    /   O peration     |
+#   \\  /    A nd           | Copyright (C) 1991-2009 OpenCFD Ltd.
+#    \\/     M anipulation  |
+#-------------------------------------------------------------------------------
+# License
+#     This file is part of OpenFOAM.
+#
+#     OpenFOAM is free software; you can redistribute it and/or modify it
+#     under the terms of the GNU General Public License as published by the
+#     Free Software Foundation; either version 2 of the License, or (at your
+#     option) any later version.
+#
+#     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+#     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+#     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#     for more details.
+#
+#     You should have received a copy of the GNU General Public License
+#     along with OpenFOAM; if not, write to the Free Software Foundation,
+#     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Script
+#     foamTags
+#
+# Description
+#     Build the tags files for all the .C and .H files
+#
+#------------------------------------------------------------------------------
+
+if [ $# -ne 0 ]; then
+   echo "Usage : ${0##*/}"
+   echo ""
+   echo "Build the tags files for all the .C and .H files"
+   echo ""
+   exit 1
+fi
+
+cd $WM_PROJECT_DIR
+mkdir .tags 2>/dev/null
+
+find -H . \( -name "*.[HC]" -not -name "lnInclude" -not -name "Doxygen" \) | \
+    etags --declarations -l c++ -o .tags/etags -
+find -H . \( -name "*.[HC]" -not -name "lnInclude" -not -name "Doxygen" \) | \
+    etags -l c++ -o .tags/etagsDef -
+find -H . \( -name "*.H" -not -name "lnInclude" -not -name "Doxygen" \) | \
+    etags --declarations -l c++ -o .tags/etagsDec -
+
+gtags -i --gtagsconf bin/tools/gtagsrc .tags
+
+foamEbrowse
+
+#------------------------------------------------------------------------------
diff --git a/bin/tools/gtagsrc b/bin/tools/gtagsrc
new file mode 100644
index 0000000000000000000000000000000000000000..ce66e0c084a8188bf63b707880344ccc18813143
--- /dev/null
+++ b/bin/tools/gtagsrc
@@ -0,0 +1,63 @@
+#------------------------------------------------------------------------------
+# =========                 |
+# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+#  \\    /   O peration     |
+#   \\  /    A nd           | Copyright (C) 1991-2009 OpenCFD Ltd.
+#    \\/     M anipulation  |
+#-------------------------------------------------------------------------------
+# License
+#     This file is part of OpenFOAM.
+#
+#     OpenFOAM is free software; you can redistribute it and/or modify it
+#     under the terms of the GNU General Public License as published by the
+#     Free Software Foundation; either version 2 of the License, or (at your
+#     option) any later version.
+#
+#     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+#     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+#     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#     for more details.
+#
+#     You should have received a copy of the GNU General Public License
+#     along with OpenFOAM; if not, write to the Free Software Foundation,
+#     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Canfiguration file
+#     gtagsrc
+#
+# Description
+#     Configuration file for gtags(1).
+#
+#------------------------------------------------------------------------------
+default:\
+	:tc=gtags:tc=htags:
+#------------------------------------------------------------------------------
+# Configuration for gtags(1)
+# See gtags(1).
+#------------------------------------------------------------------------------
+common:\
+	:skip=GPATH,GTAGS,GRTAGS,GSYMS,HTML/,HTML.pub/,html/,tags,TAGS,ID,.ebrowse,.etags,.etagsDef,.etagsDec,y.tab.c,y.tab.h,.notfunction,cscope.out,cscope.po.out,cscope.in.out,.gdbinit,SCCS/,RCS/,CVS/,CVSROOT/,{arch}/,.svn/,.git/,.cvsrc,.cvsignore,.gitignore,.cvspass,.cvswrappers,.deps/,autom4te.cache/,.snprj/:\
+	:langmap=c\:.c.h,yacc\:.y,asm\:.s.S,java\:.java,cpp\:.c++.cc.cpp.cxx.hxx.hpp.C.H,php\:.php.php3.phtml:
+gtags:\
+	:tc=common:\
+	:GTAGS=gtags-parser %s:\
+	:GRTAGS=gtags-parser -r %s:\
+	:GSYMS=gtags-parser -s %s:\
+	:skip=lnInclude/,tutorials/,wmake/,doc/,lib/,etc/:
+#
+#------------------------------------------------------------------------------
+# Configuration for htags(1)
+#------------------------------------------------------------------------------
+htags:\
+	:body_begin=<body text='#191970' bgcolor='#f5f5dc' vlink='gray'>:body_end=</body>:\
+	:table_begin=<table>:table_end=</table>:\
+	:title_begin=<h1><font color='#cc0000'>:title_end=</font></h1>:\
+	:comment_begin=<i><font color='green'>:comment_end=</font></i>:\
+	:sharp_begin=<font color='darkred'>:sharp_end=</font>:\
+	:brace_begin=<font color='red'>:brace_end=</font>:\
+	:warned_line_begin=<span style='background-color\:yellow'>:warned_line_end=</span>:\
+	:reserved_begin=<b>:reserved_end=</b>:script_alias=/cgi-bin/:\
+	:ncol#4:tabs#8:normal_suffix=html:gzipped_suffix=ghtml:\
+	:definition_header=no:
+
+#------------------------------------------------------------------------------
\ No newline at end of file
diff --git a/src/Allwmake b/src/Allwmake
index f22e0729dbe8e50694ee43a373205494b0a2a536..c3ce648ba0aa1462b53dff9a1502db02d5a215aa 100755
--- a/src/Allwmake
+++ b/src/Allwmake
@@ -5,8 +5,8 @@ set -x
 # update OpenFOAM version strings if required
 wmakePrintBuild -check || /bin/rm -f OpenFOAM/Make/$WM_OPTIONS/global.? 2>/dev/null
 
-wmakeLnInclude -f OpenFOAM
-wmakeLnInclude -f OSspecific/$WM_OS
+wmakeLnInclude -f OpenFOAM -sf
+wmakeLnInclude -f OSspecific/$WM_OS -sf
 Pstream/Allwmake
 
 wmake libo  OSspecific/$WM_OS
diff --git a/src/OpenFOAM/db/Time/findInstance.C b/src/OpenFOAM/db/Time/findInstance.C
index f21a524c80919f0a395e36b479c8a30390f9ce75..a19d3bda633975b579013deb8e6149a5006506de 100644
--- a/src/OpenFOAM/db/Time/findInstance.C
+++ b/src/OpenFOAM/db/Time/findInstance.C
@@ -58,8 +58,9 @@ Foam::word Foam::Time::findInstance
     {
         if (debug)
         {
-            Info<< "Time::findInstance(const fileName&, const word&) : "
-                << "found \"" << name
+            Info<< "Time::findInstance"
+                "(const fileName&, const word&, const IOobject::readOption)"
+                << " : found \"" << name
                 << "\" in " << timeName()/dir
                 << endl;
         }
@@ -98,8 +99,8 @@ Foam::word Foam::Time::findInstance
             if (debug)
             {
                 Info<< "Time::findInstance"
-                    "(const fileName&,const word&) : "
-                    << "found \"" << name
+                    "(const fileName&, const word&, const IOobject::readOption)"
+                    << " : found \"" << name
                     << "\" in " << ts[instanceI].name()/dir
                     << endl;
             }
@@ -129,8 +130,8 @@ Foam::word Foam::Time::findInstance
         if (debug)
         {
             Info<< "Time::findInstance"
-                   "(const fileName&,const word&) : "
-                << "found \"" << name
+                "(const fileName&, const word&, const IOobject::readOption)"
+                << " : found \"" << name
                 << "\" in " << constant()/dir
                 << endl;
         }
@@ -141,10 +142,10 @@ Foam::word Foam::Time::findInstance
     if (rOpt == IOobject::MUST_READ)
     {
         FatalErrorIn
-            (
-                "Time::findInstance(const fileName&,const word&)"
-            )
-            << "Cannot find file \"" << name << "\" in directory "
+        (
+            "Time::findInstance"
+            "(const fileName&, const word&, const IOobject::readOption)"
+        )   << "Cannot find file \"" << name << "\" in directory "
             << constant()/dir
             << exit(FatalError);
     }
diff --git a/src/OpenFOAM/fields/GeometricFields/GeometricScalarField/GeometricScalarField.C b/src/OpenFOAM/fields/GeometricFields/GeometricScalarField/GeometricScalarField.C
index 70f738fcfbd41f9b4d369b19d33e3442d420a312..fa6a2a58d0a2874f56b6ed7db2e7bc15af060f4c 100644
--- a/src/OpenFOAM/fields/GeometricFields/GeometricScalarField/GeometricScalarField.C
+++ b/src/OpenFOAM/fields/GeometricFields/GeometricScalarField/GeometricScalarField.C
@@ -154,7 +154,7 @@ tmp<GeometricField<scalar, PatchField, GeoMesh> > pow
             pow
             (
                 gsf1.dimensions(),
-                dimensionedScalar("1", 1.0, gsf2.dimensions())
+                dimensionedScalar("1", gsf2.dimensions(), 1.0)
             )
         )
     );
@@ -183,7 +183,7 @@ tmp<GeometricField<scalar, PatchField, GeoMesh> > pow
             pow
             (
                 gsf1.dimensions(),
-                dimensionedScalar("1", 1.0, gsf2.dimensions())
+                dimensionedScalar("1", gsf2.dimensions(), 1.0)
             )
         )
     );
@@ -214,7 +214,7 @@ tmp<GeometricField<scalar, PatchField, GeoMesh> > pow
             pow
             (
                 gsf1.dimensions(),
-                dimensionedScalar("1", 1.0, gsf2.dimensions())
+                dimensionedScalar("1", gsf2.dimensions(), 1.0)
             )
         )
     );
@@ -247,7 +247,7 @@ tmp<GeometricField<scalar, PatchField, GeoMesh> > pow
             pow
             (
                 gsf1.dimensions(),
-                dimensionedScalar("1", 1.0, gsf2.dimensions())
+                dimensionedScalar("1", gsf2.dimensions(), 1.0)
             )
         )
     );
diff --git a/src/OpenFOAM/matrices/lduMatrix/lduMatrix/lduMatrixATmul.C b/src/OpenFOAM/matrices/lduMatrix/lduMatrix/lduMatrixATmul.C
index 666d84a5c1206588bce906d4174fe31a8857cda1..05958edf68ad060e63c51e8f078656fbbb82a5e6 100644
--- a/src/OpenFOAM/matrices/lduMatrix/lduMatrix/lduMatrixATmul.C
+++ b/src/OpenFOAM/matrices/lduMatrix/lduMatrix/lduMatrixATmul.C
@@ -60,7 +60,7 @@ void Foam::lduMatrix::Amul
         interfaceBouCoeffs,
         interfaces,
         psi,
-        Apsi, 
+        Apsi,
         cmpt
     );
 
@@ -79,7 +79,7 @@ void Foam::lduMatrix::Amul
 
     register const label nFaces = upper().size();
     #ifdef ICC_IA64_PREFETCH
-    #pragma swp  
+    #pragma swp
     #endif
     for (register label face=0; face<nFaces; face++)
     {
@@ -227,7 +227,7 @@ void Foam::lduMatrix::sumA
     }
 
     #ifdef ICC_IA64_PREFETCH
-    #pragma swp  
+    #pragma swp
     #endif
 
     for (register label face=0; face<nFaces; face++)
@@ -316,7 +316,7 @@ void Foam::lduMatrix::residual
         mBouCoeffs,
         interfaces,
         psi,
-        rA, 
+        rA,
         cmpt
     );
 
@@ -336,7 +336,7 @@ void Foam::lduMatrix::residual
 
     register const label nFaces = upper().size();
     #ifdef ICC_IA64_PREFETCH
-    #pragma swp  
+    #pragma swp
     #endif
     for (register label face=0; face<nFaces; face++)
     {
diff --git a/src/OpenFOAM/meshes/polyMesh/polyMesh.C b/src/OpenFOAM/meshes/polyMesh/polyMesh.C
index 0428b252d7d173713c13b79510a4d5244e64dd39..e0b4c0536c4ff4623475789c7db5589bb9beff7a 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyMesh.C
+++ b/src/OpenFOAM/meshes/polyMesh/polyMesh.C
@@ -54,40 +54,79 @@ void Foam::polyMesh::calcDirections() const
 {
     for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
     {
-        directions_[cmpt] = 1;
+        solutionD_[cmpt] = 1;
     }
 
+    // Knock out empty and wedge directions. Note:they will be present on all
+    // domains.
+
     label nEmptyPatches = 0;
+    label nWedgePatches = 0;
 
-    vector dirVec = vector::zero;
+    vector emptyDirVec = vector::zero;
+    vector wedgeDirVec = vector::zero;
 
     forAll(boundaryMesh(), patchi)
     {
-        if (isA<emptyPolyPatch>(boundaryMesh()[patchi]))
+        if (boundaryMesh()[patchi].size())
         {
-            if (boundaryMesh()[patchi].size())
+            if (isA<emptyPolyPatch>(boundaryMesh()[patchi]))
             {
                 nEmptyPatches++;
-                dirVec += sum(cmptMag(boundaryMesh()[patchi].faceAreas()));
+                emptyDirVec += sum(cmptMag(boundaryMesh()[patchi].faceAreas()));
+            }
+            else if (isA<wedgePolyPatch>(boundaryMesh()[patchi]))
+            {
+                const wedgePolyPatch& wpp = refCast<const wedgePolyPatch>
+                (
+                    boundaryMesh()[patchi]
+                );
+
+                nWedgePatches++;
+                wedgeDirVec += cmptMag(wpp.centreNormal());
             }
         }
     }
 
     if (nEmptyPatches)
     {
-        reduce(dirVec, sumOp<vector>());
+        reduce(emptyDirVec, sumOp<vector>());
 
-        dirVec /= mag(dirVec);
+        emptyDirVec /= mag(emptyDirVec);
 
         for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
         {
-            if (dirVec[cmpt] > 1e-6)
+            if (emptyDirVec[cmpt] > 1e-6)
             {
-                directions_[cmpt] = -1;
+                solutionD_[cmpt] = -1;
             }
             else
             {
-                directions_[cmpt] = 1;
+                solutionD_[cmpt] = 1;
+            }
+        }
+    }
+
+
+    // Knock out wedge directions
+
+    geometricD_ = solutionD_;
+
+    if (nWedgePatches)
+    {
+        reduce(wedgeDirVec, sumOp<vector>());
+
+        wedgeDirVec /= mag(wedgeDirVec);
+
+        for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
+        {
+            if (wedgeDirVec[cmpt] > 1e-6)
+            {
+                geometricD_[cmpt] = -1;
+            }
+            else
+            {
+                geometricD_[cmpt] = 1;
             }
         }
     }
@@ -163,7 +202,8 @@ Foam::polyMesh::polyMesh(const IOobject& io)
         *this
     ),
     bounds_(points_),
-    directions_(Vector<label>::zero),
+    geometricD_(Vector<label>::zero),
+    solutionD_(Vector<label>::zero),
     pointZones_
     (
         IOobject
@@ -350,7 +390,8 @@ Foam::polyMesh::polyMesh
         0
     ),
     bounds_(points_, syncPar),
-    directions_(Vector<label>::zero),
+    geometricD_(Vector<label>::zero),
+    solutionD_(Vector<label>::zero),
     pointZones_
     (
         IOobject
@@ -505,7 +546,8 @@ Foam::polyMesh::polyMesh
         0
     ),
     bounds_(points_, syncPar),
-    directions_(Vector<label>::zero),
+    geometricD_(Vector<label>::zero),
+    solutionD_(Vector<label>::zero),
     pointZones_
     (
         IOobject
@@ -766,44 +808,37 @@ const Foam::fileName& Foam::polyMesh::facesInstance() const
 }
 
 
-const Foam::Vector<Foam::label>& Foam::polyMesh::directions() const
+const Foam::Vector<Foam::label>& Foam::polyMesh::geometricD() const
 {
-    if (directions_.x() == 0)
+    if (geometricD_.x() == 0)
     {
         calcDirections();
     }
 
-    return directions_;
+    return geometricD_;
 }
 
 
 Foam::label Foam::polyMesh::nGeometricD() const
 {
-    label nWedges = 0;
+    return cmptSum(geometricD() + Vector<label>::one)/2;
+}
 
-    forAll(boundary_, patchi)
-    {
-        if (isA<wedgePolyPatch>(boundary_[patchi]))
-        {
-            nWedges++;
-        }
-    }
 
-    if (nWedges != 0 && nWedges != 2 && nWedges != 4)
+const Foam::Vector<Foam::label>& Foam::polyMesh::solutionD() const
+{
+    if (solutionD_.x() == 0)
     {
-        FatalErrorIn("label polyMesh::nGeometricD() const")
-            << "Number of wedge patches " << nWedges << " is incorrect, "
-               "should be 0, 2 or 4"
-            << exit(FatalError);
+        calcDirections();
     }
 
-    return nSolutionD() - nWedges/2;
+    return solutionD_;
 }
 
 
 Foam::label Foam::polyMesh::nSolutionD() const
 {
-    return cmptSum(directions() + Vector<label>::one)/2;
+    return cmptSum(solutionD() + Vector<label>::one)/2;
 }
 
 
@@ -823,6 +858,10 @@ void Foam::polyMesh::addPatches
             << abort(FatalError);
     }
 
+    // Reset valid directions
+    geometricD_ = Vector<label>::zero;
+    solutionD_ = Vector<label>::zero;
+
     boundary_.setSize(p.size());
 
     // Copy the patch pointers
@@ -1037,6 +1076,10 @@ Foam::tmp<Foam::scalarField> Foam::polyMesh::movePoints
     faceZones_.movePoints(points_);
     cellZones_.movePoints(points_);
 
+    // Reset valid directions (could change with rotation)
+    geometricD_ = Vector<label>::zero;
+    solutionD_ = Vector<label>::zero;
+
 
     // Hack until proper callbacks. Below are all the polyMeh MeshObjects with a
     // movePoints function.
diff --git a/src/OpenFOAM/meshes/polyMesh/polyMesh.H b/src/OpenFOAM/meshes/polyMesh/polyMesh.H
index 588394d1c230e771d5155e537dd81673befd4925..ecb805ad7f0d7912a916bbd302cf9d96da219f77 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyMesh.H
+++ b/src/OpenFOAM/meshes/polyMesh/polyMesh.H
@@ -120,9 +120,13 @@ private:
             //  Created from points on construction, updated when the mesh moves
             boundBox bounds_;
 
+            //- vector of non-constrained directions in mesh
+            //  defined according to the presence of empty and wedge patches
+            mutable Vector<label> geometricD_;
+
             //- vector of valid directions in mesh
             //  defined according to the presence of empty patches
-            mutable Vector<label> directions_;
+            mutable Vector<label> solutionD_;
 
 
         // Zoning information
@@ -309,17 +313,22 @@ public:
                 return bounds_;
             }
 
-            //- Return the vector of valid directions in mesh.
-            //  Defined according to the presence of empty patches.
-            //  1 indicates valid direction and -1 an invalid direction.
-            const Vector<label>& directions() const;
+            //- Return the vector of geometric directions in mesh.
+            //  Defined according to the presence of empty and wedge patches.
+            //  1 indicates unconstrained direction and -1 a constrained
+            //  direction.
+            const Vector<label>& geometricD() const;
 
             //- Return the number of valid geometric dimensions in the mesh
             label nGeometricD() const;
 
-            //- Return the number of valid solution dimensions in the mesh.
-            //  For wedge cases this includes the circumferential direction
-            //  in case of swirl.
+            //- Return the vector of solved-for directions in mesh.
+            //  Differs from geometricD in that it includes for wedge cases
+            //  the circumferential direction in case of swirl.
+            //  1 indicates valid direction and -1 an invalid direction.
+            const Vector<label>& solutionD() const;
+
+            //- Return the number of valid solved-for dimensions in the mesh
             label nSolutionD() const;
 
             //- Return point zone mesh
diff --git a/src/OpenFOAM/meshes/polyMesh/polyMeshClear.C b/src/OpenFOAM/meshes/polyMesh/polyMeshClear.C
index 52f44464444b3643044c37fb6ba14563989121da..71831209849efb0106a2adde6d0d1a8522670ecc 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyMeshClear.C
+++ b/src/OpenFOAM/meshes/polyMesh/polyMeshClear.C
@@ -68,6 +68,10 @@ void Foam::polyMesh::clearGeom()
         boundary_[patchI].clearGeom();
     }
 
+    // Reset valid directions (could change with rotation)
+    geometricD_ = Vector<label>::zero;
+    solutionD_ = Vector<label>::zero;
+
     pointMesh::Delete(*this);
 }
 
@@ -87,6 +91,10 @@ void Foam::polyMesh::clearAddressing()
     // recalculation
     deleteDemandDrivenData(globalMeshDataPtr_);
 
+    // Reset valid directions
+    geometricD_ = Vector<label>::zero;
+    solutionD_ = Vector<label>::zero;
+
     pointMesh::Delete(*this);
 }
 
diff --git a/src/OpenFOAM/meshes/polyMesh/polyMeshFromShapeMesh.C b/src/OpenFOAM/meshes/polyMesh/polyMeshFromShapeMesh.C
index d12dffff62be220a1016e6ac59eedafeba6018ba..f1cc51cb9ec05fd5f3261584f6b92391eda8316b 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyMeshFromShapeMesh.C
+++ b/src/OpenFOAM/meshes/polyMesh/polyMeshFromShapeMesh.C
@@ -217,7 +217,8 @@ Foam::polyMesh::polyMesh
         boundaryFaces.size() + 1    // add room for a default patch
     ),
     bounds_(points_, syncPar),
-    directions_(Vector<label>::zero),
+    geometricD_(Vector<label>::zero),
+    solutionD_(Vector<label>::zero),
     pointZones_
     (
         IOobject
diff --git a/src/OpenFOAM/meshes/polyMesh/polyMeshUpdate.C b/src/OpenFOAM/meshes/polyMesh/polyMeshUpdate.C
index 24d9ebbb136d1f7d751d2f30549d43d34896c533..7dcd3ba6b40eb1fdbf088af60b8a90c5e3f24991 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyMeshUpdate.C
+++ b/src/OpenFOAM/meshes/polyMesh/polyMeshUpdate.C
@@ -68,6 +68,11 @@ void Foam::polyMesh::updateMesh(const mapPolyMesh& mpm)
         newMotionPoints.map(oldMotionPoints, mpm.pointMap());
     }
 
+    // Reset valid directions (could change by faces put into empty patches)
+    geometricD_ = Vector<label>::zero;
+    solutionD_ = Vector<label>::zero;
+
+
     // Hack until proper callbacks. Below are all the polyMesh-MeshObjects.
 
     // pointMesh
diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C
index ecfff62ac3f9b3bb43cff0b9021f31a71780d08d..ddf162dd0f2910d2aaaf89a0f2465a26b86926b7 100644
--- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C
+++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/layerParameters/layerParameters.C
@@ -29,6 +29,7 @@ License
 #include "mathematicalConstants.H"
 #include "refinementSurfaces.H"
 #include "searchableSurfaces.H"
+#include "regExp.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -300,10 +301,44 @@ Foam::layerParameters::layerParameters
             //    readScalar(layerDict.lookup("minThickness"));
         }
     }
-}
 
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+    // Check whether layer specification matches any patches
+    const List<keyType> wildCards = layersDict.keys(true);
+
+    forAll(wildCards, i)
+    {
+        regExp re(wildCards[i]);
+
+        bool hasMatch = false;
+        forAll(boundaryMesh, patchI)
+        {
+            if (re.match(boundaryMesh[patchI].name()))
+            {
+                hasMatch = true;
+                break;
+            }
+        }
+        if (!hasMatch)
+        {
+            IOWarningIn("layerParameters::layerParameters(..)", layersDict)
+                << "Wildcard layer specification for " << wildCards[i]
+                << " does not match any patch." << endl;
+        }
+    }
+
+    const List<keyType> nonWildCards = layersDict.keys(false);
+
+    forAll(nonWildCards, i)
+    {
+        if (boundaryMesh.findPatchID(nonWildCards[i]) == -1)
+        {
+            IOWarningIn("layerParameters::layerParameters(..)", layersDict)
+                << "Layer specification for " << nonWildCards[i]
+                << " does not match any patch." << endl;
+        }
+    }
+}
 
 
 // ************************************************************************* //
diff --git a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C
index a626103cd1af105355aee538164e09ed9250a102..6bbb1c8d3987ebf35cc723c407340a3ad86f2962 100644
--- a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C
+++ b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C
@@ -265,101 +265,112 @@ Foam::refinementSurfaces::refinementSurfaces
     zoneInside_(surfacesDict.size()),
     regionOffset_(surfacesDict.size())
 {
-    labelList globalMinLevel(surfacesDict.size(), 0);
-    labelList globalMaxLevel(surfacesDict.size(), 0);
-    scalarField globalAngle(surfacesDict.size(), -GREAT);
-    List<Map<label> > regionMinLevel(surfacesDict.size());
-    List<Map<label> > regionMaxLevel(surfacesDict.size());
-    List<Map<scalar> > regionAngle(surfacesDict.size());
+    // Wilcard specification : loop over all surface, all regions
+    // and try to find a match.
 
+    // Count number of surfaces.
     label surfI = 0;
-    forAllConstIter(dictionary, surfacesDict, iter)
+    forAll(allGeometry.names(), geomI)
     {
-        names_[surfI] = iter().keyword();
+        const word& geomName = allGeometry_.names()[geomI];
 
-        surfaces_[surfI] = allGeometry_.findSurfaceID(names_[surfI]);
-
-        if (surfaces_[surfI] == -1)
+        if (surfacesDict.found(geomName))
         {
-            FatalErrorIn
-            (
-                "refinementSurfaces::refinementSurfaces"
-                "(const searchableSurfaces&, const dictionary>&"
-            )   << "No surface called " << iter().keyword() << endl
-                << "Valid surfaces are " << allGeometry_.names()
-                << exit(FatalError);
+            surfI++;
         }
-        const dictionary& dict = surfacesDict.subDict(iter().keyword());
+    }
 
-        const labelPair refLevel(dict.lookup("level"));
-        globalMinLevel[surfI] = refLevel[0];
-        globalMaxLevel[surfI] = refLevel[1];
+    // Size lists
+    surfaces_.setSize(surfI);
+    names_.setSize(surfI);
+    faceZoneNames_.setSize(surfI);
+    cellZoneNames_.setSize(surfI);
+    zoneInside_.setSize(surfI);
+    regionOffset_.setSize(surfI);
+
+    labelList globalMinLevel(surfI, 0);
+    labelList globalMaxLevel(surfI, 0);
+    scalarField globalAngle(surfI, -GREAT);
+    List<Map<label> > regionMinLevel(surfI);
+    List<Map<label> > regionMaxLevel(surfI);
+    List<Map<scalar> > regionAngle(surfI);
+
+    surfI = 0;
+    forAll(allGeometry.names(), geomI)
+    {
+        const word& geomName = allGeometry_.names()[geomI];
 
-        // Global zone names per surface
-        if (dict.found("faceZone"))
+        if (surfacesDict.found(geomName))
         {
-            dict.lookup("faceZone") >> faceZoneNames_[surfI];
-            dict.lookup("cellZone") >> cellZoneNames_[surfI];
-            dict.lookup("zoneInside") >> zoneInside_[surfI];
-        }
+            const dictionary& dict = surfacesDict.subDict(geomName);
 
-        // Global perpendicular angle
-        if (dict.found("perpendicularAngle"))
-        {
-            globalAngle[surfI] = readScalar(dict.lookup("perpendicularAngle"));
-        }
+            names_[surfI] = geomName;
+            surfaces_[surfI] = geomI;
 
-        if (dict.found("regions"))
-        {
-            const dictionary& regionsDict = dict.subDict("regions");
-            const wordList& regionNames =
-                allGeometry_[surfaces_[surfI]].regions();
+            const labelPair refLevel(dict.lookup("level"));
+            globalMinLevel[surfI] = refLevel[0];
+            globalMaxLevel[surfI] = refLevel[1];
 
-            forAllConstIter(dictionary, regionsDict, iter)
+            // Global zone names per surface
+            if (dict.found("faceZone"))
             {
-                const word& key = iter().keyword();
-
-                if (regionsDict.isDict(key))
-                {
-                    // Get the dictionary for region iter.keyword()
-                    const dictionary& regionDict = regionsDict.subDict(key);
-
-                    label regionI = findIndex(regionNames, key);
-                    if (regionI == -1)
-                    {
-                        FatalErrorIn
-                        (
-                            "refinementSurfaces::refinementSurfaces"
-                            "(const searchableSurfaces&, const dictionary>&"
-                        )   << "No region called " << key << " on surface "
-                            << allGeometry_[surfaces_[surfI]].name() << endl
-                            << "Valid regions are " << regionNames
-                            << exit(FatalError);
-                    }
+                dict.lookup("faceZone") >> faceZoneNames_[surfI];
+                dict.lookup("cellZone") >> cellZoneNames_[surfI];
+                dict.lookup("zoneInside") >> zoneInside_[surfI];
+            }
 
-                    const labelPair refLevel(regionDict.lookup("level"));
+            // Global perpendicular angle
+            if (dict.found("perpendicularAngle"))
+            {
+                globalAngle[surfI] = readScalar
+                (
+                    dict.lookup("perpendicularAngle")
+                );
+            }
 
-                    regionMinLevel[surfI].insert(regionI, refLevel[0]);
-                    regionMaxLevel[surfI].insert(regionI, refLevel[1]);
+            if (dict.found("regions"))
+            {
+                const dictionary& regionsDict = dict.subDict("regions");
+                const wordList& regionNames =
+                    allGeometry_[surfaces_[surfI]].regions();
 
-                    if (regionDict.found("perpendicularAngle"))
+                forAll(regionNames, regionI)
+                {
+                    if (regionsDict.found(regionNames[regionI]))
                     {
-                        regionAngle[surfI].insert
+                        // Get the dictionary for region 
+                        const dictionary& regionDict = regionsDict.subDict
                         (
-                            regionI,
-                            readScalar(regionDict.lookup("perpendicularAngle"))
+                            regionNames[regionI]
                         );
+
+                        const labelPair refLevel(regionDict.lookup("level"));
+
+                        regionMinLevel[surfI].insert(regionI, refLevel[0]);
+                        regionMaxLevel[surfI].insert(regionI, refLevel[1]);
+
+                        if (regionDict.found("perpendicularAngle"))
+                        {
+                            regionAngle[surfI].insert
+                            (
+                                regionI,
+                                readScalar
+                                (
+                                    regionDict.lookup("perpendicularAngle")
+                                )
+                            );
+                        }
                     }
                 }
             }
+            surfI++;
         }
-        surfI++;
     }
 
     // Calculate local to global region offset
     label nRegions = 0;
 
-    forAll(surfacesDict, surfI)
+    forAll(surfaces_, surfI)
     {
         regionOffset_[surfI] = nRegions;
         nRegions += allGeometry_[surfaces_[surfI]].regions().size();
diff --git a/src/finiteVolume/cfdTools/general/MRF/MRFZone.C b/src/finiteVolume/cfdTools/general/MRF/MRFZone.C
index 8bc4d3b938109171a57dbb8513f7a4d6ec753537..ab9709e993871b6aeaf16138e3f13408b664a591 100644
--- a/src/finiteVolume/cfdTools/general/MRF/MRFZone.C
+++ b/src/finiteVolume/cfdTools/general/MRF/MRFZone.C
@@ -29,6 +29,10 @@ License
 #include "volFields.H"
 #include "surfaceFields.H"
 #include "fvMatrices.H"
+#include "PackedList.H"
+#include "syncTools.H"
+
+#include "faceSet.H"
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
@@ -39,12 +43,15 @@ Foam::MRFZone::MRFZone(const fvMesh& mesh, Istream& is)
     dict_(is),
     cellZoneID_(mesh_.cellZones().findZoneID(name_)),
     faceZoneID_(mesh_.faceZones().findZoneID(name_)),
+    outsideFaces_(0),
     patchNames_(dict_.lookup("patches")),
     origin_(dict_.lookup("origin")),
     axis_(dict_.lookup("axis")),
     omega_(dict_.lookup("omega")),
     Omega_("Omega", omega_*axis_)
 {
+    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
+
     axis_ = axis_/mag(axis_);
     Omega_ = omega_*axis_;
 
@@ -65,18 +72,71 @@ Foam::MRFZone::MRFZone(const fvMesh& mesh, Istream& is)
 
     if (!faceZoneFound)
     {
-        FatalErrorIn
-        (
-            "Foam::MRFZone::MRFZone(const fvMesh& , const dictionary&)"
-        )   << "cannot find MRF faceZone " << name_
-            << exit(FatalError);
+        // Determine faces in cell zone
+        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        // (does not construct cells)
+
+        const labelList& own = mesh_.faceOwner();
+        const labelList& nei = mesh_.faceNeighbour();
+
+        // Cells in zone
+        PackedBoolList zoneCell(mesh_.nCells());
+
+        if (cellZoneID_ != -1)
+        {
+            const labelList& cellLabels = mesh_.cellZones()[cellZoneID_];
+            forAll(cellLabels, i)
+            {
+                zoneCell[cellLabels[i]] = 1u;
+            }
+        }
+
+
+        // Faces in zone
+        PackedBoolList zoneFacesSet(mesh_.nFaces());
+
+        for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
+        {
+            if
+            (
+                zoneCell.get(own[faceI]) == 1u
+             || zoneCell.get(nei[faceI]) == 1u
+            )
+            {
+                zoneFacesSet[faceI] = 1u;
+            }
+        }
+        syncTools::syncFaceList(mesh_, zoneFacesSet, orEqOp<unsigned int>());
+
+
+        // Transfer to labelList
+        label n = zoneFacesSet.count();
+        outsideFaces_.setSize(n);
+        n = 0;
+        forAll(zoneFacesSet, faceI)
+        {
+            if (zoneFacesSet.get(faceI) == 1u)
+            {
+                outsideFaces_[n++] = faceI;
+            }
+        }
+
+        Info<< nl
+            << "MRFZone " << name_ << " : did not find a faceZone; using "
+            << returnReduce(outsideFaces_.size(), sumOp<label>())
+            << " faces internal to cellZone instead." << endl;
+
+
+        // Flag use of outsideFaces
+        faceZoneID_ = -2;
     }
 
+
     patchLabels_.setSize(patchNames_.size());
 
     forAll(patchNames_, i)
     {
-        patchLabels_[i] = mesh_.boundaryMesh().findPatchID(patchNames_[i]);
+        patchLabels_[i] = patches.findPatchID(patchNames_[i]);
 
         if (patchLabels_[i] == -1)
         {
@@ -125,7 +185,13 @@ void Foam::MRFZone::relativeFlux(surfaceScalarField& phi) const
     const vector& origin = origin_.value();
     const vector& Omega = Omega_.value();
 
-    const labelList& faces = mesh_.faceZones()[faceZoneID_];
+    // Use either zone faces or outsideFaces_
+    const labelList& faces =
+    (
+        faceZoneID_ == -2
+      ? outsideFaces_
+      : mesh_.faceZones()[faceZoneID_]
+    );
 
     forAll(faces, i)
     {
diff --git a/src/finiteVolume/cfdTools/general/MRF/MRFZone.H b/src/finiteVolume/cfdTools/general/MRF/MRFZone.H
index 3ffb4e461a853a7703ee7a5a9038bc99893c5efb..7c489ed25bba06d0e9e44334ff609ced8fbd0f57 100644
--- a/src/finiteVolume/cfdTools/general/MRF/MRFZone.H
+++ b/src/finiteVolume/cfdTools/general/MRF/MRFZone.H
@@ -26,7 +26,7 @@ Class
     Foam::MRFZone
 
 Description
-    MRF zone definition based on both cell and face zones and parameters
+    MRF zone definition based on cell zone and optional face zone and parameters
     obtained from a control dictionary constructed from the given stream.
 
     The rotation of the MRF region is defined by an origin and axis of
@@ -68,18 +68,26 @@ class MRFZone
 
         const fvMesh& mesh_;
 
-        word name_;
+        const word name_;
 
-        dictionary dict_;
+        const dictionary dict_;
 
         label cellZoneID_;
+
+        //- label of face zone with faces on outside of cell zone.
+        //  If -2 determines outside faces itself
         label faceZoneID_;
-        wordList patchNames_;
+
+        //- outside faces (only if faceZoneID = -2)
+        labelList outsideFaces_;
+
+
+        const wordList patchNames_;
         labelList patchLabels_;
 
-        dimensionedVector origin_;
+        const dimensionedVector origin_;
         dimensionedVector axis_;
-        dimensionedScalar omega_;
+        const dimensionedScalar omega_;
         dimensionedVector Omega_;
 
 
diff --git a/src/finiteVolume/finiteVolume/snGradSchemes/quadraticFitSnGrad/quadraticFitSnGradData.C b/src/finiteVolume/finiteVolume/snGradSchemes/quadraticFitSnGrad/quadraticFitSnGradData.C
index 133f1e79332a307bb6cf73a57a9cdc30077a732f..6bef8de896812095279f28d7a1d066104d81de39 100644
--- a/src/finiteVolume/finiteVolume/snGradSchemes/quadraticFitSnGrad/quadraticFitSnGradData.C
+++ b/src/finiteVolume/finiteVolume/snGradSchemes/quadraticFitSnGrad/quadraticFitSnGradData.C
@@ -140,11 +140,11 @@ void Foam::quadraticFitSnGradData::findFaceDirs
     #ifndef SPHERICAL_GEOMETRY
         if (mesh.nGeometricD() <= 2) // find the normal direcion
         {
-            if (mesh.directions()[0] == -1)
+            if (mesh.geometricD()[0] == -1)
             {
                 kdir = vector(1, 0, 0);
             }
-            else if (mesh.directions()[1] == -1)
+            else if (mesh.geometricD()[1] == -1)
             {
                 kdir = vector(0, 1, 0);
             }
@@ -153,7 +153,7 @@ void Foam::quadraticFitSnGradData::findFaceDirs
                 kdir = vector(0, 0, 1);
             }
         }
-        else // 3D so find a direction in the place of the face
+        else // 3D so find a direction in the plane of the face
         {
             const face& f = mesh.faces()[faci];
             kdir = mesh.points()[f[0]] - mesh.points()[f[1]];
diff --git a/src/finiteVolume/fvMatrices/fvMatrix/fvMatrix.C b/src/finiteVolume/fvMatrices/fvMatrix/fvMatrix.C
index e1ef6135a6c407e754baa42ea404bcb345aa3c76..2134420eadf769f6e09dd30b5dd3d622757714ec 100644
--- a/src/finiteVolume/fvMatrices/fvMatrix/fvMatrix.C
+++ b/src/finiteVolume/fvMatrices/fvMatrix/fvMatrix.C
@@ -713,7 +713,7 @@ Foam::fvMatrix<Type>::H() const
     (
         pow
         (
-            psi_.mesh().directions(),
+            psi_.mesh().solutionD(),
             pTraits<typename powProduct<Vector<label>, Type::rank>::type>::zero
         )
     );
diff --git a/src/finiteVolume/fvMatrices/fvMatrix/fvMatrixSolve.C b/src/finiteVolume/fvMatrices/fvMatrix/fvMatrixSolve.C
index e8f4e6de494b64a43e0f24ffa77ec1838a4ab4ec..21f3738a02692932c687d8d02c07e365b661b0e0 100644
--- a/src/finiteVolume/fvMatrices/fvMatrix/fvMatrixSolve.C
+++ b/src/finiteVolume/fvMatrices/fvMatrix/fvMatrixSolve.C
@@ -82,7 +82,7 @@ Foam::lduMatrix::solverPerformance Foam::fvMatrix<Type>::solve
     (
         pow
         (
-            psi_.mesh().directions(),
+            psi_.mesh().solutionD(),
             pTraits<typename powProduct<Vector<label>, Type::rank>::type>::zero
         )
     );
diff --git a/src/finiteVolume/interpolation/surfaceInterpolation/schemes/FitData/FitData.C b/src/finiteVolume/interpolation/surfaceInterpolation/schemes/FitData/FitData.C
index 0872cb81a9c3cdc33fd43e20353b745a37d17590..28a3c41e64d68edde533776ab6cb4317eacef0b0 100644
--- a/src/finiteVolume/interpolation/surfaceInterpolation/schemes/FitData/FitData.C
+++ b/src/finiteVolume/interpolation/surfaceInterpolation/schemes/FitData/FitData.C
@@ -83,11 +83,11 @@ void Foam::FitData<FitDataType, ExtendedStencil, Polynomial>::findFaceDirs
 #   ifndef SPHERICAL_GEOMETRY
     if (mesh.nGeometricD() <= 2) // find the normal direction
     {
-        if (mesh.directions()[0] == -1)
+        if (mesh.geometricD()[0] == -1)
         {
             kdir = vector(1, 0, 0);
         }
-        else if (mesh.directions()[1] == -1)
+        else if (mesh.geometricD()[1] == -1)
         {
             kdir = vector(0, 1, 0);
         }
@@ -115,7 +115,7 @@ void Foam::FitData<FitDataType, ExtendedStencil, Polynomial>::findFaceDirs
 
         if (magk < SMALL)
         {
-            FatalErrorIn("findFaceDirs") << " calculated kdir = zero"
+            FatalErrorIn("findFaceDirs(..)") << " calculated kdir = zero"
                 << exit(FatalError);
         }
         else
diff --git a/src/meshTools/Make/files b/src/meshTools/Make/files
index a93cd58400f6dfb5c138fa3e1f67b0252df6139a..9f849c58945b11d04d9193da1fe201653c09f01d 100644
--- a/src/meshTools/Make/files
+++ b/src/meshTools/Make/files
@@ -60,6 +60,7 @@ $(searchableSurface)/searchablePlane.C
 $(searchableSurface)/searchablePlate.C
 $(searchableSurface)/searchableSphere.C
 $(searchableSurface)/searchableSurface.C
+$(searchableSurface)/searchableSurfaceCollection.C
 $(searchableSurface)/searchableSurfaces.C
 $(searchableSurface)/searchableSurfacesQueries.C
 $(searchableSurface)/searchableSurfaceWithGaps.C
diff --git a/src/meshTools/cellDist/wallPoint/wallPoint.H b/src/meshTools/cellDist/wallPoint/wallPoint.H
index 0544b6ce361ea8d9f4143987703f83765b3996cf..82d6b385af96d0efe538574416ec70a3d41f579d 100644
--- a/src/meshTools/cellDist/wallPoint/wallPoint.H
+++ b/src/meshTools/cellDist/wallPoint/wallPoint.H
@@ -51,6 +51,12 @@ namespace Foam
 // Forward declaration of classes
 class polyPatch;
 class polyMesh;
+class wallPoint;
+
+// Forward declaration of friend functions and operators
+Ostream& operator<<(Ostream&, const wallPoint&);
+Istream& operator>>(Istream&, wallPoint&);
+
 
 /*---------------------------------------------------------------------------*\
                            Class wallPoint Declaration
@@ -78,12 +84,15 @@ class wallPoint
             const scalar tol
         );
 
+
 public:
+
     // Static data members
 
         //- initial point far away.
         static point greatPoint;
 
+
     // Constructors
 
         //- Construct null
@@ -102,6 +111,7 @@ public:
             const wallPoint&
         );
 
+
     // Member Functions
 
         // Access
@@ -184,11 +194,11 @@ public:
                 const scalar tol
             );
 
+
     // Member Operators
 
         // Needed for List IO
         inline bool operator==(const wallPoint&) const;
-
         inline bool operator!=(const wallPoint&) const;
 
 
diff --git a/src/meshTools/meshTools/meshTools.C b/src/meshTools/meshTools/meshTools.C
index a4f57a8de844d777f6ba7dd6aa4161a95b3f5dd8..f826675b30a0fd9ed2985c1459cf3d88035cead9 100644
--- a/src/meshTools/meshTools/meshTools.C
+++ b/src/meshTools/meshTools/meshTools.C
@@ -25,7 +25,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "meshTools.H"
-#include "primitiveMesh.H"
+#include "polyMesh.H"
 #include "hexMatcher.H"
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
@@ -635,6 +635,103 @@ Foam::label Foam::meshTools::walkFace
 }
 
 
+void Foam::meshTools::constrainToMeshCentre(const polyMesh& mesh, point& pt)
+{
+    const Vector<label>& dirs = mesh.geometricD();
+    const point& min = mesh.bounds().min();
+    const point& max = mesh.bounds().max();
+
+    for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
+    {
+        if (dirs[cmpt] == -1)
+        {
+            pt[cmpt] = 0.5*(min[cmpt]+max[cmpt]);
+        }
+    }
+}
+
+
+void Foam::meshTools::constrainToMeshCentre
+(
+    const polyMesh& mesh,
+    pointField& pts
+)
+{
+    const Vector<label>& dirs = mesh.geometricD();
+    const point& min = mesh.bounds().min();
+    const point& max = mesh.bounds().max();
+
+    bool isConstrained = false;
+    for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
+    {
+        if (dirs[cmpt] == -1)
+        {
+            isConstrained = true;
+            break;
+        }
+    }
+
+    if (isConstrained)
+    {
+        forAll(pts, i)
+        {
+            for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
+            {
+                if (dirs[cmpt] == -1)
+                {
+                    pts[i][cmpt] = 0.5*(min[cmpt]+max[cmpt]);
+                }
+            }
+        }
+    }
+}
+
+
+//- Set the constrained components of directions/velocity to zero
+void Foam::meshTools::constrainDirection(const polyMesh& mesh, vector& d)
+{
+    const Vector<label>& dirs = mesh.geometricD();
+
+    for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
+    {
+        if (dirs[cmpt] == -1)
+        {
+            d[cmpt] = 0.0;
+        }
+    }
+}
+
+
+void Foam::meshTools::constrainDirection(const polyMesh& mesh, vectorField& d)
+{
+    const Vector<label>& dirs = mesh.geometricD();
+
+    bool isConstrained = false;
+    for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
+    {
+        if (dirs[cmpt] == -1)
+        {
+            isConstrained = true;
+            break;
+        }
+    }
+
+    if (isConstrained)
+    {
+        forAll(d, i)
+        {
+            for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
+            {
+                if (dirs[cmpt] == -1)
+                {
+                    d[i][cmpt] = 0.0;
+                }
+            }
+        }
+    }
+}
+
+
 void Foam::meshTools::getParallelEdges
 (
     const primitiveMesh& mesh,
diff --git a/src/meshTools/meshTools/meshTools.H b/src/meshTools/meshTools/meshTools.H
index 304159e04589cc22006931636049ba4d128f10ef..3710d5af06250dc654465ebcba5bb47697f13465 100644
--- a/src/meshTools/meshTools/meshTools.H
+++ b/src/meshTools/meshTools/meshTools.H
@@ -50,7 +50,7 @@ namespace Foam
 {
 
 class primitiveMesh;
-
+class polyMesh;
 
 /*---------------------------------------------------------------------------*\
                         Namespace meshTools Declaration
@@ -81,196 +81,212 @@ namespace meshTools
     static const label pXpYpZMask = 1 << pXpYpZ;
 
 
-    //- Check if n is in same direction as normals of all faceLabels
-    bool visNormal
-    (
-        const vector& n,
-        const vectorField& faceNormals,
-        const labelList& faceLabels
-    );
-
-    //- Calculate point normals on a 'box' mesh (all edges aligned with
-    //  coordinate axes)
-    vectorField calcBoxPointNormals(const primitivePatch& pp);
-
-    //- Normalized edge vector
-    vector normEdgeVec(const primitiveMesh&, const label edgeI);
-
-    //- Write obj representation of point
-    void writeOBJ
-    (
-        Ostream& os,
-        const point& pt
-    );
-
-
-    //- Write obj representation of faces subset
-    void writeOBJ
-    (
-        Ostream& os,
-        const faceList&,
-        const pointField&,
-        const labelList& faceLabels
-    );
-
-    //- Write obj representation of faces
-    void writeOBJ
-    (
-        Ostream& os,
-        const faceList&,
-        const pointField&
-    );
-
-    //- Write obj representation of cell subset
-    void writeOBJ
-    (
-        Ostream& os,
-        const cellList&,
-        const faceList&,
-        const pointField&,
-        const labelList& cellLabels
-    );
-
-    //- Is edge used by cell
-    bool edgeOnCell
-    (
-        const primitiveMesh&,
-        const label cellI,
-        const label edgeI
-    );
-
-    //- Is edge used by face
-    bool edgeOnFace
-    (
-        const primitiveMesh&,
-        const label faceI,
-        const label edgeI
-    );
-    
-    //- Is face used by cell
-    bool faceOnCell
-    (
-        const primitiveMesh&,
-        const label cellI,
-        const label faceI
-    );
-
-    //- Return edge among candidates that uses the two vertices.
-    label findEdge
-    (
-        const edgeList& edges,
-        const labelList& candidates,
-        const label v0,
-        const label v1
-    );
-
-    //- Return edge between two vertices. Returns -1 if no edge.
-    label findEdge
-    (
-        const primitiveMesh&,
-        const label v0,
-        const label v1
-    );
-
-    //- Return edge shared by two faces. Throws error if no edge found.
-    label getSharedEdge
-    (
-        const primitiveMesh&,
-        const label f0,
-        const label f1
-    );
-    
-    //- Return face shared by two cells. Throws error if none found.
-    label getSharedFace
-    (
-        const primitiveMesh&,
-        const label cell0,
-        const label cell1
-    );
-
-    //- Get faces on cell using edgeI. Throws error if no two found.
-    void getEdgeFaces
-    (
-        const primitiveMesh&,
-        const label cellI,
-        const label edgeI,
-        label& face0,
-        label& face1
-    );
-
-    //- Return label of other edge (out of candidates edgeLabels)
-    //  connected to vertex but not edgeI. Throws error if none found.
-    label otherEdge
-    (
-        const primitiveMesh&,
-        const labelList& edgeLabels,
-        const label edgeI,
-        const label vertI
-    );
-    
-    //- Return face on cell using edgeI but not faceI. Throws error 
-    //  if none found.
-    label otherFace
-    (
-        const primitiveMesh&,
-        const label cellI,
-        const label faceI,
-        const label edgeI
-    );
-
-    //- Return cell on other side of face. Throws error 
-    //  if face not internal.
-    label otherCell
-    (
-        const primitiveMesh&,
-        const label cellI,
-        const label faceI
-    );
-    
-    //- Returns label of edge nEdges away from startEdge (in the direction
-    // of startVertI)
-    label walkFace
-    (
-        const primitiveMesh&,
-        const label faceI,
-        const label startEdgeI,
-        const label startVertI,
-        const label nEdges
-    );
+    // Normal handling
+
+        //- Check if n is in same direction as normals of all faceLabels
+        bool visNormal
+        (
+            const vector& n,
+            const vectorField& faceNormals,
+            const labelList& faceLabels
+        );
+
+        //- Calculate point normals on a 'box' mesh (all edges aligned with
+        //  coordinate axes)
+        vectorField calcBoxPointNormals(const primitivePatch& pp);
+
+        //- Normalized edge vector
+        vector normEdgeVec(const primitiveMesh&, const label edgeI);
+
+
+    // OBJ writing
+
+        //- Write obj representation of point
+        void writeOBJ
+        (
+            Ostream& os,
+            const point& pt
+        );
+
+        //- Write obj representation of faces subset
+        void writeOBJ
+        (
+            Ostream& os,
+            const faceList&,
+            const pointField&,
+            const labelList& faceLabels
+        );
+
+        //- Write obj representation of faces
+        void writeOBJ
+        (
+            Ostream& os,
+            const faceList&,
+            const pointField&
+        );
+
+        //- Write obj representation of cell subset
+        void writeOBJ
+        (
+            Ostream& os,
+            const cellList&,
+            const faceList&,
+            const pointField&,
+            const labelList& cellLabels
+        );
+
+
+    // Cell/face/edge walking
+
+        //- Is edge used by cell
+        bool edgeOnCell
+        (
+            const primitiveMesh&,
+            const label cellI,
+            const label edgeI
+        );
+
+        //- Is edge used by face
+        bool edgeOnFace
+        (
+            const primitiveMesh&,
+            const label faceI,
+            const label edgeI
+        );
+
+        //- Is face used by cell
+        bool faceOnCell
+        (
+            const primitiveMesh&,
+            const label cellI,
+            const label faceI
+        );
+
+        //- Return edge among candidates that uses the two vertices.
+        label findEdge
+        (
+            const edgeList& edges,
+            const labelList& candidates,
+            const label v0,
+            const label v1
+        );
+
+        //- Return edge between two vertices. Returns -1 if no edge.
+        label findEdge
+        (
+            const primitiveMesh&,
+            const label v0,
+            const label v1
+        );
+
+        //- Return edge shared by two faces. Throws error if no edge found.
+        label getSharedEdge
+        (
+            const primitiveMesh&,
+            const label f0,
+            const label f1
+        );
+
+        //- Return face shared by two cells. Throws error if none found.
+        label getSharedFace
+        (
+            const primitiveMesh&,
+            const label cell0,
+            const label cell1
+        );
+
+        //- Get faces on cell using edgeI. Throws error if no two found.
+        void getEdgeFaces
+        (
+            const primitiveMesh&,
+            const label cellI,
+            const label edgeI,
+            label& face0,
+            label& face1
+        );
+
+        //- Return label of other edge (out of candidates edgeLabels)
+        //  connected to vertex but not edgeI. Throws error if none found.
+        label otherEdge
+        (
+            const primitiveMesh&,
+            const labelList& edgeLabels,
+            const label edgeI,
+            const label vertI
+        );
+
+        //- Return face on cell using edgeI but not faceI. Throws error 
+        //  if none found.
+        label otherFace
+        (
+            const primitiveMesh&,
+            const label cellI,
+            const label faceI,
+            const label edgeI
+        );
+
+        //- Return cell on other side of face. Throws error 
+        //  if face not internal.
+        label otherCell
+        (
+            const primitiveMesh&,
+            const label cellI,
+            const label faceI
+        );
+
+        //- Returns label of edge nEdges away from startEdge (in the direction
+        // of startVertI)
+        label walkFace
+        (
+            const primitiveMesh&,
+            const label faceI,
+            const label startEdgeI,
+            const label startVertI,
+            const label nEdges
+        );
+
+
+    // Constraints on position
+
+        //- Set the constrained components of position to mesh centre
+        void constrainToMeshCentre(const polyMesh&, point&);
+        void constrainToMeshCentre(const polyMesh&, pointField&);
+
+        //- Set the constrained components of directions/velocity to zero
+        void constrainDirection(const polyMesh&, vector&);
+        void constrainDirection(const polyMesh&, vectorField&);
 
     
-    //
     // Hex only functionality.
-    //
-
-    //- Given edge on hex find other 'parallel', non-connected edges.
-    void getParallelEdges
-    (
-        const primitiveMesh&,
-        const label cellI,
-        const label e0,
-        label&,
-        label&,
-        label&
-    );
-
-    //- Given edge on hex find all 'parallel' (i.e. non-connected)
-    //  edges and average direction of them
-    vector edgeToCutDir
-    (
-        const primitiveMesh&,
-        const label cellI,
-        const label edgeI
-    );
-
-    //- Reverse of edgeToCutDir: given direction find edge bundle and
-    //  return one of them.
-    label cutDirToEdge
-    (
-        const primitiveMesh&,
-        const label cellI,
-        const vector& cutDir
-    );
+
+        //- Given edge on hex find other 'parallel', non-connected edges.
+        void getParallelEdges
+        (
+            const primitiveMesh&,
+            const label cellI,
+            const label e0,
+            label&,
+            label&,
+            label&
+        );
+
+        //- Given edge on hex find all 'parallel' (i.e. non-connected)
+        //  edges and average direction of them
+        vector edgeToCutDir
+        (
+            const primitiveMesh&,
+            const label cellI,
+            const label edgeI
+        );
+
+        //- Reverse of edgeToCutDir: given direction find edge bundle and
+        //  return one of them.
+        label cutDirToEdge
+        (
+            const primitiveMesh&,
+            const label cellI,
+            const vector& cutDir
+        );
     
 } // End namespace meshTools
 
diff --git a/src/meshTools/searchableSurface/distributedTriSurfaceMesh.C b/src/meshTools/searchableSurface/distributedTriSurfaceMesh.C
index 06020467036039319af49714caa501e7d74ae6b5..7f86c0f6581fcd94504b9cb7d39fdc67284a4506 100644
--- a/src/meshTools/searchableSurface/distributedTriSurfaceMesh.C
+++ b/src/meshTools/searchableSurface/distributedTriSurfaceMesh.C
@@ -76,10 +76,8 @@ bool Foam::distributedTriSurfaceMesh::read()
     // Distribution type
     distType_ = distributionTypeNames_.read(dict_.lookup("distributionType"));
 
-    if (dict_.found("mergeDistance"))
-    {
-        dict_.lookup("mergeDistance") >> mergeDist_;
-    }
+    // Merge distance
+    mergeDist_ = readScalar(dict_.lookup("mergeDistance"));
 
     return true;
 }
@@ -1341,25 +1339,44 @@ Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
     dict_(io, dict)
 {
     read();
+
+    if (debug)
+    {
+        Info<< "Constructed from triSurface:" << endl;
+        writeStats(Info);
+
+        labelList nTris(Pstream::nProcs());
+        nTris[Pstream::myProcNo()] = triSurface::size();
+        Pstream::gatherList(nTris);
+        Pstream::scatterList(nTris);
+
+        Info<< endl<< "\tproc\ttris\tbb" << endl;
+        forAll(nTris, procI)
+        {
+            Info<< '\t' << procI << '\t' << nTris[procI]
+                 << '\t' << procBb_[procI] << endl;
+        }
+        Info<< endl;
+    }
 }
 
 
 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh(const IOobject& io)
 :
-    triSurfaceMesh(io),
-//    triSurfaceMesh
-//    (
-//        IOobject
-//        (
-//            io.name(),
-//            io.db().time().findInstanceDir(io.local()),
-//            io.local(),
-//            io.db(),
-//            io.readOpt(),
-//            io.writeOpt(),
-//            io.registerObject()
-//        )
-//    ),
+    //triSurfaceMesh(io),
+    triSurfaceMesh
+    (
+        IOobject
+        (
+            io.name(),
+            io.time().findInstance(io.local(), word::null),
+            io.local(),
+            io.db(),
+            io.readOpt(),
+            io.writeOpt(),
+            io.registerObject()
+        )
+    ),
     dict_
     (
         IOobject
@@ -1375,6 +1392,26 @@ Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh(const IOobject& io)
     )
 {
     read();
+
+    if (debug)
+    {
+        Info<< "Read distributedTriSurface from " << io.objectPath()
+            << ':' << endl;
+        writeStats(Info);
+
+        labelList nTris(Pstream::nProcs());
+        nTris[Pstream::myProcNo()] = triSurface::size();
+        Pstream::gatherList(nTris);
+        Pstream::scatterList(nTris);
+
+        Info<< endl<< "\tproc\ttris\tbb" << endl;
+        forAll(nTris, procI)
+        {
+            Info<< '\t' << procI << '\t' << nTris[procI]
+                 << '\t' << procBb_[procI] << endl;
+        }
+        Info<< endl;
+    }
 }
 
 
@@ -1384,21 +1421,21 @@ Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
     const dictionary& dict
 )
 :
-    triSurfaceMesh(io, dict),
-//    triSurfaceMesh
-//    (
-//        IOobject
-//        (
-//            io.name(),
-//            io.db().time().findInstanceDir(io.local()),
-//            io.local(),
-//            io.db(),
-//            io.readOpt(),
-//            io.writeOpt(),
-//            io.registerObject()
-//        ),
-//        dict
-//    ),
+    //triSurfaceMesh(io, dict),
+    triSurfaceMesh
+    (
+        IOobject
+        (
+            io.name(),
+            io.time().findInstance(io.local(), word::null),
+            io.local(),
+            io.db(),
+            io.readOpt(),
+            io.writeOpt(),
+            io.registerObject()
+        ),
+        dict
+    ),
     dict_
     (
         IOobject
@@ -1414,6 +1451,26 @@ Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
     )
 {
     read();
+
+    if (debug)
+    {
+        Info<< "Read distributedTriSurface from " << io.objectPath()
+            << " and dictionary:" << endl;
+        writeStats(Info);
+
+        labelList nTris(Pstream::nProcs());
+        nTris[Pstream::myProcNo()] = triSurface::size();
+        Pstream::gatherList(nTris);
+        Pstream::scatterList(nTris);
+
+        Info<< endl<< "\tproc\ttris\tbb" << endl;
+        forAll(nTris, procI)
+        {
+            Info<< '\t' << procI << '\t' << nTris[procI]
+                 << '\t' << procBb_[procI] << endl;
+        }
+        Info<< endl;
+    }
 }
 
 
@@ -2416,6 +2473,8 @@ void Foam::distributedTriSurfaceMesh::writeStats(Ostream& os) const
     boundBox bb;
     label nPoints;
     calcBounds(bb, nPoints);
+    reduce(bb.min(), minOp<point>());
+    reduce(bb.max(), maxOp<point>());
 
     os  << "Triangles    : " << returnReduce(triSurface::size(), sumOp<label>())
         << endl
diff --git a/src/meshTools/searchableSurface/distributedTriSurfaceMesh.H b/src/meshTools/searchableSurface/distributedTriSurfaceMesh.H
index 733cd24891e21befee9e9318fa301180bc3f8966..4d5f7dfd173edd6ccb3c559221de0564d46edc50 100644
--- a/src/meshTools/searchableSurface/distributedTriSurfaceMesh.H
+++ b/src/meshTools/searchableSurface/distributedTriSurfaceMesh.H
@@ -91,15 +91,14 @@ public:
 
 private:
 
+    // Private member data
+
         //- Merging distance
         scalar mergeDist_;
 
         //- Decomposition used when independently decomposing surface.
         autoPtr<decompositionMethod> decomposer_;
 
-
-    // Private member data
-
         //- Bounding box settings
         IOdictionary dict_;
 
@@ -317,10 +316,11 @@ public:
             const dictionary& dict
         );
 
-        //- Construct read
+        //- Construct read. Does findInstance to find io.local().
         distributedTriSurfaceMesh(const IOobject& io);
 
-        //- Construct from dictionary (used by searchableSurface)
+        //- Construct from dictionary (used by searchableSurface).
+        //  Does read. Does findInstance to find io.local().
         distributedTriSurfaceMesh
         (
             const IOobject& io,
diff --git a/src/meshTools/searchableSurface/searchableSphere.C b/src/meshTools/searchableSurface/searchableSphere.C
index ba5a1888cfb343f39605b49b8111083427d7562c..287ae6743c2bb508c0ef64322036fac617123dcd 100644
--- a/src/meshTools/searchableSurface/searchableSphere.C
+++ b/src/meshTools/searchableSurface/searchableSphere.C
@@ -53,7 +53,14 @@ Foam::pointIndexHit Foam::searchableSphere::findNearest
 
     if (nearestDistSqr > sqr(magN-radius_))
     {
-        info.rawPoint() = centre_ + n/magN*radius_;
+        if (magN < ROOTVSMALL)
+        {
+            info.rawPoint() = centre_ + vector(1,0,0)/magN*radius_;
+        }
+        else
+        {
+            info.rawPoint() = centre_ + n/magN*radius_;
+        }
         info.setHit();
         info.setIndex(0);
     }
diff --git a/src/meshTools/searchableSurface/searchableSurfaceCollection.C b/src/meshTools/searchableSurface/searchableSurfaceCollection.C
new file mode 100644
index 0000000000000000000000000000000000000000..ce6ddd643122703e9214fc6041a5a76265b098f4
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableSurfaceCollection.C
@@ -0,0 +1,525 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+\*---------------------------------------------------------------------------*/
+
+#include "searchableSurfaceCollection.H"
+#include "addToRunTimeSelectionTable.H"
+#include "SortableList.H"
+#include "Time.H"
+#include "ListOps.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+defineTypeNameAndDebug(searchableSurfaceCollection, 0);
+addToRunTimeSelectionTable(searchableSurface, searchableSurfaceCollection, dict);
+
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::searchableSurfaceCollection::findNearest
+(
+    const pointField& samples,
+    scalarField& minDistSqr,
+    List<pointIndexHit>& nearestInfo,
+    labelList& nearestSurf
+) const
+{
+    // Initialise
+    nearestInfo.setSize(samples.size());
+    nearestInfo = pointIndexHit();
+    nearestSurf.setSize(samples.size());
+    nearestSurf = -1;
+
+    List<pointIndexHit> hitInfo(samples.size());
+
+    const scalarField localMinDistSqr(samples.size(), GREAT);
+
+    forAll(subGeom_, surfI)
+    {
+        // Transform then divide
+        tmp<pointField> localSamples = cmptDivide
+        (
+            transform_[surfI].localPosition(samples),
+            scale_[surfI]
+        );
+
+        subGeom_[surfI].findNearest(localSamples, localMinDistSqr, hitInfo);
+
+        forAll(hitInfo, pointI)
+        {
+            if (hitInfo[pointI].hit())
+            {
+                // Rework back into global coordinate sys. Multiply then
+                // transform
+                point globalPt = transform_[surfI].globalPosition
+                (
+                    cmptMultiply
+                    (
+                        hitInfo[pointI].rawPoint(),
+                        scale_[surfI]
+                    )
+                );
+
+                scalar distSqr = magSqr(globalPt - samples[pointI]);
+
+                if (distSqr < minDistSqr[pointI])
+                {
+                    minDistSqr[pointI] = distSqr;
+                    nearestInfo[pointI].setPoint(globalPt);
+                    nearestInfo[pointI].setHit();
+                    nearestInfo[pointI].setIndex(hitInfo[pointI].index());
+                    nearestSurf[pointI] = surfI;
+                }
+            }
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::searchableSurfaceCollection::searchableSurfaceCollection
+(
+    const IOobject& io,
+    const dictionary& dict
+)
+:
+    searchableSurface(io),
+    instance_(dict.size()),
+    scale_(dict.size()),
+    transform_(dict.size()),
+    subGeom_(dict.size())
+{
+    Info<< "SearchableCollection : " << name() << endl;
+
+    label surfI = 0;
+    forAllConstIter(dictionary, dict, iter)
+    {
+        if (dict.isDict(iter().keyword()))
+        {
+            instance_[surfI] = iter().keyword();
+
+            const dictionary& subDict = dict.subDict(instance_[surfI]);
+
+            scale_[surfI] = subDict.lookup("scale");
+            transform_.set
+            (
+                surfI,
+                coordinateSystem::New
+                (
+                    "",
+                    subDict.subDict("transform")
+                )
+            );
+
+            const word subGeomName(subDict.lookup("surface"));
+            //Pout<< "Trying to find " << subGeomName << endl;
+
+            const searchableSurface& s =
+                io.db().lookupObject<searchableSurface>(subGeomName);
+
+            subGeom_.set(surfI, &const_cast<searchableSurface&>(s));
+
+            Info<< "    instance : " << instance_[surfI] << endl;
+            Info<< "    surface  : " << s.name() << endl;
+            Info<< "    scale    : " << scale_[surfI] << endl;
+            Info<< "    coordsys : " << transform_[surfI] << endl;
+
+            surfI++;
+        }
+    }
+    instance_.setSize(surfI);
+    scale_.setSize(surfI);
+    transform_.setSize(surfI);
+    subGeom_.setSize(surfI);
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::searchableSurfaceCollection::~searchableSurfaceCollection()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+const Foam::wordList& Foam::searchableSurfaceCollection::regions() const
+{
+    if (regions_.size() == 0)
+    {
+        regionOffset_.setSize(subGeom_.size());
+
+        DynamicList<word> allRegions;
+        forAll(subGeom_, surfI)
+        {
+            regionOffset_[surfI] = allRegions.size();
+
+            const wordList& subRegions = subGeom_[surfI].regions();
+
+            forAll(subRegions, i)
+            {
+                //allRegions.append(subRegions[i] + "_" + Foam::name(surfI));
+                allRegions.append(instance_[surfI] + "_" + subRegions[i]);
+            }
+        }
+        regions_.transfer(allRegions.shrink());
+    }
+    return regions_;
+}
+
+
+Foam::label Foam::searchableSurfaceCollection::size() const
+{
+    label n = 0;
+    forAll(subGeom_, surfI)
+    {
+        n += subGeom_[surfI].size();
+    }
+    return n;
+}
+
+
+void Foam::searchableSurfaceCollection::findNearest
+(
+    const pointField& samples,
+    const scalarField& nearestDistSqr,
+    List<pointIndexHit>& nearestInfo
+) const
+{
+    // How to scale distance?
+    scalarField minDistSqr(nearestDistSqr);
+
+    labelList nearestSurf;
+    findNearest
+    (
+        samples,
+        minDistSqr,
+        nearestInfo,
+        nearestSurf
+    );
+}
+
+
+void Foam::searchableSurfaceCollection::findLine
+(
+    const pointField& start,
+    const pointField& end,
+    List<pointIndexHit>& info
+) const
+{
+    info.setSize(start.size());
+    info = pointIndexHit();
+
+    // Current nearest (to start) intersection
+    pointField nearest(end);
+
+    List<pointIndexHit> hitInfo(start.size());
+
+    forAll(subGeom_, surfI)
+    {
+        // Starting point
+        tmp<pointField> e0 = cmptDivide
+        (
+            transform_[surfI].localPosition
+            (
+                start
+            ),
+            scale_[surfI]
+        );
+
+        // Current best end point
+        tmp<pointField> e1 = cmptDivide
+        (
+            transform_[surfI].localPosition
+            (
+                nearest
+            ),
+            scale_[surfI]
+        );
+
+        subGeom_[surfI].findLine(e0, e1, hitInfo);
+
+        forAll(hitInfo, pointI)
+        {
+            if (hitInfo[pointI].hit())
+            {
+                // Transform back to global coordinate sys.
+                nearest[pointI] = transform_[surfI].globalPosition
+                (
+                    cmptMultiply
+                    (
+                        hitInfo[pointI].rawPoint(),
+                        scale_[surfI]
+                    )
+                );
+                info[pointI] = hitInfo[pointI];
+                info[pointI].rawPoint() = nearest[pointI];
+            }
+        }
+    }
+
+
+    // Debug check
+    if (false)
+    {
+        forAll(info, pointI)
+        {
+            if (info[pointI].hit())
+            {
+                vector n(end[pointI] - start[pointI]);
+                scalar magN = mag(n);
+
+                if (magN > SMALL)
+                {
+                    n /= mag(n);
+
+                    scalar s = ((info[pointI].rawPoint()-start[pointI])&n);
+
+                    if (s < 0 || s > 1)
+                    {
+                        FatalErrorIn
+                        (
+                            "searchableSurfaceCollection::findLine(..)"
+                        )   << "point:" << info[pointI]
+                            << " s:" << s
+                            << " outside vector "
+                            << " start:" << start[pointI]
+                            << " end:" << end[pointI]
+                            << abort(FatalError);
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+void Foam::searchableSurfaceCollection::findLineAny
+(
+    const pointField& start,
+    const pointField& end,
+    List<pointIndexHit>& info
+) const
+{
+    // To be done ...
+    findLine(start, end, info);
+}
+
+
+void Foam::searchableSurfaceCollection::findLineAll
+(
+    const pointField& start,
+    const pointField& end,
+    List<List<pointIndexHit> >& info
+) const
+{
+    // To be done. Assume for now only one intersection.
+    List<pointIndexHit> nearestInfo;
+    findLine(start, end, nearestInfo);
+
+    info.setSize(start.size());
+    forAll(info, pointI)
+    {
+        if (nearestInfo[pointI].hit())
+        {
+            info[pointI].setSize(1);
+            info[pointI][0] = nearestInfo[pointI];
+        }
+        else
+        {
+            info[pointI].clear();
+        }
+    }
+}
+
+
+void Foam::searchableSurfaceCollection::getRegion
+(
+    const List<pointIndexHit>& info,
+    labelList& region
+) const
+{
+    if (subGeom_.size() == 0)
+    {}
+    else if (subGeom_.size() == 1)
+    {
+        subGeom_[0].getRegion(info, region);
+    }
+    else
+    {
+        region.setSize(info.size());
+        region = -1;
+
+        // Which region did point come from. Retest for now to see which
+        // surface it originates from - crap solution! Should use global indices
+        // in index inside pointIndexHit to do this better.
+
+        pointField samples(info.size());
+        forAll(info, pointI)
+        {
+            if (info[pointI].hit())
+            {
+                samples[pointI] = info[pointI].hitPoint();
+            }
+            else
+            {
+                samples[pointI] = vector::zero;
+            }
+        }
+        //scalarField minDistSqr(info.size(), SMALL);
+        scalarField minDistSqr(info.size(), GREAT);
+
+        labelList nearestSurf;
+        List<pointIndexHit> nearestInfo;
+        findNearest
+        (
+            samples,
+            minDistSqr,
+            nearestInfo,
+            nearestSurf
+        );
+
+        // Check
+        {
+            forAll(info, pointI)
+            {
+                if (info[pointI].hit() && nearestSurf[pointI] == -1)
+                {
+                    FatalErrorIn
+                    (
+                        "searchableSurfaceCollection::getRegion(..)"
+                    )   << "pointI:" << pointI
+                        << " sample:" << samples[pointI]
+                        << " nearest:" << nearestInfo[pointI]
+                        << " nearestsurf:" << nearestSurf[pointI]
+                        << abort(FatalError);
+                }
+            }
+        }
+
+        forAll(subGeom_, surfI)
+        {
+            // Collect points from my surface
+            labelList indices(findIndices(nearestSurf, surfI));
+
+            labelList surfRegion;
+            subGeom_[surfI].getRegion
+            (
+                IndirectList<pointIndexHit>(info, indices),
+                surfRegion
+            );
+            forAll(indices, i)
+            {
+                region[indices[i]] = regionOffset_[surfI] + surfRegion[i];
+            }
+        }
+    }
+}
+
+
+void Foam::searchableSurfaceCollection::getNormal
+(
+    const List<pointIndexHit>& info,
+    vectorField& normal
+) const
+{
+    if (subGeom_.size() == 0)
+    {}
+    else if (subGeom_.size() == 1)
+    {
+        subGeom_[0].getNormal(info, normal);
+    }
+    else
+    {
+        normal.setSize(info.size());
+
+        // See above - crap retest to find surface point originates from.
+        pointField samples(info.size());
+        forAll(info, pointI)
+        {
+            if (info[pointI].hit())
+            {
+                samples[pointI] = info[pointI].hitPoint();
+            }
+            else
+            {
+                samples[pointI] = vector::zero;
+            }
+        }
+        //scalarField minDistSqr(info.size(), SMALL);
+        scalarField minDistSqr(info.size(), GREAT);
+
+        labelList nearestSurf;
+        List<pointIndexHit> nearestInfo;
+        findNearest
+        (
+            samples,
+            minDistSqr,
+            nearestInfo,
+            nearestSurf
+        );
+
+
+        forAll(subGeom_, surfI)
+        {
+            // Collect points from my surface
+            labelList indices(findIndices(nearestSurf, surfI));
+
+            vectorField surfNormal;
+            subGeom_[surfI].getNormal
+            (
+                IndirectList<pointIndexHit>(info, indices),
+                surfNormal
+            );
+            forAll(indices, i)
+            {
+                normal[indices[i]] = surfNormal[i];
+            }
+        }
+    }
+}
+
+
+void Foam::searchableSurfaceCollection::getVolumeType
+(
+    const pointField& points,
+    List<volumeType>& volType
+) const
+{
+    FatalErrorIn
+    (
+        "searchableSurfaceCollection::getVolumeType(const pointField&"
+        ", List<volumeType>&) const"
+    )   << "Volume type not supported for collection."
+        << exit(FatalError);
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurface/searchableSurfaceCollection.H b/src/meshTools/searchableSurface/searchableSurfaceCollection.H
new file mode 100644
index 0000000000000000000000000000000000000000..c85eaa10264f69939fae9f2c2924522b2cefcb8e
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableSurfaceCollection.H
@@ -0,0 +1,212 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    Foam::searchableSurfaceCollection
+
+Description
+    Union of transformed searchableSurfaces
+
+SourceFiles
+    searchableSurfaceCollection.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef searchableSurfaceCollection_H
+#define searchableSurfaceCollection_H
+
+#include "searchableSurface.H"
+#include "treeBoundBox.H"
+#include "coordinateSystem.H"
+#include "UPtrList.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+
+/*---------------------------------------------------------------------------*\
+                           Class searchableSurfaceCollection Declaration
+\*---------------------------------------------------------------------------*/
+
+class searchableSurfaceCollection
+:
+    public searchableSurface
+{
+private:
+
+    // Private Member Data
+
+        // Per instance data
+
+            //- instance name
+            wordList instance_;
+
+            //- scaling vector
+            vectorField scale_;
+
+            //- transformation
+            PtrList<coordinateSystem> transform_;
+
+            UPtrList<searchableSurface> subGeom_;
+
+        //- Region names
+        mutable wordList regions_;
+        //- From individual regions to collection regions
+        mutable labelList regionOffset_;
+
+
+    // Private Member Functions
+
+        //- Find point nearest to sample. Updates minDistSqr. Sets nearestInfo
+        //  and surface index
+        void findNearest
+        (
+            const pointField& samples,
+            scalarField& minDistSqr,
+            List<pointIndexHit>& nearestInfo,
+            labelList& nearestSurf
+        ) const;
+
+
+        //- Disallow default bitwise copy construct
+        searchableSurfaceCollection(const searchableSurfaceCollection&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const searchableSurfaceCollection&);
+
+
+public:
+
+    //- Runtime type information
+    TypeName("searchableSurfaceCollection");
+
+
+    // Constructors
+
+        //- Construct from dictionary (used by searchableSurface)
+        searchableSurfaceCollection
+        (
+            const IOobject& io,
+            const dictionary& dict
+        );
+
+    // Destructor
+
+        virtual ~searchableSurfaceCollection();
+
+
+    // Member Functions
+
+        virtual const wordList& regions() const;
+
+        //- Whether supports volume type below
+        virtual bool hasVolumeType() const
+        {
+            return false;
+        }
+
+        //- Range of local indices that can be returned.
+        virtual label size() const;
+
+
+        // Multiple point queries.
+
+            virtual void findNearest
+            (
+                const pointField& sample,
+                const scalarField& nearestDistSqr,
+                List<pointIndexHit>&
+            ) const;
+
+            virtual void findLine
+            (
+                const pointField& start,
+                const pointField& end,
+                List<pointIndexHit>&
+            ) const;
+
+            virtual void findLineAny
+            (
+                const pointField& start,
+                const pointField& end,
+                List<pointIndexHit>&
+            ) const;
+
+            //- Get all intersections in order from start to end.
+            virtual void findLineAll
+            (
+                const pointField& start,
+                const pointField& end,
+                List<List<pointIndexHit> >&
+            ) const;
+
+            //- From a set of points and indices get the region
+            virtual void getRegion
+            (
+                const List<pointIndexHit>&,
+                labelList& region
+            ) const;
+
+            //- From a set of points and indices get the normal
+            virtual void getNormal
+            (
+                const List<pointIndexHit>&,
+                vectorField& normal
+            ) const;
+
+            //- Determine type (inside/outside/mixed) for point. unknown if
+            //  cannot be determined (e.g. non-manifold surface)
+            virtual void getVolumeType
+            (
+                const pointField&,
+                List<volumeType>&
+            ) const;
+
+
+        // regIOobject implementation
+
+            bool writeData(Ostream&) const
+            {
+                notImplemented
+                (
+                    "searchableSurfaceCollection::writeData(Ostream&) const"
+                );
+                return false;
+            }
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurface/searchableSurfaces.C b/src/meshTools/searchableSurface/searchableSurfaces.C
index 46c968f15369b62c8f47abe05d5fcad7eb8449cd..cec34bd7e792669ace03bad6f68ea2e0b12ffe9b 100644
--- a/src/meshTools/searchableSurface/searchableSurfaces.C
+++ b/src/meshTools/searchableSurface/searchableSurfaces.C
@@ -39,8 +39,6 @@ defineTypeNameAndDebug(searchableSurfaces, 0);
 }
 
 
-// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
-
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 // Construct with length.
@@ -187,14 +185,6 @@ Foam::searchableSurfaces::searchableSurfaces
         // their object name. Maybe have stlTriSurfaceMesh which appends .stl
         // when reading/writing?
         namedIO().rename(key);  // names_[surfI]
-        if (namedIO().local() != word::null)
-        {
-            namedIO().instance() = namedIO().time().findInstance
-            (
-                namedIO().local(),
-                namedIO().name()
-            );
-        }
 
         // Create and hook surface
         set
diff --git a/src/meshTools/searchableSurface/searchableSurfaces.H b/src/meshTools/searchableSurface/searchableSurfaces.H
index ea91fcdee958a6d45a9fdb922b286f8580544477..af02ae188396fd12b255b2e308f6dff3cd970de0 100644
--- a/src/meshTools/searchableSurface/searchableSurfaces.H
+++ b/src/meshTools/searchableSurface/searchableSurfaces.H
@@ -69,6 +69,8 @@ class searchableSurfaces
         labelList allSurfaces_;
 
 
+    // Private Member Functions
+
         //- Disallow default bitwise copy construct
         searchableSurfaces(const searchableSurfaces&);
 
diff --git a/src/meshTools/searchableSurface/triSurfaceMesh.C b/src/meshTools/searchableSurface/triSurfaceMesh.C
index 7b9abc1aec6664b9efa541cbb128a7a9e27a5528..9958afd1b155167a1e08bc9f3926f94cad434532 100644
--- a/src/meshTools/searchableSurface/triSurfaceMesh.C
+++ b/src/meshTools/searchableSurface/triSurfaceMesh.C
@@ -43,6 +43,64 @@ addToRunTimeSelectionTable(searchableSurface, triSurfaceMesh, dict);
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
+//// Special version of Time::findInstance that does not check headerOk
+//// to search for instances of raw files
+//Foam::word Foam::triSurfaceMesh::findRawInstance
+//(
+//    const Time& runTime,
+//    const fileName& dir,
+//    const word& name
+//)
+//{
+//    // Check current time first
+//    if (isFile(runTime.path()/runTime.timeName()/dir/name))
+//    {
+//        return runTime.timeName();
+//    }
+//    instantList ts = runTime.times();
+//    label instanceI;
+//
+//    for (instanceI = ts.size()-1; instanceI >= 0; --instanceI)
+//    {
+//        if (ts[instanceI].value() <= runTime.timeOutputValue())
+//        {
+//            break;
+//        }
+//    }
+//
+//    // continue searching from here
+//    for (; instanceI >= 0; --instanceI)
+//    {
+//        if (isFile(runTime.path()/ts[instanceI].name()/dir/name))
+//        {
+//            return ts[instanceI].name();
+//        }
+//    }
+//
+//
+//    // not in any of the time directories, try constant
+//
+//    // Note. This needs to be a hard-coded constant, rather than the
+//    // constant function of the time, because the latter points to
+//    // the case constant directory in parallel cases
+//
+//    if (isFile(runTime.path()/runTime.constant()/dir/name))
+//    {
+//        return runTime.constant();
+//    }
+//
+//    FatalErrorIn
+//    (
+//        "searchableSurfaces::findRawInstance"
+//        "(const Time&, const fileName&, const word&)"
+//    )   << "Cannot find file \"" << name << "\" in directory "
+//        << runTime.constant()/dir
+//        << exit(FatalError);
+//
+//    return runTime.constant();
+//}
+
+
 //- Check file existence
 const Foam::fileName& Foam::triSurfaceMesh::checkFile
 (
@@ -149,7 +207,19 @@ bool Foam::triSurfaceMesh::isSurfaceClosed() const
 Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io, const triSurface& s)
 :
     searchableSurface(io),
-    objectRegistry(io),
+    objectRegistry
+    (
+        IOobject
+        (
+            io.name(),
+            io.instance(),
+            io.local(),
+            io.db(),
+            io.readOpt(),
+            io.writeOpt(),
+            false       // searchableSurface already registered under name
+        )
+    ),
     triSurface(s),
     surfaceClosed_(-1)
 {}
@@ -157,8 +227,34 @@ Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io, const triSurface& s)
 
 Foam::triSurfaceMesh::triSurfaceMesh(const IOobject& io)
 :
+    // Find instance for triSurfaceMesh
     searchableSurface(io),
-    objectRegistry(io),
+    //(
+    //    IOobject
+    //    (
+    //        io.name(),
+    //        io.time().findInstance(io.local(), word::null),
+    //        io.local(),
+    //        io.db(),
+    //        io.readOpt(),
+    //        io.writeOpt(),
+    //        io.registerObject()
+    //    )
+    //),
+    // Reused found instance in objectRegistry
+    objectRegistry
+    (
+        IOobject
+        (
+            io.name(),
+            static_cast<const searchableSurface&>(*this).instance(),
+            io.local(),
+            io.db(),
+            io.readOpt(),
+            io.writeOpt(),
+            false       // searchableSurface already registered under name
+        )
+    ),
     triSurface
     (
         checkFile
@@ -178,7 +274,32 @@ Foam::triSurfaceMesh::triSurfaceMesh
 )
 :
     searchableSurface(io),
-    objectRegistry(io),
+    //(
+    //    IOobject
+    //    (
+    //        io.name(),
+    //        io.time().findInstance(io.local(), word::null),
+    //        io.local(),
+    //        io.db(),
+    //        io.readOpt(),
+    //        io.writeOpt(),
+    //        io.registerObject()
+    //    )
+    //),
+    // Reused found instance in objectRegistry
+    objectRegistry
+    (
+        IOobject
+        (
+            io.name(),
+            static_cast<const searchableSurface&>(*this).instance(),
+            io.local(),
+            io.db(),
+            io.readOpt(),
+            io.writeOpt(),
+            false       // searchableSurface already registered under name
+        )
+    ),
     triSurface
     (
         checkFile
diff --git a/src/meshTools/searchableSurface/triSurfaceMesh.H b/src/meshTools/searchableSurface/triSurfaceMesh.H
index aa0af5979c56e582ba96beb8186aec90b4840d6b..a4231457d5183097cff2eceb31ca00e944c6a05d 100644
--- a/src/meshTools/searchableSurface/triSurfaceMesh.H
+++ b/src/meshTools/searchableSurface/triSurfaceMesh.H
@@ -76,6 +76,14 @@ private:
 
     // Private Member Functions
 
+        ////- Helper: find instance of files without header
+        //static word findRawInstance
+        //(
+        //    const Time&,
+        //    const fileName&,
+        //    const word&
+        //);
+
         //- Check file existence
         static const fileName& checkFile
         (
@@ -105,10 +113,10 @@ public:
         //- Construct from triSurface
         triSurfaceMesh(const IOobject&, const triSurface&);
 
-        //- Construct read
+        //- Construct read.
         triSurfaceMesh(const IOobject& io);
 
-        //- Construct from dictionary (used by searchableSurface)
+        //- Construct from IO and dictionary (used by searchableSurface).
         //  Dictionary may contain a 'scale' entry (eg, 0.001: mm -> m)
         triSurfaceMesh
         (
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurface.C b/src/sampling/sampledSurface/isoSurface/isoSurface.C
index c69a51f40731f18bc1c3aaa377aed705f84ce109..78081050ab4e715d3ec6f4378e3f91e1e91dc8da 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurface.C
+++ b/src/sampling/sampledSurface/isoSurface/isoSurface.C
@@ -30,6 +30,7 @@ License
 #include "syncTools.H"
 #include "addToRunTimeSelectionTable.H"
 #include "slicedVolFields.H"
+#include "surfaceFields.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -84,9 +85,74 @@ bool Foam::isoSurface::isEdgeOfFaceCut
 }
 
 
+// Get neighbour value and position.
+void Foam::isoSurface::getNeighbour
+(
+    const labelList& boundaryRegion,
+    const volScalarField& cVals,
+    const label cellI,
+    const label faceI,
+    scalar& nbrValue,
+    point& nbrPoint
+) const
+{
+    const labelList& own = mesh_.faceOwner();
+    const labelList& nei = mesh_.faceNeighbour();
+    const surfaceScalarField& weights = mesh_.weights();
+
+    if (mesh_.isInternalFace(faceI))
+    {
+        label nbr = (own[faceI] == cellI ? nei[faceI] : own[faceI]);
+        nbrValue = cVals[nbr];
+        nbrPoint = mesh_.cellCentres()[nbr];
+    }
+    else
+    {
+        label bFaceI = faceI-mesh_.nInternalFaces();
+        label patchI = boundaryRegion[bFaceI];
+        const polyPatch& pp = mesh_.boundaryMesh()[patchI];
+        label patchFaceI = faceI-pp.start();
+
+        if (isA<emptyPolyPatch>(pp))
+        {
+            // Assume zero gradient
+            nbrValue = cVals[own[faceI]];
+            nbrPoint = mesh_.faceCentres()[faceI];
+        }
+        else if (pp.coupled())
+        {
+            if (!refCast<const coupledPolyPatch>(pp).separated())
+            {
+                // Behave as internal face:
+                // other side value
+                nbrValue = cVals.boundaryField()[patchI][patchFaceI];
+                // other side cell centre
+                nbrPoint = mesh_.C().boundaryField()[patchI][patchFaceI];
+            }
+            else
+            {
+                // Do some interpolation for now
+                const scalarField& w = weights.boundaryField()[patchI];
+
+                nbrPoint = mesh_.faceCentres()[faceI];
+                nbrValue =
+                    (1-w[patchFaceI])*cVals[own[faceI]]
+                  + w[patchFaceI]*cVals.boundaryField()[patchI][patchFaceI];
+            }
+        }
+        else
+        {
+            nbrValue = cVals.boundaryField()[patchI][patchFaceI];
+            nbrPoint = mesh_.faceCentres()[faceI];
+        }
+    }
+}
+
+
 // Determine for every face/cell whether it (possibly) generates triangles.
 void Foam::isoSurface::calcCutTypes
 (
+    const labelList& boundaryRegion,
     const volScalarField& cVals,
     const scalarField& pVals
 )
@@ -102,7 +168,20 @@ void Foam::isoSurface::calcCutTypes
     {
         // CC edge.
         bool ownLower = (cVals[own[faceI]] < iso_);
-        bool neiLower = (cVals[nei[faceI]] < iso_);
+
+        scalar nbrValue;
+        point nbrPoint;
+        getNeighbour
+        (
+            boundaryRegion,
+            cVals,
+            own[faceI],
+            faceI,
+            nbrValue,
+            nbrPoint
+        );
+
+        bool neiLower = (nbrValue < iso_);
 
         if (ownLower != neiLower)
         {
@@ -120,53 +199,47 @@ void Foam::isoSurface::calcCutTypes
             }
         }
     }
+
     forAll(patches, patchI)
     {
         const polyPatch& pp = patches[patchI];
 
         label faceI = pp.start();
 
-        if (isA<emptyPolyPatch>(pp))
+        forAll(pp, i)
         {
-            // Assume zero gradient so owner and neighbour/boundary value equal
-
-            forAll(pp, i)
-            {
-                bool ownLower = (cVals[own[faceI]] < iso_);
+            bool ownLower = (cVals[own[faceI]] < iso_);
 
-                const face f = mesh_.faces()[faceI];
+            scalar nbrValue;
+            point nbrPoint;
+            getNeighbour
+            (
+                boundaryRegion,
+                cVals,
+                own[faceI],
+                faceI,
+                nbrValue,
+                nbrPoint
+            );
 
-                if (isEdgeOfFaceCut(pVals, f, ownLower, ownLower))
-                {
-                    faceCutType_[faceI] = CUT;
-                }
+            bool neiLower = (nbrValue < iso_);
 
-                faceI++;
+            if (ownLower != neiLower)
+            {
+                faceCutType_[faceI] = CUT;
             }
-        }
-        else
-        {
-            forAll(pp, i)
+            else
             {
-                bool ownLower = (cVals[own[faceI]] < iso_);
-                bool neiLower = (cVals.boundaryField()[patchI][i] < iso_);
+                // Mesh edge.
+                const face f = mesh_.faces()[faceI];
 
-                if (ownLower != neiLower)
+                if (isEdgeOfFaceCut(pVals, f, ownLower, neiLower))
                 {
                     faceCutType_[faceI] = CUT;
                 }
-                else
-                {
-                    // Mesh edge.
-                    const face f = mesh_.faces()[faceI];
-
-                    if (isEdgeOfFaceCut(pVals, f, ownLower, neiLower))
-                    {
-                        faceCutType_[faceI] = CUT;
-                    }
-                }
-                faceI++;
             }
+
+            faceI++;
         }
     }
 
@@ -330,59 +403,6 @@ Foam::pointIndexHit Foam::isoSurface::collapseSurface
 }
 
 
-// Get neighbour value and position.
-void Foam::isoSurface::getNeighbour
-(
-    const labelList& boundaryRegion,
-    const volScalarField& cVals,
-    const label cellI,
-    const label faceI,
-    scalar& nbrValue,
-    point& nbrPoint
-) const
-{
-    const labelList& own = mesh_.faceOwner();
-    const labelList& nei = mesh_.faceNeighbour();
-
-    if (mesh_.isInternalFace(faceI))
-    {
-        label nbr = (own[faceI] == cellI ? nei[faceI] : own[faceI]);
-        nbrValue = cVals[nbr];
-        nbrPoint = mesh_.cellCentres()[nbr];
-    }
-    else
-    {
-        label bFaceI = faceI-mesh_.nInternalFaces();
-        label patchI = boundaryRegion[bFaceI];
-        const polyPatch& pp = mesh_.boundaryMesh()[patchI];
-        label patchFaceI = faceI-pp.start();
-
-        if (isA<emptyPolyPatch>(pp))
-        {
-            // Assume zero gradient
-            nbrValue = cVals[own[faceI]];
-            nbrPoint = mesh_.faceCentres()[faceI];
-        }
-        else if
-        (
-            pp.coupled()
-        && !refCast<const coupledPolyPatch>(pp).separated()
-        )
-        {
-            // other side value
-            nbrValue = cVals.boundaryField()[patchI][patchFaceI];
-            // other side cell centre
-            nbrPoint = mesh_.C().boundaryField()[patchI][patchFaceI];
-        }
-        else
-        {
-            nbrValue = cVals.boundaryField()[patchI][patchFaceI];
-            nbrPoint = mesh_.faceCentres()[faceI];
-        }
-    }
-}
-
-
 // Determine per cell centre whether all the intersections get collapsed
 // to a single point
 void Foam::isoSurface::calcSnappedCc
@@ -606,13 +626,14 @@ void Foam::isoSurface::calcSnappedPoint
 
         forAll(pFaces, pFaceI)
         {
+            // Create points for all intersections close to point
+            // (i.e. from pyramid edges)
+
             label faceI = pFaces[pFaceI];
             const face& f = mesh_.faces()[faceI];
             label own = mesh_.faceOwner()[faceI];
 
-            // Create points for all intersections close to point
-            // (i.e. from pyramid edges)
-
+            // Get neighbour value
             scalar nbrValue;
             point nbrPoint;
             getNeighbour
@@ -831,6 +852,7 @@ Foam::triSurface Foam::isoSurface::stitchTriPoints
     }
 
 
+
     // Determine 'flat hole' situation (see RMT paper).
     // Two unconnected triangles get connected because (some of) the edges
     // separating them get collapsed. Below only checks for duplicate triangles,
@@ -846,22 +868,29 @@ Foam::triSurface Foam::isoSurface::stitchTriPoints
         forAll(tris, triI)
         {
             const labelledTri& tri = tris[triI];
-
             const labelList& pFaces = pointFaces[tri[0]];
 
-            // Find the minimum of any duplicates
+            // Find the maximum of any duplicates. Maximum since the tris
+            // below triI
+            // get overwritten so we cannot use them in a comparison.
             label dupTriI = -1;
             forAll(pFaces, i)
             {
-                if (pFaces[i] < triI && tris[pFaces[i]] == tri)
+                label nbrTriI = pFaces[i];
+
+                if (nbrTriI > triI && (tris[nbrTriI] == tri))
                 {
-                    dupTriI = pFaces[i];
+                    //Pout<< "Duplicate : " << triI << " verts:" << tri
+                    //    << " to " << nbrTriI << " verts:" << tris[nbrTriI]
+                    //    << endl;
+                    dupTriI = nbrTriI;
+                    break;
                 }
             }
 
             if (dupTriI == -1)
             {
-                // There is no lower triangle
+                // There is no (higher numbered) duplicate triangle
                 label newTriI = newToOldTri.size();
                 newToOldTri.append(triI);
                 tris[newTriI] = tris[triI];
@@ -876,6 +905,43 @@ Foam::triSurface Foam::isoSurface::stitchTriPoints
             Pout<< "isoSurface : merged from " << nTris
                 << " down to " << tris.size() << " unique triangles." << endl;
         }
+
+
+        if (debug)
+        {
+            triSurface surf(tris, geometricSurfacePatchList(0), newPoints);
+
+            forAll(surf, faceI)
+            {
+                const labelledTri& f = surf[faceI];
+                const labelList& fFaces = surf.faceFaces()[faceI];
+
+                forAll(fFaces, i)
+                {
+                    label nbrFaceI = fFaces[i];
+
+                    if (nbrFaceI <= faceI)
+                    {
+                        // lower numbered faces already checked
+                        continue;
+                    }
+
+                    const labelledTri& nbrF = surf[nbrFaceI];
+
+                    if (f == nbrF)
+                    {
+                        FatalErrorIn("validTri(const triSurface&, const label)")
+                            << "Check : "
+                            << " triangle " << faceI << " vertices " << f
+                            << " fc:" << f.centre(surf.points())
+                            << " has the same vertices as triangle " << nbrFaceI
+                            << " vertices " << nbrF
+                            << " fc:" << nbrF.centre(surf.points())
+                            << abort(FatalError);
+                    }
+                }
+            }
+        }
     }
 
     return triSurface(tris, geometricSurfacePatchList(0), newPoints, true);
@@ -1473,45 +1539,23 @@ Foam::isoSurface::isoSurface
 {
     if (debug)
     {
-        Pout<< "isoSurface     :" << nl
-            << "    isoField   : " << cVals.name() << nl
-            << "    isoValue   : " << iso << nl
-            << "    regularise : " << regularise << nl
-            << "    mergeTol   : " << mergeTol << nl
+        Pout<< "isoSurface:" << nl
+            << "    isoField      : " << cVals.name() << nl
+            << "    cell min/max  : "
+            << min(cVals.internalField()) << " / "
+            << max(cVals.internalField()) << nl
+            << "    point min/max : "
+            << min(pVals) << " / "
+            << max(pVals) << nl
+            << "    isoValue      : " << iso << nl
+            << "    regularise    : " << regularise << nl
+            << "    mergeTol      : " << mergeTol << nl
             << endl;
     }
 
     const polyBoundaryMesh& patches = mesh_.boundaryMesh();
 
-    // Check
-    forAll(patches, patchI)
-    {
-        if (isA<emptyPolyPatch>(patches[patchI]))
-        {
-            FatalErrorIn
-            (
-                "isoSurface::isoSurface\n"
-                "(\n"
-                "    const volScalarField& cVals,\n"
-                "    const scalarField& pVals,\n"
-                "    const scalar iso,\n"
-                "    const bool regularise,\n"
-                "    const scalar mergeTol\n"
-                ")\n"
-            )   << "Iso surfaces not supported on case with empty patches."
-                << exit(FatalError);
-        }
-    }
-
-
-    // Determine if any cut through face/cell
-    calcCutTypes(cVals, pVals);
-
-
-    // Determine if point is on boundary. Points on boundaries are never
-    // snapped. Coupled boundaries are handled explicitly so not marked here.
-    PackedBoolList isBoundaryPoint(mesh_.nPoints());
-
+    // Pre-calculate patch-per-face to avoid whichPatch call.
     labelList boundaryRegion(mesh_.nFaces()-mesh_.nInternalFaces());
 
     forAll(patches, patchI)
@@ -1525,31 +1569,11 @@ Foam::isoSurface::isoSurface
             boundaryRegion[faceI-mesh_.nInternalFaces()] = patchI;
             faceI++;
         }
+    }
 
-        // Mark all points that are not physically coupled (so anything
-        // but collocated coupled patches)
-        if
-        (
-           !pp.coupled()
-        || refCast<const coupledPolyPatch>(pp).separated()
-        )
-        {
-            label faceI = pp.start();
-
-            forAll(pp, i)
-            {
-                boundaryRegion[faceI-mesh_.nInternalFaces()] = patchI;
-
-                const face& f = mesh_.faces()[faceI];
 
-                forAll(f, fp)
-                {
-                    isBoundaryPoint.set(f[fp], 1);
-                }
-                faceI++;
-            }
-        }
-    }
+    // Determine if any cut through face/cell
+    calcCutTypes(boundaryRegion, cVals, pVals);
 
 
     DynamicList<point> snappedPoints(nCutCells_);
@@ -1584,6 +1608,39 @@ Foam::isoSurface::isoSurface
 
     label nCellSnaps = snappedPoints.size();
 
+
+    // Determine if point is on boundary. Points on boundaries are never
+    // snapped. Coupled boundaries are handled explicitly so not marked here.
+    PackedBoolList isBoundaryPoint(mesh_.nPoints());
+
+    forAll(patches, patchI)
+    {
+        // Mark all boundary points that are not physically coupled (so anything
+        // but collocated coupled patches)
+        const polyPatch& pp = patches[patchI];
+
+        if
+        (
+           !pp.coupled()
+        || refCast<const coupledPolyPatch>(pp).separated()
+        )
+        {
+            label faceI = pp.start();
+
+            forAll(pp, i)
+            {
+                const face& f = mesh_.faces()[faceI];
+
+                forAll(f, fp)
+                {
+                    isBoundaryPoint.set(f[fp], 1);
+                }
+                faceI++;
+            }
+        }
+    }
+
+
     // Per point -1 or a point inside snappedPoints.
     labelList snappedPoint;
     if (regularise)
@@ -1613,7 +1670,7 @@ Foam::isoSurface::isoSurface
 
 
     // Generate field to interpolate. This is identical to the mesh.C()
-    // except on separated coupled patches.
+    // except on separated coupled patches and on empty patches.
     slicedVolVectorField meshC
     (
         IOobject
@@ -1635,10 +1692,12 @@ Foam::isoSurface::isoSurface
         const polyBoundaryMesh& patches = mesh_.boundaryMesh();
         forAll(patches, patchI)
         {
+            const polyPatch& pp = patches[patchI];
+
             if
             (
-                patches[patchI].coupled()
-             && refCast<const coupledPolyPatch>(patches[patchI]).separated()
+                pp.coupled()
+             && refCast<const coupledPolyPatch>(pp).separated()
             )
             {
                 fvPatchVectorField& pfld = const_cast<fvPatchVectorField&>
@@ -1647,8 +1706,31 @@ Foam::isoSurface::isoSurface
                 );
                 pfld.operator==
                 (
-                    patches[patchI].patchSlice(mesh_.faceCentres())
+                    pp.patchSlice(mesh_.faceCentres())
+                );
+            }
+            else if (isA<emptyPolyPatch>(pp))
+            {
+                typedef slicedVolVectorField::GeometricBoundaryField bType;
+
+                bType& bfld = const_cast<bType&>(meshC.boundaryField());
+
+                // Clear old value. Cannot resize it since slice.
+                bfld.set(patchI, NULL);
+
+                // Set new value we can change
+                bfld.set
+                (
+                    patchI,
+                    new calculatedFvPatchField<vector>
+                    (
+                        mesh_.boundary()[patchI],
+                        meshC
+                    )
                 );
+
+                // Change to face centres
+                bfld[patchI] = pp.patchSlice(mesh_.faceCentres());
             }
         }
     }
@@ -1676,7 +1758,8 @@ Foam::isoSurface::isoSurface
     if (debug)
     {
         Pout<< "isoSurface : generated " << triMeshCells.size()
-            << " unmerged triangles." << endl;
+            << " unmerged triangles from " << triPoints.size()
+            << " unmerged points." << endl;
     }
 
 
@@ -1773,6 +1856,14 @@ Foam::isoSurface::isoSurface
 
     orientSurface(*this, faceEdges, edgeFace0, edgeFace1, edgeFacesRest);
     //}
+
+
+    if (debug)
+    {
+        fileName stlFile = mesh_.time().path() + ".stl";
+        Pout<< "Dumping surface to " << stlFile << endl;
+        triSurface::write(stlFile);
+    }
 }
 
 
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurface.H b/src/sampling/sampledSurface/isoSurface/isoSurface.H
index 7dc0588a1c0d0ccb448f5e00e693d09de2dbe721..b859524b2cc40f21aad1351b3dfa2d6f4d798a88 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurface.H
+++ b/src/sampling/sampledSurface/isoSurface/isoSurface.H
@@ -31,9 +31,6 @@ Description
     G.M. Treece, R.W. Prager and A.H. Gee.
 
     Note:
-    - not possible on patches of type 'empty'. There are no values on
-    'empty' patch fields so even the api would have to change
-     (no volScalarField as argument). Too messy.
     - in parallel the regularisation (coarsening) always takes place
     and slightly different surfaces will be created compared to non-parallel.
     The surface will still be continuous though!
@@ -43,6 +40,7 @@ Description
     - uses geometric merge with fraction of bounding box as distance.
     - triangles can be between two cell centres so constant sampling
       does not make sense.
+    - on empty patches behaves like zero gradient.
     - does not do 2D correctly, creates non-flat iso surface.
 
 SourceFiles
@@ -135,9 +133,20 @@ class isoSurface
             const bool neiLower
         ) const;
 
+        void getNeighbour
+        (
+            const labelList& boundaryRegion,
+            const volScalarField& cVals,
+            const label cellI,
+            const label faceI,
+            scalar& nbrValue,
+            point& nbrPoint
+        ) const;
+
         //- Set faceCutType,cellCutType.
         void calcCutTypes
         (
+            const labelList& boundaryRegion,
             const volScalarField& cVals,
             const scalarField& pVals
         );
@@ -156,16 +165,6 @@ class isoSurface
             DynamicList<labelledTri, 64>& localTris
         );
 
-        void getNeighbour
-        (
-            const labelList& boundaryRegion,
-            const volScalarField& cVals,
-            const label cellI,
-            const label faceI,
-            scalar& nbrValue,
-            point& nbrPoint
-        ) const;
-
         //- Determine per cc whether all near cuts can be snapped to single
         //  point.
         void calcSnappedCc
@@ -193,37 +192,39 @@ class isoSurface
         template<class Type>
         Type generatePoint
         (
-            const DynamicList<Type>& snappedPoints,
-
             const scalar s0,
             const Type& p0,
-            const label p0Index,
+            const bool hasSnap0,
+            const Type& snapP0,
 
             const scalar s1,
             const Type& p1,
-            const label p1Index
+            const bool hasSnap1,
+            const Type& snapP1
         ) const;
 
         template<class Type>
         void generateTriPoints
         (
-            const DynamicList<Type>& snapped,
-
             const scalar s0,
             const Type& p0,
-            const label p0Index,
+            const bool hasSnap0,
+            const Type& snapP0,
 
             const scalar s1,
             const Type& p1,
-            const label p1Index,
+            const bool hasSnap1,
+            const Type& snapP1,
 
             const scalar s2,
             const Type& p2,
-            const label p2Index,
+            const bool hasSnap2,
+            const Type& snapP2,
 
             const scalar s3,
             const Type& p3,
-            const label p3Index,
+            const bool hasSnap3,
+            const Type& snapP3,
 
             DynamicList<Type>& points
         ) const;
@@ -244,7 +245,8 @@ class isoSurface
 
             const scalar neiVal,
             const Type& neiPt,
-            const label neiSnap,
+            const bool hasNeiSnap,
+            const Type& neiSnapPt,
 
             DynamicList<Type>& triPoints,
             DynamicList<label>& triMeshCells
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurfaceTemplates.C b/src/sampling/sampledSurface/isoSurface/isoSurfaceTemplates.C
index e2251aad2abdecd824c6d3afc61a93ec7d222432..0760b06a52561de62d50ceb68b00f79b4b016fe7 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurfaceTemplates.C
+++ b/src/sampling/sampledSurface/isoSurface/isoSurfaceTemplates.C
@@ -33,15 +33,15 @@ License
 template<class Type>
 Type Foam::isoSurface::generatePoint
 (
-    const DynamicList<Type>& snappedPoints,
-
     const scalar s0,
     const Type& p0,
-    const label p0Index,
+    const bool hasSnap0,
+    const Type& snapP0,
 
     const scalar s1,
     const Type& p1,
-    const label p1Index
+    const bool hasSnap1,
+    const Type& snapP1
 ) const
 {
     scalar d = s1-s0;
@@ -50,13 +50,13 @@ Type Foam::isoSurface::generatePoint
     {
         scalar s = (iso_-s0)/d;
 
-        if (s >= 0.5 && s <= 1 && p1Index != -1)
+        if (hasSnap1 && s >= 0.5 && s <= 1)
         {
-            return snappedPoints[p1Index];
+            return snapP1;
         }
-        else if (s >= 0.0 && s <= 0.5 && p0Index != -1)
+        else if (hasSnap0 && s >= 0.0 && s <= 0.5)
         {
-            return snappedPoints[p0Index];
+            return snapP0;
         }
         else
         {
@@ -75,23 +75,25 @@ Type Foam::isoSurface::generatePoint
 template<class Type>
 void Foam::isoSurface::generateTriPoints
 (
-    const DynamicList<Type>& snapped,
-
     const scalar s0,
     const Type& p0,
-    const label p0Index,
+    const bool hasSnap0,
+    const Type& snapP0,
 
     const scalar s1,
     const Type& p1,
-    const label p1Index,
+    const bool hasSnap1,
+    const Type& snapP1,
 
     const scalar s2,
     const Type& p2,
-    const label p2Index,
+    const bool hasSnap2,
+    const Type& snapP2,
 
     const scalar s3,
     const Type& p3,
-    const label p3Index,
+    const bool hasSnap3,
+    const Type& snapP3,
 
     DynamicList<Type>& points
 ) const
@@ -123,29 +125,55 @@ void Foam::isoSurface::generateTriPoints
 
         case 0x0E:
         case 0x01:
-            points.append(generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index));
-            points.append(generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index));
-            points.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
+            points.append
+            (
+                generatePoint(s0,p0,hasSnap0,snapP0,s1,p1,hasSnap1,snapP1)
+            );
+            points.append
+            (
+                generatePoint(s0,p0,hasSnap0,snapP0,s2,p2,hasSnap2,snapP2)
+            );
+            points.append
+            (
+                generatePoint(s0,p0,hasSnap0,snapP0,s3,p3,hasSnap3,snapP3)
+            );
         break;
 
         case 0x0D:
         case 0x02:
-            points.append(generatePoint(snapped,s1,p1,p1Index,s0,p0,p0Index));
-            points.append(generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index));
-            points.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
+            points.append
+            (
+                generatePoint(s1,p1,hasSnap1,snapP1,s0,p0,hasSnap0,snapP0)
+            );
+            points.append
+            (
+                generatePoint(s1,p1,hasSnap1,snapP1,s3,p3,hasSnap3,snapP3)
+            );
+            points.append
+            (
+                generatePoint(s1,p1,hasSnap1,snapP1,s2,p2,hasSnap2,snapP2)
+            );
         break;
 
         case 0x0C:
         case 0x03:
         {
-            Type tp1 = generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index);
-            Type tp2 = generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index);
+            Type tp1 =
+                generatePoint(s0,p0,hasSnap0,snapP0,s2,p2,hasSnap2,snapP2);
+            Type tp2 =
+                generatePoint(s1,p1,hasSnap1,snapP1,s3,p3,hasSnap3,snapP3);
 
-            points.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
+            points.append
+            (
+                generatePoint(s0,p0,hasSnap0,snapP0,s3,p3,hasSnap3,snapP3)
+            );
             points.append(tp1);
             points.append(tp2);
             points.append(tp2);
-            points.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
+            points.append
+            (
+                generatePoint(s1,p1,hasSnap1,snapP1,s2,p2,hasSnap2,snapP2)
+            );
             points.append(tp1);
         }
         break;
@@ -153,23 +181,40 @@ void Foam::isoSurface::generateTriPoints
         case 0x0B:
         case 0x04:
         {
-            points.append(generatePoint(snapped,s2,p2,p2Index,s0,p0,p0Index));
-            points.append(generatePoint(snapped,s2,p2,p2Index,s1,p1,p1Index));
-            points.append(generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index));
+            points.append
+            (
+                generatePoint(s2,p2,hasSnap2,snapP2,s0,p0,hasSnap0,snapP0)
+            );
+            points.append
+            (
+                generatePoint(s2,p2,hasSnap2,snapP2,s1,p1,hasSnap1,snapP1)
+            );
+            points.append
+            (
+                generatePoint(s2,p2,hasSnap2,snapP2,s3,p3,hasSnap3,snapP3)
+            );
         }
         break;
 
         case 0x0A:
         case 0x05:
         {
-            Type tp0 = generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index);
-            Type tp1 = generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index);
+            Type tp0 =
+                generatePoint(s0,p0,hasSnap0,snapP0,s1,p1,hasSnap1,snapP1);
+            Type tp1 =
+                generatePoint(s2,p2,hasSnap2,snapP2,s3,p3,hasSnap3,snapP3);
 
             points.append(tp0);
             points.append(tp1);
-            points.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
+            points.append
+            (
+                generatePoint(s0,p0,hasSnap0,snapP0,s3,p3,hasSnap3,snapP3)
+            );
             points.append(tp0);
-            points.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
+            points.append
+            (
+                generatePoint(s1,p1,hasSnap1,snapP1,s2,p2,hasSnap2,snapP2)
+            );
             points.append(tp1);
         }
         break;
@@ -177,23 +222,40 @@ void Foam::isoSurface::generateTriPoints
         case 0x09:
         case 0x06:
         {
-            Type tp0 = generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index);
-            Type tp1 = generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index);
+            Type tp0 =
+                generatePoint(s0,p0,hasSnap0,snapP0,s1,p1,hasSnap1,snapP1);
+            Type tp1 =
+                generatePoint(s2,p2,hasSnap2,snapP2,s3,p3,hasSnap3,snapP3);
 
             points.append(tp0);
-            points.append(generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index));
+            points.append
+            (
+                generatePoint(s1,p1,hasSnap1,snapP1,s3,p3,hasSnap3,snapP3)
+            );
             points.append(tp1);
             points.append(tp0);
-            points.append(generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index));
+            points.append
+            (
+                generatePoint(s0,p0,hasSnap0,snapP0,s2,p2,hasSnap2,snapP2)
+            );
             points.append(tp1);
         }
         break;
 
         case 0x07:
         case 0x08:
-            points.append(generatePoint(snapped,s3,p3,p3Index,s0,p0,p0Index));
-            points.append(generatePoint(snapped,s3,p3,p3Index,s2,p2,p2Index));
-            points.append(generatePoint(snapped,s3,p3,p3Index,s1,p1,p1Index));
+            points.append
+            (
+                generatePoint(s3,p3,hasSnap3,snapP3,s0,p0,hasSnap0,snapP0)
+            );
+            points.append
+            (
+                generatePoint(s3,p3,hasSnap3,snapP3,s2,p2,hasSnap2,snapP2)
+            );
+            points.append
+            (
+                generatePoint(s3,p3,hasSnap3,snapP3,s1,p1,hasSnap1,snapP1)
+            );
         break;
     }
 }
@@ -215,7 +277,8 @@ Foam::label Foam::isoSurface::generateFaceTriPoints
 
     const scalar neiVal,
     const Type& neiPt,
-    const label neiSnap,
+    const bool hasNeiSnap,
+    const Type& neiSnapPt,
 
     DynamicList<Type>& triPoints,
     DynamicList<label>& triMeshCells
@@ -234,23 +297,37 @@ Foam::label Foam::isoSurface::generateFaceTriPoints
 
         generateTriPoints
         (
-            snappedPoints,
-
             pVals[pointI],
             pCoords[pointI],
-            snappedPoint[pointI],
+            snappedPoint[pointI] != -1,
+            (
+                snappedPoint[pointI] != -1
+              ? snappedPoints[snappedPoint[pointI]]
+              : pTraits<Type>::zero
+            ),
 
             pVals[nextPointI],
             pCoords[nextPointI],
-            snappedPoint[nextPointI],
+            snappedPoint[nextPointI] != -1,
+            (
+                snappedPoint[nextPointI] != -1
+              ? snappedPoints[snappedPoint[nextPointI]]
+              : pTraits<Type>::zero
+            ),
 
             cVals[own],
             cCoords[own],
-            snappedCc[own],
+            snappedCc[own] != -1,
+            (
+                snappedCc[own] != -1
+              ? snappedPoints[snappedCc[own]]
+              : pTraits<Type>::zero
+            ),
 
             neiVal,
             neiPt,
-            neiSnap,
+            hasNeiSnap,
+            neiSnapPt,
 
             triPoints
         );
@@ -311,25 +388,6 @@ void Foam::isoSurface::generateTriPoints
             << abort(FatalError);
     }
 
-    // Determine neighbouring snap status
-    labelList neiSnappedCc(mesh_.nFaces()-mesh_.nInternalFaces(), -1);
-    forAll(patches, patchI)
-    {
-        const polyPatch& pp = patches[patchI];
-
-        if (pp.coupled())
-        {
-            label faceI = pp.start();
-            forAll(pp, i)
-            {
-                neiSnappedCc[faceI-mesh_.nInternalFaces()] =
-                    snappedCc[own[faceI]];
-                faceI++;
-            }
-        }
-    }
-    syncTools::swapBoundaryFaceList(mesh_, neiSnappedCc, false);
-
 
 
     // Generate triangle points
@@ -356,7 +414,12 @@ void Foam::isoSurface::generateTriPoints
 
                 cVals[nei[faceI]],
                 cCoords[nei[faceI]],
-                snappedCc[nei[faceI]],
+                snappedCc[nei[faceI]] != -1,
+                (
+                    snappedCc[nei[faceI]] != -1
+                  ? snappedPoints[snappedCc[nei[faceI]]]
+                  : pTraits<Type>::zero
+                ),
 
                 triPoints,
                 triMeshCells
@@ -365,52 +428,139 @@ void Foam::isoSurface::generateTriPoints
     }
 
 
+    // Determine neighbouring snap status
+    boolList neiSnapped(mesh_.nFaces()-mesh_.nInternalFaces(), false);
+    List<Type> neiSnappedPoint(neiSnapped.size(), pTraits<Type>::zero);
     forAll(patches, patchI)
     {
         const polyPatch& pp = patches[patchI];
 
-        if
-        (
-            isA<processorPolyPatch>(pp)
-         && refCast<const processorPolyPatch>(pp).owner()
-         && !refCast<const processorPolyPatch>(pp).separated()
-        )
+        if (pp.coupled())
         {
             label faceI = pp.start();
-
             forAll(pp, i)
             {
-                if (faceCutType_[faceI] != NOTCUT)
+                label bFaceI = faceI-mesh_.nInternalFaces();
+                label snappedIndex = snappedCc[own[faceI]];
+
+                if (snappedIndex != -1)
                 {
-                    generateFaceTriPoints
-                    (
-                        cVals,
-                        pVals,
+                    neiSnapped[bFaceI] = true;
+                    neiSnappedPoint[bFaceI] = snappedPoints[snappedIndex];
+                }
+                faceI++;
+            }
+        }
+    }
+    syncTools::swapBoundaryFaceList(mesh_, neiSnapped, false);
+    syncTools::swapBoundaryFaceList(mesh_, neiSnappedPoint, false);
 
-                        cCoords,
-                        pCoords,
 
-                        snappedPoints,
-                        snappedCc,
-                        snappedPoint,
-                        faceI,
+    forAll(patches, patchI)
+    {
+        const polyPatch& pp = patches[patchI];
 
-                        cVals.boundaryField()[patchI][i],
-                        cCoords.boundaryField()[patchI][i],
-                        neiSnappedCc[faceI-mesh_.nInternalFaces()],
+        if
+        (
+            isA<processorPolyPatch>(pp)
+         && !refCast<const processorPolyPatch>(pp).separated()
+        )
+        {
+            //if (refCast<const processorPolyPatch>(pp).owner())
+            {
+                label faceI = pp.start();
 
-                        triPoints,
-                        triMeshCells
-                    );
+                forAll(pp, i)
+                {
+                    if (faceCutType_[faceI] != NOTCUT)
+                    {
+                        label bFaceI = faceI-mesh_.nInternalFaces();
+                        if
+                        (
+                            neiSnapped[bFaceI]
+                         && (neiSnappedPoint[bFaceI]==pTraits<Type>::zero)
+                        )
+                        {
+                            FatalErrorIn("isoSurface::generateTriPoints(..)")
+                                << "problem:" << abort(FatalError);
+                        }
+
+
+                        generateFaceTriPoints
+                        (
+                            cVals,
+                            pVals,
+
+                            cCoords,
+                            pCoords,
+
+                            snappedPoints,
+                            snappedCc,
+                            snappedPoint,
+                            faceI,
+
+                            cVals.boundaryField()[patchI][i],
+                            cCoords.boundaryField()[patchI][i],
+                            neiSnapped[faceI-mesh_.nInternalFaces()],
+                            neiSnappedPoint[faceI-mesh_.nInternalFaces()],
+
+                            triPoints,
+                            triMeshCells
+                        );
+                    }
+                    faceI++;
                 }
-                faceI++;
             }
         }
         else if (isA<emptyPolyPatch>(pp))
         {
-            // Assume zero-gradient. But what about coordinates?
+            // Check if field is there (when generating geometry the
+            // empty patches have been rewritten to be the face centres),
+            // otherwise use zero-gradient.
+
             label faceI = pp.start();
 
+
+            const fvPatchScalarField& fvp = cVals.boundaryField()[patchI];
+
+            // Owner value of cVals
+            scalarField internalVals;
+            if (fvp.size() == 0)
+            {
+                internalVals.setSize(pp.size());
+                forAll(pp, i)
+                {
+                    internalVals[i] = cVals[own[pp.start()+i]];
+                }
+            }
+            const scalarField& bVals =
+            (
+                fvp.size() > 0
+              ? static_cast<const scalarField&>(fvp)
+              : internalVals
+            );
+
+
+            const fvPatchField<Type>& pc = cCoords.boundaryField()[patchI];
+
+            // Owner value of cCoords
+            Field<Type> internalCoords;
+            if (pc.size() == 0)
+            {
+                internalCoords.setSize(pp.size());
+                forAll(pp, i)
+                {
+                    internalCoords[i] = cCoords[own[pp.start()+i]];
+                }
+            }
+            const Field<Type>& bCoords =
+            (
+                pc.size() > 0
+              ? static_cast<const Field<Type>&>(pc)
+              : internalCoords
+            );
+
+
             forAll(pp, i)
             {
                 if (faceCutType_[faceI] != NOTCUT)
@@ -428,9 +578,10 @@ void Foam::isoSurface::generateTriPoints
                         snappedPoint,
                         faceI,
 
-                        cVals[own[faceI]],
-                        cCoords.boundaryField()[patchI][i],
-                        -1, // fc not snapped
+                        bVals[i],
+                        bCoords[i],
+                        false,  // fc not snapped
+                        pTraits<Type>::zero,
 
                         triPoints,
                         triMeshCells
@@ -462,7 +613,8 @@ void Foam::isoSurface::generateTriPoints
 
                         cVals.boundaryField()[patchI][i],
                         cCoords.boundaryField()[patchI][i],
-                        -1, // fc not snapped
+                        false,  // fc not snapped
+                        pTraits<Type>::zero,
 
                         triPoints,
                         triMeshCells
diff --git a/src/turbulenceModels/LES/Allwmake b/src/turbulenceModels/LES/Allwmake
index a80c71ab57d28206f7585707735d49f8be229d95..d83439a9130c64ad25c955e5059ee79e1206c5d8 100755
--- a/src/turbulenceModels/LES/Allwmake
+++ b/src/turbulenceModels/LES/Allwmake
@@ -2,7 +2,7 @@
 cd ${0%/*} || exit 1    # run from this directory
 set -x
 
-wmakeLnInclude -f ../incompressible/LES
+wmakeLnInclude -f ../incompressible/LES -sf
 
 wmake libso LESfilters
 wmake libso LESdeltas
diff --git a/src/turbulenceModels/LES/LESdeltas/cubeRootVolDelta/cubeRootVolDelta.C b/src/turbulenceModels/LES/LESdeltas/cubeRootVolDelta/cubeRootVolDelta.C
index a3ce3ab3a99b1b94fe2ecc20e69d947dc3d7501d..2002deaa2181d05711c147f2f22bccc104712631 100644
--- a/src/turbulenceModels/LES/LESdeltas/cubeRootVolDelta/cubeRootVolDelta.C
+++ b/src/turbulenceModels/LES/LESdeltas/cubeRootVolDelta/cubeRootVolDelta.C
@@ -42,8 +42,7 @@ addToRunTimeSelectionTable(LESdelta, cubeRootVolDelta, dictionary);
 
 void cubeRootVolDelta::calcDelta()
 {
-    const Vector<label>& directions = mesh().directions();
-    label nD = (directions.nComponents + cmptSum(directions))/2;
+    label nD = mesh().nGeometricD();
 
     if (nD == 3)
     {
@@ -55,14 +54,15 @@ void cubeRootVolDelta::calcDelta()
             << "Case is 2D, LES is not strictly applicable\n"
             << endl;
 
+        const Vector<label>& directions = mesh().geometricD();
+
         scalar thickness = 0.0;
         for (direction dir=0; dir<directions.nComponents; dir++)
         {
             if (directions[dir] == -1)
             {
-                boundBox bb(mesh().points(), false);
-
-                thickness = bb.span()[dir];
+                thickness = mesh().bounds().span()[dir];
+                break;
             }
         }
 
diff --git a/src/turbulenceModels/incompressible/LES/SpalartAllmarasIDDES/IDDESDelta/IDDESDelta.C b/src/turbulenceModels/incompressible/LES/SpalartAllmarasIDDES/IDDESDelta/IDDESDelta.C
index 3f3aa7699bb335fdebb01684e02f9b32de037ac4..005ee2eb1610b6f43a58db645123f7096f015b44 100644
--- a/src/turbulenceModels/incompressible/LES/SpalartAllmarasIDDES/IDDESDelta/IDDESDelta.C
+++ b/src/turbulenceModels/incompressible/LES/SpalartAllmarasIDDES/IDDESDelta/IDDESDelta.C
@@ -41,8 +41,7 @@ namespace Foam
 
 void Foam::IDDESDelta::calcDelta()
 {
-    const Vector<label>& directions = mesh().directions();
-    label nD = (directions.nComponents + cmptSum(directions))/2;
+    label nD = mesh().nGeometricD();
 
     // initialise hwn as wall distance
     volScalarField hwn = wallDist(mesh()).y();
diff --git a/tutorials/incompressible/MRFSimpleFoam/MRFSimpleFoam/MRFSimpleFoam.C b/tutorials/incompressible/MRFSimpleFoam/MRFSimpleFoam/MRFSimpleFoam.C
index 9fc36826fe69d29b6164386dc74e19eb6b5df6ff..b3d7312a064a37cea473bb0de18e0e6687da3133 100644
--- a/tutorials/incompressible/MRFSimpleFoam/MRFSimpleFoam/MRFSimpleFoam.C
+++ b/tutorials/incompressible/MRFSimpleFoam/MRFSimpleFoam/MRFSimpleFoam.C
@@ -32,8 +32,8 @@ Description
 \*---------------------------------------------------------------------------*/
 
 #include "fvCFD.H"
-#include "incompressible/singlePhaseTransportModel/singlePhaseTransportModel.H"
-#include "incompressible/RASModel/RASModel.H"
+#include "singlePhaseTransportModel.H"
+#include "RASModel.H"
 #include "MRFZones.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/tutorials/incompressible/MRFSimpleFoam/MRFSimpleFoam/Make/options b/tutorials/incompressible/MRFSimpleFoam/MRFSimpleFoam/Make/options
index 2a417f954936f537595fba5fa461a73a81650574..1223bdd06f48178f0b2eee8032d29c936634f328 100644
--- a/tutorials/incompressible/MRFSimpleFoam/MRFSimpleFoam/Make/options
+++ b/tutorials/incompressible/MRFSimpleFoam/MRFSimpleFoam/Make/options
@@ -1,7 +1,9 @@
 EXE_INC = \
-    -I$(LIB_SRC)/finiteVolume/lnInclude \
-    -I$(LIB_SRC)/turbulenceModels/RAS \
-    -I$(LIB_SRC)/transportModels
+    -I$(LIB_SRC)/turbulenceModels \
+    -I$(LIB_SRC)/turbulenceModels/incompressible/RAS/RASModel \
+    -I$(LIB_SRC)/transportModels \
+    -I$(LIB_SRC)/transportModels/incompressible/singlePhaseTransportModel \
+    -I$(LIB_SRC)/finiteVolume/lnInclude
 
 EXE_LIBS = \
     -lincompressibleRASModels \
diff --git a/tutorials/incompressible/MRFSimpleFoam/mixerVessel2D/makeMesh b/tutorials/incompressible/MRFSimpleFoam/mixerVessel2D/makeMesh
index f45c6ff0be3a4fe281484bbfd4789baf4fe00b32..b0be10d8e5f2b0525cec8f23c93585fde73f5879 100755
--- a/tutorials/incompressible/MRFSimpleFoam/mixerVessel2D/makeMesh
+++ b/tutorials/incompressible/MRFSimpleFoam/mixerVessel2D/makeMesh
@@ -3,8 +3,9 @@
 m4 < constant/polyMesh/blockMeshDict.m4 > constant/polyMesh/blockMeshDict
 blockMesh
 cellSet
-cp system/faceSetDict_rotorFaces system/faceSetDict
-faceSet
-cp system/faceSetDict_noBoundaryFaces system/faceSetDict
-faceSet
+#- MRF determines its own faceZone if not supplied
+#cp system/faceSetDict_rotorFaces system/faceSetDict
+#faceSet
+#cp system/faceSetDict_noBoundaryFaces system/faceSetDict
+#faceSet
 setsToZones -noFlipMap
diff --git a/tutorials/incompressible/channelFoam/channel395/constant/postChannelDict b/tutorials/incompressible/channelFoam/channel395/constant/postChannelDict
index 89fcd5080961334007bc68fd3ea0921fcdddf1d9..96bbe30d760a249594044f2dfd8637b878fb1eb2 100644
--- a/tutorials/incompressible/channelFoam/channel395/constant/postChannelDict
+++ b/tutorials/incompressible/channelFoam/channel395/constant/postChannelDict
@@ -15,10 +15,14 @@ FoamFile
 }
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+// Seed patches to start layering from
 patches         ( bottomWall );
 
+// Direction in which the layers are
 component       y;
 
+// Is the mesh symmetric? If so average(symmetric fields) or
+// subtract(asymmetric) contributions from both halves
 symmetric       true;
 
 
diff --git a/tutorials/incompressible/channelFoam/channel395/system/controlDict b/tutorials/incompressible/channelFoam/channel395/system/controlDict
index 2ca28c29a1150383756dc56581f73663dd918fa9..218a76d8617819d086e88f897203bf152dae747f 100644
--- a/tutorials/incompressible/channelFoam/channel395/system/controlDict
+++ b/tutorials/incompressible/channelFoam/channel395/system/controlDict
@@ -43,7 +43,35 @@ timePrecision   6;
 
 runTimeModifiable yes;
 
-functions       ( fieldAverage1 { type fieldAverage ; functionObjectLibs ( "libfieldFunctionObjects.so" ) ; enabled true ; outputControl outputTime ; fields ( U { mean on ; prime2Mean on ; base time ; } p { mean on ; prime2Mean on ; base time ; } ) ; } );
+functions
+(
+    fieldAverage1
+    {
+        type fieldAverage;
+
+        functionObjectLibs ( "libfieldFunctionObjects.so" );
+
+        enabled true;
+
+        outputControl outputTime;
+
+        fields
+        (
+            U
+            {
+                mean on;
+                prime2Mean on;
+                base time;
+            }
+            p
+            {
+                mean on;
+                prime2Mean on;
+                base time;
+            }
+        );
+    }
+);
 
 
 // ************************************************************************* //
diff --git a/tutorials/mesh/snappyHexMesh/iglooWithFridges/system/snappyHexMeshDict b/tutorials/mesh/snappyHexMesh/iglooWithFridges/system/snappyHexMeshDict
index 2efe6901aa1657a7bb782cd7991cfc944b713132..19ef2afec1d08e169d49fd7907cc518d0eccd94b 100644
--- a/tutorials/mesh/snappyHexMesh/iglooWithFridges/system/snappyHexMeshDict
+++ b/tutorials/mesh/snappyHexMesh/iglooWithFridges/system/snappyHexMeshDict
@@ -2,7 +2,7 @@
 | =========                 |                                                 |
 | \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
 |  \\    /   O peration     | Version:  1.5                                   |
-|   \\  /    A nd           | Web:      www.OpenFOAM.org                      |
+|   \\  /    A nd           | Web:      http://www.OpenFOAM.org               |
 |    \\/     M anipulation  |                                                 |
 \*---------------------------------------------------------------------------*/
 FoamFile
@@ -10,138 +10,373 @@ FoamFile
     version     2.0;
     format      ascii;
     class       dictionary;
-    location    "system";
-    object      snappyHexMeshDict;
+    object      autoHexMeshDict;
 }
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+// Which of the steps to run
 castellatedMesh true;
-
 snap            true;
-
 addLayers       true;
 
+
+// Geometry. Definition of all surfaces. All surfaces are of class
+// searchableSurface.
+// Surfaces are used
+// - to specify refinement for any mesh cell intersecting it
+// - to specify refinement for any mesh cell inside/outside/near
+// - to 'snap' the mesh boundary to the surface
 geometry
 {
-    fridgeA
+    igloo
     {
-        type            searchableBox;
-        min             ( 2 2 0 );
-        max             ( 3 3 2 );
+        type searchableSphere;
+        centre (3 3 0);
+        radius 4;
     }
 
-    fridgeB
+    box1
     {
-        type            searchableBox;
-        min             ( 3.5 3 0 );
-        max             ( 4.3 3.8 1.8 );
+        type searchableBox;
+        min (0 0 0);
+        max (1 1 1);
     }
-
-    igloo
+    fridgeFreezer
     {
-        type            searchableSphere;
-        centre          ( 3 3 0 );
-        radius          4;
+        type searchableSurfaceCollection;
+    
+        freezer
+        {
+            surface box1;
+            scale (1 1 1);
+            transform
+            {
+                type    cartesian;
+                origin  (0 0 0);
+                e1      (1 0 0);
+                e3      (0 0 1);
+            }
+        }
+        fridge
+        {
+            surface box1;
+            scale (1 1 1.1);
+            transform
+            {
+                type    cartesian;
+                origin  (0 0 1);
+                e1      (1 0 0);
+                e3      (0 0 1);
+            }
+        }
     }
-}
+    twoFridgeFreezers
+    {
+        type searchableSurfaceCollection;
+    
+        seal
+        {
+            surface fridgeFreezer;
+            scale (1.0 1.0 1.0);
+            transform
+            {
+                type    cartesian;
+                origin  (2 2 0);
+                e1      (1 0 0);
+                e3      (0 0 1);
+            }
+        }
+        herring
+        {
+            surface fridgeFreezer;
+            scale (1.0 1.0 1.0);
+            transform
+            {
+                type    cartesian;
+                origin  (3.5 3 0);
+                e1      (1 0 0);
+                e3      (0 0 1);
+            }
+        }
+    }
+};
+
 
+
+// Settings for the castellatedMesh generation.
 castellatedMeshControls
 {
-    maxLocalCells   1000000;
-    maxGlobalCells  2000000;
-    minRefinementCells 0;
+
+    // Refinement parameters
+    // ~~~~~~~~~~~~~~~~~~~~~
+
+    // While refining maximum number of cells per processor. This is basically
+    // the number of cells that fit on a processor. If you choose this too small
+    // it will do just more refinement iterations to obtain a similar mesh.
+    maxLocalCells 1000000;
+
+    // Overall cell limit (approximately). Refinement will stop immediately
+    // upon reaching this number so a refinement level might not complete.
+    // Note that this is the number of cells before removing the part which
+    // is not 'visible' from the keepPoint. The final number of cells might
+    // actually be a lot less.
+    maxGlobalCells 2000000;
+
+    // The surface refinement loop might spend lots of iterations refining just a
+    // few cells. This setting will cause refinement to stop if <= minimumRefine
+    // are selected for refinement. Note: it will at least do one iteration
+    // (unless the number of cells to refine is 0)
+    minRefinementCells 100;
+
+    // Number of buffer layers between different levels.
+    // 1 means normal 2:1 refinement restriction, larger means slower
+    // refinement.
     nCellsBetweenLevels 1;
-    features        ( );
+
+
+
+    // Explicit feature edge refinement
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    // Specifies a level for any cell intersected by its edges.
+    // This is a featureEdgeMesh, read from constant/triSurface for now.
+    features
+    (
+//        {
+//            file "fridgeA.eMesh";
+//            level 3;
+//        }
+    );
+
+
+
+    // Surface based refinement
+    // ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    // Specifies two levels for every surface. The first is the minimum level,
+    // every cell intersecting a surface gets refined up to the minimum level.
+    // The second level is the maximum level. Cells that 'see' multiple
+    // intersections where the intersections make an
+    // angle > resolveFeatureAngle get refined up to the maximum level.
+
     refinementSurfaces
     {
-        fridgeA
+        twoFridgeFreezers
         {
-            level           ( 2 2 );
-        }
+            // Surface-wise min and max refinement level
+            level (2 2);
 
-        fridgeB
-        {
-            level           ( 2 2 );
+            regions
+            {
+                // Region-wise override
+                "cook.*"
+                {
+                    level (3 3);
+                }
+            }
         }
 
-        igloo
+        "iglo.*"
         {
-            level           ( 1 1 );
+            // Surface-wise min and max refinement level
+            level (1 1);
         }
     }
 
+    // Resolve sharp angles on fridges
     resolveFeatureAngle 60;
+
+
+    // Region-wise refinement
+    // ~~~~~~~~~~~~~~~~~~~~~~
+
+    // Specifies refinement level for cells in relation to a surface. One of
+    // three modes
+    // - distance. 'levels' specifies per distance to the surface the
+    //   wanted refinement level. The distances need to be specified in
+    //   descending order.
+    // - inside. 'levels' is only one entry and only the level is used. All
+    //   cells inside the surface get refined up to the level. The surface
+    //   needs to be closed for this to be possible.
+    // - outside. Same but cells outside.
+
     refinementRegions
     {
     }
 
-    locationInMesh  ( 3 0.28 0.43 );
+
+    // Mesh selection
+    // ~~~~~~~~~~~~~~
+
+    // After refinement patches get added for all refinementSurfaces and
+    // all cells intersecting the surfaces get put into these patches. The
+    // section reachable from the locationInMesh is kept.
+    // NOTE: This point should never be on a face, always inside a cell, even
+    // after refinement.
+    locationInMesh (3 0.28 0.43);
 }
 
+
+
+// Settings for the snapping.
 snapControls
 {
-    nSmoothPatch    3;
-    tolerance       4;
-    nSolveIter      30;
-    nRelaxIter      5;
+    //- Number of patch smoothing iterations before finding correspondence
+    //  to surface
+    nSmoothPatch 3;
+
+    //- Relative distance for points to be attracted by surface feature point
+    //  or edge. True distance is this factor times local
+    //  maximum edge length.
+    tolerance 4.0;
+
+    //- Number of mesh displacement relaxation iterations.
+    nSolveIter 30;
+
+    //- Maximum number of snapping relaxation iterations. Should stop
+    //  before upon reaching a correct mesh.
+    nRelaxIter 5;
 }
 
+
+
+// Settings for the layer addition.
 addLayersControls
 {
+    // Per final patch (so not geometry!) the layer information
     layers
     {
-        fridgeA_region0
+        "two.*"
         {
-            nSurfaceLayers  1;
+            nSurfaceLayers 3;
         }
-
-        fridgeB_region0
-        {
-            nSurfaceLayers  1;
-        }
-
-        igloo_region0
+        "igloo_.*"
         {
-            nSurfaceLayers  1;
+            nSurfaceLayers 1;
         }
     }
 
-    expansionRatio  1;
+    // Expansion factor for layer mesh
+    expansionRatio 1.0;
+
+    //- Wanted thickness of final added cell layer. If multiple layers
+    //  is the
+    //  thickness of the layer furthest away from the wall.
+    //  Relative to undistorted size of cell outside layer.
     finalLayerRatio 0.5;
-    minThickness    0.25;
-    nGrow           0;
-    featureAngle    60;
-    nRelaxIter      5;
+
+    //- Minimum thickness of cell layer. If for any reason layer
+    //  cannot be above minThickness do not add layer.
+    //  Relative to undistorted size of cell outside layer.
+    minThickness 0.25;
+
+    //- If points get not extruded do nGrow layers of connected faces that are
+    //  also not grown. This helps convergence of the layer addition process
+    //  close to features.
+    nGrow 0;
+
+
+    // Advanced settings
+
+    //- When not to extrude surface. 0 is flat surface, 90 is when two faces
+    //  make straight angle.
+    featureAngle 60;
+
+    //- Maximum number of snapping relaxation iterations. Should stop
+    //  before upon reaching a correct mesh.
+    nRelaxIter 5;
+
+    // Number of smoothing iterations of surface normals
     nSmoothSurfaceNormals 1;
-    nSmoothNormals  3;
+
+    // Number of smoothing iterations of interior mesh movement direction
+    nSmoothNormals 3;
+
+    // Smooth layer thickness over surface patches
     nSmoothThickness 10;
+
+    // Stop layer growth on highly warped cells
     maxFaceThicknessRatio 0.5;
+
+    // Reduce layer growth where ratio thickness to medial
+    // distance is large
     maxThicknessToMedialRatio 0.3;
+
+    // Angle used to pick up medial axis points
     minMedianAxisAngle 130;
+
+    // Create buffer region for new layer terminations
     nBufferCellsNoExtrude 0;
 }
 
+
+
+// Generic mesh quality settings. At any undoable phase these determine
+// where to undo.
 meshQualityControls
 {
-    maxNonOrtho     65;
+    //- Maximum non-orthogonality allowed. Set to 180 to disable.
+    maxNonOrtho 65;
+
+    //- Max skewness allowed. Set to <0 to disable.
     maxBoundarySkewness 20;
     maxInternalSkewness 4;
-    maxConcave      80;
-    minFlatness     0.5;
-    minVol          1e-13;
-    minArea         -1;
-    minTwist        0.05;
-    minDeterminant  0.001;
-    minFaceWeight   0.05;
-    minVolRatio     0.01;
+
+    //- Max concaveness allowed. Is angle (in degrees) below which concavity
+    //  is allowed. 0 is straight face, <0 would be convex face.
+    //  Set to 180 to disable.
+    maxConcave 80;
+
+    //- Minimum projected area v.s. actual area. Set to -1 to disable.
+    minFlatness 0.5;
+
+    //- Minimum pyramid volume. Is absolute volume of cell pyramid.
+    //  Set to very negative number (e.g. -1E30) to disable.
+    minVol 1e-13;
+
+    //- Minimum face area. Set to <0 to disable.
+    minArea -1;
+
+    //- Minimum face twist. Set to <-1 to disable. dot product of face normal
+    //- and face centre triangles normal
+    minTwist 0.05;
+
+    //- minimum normalised cell determinant
+    //- 1 = hex, <= 0 = folded or flattened illegal cell
+    minDeterminant 0.001;
+
+    //- minFaceWeight (0 -> 0.5)
+    minFaceWeight 0.05;
+
+    //- minVolRatio (0 -> 1)
+    minVolRatio 0.01;
+
+    //must be >0 for Fluent compatibility
     minTriangleTwist -1;
-    nSmoothScale    4;
-    errorReduction  0.75;
+
+
+    // Advanced
+
+    //- Number of error distribution iterations
+    nSmoothScale 4;
+    //- amount to scale back displacement at error points
+    errorReduction 0.75;
 }
 
-debug           0;
 
-mergeTolerance  1e-06;
+// Advanced
+
+// Flags for optional output
+// 0 : only write final meshes
+// 1 : write intermediate meshes
+// 2 : write volScalarField with cellLevel for postprocessing
+// 4 : write current intersections as .obj files
+debug 0;
+
 
+// Merge tolerance. Is fraction of overall bounding box of initial mesh.
+// Note: the write tolerance needs to be higher than this.
+mergeTolerance 1E-6;
 
 // ************************************************************************* //
diff --git a/tutorials/mesh/snappyHexMesh/motorBike/system/snappyHexMeshDict b/tutorials/mesh/snappyHexMesh/motorBike/system/snappyHexMeshDict
index fa094e1b03b4fe1b3d419af45a6b757592cfac4c..3f0ff0417e6b92047878cb285aa71452c8fd3c74 100644
--- a/tutorials/mesh/snappyHexMesh/motorBike/system/snappyHexMeshDict
+++ b/tutorials/mesh/snappyHexMesh/motorBike/system/snappyHexMeshDict
@@ -13,14 +13,21 @@ FoamFile
     location    "system";
     object      snappyHexMeshDict;
 }
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+// Which of the steps to run
 castellatedMesh true;
-
 snap            true;
-
 addLayers       true;
 
+
+// Geometry. Definition of all surfaces. All surfaces are of class
+// searchableSurface.
+// Surfaces are used
+// - to specify refinement for any mesh cell intersecting it
+// - to specify refinement for any mesh cell inside/outside/near
+// - to 'snap' the mesh boundary to the surface
 geometry
 {
     motorBike.stl
@@ -37,22 +44,89 @@ geometry
     }
 }
 
+
+// Settings for the castellatedMesh generation.
 castellatedMeshControls
 {
+
+    // Refinement parameters
+    // ~~~~~~~~~~~~~~~~~~~~~
+
+    // While refining maximum number of cells per processor. This is basically
+    // the number of cells that fit on a processor. If you choose this too small
+    // it will do just more refinement iterations to obtain a similar mesh.
     maxLocalCells   1000000;
+
+
+    // Overall cell limit (approximately). Refinement will stop immediately
+    // upon reaching this number so a refinement level might not complete.
+    // Note that this is the number of cells before removing the part which
+    // is not 'visible' from the keepPoint. The final number of cells might
+    // actually be a lot less.
     maxGlobalCells  2000000;
+
+    // The surface refinement loop might spend lots of iterations refining just a
+    // few cells. This setting will cause refinement to stop if <= minimumRefine
+    // are selected for refinement. Note: it will at least do one iteration
+    // (unless the number of cells to refine is 0)
     minRefinementCells 10;
+
+    // Number of buffer layers between different levels.
+    // 1 means normal 2:1 refinement restriction, larger means slower
+    // refinement.
     nCellsBetweenLevels 2;
-    features        ( );
+
+
+
+    // Explicit feature edge refinement
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    // Specifies a level for any cell intersected by its edges.
+    // This is a featureEdgeMesh, read from constant/triSurface for now.
+    features
+    (
+        //{
+        //    file "someLine.eMesh";
+        //    level 2;
+        //}
+    );
+
+
+
+    // Surface based refinement
+    // ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    // Specifies two levels for every surface. The first is the minimum level,
+    // every cell intersecting a surface gets refined up to the minimum level.
+    // The second level is the maximum level. Cells that 'see' multiple
+    // intersections where the intersections make an
+    // angle > resolveFeatureAngle get refined up to the maximum level.
+
     refinementSurfaces
     {
         motorBike
         {
+            // Surface-wise min and max refinement level
             level           ( 5 6 );
         }
     }
 
+    // Resolve sharp angles
     resolveFeatureAngle 30;
+
+
+    // Region-wise refinement
+    // ~~~~~~~~~~~~~~~~~~~~~~
+
+    // Specifies refinement level for cells in relation to a surface. One of
+    // three modes
+    // - distance. 'levels' specifies per distance to the surface the
+    //   wanted refinement level. The distances need to be specified in
+    //   descending order.
+    // - inside. 'levels' is only one entry and only the level is used. All
+    //   cells inside the surface get refined up to the level. The surface
+    //   needs to be closed for this to be possible.
+    // - outside. Same but cells outside.
     refinementRegions
     {
         refinementBox
@@ -62,19 +136,45 @@ castellatedMeshControls
         }
     }
 
+
+
+    // Mesh selection
+    // ~~~~~~~~~~~~~~
+
+    // After refinement patches get added for all refinementSurfaces and
+    // all cells intersecting the surfaces get put into these patches. The
+    // section reachable from the locationInMesh is kept.
+    // NOTE: This point should never be on a face, always inside a cell, even
+    // after refinement.
     locationInMesh  ( 3 3 0.43 );
 }
 
+
+// Settings for the snapping.
 snapControls
 {
+    //- Number of patch smoothing iterations before finding correspondence
+    //  to surface
     nSmoothPatch    3;
+
+    //- Relative distance for points to be attracted by surface feature point
+    //  or edge. True distance is this factor times local
+    //  maximum edge length.
     tolerance       4;
+
+    //- Number of mesh displacement relaxation iterations.
     nSolveIter      30;
+
+    //- Maximum number of snapping relaxation iterations. Should stop
+    //  before upon reaching a correct mesh.
     nRelaxIter      5;
 }
 
+
+// Settings for the layer addition.
 addLayersControls
 {
+    // Per final patch (so not geometry!) the layer information
     layers
     {
         minZ
@@ -418,41 +518,126 @@ addLayersControls
         }
     }
 
+    // Expansion factor for layer mesh
     expansionRatio  1;
+
+    //- Wanted thickness of final added cell layer. If multiple layers
+    //  is the
+    //  thickness of the layer furthest away from the wall.
+    //  Relative to undistorted size of cell outside layer.
     finalLayerRatio 0.3;
+
+    //- Minimum thickness of cell layer. If for any reason layer
+    //  cannot be above minThickness do not add layer.
+    //  Relative to undistorted size of cell outside layer.
     minThickness    0.1;
+
+    //- If points get not extruded do nGrow layers of connected faces that are
+    //  also not grown. This helps convergence of the layer addition process
+    //  close to features.
     nGrow           1;
+
+
+    // Advanced settings
+
+    //- When not to extrude surface. 0 is flat surface, 90 is when two faces
+    //  make straight angle.
     featureAngle    30;
+
+    //- Maximum number of snapping relaxation iterations. Should stop
+    //  before upon reaching a correct mesh.
     nRelaxIter      3;
+
+    // Number of smoothing iterations of surface normals
     nSmoothSurfaceNormals 1;
+
+    // Number of smoothing iterations of interior mesh movement direction
     nSmoothNormals  3;
+
+    // Smooth layer thickness over surface patches
     nSmoothThickness 10;
+
+    // Stop layer growth on highly warped cells
     maxFaceThicknessRatio 0.5;
+
+    // Reduce layer growth where ratio thickness to medial
+    // distance is large
     maxThicknessToMedialRatio 0.3;
+
+    // Angle used to pick up medial axis points
     minMedianAxisAngle 130;
+
+    // Create buffer region for new layer terminations
     nBufferCellsNoExtrude 0;
 }
 
+
+// Generic mesh quality settings. At any undoable phase these determine
+// where to undo.
 meshQualityControls
 {
+    //- Maximum non-orthogonality allowed. Set to 180 to disable.
     maxNonOrtho     65;
+
+    //- Max skewness allowed. Set to <0 to disable.
     maxBoundarySkewness 20;
     maxInternalSkewness 4;
+
+    //- Max concaveness allowed. Is angle (in degrees) below which concavity
+    //  is allowed. 0 is straight face, <0 would be convex face.
+    //  Set to 180 to disable.
     maxConcave      80;
+
+    //- Minimum projected area v.s. actual area. Set to -1 to disable.
     minFlatness     0.5;
+
+    //- Minimum pyramid volume. Is absolute volume of cell pyramid.
+    //  Set to very negative number (e.g. -1E30) to disable.
     minVol          1e-13;
+
+    //- Minimum face area. Set to <0 to disable.
     minArea         -1;
+
+    //- Minimum face twist. Set to <-1 to disable. dot product of face normal
+    //- and face centre triangles normal
     minTwist        0.02;
+
+    //- minimum normalised cell determinant
+    //- 1 = hex, <= 0 = folded or flattened illegal cell
     minDeterminant  0.001;
+
+    //- minFaceWeight (0 -> 0.5)
     minFaceWeight   0.02;
+
+    //- minVolRatio (0 -> 1)
     minVolRatio     0.01;
+
+    //must be >0 for Fluent compatibility
     minTriangleTwist -1;
+
+
+    // Advanced
+
+    //- Number of error distribution iterations
     nSmoothScale    4;
+    //- amount to scale back displacement at error points
     errorReduction  0.75;
 }
 
+
+
+// Advanced
+
+// Flags for optional output
+// 0 : only write final meshes
+// 1 : write intermediate meshes
+// 2 : write volScalarField with cellLevel for postprocessing
+// 4 : write current intersections as .obj files
 debug           0;
 
+
+// Merge tolerance. Is fraction of overall bounding box of initial mesh.
+// Note: the write tolerance needs to be higher than this.
 mergeTolerance  1e-06;
 
 
diff --git a/wmake/wmakeLnInclude b/wmake/wmakeLnInclude
index bce2cfbb51d3cfcb74c52a54432dd386bbdafc49..1ed1671e7a32e3043027fe2a680eb3e3031048ca 100755
--- a/wmake/wmakeLnInclude
+++ b/wmake/wmakeLnInclude
@@ -145,16 +145,6 @@ find -L . -type l -exec rm \{\} \;
 find .. $findOpt \
     \( -name lnInclude -o -name Make -o -name config -o -name noLink \) -prune \
  -o \( -name '*.[CHh]' -o -name '*.[ch]xx' -o -name '*.[ch]pp' -o -name '*.type' \)  \
- -a ! -name ".#*" \
- -print | \
-    while read src
-    do
-        link=$(readlink ${src##*/})
-        if [ "$link" != "$src" ]
-        then
-            rm $link 2>/dev/null
-            ln $lnOpt $src .
-        fi
-    done
+ -exec ln $lnOpt {} . \;
 
 #------------------------------------------------------------------------------