diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict
index dab2d1d064f34104846954217ec51dc5c0255bbb..31a841b80fc3733ea0f0a1090e610a097a4881f9 100644
--- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict
+++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict
@@ -327,14 +327,17 @@ meshQualityControls
     //  Set to 180 to disable.
     maxConcave 80;
 
-    //- Minimum projected area v.s. actual area. Set to -1 to disable.
-    minFlatness 0.5;
-
     //- Minimum pyramid volume. Is absolute volume of cell pyramid.
     //  Set to a sensible fraction of the smallest cell volume expected.
     //  Set to very negative number (e.g. -1E30) to disable.
     minVol 1e-13;
 
+    //- Minimum tet volume. Is absolute volume of the tet formed by the
+    //  face-centre decomposition triangle and the cell centre.
+    //  Set to a sensible fraction of the smallest cell volume expected.
+    //  Set to very negative number (e.g. -1E30) to disable.
+    minTetVol 1e-20;
+
     //- Minimum face area. Set to <0 to disable.
     minArea -1;
 
diff --git a/applications/utilities/mesh/manipulation/checkMesh/checkGeometry.C b/applications/utilities/mesh/manipulation/checkMesh/checkGeometry.C
index 44ad601a02906c067b1d3180a6e721d0a090a937..e16d90bbbd1adbd1be557973de6b8107776f9d97 100644
--- a/applications/utilities/mesh/manipulation/checkMesh/checkGeometry.C
+++ b/applications/utilities/mesh/manipulation/checkMesh/checkGeometry.C
@@ -159,6 +159,25 @@ Foam::label Foam::checkGeometry(const polyMesh& mesh, const bool allGeometry)
         }
     }
 
+    {
+        faceSet faces(mesh, "wrongOrientedTriangleFaces", mesh.nFaces()/100 + 1);
+        if (mesh.checkFaceTets(true, 0, &faces))
+        {
+            noFailedChecks++;
+
+            label nFaces = returnReduce(faces.size(), sumOp<label>());
+
+            if (nFaces > 0)
+            {
+                Info<< "  <<Writing " << nFaces
+                    << " faces with incorrectly orientated triangles to set "
+                    << faces.name() << endl;
+                faces.instance() = mesh.pointsInstance();
+                faces.write();
+            }
+        }
+    }
+
     {
         faceSet faces(mesh, "skewFaces", mesh.nFaces()/100 + 1);
         if (mesh.checkFaceSkewness(true, &faces))
diff --git a/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C b/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C
index 7b9d5ea8cef40a92f51bdf95ffa56ee545ae5bea..07a3b8442614e2a13ae57d87ff31547df92f052d 100644
--- a/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C
+++ b/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C
@@ -22,6 +22,9 @@ License
     along with OpenFOAM; if not, write to the Free Software Foundation,
     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 
+Application
+    splitMeshRegions
+
 Description
     Splits mesh into multiple regions.
 
@@ -32,6 +35,7 @@ Description
     - any face inbetween differing cellZones (-cellZones)
 
     Output is:
+    - volScalarField with regions as different scalars (-detectOnly) or
     - mesh with multiple regions or
     - mesh with cells put into cellZones (-makeCellZones)
 
@@ -47,7 +51,13 @@ Description
     - useCellZonesOnly does not do a walk and uses the cellZones only. Use
     this if you don't mind having disconnected domains in a single region.
     This option requires all cells to be in one (and one only) cellZone.
-
+    - writes maps like decomposePar back to original mesh:
+        - pointRegionAddressing : for every point in this region the point in
+        the original mesh
+        - cellRegionAddressing  :   ,,      cell                ,,  cell    ,,
+        - faceRegionAddressing  :   ,,      face                ,,  face in
+        the original mesh + 'turning index'. For a face in the same orientation
+        this is the original facelabel+1, for a turned face this is -facelabel-1
 \*---------------------------------------------------------------------------*/
 
 #include "SortableList.H"
diff --git a/applications/utilities/parallelProcessing/decomposePar/decomposePar.C b/applications/utilities/parallelProcessing/decomposePar/decomposePar.C
index 02d8005e923f0930c177f8ae3f9843f8bf700ea7..afd3667f6e348e6ce3ac70ae9c8a3a214a5beadc 100644
--- a/applications/utilities/parallelProcessing/decomposePar/decomposePar.C
+++ b/applications/utilities/parallelProcessing/decomposePar/decomposePar.C
@@ -334,6 +334,14 @@ int main(int argc, char *argv[])
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     PtrList<surfaceScalarField> surfaceScalarFields;
     readFields(mesh, objects, surfaceScalarFields);
+    PtrList<surfaceVectorField> surfaceVectorFields;
+    readFields(mesh, objects, surfaceVectorFields);
+    PtrList<surfaceSphericalTensorField> surfaceSphericalTensorFields;
+    readFields(mesh, objects, surfaceSphericalTensorFields);
+    PtrList<surfaceSymmTensorField> surfaceSymmTensorFields;
+    readFields(mesh, objects, surfaceSymmTensorFields);
+    PtrList<surfaceTensorField> surfaceTensorFields;
+    readFields(mesh, objects, surfaceTensorFields);
 
 
     // Construct the point fields
@@ -619,6 +627,10 @@ int main(int argc, char *argv[])
          || volSymmTensorFields.size()
          || volTensorFields.size()
          || surfaceScalarFields.size()
+         || surfaceVectorFields.size()
+         || surfaceSphericalTensorFields.size()
+         || surfaceSymmTensorFields.size()
+         || surfaceTensorFields.size()
         )
         {
             labelIOList faceProcAddressing
@@ -650,6 +662,10 @@ int main(int argc, char *argv[])
             fieldDecomposer.decomposeFields(volTensorFields);
 
             fieldDecomposer.decomposeFields(surfaceScalarFields);
+            fieldDecomposer.decomposeFields(surfaceVectorFields);
+            fieldDecomposer.decomposeFields(surfaceSphericalTensorFields);
+            fieldDecomposer.decomposeFields(surfaceSymmTensorFields);
+            fieldDecomposer.decomposeFields(surfaceTensorFields);
         }
 
 
diff --git a/applications/utilities/parallelProcessing/reconstructPar/reconstructPar.C b/applications/utilities/parallelProcessing/reconstructPar/reconstructPar.C
index d2dcd818cade4bd3d76106df808672c968ecd1cd..d40be34b0ad8ed00ded8560c7d2458b0ef2a59f2 100644
--- a/applications/utilities/parallelProcessing/reconstructPar/reconstructPar.C
+++ b/applications/utilities/parallelProcessing/reconstructPar/reconstructPar.C
@@ -191,6 +191,10 @@ int main(int argc, char *argv[])
          || objects.lookupClass(volSymmTensorField::typeName).size()
          || objects.lookupClass(volTensorField::typeName).size()
          || objects.lookupClass(surfaceScalarField::typeName).size()
+         || objects.lookupClass(surfaceVectorField::typeName).size()
+         || objects.lookupClass(surfaceSphericalTensorField::typeName).size()
+         || objects.lookupClass(surfaceSymmTensorField::typeName).size()
+         || objects.lookupClass(surfaceTensorField::typeName).size()
         )
         {
             Info<< "Reconstructing FV fields" << nl << endl;
@@ -235,6 +239,26 @@ int main(int argc, char *argv[])
                 objects,
                 selectedFields
             );
+            fvReconstructor.reconstructFvSurfaceFields<vector>
+            (
+                objects,
+                selectedFields
+            );
+            fvReconstructor.reconstructFvSurfaceFields<sphericalTensor>
+            (
+                objects,
+                selectedFields
+            );
+            fvReconstructor.reconstructFvSurfaceFields<symmTensor>
+            (
+                objects,
+                selectedFields
+            );
+            fvReconstructor.reconstructFvSurfaceFields<tensor>
+            (
+                objects,
+                selectedFields
+            );
         }
         else
         {
diff --git a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.C b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.C
index 07bb357ff34bb39318d0638c1491779cd3509c79..1820c43ef05c0212792deecef9dd99bf97b52762 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.C
+++ b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.C
@@ -61,8 +61,7 @@ Foam::polyBoundaryMesh::polyBoundaryMesh
 :
     polyPatchList(),
     regIOobject(io),
-    mesh_(mesh),
-    neighbourEdgesPtr_(NULL)
+    mesh_(mesh)
 {
     if (readOpt() == IOobject::MUST_READ)
     {
@@ -110,17 +109,14 @@ Foam::polyBoundaryMesh::polyBoundaryMesh
 :
     polyPatchList(size),
     regIOobject(io),
-    mesh_(pm),
-    neighbourEdgesPtr_(NULL)
+    mesh_(pm)
 {}
 
 
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 Foam::polyBoundaryMesh::~polyBoundaryMesh()
-{
-    deleteDemandDrivenData(neighbourEdgesPtr_);
-}
+{}
 
 
 void Foam::polyBoundaryMesh::clearGeom()
@@ -134,7 +130,8 @@ void Foam::polyBoundaryMesh::clearGeom()
 
 void Foam::polyBoundaryMesh::clearAddressing()
 {
-    deleteDemandDrivenData(neighbourEdgesPtr_);
+    neighbourEdgesPtr_.clear();
+    patchIDPtr_.clear();
 
     forAll (*this, patchi)
     {
@@ -201,10 +198,10 @@ Foam::polyBoundaryMesh::neighbourEdges() const
             << " boundaries." << endl;
     }
 
-    if (!neighbourEdgesPtr_)
+    if (!neighbourEdgesPtr_.valid())
     {
-        neighbourEdgesPtr_ = new List<labelPairList>(size());
-        List<labelPairList>& neighbourEdges = *neighbourEdgesPtr_;
+        neighbourEdgesPtr_.reset(new List<labelPairList>(size()));
+        List<labelPairList>& neighbourEdges = neighbourEdgesPtr_();
 
         // Initialize.
         label nEdgePairs = 0;
@@ -320,7 +317,36 @@ Foam::polyBoundaryMesh::neighbourEdges() const
         }
     }
 
-    return *neighbourEdgesPtr_;
+    return neighbourEdgesPtr_();
+}
+
+
+const Foam::labelList& Foam::polyBoundaryMesh::patchID() const
+{
+    if (!patchIDPtr_.valid())
+    {
+        patchIDPtr_.reset
+        (
+            new labelList
+            (
+                mesh_.nFaces()
+              - mesh_.nInternalFaces()
+            )
+        );
+        labelList& patchID = patchIDPtr_();
+
+        const polyBoundaryMesh& bm = *this;
+
+        forAll(bm, patchI)
+        {
+            label bFaceI = bm[patchI].start() - mesh_.nInternalFaces();
+            forAll(bm[patchI], i)
+            {
+                patchID[bFaceI++] = patchI;
+            }
+        }
+    }
+    return patchIDPtr_();
 }
 
 
@@ -654,7 +680,8 @@ void Foam::polyBoundaryMesh::movePoints(const pointField& p)
 
 void Foam::polyBoundaryMesh::updateMesh()
 {
-    deleteDemandDrivenData(neighbourEdgesPtr_);
+    neighbourEdgesPtr_.clear();
+    patchIDPtr_.clear();
 
     PstreamBuffers pBufs(Pstream::defaultCommsType);
 
diff --git a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.H b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.H
index fdea473ed3abd8b438604cce9b59ca36e15edb82..76981ef2bceeb0b3bd449ddcf32953e59b41c9b3 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.H
+++ b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.H
@@ -67,8 +67,10 @@ class polyBoundaryMesh
         //- Reference to mesh
         const polyMesh& mesh_;
 
+        mutable autoPtr<labelList> patchIDPtr_;
+
         //- Edges of neighbouring patches
-        mutable List<labelPairList>* neighbourEdgesPtr_;
+        mutable autoPtr<List<labelPairList> > neighbourEdgesPtr_;
 
 
     // Private Member Functions
@@ -157,6 +159,9 @@ public:
         //- Return patch index for a given face label
         label whichPatch(const label faceIndex) const;
 
+        //- Per boundary face label the patch index
+        const labelList& patchID() const;
+
         //- Return the set of patch IDs corresponding to the given list of names
         //  Wild cards are expanded.
         labelHashSet patchSet(const wordList&) const;
diff --git a/src/OpenFOAM/meshes/primitiveMesh/primitiveMesh.H b/src/OpenFOAM/meshes/primitiveMesh/primitiveMesh.H
index 26550cda5618b828ccb3669bda4dc7b38e6f73f5..1e3e2293d9f17508bfee4cbf05823a2c90b4b143 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/primitiveMesh.H
+++ b/src/OpenFOAM/meshes/primitiveMesh/primitiveMesh.H
@@ -556,7 +556,6 @@ public:
                 //- Check for negative cell volumes
                 bool checkCellVolumes
                 (
-
                     const bool report = false,
                     labelHashSet* setPtr = NULL
                 ) const;
@@ -576,6 +575,14 @@ public:
                     labelHashSet* setPtr = NULL
                 ) const;
 
+                //- Check face-decomposition tet volume
+                bool checkFaceTets
+                (
+                    const bool report = false,
+                    const scalar minTetVol = 0,
+                    labelHashSet* setPtr = NULL
+                ) const;
+
                 //- Check face skewness
                 bool checkFaceSkewness
                 (
diff --git a/src/OpenFOAM/meshes/primitiveMesh/primitiveMeshCheck/primitiveMeshCheck.C b/src/OpenFOAM/meshes/primitiveMesh/primitiveMeshCheck/primitiveMeshCheck.C
index 36d6b1a28f34da1748e22ef35fe5fe0f04e907c4..a7eab05ab99b28ad0d7e1cf41bc39929a9a1fded 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/primitiveMeshCheck/primitiveMeshCheck.C
+++ b/src/OpenFOAM/meshes/primitiveMesh/primitiveMeshCheck/primitiveMeshCheck.C
@@ -26,6 +26,7 @@ License
 
 #include "primitiveMesh.H"
 #include "pyramidPointFaceRef.H"
+#include "tetPointRef.H"
 #include "ListOps.H"
 #include "unitConversion.H"
 #include "SortableList.H"
@@ -401,7 +402,7 @@ bool Foam::primitiveMesh::checkFaceOrthogonality
             << "checking mesh non-orthogonality" << endl;
     }
 
-    // for all internal faces check theat the d dot S product is positive
+    // for all internal faces check that the d dot S product is positive
     const vectorField& centres = cellCentres();
     const vectorField& areas = faceAreas();
 
@@ -591,6 +592,114 @@ bool Foam::primitiveMesh::checkFacePyramids
 }
 
 
+bool Foam::primitiveMesh::checkFaceTets
+(
+    const bool report,
+    const scalar minTetVol,
+    labelHashSet* setPtr
+) const
+{
+    if (debug)
+    {
+        Info<< "bool primitiveMesh::checkFaceTets("
+            << "const bool, const scalar, labelHashSet*) const: "
+            << "checking face orientation" << endl;
+    }
+
+    // check whether face area vector points to the cell with higher label
+    const vectorField& cc = cellCentres();
+    const vectorField& fc = faceCentres();
+
+    const labelList& own = faceOwner();
+    const labelList& nei = faceNeighbour();
+
+    const faceList& fcs = faces();
+
+    const pointField& p = points();
+
+    label nErrorPyrs = 0;
+
+    forAll (fcs, faceI)
+    {
+        // Create the owner tets - they will have negative volume
+        const face& f = fcs[faceI];
+
+        forAll(f, fp)
+        {
+            scalar tetVol = tetPointRef
+            (
+                p[f[fp]],
+                p[f.nextLabel(fp)],
+                fc[faceI],
+                cc[own[faceI]]
+            ).mag();
+
+            if (tetVol > -minTetVol)
+            {
+                if (setPtr)
+                {
+                    setPtr->insert(faceI);
+                }
+
+                nErrorPyrs++;
+                break;              // no need to check other tets
+            }
+        }
+
+        if (isInternalFace(faceI))
+        {
+            // Create the neighbour tet - it will have positive volume
+            const face& f = fcs[faceI];
+
+            forAll(f, fp)
+            {
+                scalar tetVol = tetPointRef
+                (
+                    p[f[fp]],
+                    p[f.nextLabel(fp)],
+                    fc[faceI],
+                    cc[nei[faceI]]
+                ).mag();
+
+                if (tetVol < minTetVol)
+                {
+                    if (setPtr)
+                    {
+                        setPtr->insert(faceI);
+                    }
+
+                    nErrorPyrs++;
+                    break;
+                }
+            }
+        }
+    }
+
+    reduce(nErrorPyrs, sumOp<label>());
+
+    if (nErrorPyrs > 0)
+    {
+        if (debug || report)
+        {
+            Info<< " ***Error in face tets: "
+                << nErrorPyrs << " faces have incorrectly oriented face"
+                << " decomposition triangles." << endl;
+        }
+
+        return true;
+    }
+    else
+    {
+        if (debug || report)
+        {
+            Info<< "    Face tets OK." << endl;
+        }
+
+        return false;
+    }
+}
+
+
 bool Foam::primitiveMesh::checkFaceSkewness
 (
     const bool report,
diff --git a/src/dynamicMesh/motionSmoother/motionSmootherCheck.C b/src/dynamicMesh/motionSmoother/motionSmootherCheck.C
index 7fcb9f1e7ac70660201f2a760565ac691aefd526..2a7c83d242c0f127c486994c20c832a1a25f8f2f 100644
--- a/src/dynamicMesh/motionSmoother/motionSmootherCheck.C
+++ b/src/dynamicMesh/motionSmoother/motionSmootherCheck.C
@@ -69,6 +69,10 @@ bool Foam::motionSmoother::checkMesh
     (
         readScalar(dict.lookup("minVol", true))
     );
+    const scalar minTetVol
+    (
+        readScalar(dict.lookup("minTetVol", true))
+    );
     const scalar maxConcave
     (
         readScalar(dict.lookup("maxConcave", true))
@@ -105,7 +109,6 @@ bool Foam::motionSmoother::checkMesh
     (
         readScalar(dict.lookup("minDeterminant", true))
     );
-
     label nWrongFaces = 0;
 
     Info<< "Checking faces in error :" << endl;
@@ -158,6 +161,30 @@ bool Foam::motionSmoother::checkMesh
         nWrongFaces = nNewWrongFaces;
     }
 
+    if (minTetVol > -GREAT)
+    {
+        polyMeshGeometry::checkFaceTets
+        (
+            report,
+            minTetVol,
+            mesh,
+            mesh.cellCentres(),
+            mesh.faceCentres(),
+            mesh.points(),
+            checkFaces,
+            baffles,
+            &wrongFaces
+        );
+
+        label nNewWrongFaces = returnReduce(wrongFaces.size(), sumOp<label>());
+
+        Info<< "    faces with face-decomposition tet volume < "
+            << setw(5) << minTetVol << "        : "
+            << nNewWrongFaces-nWrongFaces << endl;
+
+        nWrongFaces = nNewWrongFaces;
+    }
+
     if (maxConcave < 180.0-SMALL)
     {
         polyMeshGeometry::checkFaceAngles
@@ -417,6 +444,10 @@ bool Foam::motionSmoother::checkMesh
     (
         readScalar(dict.lookup("minVol", true))
     );
+    const scalar minTetVol
+    (
+        readScalar(dict.lookup("minTetVol", true))
+    );
     const scalar maxConcave
     (
         readScalar(dict.lookup("maxConcave", true))
@@ -501,6 +532,27 @@ bool Foam::motionSmoother::checkMesh
         nWrongFaces = nNewWrongFaces;
     }
 
+    if (minTetVol > -GREAT)
+    {
+        meshGeom.checkFaceTets
+        (
+            report,
+            minTetVol,
+            meshGeom.mesh().points(),
+            checkFaces,
+            baffles,
+            &wrongFaces
+        );
+
+        label nNewWrongFaces = returnReduce(wrongFaces.size(), sumOp<label>());
+
+        Info<< "    faces with face-decomposition tet volume < "
+            << setw(5) << minTetVol << "                 : "
+            << nNewWrongFaces-nWrongFaces << endl;
+
+        nWrongFaces = nNewWrongFaces;
+    }
+
     if (maxConcave < 180.0-SMALL)
     {
         meshGeom.checkFaceAngles
diff --git a/src/dynamicMesh/motionSmoother/polyMeshGeometry/polyMeshGeometry.C b/src/dynamicMesh/motionSmoother/polyMeshGeometry/polyMeshGeometry.C
index f777081d03097dfc72b6307ba8d7306441a1fae7..6428bb9160060184494ad1c71102509fca3bdd85 100644
--- a/src/dynamicMesh/motionSmoother/polyMeshGeometry/polyMeshGeometry.C
+++ b/src/dynamicMesh/motionSmoother/polyMeshGeometry/polyMeshGeometry.C
@@ -26,6 +26,7 @@ License
 
 #include "polyMeshGeometry.H"
 #include "pyramidPointFaceRef.H"
+#include "tetPointRef.H"
 #include "syncTools.H"
 #include "unitConversion.H"
 
@@ -308,6 +309,59 @@ Foam::scalar Foam::polyMeshGeometry::calcSkewness
 }
 
 
+// Create the neighbour pyramid - it will have positive volume
+bool Foam::polyMeshGeometry::checkFaceTet
+(
+    const polyMesh& mesh,
+    const bool report,
+    const scalar minTetVol,
+    const pointField& p,
+    const label faceI,
+    const point& fc,    // face centre
+    const point& cc,    // cell centre
+
+    labelHashSet* setPtr
+)
+{
+    const face& f = mesh.faces()[faceI];
+
+    forAll(f, fp)
+    {
+        scalar tetVol = tetPointRef
+        (
+            p[f[fp]],
+            p[f.nextLabel(fp)],
+            fc,
+            cc
+        ).mag();
+
+        if (tetVol < minTetVol)
+        {
+            if (report)
+            {
+                Pout<< "bool polyMeshGeometry::checkFaceTets("
+                    << "const bool, const scalar, const pointField&"
+                    << ", const pointField&, const labelList&,"
+                    << " labelHashSet*): "
+                    << "face " << faceI
+                    << " has a triangle that points the wrong way."
+                     << endl
+                    << "Tet volume: " << tetVol
+                    << " Face " << faceI
+                    << endl;
+            }
+
+            if (setPtr)
+            {
+                setPtr->insert(faceI);
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 // Construct from components
@@ -719,6 +773,139 @@ bool Foam::polyMeshGeometry::checkFacePyramids
 }
 
 
+bool Foam::polyMeshGeometry::checkFaceTets
+(
+    const bool report,
+    const scalar minTetVol,
+    const polyMesh& mesh,
+    const vectorField& cellCentres,
+    const vectorField& faceCentres,
+    const pointField& p,
+    const labelList& checkFaces,
+    const List<labelPair>& baffles,
+    labelHashSet* setPtr
+)
+{
+    // check whether face area vector points to the cell with higher label
+    const labelList& own = mesh.faceOwner();
+    const labelList& nei = mesh.faceNeighbour();
+
+    label nErrorPyrs = 0;
+
+    forAll(checkFaces, i)
+    {
+        label faceI = checkFaces[i];
+
+        // Create the owner pyramid - note: exchange cell and face centre
+        // to get positive volume.
+        bool tetError = checkFaceTet
+        (
+            mesh,
+            report,
+            minTetVol,
+            p,
+            faceI,
+            cellCentres[own[faceI]],    // face centre
+            faceCentres[faceI],    // cell centre
+            setPtr
+        );
+
+        if (tetError)
+        {
+            nErrorPyrs++;
+        }
+
+        if (mesh.isInternalFace(faceI))
+        {
+            // Create the neighbour pyramid - it will have positive volume
+            bool tetError = checkFaceTet
+            (
+                mesh,
+                report,
+                minTetVol,
+                p,
+                faceI,
+                faceCentres[faceI],    // face centre
+                cellCentres[nei[faceI]],    // cell centre
+                setPtr
+            );
+            if (tetError)
+            {
+                nErrorPyrs++;
+            }
+        }
+    }
+
+    forAll(baffles, i)
+    {
+        label face0 = baffles[i].first();
+        label face1 = baffles[i].second();
+
+        bool tetError = checkFaceTet
+        (
+            mesh,
+            report,
+            minTetVol,
+            p,
+            face0,
+            cellCentres[own[face0]],    // face centre
+            faceCentres[face0],         // cell centre
+            setPtr
+        );
+
+        if (tetError)
+        {
+            nErrorPyrs++;
+        }
+
+        // Create the neighbour pyramid - it will have positive volume
+        tetError = checkFaceTet
+        (
+            mesh,
+            report,
+            minTetVol,
+            p,
+            face0,
+            faceCentres[face0],         // face centre
+            cellCentres[own[face1]],    // cell centre
+            setPtr
+        );
+
+        if (tetError)
+        {
+            nErrorPyrs++;
+        }
+    }
+
+    reduce(nErrorPyrs, sumOp<label>());
+
+    if (nErrorPyrs > 0)
+    {
+        if (report)
+        {
+            SeriousErrorIn
+            (
+                "polyMeshGeometry::checkFaceTets("
+                "const bool, const scalar, const pointField&, const pointField&"
+                ", const labelList&, labelHashSet*)"
+            )   << "Error in face pyramids: faces pointing the wrong way!"
+                << endl;
+        }
+
+        return true;
+    }
+    else
+    {
+        if (report)
+        {
+            Info<< "Face tets OK.\n" << endl;
+        }
+
+        return false;
+    }
+}
+
+
 bool Foam::polyMeshGeometry::checkFaceSkewness
 (
     const bool report,
@@ -1946,6 +2133,31 @@ bool Foam::polyMeshGeometry::checkFacePyramids
 }
 
 
+bool Foam::polyMeshGeometry::checkFaceTets
+(
+    const bool report,
+    const scalar minTetVol,
+    const pointField& p,
+    const labelList& checkFaces,
+    const List<labelPair>& baffles,
+    labelHashSet* setPtr
+) const
+{
+    return checkFaceTets
+    (
+        report,
+        minTetVol,
+        mesh_,
+        cellCentres_,
+        faceCentres_,
+        p,
+        checkFaces,
+        baffles,
+        setPtr
+    );
+}
+
+
 bool Foam::polyMeshGeometry::checkFaceSkewness
 (
     const bool report,
diff --git a/src/dynamicMesh/motionSmoother/polyMeshGeometry/polyMeshGeometry.H b/src/dynamicMesh/motionSmoother/polyMeshGeometry/polyMeshGeometry.H
index 91f27e6a001137aceb5d532baa76e7a014594289..f0135aae33931ccaab40a84458a6e3e7c2f9cf55 100644
--- a/src/dynamicMesh/motionSmoother/polyMeshGeometry/polyMeshGeometry.H
+++ b/src/dynamicMesh/motionSmoother/polyMeshGeometry/polyMeshGeometry.H
@@ -109,6 +109,19 @@ class polyMeshGeometry
             const point& fc
         );
 
+        //- Detect&report incorrect face-triangle orientation
+        static bool checkFaceTet
+        (
+            const polyMesh&,
+            const bool report,
+            const scalar minTetVol,
+            const pointField& p,
+            const label faceI,
+            const point& fc,    // face centre
+            const point& cc,    // cell centre
+            labelHashSet* setPtr
+        );
+
 public:
 
     ClassName("polyMeshGeometry");
@@ -195,6 +208,20 @@ public:
                 labelHashSet*
             );
 
+            //- See primitiveMesh
+            static bool checkFaceTets
+            (
+                const bool report,
+                const scalar minPyrVol,
+                const polyMesh&,
+                const vectorField& cellCentres,
+                const vectorField& faceCentres,
+                const pointField& p,
+                const labelList& checkFaces,
+                const List<labelPair>& baffles,
+                labelHashSet*
+            );
+
             //- See primitiveMesh
             static bool checkFaceSkewness
             (
@@ -321,6 +348,16 @@ public:
                 labelHashSet* setPtr
             ) const;
 
+            bool checkFaceTets
+            (
+                const bool report,
+                const scalar minTetVol,
+                const pointField& p,
+                const labelList& checkFaces,
+                const List<labelPair>& baffles,
+                labelHashSet* setPtr
+            ) const;
+
             bool checkFaceSkewness
             (
                 const bool report,
diff --git a/src/postProcessing/functionObjects/field/fieldValues/faceSource/faceSource.H b/src/postProcessing/functionObjects/field/fieldValues/faceSource/faceSource.H
index 8ef65d870b717b31423ec919d89cfa61f515ee04..0d013cd7e3c7b9a23256aca8519b5d7d18f3ad00 100644
--- a/src/postProcessing/functionObjects/field/fieldValues/faceSource/faceSource.H
+++ b/src/postProcessing/functionObjects/field/fieldValues/faceSource/faceSource.H
@@ -29,9 +29,9 @@ Description
     Face source variant of field value function object. Values of user-
     specified fields reported for collections of faces.
 
-    cellObj1                        // Name also used to identify output folder
+    faceObj1                        // Name also used to identify output folder
     {
-        type            cellSource;
+        type            faceSource;
         functionObjectLibs ("libfieldValueFunctionObjects.so");
         enabled         true;
         outputControl   outputTime;
diff --git a/tutorials/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges/system/snappyHexMeshDict b/tutorials/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges/system/snappyHexMeshDict
index 14b7a8fa0bc4010f3c826e88b698c988e8b064a4..4c921888160634dd27f7603a95d5b828521f7341 100644
--- a/tutorials/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges/system/snappyHexMeshDict
+++ b/tutorials/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges/system/snappyHexMeshDict
@@ -353,14 +353,17 @@ meshQualityControls
     //  Set to 180 to disable.
     maxConcave 80;
 
-    //- Minimum projected area v.s. actual area. Set to -1 to disable.
-    minFlatness 0.5;
-
     //- Minimum pyramid volume. Is absolute volume of cell pyramid.
     //  Set to a sensible fraction of the smallest cell volume expected.
     //  Set to very negative number (e.g. -1E30) to disable.
     minVol 1e-13;
 
+    //- Minimum tet volume. Is absolute volume of the tet formed by the
+    //  face-centre decomposition triangle and the cell centre.
+    //  Set to a sensible fraction of the smallest cell volume expected.
+    //  Set to very negative number (e.g. -1E30) to disable.
+    minTetVol 1e-20;
+
     //- Minimum face area. Set to <0 to disable.
     minArea -1;
 
diff --git a/tutorials/heatTransfer/chtMultiRegionFoam/snappyMultiRegionHeater/system/snappyHexMeshDict b/tutorials/heatTransfer/chtMultiRegionFoam/snappyMultiRegionHeater/system/snappyHexMeshDict
index bb6fb94f13f99d1741a94ec4f6bd90b598757f13..5e89caf1cb505d4b870787bedf074d1a5d836e5d 100644
--- a/tutorials/heatTransfer/chtMultiRegionFoam/snappyMultiRegionHeater/system/snappyHexMeshDict
+++ b/tutorials/heatTransfer/chtMultiRegionFoam/snappyMultiRegionHeater/system/snappyHexMeshDict
@@ -335,13 +335,16 @@ meshQualityControls
     //  Set to 180 to disable.
     maxConcave 80;
 
-    //- Minimum projected area v.s. actual area. Set to -1 to disable.
-    minFlatness 0.5;
-
     //- Minimum pyramid volume. Is absolute volume of cell pyramid.
     //  Set to very negative number (e.g. -1E30) to disable.
     minVol 0;
 
+    //- Minimum tet volume. Is absolute volume of the tet formed by the
+    //  face-centre decomposition triangle and the cell centre.
+    //  Set to a sensible fraction of the smallest cell volume expected.
+    //  Set to very negative number (e.g. -1E30) to disable.
+    minTetVol 1e-20;
+
     //- Minimum face area. Set to <0 to disable.
     minArea -1;
 
diff --git a/tutorials/incompressible/simpleFoam/motorBike/system/snappyHexMeshDict b/tutorials/incompressible/simpleFoam/motorBike/system/snappyHexMeshDict
index 1878f5b1a7a4dd8ae2c8440dc58cfeaba3d109b2..1ce2a9bbe6e979eb780c885cc168afb510477860 100644
--- a/tutorials/incompressible/simpleFoam/motorBike/system/snappyHexMeshDict
+++ b/tutorials/incompressible/simpleFoam/motorBike/system/snappyHexMeshDict
@@ -546,14 +546,17 @@ meshQualityControls
     //  Set to 180 to disable.
     maxConcave 80;
 
-    //- Minimum projected area v.s. actual area. Set to -1 to disable.
-    minFlatness 0.5;
-
     //- Minimum pyramid volume. Is absolute volume of cell pyramid.
     //  Set to a sensible fraction of the smallest cell volume expected.
     //  Set to very negative number (e.g. -1E30) to disable.
     minVol 1e-13;
 
+    //- Minimum tet volume. Is absolute volume of the tet formed by the
+    //  face-centre decomposition triangle and the cell centre.
+    //  Set to a sensible fraction of the smallest cell volume expected.
+    //  Set to very negative number (e.g. -1E30) to disable.
+    minTetVol 1e-20;
+
     //- Minimum face area. Set to <0 to disable.
     minArea -1;
 
diff --git a/tutorials/multiphase/interPhaseChangeFoam/cavitatingBullet/system/snappyHexMeshDict b/tutorials/multiphase/interPhaseChangeFoam/cavitatingBullet/system/snappyHexMeshDict
index b11bf56a0f60ec77d9c828a7b4dc8b52d496248b..97affa0fd77003812350b512e666a4c0849a42bd 100644
--- a/tutorials/multiphase/interPhaseChangeFoam/cavitatingBullet/system/snappyHexMeshDict
+++ b/tutorials/multiphase/interPhaseChangeFoam/cavitatingBullet/system/snappyHexMeshDict
@@ -288,13 +288,16 @@ meshQualityControls
     //  Set to 180 to disable.
     maxConcave 80;
 
-    //- Minimum projected area v.s. actual area. Set to -1 to disable.
-    minFlatness 0.5;
-
     //- Minimum pyramid volume. Is absolute volume of cell pyramid.
     //  Set to very negative number (e.g. -1E30) to disable.
     minVol 1e-20;
 
+    //- Minimum tet volume. Is absolute volume of the tet formed by the
+    //  face-centre decomposition triangle and the cell centre.
+    //  Set to a sensible fraction of the smallest cell volume expected.
+    //  Set to very negative number (e.g. -1E30) to disable.
+    minTetVol 1e-20;
+
     //- Minimum face area. Set to <0 to disable.
     minArea -1;