diff --git a/applications/test/momentOfInertia/Test-momentOfInertia.C b/applications/test/momentOfInertia/Test-momentOfInertia.C
index 5abba3d382a4e58894c60905a654f8e27c9488bd..3961caaffc1ade2f72099029e7079f23361cfa14 100644
--- a/applications/test/momentOfInertia/Test-momentOfInertia.C
+++ b/applications/test/momentOfInertia/Test-momentOfInertia.C
@@ -2,7 +2,7 @@
  =========                   |
  \\      /   F ield          | OpenFOAM: The Open Source CFD Toolbox
   \\    /    O peration      |
-   \\  /     A nd            | Copyright (C) 2011-2016 OpenFOAM Foundation
+   \\  /     A nd            | Copyright (C) 2011-2017 OpenFOAM Foundation
     \\/      M anipulation   |
 -------------------------------------------------------------------------------
 License
@@ -35,7 +35,7 @@ Description
 #include "polyMesh.H"
 #include "ListOps.H"
 #include "face.H"
-#include "tetrahedron.H"
+#include "tetPointRef.H"
 #include "triFaceList.H"
 #include "OFstream.H"
 #include "meshTools.H"
diff --git a/applications/test/tetTetOverlap/Test-tetTetOverlap.C b/applications/test/tetTetOverlap/Test-tetTetOverlap.C
index e31493161484898ea134c47de7bd7581e67b2b11..b85db9c681b79ad8c6b468352e78be0fedc8ac68 100644
--- a/applications/test/tetTetOverlap/Test-tetTetOverlap.C
+++ b/applications/test/tetTetOverlap/Test-tetTetOverlap.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2012-2015 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2012-2017 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -29,9 +29,10 @@ Description
 
 \*---------------------------------------------------------------------------*/
 
-#include "tetrahedron.H"
+#include "tetPointRef.H"
 #include "OFstream.H"
 #include "meshTools.H"
+#include "cut.H"
 
 using namespace Foam;
 
@@ -41,7 +42,7 @@ void writeOBJ
 (
     Ostream& os,
     label& vertI,
-    const tetPoints& tet
+    const FixedList<point, 4>& tet
 )
 {
     forAll(tet, fp)
@@ -58,105 +59,126 @@ void writeOBJ
 }
 
 
+tetPointRef makeTetPointRef(const FixedList<point, 4>& p)
+{
+    return tetPointRef(p[0], p[1], p[2], p[3]);
+}
+
+
 int main(int argc, char *argv[])
 {
-    tetPoints A
-    (
+    // Tets to test
+    FixedList<point, 4> tetA
+    ({
         point(0, 0, 0),
         point(1, 0, 0),
         point(1, 1, 0),
         point(1, 1, 1)
-    );
-    const tetPointRef tetA = A.tet();
-
-    tetPoints B
-    (
+    });
+    FixedList<point, 4> tetB
+    ({
         point(0.1, 0.1, 0.1),
         point(1.1, 0.1, 0.1),
         point(1.1, 1.1, 0.1),
         point(1.1, 1.1, 1.1)
-    );
-    const tetPointRef tetB = B.tet();
+    });
 
 
-    tetPointRef::tetIntersectionList insideTets;
-    label nInside = 0;
-    tetPointRef::tetIntersectionList outsideTets;
-    label nOutside = 0;
+    // Do intersection
+    typedef DynamicList<FixedList<point, 4>> tetList;
+    tetList tetsIn1, tetsIn2, tetsOut;
+    cut::appendOp<tetList> tetOpIn1(tetsIn1);
+    cut::appendOp<tetList> tetOpIn2(tetsIn2);
+    cut::appendOp<tetList> tetOpOut(tetsOut);
 
-    tetA.tetOverlap
-    (
-        tetB,
-        insideTets,
-        nInside,
-        outsideTets,
-        nOutside
-    );
+    const plane p0(tetB[1], tetB[3], tetB[2]);
+    tetsIn1.clear();
+    tetCut(tetA, p0, tetOpIn1, tetOpOut);
 
+    const plane p1(tetB[0], tetB[2], tetB[3]);
+    tetsIn2.clear();
+    forAll(tetsIn1, i)
+    {
+        tetCut(tetsIn1[i], p1, tetOpIn2, tetOpOut);
+    }
 
-    // Dump to file
-    // ~~~~~~~~~~~~
+    const plane p2(tetB[0], tetB[3], tetB[1]);
+    tetsIn1.clear();
+    forAll(tetsIn2, i)
+    {
+        tetCut(tetsIn2[i], p2, tetOpIn1, tetOpOut);
+    }
 
+    const plane p3(tetB[0], tetB[1], tetB[2]);
+    tetsIn2.clear();
+    forAll(tetsIn1, i)
     {
-        OFstream str("tetA.obj");
+        tetCut(tetsIn1[i], p3, tetOpIn2, tetOpOut);
+    }
+
+    const tetList& tetsIn = tetsIn2;
+
+
+    // Dump to file
+    {
+        OFstream str("A.obj");
         Info<< "Writing A to " << str.name() << endl;
         label vertI = 0;
-        writeOBJ(str, vertI, A);
+        writeOBJ(str, vertI, tetA);
     }
     {
-        OFstream str("tetB.obj");
+        OFstream str("B.obj");
         Info<< "Writing B to " << str.name() << endl;
         label vertI = 0;
-        writeOBJ(str, vertI, B);
+        writeOBJ(str, vertI, tetB);
     }
     {
-        OFstream str("inside.obj");
-        Info<< "Writing parts of A inside B to " << str.name() << endl;
+        OFstream str("AInB.obj");
+        Info<< "Writing parts of B inside A to " << str.name() << endl;
         label vertI = 0;
-        for (label i = 0; i < nInside; ++i)
+        forAll(tetsIn, i)
         {
-            writeOBJ(str, vertI, insideTets[i]);
+            writeOBJ(str, vertI, tetsIn[i]);
         }
     }
     {
-        OFstream str("outside.obj");
-        Info<< "Writing parts of A outside B to " << str.name() << endl;
+        OFstream str("AOutB.obj");
+        Info<< "Writing parts of B inside A to " << str.name() << endl;
         label vertI = 0;
-        for (label i = 0; i < nOutside; ++i)
+        forAll(tetsOut, i)
         {
-            writeOBJ(str, vertI, outsideTets[i]);
+            writeOBJ(str, vertI, tetsOut[i]);
         }
     }
 
 
-    // Check
-    // ~~~~~
+    // Check the volumes
+    Info<< "Vol A: " << makeTetPointRef(tetA).mag() << endl;
 
-    Info<< "Vol A:" << tetA.mag() << endl;
-
-    scalar volInside = 0;
-    for (label i = 0; i < nInside; ++i)
+    scalar volIn = 0;
+    forAll(tetsIn, i)
     {
-        volInside += insideTets[i].tet().mag();
+        volIn += makeTetPointRef(tetsIn[i]).mag();
     }
-    Info<< "Vol A inside B:" << volInside << endl;
+    Info<< "Vol A inside B: " << volIn << endl;
 
-    scalar volOutside = 0;
-    for (label i = 0; i < nOutside; ++i)
+    scalar volOut = 0;
+    forAll(tetsOut, i)
     {
-        volOutside += outsideTets[i].tet().mag();
+        volOut += makeTetPointRef(tetsOut[i]).mag();
     }
-    Info<< "Vol A outside B:" << volOutside << endl;
+    Info<< "Vol A outside B: " << volOut << endl;
 
-    Info<< "Sum inside and outside:" << volInside+volOutside << endl;
+    Info<< "Sum inside and outside: " << volIn + volOut << endl;
 
-    if (mag(volInside+volOutside-tetA.mag()) > SMALL)
+    if (mag(volIn + volOut - makeTetPointRef(tetA).mag()) > SMALL)
     {
         FatalErrorInFunction
             << "Tet volumes do not sum up to input tet."
             << exit(FatalError);
     }
 
+
     return 0;
 }
 
diff --git a/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.C b/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.C
index a36e0370cfb0d12b097b941af3598c6cac477298..1ab57746900c2ac4fb79a2148e32d22e7cacf88d 100644
--- a/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.C
+++ b/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2012-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2012-2017 OpenFOAM Foundation
      \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
@@ -28,7 +28,7 @@ License
 #include "pointIOField.H"
 #include "scalarIOField.H"
 #include "triadIOField.H"
-#include "tetrahedron.H"
+#include "tetPointRef.H"
 #include "plane.H"
 #include "transform.H"
 #include "meshTools.H"
diff --git a/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/fileControl/fileControl.C b/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/fileControl/fileControl.C
index a644134066fe54f1f7ab9c3aa9083ac4a37e715d..8f8aac17e988dc52095754762bbe7b6edcc99b31 100644
--- a/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/fileControl/fileControl.C
+++ b/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/fileControl/fileControl.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2012-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2012-2017 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -25,7 +25,7 @@ License
 
 #include "fileControl.H"
 #include "addToRunTimeSelectionTable.H"
-#include "tetrahedron.H"
+#include "tetPointRef.H"
 #include "scalarList.H"
 #include "vectorTools.H"
 #include "pointIOField.H"
diff --git a/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/searchableSurfaceControl/searchableSurfaceControl.C b/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/searchableSurfaceControl/searchableSurfaceControl.C
index ef565a405f0b33a422d0b3b7acf384114e5d43f7..c0782e3a3c712e2d7e5c906a670a8ace0fef4fdc 100644
--- a/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/searchableSurfaceControl/searchableSurfaceControl.C
+++ b/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/searchableSurfaceControl/searchableSurfaceControl.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2012-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2012-2017 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -28,7 +28,7 @@ License
 #include "cellSizeFunction.H"
 #include "triSurfaceMesh.H"
 #include "searchableBox.H"
-#include "tetrahedron.H"
+#include "tetPointRef.H"
 #include "vectorTools.H"
 #include "quaternion.H"
 
diff --git a/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellChecks.C b/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellChecks.C
index 49f6796781d235b8690a6a41819850e32a65cf06..570ad3e1845e0a15db87522c2adbfcc9e10b9e2c 100644
--- a/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellChecks.C
+++ b/applications/utilities/mesh/generation/foamyMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellChecks.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2012-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2012-2017 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -24,7 +24,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "plane.H"
-#include "tetrahedron.H"
+#include "tetPointRef.H"
 #include "pointConversion.H"
 #include "CGALTriangulation3DKernel.H"
 
diff --git a/src/OpenFOAM/meshes/meshShapes/tetCell/tetCell.H b/src/OpenFOAM/meshes/meshShapes/tetCell/tetCell.H
index 18f1459f4e8565cb745b6fdd0c0bf51dc36f62fe..8669efbc3c3e8b285d54fa214e86cf28ec9193e4 100644
--- a/src/OpenFOAM/meshes/meshShapes/tetCell/tetCell.H
+++ b/src/OpenFOAM/meshes/meshShapes/tetCell/tetCell.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -43,7 +43,7 @@ SourceFiles
 #include "triFace.H"
 #include "edge.H"
 #include "pointField.H"
-#include "tetrahedron.H"
+#include "tetPointRef.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
diff --git a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.H b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.H
index 0a3ed7a03b8624dbf3504abaf028d71559ff6c8d..18de73777c620b5bf63554d28e8539389ae48966 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.H
+++ b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -42,7 +42,7 @@ SourceFiles
 #include "polyMesh.H"
 #include "coupledPolyPatch.H"
 #include "syncTools.H"
-#include "tetrahedron.H"
+#include "tetPointRef.H"
 #include "tetIndices.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/tetIndices.H b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/tetIndices.H
index 0c80210e636e62b6a25ee1335ea2efc7ae411d2f..8ad320403a8b22b00ed14a381a1c8ebc9d77b8a5 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/tetIndices.H
+++ b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/tetIndices.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -56,7 +56,7 @@ SourceFiles
 #define tetIndices_H
 
 #include "label.H"
-#include "tetrahedron.H"
+#include "tetPointRef.H"
 #include "triPointRef.H"
 #include "polyMesh.H"
 #include "triFace.H"
diff --git a/src/OpenFOAM/meshes/primitiveShapes/cut/cut.H b/src/OpenFOAM/meshes/primitiveShapes/cut/cut.H
new file mode 100644
index 0000000000000000000000000000000000000000..9e821c0c536050045c73445f6371e7416c92fa3e
--- /dev/null
+++ b/src/OpenFOAM/meshes/primitiveShapes/cut/cut.H
@@ -0,0 +1,539 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Description:
+    Functions which cut triangles and tetrahedra. Generic operations are
+    applied to each half of a cut.
+
+SourceFiles:
+    cutI.H
+    cutTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef cut_H
+#define cut_H
+
+#include "FixedList.H"
+#include "nil.H"
+#include "plane.H"
+#include "tetPointRef.H"
+#include "triPointRef.H"
+#include "zero.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace cut
+{
+
+/*---------------------------------------------------------------------------*\
+                          Class uniformOp Declaration
+\*---------------------------------------------------------------------------*/
+
+template<class Type>
+class uniformOp
+{
+private:
+
+    //- Data
+    Type data_;
+
+
+public:
+
+    // Constructors
+
+        //- Construct null
+        uniformOp()
+        {}
+
+        //- Construct from data
+        uniformOp(Type data)
+        :
+            data_(data)
+        {}
+
+
+    // Member functions
+
+        //- Access the data
+        Type data() const
+        {
+            return data_;
+        }
+};
+
+
+/*---------------------------------------------------------------------------*\
+                             Class noOp Declaration
+\*---------------------------------------------------------------------------*/
+
+class noOp
+:
+    public uniformOp<nil>
+{
+public:
+
+    // Typedefs
+
+        //- Result type
+        typedef zero result;
+
+
+    // Constructors
+
+        //- Construct null
+        noOp()
+        {}
+
+        //- Construct from base
+        noOp(const uniformOp<nil>& op)
+        :
+            uniformOp<nil>(op)
+        {}
+
+
+    // Member operators
+
+        //- Operate on nothing
+        result operator()() const
+        {
+            return result();
+        }
+
+        //- Operate on a triangle or tetrahedron
+        template<unsigned Size>
+        result operator()(const FixedList<point, Size>& p) const
+        {
+            return result();
+        }
+};
+
+
+/*---------------------------------------------------------------------------*\
+                            Class areaOp Declaration
+\*---------------------------------------------------------------------------*/
+
+class areaOp
+:
+    public uniformOp<nil>
+{
+public:
+
+    // Typedefs
+
+        //- Result type
+        typedef vector result;
+
+
+    // Constructors
+
+        //- Construct null
+        areaOp()
+        {}
+
+        //- Construct from base
+        areaOp(const uniformOp<nil>& op)
+        :
+            uniformOp<nil>(op)
+        {}
+
+
+    // Member operators
+
+        //- Operate on nothing
+        result operator()() const
+        {
+            return vector::zero;
+        }
+
+        //- Operate on a triangle
+        result operator()(const FixedList<point, 3>& p) const
+        {
+            return result(triPointRef(p[0], p[1], p[2]).normal());
+        }
+};
+
+
+/*---------------------------------------------------------------------------*\
+                           Class volumeOp Declaration
+\*---------------------------------------------------------------------------*/
+
+class volumeOp
+:
+    public uniformOp<nil>
+{
+public:
+
+    // Typedefs
+
+        //- Result type
+        typedef scalar result;
+
+
+    // Constructors
+
+        //- Construct null
+        volumeOp()
+        {}
+
+        //- Construct from base
+        volumeOp(const uniformOp<nil>& op)
+        :
+            uniformOp<nil>(op)
+        {}
+
+
+    // Member operators
+
+        //- Operate on nothing
+        result operator()() const
+        {
+            return 0;
+        }
+
+        //- Operate on a tetrahedron
+        result operator()(const FixedList<point, 4>& p) const
+        {
+            return result(tetPointRef(p[0], p[1], p[2], p[3]).mag());
+        }
+};
+
+
+/*---------------------------------------------------------------------------*\
+                       Class areaIntegrateOp Declaration
+\*---------------------------------------------------------------------------*/
+
+template<class Type>
+class areaIntegrateOp
+:
+    public FixedList<Type, 3>
+{
+public:
+
+    // Typedefs
+
+        //- Result type
+        typedef typename outerProduct<Type, vector>::type result;
+
+
+    // Constructors
+
+        //- Construct from base
+        areaIntegrateOp(const FixedList<Type, 3>& x)
+        :
+            FixedList<Type, 3>(x)
+        {}
+
+
+    // Member operators
+
+        //- Operate on nothing
+        result operator()() const
+        {
+            return pTraits<result>::zero;
+        }
+
+        //- Operate on a triangle
+        result operator()(const FixedList<point, 3>& p) const
+        {
+            const FixedList<Type, 3>& x = *this;
+            return result(areaOp()(p)*(x[0] + x[1] + x[2])/3);
+        }
+};
+
+
+/*---------------------------------------------------------------------------*\
+                      Class volumeIntegrateOp Declaration
+\*---------------------------------------------------------------------------*/
+
+template<class Type>
+class volumeIntegrateOp
+:
+    public FixedList<Type, 4>
+{
+public:
+
+    // Typedefs
+
+        //- Result type
+        typedef Type result;
+
+
+    // Constructors
+
+        //- Construct from base
+        volumeIntegrateOp(const FixedList<Type, 4>& x)
+        :
+            FixedList<Type, 4>(x)
+        {}
+
+
+    // Member operators
+
+        //- Operate on nothing
+        result operator()() const
+        {
+            return pTraits<result>::zero;
+        }
+
+        //- Operate on a tetrahedron
+        result operator()(const FixedList<point, 4>& p) const
+        {
+            const FixedList<Type, 4>& x = *this;
+            return result(volumeOp()(p)*(x[0] + x[1] + x[2] + x[3])/4);
+        }
+};
+
+
+/*---------------------------------------------------------------------------*\
+                            Class listOp Declaration
+\*---------------------------------------------------------------------------*/
+
+template<unsigned Size>
+class listOp
+:
+    public uniformOp<nil>
+{
+public:
+
+    // Classes
+
+        //- Result class
+        class result
+        :
+            public DynamicList<FixedList<point, Size>>
+        {
+        public:
+
+            // Constructors
+
+                //- Construct from a single element
+                result(const FixedList<point, Size>& x)
+                :
+                    DynamicList<FixedList<point, Size>>(1, x)
+                {}
+
+
+            // Member operators
+
+                //- Add together two lists
+                result operator+(const result& x) const
+                {
+                    result r(*this);
+                    r.append(x);
+                    return r;
+                }
+        };
+
+
+    // Constructors
+
+        //- Construct null
+        listOp()
+        {}
+
+        //- Construct from base
+        listOp(const uniformOp<nil>& op)
+        :
+            uniformOp<nil>(op)
+        {}
+
+
+    // Member operators
+
+        //- Operate on nothing
+        result operator()() const
+        {
+            return result();
+        }
+
+        //- Operate on a triangle or tetrahedron
+        result operator()(const FixedList<point, Size>& p) const
+        {
+            return result(p);
+        }
+};
+
+
+typedef listOp<3> listTriOp;
+
+
+typedef listOp<4> listTetOp;
+
+
+/*---------------------------------------------------------------------------*\
+                          Class appendOp Declaration
+\*---------------------------------------------------------------------------*/
+
+template<class Container>
+class appendOp
+:
+    public uniformOp<Container&>
+{
+public:
+
+    // Typedefs
+
+        //- Result type
+        typedef zero result;
+
+
+    // Constructors
+
+        //- Construct from a container reference
+        appendOp(Container& x)
+        :
+            uniformOp<Container&>(x)
+        {}
+
+        //- Construct from base
+        appendOp(const uniformOp<Container&>& op)
+        :
+            uniformOp<Container&>(op)
+        {}
+
+
+    // Member operators
+
+        //- Operate on nothing
+        result operator()() const
+        {
+            return result();
+        }
+
+        //- Operate on a triangle or tetrahedron
+        template<unsigned Size>
+        result operator()(const FixedList<point, Size>& p) const
+        {
+            this->data().append(p);
+            return result();
+        }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+//- Trait to determine the result of the addition of two operations
+template<class AheadOp, class BehindOp>
+class opAddResult;
+
+template<class Op>
+class opAddResult<Op, Op>
+{
+public:
+
+    typedef typename Op::result type;
+};
+
+template<>
+class opAddResult<noOp, noOp>
+{
+public:
+
+    typedef typename noOp::result type;
+};
+
+template<class Op>
+class opAddResult<noOp, Op>
+{
+public:
+
+    typedef typename Op::result type;
+};
+
+template<class Op>
+class opAddResult<Op, noOp>
+{
+public:
+
+    typedef typename Op::result type;
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace cut
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+//- Cut a triangle along the zero plane defined by the given levels. Templated
+//  on aboveOp and belowOp; the operations applied to the regions on either side
+//  of the cut.
+template<class AboveOp, class BelowOp>
+typename cut::opAddResult<AboveOp, BelowOp>::type triCut
+(
+    const FixedList<point, 3>& tri,
+    const FixedList<scalar, 3>& level,
+    const AboveOp& aboveOp,
+    const BelowOp& belowOp
+);
+
+//- As above, but with a plane specifying the location of the cut
+template<class AboveOp, class BelowOp>
+typename cut::opAddResult<AboveOp, BelowOp>::type triCut
+(
+    const FixedList<point, 3>& tri,
+    const plane& s,
+    const AboveOp& aboveOp,
+    const BelowOp& belowOp
+);
+
+//- As triCut, but for a tetrahedron.
+template<class AboveOp, class BelowOp>
+typename cut::opAddResult<AboveOp, BelowOp>::type tetCut
+(
+    const FixedList<point, 4>& tet,
+    const FixedList<scalar, 4>& level,
+    const AboveOp& aboveOp,
+    const BelowOp& belowOp
+);
+
+//- As above, but with a plane specifying the location of the cut
+template<class AboveOp, class BelowOp>
+typename cut::opAddResult<AboveOp, BelowOp>::type tetCut
+(
+    const FixedList<point, 4>& tet,
+    const plane& s,
+    const AboveOp& aboveOp,
+    const BelowOp& belowOp
+);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "cutI.H"
+
+#ifdef NoRepository
+    #include "cutTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/primitiveShapes/cut/cutI.H b/src/OpenFOAM/meshes/primitiveShapes/cut/cutI.H
new file mode 100644
index 0000000000000000000000000000000000000000..aefc537f519929d3230f95d97ce9ad3b8aeecb51
--- /dev/null
+++ b/src/OpenFOAM/meshes/primitiveShapes/cut/cutI.H
@@ -0,0 +1,400 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "cut.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+//- Modify a uniform operation for reordering a tri (does nothing)
+template<class Type>
+inline const cut::uniformOp<Type>& triReorder
+(
+    const cut::uniformOp<Type>& x,
+    const FixedList<label, 3>&
+)
+{
+    return x;
+}
+
+
+//- Modify a uniform operation for cutting a tri from a tri (does nothing)
+template<class Type>
+inline const cut::uniformOp<Type>& triCutTri
+(
+    const cut::uniformOp<Type>& x,
+    const Pair<scalar>&
+)
+{
+    return x;
+}
+
+
+//- Modify a uniform operation for cutting a quad from a tri (does nothing)
+template<class Type>
+inline const cut::uniformOp<Type>& triCutQuad
+(
+    const cut::uniformOp<Type>& x,
+    const Pair<scalar>&
+)
+{
+    return x;
+}
+
+
+//- Modify a uniform operation for reordering a tet (does nothing)
+template<class Type>
+inline const cut::uniformOp<Type>& tetReorder
+(
+    const cut::uniformOp<Type>& x,
+    const FixedList<label, 4>&
+)
+{
+    return x;
+}
+
+
+//- Modify a uniform operation for cutting a tet from a tet (does nothing)
+template<class Type>
+inline const cut::uniformOp<Type>& tetCutTet
+(
+    const cut::uniformOp<Type>& x,
+    const FixedList<scalar, 3>&
+)
+{
+    return x;
+}
+
+
+//- Modify a uniform operation for cutting prism0 from a tet (does nothing)
+template<class Type>
+inline const cut::uniformOp<Type>& tetCutPrism0
+(
+    const cut::uniformOp<Type>& x,
+    const FixedList<scalar, 3>&
+)
+{
+    return x;
+}
+
+
+//- Modify a uniform operation for cutting prism01 from a tet (does nothing)
+template<class Type>
+inline const cut::uniformOp<Type>& tetCutPrism01
+(
+    const cut::uniformOp<Type>& x,
+    const FixedList<scalar, 4>&
+)
+{
+    return x;
+}
+
+
+//- Modify a uniform operation for cutting prism23 from a tet (does nothing)
+template<class Type>
+inline const cut::uniformOp<Type>& tetCutPrism23
+(
+    const cut::uniformOp<Type>& x,
+    const FixedList<scalar, 4>&
+)
+{
+    return x;
+}
+
+
+//- Modify a fixed list for reordering a tri (does nothing)
+template<class Type, unsigned Size>
+inline FixedList<Type, 3> triReorder
+(
+    const FixedList<Type, Size>& x,
+    const FixedList<label, 3>& indices
+)
+{
+    FixedList<Type, 3> result;
+    for (unsigned i = 0; i < 3; ++ i)
+    {
+        result[i] = x[indices[i]];
+    }
+    return result;
+}
+
+
+//- Modify a list for cutting a tri from a tri
+template<class Type>
+inline FixedList<Type, 3> triCutTri
+(
+    const FixedList<Type, 3>& x,
+    const Pair<scalar>& f
+)
+{
+    FixedList<Type, 3> result;
+    result[0] = x[0];
+    for (label i = 0; i < 2; ++ i)
+    {
+        result[i+1] = x[0] + f[i]*(x[i+1] - x[0]);
+    }
+    return result;
+}
+
+
+//- Modify a list for cutting a quad from a tri
+template<class Type>
+inline FixedList<Type, 4> triCutQuad
+(
+    const FixedList<Type, 3>& x,
+    const Pair<scalar>& f
+)
+{
+    FixedList<Type, 4> result;
+    for (label i = 0; i < 2; ++ i)
+    {
+        result[i] = x[i+1];
+        result[3-i] = x[0] + f[i]*(x[i+1] - x[0]);
+    }
+    return result;
+}
+
+
+//- Modify a fixed list for reordering a tet (does nothing)
+template<class Type, unsigned Size>
+inline FixedList<Type, 4> tetReorder
+(
+    const FixedList<Type, Size>& x,
+    const FixedList<label, 4>& indices
+)
+{
+    FixedList<Type, 4> result;
+    for (unsigned i = 0; i < 4; ++ i)
+    {
+        result[i] = x[indices[i]];
+    }
+    return result;
+}
+
+
+//- Modify a list for cutting a tet from a tet
+template<class Type>
+inline FixedList<Type, 4> tetCutTet
+(
+    const FixedList<Type, 4>& x,
+    const FixedList<scalar, 3>& f
+)
+{
+    FixedList<Type, 4> result;
+    result[0] = x[0];
+    for (label i = 0; i < 3; ++ i)
+    {
+        result[i+1] = x[0] + f[i]*(x[i+1] - x[0]);
+    }
+    return result;
+}
+
+
+//- Modify a list for cutting prism0 from a tet
+template<class Type>
+inline FixedList<Type, 6> tetCutPrism0
+(
+    const FixedList<Type, 4>& x,
+    const FixedList<scalar, 3>& f
+)
+{
+    FixedList<Type, 6> result;
+    for (label i = 0; i < 3; ++ i)
+    {
+        result[i] = x[0] + f[i]*(x[i+1] - x[0]);
+        result[i+3] = x[i+1];
+    }
+    return result;
+}
+
+
+//- Modify a list for cutting prism01 from a tet
+template<class Type>
+inline FixedList<Type, 6> tetCutPrism01
+(
+    const FixedList<Type, 4>& x,
+    const FixedList<scalar, 4>& f
+)
+{
+    FixedList<Type, 6> result;
+    for (label i = 0; i < 2; ++ i)
+    {
+        result[3*i] = x[i];
+        for (label j = 0; j < 2; ++ j)
+        {
+            result[3*i+j+1] = x[i] + f[2*i+j]*(x[j+2] - x[i]);
+        }
+    }
+
+    return result;
+}
+
+
+//- Modify a list for cutting prism23 from a tet
+template<class Type>
+inline FixedList<Type, 6> tetCutPrism23
+(
+    const FixedList<Type, 4>& x,
+    const FixedList<scalar, 4>& f
+)
+{
+    FixedList<Type, 6> result = tetCutPrism01(x, f);
+    result[0] = x[2];
+    result[3] = x[3];
+    Swap(result[2], result[4]);
+    return result;
+}
+
+
+//- Cut a tri from a tri and apply an operation to the result. The cut is made
+//  along the two edges connected to vertex 0, and the cut locations are given
+//  as factors along these edges. The result is the side connected to vertex 0.
+template<class Op>
+inline typename Op::result triCutTri
+(
+    const Op& op,
+    const FixedList<point, 3>& p,
+    const Pair<scalar>& f
+)
+{
+    return Op(triCutTri(op, f))(triCutTri(p, f));
+}
+
+
+//- Apply an operation to a quad. Splits the quad into two tris.
+template<class Op, class OpData>
+inline typename Op::result quadOp
+(
+    const OpData& opData,
+    const FixedList<point, 4>& p
+)
+{
+    static const FixedList<FixedList<label, 3>, 2> i =
+        {{0, 1, 2}, {0, 2, 3}};
+    return
+        Op(triReorder(opData, i[0]))(triReorder(p, i[0]))
+      + Op(triReorder(opData, i[1]))(triReorder(p, i[1]));
+}
+
+
+//- Cut a quad from a tri and apply an operation to the result. The cuts are
+//  the same as for triCutTri. The result is the side connected to vertices 1
+//  and 2.
+template<class Op>
+inline typename Op::result triCutQuad
+(
+    const Op& op,
+    const FixedList<point, 3>& p,
+    const FixedList<scalar, 2>& f
+)
+{
+    return quadOp<Op>(triCutQuad(op, f), triCutQuad(p, f));
+}
+
+
+//- Cut a tet from a tet and apply an operation to the result. The cut is made
+//  along the three edges connected to vertex 0, and the cut locations are given
+//  as factors along these edges. The result is the side connected to vertex 0.
+template<class Op>
+inline typename Op::result tetCutTet
+(
+    const Op& op,
+    const FixedList<point, 4>& p,
+    const FixedList<scalar, 3>& f
+)
+{
+    return Op(tetCutTet(op, f))(tetCutTet(p, f));
+}
+
+
+//- Apply an operation to a prism. Splits the prism into three tets.
+template<class Op, class OpData>
+inline typename Op::result prismOp
+(
+    const OpData& opData,
+    const FixedList<point, 6>& p
+)
+{
+    static const FixedList<FixedList<label, 4>, 3> i =
+        {{0, 1, 2, 4}, {0, 2, 5, 4}, {0, 4, 5, 3}};
+    return
+        Op(tetReorder(opData, i[0]))(tetReorder(p, i[0]))
+      + Op(tetReorder(opData, i[1]))(tetReorder(p, i[1]))
+      + Op(tetReorder(opData, i[2]))(tetReorder(p, i[2]));
+}
+
+
+//- Cut a prism from a tet and apply an operation to the result. The cuts are
+//  the same as for tetCutTet. The result is the side connected to vertices 1,
+//  2 and 3.
+template<class Op>
+inline typename Op::result tetCutPrism0
+(
+    const Op& op,
+    const FixedList<point, 4>& p,
+    const FixedList<scalar, 3>& f
+)
+{
+    return prismOp<Op>(tetCutPrism0(op, f), tetCutPrism0(p, f));
+}
+
+
+//- Cut a prism from a tet and apply an operation to the result. The cut is made
+//  along four edges, not edges 01 or 23, and the cut locations are given as
+//  factors along these edges. The result is the side connected to edge 01.
+template<class Op>
+inline typename Op::result tetCutPrism01
+(
+    const Op& op,
+    const FixedList<point, 4>& p,
+    const FixedList<scalar, 4>& f
+)
+{
+    return prismOp<Op>(tetCutPrism01(op, f), tetCutPrism01(p, f));
+}
+
+
+//- Cut a prism from a tet and apply an operation to the result. The cuts are
+//  the same as for tetCutPrism01. The result is the side connected to edge 23.
+template<class Op>
+inline typename Op::result tetCutPrism23
+(
+    const Op& op,
+    const FixedList<point, 4>& p,
+    const FixedList<scalar, 4>& f
+)
+{
+    return prismOp<Op>(tetCutPrism23(op, f), tetCutPrism23(p, f));
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/primitiveShapes/cut/cutTemplates.C b/src/OpenFOAM/meshes/primitiveShapes/cut/cutTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..b4dda7f4c04be47af17a1cfa824e058c940d0bf2
--- /dev/null
+++ b/src/OpenFOAM/meshes/primitiveShapes/cut/cutTemplates.C
@@ -0,0 +1,263 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "cut.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class AboveOp, class BelowOp>
+typename Foam::cut::opAddResult<AboveOp, BelowOp>::type Foam::triCut
+(
+    const FixedList<point, 3>& tri,
+    const FixedList<scalar, 3>& level,
+    const AboveOp& aboveOp,
+    const BelowOp& belowOp
+)
+{
+    // If everything is positive or negative, then process the triangle as a
+    // whole, and do a quick return
+    if (level[0] >= 0 && level[1] >= 0 && level[2] >= 0)
+    {
+        return aboveOp(tri) + belowOp();
+    }
+    if (level[0] <= 0 && level[1] <= 0 && level[2] <= 0)
+    {
+        return aboveOp() + belowOp(tri);
+    }
+
+    // There will be just one edge without a sign change. Find it, and put it
+    // opposite the first vertex. This may change the sign of the tri.
+    FixedList<label, 3> indices({0, 1, 2});
+    label i;
+    for (i = 0; i < 3; ++ i)
+    {
+        if (level[(i + 1)%3]*level[(i + 2)%3] >= 0)
+        {
+            Swap(indices[0], indices[i]);
+            break;
+        }
+    }
+    if (i == 3)
+    {
+        FatalErrorInFunction
+            << "The number of tri vertices above the level set should always "
+            << "be 1" << exit(FatalError);
+    }
+
+    // Correct the sign
+    if (indices[0] != 0)
+    {
+        Swap(indices[1], indices[2]);
+    }
+
+    // Permute the data
+    const FixedList<point, 3> p = triReorder(tri, indices);
+    const FixedList<scalar, 3> l = triReorder(level, indices);
+    AboveOp a = triReorder(aboveOp, indices);
+    BelowOp b = triReorder(belowOp, indices);
+
+    // Slice off one corner to form a tri and a quad
+    Pair<scalar> f;
+    for (label i = 0; i < 2; ++ i)
+    {
+        f[i] = l[0]/(l[0] - l[i+1]);
+    }
+    if (l[0] > 0)
+    {
+        return triCutTri(a, p, f) + triCutQuad(b, p, f);
+    }
+    else
+    {
+        return triCutQuad(a, p, f) + triCutTri(b, p, f);
+    }
+}
+
+
+template<class AboveOp, class BelowOp>
+typename Foam::cut::opAddResult<AboveOp, BelowOp>::type Foam::triCut
+(
+    const FixedList<point, 3>& tri,
+    const plane& p,
+    const AboveOp& aboveOp,
+    const BelowOp& belowOp
+)
+{
+    // Set the level set to the signed distance from the plane
+    FixedList<scalar, 3> level;
+    for (label i = 0; i < 3; ++ i)
+    {
+        level[i] = (tri[i] - p.refPoint()) & p.normal();
+    }
+
+    // Run the level set function
+    return triCut(tri, level, aboveOp, belowOp);
+}
+
+
+template<class AboveOp, class BelowOp>
+typename Foam::cut::opAddResult<AboveOp, BelowOp>::type Foam::tetCut
+(
+    const FixedList<point, 4>& tet,
+    const FixedList<scalar, 4>& level,
+    const AboveOp& aboveOp,
+    const BelowOp& belowOp
+)
+{
+    // Get the min and max over all four vertices and quick return if there is
+    // no change of sign
+    scalar levelMin = VGREAT, levelMax = - VGREAT;
+    for (label i = 0; i < 4; ++ i)
+    {
+        levelMin = min(levelMin, level[i]);
+        levelMax = max(levelMax, level[i]);
+    }
+    if (levelMin >= 0)
+    {
+        return aboveOp(tet) + belowOp();
+    }
+    if (levelMax <= 0)
+    {
+        return aboveOp() + belowOp(tet);
+    }
+
+    // Partition the level so that positive values are at the start. This is
+    // like a single iteration of quick-sort, except that the pivot is a hard-
+    // coded zero, rather than an element of the array. This can change the sign
+    // of the tet.
+    FixedList<label, 4> indices({0, 1, 2, 3});
+    bool signChange = false;
+    label i = 0, j = 3;
+    while (true)
+    {
+        while (i < j && level[indices[i]] > 0)
+        {
+            i ++;
+        }
+        while (j > i && level[indices[j]] <= 0)
+        {
+            j --;
+        }
+        if (i == j)
+        {
+            break;
+        }
+        Swap(indices[i], indices[j]);
+        signChange = !signChange;
+    }
+
+    // The number of vertices above the slice
+    label n = i;
+
+    // If there are more positives than negatives then reverse the order so that
+    // the negatives are at the start
+    if (n > 2)
+    {
+        n = 4 - n;
+        for (label i = 0; i < 2; ++ i)
+        {
+            Swap(indices[i], indices[3-i]);
+        }
+    }
+
+    // Correct the sign
+    if (signChange)
+    {
+        Swap(indices[2], indices[3]);
+    }
+
+    // Permute the data
+    const FixedList<point, 4> p = tetReorder(tet, indices);
+    const FixedList<scalar, 4> l = tetReorder(level, indices);
+    AboveOp a = tetReorder(aboveOp, indices);
+    BelowOp b = tetReorder(belowOp, indices);
+
+    // Calculate the integrals above and below the level set
+    if (n == 1)
+    {
+        // Slice off one corner to form a tet and a prism
+        FixedList<scalar, 3> f;
+        for (label i = 0; i < 3; ++ i)
+        {
+            f[i] = l[0]/(l[0] - l[i+1]);
+        }
+        if (l[0] > 0)
+        {
+            return tetCutTet(a, p, f) + tetCutPrism0(b, p, f);
+        }
+        else
+        {
+            return tetCutPrism0(a, p, f) + tetCutTet(b, p, f);
+        }
+    }
+    else if (n == 2)
+    {
+        // Slice off two corners to form two prisms
+        FixedList<scalar, 4> f;
+        for (label i = 0; i < 2; ++ i)
+        {
+            for (label j = 0; j < 2; ++ j)
+            {
+                f[2*i+j] = l[i]/(l[i] - l[j+2]);
+            }
+        }
+        if (l[0] > 0)
+        {
+            return tetCutPrism01(a, p, f) + tetCutPrism23(b, p, f);
+        }
+        else
+        {
+            return tetCutPrism23(a, p, f) + tetCutPrism01(b, p, f);
+        }
+    }
+
+    FatalErrorInFunction
+        << "The number of tet vertices above the level set should always be "
+        << "either 1 or 2" << exit(FatalError);
+
+    return aboveOp() + belowOp();
+}
+
+
+template<class AboveOp, class BelowOp>
+typename Foam::cut::opAddResult<AboveOp, BelowOp>::type Foam::tetCut
+(
+    const FixedList<point, 4>& tet,
+    const plane& p,
+    const AboveOp& aboveOp,
+    const BelowOp& belowOp
+)
+{
+    // Set the level set to the signed distance from the plane
+    FixedList<scalar, 4> level;
+    for (label i = 0; i < 4; ++ i)
+    {
+        level[i] = (tet[i] - p.refPoint()) & p.normal();
+    }
+
+    // Run the level set function
+    return tetCut(tet, level, aboveOp, belowOp);
+}
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetPointRef.H b/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetPointRef.H
new file mode 100644
index 0000000000000000000000000000000000000000..8854eb46fb69bd3e2a3224d499c7f853dae048cb
--- /dev/null
+++ b/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetPointRef.H
@@ -0,0 +1,52 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Typedef
+    Foam::tetPointRef
+
+Description
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef tetPointRef_H
+#define tetPointRef_H
+
+#include "point.H"
+#include "tetrahedron.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+typedef tetrahedron<point, const point&> tetPointRef;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetPoints.H b/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetPoints.H
deleted file mode 100644
index 8ac906ca62072f5bf373f52d124dad126a75a3cf..0000000000000000000000000000000000000000
--- a/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetPoints.H
+++ /dev/null
@@ -1,113 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-Class
-    Foam::tetPoints
-
-Description
-    Tet storage. Null constructable (unfortunately tetrahedron<point, point>
-    is not)
-
-SourceFiles
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef tetPoints_H
-#define tetPoints_H
-
-#include "tetrahedron.H"
-#include "FixedList.H"
-#include "treeBoundBox.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-/*---------------------------------------------------------------------------*\
-                         Class tetPoints Declaration
-\*---------------------------------------------------------------------------*/
-
-class tetPoints
-:
-    public FixedList<point, 4>
-{
-public:
-
-    // Constructors
-
-        //- Construct null
-        inline tetPoints()
-        {}
-
-        //- Construct from four points
-        inline tetPoints
-        (
-            const point& a,
-            const point& b,
-            const point& c,
-            const point& d
-        )
-        {
-            operator[](0) = a;
-            operator[](1) = b;
-            operator[](2) = c;
-            operator[](3) = d;
-        }
-
-    // Member Functions
-
-        //- Return the tetrahedron
-        inline tetPointRef tet() const
-        {
-            return tetPointRef
-            (
-                operator[](0),
-                operator[](1),
-                operator[](2),
-                operator[](3)
-            );
-        }
-
-        //- Calculate the bounding box
-        inline treeBoundBox bounds() const
-        {
-            treeBoundBox bb(operator[](0));
-            for (label i = 1; i < size(); ++i)
-            {
-                bb.add(operator[](i));
-            }
-            return bb;
-        }
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetrahedron.C b/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetrahedron.C
index 163476a6b32e5166bca73e7e1402e17d9240d99a..45b10041f32c7f297d443ca83f4027111b7b75d5 100644
--- a/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetrahedron.C
+++ b/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetrahedron.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -29,96 +29,6 @@ License
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-template<class Point, class PointRef>
-void Foam::tetrahedron<Point, PointRef>::tetOverlap
-(
-    const tetrahedron<Point, PointRef>& tetB,
-    tetIntersectionList& insideTets,
-    label& nInside,
-    tetIntersectionList& outsideTets,
-    label& nOutside
-) const
-{
-    // Work storage
-    tetIntersectionList cutInsideTets;
-    label nCutInside = 0;
-
-    nInside = 0;
-    storeOp inside(insideTets, nInside);
-    storeOp cutInside(cutInsideTets, nCutInside);
-
-    nOutside = 0;
-    storeOp outside(outsideTets, nOutside);
-
-
-    // Cut tetA with all inwards pointing faces of tetB. Any tets remaining
-    // in aboveTets are inside tetB.
-
-    {
-        // face0
-        plane pl0(tetB.b_, tetB.d_, tetB.c_);
-
-        // Cut and insert subtets into cutInsideTets (either by getting
-        // an index from freeSlots or by appending to insideTets) or
-        // insert into outsideTets
-        sliceWithPlane(pl0, cutInside, outside);
-    }
-
-    if (nCutInside == 0)
-    {
-        nInside = nCutInside;
-        return;
-    }
-
-    {
-        // face1
-        plane pl1(tetB.a_, tetB.c_, tetB.d_);
-
-        nInside = 0;
-
-        for (label i = 0; i < nCutInside; i++)
-        {
-            cutInsideTets[i].tet().sliceWithPlane(pl1, inside, outside);
-        }
-
-        if (nInside == 0)
-        {
-            return;
-        }
-    }
-
-    {
-        // face2
-        plane pl2(tetB.a_, tetB.d_, tetB.b_);
-
-        nCutInside = 0;
-
-        for (label i = 0; i < nInside; i++)
-        {
-            insideTets[i].tet().sliceWithPlane(pl2, cutInside, outside);
-        }
-
-        if (nCutInside == 0)
-        {
-            nInside = nCutInside;
-            return;
-        }
-    }
-
-    {
-        // face3
-        plane pl3(tetB.a_, tetB.b_, tetB.c_);
-
-        nInside = 0;
-
-        for (label i = 0; i < nCutInside; i++)
-        {
-            cutInsideTets[i].tet().sliceWithPlane(pl3, inside, outside);
-        }
-    }
-}
-
-
 template<class Point, class PointRef>
 Foam::pointHit Foam::tetrahedron<Point, PointRef>::containmentSphere
 (
@@ -426,4 +336,16 @@ void Foam::tetrahedron<Point, PointRef>::gradNiGradNj
 }
 
 
+template<class Point, class PointRef>
+Foam::boundBox Foam::tetrahedron<Point, PointRef>::bounds() const
+{
+    return
+        boundBox
+        (
+            min(a(), min(b(), min(c(), d()))),
+            max(a(), max(b(), max(c(), d())))
+        );
+}
+
+
 // ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetrahedron.H b/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetrahedron.H
index 2369e77ca81ced17a9d7d162bce139dd4432a45f..27e1ad63c306cf80add94460191037874bbaf5c7 100644
--- a/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetrahedron.H
+++ b/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetrahedron.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -46,6 +46,7 @@ SourceFiles
 #include "FixedList.H"
 #include "UList.H"
 #include "triPointRef.H"
+#include "boundBox.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -54,8 +55,6 @@ namespace Foam
 
 class Istream;
 class Ostream;
-class tetPoints;
-class plane;
 
 // Forward declaration of friend functions and operators
 
@@ -75,8 +74,6 @@ inline Ostream& operator<<
     const tetrahedron<Point, PointRef>&
 );
 
-typedef tetrahedron<point, const point&> tetPointRef;
-
 /*---------------------------------------------------------------------------*\
                            class tetrahedron Declaration
 \*---------------------------------------------------------------------------*/
@@ -84,78 +81,12 @@ typedef tetrahedron<point, const point&> tetPointRef;
 template<class Point, class PointRef>
 class tetrahedron
 {
-public:
-
-    // Public typedefs
-
-        //- Storage type for tets originating from intersecting tets.
-        //  (can possibly be smaller than 200)
-        typedef FixedList<tetPoints, 200> tetIntersectionList;
-
-
-        // Classes for use in sliceWithPlane. What to do with decomposition
-        // of tet.
-
-            //- Dummy
-            class dummyOp
-            {
-            public:
-                inline void operator()(const tetPoints&);
-            };
-
-            //- Sum resulting volumes
-            class sumVolOp
-            {
-            public:
-                scalar vol_;
-
-                inline sumVolOp();
-
-                inline void operator()(const tetPoints&);
-            };
-
-            //- Store resulting tets
-            class storeOp
-            {
-                tetIntersectionList& tets_;
-                label& nTets_;
-
-            public:
-                inline storeOp(tetIntersectionList&, label&);
-
-                inline void operator()(const tetPoints&);
-            };
-
 private:
 
     // Private data
 
         PointRef a_, b_, c_, d_;
 
-        inline static point planeIntersection
-        (
-            const FixedList<scalar, 4>&,
-            const tetPoints&,
-            const label,
-            const label
-        );
-
-        template<class TetOp>
-        inline static void decomposePrism
-        (
-            const FixedList<point, 6>& points,
-            TetOp& op
-        );
-
-        template<class AboveTetOp, class BelowTetOp>
-        inline static void tetSliceWithPlane
-        (
-            const plane& pl,
-            const tetPoints& tet,
-            AboveTetOp& aboveOp,
-            BelowTetOp& belowOp
-        );
-
 
 public:
 
@@ -254,26 +185,6 @@ public:
             //- Return true if point is inside tetrahedron
             inline bool inside(const point& pt) const;
 
-            //- Decompose tet into tets above and below plane
-            template<class AboveTetOp, class BelowTetOp>
-            inline void sliceWithPlane
-            (
-                const plane& pl,
-                AboveTetOp& aboveOp,
-                BelowTetOp& belowOp
-            ) const;
-
-            //- Decompose tet into tets inside and outside other tet
-            inline void tetOverlap
-            (
-                const tetrahedron<Point, PointRef>& tetB,
-                tetIntersectionList& insideTets,
-                label& nInside,
-                tetIntersectionList& outsideTets,
-                label& nOutside
-            ) const;
-
-
             //- Return (min)containment sphere, i.e. the smallest sphere with
             //  all points inside. Returns pointHit with:
             //  - hit         : if sphere is equal to circumsphere
@@ -294,6 +205,9 @@ public:
 
             void gradNiGradNj(tensorField& buffer) const;
 
+            //- Calculate the bounding box
+            boundBox bounds() const;
+
 
     // IOstream operators
 
diff --git a/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetrahedronI.H b/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetrahedronI.H
index b98fc15bb8088f36443445877435677f365ed3cf..8661a5487ee00307119e5bb0e7552fc335923673 100644
--- a/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetrahedronI.H
+++ b/src/OpenFOAM/meshes/primitiveShapes/tetrahedron/tetrahedronI.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -25,7 +25,6 @@ License
 
 #include "triangle.H"
 #include "IOstreams.H"
-#include "tetPoints.H"
 #include "plane.H"
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
@@ -490,470 +489,6 @@ bool Foam::tetrahedron<Point, PointRef>::inside(const point& pt) const
 }
 
 
-template<class Point, class PointRef>
-inline void Foam::tetrahedron<Point, PointRef>::dummyOp::operator()
-(
-    const tetPoints&
-)
-{}
-
-
-template<class Point, class PointRef>
-inline Foam::tetrahedron<Point, PointRef>::sumVolOp::sumVolOp()
-:
-    vol_(0.0)
-{}
-
-
-template<class Point, class PointRef>
-inline void Foam::tetrahedron<Point, PointRef>::sumVolOp::operator()
-(
-    const tetPoints& tet
-)
-{
-    vol_ += tet.tet().mag();
-}
-
-
-template<class Point, class PointRef>
-inline Foam::tetrahedron<Point, PointRef>::storeOp::storeOp
-(
-    tetIntersectionList& tets,
-    label& nTets
-)
-:
-    tets_(tets),
-    nTets_(nTets)
-{}
-
-
-template<class Point, class PointRef>
-inline void Foam::tetrahedron<Point, PointRef>::storeOp::operator()
-(
-    const tetPoints& tet
-)
-{
-    tets_[nTets_++] = tet;
-}
-
-
-template<class Point, class PointRef>
-inline Foam::point Foam::tetrahedron<Point, PointRef>::planeIntersection
-(
-    const FixedList<scalar, 4>& d,
-    const tetPoints& t,
-    const label negI,
-    const label posI
-)
-{
-    return
-        (d[posI]*t[negI] - d[negI]*t[posI])
-      / (-d[negI]+d[posI]);
-}
-
-
-template<class Point, class PointRef>
-template<class TetOp>
-inline void Foam::tetrahedron<Point, PointRef>::decomposePrism
-(
-    const FixedList<point, 6>& points,
-    TetOp& op
-)
-{
-    op(tetPoints(points[1], points[3], points[2], points[0]));
-    op(tetPoints(points[1], points[2], points[3], points[4]));
-    op(tetPoints(points[4], points[2], points[3], points[5]));
-}
-
-
-template<class Point, class PointRef>
-template<class AboveTetOp, class BelowTetOp>
-inline void Foam::tetrahedron<Point, PointRef>::
-tetSliceWithPlane
-(
-    const plane& pl,
-    const tetPoints& tet,
-    AboveTetOp& aboveOp,
-    BelowTetOp& belowOp
-)
-{
-    // Distance to plane
-    FixedList<scalar, 4> d;
-    label nPos = 0;
-    forAll(tet, i)
-    {
-        d[i] = ((tet[i]-pl.refPoint()) & pl.normal());
-        if (d[i] > 0)
-        {
-            nPos++;
-        }
-    }
-
-    if (nPos == 4)
-    {
-        aboveOp(tet);
-    }
-    else if (nPos == 3)
-    {
-        // Sliced into below tet and above prism. Prism gets split into
-        // two tets.
-
-        // Find the below tet
-        label i0 = -1;
-        forAll(d, i)
-        {
-            if (d[i] <= 0)
-            {
-                i0 = i;
-                break;
-            }
-        }
-
-        label i1 = d.fcIndex(i0);
-        label i2 = d.fcIndex(i1);
-        label i3 = d.fcIndex(i2);
-
-        point p01 = planeIntersection(d, tet, i0, i1);
-        point p02 = planeIntersection(d, tet, i0, i2);
-        point p03 = planeIntersection(d, tet, i0, i3);
-
-        // i0 = tetCell vertex 0: p01,p02,p03 outwards pointing triad
-        //          ,,         1 :     ,,     inwards pointing triad
-        //          ,,         2 :     ,,     outwards pointing triad
-        //          ,,         3 :     ,,     inwards pointing triad
-
-        //Pout<< "Split 3pos tet " << tet << " d:" << d << " into" << nl;
-
-        if (i0 == 0 || i0 == 2)
-        {
-            tetPoints t(tet[i0], p01, p02, p03);
-            //Pout<< "    belowtet:" << t << " around i0:" << i0 << endl;
-            //checkTet(t, "nPos 3, belowTet i0==0 or 2");
-            belowOp(t);
-
-            // Prism
-            FixedList<point, 6> p;
-            p[0] = tet[i1];
-            p[1] = tet[i3];
-            p[2] = tet[i2];
-            p[3] = p01;
-            p[4] = p03;
-            p[5] = p02;
-            //Pout<< "    aboveprism:" << p << endl;
-            decomposePrism(p, aboveOp);
-        }
-        else
-        {
-            tetPoints t(p01, p02, p03, tet[i0]);
-            //Pout<< "    belowtet:" << t << " around i0:" << i0 << endl;
-            //checkTet(t, "nPos 3, belowTet i0==1 or 3");
-            belowOp(t);
-
-            // Prism
-            FixedList<point, 6> p;
-            p[0] = tet[i3];
-            p[1] = tet[i1];
-            p[2] = tet[i2];
-            p[3] = p03;
-            p[4] = p01;
-            p[5] = p02;
-            //Pout<< "    aboveprism:" << p << endl;
-            decomposePrism(p, aboveOp);
-        }
-    }
-    else if (nPos == 2)
-    {
-        // Tet cut into two prisms. Determine the positive one.
-        label pos0 = -1;
-        label pos1 = -1;
-        forAll(d, i)
-        {
-            if (d[i] > 0)
-            {
-                if (pos0 == -1)
-                {
-                    pos0 = i;
-                }
-                else
-                {
-                    pos1 = i;
-                }
-            }
-        }
-
-        //Pout<< "Split 2pos tet " << tet << " d:" << d
-        //    << " around pos0:" << pos0 << " pos1:" << pos1
-        //    << " neg0:" << neg0 << " neg1:" << neg1 << " into" << nl;
-
-        const edge posEdge(pos0, pos1);
-
-        if (posEdge == edge(0, 1))
-        {
-            point p02 = planeIntersection(d, tet, 0, 2);
-            point p03 = planeIntersection(d, tet, 0, 3);
-            point p12 = planeIntersection(d, tet, 1, 2);
-            point p13 = planeIntersection(d, tet, 1, 3);
-            // Split the resulting prism
-            {
-                FixedList<point, 6> p;
-                p[0] = tet[0];
-                p[1] = p02;
-                p[2] = p03;
-                p[3] = tet[1];
-                p[4] = p12;
-                p[5] = p13;
-                //Pout<< "    01 aboveprism:" << p << endl;
-                decomposePrism(p, aboveOp);
-            }
-            {
-                FixedList<point, 6> p;
-                p[0] = tet[2];
-                p[1] = p02;
-                p[2] = p12;
-                p[3] = tet[3];
-                p[4] = p03;
-                p[5] = p13;
-                //Pout<< "    01 belowprism:" << p << endl;
-                decomposePrism(p, belowOp);
-            }
-        }
-        else if (posEdge == edge(1, 2))
-        {
-            point p01 = planeIntersection(d, tet, 0, 1);
-            point p13 = planeIntersection(d, tet, 1, 3);
-            point p02 = planeIntersection(d, tet, 0, 2);
-            point p23 = planeIntersection(d, tet, 2, 3);
-            // Split the resulting prism
-            {
-                FixedList<point, 6> p;
-                p[0] = tet[1];
-                p[1] = p01;
-                p[2] = p13;
-                p[3] = tet[2];
-                p[4] = p02;
-                p[5] = p23;
-                //Pout<< "    12 aboveprism:" << p << endl;
-                decomposePrism(p, aboveOp);
-            }
-            {
-                FixedList<point, 6> p;
-                p[0] = tet[3];
-                p[1] = p23;
-                p[2] = p13;
-                p[3] = tet[0];
-                p[4] = p02;
-                p[5] = p01;
-                //Pout<< "    12 belowprism:" << p << endl;
-                decomposePrism(p, belowOp);
-            }
-        }
-        else if (posEdge == edge(2, 0))
-        {
-            point p01 = planeIntersection(d, tet, 0, 1);
-            point p03 = planeIntersection(d, tet, 0, 3);
-            point p12 = planeIntersection(d, tet, 1, 2);
-            point p23 = planeIntersection(d, tet, 2, 3);
-            // Split the resulting prism
-            {
-                FixedList<point, 6> p;
-                p[0] = tet[2];
-                p[1] = p12;
-                p[2] = p23;
-                p[3] = tet[0];
-                p[4] = p01;
-                p[5] = p03;
-                //Pout<< "    20 aboveprism:" << p << endl;
-                decomposePrism(p, aboveOp);
-            }
-            {
-                FixedList<point, 6> p;
-                p[0] = tet[1];
-                p[1] = p12;
-                p[2] = p01;
-                p[3] = tet[3];
-                p[4] = p23;
-                p[5] = p03;
-                //Pout<< "    20 belowprism:" << p << endl;
-                decomposePrism(p, belowOp);
-            }
-        }
-        else if (posEdge == edge(0, 3))
-        {
-            point p01 = planeIntersection(d, tet, 0, 1);
-            point p02 = planeIntersection(d, tet, 0, 2);
-            point p13 = planeIntersection(d, tet, 1, 3);
-            point p23 = planeIntersection(d, tet, 2, 3);
-            // Split the resulting prism
-            {
-                FixedList<point, 6> p;
-                p[0] = tet[3];
-                p[1] = p23;
-                p[2] = p13;
-                p[3] = tet[0];
-                p[4] = p02;
-                p[5] = p01;
-                //Pout<< "    03 aboveprism:" << p << endl;
-                decomposePrism(p, aboveOp);
-            }
-            {
-                FixedList<point, 6> p;
-                p[0] = tet[2];
-                p[1] = p23;
-                p[2] = p02;
-                p[3] = tet[1];
-                p[4] = p13;
-                p[5] = p01;
-                //Pout<< "    03 belowprism:" << p << endl;
-                decomposePrism(p, belowOp);
-            }
-        }
-        else if (posEdge == edge(1, 3))
-        {
-            point p01 = planeIntersection(d, tet, 0, 1);
-            point p12 = planeIntersection(d, tet, 1, 2);
-            point p03 = planeIntersection(d, tet, 0, 3);
-            point p23 = planeIntersection(d, tet, 2, 3);
-            // Split the resulting prism
-            {
-                FixedList<point, 6> p;
-                p[0] = tet[1];
-                p[1] = p12;
-                p[2] = p01;
-                p[3] = tet[3];
-                p[4] = p23;
-                p[5] = p03;
-                //Pout<< "    13 aboveprism:" << p << endl;
-                decomposePrism(p, aboveOp);
-            }
-            {
-                FixedList<point, 6> p;
-                p[0] = tet[2];
-                p[1] = p12;
-                p[2] = p23;
-                p[3] = tet[0];
-                p[4] = p01;
-                p[5] = p03;
-                //Pout<< "    13 belowprism:" << p << endl;
-                decomposePrism(p, belowOp);
-            }
-        }
-        else if (posEdge == edge(2, 3))
-        {
-            point p02 = planeIntersection(d, tet, 0, 2);
-            point p12 = planeIntersection(d, tet, 1, 2);
-            point p03 = planeIntersection(d, tet, 0, 3);
-            point p13 = planeIntersection(d, tet, 1, 3);
-            // Split the resulting prism
-            {
-                FixedList<point, 6> p;
-                p[0] = tet[2];
-                p[1] = p02;
-                p[2] = p12;
-                p[3] = tet[3];
-                p[4] = p03;
-                p[5] = p13;
-                //Pout<< "    23 aboveprism:" << p << endl;
-                decomposePrism(p, aboveOp);
-            }
-            {
-                FixedList<point, 6> p;
-                p[0] = tet[0];
-                p[1] = p02;
-                p[2] = p03;
-                p[3] = tet[1];
-                p[4] = p12;
-                p[5] = p13;
-                //Pout<< "    23 belowprism:" << p << endl;
-                decomposePrism(p, belowOp);
-            }
-        }
-        else
-        {
-            FatalErrorInFunction
-                << "Missed edge:" << posEdge
-                << abort(FatalError);
-        }
-    }
-    else if (nPos == 1)
-    {
-        // Find the positive tet
-        label i0 = -1;
-        forAll(d, i)
-        {
-            if (d[i] > 0)
-            {
-                i0 = i;
-                break;
-            }
-        }
-
-        label i1 = d.fcIndex(i0);
-        label i2 = d.fcIndex(i1);
-        label i3 = d.fcIndex(i2);
-
-        point p01 = planeIntersection(d, tet, i0, i1);
-        point p02 = planeIntersection(d, tet, i0, i2);
-        point p03 = planeIntersection(d, tet, i0, i3);
-
-        //Pout<< "Split 1pos tet " << tet << " d:" << d << " into" << nl;
-
-        if (i0 == 0 || i0 == 2)
-        {
-            tetPoints t(tet[i0], p01, p02, p03);
-            //Pout<< "    abovetet:" << t << " around i0:" << i0 << endl;
-            //checkTet(t, "nPos 1, aboveTets i0==0 or 2");
-            aboveOp(t);
-
-            // Prism
-            FixedList<point, 6> p;
-            p[0] = tet[i1];
-            p[1] = tet[i3];
-            p[2] = tet[i2];
-            p[3] = p01;
-            p[4] = p03;
-            p[5] = p02;
-            //Pout<< "    belowprism:" << p << endl;
-            decomposePrism(p, belowOp);
-        }
-        else
-        {
-            tetPoints t(p01, p02, p03, tet[i0]);
-            //Pout<< "    abovetet:" << t << " around i0:" << i0 << endl;
-            //checkTet(t, "nPos 1, aboveTets i0==1 or 3");
-            aboveOp(t);
-
-            // Prism
-            FixedList<point, 6> p;
-            p[0] = tet[i3];
-            p[1] = tet[i1];
-            p[2] = tet[i2];
-            p[3] = p03;
-            p[4] = p01;
-            p[5] = p02;
-            //Pout<< "    belowprism:" << p << endl;
-            decomposePrism(p, belowOp);
-        }
-    }
-    else    // nPos == 0
-    {
-        belowOp(tet);
-    }
-}
-
-
-template<class Point, class PointRef>
-template<class AboveTetOp, class BelowTetOp>
-inline void Foam::tetrahedron<Point, PointRef>::sliceWithPlane
-(
-    const plane& pl,
-    AboveTetOp& aboveOp,
-    BelowTetOp& belowOp
-) const
-{
-    tetSliceWithPlane(pl, tetPoints(a_, b_, c_, d_), aboveOp, belowOp);
-}
-
-
 // * * * * * * * * * * * * * * * Ostream Operator  * * * * * * * * * * * * * //
 
 template<class Point, class PointRef>
diff --git a/src/OpenFOAM/primitives/zero/zeroI.H b/src/OpenFOAM/primitives/zero/zeroI.H
index 0b7b75f23766223f97e052a3bdc75f1a4aa77412..d69255f1599a4bd1ed018bdedbc91cc49c77dbe6 100644
--- a/src/OpenFOAM/primitives/zero/zeroI.H
+++ b/src/OpenFOAM/primitives/zero/zeroI.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -32,6 +32,11 @@ namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+inline zero operator+(const zero&, const zero&)
+{
+    return Zero;
+}
+
 template<class Type>
 inline const Type& operator+(const Type& t, const zero&)
 {
@@ -44,6 +49,11 @@ inline const Type& operator+(const zero&, const Type& t)
     return t;
 }
 
+inline zero operator-(const zero&, const zero&)
+{
+    return Zero;
+}
+
 template<class Type>
 inline const Type& operator-(const Type& t, const zero&)
 {
@@ -56,6 +66,11 @@ inline Type operator-(const zero&, const Type& t)
     return -t;
 }
 
+inline zero operator*(const zero&, const zero&)
+{
+    return Zero;
+}
+
 template<class Type>
 inline zero operator*(const Type& t, const zero&)
 {
diff --git a/src/dynamicMesh/motionSmoother/polyMeshGeometry/polyMeshGeometry.C b/src/dynamicMesh/motionSmoother/polyMeshGeometry/polyMeshGeometry.C
index b7cd414123fb3851d63a44e352c1e50d8217ea42..7c580ae692fc808c6708582a5a55853758c78bc1 100644
--- a/src/dynamicMesh/motionSmoother/polyMeshGeometry/polyMeshGeometry.C
+++ b/src/dynamicMesh/motionSmoother/polyMeshGeometry/polyMeshGeometry.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
      \\/     M anipulation  | Copyright (C) 2015-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
@@ -26,7 +26,7 @@ License
 #include "polyMeshGeometry.H"
 #include "polyMeshTetDecomposition.H"
 #include "pyramidPointFaceRef.H"
-#include "tetrahedron.H"
+#include "tetPointRef.H"
 #include "syncTools.H"
 #include "unitConversion.H"
 #include "primitiveMeshTools.H"
diff --git a/src/lagrangian/basic/particle/particle.H b/src/lagrangian/basic/particle/particle.H
index ea678968ce23118d56c1c0e49bec1d0e956e33ca..24355e3a59353118ce0ae36b74397e777b1efb66 100644
--- a/src/lagrangian/basic/particle/particle.H
+++ b/src/lagrangian/basic/particle/particle.H
@@ -40,7 +40,7 @@ Description
 #include "pointField.H"
 #include "faceList.H"
 #include "OFstream.H"
-#include "tetrahedron.H"
+#include "tetPointRef.H"
 #include "FixedList.H"
 #include "polyMeshTetDecomposition.H"
 #include "particleMacros.H"
diff --git a/src/meshTools/tetOverlapVolume/tetOverlapVolume.C b/src/meshTools/tetOverlapVolume/tetOverlapVolume.C
index 73a5b67fbd9046b4fc822dda311bd4e8eaef5de5..dcae8ae427c2a7d54e8323d1b2276ff2997d0707 100644
--- a/src/meshTools/tetOverlapVolume/tetOverlapVolume.C
+++ b/src/meshTools/tetOverlapVolume/tetOverlapVolume.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2012-2015 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2012-2017 OpenFOAM Foundation
      \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
@@ -24,13 +24,12 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "tetOverlapVolume.H"
-#include "tetrahedron.H"
-#include "tetPoints.H"
 #include "polyMesh.H"
 #include "OFstream.H"
 #include "treeBoundBox.H"
 #include "indexedOctree.H"
 #include "treeDataCell.H"
+#include "cut.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -48,6 +47,67 @@ Foam::tetOverlapVolume::tetOverlapVolume()
 
 // * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * * //
 
+Foam::scalar Foam::tetOverlapVolume::tetTetOverlapVol
+(
+    const tetPointRef& tetA,
+    const tetPointRef& tetB
+) const
+{
+    // A maximum of three cuts are made (the tets that result from the final cut
+    // are not stored), and each cut can create at most three tets. The
+    // temporary storage must therefore extend to 3^3 = 27 tets.
+    typedef cutTetList<27> tetListType;
+    static tetListType cutTetList1, cutTetList2;
+
+    // face 0
+    const plane pl0(tetB.b(), tetB.d(), tetB.c());
+    const FixedList<point, 4> t({tetA.a(), tetA.b(), tetA.c(), tetA.d()});
+    cutTetList1.clear();
+    tetCut(t, pl0, cut::appendOp<tetListType>(cutTetList1), cut::noOp());
+    if (cutTetList1.size() == 0)
+    {
+        return 0;
+    }
+
+    // face 1
+    const plane pl1(tetB.a(), tetB.c(), tetB.d());
+    cutTetList2.clear();
+    for (label i = 0; i < cutTetList1.size(); i++)
+    {
+        const FixedList<point, 4>& t = cutTetList1[i];
+        tetCut(t, pl1, cut::appendOp<tetListType>(cutTetList2), cut::noOp());
+    }
+    if (cutTetList2.size() == 0)
+    {
+        return 0;
+    }
+
+    // face 2
+    const plane pl2(tetB.a(), tetB.d(), tetB.b());
+    cutTetList1.clear();
+    for (label i = 0; i < cutTetList2.size(); i++)
+    {
+        const FixedList<point, 4>& t = cutTetList2[i];
+        tetCut(t, pl2, cut::appendOp<tetListType>(cutTetList1), cut::noOp());
+    }
+    if (cutTetList1.size() == 0)
+    {
+        return 0;
+    }
+
+    // face 3
+    const plane pl3(tetB.a(), tetB.b(), tetB.c());
+    scalar v = 0;
+    for (label i = 0; i < cutTetList1.size(); i++)
+    {
+        const FixedList<point, 4>& t = cutTetList1[i];
+        v += tetCut(t, pl3, cut::volumeOp(), cut::noOp());
+    }
+
+    return v;
+}
+
+
 Foam::treeBoundBox Foam::tetOverlapVolume::pyrBb
 (
     const pointField& points,
@@ -74,43 +134,122 @@ bool Foam::tetOverlapVolume::cellCellOverlapMinDecomp
     const scalar threshold
 ) const
 {
-    hasOverlapOp overlapCheckOp(threshold);
-    cellCellOverlapMinDecomp<hasOverlapOp>
-    (
-        meshA,
-        cellAI,
-        meshB,
-        cellBI,
-        cellBbB,
-        overlapCheckOp
-    );
-
-    return overlapCheckOp.ok_;
-}
-
-
-Foam::scalar Foam::tetOverlapVolume::cellCellOverlapVolumeMinDecomp
-(
-    const primitiveMesh& meshA,
-    const label cellAI,
-
-    const primitiveMesh& meshB,
-    const label cellBI,
-    const treeBoundBox& cellBbB
-) const
-{
-    sumOverlapOp overlapSumOp;
-    cellCellOverlapMinDecomp<sumOverlapOp>
-    (
-        meshA,
-        cellAI,
-        meshB,
-        cellBI,
-        cellBbB,
-        overlapSumOp
-    );
-
-    return overlapSumOp.iop_.vol_;
+    const cell& cFacesA = meshA.cells()[cellAI];
+    const point& ccA = meshA.cellCentres()[cellAI];
+
+    const cell& cFacesB = meshB.cells()[cellBI];
+    const point& ccB = meshB.cellCentres()[cellBI];
+
+    scalar vol = 0.0;
+
+    forAll(cFacesA, cFA)
+    {
+        label faceAI = cFacesA[cFA];
+
+        const face& fA = meshA.faces()[faceAI];
+        const treeBoundBox pyrA = pyrBb(meshA.points(), fA, ccA);
+        if (!pyrA.overlaps(cellBbB))
+        {
+            continue;
+        }
+
+        bool ownA = (meshA.faceOwner()[faceAI] == cellAI);
+
+        label tetBasePtAI = 0;
+
+        const point& tetBasePtA = meshA.points()[fA[tetBasePtAI]];
+
+        for (label tetPtI = 1; tetPtI < fA.size() - 1; tetPtI++)
+        {
+            label facePtAI = (tetPtI + tetBasePtAI) % fA.size();
+            label otherFacePtAI = fA.fcIndex(facePtAI);
+
+            label pt0I = -1;
+            label pt1I = -1;
+
+            if (ownA)
+            {
+                pt0I = fA[facePtAI];
+                pt1I = fA[otherFacePtAI];
+            }
+            else
+            {
+                pt0I = fA[otherFacePtAI];
+                pt1I = fA[facePtAI];
+            }
+
+            const tetPointRef tetA
+            (
+                ccA,
+                tetBasePtA,
+                meshA.points()[pt0I],
+                meshA.points()[pt1I]
+            );
+            const treeBoundBox tetABb(tetA.bounds());
+
+
+            // Loop over tets of cellB
+            forAll(cFacesB, cFB)
+            {
+                label faceBI = cFacesB[cFB];
+
+                const face& fB = meshB.faces()[faceBI];
+                const treeBoundBox pyrB = pyrBb(meshB.points(), fB, ccB);
+                if (!pyrB.overlaps(pyrA))
+                {
+                    continue;
+                }
+
+                bool ownB = (meshB.faceOwner()[faceBI] == cellBI);
+
+                label tetBasePtBI = 0;
+
+                const point& tetBasePtB = meshB.points()[fB[tetBasePtBI]];
+
+                for (label tetPtI = 1; tetPtI < fB.size() - 1; tetPtI++)
+                {
+                    label facePtBI = (tetPtI + tetBasePtBI) % fB.size();
+                    label otherFacePtBI = fB.fcIndex(facePtBI);
+
+                    label pt0I = -1;
+                    label pt1I = -1;
+
+                    if (ownB)
+                    {
+                        pt0I = fB[facePtBI];
+                        pt1I = fB[otherFacePtBI];
+                    }
+                    else
+                    {
+                        pt0I = fB[otherFacePtBI];
+                        pt1I = fB[facePtBI];
+                    }
+
+                    const tetPointRef tetB
+                    (
+                        ccB,
+                        tetBasePtB,
+                        meshB.points()[pt0I],
+                        meshB.points()[pt1I]
+                    );
+
+                    if (!tetB.bounds().overlaps(tetABb))
+                    {
+                        continue;
+                    }
+
+                    vol += tetTetOverlapVol(tetA, tetB);
+
+                    if (vol > threshold)
+                    {
+                        return true;
+                    }
+                }
+            }
+        }
+    }
+
+    return false;
 }
 
 
@@ -125,18 +264,116 @@ Foam::tetOverlapVolume::cellCellOverlapMomentMinDecomp
     const treeBoundBox& cellBbB
 ) const
 {
-    sumOverlapMomentOp overlapSumOp;
-    cellCellOverlapMinDecomp<sumOverlapMomentOp>
-    (
-        meshA,
-        cellAI,
-        meshB,
-        cellBI,
-        cellBbB,
-        overlapSumOp
-    );
-
-    return overlapSumOp.iop_.vol_;
+    const cell& cFacesA = meshA.cells()[cellAI];
+    const point& ccA = meshA.cellCentres()[cellAI];
+
+    const cell& cFacesB = meshB.cells()[cellBI];
+    const point& ccB = meshB.cellCentres()[cellBI];
+
+    scalar vol = 0.0;
+
+    forAll(cFacesA, cFA)
+    {
+        label faceAI = cFacesA[cFA];
+
+        const face& fA = meshA.faces()[faceAI];
+        const treeBoundBox pyrA = pyrBb(meshA.points(), fA, ccA);
+        if (!pyrA.overlaps(cellBbB))
+        {
+            continue;
+        }
+
+        bool ownA = (meshA.faceOwner()[faceAI] == cellAI);
+
+        label tetBasePtAI = 0;
+
+        const point& tetBasePtA = meshA.points()[fA[tetBasePtAI]];
+
+        for (label tetPtI = 1; tetPtI < fA.size() - 1; tetPtI++)
+        {
+            label facePtAI = (tetPtI + tetBasePtAI) % fA.size();
+            label otherFacePtAI = fA.fcIndex(facePtAI);
+
+            label pt0I = -1;
+            label pt1I = -1;
+
+            if (ownA)
+            {
+                pt0I = fA[facePtAI];
+                pt1I = fA[otherFacePtAI];
+            }
+            else
+            {
+                pt0I = fA[otherFacePtAI];
+                pt1I = fA[facePtAI];
+            }
+
+            const tetPointRef tetA
+            (
+                ccA,
+                tetBasePtA,
+                meshA.points()[pt0I],
+                meshA.points()[pt1I]
+            );
+            const treeBoundBox tetABb(tetA.bounds());
+
+
+            // Loop over tets of cellB
+            forAll(cFacesB, cFB)
+            {
+                label faceBI = cFacesB[cFB];
+
+                const face& fB = meshB.faces()[faceBI];
+                const treeBoundBox pyrB = pyrBb(meshB.points(), fB, ccB);
+                if (!pyrB.overlaps(pyrA))
+                {
+                    continue;
+                }
+
+                bool ownB = (meshB.faceOwner()[faceBI] == cellBI);
+
+                label tetBasePtBI = 0;
+
+                const point& tetBasePtB = meshB.points()[fB[tetBasePtBI]];
+
+                for (label tetPtI = 1; tetPtI < fB.size() - 1; tetPtI++)
+                {
+                    label facePtBI = (tetPtI + tetBasePtBI) % fB.size();
+                    label otherFacePtBI = fB.fcIndex(facePtBI);
+
+                    label pt0I = -1;
+                    label pt1I = -1;
+
+                    if (ownB)
+                    {
+                        pt0I = fB[facePtBI];
+                        pt1I = fB[otherFacePtBI];
+                    }
+                    else
+                    {
+                        pt0I = fB[otherFacePtBI];
+                        pt1I = fB[facePtBI];
+                    }
+
+                    const tetPointRef tetB
+                    (
+                        ccB,
+                        tetBasePtB,
+                        meshB.points()[pt0I],
+                        meshB.points()[pt1I]
+                    );
+                    if (!tetB.bounds().overlaps(tetABb))
+                    {
+                        continue;
+                    }
+
+                    vol += tetTetOverlapVol(tetA, tetB);
+                }
+            }
+        }
+    }
+
+    return vol;
 }
 
 
diff --git a/src/meshTools/tetOverlapVolume/tetOverlapVolume.H b/src/meshTools/tetOverlapVolume/tetOverlapVolume.H
index a77e608c6e926a455275db78ae34225db50fbf59..06b315d47f96ff00547491abfbaf87f6adc71949 100644
--- a/src/meshTools/tetOverlapVolume/tetOverlapVolume.H
+++ b/src/meshTools/tetOverlapVolume/tetOverlapVolume.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2012-2014 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2012-2017 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -29,7 +29,6 @@ Description
 
 SourceFiles
     tetOverlapVolume.C
-    tetOverlapVolumeTemplates.C
 
 \*---------------------------------------------------------------------------*/
 
@@ -39,8 +38,7 @@ SourceFiles
 #include "FixedList.H"
 #include "labelList.H"
 #include "treeBoundBox.H"
-#include "Tuple2.H"
-#include "tetrahedron.H"
+#include "tetPointRef.H"
 
 namespace Foam
 {
@@ -54,126 +52,69 @@ class polyMesh;
 
 class tetOverlapVolume
 {
-    // Private classes
+    // Private member functions
 
-        //- tetPoints handling : sum resulting volumes
-        class sumMomentOp
-        {
-        public:
-            Tuple2<scalar, point> vol_;
+        //- Tet overlap volume
+        scalar tetTetOverlapVol
+        (
+            const tetPointRef& tetA,
+            const tetPointRef& tetB
+        ) const;
 
-            inline sumMomentOp()
-            :
-                vol_(0.0, Zero)
-            {}
+        //- Return a const treeBoundBox
+        treeBoundBox pyrBb
+        (
+            const pointField& points,
+            const face& f,
+            const point& fc
+        ) const;
 
-            inline void operator()(const tetPoints& tet)
-            {
-                const tetPointRef t(tet.tet());
-                scalar tetVol = t.mag();
-                vol_.first() += tetVol;
-                vol_.second() += (tetVol*t.centre());
-            }
-        };
 
-        //- tetPoints combining : check for overlap
-        class hasOverlapOp
+    // Private classes
+
+        //- A fixed list of tets which simulates a dynamic list by incrementing
+        //  a counter whenever its append method is called. This is used as an
+        //  optimisation for the tetTetOverlapVol method.
+        template<unsigned Size>
+        class cutTetList
+        :
+            public FixedList<FixedList<point, 4>, Size>
         {
-        public:
+        private:
 
-            const scalar threshold_;
-            tetPointRef::sumVolOp iop_;
-            bool ok_;
+            //- The number of stored elements
+            label n_;
 
-            inline hasOverlapOp(const scalar threshold)
-            :
-                threshold_(threshold),
-                iop_(),
-                ok_(false)
-            {}
-
-            //- Overlap two tets
-            inline bool operator()(const tetPoints& A, const tetPoints& B)
-            {
-                tetTetOverlap<tetPointRef::sumVolOp>(A, B, iop_);
-                ok_ = (iop_.vol_ > threshold_);
-                return ok_;
-            }
-        };
 
-        //- tetPoints combining : sum overlap volume
-        class sumOverlapOp
-        {
         public:
 
-            tetPointRef::sumVolOp iop_;
-
-            inline sumOverlapOp()
+            //- Construct null
+            cutTetList()
             :
-                iop_()
+                n_(0)
             {}
 
-            //- Overlap two tets
-            inline bool operator()(const tetPoints& A, const tetPoints& B)
+            //- Clear the array
+            void clear()
             {
-                tetTetOverlap<tetPointRef::sumVolOp>(A, B, iop_);
-                return false;
+                n_ = 0;
             }
-        };
-
-        //- tetPoints combining : sum overlap volume
-        class sumOverlapMomentOp
-        {
-        public:
 
-            sumMomentOp iop_;
-
-            inline sumOverlapMomentOp()
-            :
-                iop_()
-            {}
+            //- Get the current size
+            label size() const
+            {
+                return n_;
+            }
 
-            //- Overlap two tets
-            inline bool operator()(const tetPoints& A, const tetPoints& B)
+            //- Add a new tet to the end of the array
+            void append(const FixedList<point, 4>& t)
             {
-                tetTetOverlap<sumMomentOp>(A, B, iop_);
-                return false;
+                this->operator[](n_) = t;
+                ++ n_;
             }
         };
 
 
-    // Private member functions
-
-        //- Tet overlap calculation
-        template<class tetPointsOp>
-        static void tetTetOverlap
-        (
-            const tetPoints& tetA,
-            const tetPoints& tetB,
-            tetPointsOp& insideOp
-        );
-
-        //- Cell overlap calculation
-        template<class tetsOp>
-        static void cellCellOverlapMinDecomp
-        (
-            const primitiveMesh& meshA,
-            const label cellAI,
-            const primitiveMesh& meshB,
-            const label cellBI,
-            const treeBoundBox& cellBbB,
-            tetsOp& combineTetsOp
-        );
-
-        //- Return a const treeBoundBox
-        static treeBoundBox pyrBb
-        (
-            const pointField& points,
-            const face& f,
-            const point& fc
-        );
-
-
 public:
 
     //- Runtime type information
@@ -218,17 +159,6 @@ public:
             const label cellBI,
             const treeBoundBox& cellBbB
         ) const;
-
-        //- Calculates the overlap volume and moment
-        Tuple2<scalar, point> cellCellOverlapMomentMinDecomp
-        (
-            const primitiveMesh& meshA,
-            const label cellAI,
-
-            const primitiveMesh& meshB,
-            const label cellBI,
-            const treeBoundBox& cellBbB
-        ) const;
 };
 
 
@@ -238,12 +168,6 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-#ifdef NoRepository
-#   include "tetOverlapVolumeTemplates.C"
-#endif
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
 #endif
 
 // ************************************************************************* //
diff --git a/src/meshTools/tetOverlapVolume/tetOverlapVolumeTemplates.C b/src/meshTools/tetOverlapVolume/tetOverlapVolumeTemplates.C
deleted file mode 100644
index 34eded1ff313478509b37fc627b996297d358213..0000000000000000000000000000000000000000
--- a/src/meshTools/tetOverlapVolume/tetOverlapVolumeTemplates.C
+++ /dev/null
@@ -1,259 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2015 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "tetOverlapVolume.H"
-#include "primitiveMesh.H"
-
-// * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * * //
-
-template<class tetPointsOp>
-void Foam::tetOverlapVolume::tetTetOverlap
-(
-    const tetPoints& tetA,
-    const tetPoints& tetB,
-    tetPointsOp& insideOp
-)
-{
-    static tetPointRef::tetIntersectionList insideTets;
-    label nInside = 0;
-    static tetPointRef::tetIntersectionList cutInsideTets;
-    label nCutInside = 0;
-
-    tetPointRef::storeOp inside(insideTets, nInside);
-    tetPointRef::storeOp cutInside(cutInsideTets, nCutInside);
-    tetPointRef::dummyOp outside;
-
-    // Precompute the tet face areas and exit early if any face area is
-    // too small
-    static FixedList<vector, 4> tetAFaceAreas;
-    static FixedList<scalar, 4> tetAMag2FaceAreas;
-    tetPointRef tetATet = tetA.tet();
-    for (label facei = 0; facei < 4; ++facei)
-    {
-        tetAFaceAreas[facei] = -tetATet.tri(facei).normal();
-        tetAMag2FaceAreas[facei] = magSqr(tetAFaceAreas[facei]);
-        if (tetAMag2FaceAreas[facei] < ROOTVSMALL)
-        {
-            return;
-        }
-    }
-
-    static FixedList<vector, 4> tetBFaceAreas;
-    static FixedList<scalar, 4> tetBMag2FaceAreas;
-    tetPointRef tetBTet = tetB.tet();
-    for (label facei = 0; facei < 4; ++facei)
-    {
-        tetBFaceAreas[facei] = -tetBTet.tri(facei).normal();
-        tetBMag2FaceAreas[facei] = magSqr(tetBFaceAreas[facei]);
-        if (tetBMag2FaceAreas[facei] < ROOTVSMALL)
-        {
-            return;
-        }
-    }
-
-
-    // Face 0
-    {
-        vector n = tetBFaceAreas[0]/Foam::sqrt(tetBMag2FaceAreas[0]);
-        plane pl0(tetBTet.tri(0).a(), n, false);
-
-        tetA.tet().sliceWithPlane(pl0, cutInside, outside);
-        if (nCutInside == 0)
-        {
-            return;
-        }
-    }
-
-    // Face 1
-    {
-        vector n = tetBFaceAreas[1]/Foam::sqrt(tetBMag2FaceAreas[1]);
-        plane pl1(tetBTet.tri(1).a(), n, false);
-
-        nInside = 0;
-        for (label i = 0; i < nCutInside; i++)
-        {
-            const tetPointRef t = cutInsideTets[i].tet();
-            t.sliceWithPlane(pl1, inside, outside);
-        }
-        if (nInside == 0)
-        {
-            return;
-        }
-    }
-
-    // Face 2
-    {
-        vector n = tetBFaceAreas[2]/Foam::sqrt(tetBMag2FaceAreas[2]);
-        plane pl2(tetBTet.tri(2).a(), n, false);
-
-        nCutInside = 0;
-        for (label i = 0; i < nInside; i++)
-        {
-            const tetPointRef t = insideTets[i].tet();
-            t.sliceWithPlane(pl2, cutInside, outside);
-        }
-        if (nCutInside == 0)
-        {
-            return;
-        }
-    }
-
-    // Face 3
-    {
-        vector n = tetBFaceAreas[3]/Foam::sqrt(tetBMag2FaceAreas[3]);
-        plane pl3(tetBTet.tri(3).a(), n, false);
-        for (label i = 0; i < nCutInside; i++)
-        {
-            const tetPointRef t = cutInsideTets[i].tet();
-            t.sliceWithPlane(pl3, insideOp, outside);
-        }
-    }
-}
-
-
-template<class tetsOp>
-void Foam::tetOverlapVolume::cellCellOverlapMinDecomp
-(
-    const primitiveMesh& meshA,
-    const label cellAI,
-
-    const primitiveMesh& meshB,
-    const label cellBI,
-    const treeBoundBox& cellBbB,
-    tetsOp& combineTetsOp
-)
-{
-    const cell& cFacesA = meshA.cells()[cellAI];
-    const point& ccA = meshA.cellCentres()[cellAI];
-
-    const cell& cFacesB = meshB.cells()[cellBI];
-    const point& ccB = meshB.cellCentres()[cellBI];
-
-    forAll(cFacesA, cFA)
-    {
-        label faceAI = cFacesA[cFA];
-
-        const face& fA = meshA.faces()[faceAI];
-        const treeBoundBox pyrA = pyrBb(meshA.points(), fA, ccA);
-        if (!pyrA.overlaps(cellBbB))
-        {
-            continue;
-        }
-
-        bool ownA = (meshA.faceOwner()[faceAI] == cellAI);
-
-        label tetBasePtAI = 0;
-
-        const point& tetBasePtA = meshA.points()[fA[tetBasePtAI]];
-
-        for (label tetPtI = 1; tetPtI < fA.size() - 1; tetPtI++)
-        {
-            label facePtAI = (tetPtI + tetBasePtAI) % fA.size();
-            label otherFacePtAI = fA.fcIndex(facePtAI);
-
-            label pt0I = -1;
-            label pt1I = -1;
-
-            if (ownA)
-            {
-                pt0I = fA[facePtAI];
-                pt1I = fA[otherFacePtAI];
-            }
-            else
-            {
-                pt0I = fA[otherFacePtAI];
-                pt1I = fA[facePtAI];
-            }
-
-            const tetPoints tetA
-            (
-                ccA,
-                tetBasePtA,
-                meshA.points()[pt0I],
-                meshA.points()[pt1I]
-            );
-            const treeBoundBox tetABb(tetA.bounds());
-
-            // Loop over tets of cellB
-            forAll(cFacesB, cFB)
-            {
-                label faceBI = cFacesB[cFB];
-
-                const face& fB = meshB.faces()[faceBI];
-                const treeBoundBox pyrB = pyrBb(meshB.points(), fB, ccB);
-                if (!pyrB.overlaps(pyrA))
-                {
-                    continue;
-                }
-
-                bool ownB = (meshB.faceOwner()[faceBI] == cellBI);
-
-                label tetBasePtBI = 0;
-
-                const point& tetBasePtB = meshB.points()[fB[tetBasePtBI]];
-
-                for (label tetPtI = 1; tetPtI < fB.size() - 1; tetPtI++)
-                {
-                    label facePtBI = (tetPtI + tetBasePtBI) % fB.size();
-                    label otherFacePtBI = fB.fcIndex(facePtBI);
-
-                    label pt0I = -1;
-                    label pt1I = -1;
-
-                    if (ownB)
-                    {
-                        pt0I = fB[facePtBI];
-                        pt1I = fB[otherFacePtBI];
-                    }
-                    else
-                    {
-                        pt0I = fB[otherFacePtBI];
-                        pt1I = fB[facePtBI];
-                    }
-
-                    const tetPoints tetB
-                    (
-                        ccB,
-                        tetBasePtB,
-                        meshB.points()[pt0I],
-                        meshB.points()[pt1I]
-                    );
-                    if (!tetB.bounds().overlaps(tetABb))
-                    {
-                        continue;
-                    }
-
-                    if (combineTetsOp(tetA, tetB))
-                    {
-                        return;
-                    }
-                }
-            }
-        }
-    }
-}
-
-
-// ************************************************************************* //