diff --git a/applications/solvers/combustion/PDRFoam/PDRModels/XiEqModels/basicXiSubXiEq/basicXiSubXiEq.H b/applications/solvers/combustion/PDRFoam/PDRModels/XiEqModels/basicXiSubXiEq/basicXiSubXiEq.H
index c89d8dc6c9bba726a9eeaa205cad3c10229bbed7..7721cadaebcd5411739213fc3ddee5a11d910f39 100644
--- a/applications/solvers/combustion/PDRFoam/PDRModels/XiEqModels/basicXiSubXiEq/basicXiSubXiEq.H
+++ b/applications/solvers/combustion/PDRFoam/PDRModels/XiEqModels/basicXiSubXiEq/basicXiSubXiEq.H
@@ -29,6 +29,36 @@ Description
     Basic sub-grid obstacle flame-wrinking enhancement factor model.
     Details supplied by J Puttock 2/7/06.
 
+    <b> Sub-grid flame area generation <\b>
+
+    \f$ n = N - \hat{\dwea{\vec{U}}}.n_{s}.\hat{\dwea{\vec{U}}} \f$
+    \f$ n_{r} = \sqrt{n} \f$
+
+    where:
+
+        \f$ \hat{\dwea{\vec{U}}} = \dwea{\vec{U}} / \vert \dwea{\vec{U}}
+        \vert \f$
+
+        \f$ b = \hat{\dwea{\vec{U}}}.B.\hat{\dwea{\vec{U}}} / n_{r} \f$
+
+    where:
+
+        \f$ B \f$ is the file "B".
+
+        \f$ N \f$ is the file "N".
+
+        \f$  n_{s} \f$ is the file "ns".
+
+    The flame area enhancement factor \f$ \Xi_{sub} \f$ is expected to
+    approach:
+
+    \f[
+        \Xi_{{sub}_{eq}} =
+            1 + max(2.2 \sqrt{b}, min(0.34 \frac{\vert \dwea{\vec{U}}
+            \vert}{{\vec{U}}^{'}}, 1.6)) \times min(\frac{n}{4}, 1)
+    \f]
+
+
 SourceFiles
     basicSubGrid.C
 
diff --git a/applications/solvers/combustion/PDRFoam/PDRModels/XiGModels/basicXiSubG/basicXiSubG.H b/applications/solvers/combustion/PDRFoam/PDRModels/XiGModels/basicXiSubG/basicXiSubG.H
index 01a6d7cb11c98f6936bc446f2f2001da676a5595..a455fd28b4963ce6ad2305230fdfee06dde245b3 100644
--- a/applications/solvers/combustion/PDRFoam/PDRModels/XiGModels/basicXiSubG/basicXiSubG.H
+++ b/applications/solvers/combustion/PDRFoam/PDRModels/XiGModels/basicXiSubG/basicXiSubG.H
@@ -25,10 +25,28 @@ License
 Class
     basicSubGrid
 
+
 Description
+
     Basic sub-grid obstacle flame-wrinking generation rate coefficient model.
     Details supplied by J Puttock 2/7/06.
 
+    \f$ G_{sub} \f$ denotes the generation coefficient and it is given by
+
+    \f[
+        G_{sub} = k_{1} /frac{\vert \dwea{\vec{U}} \vert}{L_{obs}}
+                 \frac{/Xi_{{sub}_{eq}}-1}{/Xi_{sub}}
+    \f]
+
+    and the removal:
+
+    \f[ - k_{1} /frac{\vert \dwea{\vec{U}} \vert}{L_{sub}}
+    \frac{\Xi_{sub}-1}{\Xi_{sub}} \f]
+
+    Finally, \f$ G_{sub} \f$ is added to generation rate \f$ G_{in} \f$
+    due to the turbulence.
+
+
 SourceFiles
     basicSubGrid.C
 
diff --git a/applications/solvers/combustion/PDRFoam/PDRModels/dragModels/basic/basic.H b/applications/solvers/combustion/PDRFoam/PDRModels/dragModels/basic/basic.H
index ceb75ff827cedb06fa61f68e57b861f7d6317618..d843214ab3bf1c16b227ced63c56f79955a7a695 100644
--- a/applications/solvers/combustion/PDRFoam/PDRModels/dragModels/basic/basic.H
+++ b/applications/solvers/combustion/PDRFoam/PDRModels/dragModels/basic/basic.H
@@ -29,6 +29,50 @@ Description
     Basic sub-grid obstacle drag model.
     Details supplied by J Puttock 2/7/06.
 
+    <b> Sub-grid drag term <\b>
+
+    The resistance term (force per unit of volume) is given by:
+
+    \f[
+        R = -\frac{1}{2} \rho \vert \dwea{\vec{U}} \vert \dwea{\vec{U}}.D
+    \f]
+
+    where:
+
+        \f$ D \f$ is the tensor field "CR" in \f$ m^{-1} \f$
+
+        This is term is treated implicitly in UEqn.H
+
+    <b> Sub-grid turbulence generation <\b>
+
+    The turbulence source term \f$ G_{R} \f$ occurring in the
+    \f$ \kappa-\epsilon \f$ equations for the generation of turbulence due
+    to interaction with unresolved obstacles :
+
+    \f$ G_{R} = C_{s}\beta_{\nu}
+    \mu_{eff} A_{w}^{2}(\dwea{\vec{U}}-\dwea{\vec{U}_{s}})^2 + \frac{1}{2}
+    \rho \vert \dwea{\vec{U}} \vert \dwea{\vec{U}}.T.\dwea{\vec{U}} \f$
+
+    where:
+
+        \f$ C_{s} \f$ = 1
+
+        \f$ \beta_{\nu} \f$ is the volume porosity (file "betav").
+
+        \f$ \mu_{eff} \f$ is the effective viscosity.
+
+        \f$ A_{w}^{2}\f$ is the obstacle surface area per unit of volume
+        (file "Aw").
+
+        \f$ \dwea{\vec{U}_{s}} \f$ is the slip velocity and is considered
+        \f$ \frac{1}{2}. \dwea{\vec{U}} \f$.
+
+        \f$ T \f$ is a tensor in the file CT.
+
+    The term \f$ G_{R} \f$ is treated explicitly in the \f$ \kappa-\epsilon
+    \f$ Eqs in the PDRkEpsilon.C file.
+
+
 SourceFiles
     basic.C
 
@@ -40,7 +84,6 @@ SourceFiles
 #include "PDRDragModel.H"
 #include "XiEqModel.H"
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
diff --git a/applications/solvers/combustion/PDRFoam/PDRModels/turbulence/PDRkEpsilon/PDRkEpsilon.H b/applications/solvers/combustion/PDRFoam/PDRModels/turbulence/PDRkEpsilon/PDRkEpsilon.H
index 15d52e72698f9cb20566a9a7d186e1d22784703c..b35ef9151ea1c7fe633475a459d38a6ded55459d 100644
--- a/applications/solvers/combustion/PDRFoam/PDRModels/turbulence/PDRkEpsilon/PDRkEpsilon.H
+++ b/applications/solvers/combustion/PDRFoam/PDRModels/turbulence/PDRkEpsilon/PDRkEpsilon.H
@@ -26,7 +26,17 @@ Class
     PDRkEpsilon
 
 Description
-    Standard k-epsilon turbulence model.
+    Standard k-epsilon turbulence model with additional source terms
+    corresponding to PDR basic drag model (basic.H)
+
+    The turbulence source term \f$ G_{R} \f$ appears in the
+    \f$ \kappa-\epsilon \f$ equation for the generation of turbulence due to
+    interaction with unresolved obstacles.
+
+    In the \f$ \epsilon  \f$ equation \f$ C_{1} G_{R} \f$ is added as a source
+    term.
+
+    In the \f$ \kappa \f$ equation \f$ G_{R} \f$ is added as a source term.
 
 SourceFiles
     PDRkEpsilon.C
diff --git a/applications/solvers/combustion/PDRFoam/XiModels/XiModel/XiModel.H b/applications/solvers/combustion/PDRFoam/XiModels/XiModel/XiModel.H
index 13fa58a53eebdd090fac5ee9b1acf56e3cf15ff8..2b76f9bc92a498028aa3ee9d48061f415f5c130b 100644
--- a/applications/solvers/combustion/PDRFoam/XiModels/XiModel/XiModel.H
+++ b/applications/solvers/combustion/PDRFoam/XiModels/XiModel/XiModel.H
@@ -27,6 +27,57 @@ Class
 
 Description
     Base-class for all Xi models used by the b-Xi combustion model.
+    See Technical Report SH/RE/01R for details on the PDR modelling.
+
+    Xi is given through an algebraic expression (algebraic.H),
+    by solving a transport equation (transport.H) or a fixed value (fixed.H).
+    See report TR/HGW/10 for details on the Weller two equations model.
+
+    In the algebraic and transport methods \f$\Xi_{eq}\f$ is calculated in
+    similar way. In the algebraic approach, \f$\Xi_{eq}\f$ is the value used in
+    the \f$ b \f$ transport equation.
+
+    \f$\Xi_{eq}\f$ is calculated as follows:
+
+    \f$\Xi_{eq} = 1 + (1 + 2\Xi_{coeff}(0.5 - \dwea{b}))(\Xi^* - 1)\f$
+
+    where:
+
+        \f$ \dwea{b} \f$ is the regress variable.
+
+        \f$ \Xi^* \f$ is the total equilibrium wrinkling combining the effects
+        of the flame inestability and turbulence interaction and is given by
+
+        \f[
+            \Xi^* = \frac {R}{R - G_\eta - G_{in}}
+        \f]
+
+    where:
+
+        \f$ G_\eta \f$ is the generation rate of wrinkling due to turbulence
+        interaction.
+
+        \f$ G_{in} = \kappa \rho_{u}/\rho_{b} \f$ is the generation
+         rate due to the flame inestability.
+
+    By adding the removal rates of the two effects:
+
+        \f[
+            R = G_\eta \frac{\Xi_{\eta_{eq}}}{\Xi_{\eta_{eq}} - 1}
+              + G_{in} \frac{\Xi_{{in}_{eq}}}{\Xi_{{in}_{eq}} - 1}
+        \f]
+
+    where:
+
+        \f$ R \f$ is the total removal.
+
+        \f$ G_\eta \f$ is a model constant.
+
+        \f$ \Xi_{\eta_{eq}} \f$ is the flame wrinkling due to turbulence.
+
+        \f$ \Xi_{{in}_{eq}} \f$ is the equilibrium level of the flame wrinkling
+        generated by inestability. It is a constant (default 2.5).
+
 
 SourceFiles
     XiModel.C
@@ -51,6 +102,8 @@ namespace Foam
                           Class XiModel Declaration
 \*---------------------------------------------------------------------------*/
 
+
+
 class XiModel
 {
 
diff --git a/applications/solvers/combustion/PDRFoam/laminarFlameSpeed/SCOPE/SCOPELaminarFlameSpeed.H b/applications/solvers/combustion/PDRFoam/laminarFlameSpeed/SCOPE/SCOPELaminarFlameSpeed.H
index e837fefa8bf94863ceac099a4bff05c49cf818f1..8c65453b946f51b0b0d2810ea334bd1b13848712 100644
--- a/applications/solvers/combustion/PDRFoam/laminarFlameSpeed/SCOPE/SCOPELaminarFlameSpeed.H
+++ b/applications/solvers/combustion/PDRFoam/laminarFlameSpeed/SCOPE/SCOPELaminarFlameSpeed.H
@@ -28,6 +28,33 @@ Class
 Description
     Laminar flame speed obtained from the SCOPE correlation.
 
+    Seven parameters are specified in terms of polynomial functions of
+    stoichiometry. Two polynomials are fitted, covering different parts of the
+    flammable range. If the mixture is outside the fitted range, linear
+    interpolation is used between the extreme of the polynomio and the upper or
+    lower flammable limit with the Markstein number constant.
+
+    Variations of pressure and temperature from the reference values are taken
+    into account through \f$ pexp \f$ and \f$ texp \f$
+
+    The laminar burning velocity fitting polynomial is:
+
+    \f$ Su = a_{0}(1+a_{1}x+K+..a_{i}x^{i}..+a_{6}x^{6}) (p/p_{ref})^{pexp}
+    (T/T_{ref})^{texp} \f$
+
+    where:
+
+        \f$ a_{i} \f$ are the polinomial coefficients.
+
+        \f$ pexp \f$ and \f$ texp \f$ are the pressure and temperature factors
+        respectively.
+
+        \f$ x \f$ is the equivalence ratio.
+
+        \f$ T_{ref} \f$ and \f$ p_{ref} \f$ are the temperature and pressure
+        references for the laminar burning velocity.
+
+
 SourceFiles
     SCOPELaminarFlameSpeed.C
 
@@ -125,7 +152,7 @@ class SCOPE
         //  corrected for temperature and pressure dependence
         inline scalar Su0pTphi(scalar p, scalar Tu, scalar phi) const;
 
-        //- Laminar flame speed evaluated from the given uniform 
+        //- Laminar flame speed evaluated from the given uniform
         //  equivalence ratio corrected for temperature and pressure dependence
         tmp<volScalarField> Su0pTphi
         (
@@ -134,7 +161,7 @@ class SCOPE
             scalar phi
         ) const;
 
-        //- Laminar flame speed evaluated from the given equivalence ratio 
+        //- Laminar flame speed evaluated from the given equivalence ratio
         //  distribution corrected for temperature and pressure dependence
         tmp<volScalarField> Su0pTphi
         (
@@ -144,7 +171,7 @@ class SCOPE
         ) const;
 
         //- Return the Markstein number
-        //  evaluated from the given equivalence ratio 
+        //  evaluated from the given equivalence ratio
         tmp<volScalarField> Ma(const volScalarField& phi) const;
 
         //- Construct as copy (not implemented)
diff --git a/applications/test/dictionary/dictionaryTest.C b/applications/test/dictionary/dictionaryTest.C
index 6064102781edfcd25fac64794ee54f9e097e3ffb..37ae9bd90c56ed11d58ee79c3734f5bb74d289be 100644
--- a/applications/test/dictionary/dictionaryTest.C
+++ b/applications/test/dictionary/dictionaryTest.C
@@ -45,6 +45,27 @@ int main(int argc, char *argv[])
 
     Info<< testDict << endl;
 
+    {
+        dictionary someDict;
+        someDict.add(keyType("a.*", true), "subdictValue");
+
+        dictionary dict;
+        dict.add("someDict", someDict);
+        dict.add(keyType(".*", true), "parentValue");
+
+        Info<< "dict:" << dict << endl;
+
+        // Wildcard find.
+        Info<< "Wildcard find \"abc\" in top directory : "
+            << dict.lookup("abc") << endl;
+        Info<< "Wildcard find \"abc\" in sub directory : "
+            << dict.subDict("someDict").lookup("abc")
+            << endl;
+        Info<< "Recursive wildcard find \"def\" in sub directory : "
+            << dict.subDict("someDict").lookup("def", true)
+            << endl;
+    }
+
     return 0;
 }
 
diff --git a/applications/utilities/mesh/conversion/polyDualMesh/Make/files b/applications/utilities/mesh/conversion/polyDualMesh/Make/files
index c43f79e8e148201c61e6d3d41f6fff50a540b4d7..752da5cfddb22955af52029c6b36312a2fedfc45 100644
--- a/applications/utilities/mesh/conversion/polyDualMesh/Make/files
+++ b/applications/utilities/mesh/conversion/polyDualMesh/Make/files
@@ -1,3 +1,4 @@
-polyDualMeshApp.C
+meshDualiser.C
+makePolyDualMesh.C
 
 EXE = $(FOAM_APPBIN)/polyDualMesh
diff --git a/applications/utilities/mesh/conversion/polyDualMesh/Make/options b/applications/utilities/mesh/conversion/polyDualMesh/Make/options
index 6dc63a7a989641aba7de693a1920eec74912cb02..dc318df99832515cca0862ee9d04aea77fda2baf 100644
--- a/applications/utilities/mesh/conversion/polyDualMesh/Make/options
+++ b/applications/utilities/mesh/conversion/polyDualMesh/Make/options
@@ -1,6 +1,9 @@
 EXE_INC = \
     -I$(LIB_SRC)/meshTools/lnInclude \
-    -I$(LIB_SRC)/conversion/lnInclude
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/dynamicMesh/lnInclude
 
 EXE_LIBS = \
-    -lmeshTools -lconversion
+    -lfiniteVolume \
+    -ldynamicMesh \
+    -lmeshTools
diff --git a/applications/utilities/mesh/conversion/polyDualMesh/makePolyDualMesh.C b/applications/utilities/mesh/conversion/polyDualMesh/makePolyDualMesh.C
new file mode 100644
index 0000000000000000000000000000000000000000..26eb18e26d0f59e3b2a4fa7a1f3aed8169f80d1f
--- /dev/null
+++ b/applications/utilities/mesh/conversion/polyDualMesh/makePolyDualMesh.C
@@ -0,0 +1,515 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Description
+    Calculate the dual of a polyMesh. Adheres to all the feature&patch edges.
+
+    Feature angle:
+    convex features : point becomes single boundary cell with multiple
+                      boundary faces.
+    concave features: point becomes multiple boundary cells.
+
+    -splitAllFaces:
+    Normally only constructs a single face between two cells. This single face
+    might be too distorted. splitAllFaces will create a single face for every
+    original cell the face passes through. The mesh will thus have
+    multiple faces inbetween two cells! (so is not strictly upper-triangular
+    anymore - checkMesh will complain)
+    -doNotPreserveFaceZones:
+    By default all faceZones are preserved by marking all faces, edges and
+    points on them as features. The -doNotPreserveFaceZones disables this
+    behaviour.
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "fvMesh.H"
+#include "mathematicalConstants.H"
+#include "polyTopoChange.H"
+#include "mapPolyMesh.H"
+#include "PackedList.H"
+#include "meshTools.H"
+#include "OFstream.H"
+#include "meshDualiser.H"
+#include "ReadFields.H"
+#include "volFields.H"
+#include "surfaceFields.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Naive feature detection. All boundary edges with angle > featureAngle become
+// feature edges. All points on feature edges become feature points. All
+// boundary faces become feature faces.
+void simpleMarkFeatures
+(
+    const polyMesh& mesh,
+    const PackedList<1>& isBoundaryEdge,
+    const scalar featureAngle,
+    const bool doNotPreserveFaceZones,
+
+    labelList& featureFaces,
+    labelList& featureEdges,
+    labelList& singleCellFeaturePoints,
+    labelList& multiCellFeaturePoints
+)
+{
+    scalar minCos = Foam::cos(featureAngle * mathematicalConstant::pi/180.0);
+
+    const polyBoundaryMesh& patches = mesh.boundaryMesh();
+
+    // Working sets
+    labelHashSet featureEdgeSet;
+    labelHashSet singleCellFeaturePointSet;
+    labelHashSet multiCellFeaturePointSet;
+
+
+    // 1. Mark all edges between patches
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    forAll(patches, patchI)
+    {
+        const polyPatch& pp = patches[patchI];
+        const labelList& meshEdges = pp.meshEdges();
+
+        // All patch corner edges. These need to be feature points & edges!
+        for (label edgeI = pp.nInternalEdges(); edgeI < pp.nEdges(); edgeI++)
+        {
+            label meshEdgeI = meshEdges[edgeI];
+            featureEdgeSet.insert(meshEdgeI);
+            singleCellFeaturePointSet.insert(mesh.edges()[meshEdgeI][0]);
+            singleCellFeaturePointSet.insert(mesh.edges()[meshEdgeI][1]);
+        }
+    }
+
+
+
+    // 2. Mark all geometric feature edges
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    // Make distinction between convex features where the boundary point becomes
+    // a single cell and concave features where the boundary point becomes
+    // multiple 'half' cells.
+
+    // Addressing for all outside faces
+    primitivePatch allBoundary
+    (
+        SubList<face>
+        (
+            mesh.faces(),
+            mesh.nFaces()-mesh.nInternalFaces(),
+            mesh.nInternalFaces()
+        ),
+        mesh.points()
+    );
+
+    // Check for non-manifold points (surface pinched at point)
+    allBoundary.checkPointManifold(false, &singleCellFeaturePointSet);
+
+    // Check for non-manifold edges (surface pinched at edge)
+    const labelListList& edgeFaces = allBoundary.edgeFaces();
+    const labelList& meshPoints = allBoundary.meshPoints();
+
+    forAll(edgeFaces, edgeI)
+    {
+        const labelList& eFaces = edgeFaces[edgeI];
+
+        if (eFaces.size() > 2)
+        {
+            const edge& e = allBoundary.edges()[edgeI];
+
+            //Info<< "Detected non-manifold boundary edge:" << edgeI
+            //    << " coords:"
+            //    << allBoundary.points()[meshPoints[e[0]]]
+            //    << allBoundary.points()[meshPoints[e[1]]] << endl;
+
+            singleCellFeaturePointSet.insert(meshPoints[e[0]]);
+            singleCellFeaturePointSet.insert(meshPoints[e[1]]);
+        }
+    }
+
+    // Check for features.
+    forAll(edgeFaces, edgeI)
+    {
+        const labelList& eFaces = edgeFaces[edgeI];
+
+        if (eFaces.size() == 2)
+        {
+            label f0 = eFaces[0];
+            label f1 = eFaces[1];
+
+            // check angle
+            const vector& n0 = allBoundary.faceNormals()[f0];
+            const vector& n1 = allBoundary.faceNormals()[f1];
+
+            if ((n0 & n1) < minCos)
+            {
+                const edge& e = allBoundary.edges()[edgeI];
+                label v0 = meshPoints[e[0]];
+                label v1 = meshPoints[e[1]];
+
+                label meshEdgeI = meshTools::findEdge(mesh, v0, v1);
+                featureEdgeSet.insert(meshEdgeI);
+
+                // Check if convex or concave by looking at angle
+                // between face centres and normal
+                vector c1c0
+                (
+                    allBoundary[f1].centre(allBoundary.points())
+                  - allBoundary[f0].centre(allBoundary.points())
+                );
+
+                if ((c1c0 & n0) > SMALL)
+                {
+                    // Found concave edge. Make into multiCell features
+                    Info<< "Detected concave feature edge:" << edgeI
+                        << " cos:" << (c1c0 & n0)
+                        << " coords:"
+                        << allBoundary.points()[v0]
+                        << allBoundary.points()[v1]
+                        << endl;
+
+                    singleCellFeaturePointSet.erase(v0);
+                    multiCellFeaturePointSet.insert(v0);
+                    singleCellFeaturePointSet.erase(v1);
+                    multiCellFeaturePointSet.insert(v1);
+                }
+                else
+                {
+                    // Convex. singleCell feature.
+                    if (!multiCellFeaturePointSet.found(v0))
+                    {
+                        singleCellFeaturePointSet.insert(v0);
+                    }
+                    if (!multiCellFeaturePointSet.found(v1))
+                    {
+                        singleCellFeaturePointSet.insert(v1);
+                    }
+                }
+            }
+        }
+    }
+
+
+    // 3. Mark all feature faces
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    // Face centres that need inclusion in the dual mesh
+    labelHashSet featureFaceSet(mesh.nFaces()-mesh.nInternalFaces());
+    // A. boundary faces.
+    for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
+    {
+        featureFaceSet.insert(faceI);
+    }
+
+    // B. face zones.
+    const faceZoneMesh& faceZones = mesh.faceZones();
+
+    if (doNotPreserveFaceZones)
+    {
+        if (faceZones.size() > 0)
+        {
+            WarningIn("simpleMarkFeatures(..)")
+                << "Detected " << faceZones.size()
+                << " faceZones. These will not be preserved."
+                << endl;
+        }
+    }
+    else
+    {
+        if (faceZones.size() > 0)
+        {
+            Info<< "Detected " << faceZones.size()
+                << " faceZones. Preserving these by marking their"
+                << " points, edges and faces as features." << endl;
+        }
+
+        forAll(faceZones, zoneI)
+        {
+            const faceZone& fz = faceZones[zoneI];
+
+            Info<< "Inserting all faces in faceZone " << fz.name()
+                << " as features." << endl;
+
+            forAll(fz, i)
+            {
+                label faceI = fz[i];
+                const face& f = mesh.faces()[faceI];
+                const labelList& fEdges = mesh.faceEdges()[faceI];
+
+                featureFaceSet.insert(faceI);
+                forAll(f, fp)
+                {
+                    // Mark point as multi cell point (since both sides of
+                    // face should have different cells)
+                    singleCellFeaturePointSet.erase(f[fp]);
+                    multiCellFeaturePointSet.insert(f[fp]);
+
+                    // Make sure there are points on the edges.
+                    featureEdgeSet.insert(fEdges[fp]);
+                }
+            }
+        }
+    }
+
+    // Transfer to arguments
+    featureFaces = featureFaceSet.toc();
+    featureEdges = featureEdgeSet.toc();
+    singleCellFeaturePoints = singleCellFeaturePointSet.toc();
+    multiCellFeaturePoints = multiCellFeaturePointSet.toc();
+}
+
+
+// Dump features to .obj files
+void dumpFeatures
+(
+    const polyMesh& mesh,
+    const labelList& featureFaces,
+    const labelList& featureEdges,
+    const labelList& singleCellFeaturePoints,
+    const labelList& multiCellFeaturePoints
+)
+{
+    {
+        OFstream str("featureFaces.obj");
+        Info<< "Dumping centres of featureFaces to obj file " << str.name()
+            << endl;
+        forAll(featureFaces, i)
+        {
+            meshTools::writeOBJ(str, mesh.faceCentres()[featureFaces[i]]);
+        }
+    }
+    {
+        OFstream str("featureEdges.obj");
+        Info<< "Dumping featureEdges to obj file " << str.name() << endl;
+        label vertI = 0;
+
+        forAll(featureEdges, i)
+        {
+            const edge& e = mesh.edges()[featureEdges[i]];
+            meshTools::writeOBJ(str, mesh.points()[e[0]]);
+            vertI++;
+            meshTools::writeOBJ(str, mesh.points()[e[1]]);
+            vertI++;
+            str<< "l " << vertI-1 << ' ' << vertI << nl;
+        }
+    }
+    {
+        OFstream str("singleCellFeaturePoints.obj");
+        Info<< "Dumping featurePoints that become a single cell to obj file "
+            << str.name() << endl;
+        forAll(singleCellFeaturePoints, i)
+        {
+            meshTools::writeOBJ(str, mesh.points()[singleCellFeaturePoints[i]]);
+        }
+    }
+    {
+        OFstream str("multiCellFeaturePoints.obj");
+        Info<< "Dumping featurePoints that become multiple cells to obj file "
+            << str.name() << endl;
+        forAll(multiCellFeaturePoints, i)
+        {
+            meshTools::writeOBJ(str, mesh.points()[multiCellFeaturePoints[i]]);
+        }
+    }
+}
+
+
+int main(int argc, char *argv[])
+{
+    argList::noParallel();
+#   include "addTimeOptions.H"
+    argList::validArgs.append("feature angle[0-180]");
+    argList::validOptions.insert("splitAllFaces", "");
+    argList::validOptions.insert("doNotPreserveFaceZones", "");
+    argList::validOptions.insert("overwrite", "");
+
+#   include "setRootCase.H"
+#   include "createTime.H"
+    // Get times list
+    instantList Times = runTime.times();
+#   include "checkTimeOptions.H"
+    runTime.setTime(Times[startTime], startTime);
+
+#   include "createMesh.H"
+
+    // Mark boundary edges and points.
+    // (Note: in 1.4.2 we can use the built-in mesh point ordering
+    //  facility instead)
+    PackedList<1> isBoundaryEdge(mesh.nEdges());
+    for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
+    {
+        const labelList& fEdges = mesh.faceEdges()[faceI];
+
+        forAll(fEdges, i)
+        {
+            isBoundaryEdge.set(fEdges[i], 1);
+        }
+    }
+
+    scalar featureAngle(readScalar(IStringStream(args.additionalArgs()[0])()));
+
+    scalar minCos = Foam::cos(featureAngle * mathematicalConstant::pi/180.0);
+
+    Info<< "Feature:" << featureAngle << endl
+        << "minCos :" << minCos << endl
+        << endl;
+
+
+    const bool splitAllFaces = args.options().found("splitAllFaces");
+    const bool overwrite = args.options().found("overwrite");
+    const bool doNotPreserveFaceZones = args.options().found
+    (
+        "doNotPreserveFaceZones"
+    );
+
+    // Face(centre)s that need inclusion in the dual mesh
+    labelList featureFaces;
+    // Edge(centre)s  ,,
+    labelList featureEdges;
+    // Points (that become a single cell) that need inclusion in the dual mesh
+    labelList singleCellFeaturePoints;
+    // Points (that become a mulitple cells)        ,,
+    labelList multiCellFeaturePoints;
+
+    // Sample implementation of feature detection.
+    simpleMarkFeatures
+    (
+        mesh,
+        isBoundaryEdge,
+        featureAngle,
+        doNotPreserveFaceZones,
+
+        featureFaces,
+        featureEdges,
+        singleCellFeaturePoints,
+        multiCellFeaturePoints
+    );
+
+    // If we want to split all polyMesh faces into one dualface per cell
+    // we are passing through we also need a point
+    // at the polyMesh facecentre and edgemid of the faces we want to
+    // split.
+    if (splitAllFaces)
+    {
+        featureEdges = identity(mesh.nEdges());
+        featureFaces = identity(mesh.nFaces());
+    }
+
+    // Write obj files for debugging
+    dumpFeatures
+    (
+        mesh,
+        featureFaces,
+        featureEdges,
+        singleCellFeaturePoints,
+        multiCellFeaturePoints
+    );
+
+
+
+    // Read objects in time directory
+    IOobjectList objects(mesh, runTime.timeName());
+
+    // Read vol fields.
+    PtrList<volScalarField> vsFlds;
+    ReadFields(mesh, objects, vsFlds);
+
+    PtrList<volVectorField> vvFlds;
+    ReadFields(mesh, objects, vvFlds);
+
+    PtrList<volSphericalTensorField> vstFlds;
+    ReadFields(mesh, objects, vstFlds);
+
+    PtrList<volSymmTensorField> vsymtFlds;
+    ReadFields(mesh, objects, vsymtFlds);
+
+    PtrList<volTensorField> vtFlds;
+    ReadFields(mesh, objects, vtFlds);
+
+    // Read surface fields.
+    PtrList<surfaceScalarField> ssFlds;
+    ReadFields(mesh, objects, ssFlds);
+
+    PtrList<surfaceVectorField> svFlds;
+    ReadFields(mesh, objects, svFlds);
+
+    PtrList<surfaceSphericalTensorField> sstFlds;
+    ReadFields(mesh, objects, sstFlds);
+
+    PtrList<surfaceSymmTensorField> ssymtFlds;
+    ReadFields(mesh, objects, ssymtFlds);
+
+    PtrList<surfaceTensorField> stFlds;
+    ReadFields(mesh, objects, stFlds);
+
+
+    // Topo change container
+    polyTopoChange meshMod(mesh.boundaryMesh().size());
+
+    // Mesh dualiser engine
+    meshDualiser dualMaker(mesh);
+
+    // Insert all commands into polyTopoChange to create dual of mesh. This does
+    // all the hard work.
+    dualMaker.setRefinement
+    (
+        splitAllFaces,
+        featureFaces,
+        featureEdges,
+        singleCellFeaturePoints,
+        multiCellFeaturePoints,
+        meshMod
+    );
+
+    // Create mesh, return map from old to new mesh.
+    autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
+
+    // Update fields
+    mesh.updateMesh(map);
+
+    // Optionally inflate mesh
+    if (map().hasMotionPoints())
+    {
+        mesh.movePoints(map().preMotionPoints());
+    }
+
+    if (!overwrite)
+    {
+        runTime++;
+        mesh.setInstance(runTime.timeName());
+    }
+
+    Info<< "Writing dual mesh to " << runTime.timeName() << endl;
+
+    mesh.write();
+ 
+    Info<< "End\n" << endl;
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/mesh/conversion/polyDualMesh/meshDualiser.C b/applications/utilities/mesh/conversion/polyDualMesh/meshDualiser.C
new file mode 100644
index 0000000000000000000000000000000000000000..4492a6f6b66d911cf96595ed9a5240ad11ff49c5
--- /dev/null
+++ b/applications/utilities/mesh/conversion/polyDualMesh/meshDualiser.C
@@ -0,0 +1,1489 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    meshDualiser
+
+\*---------------------------------------------------------------------------*/
+
+#include "meshDualiser.H"
+#include "meshTools.H"
+#include "polyMesh.H"
+#include "polyTopoChange.H"
+#include "mapPolyMesh.H"
+#include "edgeFaceCirculator.H"
+#include "mergePoints.H"
+#include "OFstream.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(meshDualiser, 0);
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::meshDualiser::checkPolyTopoChange(const polyTopoChange& meshMod)
+{
+    // Assume no removed points
+    pointField points(meshMod.points().size());
+    forAll(meshMod.points(), i)
+    {
+        points[i] = meshMod.points()[i];
+    }
+
+    labelList oldToNew;
+    pointField newPoints;
+    bool hasMerged = mergePoints
+    (
+        points,
+        1E-6,
+        false,
+        oldToNew,
+        newPoints
+    );
+
+    if (hasMerged)
+    {
+        labelListList newToOld(invertOneToMany(newPoints.size(), oldToNew));
+
+        forAll(newToOld, newI)
+        {
+            if (newToOld[newI].size() != 1)
+            {
+                FatalErrorIn
+                (
+                    "meshDualiser::checkPolyTopoChange(const polyTopoChange&)"
+                )   << "duplicate verts:" << newToOld[newI]
+                    << " coords:"
+                    << IndirectList<point>(points, newToOld[newI])()
+                    << abort(FatalError);
+            }
+        }
+    }
+}
+
+
+// Dump state so far.
+void Foam::meshDualiser::dumpPolyTopoChange
+(
+    const polyTopoChange& meshMod,
+    const fileName& prefix
+)
+{
+    OFstream str1(prefix + "Faces.obj");
+    OFstream str2(prefix + "Edges.obj");
+
+    Info<< "Dumping current polyTopoChange. Faces to " << str1.name()
+        << " , points and edges to " << str2.name() << endl;
+
+    const DynamicList<point>& points = meshMod.points();
+
+    forAll(points, pointI)
+    {
+        meshTools::writeOBJ(str1, points[pointI]);
+        meshTools::writeOBJ(str2, points[pointI]);
+    }
+
+    const DynamicList<face>& faces = meshMod.faces();
+
+    forAll(faces, faceI)
+    {
+        const face& f = faces[faceI];
+
+        str1<< 'f';
+        forAll(f, fp)
+        {
+            str1<< ' ' << f[fp]+1;
+        }
+        str1<< nl;
+
+        str2<< 'l';
+        forAll(f, fp)
+        {
+            str2<< ' ' << f[fp]+1;
+        }
+        str2<< ' ' << f[0]+1 << nl;
+    }
+}
+
+
+//- Given cell and point on mesh finds the corresponding dualCell. Most
+//  points become only one cell but the feature points might be split.
+Foam::label Foam::meshDualiser::findDualCell
+(
+    const label cellI,
+    const label pointI
+) const
+{
+    const labelList& dualCells = pointToDualCells_[pointI];
+
+    if (dualCells.size() == 1)
+    {
+        return dualCells[0];
+    }
+    else
+    {
+        label index = findIndex(mesh_.pointCells()[pointI], cellI);
+
+        return dualCells[index];
+    }
+}
+
+
+// Helper function to generate dualpoints on all boundary edges emanating
+// from (boundary & feature) point
+void Foam::meshDualiser::generateDualBoundaryEdges
+(
+    const PackedList<1>& isBoundaryEdge,
+    const label pointI,
+    polyTopoChange& meshMod
+)
+{
+    const labelList& pEdges = mesh_.pointEdges()[pointI];
+
+    forAll(pEdges, pEdgeI)
+    {
+        label edgeI = pEdges[pEdgeI];
+
+        if (edgeToDualPoint_[edgeI] == -1 && isBoundaryEdge.get(edgeI) == 1)
+        {
+            const edge& e = mesh_.edges()[edgeI];
+
+            edgeToDualPoint_[edgeI] = meshMod.addPoint
+            (
+                e.centre(mesh_.points()),
+                pointI, // masterPoint
+                -1,     // zoneID
+                true    // inCell
+            );
+        }
+    }
+}
+
+
+// Return true if point on face has same dual cells on both owner and neighbour
+// sides.
+bool Foam::meshDualiser::sameDualCell
+(
+    const label faceI,
+    const label pointI
+) const
+{
+    if (!mesh_.isInternalFace(faceI))
+    {
+        FatalErrorIn("sameDualCell(const label, const label)")
+            << "face:" << faceI << " is not internal face."
+            << abort(FatalError);
+    }
+
+    label own = mesh_.faceOwner()[faceI];
+    label nei = mesh_.faceNeighbour()[faceI];
+
+    return findDualCell(own, pointI) == findDualCell(nei, pointI);
+}
+
+
+Foam::label Foam::meshDualiser::addInternalFace
+(
+    const label masterPointI,
+    const label masterEdgeI,
+    const label masterFaceI,
+
+    const bool edgeOrder,
+    const label dualCell0,
+    const label dualCell1,
+    const DynamicList<label>& verts,
+    polyTopoChange& meshMod
+) const
+{
+    face newFace(verts);
+
+    if (edgeOrder != (dualCell0 < dualCell1))
+    {
+        reverse(newFace);
+    }
+
+    if (debug)
+    {
+        pointField facePoints
+        (
+            IndirectList<point>(meshMod.points(), newFace)()
+        );
+
+        labelList oldToNew;
+        pointField newPoints;
+        bool hasMerged = mergePoints
+        (
+            facePoints,
+            1E-6,
+            false,
+            oldToNew,
+            newPoints
+        );
+
+        if (hasMerged)
+        {
+            FatalErrorIn("addInternalFace(..)")
+                << "verts:" << verts << " newFace:" << newFace
+                << " face points:" << facePoints
+                << abort(FatalError);
+        }
+    }
+
+
+    label zoneID = -1;
+    bool zoneFlip = false;
+    if (masterFaceI != -1)
+    {
+        zoneID = mesh_.faceZones().whichZone(masterFaceI);
+
+        if (zoneID != -1)
+        {
+            const faceZone& fZone = mesh_.faceZones()[zoneID];
+
+            zoneFlip = fZone.flipMap()[fZone.whichFace(masterFaceI)];
+        }
+    }
+
+    label dualFaceI;
+
+    if (dualCell0 < dualCell1)
+    {
+        dualFaceI = meshMod.addFace
+        (
+            newFace,
+            dualCell0,      // own
+            dualCell1,      // nei
+            masterPointI,   // masterPointID
+            masterEdgeI,    // masterEdgeID
+            masterFaceI,    // masterFaceID
+            false,          // flipFaceFlux
+            -1,             // patchID
+            zoneID,         // zoneID
+            zoneFlip        // zoneFlip
+        );
+
+        //pointField dualPoints(meshMod.points());
+        //vector n(newFace.normal(dualPoints));
+        //n /= mag(n);
+        //Pout<< "Generated internal dualFace:" << dualFaceI
+        //    << " verts:" << newFace
+        //    << " points:" << IndirectList<point>(meshMod.points(), newFace)()
+        //    << " n:" << n
+        //    << " between dualowner:" << dualCell0
+        //    << " dualneigbour:" << dualCell1
+        //    << endl;
+    }
+    else
+    {
+        dualFaceI = meshMod.addFace
+        (
+            newFace,
+            dualCell1,      // own
+            dualCell0,      // nei
+            masterPointI,   // masterPointID
+            masterEdgeI,    // masterEdgeID
+            masterFaceI,    // masterFaceID
+            false,          // flipFaceFlux
+            -1,             // patchID
+            zoneID,         // zoneID
+            zoneFlip        // zoneFlip
+        );
+
+        //pointField dualPoints(meshMod.points());
+        //vector n(newFace.normal(dualPoints));
+        //n /= mag(n);
+        //Pout<< "Generated internal dualFace:" << dualFaceI
+        //    << " verts:" << newFace
+        //    << " points:" << IndirectList<point>(meshMod.points(), newFace)()
+        //    << " n:" << n
+        //    << " between dualowner:" << dualCell1
+        //    << " dualneigbour:" << dualCell0
+        //    << endl;
+    }
+    return dualFaceI;
+}
+
+
+Foam::label Foam::meshDualiser::addBoundaryFace
+(
+    const label masterPointI,
+    const label masterEdgeI,
+    const label masterFaceI,
+
+    const label dualCellI,
+    const label patchI,
+    const DynamicList<label>& verts,
+    polyTopoChange& meshMod
+) const
+{
+    face newFace(verts);
+
+    label zoneID = -1;
+    bool zoneFlip = false;
+    if (masterFaceI != -1)
+    {
+        zoneID = mesh_.faceZones().whichZone(masterFaceI);
+
+        if (zoneID != -1)
+        {
+            const faceZone& fZone = mesh_.faceZones()[zoneID];
+
+            zoneFlip = fZone.flipMap()[fZone.whichFace(masterFaceI)];
+        }
+    }
+
+    label dualFaceI = meshMod.addFace
+    (
+        newFace,
+        dualCellI,      // own
+        -1,             // nei
+        masterPointI,   // masterPointID
+        masterEdgeI,    // masterEdgeID
+        masterFaceI,    // masterFaceID
+        false,          // flipFaceFlux
+        patchI,         // patchID
+        zoneID,         // zoneID
+        zoneFlip        // zoneFlip
+    );
+
+    //pointField dualPoints(meshMod.points());
+    //vector n(newFace.normal(dualPoints));
+    //n /= mag(n);
+    //Pout<< "Generated boundary dualFace:" << dualFaceI
+    //    << " verts:" << newFace
+    //    << " points:" << IndirectList<point>(meshMod.points(), newFace)()
+    //    << " n:" << n
+    //    << " on dualowner:" << dualCellI
+    //    << endl;
+    return dualFaceI;
+}
+
+
+// Walks around edgeI.
+// splitFace=true : creates multiple faces
+// splitFace=false: creates single face if same dual cells on both sides,
+//                  multiple faces otherwise.
+void Foam::meshDualiser::createFacesAroundEdge
+(
+    const bool splitFace,
+    const PackedList<1>& isBoundaryEdge,
+    const label edgeI,
+    const label startFaceI,
+    polyTopoChange& meshMod,
+    boolList& doneEFaces
+) const
+{
+    const edge& e = mesh_.edges()[edgeI];
+    const labelList& eFaces = mesh_.edgeFaces()[edgeI];
+
+    label fp = edgeFaceCirculator::getMinIndex
+    (
+        mesh_.faces()[startFaceI],
+        e[0],
+        e[1]
+    );
+
+    edgeFaceCirculator ie
+    (
+        mesh_,
+        startFaceI, // face
+        true,       // ownerSide
+        fp,         // fp
+        isBoundaryEdge.get(edgeI) == 1  // isBoundaryEdge
+    );
+    ie.setCanonical();
+
+    bool edgeOrder = ie.sameOrder(e[0], e[1]);
+    label startFaceLabel = ie.faceLabel();
+
+    //Pout<< "At edge:" << edgeI << " verts:" << e
+    //    << " points:" << mesh_.points()[e[0]] << mesh_.points()[e[1]]
+    //    << " started walking at face:" << ie.faceLabel()
+    //    << " verts:" << mesh_.faces()[ie.faceLabel()]
+    //    << " edgeOrder:" << edgeOrder
+    //    << " in direction of cell:" << ie.cellLabel()
+    //    << endl;
+
+    // Walk and collect face.
+    DynamicList<label> verts(100);
+
+    if (edgeToDualPoint_[edgeI] != -1)
+    {
+        verts.append(edgeToDualPoint_[edgeI]);
+    }
+    if (faceToDualPoint_[ie.faceLabel()] != -1)
+    {
+        doneEFaces[findIndex(eFaces, ie.faceLabel())] = true;
+        verts.append(faceToDualPoint_[ie.faceLabel()]);
+    }
+    if (cellToDualPoint_[ie.cellLabel()] != -1)
+    {
+        verts.append(cellToDualPoint_[ie.cellLabel()]);
+    }
+
+    label currentDualCell0 = findDualCell(ie.cellLabel(), e[0]);
+    label currentDualCell1 = findDualCell(ie.cellLabel(), e[1]);
+
+    ++ie;
+
+    while (true)
+    {
+        label faceI = ie.faceLabel();
+
+        // Mark face as visited.
+        doneEFaces[findIndex(eFaces, faceI)] = true;
+
+        if (faceToDualPoint_[faceI] != -1)
+        {
+            verts.append(faceToDualPoint_[faceI]);
+        }
+
+        label cellI = ie.cellLabel();
+
+        if (cellI == -1)
+        {
+            // At ending boundary face. We've stored the face point above
+            // so this is the whole face.
+            break;
+        }
+
+
+        label dualCell0 = findDualCell(cellI, e[0]);
+        label dualCell1 = findDualCell(cellI, e[1]);
+
+        // Generate face. (always if splitFace=true; only if needed to
+        // separate cells otherwise)
+        if
+        (
+            splitFace
+         || (
+                dualCell0 != currentDualCell0
+             || dualCell1 != currentDualCell1
+            )
+        )
+        {
+            // Close current face.
+            addInternalFace
+            (
+                -1,         // masterPointI
+                edgeI,      // masterEdgeI
+                -1,         // masterFaceI
+                edgeOrder,
+                currentDualCell0,
+                currentDualCell1,
+                verts.shrink(),
+                meshMod
+            );
+
+            // Restart
+            currentDualCell0 = dualCell0;
+            currentDualCell1 = dualCell1;
+
+            verts.clear();
+            if (edgeToDualPoint_[edgeI] != -1)
+            {
+                verts.append(edgeToDualPoint_[edgeI]);
+            }
+            if (faceToDualPoint_[faceI] != -1)
+            {
+                verts.append(faceToDualPoint_[faceI]);
+            }
+        }
+
+        if (cellToDualPoint_[cellI] != -1)
+        {
+            verts.append(cellToDualPoint_[cellI]);
+        }
+
+        ++ie;
+
+        if (ie == ie.end())
+        {
+            // Back at start face (for internal edge only). See if this needs
+            // adding.
+            if (isBoundaryEdge.get(edgeI) == 0)
+            {
+                label startDual = faceToDualPoint_[startFaceLabel];
+
+                if (startDual != -1 && findIndex(verts, startDual) == -1)
+                {
+                    verts.append(startDual);
+                }
+            }
+            break;
+        }
+    }
+
+    verts.shrink();
+    addInternalFace
+    (
+        -1,         // masterPointI
+        edgeI,      // masterEdgeI
+        -1,         // masterFaceI
+        edgeOrder,
+        currentDualCell0,
+        currentDualCell1,
+        verts,
+        meshMod
+    );
+}
+
+
+// Walks around circumference of faceI. Creates single face. Gets given
+// starting (feature) edge to start from. Returns ending edge. (all edges
+// in form of index in faceEdges)
+void Foam::meshDualiser::createFaceFromInternalFace
+(
+    const label faceI,
+    label& fp,
+    polyTopoChange& meshMod
+) const
+{
+    const face& f = mesh_.faces()[faceI];
+    const labelList& fEdges = mesh_.faceEdges()[faceI];
+    label own = mesh_.faceOwner()[faceI];
+    label nei = mesh_.faceNeighbour()[faceI];
+
+    //Pout<< "createFaceFromInternalFace : At face:" << faceI
+    //    << " verts:" << f
+    //    << " points:" << IndirectList<point>(mesh_.points(), f)()
+    //    << " started walking at edge:" << fEdges[fp]
+    //    << " verts:" << mesh_.edges()[fEdges[fp]]
+    //    << endl;
+
+
+    // Walk and collect face.
+    DynamicList<label> verts(100);
+
+    verts.append(faceToDualPoint_[faceI]);
+    verts.append(edgeToDualPoint_[fEdges[fp]]);
+
+    // Step to vertex after edge mid
+    fp = f.fcIndex(fp);
+
+    // Get cells on either side of face at that point
+    label currentDualCell0 = findDualCell(own, f[fp]);
+    label currentDualCell1 = findDualCell(nei, f[fp]);
+
+    forAll(f, i)
+    {
+        // Check vertex
+        if (pointToDualPoint_[f[fp]] != -1)
+        {
+            verts.append(pointToDualPoint_[f[fp]]);
+        }
+
+        // Edge between fp and fp+1
+        label edgeI = fEdges[fp];
+
+        if (edgeToDualPoint_[edgeI] != -1)
+        {
+            verts.append(edgeToDualPoint_[edgeI]);
+        }
+
+        // Next vertex on edge
+        label nextFp = f.fcIndex(fp);
+
+        // Get dual cells on nextFp to check whether face needs closing.
+        label dualCell0 = findDualCell(own, f[nextFp]);
+        label dualCell1 = findDualCell(nei, f[nextFp]);
+
+        if (dualCell0 != currentDualCell0 || dualCell1 != currentDualCell1)
+        {
+            // Check: make sure that there is a midpoint on the edge.
+            if (edgeToDualPoint_[edgeI] == -1)
+            {
+                FatalErrorIn("createFacesFromInternalFace(..)")
+                    << "face:" << faceI << " verts:" << f
+                    << " points:" << IndirectList<point>(mesh_.points(), f)()
+                    << " no feature edge between " << f[fp]
+                    << " and " << f[nextFp] << " although have different"
+                    << " dual cells." << endl
+                    << "point " << f[fp] << " has dual cells "
+                    << currentDualCell0 << " and " << currentDualCell1
+                    << " ; point "<< f[nextFp] << " has dual cells "
+                    << dualCell0 << " and " << dualCell1
+                    << abort(FatalError);
+            }
+
+
+            // Close current face.
+            verts.shrink();
+            addInternalFace
+            (
+                -1,         // masterPointI
+                -1,         // masterEdgeI
+                faceI,      // masterFaceI
+                true,       // edgeOrder,
+                currentDualCell0,
+                currentDualCell1,
+                verts,
+                meshMod
+            );
+            break;
+        }
+
+        fp = nextFp;
+    }
+}
+
+
+// Given a point on a face converts the faces around the point.
+// (pointFaces()). Gets starting face and marks off visited faces in donePFaces.
+void Foam::meshDualiser::createFacesAroundBoundaryPoint
+(
+    const label patchI,
+    const label patchPointI,
+    const label startFaceI,
+    polyTopoChange& meshMod,
+    boolList& donePFaces            // pFaces visited
+) const
+{
+    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
+    const polyPatch& pp = patches[patchI];
+    const labelList& pFaces = pp.pointFaces()[patchPointI];
+    const labelList& own = mesh_.faceOwner();
+
+    label pointI = pp.meshPoints()[patchPointI];
+
+    if (pointToDualPoint_[pointI] == -1)
+    {
+        // Not a feature point. Loop over all connected
+        // pointFaces.
+
+        // Starting face
+        label faceI = startFaceI;
+
+        DynamicList<label> verts(4);
+
+        while (true)
+        {
+            label index = findIndex(pFaces, faceI-pp.start());
+
+            // Has face been visited already?
+            if (donePFaces[index])
+            {
+                break;
+            }
+            donePFaces[index] = true;
+
+            // Insert face centre
+            verts.append(faceToDualPoint_[faceI]);
+
+            label dualCellI = findDualCell(own[faceI], pointI);
+
+            // Get the edge before the patchPointI
+            const face& f = mesh_.faces()[faceI];
+            label fp = findIndex(f, pointI);
+            label prevFp = f.rcIndex(fp);
+            label edgeI = mesh_.faceEdges()[faceI][prevFp];
+
+            if (edgeToDualPoint_[edgeI] != -1)
+            {
+                verts.append(edgeToDualPoint_[edgeI]);
+            }
+
+            // Get next boundary face (whilst staying on edge).
+            edgeFaceCirculator circ
+            (
+                mesh_,
+                faceI,
+                true,   // ownerSide
+                prevFp, // index of edge in face
+                true    // isBoundaryEdge
+            );
+
+            do
+            {
+                ++circ;
+            }
+            while (mesh_.isInternalFace(circ.faceLabel()));
+
+            // Step to next face
+            faceI = circ.faceLabel();
+
+            if (faceI < pp.start() || faceI >= pp.start()+pp.size())
+            {
+                FatalErrorIn
+                (
+                    "meshDualiser::createFacesAroundBoundaryPoint(..)"
+                )   << "Walked from face on patch:" << patchI
+                    << " to face:" << faceI
+                    << " fc:" << mesh_.faceCentres()[faceI]
+                    << " on patch:" << patches.whichPatch(faceI) 
+                    << abort(FatalError);
+            }
+
+            // Check if different cell.
+            if (dualCellI != findDualCell(own[faceI], pointI))
+            {
+                FatalErrorIn
+                (
+                    "meshDualiser::createFacesAroundBoundaryPoint(..)"
+                )   << "Different dual cells but no feature edge"
+                    << " inbetween point:" << pointI
+                    << " coord:" << mesh_.points()[pointI]
+                    << abort(FatalError);
+            }
+        }
+
+        verts.shrink();
+
+        label dualCellI = findDualCell(own[faceI], pointI);
+
+        //Bit dodgy: create dualface from the last face (instead of from
+        // the central point). This will also use the original faceZone to
+        // put the new face (which might span multiple original faces) in.
+
+        addBoundaryFace
+        (
+            //pointI,     // masterPointI
+            -1,         // masterPointI
+            -1,         // masterEdgeI
+            faceI,      // masterFaceI
+            dualCellI,
+            patchI,
+            verts,
+            meshMod
+        );
+    }
+    else
+    {
+        label faceI = startFaceI;
+
+        // Storage for face
+        DynamicList<label> verts(mesh_.faces()[faceI].size());
+
+        // Starting point.
+        verts.append(pointToDualPoint_[pointI]);
+
+        // Find edge between pointI and next point on face.
+        const labelList& fEdges = mesh_.faceEdges()[faceI];
+        label nextEdgeI = fEdges[findIndex(mesh_.faces()[faceI], pointI)];
+        if (edgeToDualPoint_[nextEdgeI] != -1)
+        {
+            verts.append(edgeToDualPoint_[nextEdgeI]);
+        }
+
+        do
+        {
+            label index = findIndex(pFaces, faceI-pp.start());
+
+            // Has face been visited already?
+            if (donePFaces[index])
+            {
+                break;
+            }
+            donePFaces[index] = true;
+
+            // Face centre
+            verts.append(faceToDualPoint_[faceI]);
+
+            // Find edge before pointI on faceI
+            const labelList& fEdges = mesh_.faceEdges()[faceI];
+            const face& f = mesh_.faces()[faceI];
+            label prevFp = f.rcIndex(findIndex(f, pointI));
+            label edgeI = fEdges[prevFp];
+
+            if (edgeToDualPoint_[edgeI] != -1)
+            {
+                // Feature edge. Close any face so far. Note: uses face to
+                // create dualFace from. Could use pointI instead.
+                verts.append(edgeToDualPoint_[edgeI]);
+                addBoundaryFace
+                (
+                    -1,     // masterPointI
+                    -1,     // masterEdgeI
+                    faceI,  // masterFaceI
+                    findDualCell(own[faceI], pointI),
+                    patchI,
+                    verts.shrink(),
+                    meshMod
+                );
+                verts.clear();
+
+                verts.append(pointToDualPoint_[pointI]);
+                verts.append(edgeToDualPoint_[edgeI]);
+            }
+
+            // Cross edgeI to next boundary face
+            edgeFaceCirculator circ
+            (
+                mesh_,
+                faceI,
+                true,   // ownerSide
+                prevFp, // index of edge in face
+                true    // isBoundaryEdge
+            );
+
+            do
+            {
+                ++circ;
+            }
+            while (mesh_.isInternalFace(circ.faceLabel()));
+
+            // Step to next face. Quit if not on same patch.
+            faceI = circ.faceLabel();
+        }
+        while
+        (
+            faceI != startFaceI
+         && faceI >= pp.start()
+         && faceI < pp.start()+pp.size()
+        );
+
+        if (verts.size() > 2)
+        {
+            // Note: face created from face, not from pointI
+            addBoundaryFace
+            (
+                -1,             // masterPointI
+                -1,             // masterEdgeI
+                startFaceI,     // masterFaceI
+                findDualCell(own[faceI], pointI),
+                patchI,
+                verts.shrink(),
+                meshMod
+            );
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::meshDualiser::meshDualiser(const polyMesh& mesh)
+:
+    mesh_(mesh),
+    pointToDualCells_(mesh_.nPoints()),
+    pointToDualPoint_(mesh_.nPoints(), -1),
+    cellToDualPoint_(mesh_.nCells()),
+    faceToDualPoint_(mesh_.nFaces(), -1),
+    edgeToDualPoint_(mesh_.nEdges(), -1)
+{}
+  
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::meshDualiser::setRefinement
+(
+    const bool splitFace,
+    const labelList& featureFaces,
+    const labelList& featureEdges,
+    const labelList& singleCellFeaturePoints,
+    const labelList& multiCellFeaturePoints,
+    polyTopoChange& meshMod
+)
+{
+    const labelList& own = mesh_.faceOwner();
+    const labelList& nei = mesh_.faceNeighbour();
+    const vectorField& cellCentres = mesh_.cellCentres();
+
+    // Mark boundary edges and points.
+    // (Note: in 1.4.2 we can use the built-in mesh point ordering
+    //  facility instead)
+    PackedList<1> isBoundaryEdge(mesh_.nEdges());
+    for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
+    {
+        const labelList& fEdges = mesh_.faceEdges()[faceI];
+
+        forAll(fEdges, i)
+        {
+            isBoundaryEdge.set(fEdges[i], 1);
+        }
+    }
+
+
+    if (splitFace)
+    {
+        // This is a special mode where whenever we are walking around an edge
+        // every area through a cell becomes a separate dualface. So two
+        // dual cells will probably have more than one dualface between them!
+        // This mode implies that
+        // - all faces have to be feature faces since there has to be a
+        //   dualpoint at the face centre.
+        // - all edges have to be feature edges ,,
+        boolList featureFaceSet(mesh_.nFaces(), false);
+        forAll(featureFaces, i)
+        {
+            featureFaceSet[featureFaces[i]] = true;
+        }
+        label faceI = findIndex(featureFaceSet, false);
+
+        if (faceI != -1)
+        {
+            FatalErrorIn
+            (
+                "meshDualiser::setRefinement"
+                "(const labelList&, const labelList&, const labelList&"
+                ", const labelList, polyTopoChange&)"
+            )   << "In split-face-mode (splitFace=true) but not all faces"
+                << " marked as feature faces." << endl
+                << "First conflicting face:" << faceI
+                << " centre:" << mesh_.faceCentres()[faceI]
+                << abort(FatalError);
+        }
+
+        boolList featureEdgeSet(mesh_.nEdges(), false);
+        forAll(featureEdges, i)
+        {
+            featureEdgeSet[featureEdges[i]] = true;
+        }
+        label edgeI = findIndex(featureEdgeSet, false);
+
+        if (edgeI != -1)
+        {
+            const edge& e = mesh_.edges()[edgeI];
+            FatalErrorIn
+            (
+                "meshDualiser::setRefinement"
+                "(const labelList&, const labelList&, const labelList&"
+                ", const labelList, polyTopoChange&)"
+            )   << "In split-face-mode (splitFace=true) but not all edges"
+                << " marked as feature edges." << endl
+                << "First conflicting edge:" << edgeI
+                << " verts:" << e
+                << " coords:" << mesh_.points()[e[0]] << mesh_.points()[e[1]]
+                << abort(FatalError);
+        }
+    }
+    else
+    {
+        // Check that all boundary faces are feature faces.
+
+        boolList featureFaceSet(mesh_.nFaces(), false);
+        forAll(featureFaces, i)
+        {
+            featureFaceSet[featureFaces[i]] = true;
+        }
+        for
+        (
+            label faceI = mesh_.nInternalFaces();
+            faceI < mesh_.nFaces();
+            faceI++
+        )
+        {
+            if (!featureFaceSet[faceI])
+            {
+                FatalErrorIn
+                (
+                    "meshDualiser::setRefinement"
+                    "(const labelList&, const labelList&, const labelList&"
+                    ", const labelList, polyTopoChange&)"
+                )   << "Not all boundary faces marked as feature faces."
+                    << endl
+                    << "First conflicting face:" << faceI
+                    << " centre:" << mesh_.faceCentres()[faceI]
+                    << abort(FatalError);
+            }
+        }
+    }
+
+
+
+
+    // Start creating cells, points, and faces (in that order)
+
+
+    // 1. Mark which cells to create
+    // Mostly every point becomes one cell but sometimes (for feature points)
+    // all cells surrounding a feature point become cells. Also a non-manifold
+    // point can create two cells! So a dual cell is uniquely defined by a
+    // mesh point + cell (as in pointCells index)
+
+    // 2. Mark which face centres to create
+
+    // 3. Internal faces can now consist of
+    //      - only cell centres of walk around edge
+    //      - cell centres + face centres of walk around edge
+    //      - same but now other side is not a single cell
+
+    // 4. Boundary faces (or internal faces between cell zones!) now consist of
+    //      - walk around boundary point.
+
+
+
+    autoPtr<OFstream> dualCcStr;
+    if (debug)
+    {
+        dualCcStr.reset(new OFstream("dualCc.obj"));
+        Pout<< "Dumping centres of dual cells to " << dualCcStr().name()
+            << endl;
+    }
+
+
+    // Dual cells (from points)
+    // ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    // pointToDualCells_[pointI]
+    // - single entry : all cells surrounding point all become the same
+    //                  cell.
+    // - multiple entries: in order of pointCells.
+
+
+    // feature points that become single cell
+    forAll(singleCellFeaturePoints, i)
+    {
+        label pointI = singleCellFeaturePoints[i];
+
+        pointToDualPoint_[pointI] = meshMod.addPoint
+        (
+            mesh_.points()[pointI],
+            pointI,                                 // masterPoint
+            mesh_.pointZones().whichZone(pointI),   // zoneID
+            true                                    // inCell
+        );
+
+        // Generate single cell
+        pointToDualCells_[pointI].setSize(1);
+        pointToDualCells_[pointI][0] = meshMod.addCell
+        (
+            pointI, //masterPointID,
+            -1,     //masterEdgeID,
+            -1,     //masterFaceID,
+            -1,     //masterCellID,
+            -1      //zoneID
+        );
+        if (dualCcStr.valid())
+        {
+            meshTools::writeOBJ(dualCcStr(), mesh_.points()[pointI]);
+        }
+    }
+
+    // feature points that become multiple cells
+    forAll(multiCellFeaturePoints, i)
+    {
+        label pointI = multiCellFeaturePoints[i];
+
+        if (pointToDualCells_[pointI].size() > 0)
+        {
+            FatalErrorIn
+            (
+                "meshDualiser::setRefinement"
+                "(const labelList&, const labelList&, const labelList&"
+                ", const labelList, polyTopoChange&)"
+            )   << "Point " << pointI << " at:" << mesh_.points()[pointI]
+                << " is both in singleCellFeaturePoints"
+                << " and multiCellFeaturePoints."
+                << abort(FatalError);
+        }
+
+        pointToDualPoint_[pointI] = meshMod.addPoint
+        (
+            mesh_.points()[pointI],
+            pointI,                                 // masterPoint
+            mesh_.pointZones().whichZone(pointI),   // zoneID
+            true                                    // inCell
+        );
+
+        // Create dualcell for every cell connected to dual point
+
+        const labelList& pCells = mesh_.pointCells()[pointI];
+
+        pointToDualCells_[pointI].setSize(pCells.size());
+
+        forAll(pCells, pCellI)
+        {
+            pointToDualCells_[pointI][pCellI] = meshMod.addCell
+            (
+                pointI,                                     //masterPointID
+                -1,                                         //masterEdgeID
+                -1,                                         //masterFaceID
+                -1,                                         //masterCellID
+                mesh_.cellZones().whichZone(pCells[pCellI]) //zoneID
+            );
+            if (dualCcStr.valid())
+            {
+                meshTools::writeOBJ
+                (
+                    dualCcStr(),
+                    0.5*(mesh_.points()[pointI]+cellCentres[pCells[pCellI]])
+                );
+            }
+        }
+    }
+    // Normal points
+    forAll(mesh_.points(), pointI)
+    {
+        if (pointToDualCells_[pointI].size() == 0)
+        {
+            pointToDualCells_[pointI].setSize(1);
+            pointToDualCells_[pointI][0] = meshMod.addCell
+            (
+                pointI, //masterPointID,
+                -1,     //masterEdgeID,
+                -1,     //masterFaceID,
+                -1,     //masterCellID,
+                -1      //zoneID
+            );
+
+            if (dualCcStr.valid())
+            {
+                meshTools::writeOBJ(dualCcStr(), mesh_.points()[pointI]);
+            }
+        }
+    }
+
+
+    // Dual points (from cell centres, feature faces, feature edges)
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    forAll(cellToDualPoint_, cellI)
+    {
+        cellToDualPoint_[cellI] = meshMod.addPoint
+        (
+            cellCentres[cellI],
+            mesh_.faces()[mesh_.cells()[cellI][0]][0],     // masterPoint
+            -1,     // zoneID
+            true    // inCell
+        );
+    }
+
+    // From face to dual point
+
+    forAll(featureFaces, i)
+    {
+        label faceI = featureFaces[i];
+
+        faceToDualPoint_[faceI] = meshMod.addPoint
+        (
+            mesh_.faceCentres()[faceI],
+            mesh_.faces()[faceI][0],     // masterPoint
+            -1,     // zoneID
+            true    // inCell
+        );
+    }
+    // Detect whether different dual cells on either side of a face. This
+    // would neccesitate having a dual face built from the face and thus a
+    // dual point at the face centre.
+    for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
+    {
+        if (faceToDualPoint_[faceI] == -1)
+        {
+            const face& f = mesh_.faces()[faceI];
+
+            forAll(f, fp)
+            {
+                label ownDualCell = findDualCell(own[faceI], f[fp]);
+                label neiDualCell = findDualCell(nei[faceI], f[fp]);
+
+                if (ownDualCell != neiDualCell)
+                {
+                    faceToDualPoint_[faceI] = meshMod.addPoint
+                    (
+                        mesh_.faceCentres()[faceI],
+                        f[fp],  // masterPoint
+                        -1,     // zoneID
+                        true    // inCell
+                    );
+
+                    break;
+                }
+            }
+        }
+    }
+
+    // From edge to dual point
+
+    forAll(featureEdges, i)
+    {
+        label edgeI = featureEdges[i];
+
+        const edge& e = mesh_.edges()[edgeI];
+
+        edgeToDualPoint_[edgeI] = meshMod.addPoint
+        (
+            e.centre(mesh_.points()),
+            e[0],   // masterPoint
+            -1,     // zoneID
+            true    // inCell
+        );
+    }
+
+    // Detect whether different dual cells on either side of an edge. This
+    // would neccesitate having a dual face built perpendicular to the edge
+    // and thus a dual point at the mid of the edge.
+    // Note: not really true - the face can be built without the edge centre!
+    const labelListList& edgeCells = mesh_.edgeCells();
+
+    forAll(edgeCells, edgeI)
+    {
+       if (edgeToDualPoint_[edgeI] == -1)
+       {
+            const edge& e = mesh_.edges()[edgeI];
+
+            // We need a point on the edge if not all cells on both sides
+            // are the same. 
+
+            const labelList& eCells = mesh_.edgeCells()[edgeI];
+
+            label dualE0 = findDualCell(eCells[0], e[0]);
+            label dualE1 = findDualCell(eCells[0], e[1]);
+
+            for (label i = 1; i < eCells.size(); i++)
+            {
+                label newDualE0 = findDualCell(eCells[i], e[0]);
+
+                if (dualE0 != newDualE0)
+                {
+                    edgeToDualPoint_[edgeI] = meshMod.addPoint
+                    (
+                        e.centre(mesh_.points()),
+                        e[0],                               // masterPoint
+                        mesh_.pointZones().whichZone(e[0]), // zoneID
+                        true                                // inCell
+                    );
+
+                    break;
+                }
+
+                label newDualE1 = findDualCell(eCells[i], e[1]);
+
+                if (dualE1 != newDualE1)
+                {
+                    edgeToDualPoint_[edgeI] = meshMod.addPoint
+                    (
+                        e.centre(mesh_.points()),
+                        e[1],   // masterPoint
+                        mesh_.pointZones().whichZone(e[1]), // zoneID
+                        true    // inCell
+                    );
+
+                    break;
+                }
+            }
+        }
+    }
+
+    // Make sure all boundary edges emanating from feature points are
+    // feature edges as well.
+    forAll(singleCellFeaturePoints, i)
+    {
+        generateDualBoundaryEdges
+        (
+            isBoundaryEdge,
+            singleCellFeaturePoints[i],
+            meshMod
+        );
+    }
+    forAll(multiCellFeaturePoints, i)
+    {
+        generateDualBoundaryEdges
+        (
+            isBoundaryEdge,
+            multiCellFeaturePoints[i],
+            meshMod
+        );
+    }
+
+
+    // Check for duplicate points
+    if (debug)
+    {
+        dumpPolyTopoChange(meshMod, "generatedPoints_");
+        checkPolyTopoChange(meshMod);
+    }
+
+
+    // Now we have all points and cells
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    //  - pointToDualCells_ : per point a single dualCell or multiple dualCells
+    //  - pointToDualPoint_ : per point -1 or the dual point at the coordinate
+    //  - edgeToDualPoint_  : per edge -1 or the edge centre
+    //  - faceToDualPoint_  : per face -1 or the face centre
+    //  - cellToDualPoint_  : per cell the cell centre
+    // Now we have to walk all edges and construct faces. Either single face
+    // per edge or multiple (-if nonmanifold edge -if different dualcells)
+
+    const edgeList& edges = mesh_.edges();
+
+    forAll(edges, edgeI)
+    {
+        const labelList& eFaces = mesh_.edgeFaces()[edgeI];
+
+        boolList doneEFaces(eFaces.size(), false);
+
+        forAll(eFaces, i)
+        {
+            if (!doneEFaces[i])
+            {
+                // We found a face that hasn't yet been visited. This might
+                // happen for non-manifold edges where a single edge can
+                // become multiple faces.
+
+                label startFaceI = eFaces[i];
+
+                //Pout<< "Walking edge:" << edgeI
+                //    << " points:" << mesh_.points()[e[0]]
+                //    << mesh_.points()[e[1]]
+                //    << " startFace:" << startFaceI
+                //    << " at:" << mesh_.faceCentres()[startFaceI]
+                //    << endl;
+
+                createFacesAroundEdge
+                (
+                    splitFace,
+                    isBoundaryEdge,
+                    edgeI,
+                    startFaceI,
+                    meshMod,
+                    doneEFaces
+                );
+            }
+        }
+    }
+
+    if (debug)
+    {
+        dumpPolyTopoChange(meshMod, "generatedFacesFromEdges_");
+    }
+
+    // Create faces from feature faces. These can be internal or external faces.
+    // - feature face : centre needs to be included.
+    //      - single cells on either side: triangulate
+    //      - multiple cells: create single face between unique cell pair. Only
+    //                        create face where cells differ on either side.
+    // - non-feature face : inbetween cell zones.
+    forAll(faceToDualPoint_, faceI)
+    {
+        if (faceToDualPoint_[faceI] != -1 && mesh_.isInternalFace(faceI))
+        {
+            const face& f = mesh_.faces()[faceI];
+            const labelList& fEdges = mesh_.faceEdges()[faceI];
+
+            // Starting edge
+            label fp = 0;
+
+            do
+            {
+                // Find edge that is in dual mesh and where the
+                // next point (fp+1) has different dual cells on either side.
+                bool foundStart = false;
+
+                do
+                {
+                    if
+                    (
+                        edgeToDualPoint_[fEdges[fp]] != -1
+                    && !sameDualCell(faceI, f.nextLabel(fp))
+                    )
+                    {
+                        foundStart = true;
+                        break;
+                    }
+                    fp = f.fcIndex(fp);
+                }
+                while (fp != 0);
+
+                if (!foundStart)
+                {
+                    break;
+                }
+
+                // Walk from edge fp and generate a face.
+                createFaceFromInternalFace
+                (
+                    faceI,
+                    fp,
+                    meshMod
+                );
+            }
+            while(fp != 0);
+        }
+    }
+
+    if (debug)
+    {
+        dumpPolyTopoChange(meshMod, "generatedFacesFromFeatFaces_");
+    }
+
+
+    // Create boundary faces. Every boundary point has one or more dualcells.
+    // These need to be closed.
+    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
+
+    forAll(patches, patchI)
+    {
+        const polyPatch& pp = patches[patchI];
+
+        const labelListList& pointFaces = pp.pointFaces();
+
+        forAll(pointFaces, patchPointI)
+        {
+            const labelList& pFaces = pointFaces[patchPointI];
+
+            boolList donePFaces(pFaces.size(), false);
+
+            forAll(pFaces, i)
+            {
+                if (!donePFaces[i])
+                {
+                    // Starting face
+                    label startFaceI = pp.start()+pFaces[i];
+
+                    //Pout<< "Walking around point:" << pointI
+                    //    << " coord:" << mesh_.points()[pointI]
+                    //    << " on patch:" << patchI
+                    //    << " startFace:" << startFaceI
+                    //    << " at:" << mesh_.faceCentres()[startFaceI]
+                    //    << endl;
+
+                    createFacesAroundBoundaryPoint
+                    (
+                        patchI,
+                        patchPointI,
+                        startFaceI,
+                        meshMod,
+                        donePFaces            // pFaces visited
+                    );
+                }
+            }
+        }
+    }
+
+    if (debug)
+    {
+        dumpPolyTopoChange(meshMod, "generatedFacesFromBndFaces_");
+    }
+}
+
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
+
+
+// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/mesh/conversion/polyDualMesh/meshDualiser.H b/applications/utilities/mesh/conversion/polyDualMesh/meshDualiser.H
new file mode 100644
index 0000000000000000000000000000000000000000..ee5599816c3c81fa9431af8c4929bd0ff5277cb6
--- /dev/null
+++ b/applications/utilities/mesh/conversion/polyDualMesh/meshDualiser.H
@@ -0,0 +1,262 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 1991-2007 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2 of the License, or (at your
+    option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Class
+    meshDualiser
+
+Description
+    Creates dual of polyMesh. Every point becomes a cell (or multiple cells
+    for feature points), a walk around every edge creates faces between them.
+
+    Put all points you want in the final mesh into featurePoints; all edge(mid)s
+    you want in the final mesh into featureEdges; all face(centre)s in
+    faceFaces.
+
+    Usually to preserve boundaries:
+        - all boundary faces are featureFaces
+        - all edges and points inbetween different patches are
+          featureEdges/points.
+
+    In same way you can also preserve internal faces (e.g. faceZones)
+
+SourceFiles
+    meshDualiser.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef meshDualiser_H
+#define meshDualiser_H
+
+#include "DynamicList.H"
+#include "PackedList.H"
+#include "boolList.H"
+#include "typeInfo.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+class polyMesh;
+class polyTopoChange;
+
+/*---------------------------------------------------------------------------*\
+                           Class meshDualiser Declaration
+\*---------------------------------------------------------------------------*/
+
+class meshDualiser
+{
+    // Private data
+
+        const polyMesh& mesh_;
+
+        //- From point on cell to dual cell. Either single entry or
+        //  one entry per pointCells
+        labelListList pointToDualCells_;
+
+        //- From point to dual point (or -1 if not feature point).
+        labelList pointToDualPoint_;
+
+        //- From cell to dual point. All cells become point
+        labelList cellToDualPoint_;
+
+        //- From face to dual point (or -1 if not feature face)
+        labelList faceToDualPoint_;
+
+        //- From edge to dual point (or -1 if not feature edge)
+        labelList edgeToDualPoint_;
+
+
+    // Private Member Functions
+
+        static void checkPolyTopoChange(const polyTopoChange&);
+
+        static void dumpPolyTopoChange(const polyTopoChange&, const fileName&);
+
+        //- Find dual cell given point and cell
+        label findDualCell(const label cellI, const label pointI) const;
+
+        //- Helper function to generate dualpoints on all boundary edges
+        //  emanating from (boundary & feature) point
+        void generateDualBoundaryEdges
+        (
+            const PackedList<1>&,
+            const label pointI,
+            polyTopoChange&
+        );
+
+        //- Check that owner and neighbour of face have same dual cell
+        bool sameDualCell
+        (
+            const label faceI,
+            const label pointI
+        ) const;
+
+        //- Add internal face
+        label addInternalFace
+        (
+            const label masterPointI,
+            const label masterEdgeI,
+            const label masterFaceI,
+
+            const bool edgeOrder,
+            const label dualCell0,
+            const label dualCell1,
+            const DynamicList<label>& verts,
+            polyTopoChange& meshMod
+        ) const;
+
+        //- Add boundary face
+        label addBoundaryFace
+        (
+            const label masterPointI,
+            const label masterEdgeI,
+            const label masterFaceI,
+
+            const label dualCellI,
+            const label patchI,
+            const DynamicList<label>& verts,
+            polyTopoChange& meshMod
+        ) const;
+
+        //- Create internal faces walking around edge
+        void createFacesAroundEdge
+        (
+            const bool splitFace,
+            const PackedList<1>&,
+            const label edgeI,
+            const label startFaceI,
+            polyTopoChange&,
+            boolList& doneEFaces
+        ) const;
+
+        //- Create single internal face from internal face
+        void createFaceFromInternalFace
+        (
+            const label faceI,
+            label& fp,
+            polyTopoChange&
+        ) const;
+
+        //- Creates boundary faces walking around point on patchI.
+        void createFacesAroundBoundaryPoint
+        (
+            const label patchI,
+            const label patchPointI,
+            const label startFaceI,
+            polyTopoChange&,
+            boolList& donePFaces            // pFaces visited
+        ) const;
+
+        //- Disallow default bitwise copy construct
+        meshDualiser(const meshDualiser&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const meshDualiser&);
+
+
+public:
+
+    //- Runtime type information
+    ClassName("meshDualiser");
+
+
+    // Constructors
+
+        //- Construct from mesh
+        meshDualiser(const polyMesh&);
+
+
+    // Member Functions
+
+        // Access
+
+            //- From point on cell to dual cell. Either single entry or
+            //  one entry per pointCells.
+            const labelListList& pointToDualCells() const
+            {
+                return pointToDualCells_;
+            }
+
+            //- From point to dual point (or -1 if not feature point).
+            const labelList& pointToDualPoint() const
+            {
+                return pointToDualPoint_;
+            }
+
+            //- From cell to dual point (at cell centre). All cells become
+            //  points.
+            const labelList& cellToDualPoint() const
+            {
+                return cellToDualPoint_;
+            }
+
+            //- From face to dual point (at face centre; or -1 if not
+            //  feature face).
+            const labelList& faceToDualPoint() const
+            {
+                return faceToDualPoint_;
+            }
+
+            //- From edge to dual point (at edge mid; or -1 if not feature
+            //  edge).
+            const labelList& edgeToDualPoint() const
+            {
+                return edgeToDualPoint_;
+            }
+
+
+        // Edit
+
+
+            //- Insert all changes into meshMod to convert the polyMesh into
+            //  its dual.
+            //  featureFaces  : faces where we want a point at the face centre
+            //  featureEdges  : edges           ,,                 edge mid
+            //  featurePoints : points          ,,    point. Two variants:
+            //      singleCellFeaturePoints : point becomes one dualcell.
+            //          Use this for e.g. convex boundary points.
+            //      multiCellFeaturePoints : one dualcell per original cell
+            //          around point. Use this for e.g. concave boundary points
+            //          since it prevents big concave boundary cells.
+            void setRefinement
+            (
+                const bool splitFace,
+                const labelList& featureFaces,
+                const labelList& featureEdges,
+                const labelList& singleCellFeaturePoints,
+                const labelList& multiCellFeaturePoints,
+                polyTopoChange& meshMod
+            );
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/mesh/conversion/polyDualMesh/polyDualMeshApp.C b/applications/utilities/mesh/conversion/polyDualMesh/polyDualMeshApp.C
deleted file mode 100644
index ffa83149528d13d447f0179ca5c9997bf99f7611..0000000000000000000000000000000000000000
--- a/applications/utilities/mesh/conversion/polyDualMesh/polyDualMeshApp.C
+++ /dev/null
@@ -1,79 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by the
-    Free Software Foundation; either version 2 of the License, or (at your
-    option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM; if not, write to the Free Software Foundation,
-    Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-Application
-    polyDualMesh
-
-Description
-    Calculate the dual of a polyMesh. Adheres to all the feature&patch edges
-
-\*---------------------------------------------------------------------------*/
-
-#include "argList.H"
-#include "Time.H"
-#include "polyDualMesh.H"
-#include "mathematicalConstants.H"
-
-using namespace Foam;
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-int main(int argc, char *argv[])
-{
-    argList::noParallel();
-    argList::validArgs.append("feature angle[0-180]");
-    argList::validOptions.insert("overwrite", "");
-
-#   include "setRootCase.H"
-#   include "createTime.H"
-    runTime.functionObjects().off();
-#   include "createPolyMesh.H"
-
-    scalar featureAngle(readScalar(IStringStream(args.additionalArgs()[0])()));
-    bool overwrite = args.options().found("overwrite");
-
-    scalar minCos = Foam::cos(featureAngle * mathematicalConstant::pi/180.0);
-
-    Info<< "Feature:" << featureAngle << endl
-        << "minCos :" << minCos << endl
-        << endl;
-
-    polyDualMesh dualMesh(mesh, minCos);
-
-    if (!overwrite)
-    {
-        runTime++;
-    }
-
-    Pout<< "Writing dualMesh to " << runTime.timeName() << endl;
-
-    dualMesh.write();
-
-    Info << "End\n" << endl;
-
-    return 0;
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.C b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.C
index 7780ad3cfd71156946731ee7501d50e23ae59ab5..7ae5853896071eed97f745af3650334f3da92c2a 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.C
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.C
@@ -617,8 +617,10 @@ void Foam::vtkPV3Foam::addPatchNames(vtkRenderer* renderer)
         {
             const labelList& eFaces = edgeFaces[edgeI];
 
-            if (eFaces.size() != 2)
+            if (eFaces.size() == 1)
             {
+                // Note: could also do ones with > 2 faces but this gives
+                // too many zones for baffles
                 featEdge[edgeI] = true;
             }
             else if (mag(n[eFaces[0]] & n[eFaces[1]]) < 0.5)
diff --git a/bin/doxyFilt b/bin/doxyFilt
index e2f8ee0a1e695d99b9fbd337763e108efbab1955..c08851c53e93fd75810468f8c93e3d93e52feb38 100755
--- a/bin/doxyFilt
+++ b/bin/doxyFilt
@@ -50,9 +50,9 @@ then
    */applications/solvers/*.C | */applications/utilities/*.C )
       awkScript=$WM_PROJECT_DIR/bin/tools/doxyFilt-top.awk
       ;;
-   */applications/solvers/*.H | */applications/utilities/*.H )
-      awkScript=$WM_PROJECT_DIR/bin/tools/doxyFilt-ignore.awk
-      ;;
+#   */applications/solvers/*.H | */applications/utilities/*.H )
+#      awkScript=$WM_PROJECT_DIR/bin/tools/doxyFilt-ignore.awk
+#      ;;
    esac
 
    awk -f $awkScript $1 | \
diff --git a/doc/Doxygen/Doxyfile b/doc/Doxygen/Doxyfile
index f5ab1204243274fe5fd6471ea8031c14dee007ac..adf242f2359866c12316f45f21788e658d612fb6 100644
--- a/doc/Doxygen/Doxyfile
+++ b/doc/Doxygen/Doxyfile
@@ -14,6 +14,16 @@
 # Project related configuration options
 #---------------------------------------------------------------------------
 
+
+#--------------------------------
+# PATH FOR OPEN CFD LATEX MACROS
+#-------------------------------
+
+@INLUDE_PATH = $(TEXINPUTS)
+@INLUDE_PATH += $(BIBINPUTS)
+@INLUDE_PATH += $(BSTINPUTS)
+
+
 # This tag specifies the encoding used for all characters in the config file that
 # follow. The default is UTF-8 which is also the encoding used for all text before
 # the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into
@@ -477,9 +487,11 @@ WARN_LOGFILE           =
 # directories like "/usr/src/myproject". Separate the files or directories
 # with spaces.
 
-INPUT                  = $(WM_PROJECT_DIR)/src \
-                         $(WM_PROJECT_DIR)/applications/utilities \
-                         $(WM_PROJECT_DIR)/applications/solvers
+INPUT              = $(WM_PROJECT_DIR)/src \
+                     $(WM_PROJECT_DIR)/applications/utilities \
+                     $(WM_PROJECT_DIR)/applications/solvers
+
+
 
 # This tag can be used to specify the character encoding of the source files that
 # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
@@ -536,7 +548,9 @@ EXCLUDE_SYMBOLS        =
 # directories that contain example code fragments that are included (see
 # the \include command).
 
-EXAMPLE_PATH           =
+EXAMPLE_PATH           = $(TEXINPUTS) \
+ 						 $(BIBINPUTS) \
+						 $(BSTINPUTS)
 
 # If the value of the EXAMPLE_PATH tag contains directories, you can use the
 # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
@@ -824,7 +838,8 @@ PAPER_TYPE             = a4wide
 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
 # packages that should be included in the LaTeX output.
 
-EXTRA_PACKAGES         =
+EXTRA_PACKAGES         = conditionalEqns finiteVolume algorithmic tensorCommon \
+						 tensorOperator tensorEquation 
 
 # The LATEX_HEADER tag can be used to specify a personal LaTeX header for
 # the generated latex document. The header should contain everything until
diff --git a/etc/settings.csh b/etc/settings.csh
index 2c9a0eb656fccab2fb84d0de0004ca4ce24997d7..4bcf3eb5108e9aa5c54695574a8333ab510b065c 100644
--- a/etc/settings.csh
+++ b/etc/settings.csh
@@ -187,7 +187,7 @@ case MPICH-GM:
     setenv FOAM_MPI_LIBBIN $FOAM_LIBBIN/mpich-gm
     breaksw
 
-case MPICH-GM:
+case HPMPI:
     setenv MPI_HOME /opt/hpmpi
     setenv MPI_ARCH_PATH $MPI_HOME
     setenv MPICH_ROOT=$MPI_ARCH_PATH
diff --git a/src/OSspecific/Unix/regularExpression.H b/src/OSspecific/Unix/regularExpression.H
index 9924caef28fb7ecec52a9d272a91aa3328b8e6ba..fed14379ad917906960e587e9d7b67eb648cfa45 100644
--- a/src/OSspecific/Unix/regularExpression.H
+++ b/src/OSspecific/Unix/regularExpression.H
@@ -37,6 +37,8 @@ SourceFiles
 
 #include <sys/types.h>
 #include <regex.h>
+#include "string.H"
+#include "IOstreams.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -73,7 +75,7 @@ public:
         {
             preg_ = new regex_t;
 
-            if (regcomp(preg_, s.c_str(), REG_EXTENDED|REG_NOSUB) != 0)
+            if (regcomp(preg_, s.c_str(), REG_EXTENDED) != 0)
             {
                 FatalErrorIn
                 (
@@ -102,10 +104,12 @@ public:
         //- Matches?
         inline bool matches(const string& s) const
         {
-            size_t nmatch = 0;
-            regmatch_t *pmatch = NULL;
+            size_t nmatch = 1;
+            regmatch_t pmatch[1];
 
-            return regexec(preg_, s.c_str(), nmatch, pmatch, 0) == 0;
+            int errVal = regexec(preg_, s.c_str(), nmatch, pmatch, 0);
+
+            return (errVal == 0 && pmatch[0].rm_eo == label(s.size()));
         }
 };
 
diff --git a/src/OpenFOAM/db/dictionary/dictionary.C b/src/OpenFOAM/db/dictionary/dictionary.C
index ad960e7405779f5cfb38063d6f246dbd84d7bc56..265a2944cb03bb1f4c2b5f9024ad2c644002d885 100644
--- a/src/OpenFOAM/db/dictionary/dictionary.C
+++ b/src/OpenFOAM/db/dictionary/dictionary.C
@@ -27,6 +27,7 @@ License
 #include "dictionary.H"
 #include "primitiveEntry.H"
 #include "dictionaryEntry.H"
+#include "regularExpression.H"
 
 /* * * * * * * * * * * * * * * Static Member Data  * * * * * * * * * * * * * */
 
diff --git a/src/OpenFOAM/db/dictionary/dictionary.H b/src/OpenFOAM/db/dictionary/dictionary.H
index ac6ca6538968f56524931d0d6a84e2bf4c1f6370..b1d0d186f65c44c4026b7c06489b8164f0b1f277 100644
--- a/src/OpenFOAM/db/dictionary/dictionary.H
+++ b/src/OpenFOAM/db/dictionary/dictionary.H
@@ -60,7 +60,6 @@ SourceFiles
 #include "HashTable.H"
 #include "wordList.H"
 #include "className.H"
-#include "regularExpression.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -68,7 +67,7 @@ namespace Foam
 {
 
 // Forward declaration of friend functions and operators
-
+class regularExpression;
 class dictionary;
 Istream& operator>>(Istream&, dictionary&);
 Ostream& operator<<(Ostream&, const dictionary&);
diff --git a/src/OpenFOAM/db/dictionary/dictionaryIO.C b/src/OpenFOAM/db/dictionary/dictionaryIO.C
index b1d5fbcbc452f760e8d7805a4764fdd0e7240fa2..cb04194915c19fa99d86dfe1ed32ab9d82e7274c 100644
--- a/src/OpenFOAM/db/dictionary/dictionaryIO.C
+++ b/src/OpenFOAM/db/dictionary/dictionaryIO.C
@@ -27,6 +27,7 @@ License
 #include "dictionary.H"
 #include "IFstream.H"
 #include "inputModeEntry.H"
+#include "regularExpression.H"
 
 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
 
diff --git a/src/OpenFOAM/fields/Fields/transformField/transformField.C b/src/OpenFOAM/fields/Fields/transformField/transformField.C
index b81ef5ecda3dd3b07aa2703ecb884b82b065724f..3a4f596e4db7528a1e5823cb4cfdb0412f6b6f86 100644
--- a/src/OpenFOAM/fields/Fields/transformField/transformField.C
+++ b/src/OpenFOAM/fields/Fields/transformField/transformField.C
@@ -26,6 +26,7 @@ License
 
 #include "transformField.H"
 #include "FieldM.H"
+#include "diagTensor.H"
 
 // * * * * * * * * * * * * * * * global functions  * * * * * * * * * * * * * //
 
@@ -75,7 +76,8 @@ void Foam::transform
 {
     vector T = tr.t();
 
-    if (mag(tr.r().w()) > SMALL)
+    // Check if any rotation
+    if (mag(tr.r().R() - I) > SMALL)
     {
         transform(rtf, tr.r(), tf);
 
@@ -90,6 +92,10 @@ void Foam::transform
         {
             TFOR_ALL_F_OP_S_OP_F(vector, rtf, =, vector, T, +, vector, tf);
         }
+        else
+        {
+            rtf = vector::zero;
+        }
     }
 }
 
diff --git a/src/engine/ignition/ignitionSite.C b/src/engine/ignition/ignitionSite.C
index 26b084456c28f1239fd39b83a3228ab150bcc3f6..1df145f582234f7064454c05bb5b453ee5daab84 100644
--- a/src/engine/ignition/ignitionSite.C
+++ b/src/engine/ignition/ignitionSite.C
@@ -37,14 +37,17 @@ namespace Foam
 
 void ignitionSite::findIgnitionCells(const fvMesh& mesh)
 {
+    // Bit tricky: generate C and V before shortcutting if cannot find
+    // cell locally. mesh.C generation uses parallel communication.
+    const volVectorField& centres = mesh.C();
+    const scalarField& vols = mesh.V();
+
     label ignCell = mesh.findCell(location_);
     if (ignCell == -1)
     {
         return;
     }
 
-    const volVectorField& centres = mesh.C();
-    const scalarField& vols = mesh.V();
     scalar radius = diameter_/2.0;
 
     cells_.setSize(1);
diff --git a/src/finiteVolume/cfdTools/general/findRefCell/findRefCell.C b/src/finiteVolume/cfdTools/general/findRefCell/findRefCell.C
index 321eeba6a87be806089b4cafd53ea2195286ca56..ea2281266bbbf0288d27687a0a3e08fbe3236a2a 100644
--- a/src/finiteVolume/cfdTools/general/findRefCell/findRefCell.C
+++ b/src/finiteVolume/cfdTools/general/findRefCell/findRefCell.C
@@ -49,6 +49,22 @@ void Foam::setRefCell
             if (Pstream::master())
             {
                 refCelli = readLabel(dict.lookup(refCellName));
+
+                if (refCelli < 0 || refCelli >= field.mesh().nCells())
+                {
+                    FatalErrorIn
+                    (
+                        "void Foam::setRefCell"
+                         "("
+                         "    const volScalarField&,"
+                         "    const dictionary&,"
+                         "    label& scalar&,"
+                         "    bool"
+                         ")"
+                    )   << "Illegal master cellID " << refCelli
+                        << ". Should be 0.." << field.mesh().nCells()
+                        << exit(FatalError);
+                }
             }
             else
             {
@@ -75,7 +91,7 @@ void Foam::setRefCell
                 )
                   << "Unable to set reference cell for field " << field.name()
                   << nl << "    Reference point " << refPointName
-                  << " found on multiple domains" << nl << abort(FatalError);
+                  << " found on multiple domains" << nl << exit(FatalError);
             }
         }
         else
@@ -92,7 +108,7 @@ void Foam::setRefCell
             )
               << "Unable to set reference cell for field" << field.name() << nl
               << "    Please supply either " << refCellName
-              << " or " << refPointName << nl << abort(FatalError);
+              << " or " << refPointName << nl << exit(FatalError);
         }
 
         refValue = readScalar(dict.lookup(refValueName));
diff --git a/src/meshTools/searchableSurface/searchableSphere.C b/src/meshTools/searchableSurface/searchableSphere.C
index 04f3f2f2b52c0f410487a6b68a13518682be0a80..74ac1929a6cc7968883451b715745fc4bb9d1c1a 100644
--- a/src/meshTools/searchableSurface/searchableSphere.C
+++ b/src/meshTools/searchableSurface/searchableSphere.C
@@ -292,7 +292,8 @@ void Foam::searchableSphere::getNormal
         if (info[i].hit())
         {
             normal[i] = info[i].hitPoint() - centre_;
-            normal[i] /= mag(normal[i]);
+
+            normal[i] /= mag(normal[i])+VSMALL;
         }
         else
         {
diff --git a/src/sampling/sampledSurface/distanceSurface/distanceSurface.C b/src/sampling/sampledSurface/distanceSurface/distanceSurface.C
index 8c4acea9967b39942148f148308d5ae83c0af641..f337d14253dd69b8e361200083f92899ef8530f5 100644
--- a/src/sampling/sampledSurface/distanceSurface/distanceSurface.C
+++ b/src/sampling/sampledSurface/distanceSurface/distanceSurface.C
@@ -30,7 +30,8 @@ License
 #include "volPointInterpolation.H"
 #include "addToRunTimeSelectionTable.H"
 #include "fvMesh.H"
-#include "isoSurfaceCell.H"
+#include "isoSurface.H"
+//#include "isoSurfaceCell.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -42,19 +43,46 @@ namespace Foam
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-void Foam::distanceSurface::createGeometry() const
+void Foam::distanceSurface::createGeometry()
 {
     // Clear any stored topo
     facesPtr_.clear();
 
+
+    const fvMesh& fvm = static_cast<const fvMesh&>(mesh());
+
     // Distance to cell centres
-    scalarField cellDistance(mesh().nCells());
+    // ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    cellDistancePtr_.reset
+    (
+        new volScalarField
+        (
+            IOobject
+            (
+                "cellDistance",
+                fvm.time().timeName(),
+                fvm.time(),
+                IOobject::NO_READ,
+                IOobject::NO_WRITE,
+                false
+            ),
+            fvm,
+            dimensionedScalar("zero", dimless/dimTime, 0)
+        )
+    );
+    volScalarField& cellDistance = cellDistancePtr_();
+
+    // Internal field
     {
+        const pointField& cc = fvm.C();
+        scalarField& fld = cellDistance.internalField();
+
         List<pointIndexHit> nearest;
         surfPtr_().findNearest
         (
-            mesh().cellCentres(),
-            scalarField(mesh().nCells(), GREAT),
+            cc,
+            scalarField(cc.size(), GREAT),
             nearest
         );
 
@@ -63,98 +91,109 @@ void Foam::distanceSurface::createGeometry() const
             vectorField normal;
             surfPtr_().getNormal(nearest, normal);
 
-            forAll(cellDistance, cellI)
+            forAll(nearest, i)
             {
-                vector d(mesh().cellCentres()[cellI]-nearest[cellI].hitPoint());
+                vector d(cc[i]-nearest[i].hitPoint());
 
-                if ((d&normal[cellI]) > 0)
+                if ((d&normal[i]) > 0)
                 {
-                    cellDistance[cellI] = Foam::mag(d);
+                    fld[i] = Foam::mag(d);
                 }
                 else
                 {
-                    cellDistance[cellI] = -Foam::mag(d);
+                    fld[i] = -Foam::mag(d);
                 }
             }
         }
         else
         {
-            forAll(cellDistance, cellI)
+            forAll(nearest, i)
             {
-                cellDistance[cellI] = Foam::mag
-                (
-                    nearest[cellI].hitPoint()
-                  - mesh().cellCentres()[cellI]
-                );
+                fld[i] = Foam::mag(cc[i] - nearest[i].hitPoint());
             }
         }
     }
 
+    // Patch fields
+    {
+        forAll(fvm.C().boundaryField(), patchI)
+        {
+            const pointField& cc = fvm.C().boundaryField()[patchI];
+            fvPatchScalarField& fld = cellDistance.boundaryField()[patchI];
+
+            List<pointIndexHit> nearest;
+            surfPtr_().findNearest
+            (
+                cc,
+                scalarField(cc.size(), GREAT),
+                nearest
+            );
+
+            if (signed_)
+            {
+                vectorField normal;
+                surfPtr_().getNormal(nearest, normal);
+
+                forAll(nearest, i)
+                {
+                    vector d(cc[i]-nearest[i].hitPoint());
+
+                    if ((d&normal[i]) > 0)
+                    {
+                        fld[i] = Foam::mag(d);
+                    }
+                    else
+                    {
+                        fld[i] = -Foam::mag(d);
+                    }
+                }
+            }
+            else
+            {
+                forAll(nearest, i)
+                {
+                    fld[i] = Foam::mag(cc[i] - nearest[i].hitPoint());
+                }
+            }
+        }
+    }
+
+    // On processor patches the mesh.C() will already be the cell centre
+    // on the opposite side so no need to swap cellDistance.
+
+
     // Distance to points
-    scalarField pointDistance(mesh().nPoints());
+    pointDistance_.setSize(fvm.nPoints());
     {
         List<pointIndexHit> nearest;
         surfPtr_().findNearest
         (
-            mesh().points(),
-            scalarField(mesh().nPoints(), GREAT),
+            fvm.points(),
+            scalarField(fvm.nPoints(), GREAT),
             nearest
         );
-        forAll(pointDistance, pointI)
+        forAll(pointDistance_, pointI)
         {
-            pointDistance[pointI] = Foam::mag
+            pointDistance_[pointI] = Foam::mag
             (
                 nearest[pointI].hitPoint()
-              - mesh().points()[pointI]
+              - fvm.points()[pointI]
             );
         }
     }
 
     //- Direct from cell field and point field.
-    const isoSurfaceCell iso
+    isoSurfPtr_.reset
     (
-        mesh(),
-        cellDistance,
-        pointDistance,
-        distance_,
-        regularise_
+        new isoSurface
+        (
+            cellDistance,
+            pointDistance_,
+            distance_,
+            regularise_
+        )
     );
 
-    ////- From point field and interpolated cell.
-    //scalarField cellAvg(mesh().nCells(), scalar(0.0));
-    //labelField nPointCells(mesh().nCells(), 0);
-    //{
-    //    for (label pointI = 0; pointI < mesh().nPoints(); pointI++)
-    //    {
-    //        const labelList& pCells = mesh().pointCells(pointI);
-    //
-    //        forAll(pCells, i)
-    //        {
-    //            label cellI = pCells[i];
-    //
-    //            cellAvg[cellI] += pointDistance[pointI];
-    //            nPointCells[cellI]++;
-    //        }
-    //    }
-    //}
-    //forAll(cellAvg, cellI)
-    //{
-    //    cellAvg[cellI] /= nPointCells[cellI];
-    //}
-    //
-    //const isoSurface iso
-    //(
-    //    mesh(),
-    //    cellAvg,
-    //    pointDistance,
-    //    distance_,
-    //    regularise_
-    //);
-
-
-    const_cast<distanceSurface&>(*this).triSurface::operator=(iso);
-    meshCells_ = iso.meshCells();
-
     if (debug)
     {
         print(Pout);
@@ -193,9 +232,8 @@ Foam::distanceSurface::distanceSurface
     signed_(readBool(dict.lookup("signed"))),
     regularise_(dict.lookupOrDefault("regularise", true)),
     zoneName_(word::null),
-    facesPtr_(NULL),
-    storedTimeIndex_(-1),
-    meshCells_(0)
+    isoSurfPtr_(NULL),
+    facesPtr_(NULL)
 {
 //    label zoneId = -1;
 //    if (dict.readIfPresent("zone", zoneName_))
diff --git a/src/sampling/sampledSurface/distanceSurface/distanceSurface.H b/src/sampling/sampledSurface/distanceSurface/distanceSurface.H
index 82fba8a83f3ff696122ffb23102d4838cb6f6c4d..64aebb1a9a0a588c9201dac2261b2727dc554871 100644
--- a/src/sampling/sampledSurface/distanceSurface/distanceSurface.H
+++ b/src/sampling/sampledSurface/distanceSurface/distanceSurface.H
@@ -37,8 +37,9 @@ SourceFiles
 #define distanceSurface_H
 
 #include "sampledSurface.H"
-#include "triSurface.H"
 #include "searchableSurface.H"
+//#include "isoSurfaceCell.H"
+#include "isoSurface.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -51,8 +52,7 @@ namespace Foam
 
 class distanceSurface
 :
-    public sampledSurface,
-    public triSurface
+    public sampledSurface
 {
     // Private data
 
@@ -71,23 +71,24 @@ class distanceSurface
         //- zone name (if restricted to zones)
         word zoneName_;
 
-        //- triangles converted to faceList
-        mutable autoPtr<faceList> facesPtr_;
 
+        //- Distance to cell centres
+        autoPtr<volScalarField> cellDistancePtr_;
 
-        // Recreated for every isoSurface
+        //- Distance to points
+        scalarField pointDistance_;
 
-            //- Time at last call
-            mutable label storedTimeIndex_;
+        //- Constructed iso surface
+        autoPtr<isoSurface> isoSurfPtr_;
 
-            //- For every triangle the original cell in mesh
-            mutable labelList meshCells_;
+        //- triangles converted to faceList
+        mutable autoPtr<faceList> facesPtr_;
 
 
     // Private Member Functions
 
-        //- Create iso surface (if time has changed)
-        void createGeometry() const;
+        //- Create iso surface
+        void createGeometry();
 
         //- sample field on faces
         template <class Type>
@@ -129,7 +130,7 @@ public:
         //- Points of surface
         virtual const pointField& points() const
         {
-            return triSurface::points();
+            return surface().points();
         }
 
         //- Faces of surface
@@ -137,7 +138,7 @@ public:
         {
             if (!facesPtr_.valid())
             {
-                const triSurface& s = *this;
+                const triSurface& s = surface();
 
                 facesPtr_.reset(new faceList(s.size()));
 
@@ -153,6 +154,10 @@ public:
         //- Correct for mesh movement and/or field changes
         virtual void correct(const bool meshChanged);
 
+        const isoSurface& surface() const
+        {
+            return isoSurfPtr_();
+        }
 
         //- sample field on surface
         virtual tmp<scalarField> sample
diff --git a/src/sampling/sampledSurface/distanceSurface/distanceSurfaceTemplates.C b/src/sampling/sampledSurface/distanceSurface/distanceSurfaceTemplates.C
index ce983c7f5f08bffe29eda422a0f47dbff83d08cb..fd1447af78ceae51b06ee26529dfdc8deb1f2734 100644
--- a/src/sampling/sampledSurface/distanceSurface/distanceSurfaceTemplates.C
+++ b/src/sampling/sampledSurface/distanceSurface/distanceSurfaceTemplates.C
@@ -39,7 +39,7 @@ Foam::distanceSurface::sampleField
     const GeometricField<Type, fvPatchField, volMesh>& vField
 ) const
 {
-    return tmp<Field<Type> >(new Field<Type>(vField, meshCells_));
+    return tmp<Field<Type> >(new Field<Type>(vField, surface().meshCells()));
 }
 
 
@@ -50,33 +50,25 @@ Foam::distanceSurface::interpolateField
     const interpolation<Type>& interpolator
 ) const
 {
-    // One value per point
-    tmp<Field<Type> > tvalues(new Field<Type>(points().size()));
-    Field<Type>& values = tvalues();
-
-    boolList pointDone(points().size(), false);
-
-    forAll(faces(), cutFaceI)
-    {
-        const face& f = faces()[cutFaceI];
-
-        forAll(f, faceVertI)
-        {
-            label pointI = f[faceVertI];
-
-            if (!pointDone[pointI])
-            {
-                values[pointI] = interpolator.interpolate
-                (
-                    points()[pointI],
-                    meshCells_[cutFaceI]
-                );
-                pointDone[pointI] = true;
-            }
-        }
-    }
-
-    return tvalues;
+    const fvMesh& fvm = static_cast<const fvMesh&>(mesh());
+
+    // Get fields to sample. Assume volPointInterpolation!
+    const GeometricField<Type, fvPatchField, volMesh>& volFld =
+        interpolator.psi();
+
+    tmp<GeometricField<Type, pointPatchField, pointMesh> > pointFld
+    (
+        volPointInterpolation::New(fvm).interpolate(volFld)
+    );
+
+    // Sample.
+    return surface().interpolate
+    (
+        cellDistancePtr_(),
+        pointDistance_,
+        volFld,
+        pointFld()
+    );
 }
 
 
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurface.C b/src/sampling/sampledSurface/isoSurface/isoSurface.C
index 13c210d395bec3eafa6c287728dd9239954abba8..937aa68616ac733a850c6407ba2fa04fbf9dda8e 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurface.C
+++ b/src/sampling/sampledSurface/isoSurface/isoSurface.C
@@ -108,17 +108,15 @@ void Foam::isoSurface::calcCutTypes
         const polyPatch& pp = patches[patchI];
 
         label faceI = pp.start();
-        forAll(pp, i)
+
+        if (isA<emptyPolyPatch>(pp))
         {
-            bool ownLower = (cVals[own[faceI]] < iso_);
-            bool neiLower = (cVals.boundaryField()[patchI][i] < iso_);
+            // Assume zero gradient so owner and neighbour/boundary value equal
 
-            if (ownLower != neiLower)
-            {
-                faceCutType_[faceI] = CUT;
-            }
-            else
+            forAll(pp, i)
             {
+                bool ownLower = (cVals[own[faceI]] < iso_);
+
                 // Mesh edge.
                 const face f = mesh_.faces()[faceI];
 
@@ -129,15 +127,48 @@ void Foam::isoSurface::calcCutTypes
                     (
                         (fpLower != (pVals[f[f.fcIndex(fp)]] < iso_))
                      || (fpLower != ownLower)
-                     || (fpLower != neiLower)
                     )
                     {
                         faceCutType_[faceI] = CUT;
                         break;
                     }
                 }
+                faceI++;
+            }
+        }
+        else
+        {
+            forAll(pp, i)
+            {
+                bool ownLower = (cVals[own[faceI]] < iso_);
+                bool neiLower = (cVals.boundaryField()[patchI][i] < iso_);
+
+                if (ownLower != neiLower)
+                {
+                    faceCutType_[faceI] = CUT;
+                }
+                else
+                {
+                    // Mesh edge.
+                    const face f = mesh_.faces()[faceI];
+
+                    forAll(f, fp)
+                    {
+                        bool fpLower = (pVals[f[fp]] < iso_);
+                        if
+                        (
+                            (fpLower != (pVals[f[f.fcIndex(fp)]] < iso_))
+                         || (fpLower != ownLower)
+                         || (fpLower != neiLower)
+                        )
+                        {
+                            faceCutType_[faceI] = CUT;
+                            break;
+                        }
+                    }
+                }
+                faceI++;
             }
-            faceI++;
         }
     }
 
@@ -328,8 +359,17 @@ void Foam::isoSurface::getNeighbour
         label patchI = boundaryRegion[bFaceI];
         label patchFaceI = faceI-mesh_.boundaryMesh()[patchI].start();
 
-        nbrValue = cVals.boundaryField()[patchI][patchFaceI];
-        nbrPoint = mesh_.C().boundaryField()[patchI][patchFaceI];
+        if (isA<emptyPolyPatch>(mesh_.boundaryMesh()[patchI]))
+        {
+            // Assume zero gradient
+            nbrValue = cVals[own[faceI]];
+            nbrPoint = mesh_.C().boundaryField()[patchI][patchFaceI];
+        }
+        else
+        {
+            nbrValue = cVals.boundaryField()[patchI][patchFaceI];
+            nbrPoint = mesh_.C().boundaryField()[patchI][patchFaceI];
+        }
     }
 }
 
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.C b/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.C
index 2812645aa3ff22db89ce62d68e40910e04cae3b6..5cffcdf0ddf4b8f21c8f2f2f01363ad97ec43df9 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.C
+++ b/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.C
@@ -201,6 +201,34 @@ Foam::isoSurfaceCell::cellCutType Foam::isoSurfaceCell::calcCutType
 }
 
 
+void Foam::isoSurfaceCell::calcCutTypes
+(
+    const PackedList<1>& isTet,
+    const scalarField& cVals,
+    const scalarField& pVals
+)
+{
+    cellCutType_.setSize(mesh_.nCells());
+    nCutCells_ = 0;
+    forAll(mesh_.cells(), cellI)
+    {
+        cellCutType_[cellI] = calcCutType(isTet, cVals, pVals, cellI);
+
+        if (cellCutType_[cellI] == CUT)
+        {
+            nCutCells_++;
+        }
+    }
+
+    if (debug)
+    {
+        Pout<< "isoSurfaceCell : detected " << nCutCells_
+            << " candidate cut cells." << endl;
+    }
+}
+
+
+
 // Return the two common points between two triangles
 Foam::labelPair Foam::isoSurfaceCell::findCommonPoints
 (
@@ -325,7 +353,6 @@ void Foam::isoSurfaceCell::calcSnappedCc
     const PackedList<1>& isTet,
     const scalarField& cVals,
     const scalarField& pVals,
-    const List<cellCutType>& cellCutType,
 
     DynamicList<point>& snappedPoints,
     labelList& snappedCc
@@ -344,7 +371,7 @@ void Foam::isoSurfaceCell::calcSnappedCc
 
     forAll(mesh_.cells(), cellI)
     {
-        if (cellCutType[cellI] == CUT && isTet.get(cellI) == 0)
+        if (cellCutType_[cellI] == CUT && isTet.get(cellI) == 0)
         {
             scalar cVal = cVals[cellI];
 
@@ -604,7 +631,6 @@ void Foam::isoSurfaceCell::calcSnappedPoint
     const PackedList<1>& isTet,
     const scalarField& cVals,
     const scalarField& pVals,
-    const List<cellCutType>& cellCutType,
 
     DynamicList<point>& snappedPoints,
     labelList& snappedPoint
@@ -635,10 +661,10 @@ void Foam::isoSurfaceCell::calcSnappedPoint
 
             if
             (
-                cellCutType[mesh_.faceOwner()[faceI]] == CUT
+                cellCutType_[mesh_.faceOwner()[faceI]] == CUT
              || (
                     mesh_.isInternalFace(faceI)
-                 && cellCutType[mesh_.faceNeighbour()[faceI]] == CUT
+                 && cellCutType_[mesh_.faceNeighbour()[faceI]] == CUT
                 )
             )
             {
@@ -766,171 +792,6 @@ void Foam::isoSurfaceCell::calcSnappedPoint
 }
 
 
-Foam::point Foam::isoSurfaceCell::generatePoint
-(
-    const DynamicList<point>& snappedPoints,
-
-    const scalar s0,
-    const point& p0,
-    const label p0Index,
-
-    const scalar s1,
-    const point& p1,
-    const label p1Index
-) const
-{
-    scalar d = s1-s0;
-
-    if (mag(d) > VSMALL)
-    {
-        scalar s = (iso_-s0)/d;
-
-        if (s >= 0.5 && s <= 1 && p1Index != -1)
-        {
-            return snappedPoints[p1Index];
-        }
-        else if (s >= 0.0 && s <= 0.5 && p0Index != -1)
-        {
-            return snappedPoints[p0Index];
-        }
-        else
-        {
-            return s*p1 + (1.0-s)*p0;
-        }
-    }
-    else
-    {
-        scalar s = 0.4999;
-
-        return s*p1 + (1.0-s)*p0;
-    }
-}
-
-
-void Foam::isoSurfaceCell::generateTriPoints
-(
-    const DynamicList<point>& snapped,
-
-    const scalar s0,
-    const point& p0,
-    const label p0Index,
-
-    const scalar s1,
-    const point& p1,
-    const label p1Index,
-
-    const scalar s2,
-    const point& p2,
-    const label p2Index,
-
-    const scalar s3,
-    const point& p3,
-    const label p3Index,
-
-    DynamicList<point>& points
-) const
-{
-    int triIndex = 0;
-    if (s0 < iso_)
-    {
-        triIndex |= 1;
-    }
-    if (s1 < iso_)
-    {
-        triIndex |= 2;
-    }
-    if (s2 < iso_)
-    {
-        triIndex |= 4;
-    }
-    if (s3 < iso_)
-    {
-        triIndex |= 8;
-    }
-
-    /* Form the vertices of the triangles for each case */
-    switch (triIndex)
-    {
-        case 0x00:
-        case 0x0F:
-        break;
-
-        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));
-        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));
-        break;
-
-        case 0x0C:
-        case 0x03:
-        {
-            point tp1 = generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index);
-            point tp2 = generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index);
-
-            points.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
-            points.append(tp1);
-            points.append(tp2);
-            points.append(tp2);
-            points.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
-            points.append(tp1);
-        }
-        break;
-
-        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));
-        }
-        break;
-
-        case 0x0A:
-        case 0x05:
-        {
-            point tp0 = generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index);
-            point tp1 = generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index);
-
-            points.append(tp0);
-            points.append(tp1);
-            points.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
-            points.append(tp0);
-            points.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
-            points.append(tp1);
-        }
-        break;
-
-        case 0x09:
-        case 0x06:
-        {
-            point tp0 = generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index);
-            point tp1 = generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index);
-
-            points.append(tp0);
-            points.append(generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index));
-            points.append(tp1);
-            points.append(tp0);
-            points.append(generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index));
-            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));
-        break;
-    }
-}
 
 
 Foam::triSurface Foam::isoSurfaceCell::stitchTriPoints
@@ -1589,26 +1450,9 @@ Foam::isoSurfaceCell::isoSurfaceCell
 
 
     // Determine if any cut through cell
+    calcCutTypes(isTet, cVals, pVals);
 
-    List<cellCutType> cellCutType(mesh_.nCells());
-    label nCutCells = 0;
-    forAll(mesh_.cells(), cellI)
-    {
-        cellCutType[cellI] = calcCutType(isTet, cVals, pVals, cellI);
-
-        if (cellCutType[cellI] == CUT)
-        {
-            nCutCells++;
-        }
-    }
-
-    if (debug)
-    {
-        Pout<< "isoSurfaceCell : detected " << nCutCells
-            << " candidate cut cells." << endl;
-    }
-
-    DynamicList<point> snappedPoints(nCutCells);
+    DynamicList<point> snappedPoints(nCutCells_);
 
     // Per cc -1 or a point inside snappedPoints.
     labelList snappedCc;
@@ -1619,7 +1463,6 @@ Foam::isoSurfaceCell::isoSurfaceCell
             isTet,
             cVals,
             pVals,
-            cellCutType,
             snappedPoints,
             snappedCc
         );
@@ -1630,6 +1473,8 @@ Foam::isoSurfaceCell::isoSurfaceCell
         snappedCc = -1;
     }
 
+    snappedPoints.shrink();
+
     if (debug)
     {
         Pout<< "isoSurfaceCell : shifted " << snappedPoints.size()
@@ -1648,7 +1493,6 @@ Foam::isoSurfaceCell::isoSurfaceCell
             isTet,
             cVals,
             pVals,
-            cellCutType,
             snappedPoints,
             snappedPoint
         );
@@ -1667,115 +1511,24 @@ Foam::isoSurfaceCell::isoSurfaceCell
 
 
 
-    DynamicList<point> triPoints(nCutCells);
-    DynamicList<label> triMeshCells(nCutCells);
-
-    forAll(mesh_.cells(), cellI)
-    {
-        if (cellCutType[cellI] != NOTCUT)
-        {
-            label oldNPoints = triPoints.size();
-
-            const cell& cFaces = mesh_.cells()[cellI];
-
-            if (isTet.get(cellI) == 1)
-            {
-                // For tets don't do cell-centre decomposition, just use the
-                // tet points and values
-
-                const face& f0 = mesh_.faces()[cFaces[0]];
-
-                // Get the other point
-                const face& f1 = mesh_.faces()[cFaces[1]];
-                label oppositeI = -1;
-                forAll(f1, fp)
-                {
-                    oppositeI = f1[fp];
-
-                    if (findIndex(f0, oppositeI) == -1)
-                    {
-                        break;
-                    }
-                }
-
-                generateTriPoints
-                (
-                    snappedPoints,
-                    pVals[f0[0]],
-                    mesh_.points()[f0[0]],
-                    snappedPoint[f0[0]],
+    DynamicList<point> triPoints(nCutCells_);
+    DynamicList<label> triMeshCells(nCutCells_);
 
-                    pVals[f0[1]],
-                    mesh_.points()[f0[1]],
-                    snappedPoint[f0[1]],
-
-                    pVals[f0[2]],
-                    mesh_.points()[f0[2]],
-                    snappedPoint[f0[2]],
-
-                    pVals[oppositeI],
-                    mesh_.points()[oppositeI],
-                    snappedPoint[oppositeI],
-
-                    triPoints
-                );
-            }
-            else
-            {
-                const cell& cFaces = mesh_.cells()[cellI];
-
-                forAll(cFaces, cFaceI)
-                {
-                    label faceI = cFaces[cFaceI];
-                    const face& f = mesh_.faces()[faceI];
-
-                    for (label fp = 1; fp < f.size() - 1; fp++)
-                    {
-                        triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
-                    //List<triFace> tris(triangulate(f));
-                    //forAll(tris, i)
-                    //{
-                    //    const triFace& tri = tris[i];
-
-
-                        generateTriPoints
-                        (
-                            snappedPoints,
-
-                            pVals[tri[0]],
-                            mesh_.points()[tri[0]],
-                            snappedPoint[tri[0]],
-
-                            pVals[tri[1]],
-                            mesh_.points()[tri[1]],
-                            snappedPoint[tri[1]],
-
-                            pVals[tri[2]],
-                            mesh_.points()[tri[2]],
-                            snappedPoint[tri[2]],
-
-                            cVals[cellI],
-                            mesh_.cellCentres()[cellI],
-                            snappedCc[cellI],
-
-                            triPoints
-                        );
-                    }
-                }
-            }
+    generateTriPoints
+    (
+        cVals,
+        pVals,
 
+        mesh_.cellCentres(),
+        mesh_.points(),
 
-            // Every three triPoints is a cell
-            label nCells = (triPoints.size()-oldNPoints)/3;
-            for (label i = 0; i < nCells; i++)
-            {
-                triMeshCells.append(cellI);
-            }
-        }
-    }
+        snappedPoints,
+        snappedCc,
+        snappedPoint,
 
-    triPoints.shrink();
-    triMeshCells.shrink();
+        triPoints,
+        triMeshCells
+    );
 
     if (debug)
     {
@@ -1878,123 +1631,123 @@ Foam::isoSurfaceCell::isoSurfaceCell
 }
 
 
-//XXXXXXX
-// Experimental retriangulation of triangles per cell. Problem is that
-// -it is very expensive   -only gets rid of internal points, not of boundary
-// ones so limited benefit (e.g. 60 v.s. 88 triangles)
-void Foam::isoSurfaceCell::combineCellTriangles()
-{
-    if (size() > 0)
-    {
-        DynamicList<labelledTri> newTris(size());
-        DynamicList<label> newTriToCell(size());
-
-        label startTriI = 0;
-
-        DynamicList<labelledTri> tris;
-
-        for (label triI = 1; triI <= meshCells_.size(); triI++)
-        {
-            if
-            (
-                triI == meshCells_.size()
-             || meshCells_[triI] != meshCells_[startTriI]
-            )
-            {
-                label nTris = triI-startTriI;
-
-                if (nTris == 1)
-                {
-                    newTris.append(operator[](startTriI));
-                    newTriToCell.append(meshCells_[startTriI]);
-                }
-                else
-                {
-                    // Collect from startTriI to triI in a triSurface
-                    tris.clear();
-                    for (label i = startTriI; i < triI; i++)
-                    {
-                        tris.append(operator[](i));
-                    }
-                    triSurface cellTris(tris, patches(), points());
-                    tris.clear();
-
-                    // Get outside
-                    const labelListList& loops = cellTris.edgeLoops();
-
-                    forAll(loops, i)
-                    {
-                        // Do proper triangulation of loop
-                        face loop(renumber(cellTris.meshPoints(), loops[i]));
-
-                        faceTriangulation faceTris
-                        (
-                            points(),
-                            loop,
-                            true
-                        );
-
-                        // Copy into newTris
-                        forAll(faceTris, faceTriI)
-                        {
-                            const triFace& tri = faceTris[faceTriI];
-
-                            newTris.append
-                            (
-                                labelledTri
-                                (
-                                    tri[0],
-                                    tri[1],
-                                    tri[2],
-                                    operator[](startTriI).region()
-                                )
-                            );
-                            newTriToCell.append(meshCells_[startTriI]);
-                        }
-                    }
-                }
-
-                startTriI = triI;
-            }
-        }
-        newTris.shrink();
-        newTriToCell.shrink();
-
-        // Compact
-        pointField newPoints(points().size());
-        label newPointI = 0;
-        labelList oldToNewPoint(points().size(), -1);
-
-        forAll(newTris, i)
-        {
-            labelledTri& tri = newTris[i];
-            forAll(tri, j)
-            {
-                label pointI = tri[j];
-
-                if (oldToNewPoint[pointI] == -1)
-                {
-                    oldToNewPoint[pointI] = newPointI;
-                    newPoints[newPointI++] = points()[pointI];
-                }
-                tri[j] = oldToNewPoint[pointI];
-            }
-        }
-        newPoints.setSize(newPointI);
-
-        triSurface::operator=
-        (
-            triSurface
-            (
-                newTris,
-                patches(),
-                newPoints,
-                true
-            )
-        );
-        meshCells_.transfer(newTriToCell);
-    }
-}
-//XXXXXXX
+////XXXXXXX
+//// Experimental retriangulation of triangles per cell. Problem is that
+//// -it is very expensive   -only gets rid of internal points, not of boundary
+//// ones so limited benefit (e.g. 60 v.s. 88 triangles)
+//void Foam::isoSurfaceCell::combineCellTriangles()
+//{
+//    if (size() > 0)
+//    {
+//        DynamicList<labelledTri> newTris(size());
+//        DynamicList<label> newTriToCell(size());
+//
+//        label startTriI = 0;
+//
+//        DynamicList<labelledTri> tris;
+//
+//        for (label triI = 1; triI <= meshCells_.size(); triI++)
+//        {
+//            if
+//            (
+//                triI == meshCells_.size()
+//             || meshCells_[triI] != meshCells_[startTriI]
+//            )
+//            {
+//                label nTris = triI-startTriI;
+//
+//                if (nTris == 1)
+//                {
+//                    newTris.append(operator[](startTriI));
+//                    newTriToCell.append(meshCells_[startTriI]);
+//                }
+//                else
+//                {
+//                    // Collect from startTriI to triI in a triSurface
+//                    tris.clear();
+//                    for (label i = startTriI; i < triI; i++)
+//                    {
+//                        tris.append(operator[](i));
+//                    }
+//                    triSurface cellTris(tris, patches(), points());
+//                    tris.clear();
+//
+//                    // Get outside
+//                    const labelListList& loops = cellTris.edgeLoops();
+//
+//                    forAll(loops, i)
+//                    {
+//                        // Do proper triangulation of loop
+//                        face loop(renumber(cellTris.meshPoints(), loops[i]));
+//
+//                        faceTriangulation faceTris
+//                        (
+//                            points(),
+//                            loop,
+//                            true
+//                        );
+//
+//                        // Copy into newTris
+//                        forAll(faceTris, faceTriI)
+//                        {
+//                            const triFace& tri = faceTris[faceTriI];
+//
+//                            newTris.append
+//                            (
+//                                labelledTri
+//                                (
+//                                    tri[0],
+//                                    tri[1],
+//                                    tri[2],
+//                                    operator[](startTriI).region()
+//                                )
+//                            );
+//                            newTriToCell.append(meshCells_[startTriI]);
+//                        }
+//                    }
+//                }
+//
+//                startTriI = triI;
+//            }
+//        }
+//        newTris.shrink();
+//        newTriToCell.shrink();
+//
+//        // Compact
+//        pointField newPoints(points().size());
+//        label newPointI = 0;
+//        labelList oldToNewPoint(points().size(), -1);
+//
+//        forAll(newTris, i)
+//        {
+//            labelledTri& tri = newTris[i];
+//            forAll(tri, j)
+//            {
+//                label pointI = tri[j];
+//
+//                if (oldToNewPoint[pointI] == -1)
+//                {
+//                    oldToNewPoint[pointI] = newPointI;
+//                    newPoints[newPointI++] = points()[pointI];
+//                }
+//                tri[j] = oldToNewPoint[pointI];
+//            }
+//        }
+//        newPoints.setSize(newPointI);
+//
+//        triSurface::operator=
+//        (
+//            triSurface
+//            (
+//                newTris,
+//                patches(),
+//                newPoints,
+//                true
+//            )
+//        );
+//        meshCells_.transfer(newTriToCell);
+//    }
+//}
+////XXXXXXX
 
 // ************************************************************************* //
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.H b/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.H
index 86b2dbef468501f8d75514898320c39eed3a7c14..40e2b6d79378ab15f5552616785c7528717a3d5e 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.H
+++ b/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.H
@@ -91,6 +91,11 @@ class isoSurfaceCell
         //- When to merge points
         const scalar mergeDistance_;
 
+        //- Whether cell might be cut
+        List<cellCutType> cellCutType_;
+
+        //- Estimated number of cut cells
+        label nCutCells_;
 
         //- For every triangle the original cell in mesh
         labelList meshCells_;
@@ -119,6 +124,13 @@ class isoSurfaceCell
             const label
         ) const;
 
+        void calcCutTypes
+        (
+            const PackedList<1>&,
+            const scalarField& cellValues,
+            const scalarField& pointValues
+        );
+
         static labelPair findCommonPoints
         (
             const labelledTri&,
@@ -140,7 +152,6 @@ class isoSurfaceCell
             const PackedList<1>& isTet,
             const scalarField& cVals,
             const scalarField& pVals,
-            const List<cellCutType>& cellCutType,
             DynamicList<point>& triPoints,
             labelList& snappedCc
         ) const;
@@ -173,39 +184,57 @@ class isoSurfaceCell
             const PackedList<1>& isTet,
             const scalarField& cVals,
             const scalarField& pVals,
-            const List<cellCutType>& cellCutType,
             DynamicList<point>& triPoints,
             labelList& snappedPoint
         ) const;
 
         //- Generate single point by interpolation or snapping
-        point generatePoint
+        template<class Type>
+        Type generatePoint
         (
-            const DynamicList<point>& snappedPoints,
+            const DynamicList<Type>& snappedPoints,
             const scalar s0,
-            const point& p0,
+            const Type& p0,
             const label p0Index,
             const scalar s1,
-            const point& p1,
+            const Type& p1,
             const label p1Index
         ) const;
 
+        template<class Type>
         void generateTriPoints
         (
-            const DynamicList<point>& snapped,
+            const DynamicList<Type>& snapped,
             const scalar s0,
-            const point& p0,
+            const Type& p0,
             const label p0Index,
             const scalar s1,
-            const point& p1,
+            const Type& p1,
             const label p1Index,
             const scalar s2,
-            const point& p2,
+            const Type& p2,
             const label p2Index,
             const scalar s3,
-            const point& p3,
+            const Type& p3,
             const label p3Index,
-            DynamicList<point>& points
+            DynamicList<Type>& points
+        ) const;
+
+        template<class Type>
+        void generateTriPoints
+        (
+            const scalarField& cVals,
+            const scalarField& pVals,
+
+            const Field<Type>& cCoords,
+            const Field<Type>& pCoords,
+
+            const DynamicList<Type>& snappedPoints,
+            const labelList& snappedCc,
+            const labelList& snappedPoint,
+
+            DynamicList<Type>& triPoints,
+            DynamicList<label>& triMeshCells
         ) const;
 
         triSurface stitchTriPoints
@@ -311,6 +340,18 @@ public:
         {
             return triPointMergeMap_;
         }
+
+
+        //- Interpolates cCoords,pCoords. Takes the original fields
+        //  used to create the iso surface.
+        template <class Type>
+        tmp<Field<Type> > interpolate
+        (
+            const scalarField& cVals,
+            const scalarField& pVals,
+            const Field<Type>& cCoords,
+            const Field<Type>& pCoords
+        ) const;
 };
 
 
@@ -320,6 +361,12 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+#ifdef NoRepository
+#   include "isoSurfaceCellTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 #endif
 
 // ************************************************************************* //
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurfaceCellTemplates.C b/src/sampling/sampledSurface/isoSurface/isoSurfaceCellTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..748e1a3311dbc19e8e26ba0dea9d1b38ddd07faf
--- /dev/null
+++ b/src/sampling/sampledSurface/isoSurface/isoSurfaceCellTemplates.C
@@ -0,0 +1,384 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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 "isoSurfaceCell.H"
+#include "polyMesh.H"
+#include "tetMatcher.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+template<class Type>
+Type Foam::isoSurfaceCell::generatePoint
+(
+    const DynamicList<Type>& snappedPoints,
+
+    const scalar s0,
+    const Type& p0,
+    const label p0Index,
+
+    const scalar s1,
+    const Type& p1,
+    const label p1Index
+) const
+{
+    scalar d = s1-s0;
+
+    if (mag(d) > VSMALL)
+    {
+        scalar s = (iso_-s0)/d;
+
+        if (s >= 0.5 && s <= 1 && p1Index != -1)
+        {
+            return snappedPoints[p1Index];
+        }
+        else if (s >= 0.0 && s <= 0.5 && p0Index != -1)
+        {
+            return snappedPoints[p0Index];
+        }
+        else
+        {
+            return s*p1 + (1.0-s)*p0;
+        }
+    }
+    else
+    {
+        scalar s = 0.4999;
+
+        return s*p1 + (1.0-s)*p0;
+    }
+}
+
+
+template<class Type>
+void Foam::isoSurfaceCell::generateTriPoints
+(
+    const DynamicList<Type>& snapped,
+
+    const scalar s0,
+    const Type& p0,
+    const label p0Index,
+
+    const scalar s1,
+    const Type& p1,
+    const label p1Index,
+
+    const scalar s2,
+    const Type& p2,
+    const label p2Index,
+
+    const scalar s3,
+    const Type& p3,
+    const label p3Index,
+
+    DynamicList<Type>& points
+) const
+{
+    int triIndex = 0;
+    if (s0 < iso_)
+    {
+        triIndex |= 1;
+    }
+    if (s1 < iso_)
+    {
+        triIndex |= 2;
+    }
+    if (s2 < iso_)
+    {
+        triIndex |= 4;
+    }
+    if (s3 < iso_)
+    {
+        triIndex |= 8;
+    }
+
+    /* Form the vertices of the triangles for each case */
+    switch (triIndex)
+    {
+        case 0x00:
+        case 0x0F:
+        break;
+
+        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));
+        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));
+        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);
+
+            points.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
+            points.append(tp1);
+            points.append(tp2);
+            points.append(tp2);
+            points.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
+            points.append(tp1);
+        }
+        break;
+
+        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));
+        }
+        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);
+
+            points.append(tp0);
+            points.append(tp1);
+            points.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
+            points.append(tp0);
+            points.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
+            points.append(tp1);
+        }
+        break;
+
+        case 0x09:
+        case 0x06:
+        {
+            Type tp0 = generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index);
+            Type tp1 = generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index);
+
+            points.append(tp0);
+            points.append(generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index));
+            points.append(tp1);
+            points.append(tp0);
+            points.append(generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index));
+            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));
+        break;
+    }
+}
+
+
+template<class Type>
+void Foam::isoSurfaceCell::generateTriPoints
+(
+    const scalarField& cVals,
+    const scalarField& pVals,
+
+    const Field<Type>& cCoords,
+    const Field<Type>& pCoords,
+
+    const DynamicList<Type>& snappedPoints,
+    const labelList& snappedCc,
+    const labelList& snappedPoint,
+
+    DynamicList<Type>& triPoints,
+    DynamicList<label>& triMeshCells
+) const
+{
+    tetMatcher tet;
+
+    forAll(mesh_.cells(), cellI)
+    {
+        if (cellCutType_[cellI] != NOTCUT)
+        {
+            label oldNPoints = triPoints.size();
+
+            const cell& cFaces = mesh_.cells()[cellI];
+
+            if (tet.isA(mesh_, cellI))
+            {
+                // For tets don't do cell-centre decomposition, just use the
+                // tet points and values
+
+                const face& f0 = mesh_.faces()[cFaces[0]];
+
+                // Get the other point
+                const face& f1 = mesh_.faces()[cFaces[1]];
+                label oppositeI = -1;
+                forAll(f1, fp)
+                {
+                    oppositeI = f1[fp];
+
+                    if (findIndex(f0, oppositeI) == -1)
+                    {
+                        break;
+                    }
+                }
+
+                generateTriPoints
+                (
+                    snappedPoints,
+                    pVals[f0[0]],
+                    pCoords[f0[0]],
+                    snappedPoint[f0[0]],
+
+                    pVals[f0[1]],
+                    pCoords[f0[1]],
+                    snappedPoint[f0[1]],
+
+                    pVals[f0[2]],
+                    pCoords[f0[2]],
+                    snappedPoint[f0[2]],
+
+                    pVals[oppositeI],
+                    pCoords[oppositeI],
+                    snappedPoint[oppositeI],
+
+                    triPoints
+                );
+            }
+            else
+            {
+                const cell& cFaces = mesh_.cells()[cellI];
+
+                forAll(cFaces, cFaceI)
+                {
+                    label faceI = cFaces[cFaceI];
+                    const face& f = mesh_.faces()[faceI];
+
+                    for (label fp = 1; fp < f.size() - 1; fp++)
+                    {
+                        triFace tri(f[0], f[fp], f[f.fcIndex(fp)]);
+                    //List<triFace> tris(triangulate(f));
+                    //forAll(tris, i)
+                    //{
+                    //    const triFace& tri = tris[i];
+
+
+                        generateTriPoints
+                        (
+                            snappedPoints,
+
+                            pVals[tri[0]],
+                            pCoords[tri[0]],
+                            snappedPoint[tri[0]],
+
+                            pVals[tri[1]],
+                            pCoords[tri[1]],
+                            snappedPoint[tri[1]],
+
+                            pVals[tri[2]],
+                            pCoords[tri[2]],
+                            snappedPoint[tri[2]],
+
+                            cVals[cellI],
+                            cCoords[cellI],
+                            snappedCc[cellI],
+
+                            triPoints
+                        );
+                    }
+                }
+            }
+
+
+            // Every three triPoints is a cell
+            label nCells = (triPoints.size()-oldNPoints)/3;
+            for (label i = 0; i < nCells; i++)
+            {
+                triMeshCells.append(cellI);
+            }
+        }
+    }
+
+    triPoints.shrink();
+    triMeshCells.shrink();
+}
+
+
+template <class Type>
+Foam::tmp<Foam::Field<Type> >
+Foam::isoSurfaceCell::interpolate
+(
+    const scalarField& cVals,
+    const scalarField& pVals,
+    const Field<Type>& cCoords,
+    const Field<Type>& pCoords
+) const
+{
+    DynamicList<Type> triPoints(nCutCells_);
+    DynamicList<label> triMeshCells(nCutCells_);
+
+    // Dummy snap data
+    DynamicList<Type> snappedPoints;
+    labelList snappedCc(mesh_.nCells(), -1);
+    labelList snappedPoint(mesh_.nPoints(), -1);
+
+
+    generateTriPoints
+    (
+        cVals,
+        pVals,
+
+        cCoords,
+        pCoords,
+
+        snappedPoints,
+        snappedCc,
+        snappedPoint,
+
+        triPoints,
+        triMeshCells
+    );
+
+
+    // One value per point
+    tmp<Field<Type> > tvalues(new Field<Type>(points().size()));
+    Field<Type>& values = tvalues();
+
+    forAll(triPoints, i)
+    {
+        label mergedPointI = triPointMergeMap_[i];
+
+        if (mergedPointI >= 0)
+        {
+            values[mergedPointI] = triPoints[i];
+        }
+    }
+
+    return tvalues;
+}
+
+
+// ************************************************************************* //
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurfaceTemplates.C b/src/sampling/sampledSurface/isoSurface/isoSurfaceTemplates.C
index b4d440c4fde3059145f3b69a7173a330b0ee6b3f..28d994f67811dfabd4068fb314245df1470a28ff 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurfaceTemplates.C
+++ b/src/sampling/sampledSurface/isoSurface/isoSurfaceTemplates.C
@@ -382,6 +382,39 @@ void Foam::isoSurface::generateTriPoints
                 }
             }
         }
+        else if (isA<emptyPolyPatch>(pp))
+        {
+            // Assume zero-gradient.
+            label faceI = pp.start();
+
+            forAll(pp, i)
+            {
+                if (faceCutType_[faceI] != NOTCUT)
+                {
+                    generateTriPoints
+                    (
+                        cVals,
+                        pVals,
+
+                        cCoords,
+                        pCoords,
+
+                        snappedPoints,
+                        snappedCc,
+                        snappedPoint,
+                        faceI,
+
+                        cVals[own[faceI]],
+                        cCoords.boundaryField()[patchI][i],
+                        -1, // fc not snapped
+
+                        triPoints,
+                        triMeshCells
+                    );
+                }
+                faceI++;
+            }
+        }
         else
         {
             label faceI = pp.start();
@@ -465,8 +498,12 @@ Foam::isoSurface::interpolate
 
 
     // One value per point
-    tmp<Field<Type> > tvalues(new Field<Type>(points().size()));
+    tmp<Field<Type> > tvalues
+    (
+        new Field<Type>(points().size(), pTraits<Type>::zero)
+    );
     Field<Type>& values = tvalues();
+    labelList nValues(values.size(), 0);
 
     forAll(triPoints, i)
     {
@@ -474,8 +511,34 @@ Foam::isoSurface::interpolate
 
         if (mergedPointI >= 0)
         {
-            values[mergedPointI] = triPoints[i];
+            values[mergedPointI] += triPoints[i];
+            nValues[mergedPointI]++;
+        }
+    }
+
+    if (debug)
+    {
+        Pout<< "nValues:" << values.size() << endl;
+        label nMult = 0;
+        forAll(nValues, i)
+        {
+            if (nValues[i] == 0)
+            {
+                FatalErrorIn("isoSurface::interpolate(..)")
+                    << "point:" << i << " nValues:" << nValues[i]
+                    << abort(FatalError);
+            }
+            else if (nValues[i] > 1)
+            {
+                nMult++;
+            }
         }
+        Pout<< "Of which mult:" << nMult << endl;
+    }
+
+    forAll(values, i)
+    {
+        values[i] /= scalar(nValues[i]);
     }
 
     return tvalues;
diff --git a/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.C b/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.C
index 782615107ba2498a486f8202a4a09a83c3cd4eb2..a1fcfd401391a13e75ec15e85918f5a56b4b651a 100644
--- a/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.C
+++ b/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.C
@@ -65,7 +65,7 @@ void Foam::sampledIsoSurface::getIsoFields() const
         if (debug)
         {
             Info<< "sampledIsoSurface::getIsoField() : reading "
-                << isoField_ << " from time " <<fvm.time().timeName()
+                << isoField_ << " from time " << fvm.time().timeName()
                 << endl;
         }
 
@@ -124,10 +124,10 @@ void Foam::sampledIsoSurface::getIsoFields() const
 
     if (debug)
     {
-        Info<< "sampledIsoSurface::getIsoField() : obtained volField "
+        Info<< "sampledIsoSurface::getIsoField() : volField "
             << volFieldPtr_->name() << " min:" << min(*volFieldPtr_).value()
             << " max:" << max(*volFieldPtr_).value() << endl;
-        Info<< "sampledIsoSurface::getIsoField() : obtained pointField "
+        Info<< "sampledIsoSurface::getIsoField() : pointField "
             << pointFieldPtr_->name()
             << " min:" << gMin(pointFieldPtr_->internalField())
             << " max:" << gMax(pointFieldPtr_->internalField()) << endl;
diff --git a/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceTemplates.C b/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceTemplates.C
index 4d4f75c739c2ab441d2ee3c124a69435e1fea991..a36811b75e03336cba8c94b4d5cb2de4ac896ba9 100644
--- a/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceTemplates.C
+++ b/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceTemplates.C
@@ -57,11 +57,16 @@ Foam::sampledIsoSurface::interpolateField
     const GeometricField<Type, fvPatchField, volMesh>& volFld =
         interpolator.psi();
 
-    tmp<GeometricField<Type, pointPatchField, pointMesh> > pointFld
+    tmp<GeometricField<Type, pointPatchField, pointMesh> > tpointFld
     (
         volPointInterpolation::New(fvm).interpolate(volFld)
     );
 
+    const GeometricField<Type, pointPatchField, pointMesh>& pointFld =
+        tpointFld();
+
+    // Get pointers to sampling field (both original and interpolated one)
+    getIsoFields();
     // Recreate geometry if time has changed
     createGeometry();
 
@@ -71,7 +76,7 @@ Foam::sampledIsoSurface::interpolateField
         *volFieldPtr_,
         *pointFieldPtr_,
         volFld,
-        pointFld()
+        pointFld
     );
 }
 
diff --git a/src/turbulenceModels/LES/LESfilters/laplaceFilter/laplaceFilter.C b/src/turbulenceModels/LES/LESfilters/laplaceFilter/laplaceFilter.C
index efcb639170eebf7593900278587fe935c721de6c..d7fcc910aef5fc6e636bed6eb05b9c455ae23ba7 100644
--- a/src/turbulenceModels/LES/LESfilters/laplaceFilter/laplaceFilter.C
+++ b/src/turbulenceModels/LES/LESfilters/laplaceFilter/laplaceFilter.C
@@ -49,7 +49,7 @@ Foam::laplaceFilter::laplaceFilter(const fvMesh& mesh, scalar widthCoeff)
     (
         IOobject
         (
-            "anisotropicFilterCoeff",
+            "laplaceFilterCoeff",
             mesh.time().timeName(),
             mesh
         ),
@@ -70,7 +70,7 @@ Foam::laplaceFilter::laplaceFilter(const fvMesh& mesh, const dictionary& bd)
     (
         IOobject
         (
-            "anisotropicFilterCoeff",
+            "laplaceFilterCoeff",
             mesh.time().timeName(),
             mesh
         ),
diff --git a/src/turbulenceModels/compressible/LES/LESModel/LESModel.C b/src/turbulenceModels/compressible/LES/LESModel/LESModel.C
index 01d3a4110ca901bad2a7368bf38eaf26660146ef..95c282e822de14df7432fdc9d6409b8f69d1bf7c 100644
--- a/src/turbulenceModels/compressible/LES/LESModel/LESModel.C
+++ b/src/turbulenceModels/compressible/LES/LESModel/LESModel.C
@@ -38,6 +38,7 @@ namespace compressible
 
 defineTypeNameAndDebug(LESModel, 0);
 defineRunTimeSelectionTable(LESModel, dictionary);
+addToRunTimeSelectionTable(turbulenceModel, LESModel, turbulenceModel);
 
 // * * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * //
 
diff --git a/src/turbulenceModels/compressible/RAS/RASModel/RASModel.C b/src/turbulenceModels/compressible/RAS/RASModel/RASModel.C
index 22b646e55e2241cdc47b3264be9735efe9477199..ba1545d4eab2cc4615f9c7a1e56f080254a06bec 100644
--- a/src/turbulenceModels/compressible/RAS/RASModel/RASModel.C
+++ b/src/turbulenceModels/compressible/RAS/RASModel/RASModel.C
@@ -39,6 +39,7 @@ namespace compressible
 
 defineTypeNameAndDebug(RASModel, 0);
 defineRunTimeSelectionTable(RASModel, dictionary);
+addToRunTimeSelectionTable(turbulenceModel, RASModel, turbulenceModel);
 
 // * * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * //