diff --git a/applications/utilities/postProcessing/sampling/sample/sampleDict b/applications/utilities/postProcessing/sampling/sample/sampleDict
index 92b1c02e35b983ca4e52f377cdc6bcf2ae5fec76..88c86bf482eda4b44f3d96bca85e4ed6468cebe5 100644
--- a/applications/utilities/postProcessing/sampling/sample/sampleDict
+++ b/applications/utilities/postProcessing/sampling/sample/sampleDict
@@ -31,18 +31,66 @@ setFormat raw;
 //      dx          : DX scalar or vector format
 //      vtk         : VTK ascii format
 //      raw         : x y z value format for use with e.g. gnuplot 'splot'.
+//      boundaryData: written in a form that can be used with timeVaryingMapped
+//                    boundary conditions (move to constant/boundaryData)
+//      starcd      : Star-CD format (geometry in .cel/.vrt, data in .usr)
+//      nastran     : Nastran (.nas) format
 //
 // Note:
-// other formats such as obj, stl, etc can also be written (by proxy)
-// but without any values!
+// - other formats such as obj, stl, etc can also be written (by proxy)
+//   but without any values!
+// - boundaryData format: typical use:
+//      - use a surfaces functionObject to sample a patch:
+//            type            surfaces;
+//            surfaceFormat   boundaryData;
+//            fields          ( p );
+//            surfaces
+//            (
+//                inlet
+//                {
+//                    type            patch;
+//                    patches         (inpletPatch);
+//                    interpolate     false;
+//                }
+//            );
+//      - the boundaryData writer will write postProcessing/surfaces/inlet/
+//      - move this to constant/boundaryData/inlet of the destination case
+//      - use a timeVaryingMappedFixedValue bc to read&interpolate and use
+//        as fixedValue.
+// - boundaryData: 'interpolate false' writes face centres, 'interpolate true'
+//   writes points. For 2D case the face centres might only be a single column
+//   so cannot be used in timeVaryingMapped with standard mapping (since
+//   uses triangulation to do interpolation).
+
 surfaceFormat vtk;
 
-// optionally define extra controls for the output formats
+// Optionally define extra controls for the output formats
 formatOptions
 {
     ensight
     {
+        // ascii/binary format
         format  ascii;
+        //collateTimes true;  // write single file containing multiple timesteps
+                              // (only for static surfaces)
+    }
+    nastran
+    {
+        // From OpenFOAM field name to Nastran field name
+        fields
+        (
+            (U      PLOAD4)
+            (p      PLOAD2)
+        );
+        // Optional scale
+        scale 1.0;
+        // Optional format
+        // short/long/free format
+        // short: scalar field width 8. default.
+        // long : scalar field width 16
+        // free : comma separated, field width according to writePrecision
+        //        setting
+        format  short;      // short/long/free
     }
 }
 
@@ -143,9 +191,19 @@ sets
         type        patchSeed;
         axis        xyz;
         patches     (".*Wall.*");
-        // Number of points to seed. Divided amongst all processors according
-        // to fraction of patches they hold.
+
+        // Subset patch faces by:
+
+        // 1. Number of points to seed. Divided amongst all processors
+        //   according to fraction of patches they hold.
         maxPoints   100;
+
+        // 2. Specified set of locations. This selects for every the specified
+        //    point the nearest patch face. (in addition the number of points
+        //    is also truncated by the maxPoints setting)
+        //    The difference with patchCloud is that this selects patch
+        //    face centres, not an arbitrary location on the face.
+        points   ((0.049 0.099 0.005)(0.051 0.054 0.005));
     }
 
 );
@@ -249,8 +307,10 @@ surfaces
         isoValue        0.5;
         interpolate     true;
 
-        //zone            ABC;          // Optional: zone only
-        //exposedPatchName fixedWalls;  // Optional: zone only
+        // zone            ABC;         // Optional: zone only
+        // exposedPatchName fixedWalls; // Optional: zone only
+
+        // bounds       (1 1 1)(2 2 2); // Optional: limit extent
 
         // regularise      false;    // Optional: do not simplify
         // mergeTol        1e-10;    // Optional: fraction of mesh bounding box
@@ -265,6 +325,9 @@ surfaces
         isoValue        0.5;
         interpolate     false;
         regularise      false;              // do not simplify
+
+        // bounds       (1 1 1)(2 2 2); // Optional: limit extent
+
         // mergeTol        1e-10;    // Optional: fraction of mesh bounding box
                                      // to merge points (default=1e-6)
     }
@@ -281,8 +344,10 @@ surfaces
         }
         interpolate     true;
 
-        //zone            ABC;          // Optional: zone only
-        //exposedPatchName fixedWalls;  // Optional: zone only
+        // zone             ABC;          // Optional: zone only
+        // exposedPatchName fixedWalls;  // Optional: zone only
+
+        // bounds       (1 1 1)(2 2 2); // Optional: limit extent
 
         // regularise      false;    // Optional: do not simplify
         // mergeTol        1e-10;    // Optional: fraction of mesh bounding box
@@ -305,6 +370,8 @@ surfaces
                                 // of isoSurfaceCell
         interpolate     false;
         regularise      false;  // Optional: do not simplify
+        // bounds       (1 1 1)(2 2 2); // Optional: limit extent
+
         // mergeTol 1e-10;      // Optional: fraction of mesh bounding box
                                 // to merge points (default=1e-6)
     }
diff --git a/src/OpenFOAM/meshes/primitiveShapes/triangle/triangle.C b/src/OpenFOAM/meshes/primitiveShapes/triangle/triangle.C
new file mode 100644
index 0000000000000000000000000000000000000000..8085ccd8f0ca7093040c19ca2e9c3e444fd8c4ad
--- /dev/null
+++ b/src/OpenFOAM/meshes/primitiveShapes/triangle/triangle.C
@@ -0,0 +1,242 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2015 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 "triangle.H"
+#include "triPoints.H"
+#include "plane.H"
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class Point, class PointRef>
+template<class AboveOp, class BelowOp>
+inline void Foam::triangle<Point, PointRef>::triSliceWithPlane
+(
+    const plane& pl,
+    const triPoints& tri,
+    AboveOp& aboveOp,
+    BelowOp& belowOp
+)
+{
+    // distance to cutting plane
+    FixedList<scalar, 3> d;
+
+    // determine how many of the points are above the cutting plane
+    label nPos = 0;
+    label posI = -1;
+    label negI = -1;
+    forAll(tri, i)
+    {
+        d[i] = ((tri[i] - pl.refPoint()) & pl.normal());
+
+        if (d[i] > 0)
+        {
+            nPos++;
+            posI = i;
+        }
+        else
+        {
+            negI = i;
+        }
+    }
+
+    if (nPos == 3)
+    {
+        aboveOp(tri);
+    }
+    else if (nPos == 2)
+    {
+        // point under the plane
+        label i0 = negI;
+
+        // indices of remaining points
+        label i1 = d.fcIndex(i0);
+        label i2 = d.fcIndex(i1);
+
+        // determine the two intersection points
+        point p01 = planeIntersection(d, tri, i0, i1);
+        point p02 = planeIntersection(d, tri, i0, i2);
+
+        aboveOp(triPoints(tri[i1], tri[i2], p02));
+        aboveOp(triPoints(tri[i1], p02, p01));
+        belowOp(triPoints(tri[i0], p01, p02));
+    }
+    else if (nPos == 1)
+    {
+        // point above the plane
+        label i0 = posI;
+
+        // indices of remaining points
+        label i1 = d.fcIndex(i0);
+        label i2 = d.fcIndex(i1);
+
+        // determine the two intersection points
+        point p01 = planeIntersection(d, tri, i0, i1);
+        point p02 = planeIntersection(d, tri, i0, i2);
+
+        belowOp(triPoints(tri[i1], tri[i2], p02));
+        belowOp(triPoints(tri[i1], p02, p01));
+        aboveOp(triPoints(tri[i0], p01, p02));
+    }
+    else
+    {
+        // All below
+        belowOp(tri);
+    }
+}
+
+
+template<class Point, class PointRef>
+template<class AboveOp, class BelowOp>
+inline void Foam::triangle<Point, PointRef>::sliceWithPlane
+(
+    const plane& pl,
+    AboveOp& aboveOp,
+    BelowOp& belowOp
+) const
+{
+    triSliceWithPlane(pl, triPoints(a_, b_, c_), aboveOp, belowOp);
+}
+
+
+template<class Point, class PointRef>
+template<class InsideOp, class OutsideOp>
+inline void Foam::triangle<Point, PointRef>::triangleOverlap
+(
+    const vector& n,
+    const triangle<Point, PointRef>& tgt,
+    InsideOp& insideOp,
+    OutsideOp& outsideOp
+) const
+{
+    // There are two possibilities with this algorithm - we either cut
+    // the outside triangles with all the edges or not (and keep them
+    // as disconnected triangles). In the first case
+    // we cannot do any evaluation short cut so we've chosen not to re-cut
+    // the outside triangles.
+
+
+    triIntersectionList insideTrisA;
+    label nInsideA = 0;
+    storeOp insideOpA(insideTrisA, nInsideA);
+
+    triIntersectionList outsideTrisA;
+    label nOutsideA = 0;
+    storeOp outsideOpA(outsideTrisA, nOutsideA);
+
+
+    const triPoints thisTri(a_, b_, c_);
+
+
+    // Cut original triangle with tgt edge 0.
+    // From *this to insideTrisA, outsideTrisA.
+    {
+        scalar s = Foam::mag(tgt.b() - tgt.a());
+        const plane pl0(tgt.a(), tgt.b(), tgt.b() + s*n);
+        triSliceWithPlane(pl0, thisTri, insideOpA, outsideOpA);
+    }
+
+    // Shortcut if nothing cut
+
+    if (insideOpA.nTris_ == 0)
+    {
+        outsideOp(thisTri);
+        return;
+    }
+
+    if (outsideOpA.nTris_ == 0)
+    {
+        insideOp(thisTri);
+        return;
+    }
+
+
+    // Cut all triangles with edge 1.
+    // From insideTrisA to insideTrisB, outsideTrisA
+
+    triIntersectionList insideTrisB;
+    label nInsideB = 0;
+    storeOp insideOpB(insideTrisB, nInsideB);
+
+    //triIntersectionList outsideTrisB;
+    //label nOutsideB = 0;
+    //storeOp outsideOpB(outsideTrisB, nOutsideB);
+
+    {
+        scalar s = Foam::mag(tgt.c() - tgt.b());
+        const plane pl0(tgt.b(), tgt.c(), tgt.c() + s*n);
+
+        for (label i = 0; i < insideOpA.nTris_; i++)
+        {
+            const triPoints& tri = insideOpA.tris_[i];
+            triSliceWithPlane(pl0, tri, insideOpB, outsideOpA);
+        }
+
+        //// Recut outside triangles (not necessary if only interested in
+        //// intersection properties)
+        //for (label i = 0; i < outsideOpA.nTris_; i++)
+        //{
+        //    const triPoints& tri = outsideOpA.tris_[i];
+        //    triSliceWithPlane(pl0, tri, outsideOpB, outsideOpB);
+        //}
+    }
+
+
+    // Cut all triangles with edge 2.
+    // From insideTrisB to insideTrisA, outsideTrisA
+    {
+        scalar s = Foam::mag(tgt.a() - tgt.c());
+        const plane pl0(tgt.c(), tgt.a(), tgt.a() + s*n);
+
+        insideOpA.nTris_ = 0;
+        //outsideOpA.nTris_ = 0;
+        for (label i = 0; i < insideOpB.nTris_; i++)
+        {
+            const triPoints& tri = insideOpB.tris_[i];
+            triSliceWithPlane(pl0, tri, insideOpA, outsideOpA);
+        }
+
+        //// Recut outside triangles (not necessary if only interested in
+        //// intersection properties)
+        //for (label i = 0; i < outsideOpB.nTris_; i++)
+        //{
+        //    const triPoints& tri = outsideOpB.tris_[i];
+        //    triSliceWithPlane(pl0, tri, outsideOpA, outsideOpA);
+        //}
+    }
+
+    // Transfer from A to argument
+    for (label i = 0; i < insideOpA.nTris_; i++)
+    {
+        insideOp(insideOpA.tris_[i]);
+    }
+
+    for (label i = 0; i < outsideOpA.nTris_; i++)
+    {
+        outsideOp(outsideOpA.tris_[i]);
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/primitiveShapes/triangle/triangle.H b/src/OpenFOAM/meshes/primitiveShapes/triangle/triangle.H
index 6e8030c797658bb16108b4d32bad9766d3adaf7f..de477d20e05277b6c1f85660643e43d6ecac312a 100644
--- a/src/OpenFOAM/meshes/primitiveShapes/triangle/triangle.H
+++ b/src/OpenFOAM/meshes/primitiveShapes/triangle/triangle.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -52,6 +52,8 @@ namespace Foam
 
 class Istream;
 class Ostream;
+class triPoints;
+class plane;
 
 // Forward declaration of friend functions and operators
 
@@ -71,6 +73,8 @@ inline Ostream& operator<<
     const triangle<Point, PointRef>&
 );
 
+typedef triangle<point, const point&> triPointRef;
+
 
 /*---------------------------------------------------------------------------*\
                           Class triangle Declaration
@@ -79,27 +83,98 @@ inline Ostream& operator<<
 template<class Point, class PointRef>
 class triangle
 {
+public:
+
+    // Public typedefs
+
+        //- Storage type for triangles originating from intersecting triangle
+        //  with another triangle
+        typedef FixedList<triPoints, 27> triIntersectionList;
+
+        //- Return types for classify
+        enum proxType
+        {
+            NONE,
+            POINT,  // Close to point
+            EDGE    // Close to edge
+        };
+
+
+    // Public classes
+
+        // Classes for use in sliceWithPlane. What to do with decomposition
+        // of triangle.
+
+            //- Dummy
+            class dummyOp
+            {
+            public:
+                inline void operator()(const triPoints&);
+            };
+
+            //- Sum resulting areas
+            class sumAreaOp
+            {
+            public:
+                scalar area_;
+
+                inline sumAreaOp();
+
+                inline void operator()(const triPoints&);
+            };
+
+            //- Store resulting tris
+            class storeOp
+            {
+            public:
+                triIntersectionList& tris_;
+                label& nTris_;
+
+                inline storeOp(triIntersectionList&, label&);
+
+                inline void operator()(const triPoints&);
+            };
+
+
+private:
+
     // Private data
 
         PointRef a_, b_, c_;
 
 
-public:
+   // Private Member Functions
 
-    //- Return types for classify
-    enum proxType
-    {
-        NONE,
-        POINT,  // Close to point
-        EDGE    // Close to edge
-    };
+        //- Helper: calculate intersection point
+        inline static point planeIntersection
+        (
+            const FixedList<scalar, 3>& d,
+            const triPoints& t,
+            const label negI,
+            const label posI
+        );
+
+        //- Helper: slice triangle with plane
+        template<class AboveOp, class BelowOp>
+        inline static void triSliceWithPlane
+        (
+            const plane& pl,
+            const triPoints& tri,
+            AboveOp& aboveOp,
+            BelowOp& belowOp
+        );
 
 
+public:
+
     // Constructors
 
         //- Construct from three points
         inline triangle(const Point& a, const Point& b, const Point& c);
 
+        //- Construct from three points
+        inline triangle(const FixedList<Point, 3>&);
+
         //- Construct from three points in the list of points
         //  The indices could be from triFace etc.
         inline triangle
@@ -237,6 +312,27 @@ public:
                 pointHit& edgePoint
             ) const;
 
+            //- Decompose triangle into triangles above and below plane
+            template<class AboveOp, class BelowOp>
+            inline void sliceWithPlane
+            (
+                const plane& pl,
+                AboveOp& aboveOp,
+                BelowOp& belowOp
+            ) const;
+
+            //- Decompose triangle into triangles inside and outside
+            //  (with respect to user provided normal) other
+            //  triangle.
+            template<class InsideOp, class OutsideOp>
+            inline void triangleOverlap
+            (
+                const vector& n,
+                const triangle<Point, PointRef>& tri,
+                InsideOp& insideOp,
+                OutsideOp& outsideOp
+            ) const;
+
 
     // IOstream operators
 
@@ -264,6 +360,12 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+#ifdef NoRepository
+#   include "triangle.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 #endif
 
 // ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/primitiveShapes/triangle/triangleI.H b/src/OpenFOAM/meshes/primitiveShapes/triangle/triangleI.H
index fbc5a14286b8d5572dcfadff2d1c0280d4ebcde1..e3f8993e2eac9c4c13515c45defb3c810f6e2eaa 100644
--- a/src/OpenFOAM/meshes/primitiveShapes/triangle/triangleI.H
+++ b/src/OpenFOAM/meshes/primitiveShapes/triangle/triangleI.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -25,6 +25,7 @@ License
 
 #include "IOstreams.H"
 #include "pointHit.H"
+#include "triPoints.H"
 #include "mathematicalConstants.H"
 
 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
@@ -43,6 +44,18 @@ inline Foam::triangle<Point, PointRef>::triangle
 {}
 
 
+template<class Point, class PointRef>
+inline Foam::triangle<Point, PointRef>::triangle
+(
+    const FixedList<Point, 3>& tri
+)
+:
+    a_(tri[0]),
+    b_(tri[1]),
+    c_(tri[2])
+{}
+
+
 template<class Point, class PointRef>
 inline Foam::triangle<Point, PointRef>::triangle
 (
@@ -804,6 +817,66 @@ inline Foam::pointHit Foam::triangle<Point, PointRef>::nearestPoint
 }
 
 
+template<class Point, class PointRef>
+inline void Foam::triangle<Point, PointRef>::dummyOp::operator()
+(
+    const triPoints&
+)
+{}
+
+
+template<class Point, class PointRef>
+inline Foam::triangle<Point, PointRef>::sumAreaOp::sumAreaOp()
+:
+    area_(0.0)
+{}
+
+
+template<class Point, class PointRef>
+inline void Foam::triangle<Point, PointRef>::sumAreaOp::operator()
+(
+    const triPoints& tri
+)
+{
+    area_ += triangle<Point, const Point&>(tri).mag();
+}
+
+
+template<class Point, class PointRef>
+inline Foam::triangle<Point, PointRef>::storeOp::storeOp
+(
+    triIntersectionList& tris,
+    label& nTris
+)
+:
+    tris_(tris),
+    nTris_(nTris)
+{}
+
+
+template<class Point, class PointRef>
+inline void Foam::triangle<Point, PointRef>::storeOp::operator()
+(
+    const triPoints& tri
+)
+{
+    tris_[nTris_++] = tri;
+}
+
+
+template<class Point, class PointRef>
+inline Foam::point Foam::triangle<Point, PointRef>::planeIntersection
+(
+    const FixedList<scalar, 3>& d,
+    const triPoints& t,
+    const label negI,
+    const label posI
+)
+{
+    return (d[posI]*t[negI] - d[negI]*t[posI])/(-d[negI] + d[posI]);
+}
+
+
 // * * * * * * * * * * * * * * * Ostream Operator  * * * * * * * * * * * * * //
 
 template<class Point, class PointRef>
diff --git a/src/mesh/extrudeModel/planeExtrusion/planeExtrusion.H b/src/mesh/extrudeModel/planeExtrusion/planeExtrusion.H
index 9fea06cf2c758c665a84d42c6195b34ab0086265..b832f7e2bede3c8bf524a951b241d3c794f7d049 100644
--- a/src/mesh/extrudeModel/planeExtrusion/planeExtrusion.H
+++ b/src/mesh/extrudeModel/planeExtrusion/planeExtrusion.H
@@ -33,8 +33,8 @@ SeeAlso
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef plane_H
-#define plane_H
+#ifndef planeExtrusion_H
+#define planeExtrusion_H
 
 #include "linearNormal.H"
 
diff --git a/src/sampling/sampledSet/patchSeed/patchSeedSet.C b/src/sampling/sampledSet/patchSeed/patchSeedSet.C
index 3560fe42046778b9e36d572a8c59bdd432d9ce36..9cdcc7d230c6b8e2e2117a58265fb55be6e7e436 100644
--- a/src/sampling/sampledSet/patchSeed/patchSeedSet.C
+++ b/src/sampling/sampledSet/patchSeed/patchSeedSet.C
@@ -30,9 +30,8 @@ License
 #include "treeDataFace.H"
 #include "Time.H"
 #include "meshTools.H"
-//#include "Random.H"
-// For 'facePoint' helper function only
 #include "mappedPatchBase.H"
+#include "indirectPrimitivePatch.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -85,19 +84,145 @@ void Foam::patchSeedSet::calcSamples
     }
 
 
-    label totalSize = returnReduce(sz, sumOp<label>());
+    if (!rndGenPtr_.valid())
+    {
+        rndGenPtr_.reset(new Random(0));
+    }
+    Random& rndGen = rndGenPtr_();
+
+
+    if (selectedLocations_.size())
+    {
+        DynamicList<label> newPatchFaces(patchFaces.size());
+
+        // Find the nearest patch face
+        {
+            // 1. All processors find nearest local patch face for all
+            //    selectedLocations
+
+            // All the info for nearest. Construct to miss
+            List<mappedPatchBase::nearInfo> nearest(selectedLocations_.size());
+
+            const indirectPrimitivePatch pp
+            (
+                IndirectList<face>(mesh().faces(), patchFaces),
+                mesh().points()
+            );
+
+            treeBoundBox patchBb
+            (
+                treeBoundBox(pp.points(), pp.meshPoints()).extend
+                (
+                    rndGen,
+                    1e-4
+                )
+            );
+            patchBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
+            patchBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
+
+            indexedOctree<treeDataFace> boundaryTree
+            (
+                treeDataFace    // all information needed to search faces
+                (
+                    false,      // do not cache bb
+                    mesh(),
+                    patchFaces  // boundary faces only
+                ),
+                patchBb,        // overall search domain
+                8,              // maxLevel
+                10,             // leafsize
+                3.0             // duplicity
+            );
+
+            // Get some global dimension so all points are equally likely
+            // to be found
+            const scalar globalDistSqr
+            (
+                //magSqr
+                //(
+                //    boundBox
+                //    (
+                //        pp.points(),
+                //        pp.meshPoints(),
+                //        true
+                //    ).span()
+                //)
+                GREAT
+            );
+
+            forAll(selectedLocations_, sampleI)
+            {
+                const point& sample = selectedLocations_[sampleI];
+
+                pointIndexHit& nearInfo = nearest[sampleI].first();
+                nearInfo = boundaryTree.findNearest
+                (
+                    sample,
+                    globalDistSqr
+                );
+
+                if (!nearInfo.hit())
+                {
+                    nearest[sampleI].second().first() = Foam::sqr(GREAT);
+                    nearest[sampleI].second().second() =
+                        Pstream::myProcNo();
+                }
+                else
+                {
+                    point fc(pp[nearInfo.index()].centre(pp.points()));
+                    nearInfo.setPoint(fc);
+                    nearest[sampleI].second().first() = magSqr(fc-sample);
+                    nearest[sampleI].second().second() =
+                        Pstream::myProcNo();
+                }
+            }
+
+
+            // 2. Reduce on master. Select nearest processor.
+
+            // Find nearest. Combine on master.
+            Pstream::listCombineGather(nearest, mappedPatchBase::nearestEqOp());
+            Pstream::listCombineScatter(nearest);
+
+
+            // 3. Pick up my local faces that have won
+
+            forAll(nearest, sampleI)
+            {
+                if (nearest[sampleI].first().hit())
+                {
+                    label procI = nearest[sampleI].second().second();
+                    label index = nearest[sampleI].first().index();
+
+                    if (procI == Pstream::myProcNo())
+                    {
+                        newPatchFaces.append(pp.addressing()[index]);
+                    }
+                }
+            }
+        }
+
+        if (debug)
+        {
+            Pout<< "Found " << newPatchFaces.size()
+                << " out of " << selectedLocations_.size()
+                << " on local processor" << endl;
+        }
+
+        patchFaces.transfer(newPatchFaces);
+    }
 
 
     // Shuffle and truncate if in random mode
+    label totalSize = returnReduce(patchFaces.size(), sumOp<label>());
+
     if (maxPoints_ < totalSize)
     {
         // Check what fraction of maxPoints_ I need to generate locally.
-        label myMaxPoints = label(scalar(sz)/totalSize*maxPoints_);
+        label myMaxPoints =
+            label(scalar(patchFaces.size())/totalSize*maxPoints_);
 
-        rndGenPtr_.reset(new Random(123456));
-        Random& rndGen = rndGenPtr_();
-
-        labelList subset = identity(sz);
+        labelList subset = identity(patchFaces.size());
         for (label iter = 0; iter < 4; iter++)
         {
             forAll(subset, i)
@@ -115,7 +240,7 @@ void Foam::patchSeedSet::calcSamples
         if (debug)
         {
             Pout<< "In random mode : selected " << patchFaces.size()
-                << " faces out of " << sz << endl;
+                << " faces out of " << patchFaces.size() << endl;
         }
     }
 
@@ -135,6 +260,9 @@ void Foam::patchSeedSet::calcSamples
     forAll(patchFaces, i)
     {
         label faceI = patchFaces[i];
+
+        // Slightly shift point in since on warped face face-diagonal
+        // decomposition might be outside cell for face-centre decomposition!
         pointIndexHit info = mappedPatchBase::facePoint
         (
             mesh(),
@@ -217,9 +345,15 @@ Foam::patchSeedSet::patchSeedSet
             wordReList(dict.lookup("patches"))
         )
     ),
-    //searchDist_(readScalar(dict.lookup("maxDistance"))),
-    //offsetDist_(readScalar(dict.lookup("offsetDist"))),
-    maxPoints_(readLabel(dict.lookup("maxPoints")))
+    maxPoints_(readLabel(dict.lookup("maxPoints"))),
+    selectedLocations_
+    (
+        dict.lookupOrDefault<pointField>
+        (
+            "points",
+            pointField(0)
+        )
+    )
 {
     genSamples();
 
diff --git a/src/sampling/sampledSet/patchSeed/patchSeedSet.H b/src/sampling/sampledSet/patchSeed/patchSeedSet.H
index a6e795ad2be1a9d641efb2cf9418b757792fcfc4..c2143a209852416839b8b6b7b4525dd986601e1f 100644
--- a/src/sampling/sampledSet/patchSeed/patchSeedSet.H
+++ b/src/sampling/sampledSet/patchSeed/patchSeedSet.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2012 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2012-2014 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -58,18 +58,15 @@ class patchSeedSet
         //- Patches to sample
         const labelHashSet patchSet_;
 
-//        //- Maximum distance to look for nearest
-//        const scalar searchDist_;
-//
-//        //- Offset distance
-//        const scalar offsetDist_;
-
-        //- Maximum number of patch faces to seed
+        //- Maximum number of patch faces to seed (if in random subset mode)
         const label maxPoints_;
 
         //- Random number generator (if maxPoints < num patch faces)
         autoPtr<Random> rndGenPtr_;
 
+        //- Patch faces to seed selected based on nearness to supplied points
+        const pointField selectedLocations_;
+
 
     // Private Member Functions
 
diff --git a/src/sampling/sampledSurface/distanceSurface/distanceSurface.C b/src/sampling/sampledSurface/distanceSurface/distanceSurface.C
index 2dafe3e98ad268312e11ca50d68c84a2669b83ec..fd2927ca719e7225fb8e55cfc1c5e72c640745fc 100644
--- a/src/sampling/sampledSurface/distanceSurface/distanceSurface.C
+++ b/src/sampling/sampledSurface/distanceSurface/distanceSurface.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -278,7 +278,8 @@ void Foam::distanceSurface::createGeometry()
                 cellDistance,
                 pointDistance_,
                 distance_,
-                regularise_
+                regularise_,
+                bounds_
             )
         );
     }
@@ -291,7 +292,8 @@ void Foam::distanceSurface::createGeometry()
                 cellDistance,
                 pointDistance_,
                 distance_,
-                regularise_
+                regularise_,
+                bounds_
             )
         );
     }
@@ -336,6 +338,7 @@ Foam::distanceSurface::distanceSurface
     cell_(dict.lookupOrDefault("cell", true)),
     regularise_(dict.lookupOrDefault("regularise", true)),
     average_(dict.lookupOrDefault("average", false)),
+    bounds_(dict.lookupOrDefault("bounds", boundBox::greatBox)),
     zoneKey_(keyType::null),
     needsUpdate_(true),
     isoSurfCellPtr_(NULL),
@@ -364,7 +367,8 @@ Foam::distanceSurface::distanceSurface
     const bool signedDistance,
     const bool cell,
     const Switch regularise,
-    const Switch average
+    const Switch average,
+    const boundBox& bounds
 )
 :
     sampledSurface(name, mesh, interpolate),
@@ -390,6 +394,7 @@ Foam::distanceSurface::distanceSurface
     cell_(cell),
     regularise_(regularise),
     average_(average),
+    bounds_(bounds),
     zoneKey_(keyType::null),
     needsUpdate_(true),
     isoSurfCellPtr_(NULL),
diff --git a/src/sampling/sampledSurface/distanceSurface/distanceSurface.H b/src/sampling/sampledSurface/distanceSurface/distanceSurface.H
index 73cd555e05e35a04dee8c5854745d8ba36fcbfed..aa3f63251144fa3a46ba4140c416070d87b0f3df 100644
--- a/src/sampling/sampledSurface/distanceSurface/distanceSurface.H
+++ b/src/sampling/sampledSurface/distanceSurface/distanceSurface.H
@@ -75,6 +75,9 @@ class distanceSurface
         //- Whether to recalculate cell values as average of point values
         const Switch average_;
 
+        //- Optional bounding box to trim triangles against
+        const boundBox bounds_;
+
         //- If restricted to zones, name of this zone or a regular expression
         keyType zoneKey_;
 
@@ -144,7 +147,8 @@ public:
             const bool signedDistance,
             const bool cell,
             const Switch regularise,
-            const Switch average
+            const Switch average,
+            const boundBox& bounds = boundBox::greatBox
         );
 
 
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurface.C b/src/sampling/sampledSurface/isoSurface/isoSurface.C
index e3105b35a56410fe8c6c1ee73425ac45874fcb95..9dbe88440d49a2e43bdbcff0f96d2f24e34685bb 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurface.C
+++ b/src/sampling/sampledSurface/isoSurface/isoSurface.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -32,12 +32,36 @@ License
 #include "surfaceFields.H"
 #include "OFstream.H"
 #include "meshTools.H"
+#include "triSurfaceSearch.H"
+#include "surfaceIntersection.H"
+#include "intersectedSurface.H"
+#include "searchableBox.H"
+#include "triSurfaceMesh.H"
+#include "triPoints.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
 namespace Foam
 {
 defineTypeNameAndDebug(isoSurface, 0);
+
+// Helper class for slicing triangles
+class storeOp
+{
+public:
+    DynamicList<triPoints>& tris_;
+
+    inline storeOp(DynamicList<triPoints>& tris)
+    :
+        tris_(tris)
+    {}
+
+    inline void operator()(const triPoints& tri)
+    {
+        tris_.append(tri);
+    }
+};
+
 }
 
 
@@ -473,43 +497,6 @@ void Foam::isoSurface::calcCutTypes
 }
 
 
-// Return the two common points between two triangles
-Foam::labelPair Foam::isoSurface::findCommonPoints
-(
-    const labelledTri& tri0,
-    const labelledTri& tri1
-)
-{
-    labelPair common(-1, -1);
-
-    label fp0 = 0;
-    label fp1 = findIndex(tri1, tri0[fp0]);
-
-    if (fp1 == -1)
-    {
-        fp0 = 1;
-        fp1 = findIndex(tri1, tri0[fp0]);
-    }
-
-    if (fp1 != -1)
-    {
-        // So tri0[fp0] is tri1[fp1]
-
-        // Find next common point
-        label fp0p1 = tri0.fcIndex(fp0);
-        label fp1p1 = tri1.fcIndex(fp1);
-        label fp1m1 = tri1.rcIndex(fp1);
-
-        if (tri0[fp0p1] == tri1[fp1p1] || tri0[fp0p1] == tri1[fp1m1])
-        {
-            common[0] = tri0[fp0];
-            common[1] = tri0[fp0p1];
-        }
-    }
-    return common;
-}
-
-
 // Caculate centre of surface.
 Foam::point Foam::isoSurface::calcCentre(const triSurface& s)
 {
@@ -523,73 +510,6 @@ Foam::point Foam::isoSurface::calcCentre(const triSurface& s)
 }
 
 
-// Replace surface (localPoints, localTris) with single point. Returns
-// point. Destructs arguments.
-Foam::pointIndexHit Foam::isoSurface::collapseSurface
-(
-    pointField& localPoints,
-    DynamicList<labelledTri, 64>& localTris
-)
-{
-    pointIndexHit info(false, vector::zero, localTris.size());
-
-    if (localTris.size() == 1)
-    {
-        const labelledTri& tri = localTris[0];
-        info.setPoint(tri.centre(localPoints));
-        info.setHit();
-    }
-    else if (localTris.size() == 2)
-    {
-        // Check if the two triangles share an edge.
-        const labelledTri& tri0 = localTris[0];
-        const labelledTri& tri1 = localTris[0];
-
-        labelPair shared = findCommonPoints(tri0, tri1);
-
-        if (shared[0] != -1)
-        {
-            info.setPoint
-            (
-                0.5
-              * (
-                    tri0.centre(localPoints)
-                  + tri1.centre(localPoints)
-                )
-            );
-            info.setHit();
-        }
-    }
-    else if (localTris.size())
-    {
-        // Check if single region. Rare situation.
-        triSurface surf
-        (
-            localTris,
-            geometricSurfacePatchList(0),
-            localPoints,
-            true
-        );
-        localTris.clearStorage();
-
-        labelList faceZone;
-        label nZones = surf.markZones
-        (
-            boolList(surf.nEdges(), false),
-            faceZone
-        );
-
-        if (nZones == 1)
-        {
-            info.setPoint(calcCentre(surf));
-            info.setHit();
-        }
-    }
-
-    return info;
-}
-
-
 // Determine per cell centre whether all the intersections get collapsed
 // to a single point
 void Foam::isoSurface::calcSnappedCc
@@ -1133,505 +1053,288 @@ Foam::triSurface Foam::isoSurface::stitchTriPoints
 }
 
 
-// Does face use valid vertices?
-bool Foam::isoSurface::validTri(const triSurface& surf, const label faceI)
+void Foam::isoSurface::trimToPlanes
+(
+    const PtrList<plane>& planes,
+    const triPointRef& tri,
+    DynamicList<point>& newTriPoints
+)
 {
-    // Simple check on indices ok.
-
-    const labelledTri& f = surf[faceI];
+    // Buffer for generated triangles
+    DynamicList<triPoints> insideTrisA;
+    storeOp insideOpA(insideTrisA);
 
-    if
-    (
-        (f[0] < 0) || (f[0] >= surf.points().size())
-     || (f[1] < 0) || (f[1] >= surf.points().size())
-     || (f[2] < 0) || (f[2] >= surf.points().size())
-    )
-    {
-        WarningIn("validTri(const triSurface&, const label)")
-            << "triangle " << faceI << " vertices " << f
-            << " uses point indices outside point range 0.."
-            << surf.points().size()-1 << endl;
+    // Buffer for generated triangles
+    DynamicList<triPoints> insideTrisB;
+    storeOp insideOpB(insideTrisB);
 
-        return false;
-    }
+    triPointRef::dummyOp dop;
 
-    if ((f[0] == f[1]) || (f[0] == f[2]) || (f[1] == f[2]))
-    {
-        WarningIn("validTri(const triSurface&, const label)")
-            << "triangle " << faceI
-            << " uses non-unique vertices " << f
-            << endl;
-        return false;
-    }
+    // Store starting triangle in insideTrisA
+    insideOpA(triPoints(tri.a(), tri.b(), tri.c()));
 
-    // duplicate triangle check
 
-    const labelList& fFaces = surf.faceFaces()[faceI];
+    bool useA = true;
 
-    // Check if faceNeighbours use same points as this face.
-    // Note: discards normal information - sides of baffle are merged.
-    forAll(fFaces, i)
+    forAll(planes, faceI)
     {
-        label nbrFaceI = fFaces[i];
+        const plane& pl = planes[faceI];
 
-        if (nbrFaceI <= faceI)
+        if (useA)
         {
-            // lower numbered faces already checked
-            continue;
+            insideOpB.tris_.clear();
+            forAll(insideOpA.tris_, i)
+            {
+                const triPoints& tri = insideOpA.tris_[i];
+                triPointRef(tri).sliceWithPlane(pl, insideOpB, dop);
+            }
+        }
+        else
+        {
+            insideOpA.tris_.clear();
+            forAll(insideOpB.tris_, i)
+            {
+                const triPoints& tri = insideOpB.tris_[i];
+                triPointRef(tri).sliceWithPlane(pl, insideOpA, dop);
+            }
         }
+        useA = !useA;
+    }
 
-        const labelledTri& nbrF = surf[nbrFaceI];
 
-        if
-        (
-            ((f[0] == nbrF[0]) || (f[0] == nbrF[1]) || (f[0] == nbrF[2]))
-         && ((f[1] == nbrF[0]) || (f[1] == nbrF[1]) || (f[1] == nbrF[2]))
-         && ((f[2] == nbrF[0]) || (f[2] == nbrF[1]) || (f[2] == nbrF[2]))
-        )
+    // Transfer
+    if (useA)
+    {
+        forAll(insideOpA.tris_, i)
         {
-            WarningIn("validTri(const triSurface&, const label)")
-                << "triangle " << faceI << " vertices " << f
-                << " fc:" << f.centre(surf.points())
-                << " has the same vertices as triangle " << nbrFaceI
-                << " vertices " << nbrF
-                << " fc:" << nbrF.centre(surf.points())
-                << endl;
-
-            return false;
+            const triPoints& tri = insideOpA.tris_[i];
+            newTriPoints.append(tri[0]);
+            newTriPoints.append(tri[1]);
+            newTriPoints.append(tri[2]);
+        }
+    }
+    else
+    {
+        forAll(insideOpB.tris_, i)
+        {
+            const triPoints& tri = insideOpB.tris_[i];
+            newTriPoints.append(tri[0]);
+            newTriPoints.append(tri[1]);
+            newTriPoints.append(tri[2]);
         }
     }
-    return true;
 }
 
 
-void Foam::isoSurface::calcAddressing
+void Foam::isoSurface::trimToBox
 (
-    const triSurface& surf,
-    List<FixedList<label, 3> >& faceEdges,
-    labelList& edgeFace0,
-    labelList& edgeFace1,
-    Map<labelList>& edgeFacesRest
-) const
+    const treeBoundBox& bb,
+    DynamicList<point>& triPoints,
+    DynamicList<label>& triMap      // trimmed to original tris
+)
 {
-    const pointField& points = surf.points();
-
-    pointField edgeCentres(3*surf.size());
-    label edgeI = 0;
-    forAll(surf, triI)
-    {
-        const labelledTri& tri = surf[triI];
-        edgeCentres[edgeI++] = 0.5*(points[tri[0]]+points[tri[1]]);
-        edgeCentres[edgeI++] = 0.5*(points[tri[1]]+points[tri[2]]);
-        edgeCentres[edgeI++] = 0.5*(points[tri[2]]+points[tri[0]]);
-    }
-
-    pointField mergedCentres;
-    labelList oldToMerged;
-    bool hasMerged = mergePoints
-    (
-        edgeCentres,
-        mergeDistance_,
-        false,
-        oldToMerged,
-        mergedCentres
-    );
-
     if (debug)
     {
-        Pout<< "isoSurface : detected "
-            << mergedCentres.size()
-            << " geometric edges on " << surf.size() << " triangles." << endl;
-    }
-
-    if (!hasMerged)
-    {
-        return;
+        Pout<< "isoSurface : trimming to " << bb << endl;
     }
 
-
-    // Determine faceEdges
-    faceEdges.setSize(surf.size());
-    edgeI = 0;
-    forAll(surf, triI)
+    // Generate inwards pointing planes
+    PtrList<plane> planes(6);
+    const pointField pts(bb.treeBoundBox::points());
+    forAll(treeBoundBox::faces, faceI)
     {
-        faceEdges[triI][0] = oldToMerged[edgeI++];
-        faceEdges[triI][1] = oldToMerged[edgeI++];
-        faceEdges[triI][2] = oldToMerged[edgeI++];
+        const face& f = treeBoundBox::faces[faceI];
+        const vector& n = treeBoundBox::faceNormals[faceI];
+        planes.set(faceI, new plane(pts[f[0]], -n));
     }
 
+    label nTris = triPoints.size()/3;
 
-    // Determine edgeFaces
-    edgeFace0.setSize(mergedCentres.size());
-    edgeFace0 = -1;
-    edgeFace1.setSize(mergedCentres.size());
-    edgeFace1 = -1;
-    edgeFacesRest.clear();
-
-    // Overflow edge faces for geometric shared edges that turned
-    // out to be different anyway.
-    EdgeMap<labelList> extraEdgeFaces(mergedCentres.size()/100);
+    DynamicList<point> newTriPoints(triPoints.size()/16);
+    triMap.setCapacity(nTris/16);
 
-    forAll(oldToMerged, oldEdgeI)
+    label vertI = 0;
+    for (label triI = 0; triI < nTris; triI++)
     {
-        label triI = oldEdgeI / 3;
-        label edgeI = oldToMerged[oldEdgeI];
+        const point& p0 = triPoints[vertI++];
+        const point& p1 = triPoints[vertI++];
+        const point& p2 = triPoints[vertI++];
+
+        label oldNPoints = newTriPoints.size();
+        trimToPlanes
+        (
+            planes,
+            triPointRef(p0, p1, p2),
+            newTriPoints
+        );
 
-        if (edgeFace0[edgeI] == -1)
+        label nCells = (newTriPoints.size()-oldNPoints)/3;
+        for (label i = 0; i < nCells; i++)
         {
-            // First triangle for edge
-            edgeFace0[edgeI] = triI;
+            triMap.append(triI);
         }
-        else
-        {
-            //- Check that the two triangles actually topologically
-            //  share an edge
-            const labelledTri& prevTri = surf[edgeFace0[edgeI]];
-            const labelledTri& tri = surf[triI];
+    }
 
-            label fp = oldEdgeI % 3;
+    if (debug)
+    {
+        Pout<< "isoSurface : trimmed from " << nTris
+            << " down to " << triMap.size()
+            << " triangles." << endl;
+    }
 
-            edge e(tri[fp], tri[tri.fcIndex(fp)]);
+    triPoints.transfer(newTriPoints);
+}
 
-            label prevTriIndex = -1;
 
-            forAll(prevTri, i)
-            {
-                if (edge(prevTri[i], prevTri[prevTri.fcIndex(i)]) == e)
-                {
-                    prevTriIndex = i;
-                    break;
-                }
-            }
+void Foam::isoSurface::trimToBox
+(
+    const treeBoundBox& bb,
+    DynamicList<point>& triPoints,  // new points
+    DynamicList<label>& triMap,     // map from (new) triangle to original
+    labelList& triPointMap,         // map from (new) point to original
+    labelList& interpolatedPoints,  // labels of newly introduced points
+    List<FixedList<label, 3> >& interpolatedOldPoints,// and their interpolation
+    List<FixedList<scalar, 3> >& interpolationWeights
+)
+{
+    const List<point> oldTriPoints(triPoints);
 
-            if (prevTriIndex == -1)
-            {
-                // Different edge. Store for later.
-                EdgeMap<labelList>::iterator iter = extraEdgeFaces.find(e);
+    // Trim triPoints, return map
+    trimToBox(bb, triPoints, triMap);
 
-                if (iter != extraEdgeFaces.end())
-                {
-                    labelList& eFaces = iter();
-                    label sz = eFaces.size();
-                    eFaces.setSize(sz+1);
-                    eFaces[sz] = triI;
-                }
-                else
-                {
-                    extraEdgeFaces.insert(e, labelList(1, triI));
-                }
-            }
-            else if (edgeFace1[edgeI] == -1)
-            {
-                edgeFace1[edgeI] = triI;
-            }
-            else
-            {
-                //WarningIn("orientSurface(triSurface&)")
-                //    << "Edge " << edgeI << " with centre "
-                //    << mergedCentres[edgeI]
-                //    << " used by more than two triangles: "
-                //    << edgeFace0[edgeI] << ", "
-                //    << edgeFace1[edgeI] << " and " << triI << endl;
-                Map<labelList>::iterator iter = edgeFacesRest.find(edgeI);
-
-                if (iter != edgeFacesRest.end())
-                {
-                    labelList& eFaces = iter();
-                    label sz = eFaces.size();
-                    eFaces.setSize(sz+1);
-                    eFaces[sz] = triI;
-                }
-                else
-                {
-                    edgeFacesRest.insert(edgeI, labelList(1, triI));
-                }
-            }
-        }
-    }
 
-    // Add extraEdgeFaces
-    edgeI = edgeFace0.size();
+    // Find point correspondence:
+    // - one-to-one for preserved original points (triPointMap)
+    // - interpolation for newly introduced points
+    //   (interpolatedOldPoints)
+    label sz = oldTriPoints.size()/100;
+    DynamicList<label> dynInterpolatedPoints(sz);
+    DynamicList<FixedList<label, 3> > dynInterpolatedOldPoints(sz);
+    DynamicList<FixedList<scalar, 3> > dynInterpolationWeights(sz);
 
-    edgeFace0.setSize(edgeI + extraEdgeFaces.size());
-    edgeFace1.setSize(edgeI + extraEdgeFaces.size(), -1);
 
-    forAllConstIter(EdgeMap<labelList>, extraEdgeFaces, iter)
+    triPointMap.setSize(triPoints.size());
+    forAll(triMap, triI)
     {
-        const labelList& eFaces = iter();
+        label oldTriI = triMap[triI];
 
-        // The current edge will become edgeI. Replace all occurrences in
-        // faceEdges
-        forAll(eFaces, i)
+        // Find point correspondence. Assumes coordinate is bit-copy.
+        for (label i = 0; i < 3; i++)
         {
-            label triI = eFaces[i];
-            const labelledTri& tri = surf[triI];
+            label pointI = 3*triI+i;
+            const point& pt = triPoints[pointI];
 
-            FixedList<label, 3>& fEdges = faceEdges[triI];
-            forAll(tri, fp)
+            // Compare to old-triangle's points
+            label matchPointI = -1;
+            for (label j = 0; j < 3; j++)
             {
-                edge e(tri[fp], tri[tri.fcIndex(fp)]);
-
-                if (e == iter.key())
+                label oldPointI = 3*oldTriI+j;
+                if (pt == oldTriPoints[oldPointI])
                 {
-                    fEdges[fp] = edgeI;
+                    matchPointI = oldPointI;
                     break;
                 }
             }
-        }
-
 
-        // Add face to edgeFaces
-
-        edgeFace0[edgeI] = eFaces[0];
-
-        if (eFaces.size() >= 2)
-        {
-            edgeFace1[edgeI] = eFaces[1];
+            triPointMap[pointI] = matchPointI;
 
-            if (eFaces.size() > 2)
+            // If new point: calculate and store interpolation
+            if (matchPointI == -1)
             {
-                edgeFacesRest.insert
-                (
-                    edgeI,
-                    SubList<label>(eFaces, eFaces.size()-2, 2)
-                );
+                dynInterpolatedPoints.append(pointI);
+
+                FixedList<label, 3> oldPoints;
+                oldPoints[0] = 3*oldTriI;
+                oldPoints[1] = 3*oldTriI+1;
+                oldPoints[2] = 3*oldTriI+2;
+                dynInterpolatedOldPoints.append(oldPoints);
+
+                triPointRef tri(oldTriPoints, oldPoints);
+                scalarList bary;
+                tri.barycentric(pt, bary);
+                FixedList<scalar, 3> weights;
+                weights[0] = bary[0];
+                weights[1] = bary[1];
+                weights[2] = bary[2];
+                dynInterpolationWeights.append(weights);
             }
         }
-
-        edgeI++;
     }
-}
-
-
-void Foam::isoSurface::walkOrientation
-(
-    const triSurface& surf,
-    const List<FixedList<label, 3> >& faceEdges,
-    const labelList& edgeFace0,
-    const labelList& edgeFace1,
-    const label seedTriI,
-    labelList& flipState
-)
-{
-    // Do walk for consistent orientation.
-    DynamicList<label> changedFaces(surf.size());
-
-    changedFaces.append(seedTriI);
-
-    while (changedFaces.size())
-    {
-        DynamicList<label> newChangedFaces(changedFaces.size());
 
-        forAll(changedFaces, i)
-        {
-            label triI = changedFaces[i];
-            const labelledTri& tri = surf[triI];
-            const FixedList<label, 3>& fEdges = faceEdges[triI];
-
-            forAll(fEdges, fp)
-            {
-                label edgeI = fEdges[fp];
-
-                // my points:
-                label p0 = tri[fp];
-                label p1 = tri[tri.fcIndex(fp)];
-
-                label nbrI =
-                (
-                    edgeFace0[edgeI] != triI
-                  ? edgeFace0[edgeI]
-                  : edgeFace1[edgeI]
-                );
-
-                if (nbrI != -1 && flipState[nbrI] == -1)
-                {
-                    const labelledTri& nbrTri = surf[nbrI];
-
-                    // nbr points
-                    label nbrFp = findIndex(nbrTri, p0);
-
-                    if (nbrFp == -1)
-                    {
-                        FatalErrorIn("isoSurface::walkOrientation(..)")
-                            << "triI:" << triI
-                            << " tri:" << tri
-                            << " p0:" << p0
-                            << " p1:" << p1
-                            << " fEdges:" << fEdges
-                            << " edgeI:" << edgeI
-                            << " edgeFace0:" << edgeFace0[edgeI]
-                            << " edgeFace1:" << edgeFace1[edgeI]
-                            << " nbrI:" << nbrI
-                            << " nbrTri:" << nbrTri
-                            << abort(FatalError);
-                    }
-
-
-                    label nbrP1 = nbrTri[nbrTri.rcIndex(nbrFp)];
-
-                    bool sameOrientation = (p1 == nbrP1);
-
-                    if (flipState[triI] == 0)
-                    {
-                        flipState[nbrI] = (sameOrientation ? 0 : 1);
-                    }
-                    else
-                    {
-                        flipState[nbrI] = (sameOrientation ? 1 : 0);
-                    }
-                    newChangedFaces.append(nbrI);
-                }
-            }
-        }
-
-        changedFaces.transfer(newChangedFaces);
-    }
+    interpolatedPoints.transfer(dynInterpolatedPoints);
+    interpolatedOldPoints.transfer(dynInterpolatedOldPoints);
+    interpolationWeights.transfer(dynInterpolationWeights);
 }
 
 
-void Foam::isoSurface::orientSurface
-(
-    triSurface& surf,
-    const List<FixedList<label, 3> >& faceEdges,
-    const labelList& edgeFace0,
-    const labelList& edgeFace1,
-    const Map<labelList>& edgeFacesRest
-)
+// Does face use valid vertices?
+bool Foam::isoSurface::validTri(const triSurface& surf, const label faceI)
 {
-    // -1 : unvisited
-    //  0 : leave as is
-    //  1 : flip
-    labelList flipState(surf.size(), -1);
-
-    label seedTriI = 0;
-
-    while (true)
-    {
-        // Find first unvisited triangle
-        for
-        (
-            ;
-            seedTriI < surf.size() && flipState[seedTriI] != -1;
-            seedTriI++
-        )
-        {}
-
-        if (seedTriI == surf.size())
-        {
-            break;
-        }
-
-        // Note: Determine orientation of seedTriI?
-        // for now assume it is ok
-        flipState[seedTriI] = 0;
+    // Simple check on indices ok.
 
-        walkOrientation
-        (
-            surf,
-            faceEdges,
-            edgeFace0,
-            edgeFace1,
-            seedTriI,
-            flipState
-        );
-    }
+    const labelledTri& f = surf[faceI];
 
-    // Do actual flipping
-    surf.clearOut();
-    forAll(surf, triI)
+    if
+    (
+        (f[0] < 0) || (f[0] >= surf.points().size())
+     || (f[1] < 0) || (f[1] >= surf.points().size())
+     || (f[2] < 0) || (f[2] >= surf.points().size())
+    )
     {
-        if (flipState[triI] == 1)
-        {
-            labelledTri tri(surf[triI]);
-
-            surf[triI][0] = tri[0];
-            surf[triI][1] = tri[2];
-            surf[triI][2] = tri[1];
-        }
-        else if (flipState[triI] == -1)
-        {
-            FatalErrorIn
-            (
-                "isoSurface::orientSurface(triSurface&, const label)"
-            )   << "problem" << abort(FatalError);
-        }
-    }
-}
-
+        WarningIn("validTri(const triSurface&, const label)")
+            << "triangle " << faceI << " vertices " << f
+            << " uses point indices outside point range 0.."
+            << surf.points().size()-1 << endl;
 
-// Checks if triangle is connected through edgeI only.
-bool Foam::isoSurface::danglingTriangle
-(
-    const FixedList<label, 3>& fEdges,
-    const labelList& edgeFace1
-)
-{
-    label nOpen = 0;
-    forAll(fEdges, i)
-    {
-        if (edgeFace1[fEdges[i]] == -1)
-        {
-            nOpen++;
-        }
+        return false;
     }
 
-    if (nOpen == 1 || nOpen == 2 || nOpen == 3)
-    {
-        return true;
-    }
-    else
+    if ((f[0] == f[1]) || (f[0] == f[2]) || (f[1] == f[2]))
     {
+        WarningIn("validTri(const triSurface&, const label)")
+            << "triangle " << faceI
+            << " uses non-unique vertices " << f
+            << endl;
         return false;
     }
-}
 
+    // duplicate triangle check
 
-// Mark triangles to keep. Returns number of dangling triangles.
-Foam::label Foam::isoSurface::markDanglingTriangles
-(
-    const List<FixedList<label, 3> >& faceEdges,
-    const labelList& edgeFace0,
-    const labelList& edgeFace1,
-    const Map<labelList>& edgeFacesRest,
-    boolList& keepTriangles
-)
-{
-    keepTriangles.setSize(faceEdges.size());
-    keepTriangles = true;
-
-    label nDangling = 0;
+    const labelList& fFaces = surf.faceFaces()[faceI];
 
-    // Remove any dangling triangles
-    forAllConstIter(Map<labelList>,  edgeFacesRest, iter)
+    // Check if faceNeighbours use same points as this face.
+    // Note: discards normal information - sides of baffle are merged.
+    forAll(fFaces, i)
     {
-        // These are all the non-manifold edges. Filter out all triangles
-        // with only one connected edge (= this edge)
-
-        label edgeI = iter.key();
-        const labelList& otherEdgeFaces = iter();
+        label nbrFaceI = fFaces[i];
 
-        // Remove all dangling triangles
-        if (danglingTriangle(faceEdges[edgeFace0[edgeI]], edgeFace1))
-        {
-            keepTriangles[edgeFace0[edgeI]] = false;
-            nDangling++;
-        }
-        if (danglingTriangle(faceEdges[edgeFace1[edgeI]], edgeFace1))
+        if (nbrFaceI <= faceI)
         {
-            keepTriangles[edgeFace1[edgeI]] = false;
-            nDangling++;
+            // lower numbered faces already checked
+            continue;
         }
-        forAll(otherEdgeFaces, i)
+
+        const labelledTri& nbrF = surf[nbrFaceI];
+
+        if
+        (
+            ((f[0] == nbrF[0]) || (f[0] == nbrF[1]) || (f[0] == nbrF[2]))
+         && ((f[1] == nbrF[0]) || (f[1] == nbrF[1]) || (f[1] == nbrF[2]))
+         && ((f[2] == nbrF[0]) || (f[2] == nbrF[1]) || (f[2] == nbrF[2]))
+        )
         {
-            label triI = otherEdgeFaces[i];
-            if (danglingTriangle(faceEdges[triI], edgeFace1))
-            {
-                keepTriangles[triI] = false;
-                nDangling++;
-            }
+            WarningIn("validTri(const triSurface&, const label)")
+                << "triangle " << faceI << " vertices " << f
+                << " fc:" << f.centre(surf.points())
+                << " has the same vertices as triangle " << nbrFaceI
+                << " vertices " << nbrF
+                << " fc:" << nbrF.centre(surf.points())
+                << endl;
+
+            return false;
         }
     }
-    return nDangling;
+    return true;
 }
 
 
@@ -1715,6 +1418,7 @@ Foam::isoSurface::isoSurface
     const scalarField& pVals,
     const scalar iso,
     const bool regularise,
+    const boundBox& bounds,
     const scalar mergeTol
 )
 :
@@ -1722,6 +1426,7 @@ Foam::isoSurface::isoSurface
     pVals_(pVals),
     iso_(iso),
     regularise_(regularise),
+    bounds_(bounds),
     mergeDistance_(mergeTol*mesh_.bounds().mag())
 {
     if (debug)
@@ -1957,138 +1662,115 @@ Foam::isoSurface::isoSurface
     }
 
 
-
-    DynamicList<point> triPoints(nCutCells_);
-    DynamicList<label> triMeshCells(nCutCells_);
-
-    generateTriPoints
-    (
-        cValsPtr_(),
-        pVals_,
-
-        meshC,
-        mesh_.points(),
-
-        snappedPoints,
-        snappedCc,
-        snappedPoint,
-
-        triPoints,
-        triMeshCells
-    );
-
-    if (debug)
     {
-        Pout<< "isoSurface : generated " << triMeshCells.size()
-            << " unmerged triangles from " << triPoints.size()
-            << " unmerged points." << endl;
-    }
+        DynamicList<point> triPoints(3*nCutCells_);
+        DynamicList<label> triMeshCells(nCutCells_);
 
-
-    // Merge points and compact out non-valid triangles
-    labelList triMap;           // merged to unmerged triangle
-    triSurface::operator=
-    (
-        stitchTriPoints
+        generateTriPoints
         (
-            true,               // check for duplicate tris
-            triPoints,
-            triPointMergeMap_,  // unmerged to merged point
-            triMap
-        )
-    );
+            cValsPtr_(),
+            pVals_,
 
-    if (debug)
-    {
-        Pout<< "isoSurface : generated " << triMap.size()
-            << " merged triangles." << endl;
-    }
+            meshC,
+            mesh_.points(),
 
-    meshCells_.setSize(triMap.size());
-    forAll(triMap, i)
-    {
-        meshCells_[i] = triMeshCells[triMap[i]];
-    }
+            snappedPoints,
+            snappedCc,
+            snappedPoint,
 
-    if (debug)
-    {
-        Pout<< "isoSurface : checking " << size()
-            << " triangles for validity." << endl;
+            triPoints,      // 3 points of the triangle
+            triMeshCells    // per triangle the originating cell
+        );
 
-        forAll(*this, triI)
+        if (debug)
         {
-            // Copied from surfaceCheck
-            validTri(*this, triI);
+            Pout<< "isoSurface : generated " << triMeshCells.size()
+                << " unmerged triangles from " << triPoints.size()
+                << " unmerged points." << endl;
         }
-    }
-
-
-    if (false)
-    {
-        List<FixedList<label, 3> > faceEdges;
-        labelList edgeFace0, edgeFace1;
-        Map<labelList> edgeFacesRest;
 
+        label nOldPoints = triPoints.size();
 
-        while (true)
+        // Trimmed to original triangle
+        DynamicList<label> trimTriMap;
+        // Trimmed to original point
+        labelList trimTriPointMap;
+        if (bounds_ != boundBox::greatBox)
         {
-            // Calculate addressing
-            calcAddressing
+            trimToBox
             (
-                *this,
-                faceEdges,
-                edgeFace0,
-                edgeFace1,
-                edgeFacesRest
+                treeBoundBox(bounds_),
+                triPoints,              // new points
+                trimTriMap,             // map from (new) triangle to original
+                trimTriPointMap,        // map from (new) point to original
+                interpolatedPoints_,    // labels of newly introduced points
+                interpolatedOldPoints_, // and their interpolation
+                interpolationWeights_
             );
+            triMeshCells = labelField(triMeshCells, trimTriMap);
+        }
 
-            // See if any dangling triangles
-            boolList keepTriangles;
-            label nDangling = markDanglingTriangles
+
+        // Merge points and compact out non-valid triangles
+        labelList triMap;           // merged to unmerged triangle
+        triSurface::operator=
+        (
+            stitchTriPoints
             (
-                faceEdges,
-                edgeFace0,
-                edgeFace1,
-                edgeFacesRest,
-                keepTriangles
-            );
+                true,               // check for duplicate tris
+                triPoints,
+                triPointMergeMap_,  // unmerged to merged point
+                triMap
+            )
+        );
 
-            if (debug)
-            {
-                Pout<< "isoSurface : detected " << nDangling
-                    << " dangling triangles." << endl;
-            }
+        if (debug)
+        {
+            Pout<< "isoSurface : generated " << triMap.size()
+                << " merged triangles." << endl;
+        }
 
-            if (nDangling == 0)
-            {
-                break;
-            }
 
-            // Create face map (new to old)
-            labelList subsetTriMap(findIndices(keepTriangles, true));
+        if (bounds_ != boundBox::greatBox)
+        {
+            // Adjust interpolatedPoints_
+            inplaceRenumber(triPointMergeMap_, interpolatedPoints_);
 
-            labelList subsetPointMap;
-            labelList reversePointMap;
-            triSurface::operator=
-            (
-                subsetMesh
-                (
-                    *this,
-                    subsetTriMap,
-                    reversePointMap,
-                    subsetPointMap
-                )
-            );
-            meshCells_ = labelField(meshCells_, subsetTriMap);
-            inplaceRenumber(reversePointMap, triPointMergeMap_);
+            // Adjust triPointMergeMap_
+            labelList newTriPointMergeMap(nOldPoints, -1);
+            forAll(trimTriPointMap, trimPointI)
+            {
+                label oldPointI = trimTriPointMap[trimPointI];
+                if (oldPointI >= 0)
+                {
+                    label pointI = triPointMergeMap_[trimPointI];
+                    if (pointI >= 0)
+                    {
+                        newTriPointMergeMap[oldPointI] = pointI;
+                    }
+                }
+            }
+            triPointMergeMap_.transfer(newTriPointMergeMap);
         }
 
-        orientSurface(*this, faceEdges, edgeFace0, edgeFace1, edgeFacesRest);
+        meshCells_.setSize(triMap.size());
+        forAll(triMap, i)
+        {
+            meshCells_[i] = triMeshCells[triMap[i]];
+        }
     }
 
-
     if (debug)
     {
+        Pout<< "isoSurface : checking " << size()
+            << " triangles for validity." << endl;
+
+        forAll(*this, triI)
+        {
+            // Copied from surfaceCheck
+            validTri(*this, triI);
+        }
+
         fileName stlFile = mesh_.time().path() + ".stl";
         Pout<< "Dumping surface to " << stlFile << endl;
         triSurface::write(stlFile);
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurface.H b/src/sampling/sampledSurface/isoSurface/isoSurface.H
index 9f6dc7d76e0318abe34e3455c9ffeb9bd0de77b1..c74586a2ce1f4f1ee07aa9f59261582beef3339b 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurface.H
+++ b/src/sampling/sampledSurface/isoSurface/isoSurface.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -76,6 +76,8 @@ namespace Foam
 {
 
 class fvMesh;
+class plane;
+class treeBoundBox;
 
 /*---------------------------------------------------------------------------*\
                        Class isoSurface Declaration
@@ -116,10 +118,12 @@ class isoSurface
         //- Regularise?
         const Switch regularise_;
 
+        //- Optional bounds
+        const boundBox bounds_;
+
         //- When to merge points
         const scalar mergeDistance_;
 
-
         //- Whether face might be cut
         List<cellCutType> faceCutType_;
 
@@ -135,6 +139,15 @@ class isoSurface
         //- For every unmerged triangle point the point in the triSurface
         labelList triPointMergeMap_;
 
+        //- triSurface points that have weighted interpolation
+        DynamicList<label> interpolatedPoints_;
+
+        //- corresponding original, unmerged points
+        DynamicList<FixedList<label, 3> > interpolatedOldPoints_;
+
+        //- corresponding weights
+        DynamicList<FixedList<scalar, 3> > interpolationWeights_;
+
 
     // Private Member Functions
 
@@ -193,20 +206,8 @@ class isoSurface
             const scalarField& pVals
         );
 
-        static labelPair findCommonPoints
-        (
-            const labelledTri&,
-            const labelledTri&
-        );
-
         static point calcCentre(const triSurface&);
 
-        static pointIndexHit collapseSurface
-        (
-            pointField& localPoints,
-            DynamicList<labelledTri, 64>& localTris
-        );
-
         //- Determine per cc whether all near cuts can be snapped to single
         //  point.
         void calcSnappedCc
@@ -323,6 +324,17 @@ class isoSurface
             DynamicList<label>& triMeshCells
         ) const;
 
+        template<class Type>
+        static tmp<Field<Type> > interpolate
+        (
+            const label nPoints,
+            const labelList& triPointMergeMap,
+            const labelList& interpolatedPoints,
+            const List<FixedList<label, 3> >& interpolatedOldPoints,
+            const List<FixedList<scalar, 3> >& interpolationWeights,
+            const DynamicList<Type>& unmergedValues
+        );
+
         triSurface stitchTriPoints
         (
             const bool checkDuplicates,
@@ -331,56 +343,37 @@ class isoSurface
             labelList& triMap               // merged to unmerged triangle
         ) const;
 
-        //- Check single triangle for (topological) validity
-        static bool validTri(const triSurface&, const label);
-
-        //- Determine edge-face addressing
-        void calcAddressing
-        (
-            const triSurface& surf,
-            List<FixedList<label, 3> >& faceEdges,
-            labelList& edgeFace0,
-            labelList& edgeFace1,
-            Map<labelList>& edgeFacesRest
-        ) const;
-
-        //- Determine orientation
-        static void walkOrientation
+        //- Trim triangle to planes
+        static void trimToPlanes
         (
-            const triSurface& surf,
-            const List<FixedList<label, 3> >& faceEdges,
-            const labelList& edgeFace0,
-            const labelList& edgeFace1,
-            const label seedTriI,
-            labelList& flipState
+            const PtrList<plane>& planes,
+            const triPointRef& tri,
+            DynamicList<point>& newTriPoints
         );
 
-        //- Orient surface
-        static void orientSurface
+        //- Trim all triangles to box
+        static void trimToBox
         (
-            triSurface&,
-            const List<FixedList<label, 3> >& faceEdges,
-            const labelList& edgeFace0,
-            const labelList& edgeFace1,
-            const Map<labelList>& edgeFacesRest
+            const treeBoundBox& bb,
+            DynamicList<point>& triPoints,
+            DynamicList<label>& triMeshCells
         );
 
-        //- Is triangle (given by 3 edges) not fully connected?
-        static bool danglingTriangle
+        //- Trim all triangles to box. Determine interpolation
+        //  for existing and new points
+        static void trimToBox
         (
-            const FixedList<label, 3>& fEdges,
-            const labelList& edgeFace1
+            const treeBoundBox& bb,
+            DynamicList<point>& triPoints,
+            DynamicList<label>& triMap,
+            labelList& triPointMap,
+            labelList& interpolatedPoints,
+            List<FixedList<label, 3> >& interpolatedOldPoints,
+            List<FixedList<scalar, 3> >& interpolationWeights
         );
 
-        //- Mark all non-fully connected triangles
-        static label markDanglingTriangles
-        (
-            const List<FixedList<label, 3> >& faceEdges,
-            const labelList& edgeFace0,
-            const labelList& edgeFace1,
-            const Map<labelList>& edgeFacesRest,
-            boolList& keepTriangles
-        );
+        //- Check single triangle for (topological) validity
+        static bool validTri(const triSurface&, const label);
 
         static triSurface subsetMesh
         (
@@ -392,6 +385,10 @@ class isoSurface
 
 public:
 
+    //- Declare friendship with isoSurfaceCell to share some functionality
+    friend class isoSurfaceCell;
+
+
     //- Runtime type information
     TypeName("isoSurface");
 
@@ -407,24 +404,19 @@ public:
             const scalarField& pointIsoVals,
             const scalar iso,
             const bool regularise,
+            const boundBox& bounds = boundBox::greatBox,
             const scalar mergeTol = 1e-6    // fraction of bounding box
         );
 
 
     // Member Functions
 
-        //- For every face original cell in mesh
+        //- For every triangle the original cell in mesh
         const labelList& meshCells() const
         {
             return meshCells_;
         }
 
-        //- For every unmerged triangle point the point in the triSurface
-        const labelList& triPointMergeMap() const
-        {
-            return triPointMergeMap_;
-        }
-
         //- Interpolates cCoords,pCoords. Uses the references to the original
         //  fields used to create the iso surface.
         template<class Type>
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.C b/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.C
index 8123541ebee8bbabcf84c9586a0bc523b5d90c6a..f0f140cfd4a791c96b59b2a6eb6334caf51cfc9e 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.C
+++ b/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -30,6 +30,9 @@ License
 #include "tetMatcher.H"
 #include "syncTools.H"
 #include "addToRunTimeSelectionTable.H"
+#include "Time.H"
+#include "triPoints.H"
+#include "isoSurface.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -1222,144 +1225,6 @@ void Foam::isoSurfaceCell::calcAddressing
 }
 
 
-//void Foam::isoSurfaceCell::walkOrientation
-//(
-//    const triSurface& surf,
-//    const List<FixedList<label, 3> >& faceEdges,
-//    const labelList& edgeFace0,
-//    const labelList& edgeFace1,
-//    const label seedTriI,
-//    labelList& flipState
-//)
-//{
-//    // Do walk for consistent orientation.
-//    DynamicList<label> changedFaces(surf.size());
-//
-//    changedFaces.append(seedTriI);
-//
-//    while (changedFaces.size())
-//    {
-//        DynamicList<label> newChangedFaces(changedFaces.size());
-//
-//        forAll(changedFaces, i)
-//        {
-//            label triI = changedFaces[i];
-//            const labelledTri& tri = surf[triI];
-//            const FixedList<label, 3>& fEdges = faceEdges[triI];
-//
-//            forAll(fEdges, fp)
-//            {
-//                label edgeI = fEdges[fp];
-//
-//                // my points:
-//                label p0 = tri[fp];
-//                label p1 = tri[tri.fcIndex(fp)];
-//
-//                label nbrI =
-//                (
-//                    edgeFace0[edgeI] != triI
-//                  ? edgeFace0[edgeI]
-//                  : edgeFace1[edgeI]
-//                );
-//
-//                if (nbrI != -1 && flipState[nbrI] == -1)
-//                {
-//                    const labelledTri& nbrTri = surf[nbrI];
-//
-//                    // nbr points
-//                    label nbrFp = findIndex(nbrTri, p0);
-//                    label nbrP1 = nbrTri[nbrTri.rcIndex(nbrFp)];
-//
-//                    bool sameOrientation = (p1 == nbrP1);
-//
-//                    if (flipState[triI] == 0)
-//                    {
-//                        flipState[nbrI] = (sameOrientation ? 0 : 1);
-//                    }
-//                    else
-//                    {
-//                        flipState[nbrI] = (sameOrientation ? 1 : 0);
-//                    }
-//                    newChangedFaces.append(nbrI);
-//                }
-//            }
-//        }
-//
-//        changedFaces.transfer(newChangedFaces);
-//    }
-//}
-//
-//
-//void Foam::isoSurfaceCell::orientSurface
-//(
-//    triSurface& surf,
-//    const List<FixedList<label, 3> >& faceEdges,
-//    const labelList& edgeFace0,
-//    const labelList& edgeFace1,
-//    const Map<labelList>& edgeFacesRest
-//)
-//{
-//    // -1 : unvisited
-//    //  0 : leave as is
-//    //  1 : flip
-//    labelList flipState(surf.size(), -1);
-//
-//    label seedTriI = 0;
-//
-//    while (true)
-//    {
-//        // Find first unvisited triangle
-//        for
-//        (
-//            ;
-//            seedTriI < surf.size() && flipState[seedTriI] != -1;
-//            seedTriI++
-//        )
-//        {}
-//
-//        if (seedTriI == surf.size())
-//        {
-//            break;
-//        }
-//
-//        // Note: Determine orientation of seedTriI?
-//        // for now assume it is ok
-//        flipState[seedTriI] = 0;
-//
-//        walkOrientation
-//        (
-//            surf,
-//            faceEdges,
-//            edgeFace0,
-//            edgeFace1,
-//            seedTriI,
-//            flipState
-//        );
-//    }
-//
-//    // Do actual flipping
-//    surf.clearOut();
-//    forAll(surf, triI)
-//    {
-//        if (flipState[triI] == 1)
-//        {
-//            labelledTri tri(surf[triI]);
-//
-//            surf[triI][0] = tri[0];
-//            surf[triI][1] = tri[2];
-//            surf[triI][2] = tri[1];
-//        }
-//        else if (flipState[triI] == -1)
-//        {
-//            FatalErrorIn
-//            (
-//                "isoSurfaceCell::orientSurface(triSurface&, const label)"
-//            )   << "problem" << abort(FatalError);
-//        }
-//    }
-//}
-
-
 // Checks if triangle is connected through edgeI only.
 bool Foam::isoSurfaceCell::danglingTriangle
 (
@@ -1517,6 +1382,7 @@ Foam::isoSurfaceCell::isoSurfaceCell
     const scalarField& pVals,
     const scalar iso,
     const bool regularise,
+    const boundBox& bounds,
     const scalar mergeTol
 )
 :
@@ -1524,6 +1390,7 @@ Foam::isoSurfaceCell::isoSurfaceCell
     cVals_(cVals),
     pVals_(pVals),
     iso_(iso),
+    bounds_(bounds),
     mergeDistance_(mergeTol*mesh.bounds().mag())
 {
     if (debug)
@@ -1607,57 +1474,105 @@ Foam::isoSurfaceCell::isoSurfaceCell
     }
 
 
+    {
+        DynamicList<point> triPoints(nCutCells_);
+        DynamicList<label> triMeshCells(nCutCells_);
 
-    DynamicList<point> triPoints(nCutCells_);
-    DynamicList<label> triMeshCells(nCutCells_);
+        generateTriPoints
+        (
+            cVals,
+            pVals,
 
-    generateTriPoints
-    (
-        cVals,
-        pVals,
+            mesh_.cellCentres(),
+            mesh_.points(),
 
-        mesh_.cellCentres(),
-        mesh_.points(),
+            snappedPoints,
+            snappedCc,
+            snappedPoint,
 
-        snappedPoints,
-        snappedCc,
-        snappedPoint,
+            triPoints,
+            triMeshCells
+        );
 
-        triPoints,
-        triMeshCells
-    );
+        if (debug)
+        {
+            Pout<< "isoSurfaceCell : generated " << triMeshCells.size()
+                << " unmerged triangles." << endl;
+        }
 
-    if (debug)
-    {
-        Pout<< "isoSurfaceCell : generated " << triMeshCells.size()
-            << " unmerged triangles." << endl;
-    }
 
-    // Merge points and compact out non-valid triangles
-    labelList triMap;           // merged to unmerged triangle
-    triSurface::operator=
-    (
-        stitchTriPoints
+        label nOldPoints = triPoints.size();
+
+        // Trimmed to original triangle
+        DynamicList<label> trimTriMap;
+        // Trimmed to original point
+        labelList trimTriPointMap;
+        if (bounds_ != boundBox::greatBox)
+        {
+            isoSurface::trimToBox
+            (
+                treeBoundBox(bounds_),
+                triPoints,              // new points
+                trimTriMap,             // map from (new) triangle to original
+                trimTriPointMap,        // map from (new) point to original
+                interpolatedPoints_,    // labels of newly introduced points
+                interpolatedOldPoints_, // and their interpolation
+                interpolationWeights_
+            );
+            triMeshCells = labelField(triMeshCells, trimTriMap);
+        }
+
+
+
+        // Merge points and compact out non-valid triangles
+        labelList triMap;
+        triSurface::operator=
         (
-            regularise,         // check for duplicate tris
-            triPoints,
-            triPointMergeMap_,  // unmerged to merged point
-            triMap
-        )
-    );
+            stitchTriPoints
+            (
+                regularise,         // check for duplicate tris
+                triPoints,
+                triPointMergeMap_,  // unmerged to merged point
+                triMap              // merged to unmerged triangle
+            )
+        );
 
-    if (debug)
-    {
-        Pout<< "isoSurfaceCell : generated " << triMap.size()
-            << " merged triangles." << endl;
-    }
+        if (debug)
+        {
+            Pout<< "isoSurfaceCell : generated " << triMap.size()
+                << " merged triangles." << endl;
+        }
 
-    meshCells_.setSize(triMap.size());
-    forAll(triMap, i)
-    {
-        meshCells_[i] = triMeshCells[triMap[i]];
+        if (bounds_ != boundBox::greatBox)
+        {
+            // Adjust interpolatedPoints_
+            inplaceRenumber(triPointMergeMap_, interpolatedPoints_);
+
+            // Adjust triPointMergeMap_
+            labelList newTriPointMergeMap(nOldPoints, -1);
+            forAll(trimTriPointMap, trimPointI)
+            {
+                label oldPointI = trimTriPointMap[trimPointI];
+                if (oldPointI >= 0)
+                {
+                    label pointI = triPointMergeMap_[trimPointI];
+                    if (pointI >= 0)
+                    {
+                        newTriPointMergeMap[oldPointI] = pointI;
+                    }
+                }
+            }
+            triPointMergeMap_.transfer(newTriPointMergeMap);
+        }
+
+        meshCells_.setSize(triMap.size());
+        forAll(triMap, i)
+        {
+            meshCells_[i] = triMeshCells[triMap[i]];
+        }
     }
 
+
     if (debug)
     {
         Pout<< "isoSurfaceCell : checking " << size()
@@ -1730,8 +1645,6 @@ Foam::isoSurfaceCell::isoSurfaceCell
             meshCells_ = labelField(meshCells_, subsetTriMap);
             inplaceRenumber(reversePointMap, triPointMergeMap_);
         }
-
-        //orientSurface(*this, faceEdges, edgeFace0, edgeFace1, edgeFacesRest);
     }
 }
 
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.H b/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.H
index 7e12efc7bbead6bdac2d7bc23561734530dfe3ca..910f3fe46ed7bdeef88d173fa1c64cceb705331c 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.H
+++ b/src/sampling/sampledSurface/isoSurface/isoSurfaceCell.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -48,6 +48,7 @@ SourceFiles
 #include "labelPair.H"
 #include "pointIndexHit.H"
 #include "PackedBoolList.H"
+#include "boundBox.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -55,6 +56,7 @@ namespace Foam
 {
 
 class polyMesh;
+class plane;
 
 /*---------------------------------------------------------------------------*\
                        Class isoSurfaceCell Declaration
@@ -91,6 +93,9 @@ class isoSurfaceCell
         //- isoSurfaceCell value
         const scalar iso_;
 
+        //- Optional bounds
+        const boundBox bounds_;
+
         //- When to merge points
         const scalar mergeDistance_;
 
@@ -106,6 +111,15 @@ class isoSurfaceCell
         //- For every unmerged triangle point the point in the triSurface
         labelList triPointMergeMap_;
 
+        //- triSurface points that have weighted interpolation
+        DynamicList<label> interpolatedPoints_;
+
+        //- corresponding original, unmerged points
+        DynamicList<FixedList<label, 3> > interpolatedOldPoints_;
+
+        //- corresponding weights
+        DynamicList<FixedList<scalar, 3> > interpolationWeights_;
+
 
     // Private Member Functions
 
@@ -214,19 +228,15 @@ class isoSurfaceCell
         void generateTriPoints
         (
             const DynamicList<Type>& snapped,
-            const scalar isoVal0,
             const scalar s0,
             const Type& p0,
             const label p0Index,
-            const scalar isoVal1,
             const scalar s1,
             const Type& p1,
             const label p1Index,
-            const scalar isoVal2,
             const scalar s2,
             const Type& p2,
             const label p2Index,
-            const scalar isoVal3,
             const scalar s3,
             const Type& p3,
             const label p3Index,
@@ -271,27 +281,6 @@ class isoSurfaceCell
             Map<labelList>& edgeFacesRest
         ) const;
 
-        ////- Determine orientation
-        //static void walkOrientation
-        //(
-        //    const triSurface& surf,
-        //    const List<FixedList<label, 3> >& faceEdges,
-        //    const labelList& edgeFace0,
-        //    const labelList& edgeFace1,
-        //    const label seedTriI,
-        //    labelList& flipState
-        //);
-
-        ////- Orient surface
-        //static void orientSurface
-        //(
-        //    triSurface&,
-        //    const List<FixedList<label, 3> >& faceEdges,
-        //    const labelList& edgeFace0,
-        //    const labelList& edgeFace1,
-        //    const Map<labelList>& edgeFacesRest
-        //);
-
         //- Is triangle (given by 3 edges) not fully connected?
         static bool danglingTriangle
         (
@@ -317,8 +306,6 @@ class isoSurfaceCell
             labelList& newToOldPoints
         );
 
-        //- Combine all triangles inside a cell into a minimal triangulation
-        void combineCellTriangles();
 
 public:
 
@@ -336,6 +323,7 @@ public:
             const scalarField& pointValues,
             const scalar iso,
             const bool regularise,
+            const boundBox& bounds = boundBox::greatBox,
             const scalar mergeTol = 1e-6    // fraction of bounding box
         );
 
@@ -348,24 +336,6 @@ public:
             return meshCells_;
         }
 
-        //- For every unmerged triangle point the point in the triSurface
-        const labelList triPointMergeMap() const
-        {
-            return triPointMergeMap_;
-        }
-
-
-        //- Interpolates cCoords,pCoords. Takes the original fields
-        //  used to create the iso surface.
-        template<class Type>
-        tmp<Field<Type> > interpolate
-        (
-            const scalarField& cVals,
-            const scalarField& pVals,
-            const Field<Type>& cCoords,
-            const Field<Type>& pCoords
-        ) const;
-
         //- Interpolates cCoords,pCoords.
         template<class Type>
         tmp<Field<Type> > interpolate
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurfaceCellTemplates.C b/src/sampling/sampledSurface/isoSurface/isoSurfaceCellTemplates.C
index c78aafeee50525ed763dab6863083546a160084e..8fdee4831b82a2b908addba634e66485077267fe 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurfaceCellTemplates.C
+++ b/src/sampling/sampledSurface/isoSurface/isoSurfaceCellTemplates.C
@@ -26,6 +26,7 @@ License
 #include "isoSurfaceCell.H"
 #include "polyMesh.H"
 #include "tetMatcher.H"
+#include "isoSurface.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -76,22 +77,18 @@ void Foam::isoSurfaceCell::generateTriPoints
 (
     const DynamicList<Type>& snapped,
 
-    const scalar isoVal0,
     const scalar s0,
     const Type& p0,
     const label p0Index,
 
-    const scalar isoVal1,
     const scalar s1,
     const Type& p1,
     const label p1Index,
 
-    const scalar isoVal2,
     const scalar s2,
     const Type& p2,
     const label p2Index,
 
-    const scalar isoVal3,
     const scalar s3,
     const Type& p3,
     const label p3Index,
@@ -124,160 +121,196 @@ void Foam::isoSurfaceCell::generateTriPoints
         case 0x0F:
         break;
 
-        case 0x0E:
         case 0x01:
+        case 0x0E:
         {
-            // 0 is common point. Orient such that normal points in positive
-            // gradient direction
-            if (isoVal0 >= isoVal1)
-            {
-                pts.append(generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index));
-                pts.append(generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index));
-                pts.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
-            }
-            else
+            pts.append
+            (
+                generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index)
+            );
+            pts.append
+            (
+                generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index)
+            );
+            pts.append
+            (
+                generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index)
+            );
+            if (triIndex == 0x0E)
             {
-                pts.append(generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index));
-                pts.append(generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index));
-                pts.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
+                // Flip normals
+                label sz = pts.size();
+                Swap(pts[sz-2], pts[sz-1]);
             }
         }
         break;
 
-        case 0x0D:
         case 0x02:
+        case 0x0D:
         {
-            // 1 is common point
-            if (isoVal1 >= isoVal0)
-            {
-                pts.append(generatePoint(snapped,s1,p1,p1Index,s0,p0,p0Index));
-                pts.append(generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index));
-                pts.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
-            }
-            else
+            pts.append
+            (
+                generatePoint(snapped,s1,p1,p1Index,s0,p0,p0Index)
+            );
+            pts.append
+            (
+                generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index)
+            );
+            pts.append
+            (
+                generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index)
+            );
+
+            if (triIndex == 0x0D)
             {
-                pts.append(generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index));
-                pts.append(generatePoint(snapped,s1,p1,p1Index,s0,p0,p0Index));
-                pts.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
+                // Flip normals
+                label sz = pts.size();
+                Swap(pts[sz-2], pts[sz-1]);
             }
         }
         break;
 
-        case 0x0C:
         case 0x03:
+        case 0x0C:
         {
-            Type s02 = generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index);
-            Type s13 = generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index);
-
-            if (isoVal0 >= isoVal3)
-            {
-                pts.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
-                pts.append(s02);
-                pts.append(s13);
-                pts.append(s13);
-                pts.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
-                pts.append(s02);
-            }
-            else
+            Type p0p2 =
+                generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index);
+            Type p1p3 =
+                generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index);
+
+            pts.append
+            (
+                generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index)
+            );
+            pts.append(p1p3);
+            pts.append(p0p2);
+
+            pts.append(p1p3);
+            pts.append
+            (
+                generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index)
+            );
+            pts.append(p0p2);
+
+            if (triIndex == 0x0C)
             {
-                pts.append(s02);
-                pts.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
-                pts.append(s13);
-                pts.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
-                pts.append(s13);
-                pts.append(s02);
+                // Flip normals
+                label sz = pts.size();
+                Swap(pts[sz-5], pts[sz-4]);
+                Swap(pts[sz-2], pts[sz-1]);
             }
         }
         break;
 
-        case 0x0B:
         case 0x04:
+        case 0x0B:
         {
-            // 2 is common point
-            if (isoVal2 >= isoVal0)
+            pts.append
+            (
+                generatePoint(snapped,s2,p2,p2Index,s0,p0,p0Index)
+            );
+            pts.append
+            (
+                generatePoint(snapped,s2,p2,p2Index,s1,p1,p1Index)
+            );
+            pts.append
+            (
+                generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index)
+            );
+
+            if (triIndex == 0x0B)
             {
-                pts.append(generatePoint(snapped,s2,p2,p2Index,s0,p0,p0Index));
-                pts.append(generatePoint(snapped,s2,p2,p2Index,s1,p1,p1Index));
-                pts.append(generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index));
-            }
-            else
-            {
-                pts.append(generatePoint(snapped,s2,p2,p2Index,s1,p1,p1Index));
-                pts.append(generatePoint(snapped,s2,p2,p2Index,s0,p0,p0Index));
-                pts.append(generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index));
+                // Flip normals
+                label sz = pts.size();
+                Swap(pts[sz-2], pts[sz-1]);
             }
         }
         break;
 
-        case 0x0A:
         case 0x05:
+        case 0x0A:
         {
-            Type s01 = generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index);
-            Type s23 = generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index);
-
-            if (isoVal3 >= isoVal0)
+            Type p0p1 =
+                generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index);
+            Type p2p3 =
+                generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index);
+
+            pts.append(p0p1);
+            pts.append(p2p3);
+            pts.append
+            (
+                generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index)
+            );
+
+            pts.append(p0p1);
+            pts.append
+            (
+                generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index)
+            );
+            pts.append(p2p3);
+
+            if (triIndex == 0x0A)
             {
-                pts.append(s01);
-                pts.append(s23);
-                pts.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
-                pts.append(s01);
-                pts.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
-                pts.append(s23);
-            }
-            else
-            {
-                pts.append(s23);
-                pts.append(s01);
-                pts.append(generatePoint(snapped,s0,p0,p0Index,s3,p3,p3Index));
-                pts.append(generatePoint(snapped,s1,p1,p1Index,s2,p2,p2Index));
-                pts.append(s01);
-                pts.append(s23);
+                // Flip normals
+                label sz = pts.size();
+                Swap(pts[sz-5], pts[sz-4]);
+                Swap(pts[sz-2], pts[sz-1]);
             }
         }
         break;
 
-        case 0x09:
         case 0x06:
+        case 0x09:
         {
-            Type s01 = generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index);
-            Type s23 = generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index);
-
-            if (isoVal3 >= isoVal1)
+            Type p0p1 =
+                generatePoint(snapped,s0,p0,p0Index,s1,p1,p1Index);
+            Type p2p3 =
+                generatePoint(snapped,s2,p2,p2Index,s3,p3,p3Index);
+
+            pts.append(p0p1);
+            pts.append
+            (
+                generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index)
+            );
+            pts.append(p2p3);
+
+            pts.append(p0p1);
+            pts.append(p2p3);
+            pts.append
+            (
+                generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index)
+            );
+
+            if (triIndex == 0x09)
             {
-                pts.append(s01);
-                pts.append(generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index));
-                pts.append(s23);
-                pts.append(s01);
-                pts.append(generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index));
-                pts.append(s23);
-            }
-            else
-            {
-                pts.append(generatePoint(snapped,s1,p1,p1Index,s3,p3,p3Index));
-                pts.append(s01);
-                pts.append(s23);
-                pts.append(generatePoint(snapped,s0,p0,p0Index,s2,p2,p2Index));
-                pts.append(s01);
-                pts.append(s23);
+                // Flip normals
+                label sz = pts.size();
+                Swap(pts[sz-5], pts[sz-4]);
+                Swap(pts[sz-2], pts[sz-1]);
             }
         }
         break;
 
-        case 0x07:
         case 0x08:
+        case 0x07:
         {
-            // 3 is common point
-            if (isoVal3 >= isoVal0)
+            pts.append
+            (
+                generatePoint(snapped,s3,p3,p3Index,s0,p0,p0Index)
+            );
+            pts.append
+            (
+                generatePoint(snapped,s3,p3,p3Index,s2,p2,p2Index)
+            );
+            pts.append
+            (
+                generatePoint(snapped,s3,p3,p3Index,s1,p1,p1Index)
+            );
+            if (triIndex == 0x07)
             {
-                pts.append(generatePoint(snapped,s3,p3,p3Index,s0,p0,p0Index));
-                pts.append(generatePoint(snapped,s3,p3,p3Index,s2,p2,p2Index));
-                pts.append(generatePoint(snapped,s3,p3,p3Index,s1,p1,p1Index));
-            }
-            else
-            {
-                pts.append(generatePoint(snapped,s3,p3,p3Index,s2,p2,p2Index));
-                pts.append(generatePoint(snapped,s3,p3,p3Index,s0,p0,p0Index));
-                pts.append(generatePoint(snapped,s3,p3,p3Index,s1,p1,p1Index));
+                // Flip normals
+                label sz = pts.size();
+                Swap(pts[sz-2], pts[sz-1]);
             }
         }
         break;
@@ -341,22 +374,18 @@ void Foam::isoSurfaceCell::generateTriPoints
                     (
                         snappedPoints,
 
-                        pVals_[f0[1]],
                         pVals[f0[1]],
                         pCoords[f0[1]],
                         snappedPoint[f0[1]],
 
-                        pVals_[f0[0]],
                         pVals[f0[0]],
                         pCoords[f0[0]],
                         snappedPoint[f0[0]],
 
-                        pVals_[f0[2]],
                         pVals[f0[2]],
                         pCoords[f0[2]],
                         snappedPoint[f0[2]],
 
-                        pVals_[oppositeI],
                         pVals[oppositeI],
                         pCoords[oppositeI],
                         snappedPoint[oppositeI],
@@ -370,22 +399,18 @@ void Foam::isoSurfaceCell::generateTriPoints
                     (
                         snappedPoints,
 
-                        pVals_[f0[0]],
                         pVals[f0[0]],
                         pCoords[f0[0]],
                         snappedPoint[f0[0]],
 
-                        pVals_[f0[1]],
                         pVals[f0[1]],
                         pCoords[f0[1]],
                         snappedPoint[f0[1]],
 
-                        pVals_[f0[2]],
                         pVals[f0[2]],
                         pCoords[f0[2]],
                         snappedPoint[f0[2]],
 
-                        pVals_[oppositeI],
                         pVals[oppositeI],
                         pCoords[oppositeI],
                         snappedPoint[oppositeI],
@@ -411,7 +436,6 @@ void Foam::isoSurfaceCell::generateTriPoints
                     }
 
                     label fp = f.fcIndex(fp0);
-
                     for (label i = 2; i < f.size(); i++)
                     {
                         label nextFp = f.fcIndex(fp);
@@ -425,22 +449,18 @@ void Foam::isoSurfaceCell::generateTriPoints
                             (
                                 snappedPoints,
 
-                                pVals_[tri[1]],
                                 pVals[tri[1]],
                                 pCoords[tri[1]],
                                 snappedPoint[tri[1]],
 
-                                pVals_[tri[0]],
                                 pVals[tri[0]],
                                 pCoords[tri[0]],
                                 snappedPoint[tri[0]],
 
-                                pVals_[tri[2]],
                                 pVals[tri[2]],
                                 pCoords[tri[2]],
                                 snappedPoint[tri[2]],
 
-                                cVals_[cellI],
                                 cVals[cellI],
                                 cCoords[cellI],
                                 snappedCc[cellI],
@@ -454,22 +474,18 @@ void Foam::isoSurfaceCell::generateTriPoints
                             (
                                 snappedPoints,
 
-                                pVals_[tri[0]],
                                 pVals[tri[0]],
                                 pCoords[tri[0]],
                                 snappedPoint[tri[0]],
 
-                                pVals_[tri[1]],
                                 pVals[tri[1]],
                                 pCoords[tri[1]],
                                 snappedPoint[tri[1]],
 
-                                pVals_[tri[2]],
                                 pVals[tri[2]],
                                 pCoords[tri[2]],
                                 snappedPoint[tri[2]],
 
-                                cVals_[cellI],
                                 cVals[cellI],
                                 cCoords[cellI],
                                 snappedCc[cellI],
@@ -495,7 +511,7 @@ void Foam::isoSurfaceCell::generateTriPoints
 
     if (countNotFoundTets > 0)
     {
-        WarningIn("Foam::isoSurfaceCell::generateTriPoints")
+        WarningIn("Foam::isoSurfaceCell::generateTriPoints(..)")
             << "Could not find " << countNotFoundTets
             << " tet base points, which may lead to inverted triangles."
             << endl;
@@ -510,13 +526,11 @@ template<class Type>
 Foam::tmp<Foam::Field<Type> >
 Foam::isoSurfaceCell::interpolate
 (
-    const scalarField& cVals,
-    const scalarField& pVals,
     const Field<Type>& cCoords,
     const Field<Type>& pCoords
 ) const
 {
-    DynamicList<Type> triPoints(nCutCells_);
+    DynamicList<Type> triPoints(3*nCutCells_);
     DynamicList<label> triMeshCells(nCutCells_);
 
     // Dummy snap data
@@ -524,59 +538,6 @@ Foam::isoSurfaceCell::interpolate
     labelList snappedCc(mesh_.nCells(), -1);
     labelList snappedPoint(mesh_.nPoints(), -1);
 
-
-    generateTriPoints
-    (
-        cVals,
-        pVals,
-
-        cCoords,
-        pCoords,
-
-        snappedPoints,
-        snappedCc,
-        snappedPoint,
-
-        triPoints,
-        triMeshCells
-    );
-
-
-    // One value per point
-    tmp<Field<Type> > tvalues(new Field<Type>(points().size()));
-    Field<Type>& values = tvalues();
-
-    forAll(triPoints, i)
-    {
-        label mergedPointI = triPointMergeMap_[i];
-
-        if (mergedPointI >= 0)
-        {
-            values[mergedPointI] = triPoints[i];
-        }
-    }
-
-    return tvalues;
-}
-
-
-template<class Type>
-Foam::tmp<Foam::Field<Type> >
-Foam::isoSurfaceCell::interpolate
-(
-    const Field<Type>& cCoords,
-    const Field<Type>& pCoords
-) const
-{
-    DynamicList<Type> triPoints(nCutCells_);
-    DynamicList<label> triMeshCells(nCutCells_);
-
-    // Dummy snap data
-    DynamicList<Type> snappedPoints;
-    labelList snappedCc(mesh_.nCells(), -1);
-    labelList snappedPoint(mesh_.nPoints(), -1);
-
-
     generateTriPoints
     (
         cVals_,
@@ -593,22 +554,15 @@ Foam::isoSurfaceCell::interpolate
         triMeshCells
     );
 
-
-    // One value per point
-    tmp<Field<Type> > tvalues(new Field<Type>(points().size()));
-    Field<Type>& values = tvalues();
-
-    forAll(triPoints, i)
-    {
-        label mergedPointI = triPointMergeMap_[i];
-
-        if (mergedPointI >= 0)
-        {
-            values[mergedPointI] = triPoints[i];
-        }
-    }
-
-    return tvalues;
+    return isoSurface::interpolate
+    (
+        points().size(),
+        triPointMergeMap_,
+        interpolatedPoints_,
+        interpolatedOldPoints_,
+        interpolationWeights_,
+        triPoints
+    );
 }
 
 
diff --git a/src/sampling/sampledSurface/isoSurface/isoSurfaceTemplates.C b/src/sampling/sampledSurface/isoSurface/isoSurfaceTemplates.C
index 6f64c9fe541198ea8524f097b69921702d525264..0c4f0f7811d53181d6b56251dc26a8213ac41416 100644
--- a/src/sampling/sampledSurface/isoSurface/isoSurfaceTemplates.C
+++ b/src/sampling/sampledSurface/isoSurface/isoSurfaceTemplates.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -120,7 +120,7 @@ Foam::isoSurface::adaptPatchFields
         {
             fvPatchField<Type>& pfld = const_cast<fvPatchField<Type>&>
             (
-                fld.boundaryField()[patchI]
+                sliceFld.boundaryField()[patchI]
             );
 
             const scalarField& w = mesh.weights().boundaryField()[patchI];
@@ -189,6 +189,8 @@ Type Foam::isoSurface::generatePoint
 }
 
 
+// Note: cannot use simpler isoSurfaceCell::generateTriPoints since
+//       the need here to sometimes pass in remote 'snappedPoints'
 template<class Type>
 void Foam::isoSurface::generateTriPoints
 (
@@ -240,8 +242,8 @@ void Foam::isoSurface::generateTriPoints
         case 0x0F:
         break;
 
-        case 0x0E:
         case 0x01:
+        case 0x0E:
             points.append
             (
                 generatePoint(s0,p0,hasSnap0,snapP0,s1,p1,hasSnap1,snapP1)
@@ -254,10 +256,16 @@ void Foam::isoSurface::generateTriPoints
             (
                 generatePoint(s0,p0,hasSnap0,snapP0,s3,p3,hasSnap3,snapP3)
             );
+            if (triIndex == 0x0E)
+            {
+                // Flip normals
+                label sz = points.size();
+                Swap(points[sz-2], points[sz-1]);
+            }
         break;
 
-        case 0x0D:
         case 0x02:
+        case 0x0D:
             points.append
             (
                 generatePoint(s1,p1,hasSnap1,snapP1,s0,p0,hasSnap0,snapP0)
@@ -270,97 +278,133 @@ void Foam::isoSurface::generateTriPoints
             (
                 generatePoint(s1,p1,hasSnap1,snapP1,s2,p2,hasSnap2,snapP2)
             );
+            if (triIndex == 0x0D)
+            {
+                // Flip normals
+                label sz = points.size();
+                Swap(points[sz-2], points[sz-1]);
+            }
         break;
 
-        case 0x0C:
         case 0x03:
-        {
-            Type tp1 =
-                generatePoint(s0,p0,hasSnap0,snapP0,s2,p2,hasSnap2,snapP2);
-            Type tp2 =
-                generatePoint(s1,p1,hasSnap1,snapP1,s3,p3,hasSnap3,snapP3);
+        case 0x0C:
+            {
+                Type p0p2 =
+                    generatePoint(s0,p0,hasSnap0,snapP0,s2,p2,hasSnap2,snapP2);
+                Type p1p3 =
+                    generatePoint(s1,p1,hasSnap1,snapP1,s3,p3,hasSnap3,snapP3);
 
-            points.append
-            (
-                generatePoint(s0,p0,hasSnap0,snapP0,s3,p3,hasSnap3,snapP3)
-            );
-            points.append(tp1);
-            points.append(tp2);
-            points.append(tp2);
-            points.append
-            (
-                generatePoint(s1,p1,hasSnap1,snapP1,s2,p2,hasSnap2,snapP2)
-            );
-            points.append(tp1);
-        }
+                points.append
+                (
+                    generatePoint(s0,p0,hasSnap0,snapP0,s3,p3,hasSnap3,snapP3)
+                );
+                points.append(p1p3);
+                points.append(p0p2);
+
+                points.append(p1p3);
+                points.append
+                (
+                    generatePoint(s1,p1,hasSnap1,snapP1,s2,p2,hasSnap2,snapP2)
+                );
+                points.append(p0p2);
+            }
+            if (triIndex == 0x0C)
+            {
+                // Flip normals
+                label sz = points.size();
+                Swap(points[sz-5], points[sz-4]);
+                Swap(points[sz-2], points[sz-1]);
+            }
         break;
 
-        case 0x0B:
         case 0x04:
-        {
-            points.append
-            (
-                generatePoint(s2,p2,hasSnap2,snapP2,s0,p0,hasSnap0,snapP0)
-            );
-            points.append
-            (
-                generatePoint(s2,p2,hasSnap2,snapP2,s1,p1,hasSnap1,snapP1)
-            );
-            points.append
-            (
-                generatePoint(s2,p2,hasSnap2,snapP2,s3,p3,hasSnap3,snapP3)
-            );
-        }
+        case 0x0B:
+            {
+                points.append
+                (
+                    generatePoint(s2,p2,hasSnap2,snapP2,s0,p0,hasSnap0,snapP0)
+                );
+                points.append
+                (
+                    generatePoint(s2,p2,hasSnap2,snapP2,s1,p1,hasSnap1,snapP1)
+                );
+                points.append
+                (
+                    generatePoint(s2,p2,hasSnap2,snapP2,s3,p3,hasSnap3,snapP3)
+                );
+            }
+            if (triIndex == 0x0B)
+            {
+                // Flip normals
+                label sz = points.size();
+                Swap(points[sz-2], points[sz-1]);
+            }
         break;
 
-        case 0x0A:
         case 0x05:
-        {
-            Type tp0 =
-                generatePoint(s0,p0,hasSnap0,snapP0,s1,p1,hasSnap1,snapP1);
-            Type tp1 =
-                generatePoint(s2,p2,hasSnap2,snapP2,s3,p3,hasSnap3,snapP3);
+        case 0x0A:
+            {
+                Type p0p1 =
+                    generatePoint(s0,p0,hasSnap0,snapP0,s1,p1,hasSnap1,snapP1);
+                Type p2p3 =
+                    generatePoint(s2,p2,hasSnap2,snapP2,s3,p3,hasSnap3,snapP3);
+
+                points.append(p0p1);
+                points.append(p2p3);
+                points.append
+                (
+                    generatePoint(s0,p0,hasSnap0,snapP0,s3,p3,hasSnap3,snapP3)
+                );
 
-            points.append(tp0);
-            points.append(tp1);
-            points.append
-            (
-                generatePoint(s0,p0,hasSnap0,snapP0,s3,p3,hasSnap3,snapP3)
-            );
-            points.append(tp0);
-            points.append
-            (
-                generatePoint(s1,p1,hasSnap1,snapP1,s2,p2,hasSnap2,snapP2)
-            );
-            points.append(tp1);
-        }
+                points.append(p0p1);
+                points.append
+                (
+                    generatePoint(s1,p1,hasSnap1,snapP1,s2,p2,hasSnap2,snapP2)
+                );
+                points.append(p2p3);
+            }
+            if (triIndex == 0x0A)
+            {
+                // Flip normals
+                label sz = points.size();
+                Swap(points[sz-5], points[sz-4]);
+                Swap(points[sz-2], points[sz-1]);
+            }
         break;
 
-        case 0x09:
         case 0x06:
-        {
-            Type tp0 =
-                generatePoint(s0,p0,hasSnap0,snapP0,s1,p1,hasSnap1,snapP1);
-            Type tp1 =
-                generatePoint(s2,p2,hasSnap2,snapP2,s3,p3,hasSnap3,snapP3);
+        case 0x09:
+            {
+                Type p0p1 =
+                    generatePoint(s0,p0,hasSnap0,snapP0,s1,p1,hasSnap1,snapP1);
+                Type p2p3 =
+                    generatePoint(s2,p2,hasSnap2,snapP2,s3,p3,hasSnap3,snapP3);
 
-            points.append(tp0);
-            points.append
-            (
-                generatePoint(s1,p1,hasSnap1,snapP1,s3,p3,hasSnap3,snapP3)
-            );
-            points.append(tp1);
-            points.append(tp0);
-            points.append
-            (
-                generatePoint(s0,p0,hasSnap0,snapP0,s2,p2,hasSnap2,snapP2)
-            );
-            points.append(tp1);
-        }
+                points.append(p0p1);
+                points.append
+                (
+                    generatePoint(s1,p1,hasSnap1,snapP1,s3,p3,hasSnap3,snapP3)
+                );
+                points.append(p2p3);
+
+                points.append(p0p1);
+                points.append(p2p3);
+                points.append
+                (
+                    generatePoint(s0,p0,hasSnap0,snapP0,s2,p2,hasSnap2,snapP2)
+                );
+            }
+            if (triIndex == 0x09)
+            {
+                // Flip normals
+                label sz = points.size();
+                Swap(points[sz-5], points[sz-4]);
+                Swap(points[sz-2], points[sz-1]);
+            }
         break;
 
-        case 0x07:
         case 0x08:
+        case 0x07:
             points.append
             (
                 generatePoint(s3,p3,hasSnap3,snapP3,s0,p0,hasSnap0,snapP0)
@@ -373,6 +417,12 @@ void Foam::isoSurface::generateTriPoints
             (
                 generatePoint(s3,p3,hasSnap3,snapP3,s1,p1,hasSnap1,snapP1)
             );
+            if (triIndex == 0x07)
+            {
+                // Flip normals
+                label sz = points.size();
+                Swap(points[sz-2], points[sz-1]);
+            }
         break;
     }
 }
@@ -689,6 +739,69 @@ void Foam::isoSurface::generateTriPoints
 //}
 
 
+template<class Type>
+Foam::tmp<Foam::Field<Type> >
+Foam::isoSurface::interpolate
+(
+    const label nPoints,
+    const labelList& triPointMergeMap,
+    const labelList& interpolatedPoints,
+    const List<FixedList<label, 3> >& interpolatedOldPoints,
+    const List<FixedList<scalar, 3> >& interpolationWeights,
+    const DynamicList<Type>& unmergedValues
+)
+{
+    // One value per point
+    tmp<Field<Type> > tvalues(new Field<Type>(nPoints, pTraits<Type>::zero));
+    Field<Type>& values = tvalues();
+
+
+    // Pass1: unweighted average of merged point values
+    {
+        labelList nValues(values.size(), 0);
+
+        forAll(unmergedValues, i)
+        {
+            label mergedPointI = triPointMergeMap[i];
+
+            if (mergedPointI >= 0)
+            {
+                values[mergedPointI] += unmergedValues[i];
+                nValues[mergedPointI]++;
+            }
+        }
+
+        forAll(values, i)
+        {
+            if (nValues[i] > 0)
+            {
+                values[i] /= scalar(nValues[i]);
+            }
+        }
+    }
+
+
+    // Pass2: weighted average for remaining values (from clipped triangles)
+
+    forAll(interpolatedPoints, i)
+    {
+        label pointI = interpolatedPoints[i];
+        const FixedList<label, 3>& oldPoints = interpolatedOldPoints[i];
+        const FixedList<scalar, 3>& w = interpolationWeights[i];
+
+        // Note: zeroing should not be necessary if interpolation only done
+        //       for newly introduced points (i.e. not in triPointMergeMap)
+        values[pointI] = pTraits<Type>::zero;
+        forAll(oldPoints, j)
+        {
+            values[pointI] = w[j]*unmergedValues[oldPoints[j]];
+        }
+    }
+
+    return tvalues;
+}
+
+
 template<class Type>
 Foam::tmp<Foam::Field<Type> >
 Foam::isoSurface::interpolate
@@ -707,7 +820,7 @@ Foam::isoSurface::interpolate
     > > c2(adaptPatchFields(cCoords));
 
 
-    DynamicList<Type> triPoints(nCutCells_);
+    DynamicList<Type> triPoints(3*nCutCells_);
     DynamicList<label> triMeshCells(nCutCells_);
 
     // Dummy snap data
@@ -731,52 +844,15 @@ Foam::isoSurface::interpolate
         triMeshCells
     );
 
-
-    // One value per point
-    tmp<Field<Type> > tvalues
+    return interpolate
     (
-        new Field<Type>(points().size(), pTraits<Type>::zero)
+        points().size(),
+        triPointMergeMap_,
+        interpolatedPoints_,
+        interpolatedOldPoints_,
+        interpolationWeights_,
+        triPoints
     );
-    Field<Type>& values = tvalues();
-    labelList nValues(values.size(), 0);
-
-    forAll(triPoints, i)
-    {
-        label mergedPointI = triPointMergeMap_[i];
-
-        if (mergedPointI >= 0)
-        {
-            values[mergedPointI] += triPoints[i];
-            nValues[mergedPointI]++;
-        }
-    }
-
-    if (debug)
-    {
-        Pout<< "nValues:" << values.size() << endl;
-        label nMult = 0;
-        forAll(nValues, i)
-        {
-            if (nValues[i] == 0)
-            {
-                FatalErrorIn("isoSurface::interpolate(..)")
-                    << "point:" << i << " nValues:" << nValues[i]
-                    << abort(FatalError);
-            }
-            else if (nValues[i] > 1)
-            {
-                nMult++;
-            }
-        }
-        Pout<< "Of which mult:" << nMult << endl;
-    }
-
-    forAll(values, i)
-    {
-        values[i] /= scalar(nValues[i]);
-    }
-
-    return tvalues;
 }
 
 
diff --git a/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.C b/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.C
index bb171c2c0e98a814e752dad4fe5865f2118b8f47..0399eeae06e824ce8b4dd8fd7ca0db77c6668fdd 100644
--- a/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.C
+++ b/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.C
@@ -122,18 +122,52 @@ void Foam::sampledIsoSurface::getIsoFields() const
     // Get pointField
     // ~~~~~~~~~~~~~~
 
+    // In case of multiple iso values we don't want to calculate multiple e.g.
+    // "volPointInterpolate(p)" so register it and re-use it. This is the
+    // same as the 'cache' functionality from volPointInterpolate but
+    // unfortunately that one does not guarantee that the field pointer
+    // remain: e.g. some other
+    // functionObject might delete the cached version.
+    // (volPointInterpolation::interpolate with cache=false deletes any
+    //  registered one or if mesh.changing())
+
     if (!subMeshPtr_.valid())
     {
-        word pointFldName = "volPointInterpolate(" + isoField_ + ')';
+        const word pointFldName =
+            "volPointInterpolate_"
+          + type()
+          + "("
+          + isoField_
+          + ')';
 
         if (fvm.foundObject<pointScalarField>(pointFldName))
         {
             if (debug)
             {
-                Info<< "sampledIsoSurface::getIsoFields() : lookup pointField "
-                    << pointFldName << endl;
+                Info<< "sampledIsoSurface::getIsoFields() :"
+                    << " lookup pointField " << pointFldName << endl;
             }
-            pointFieldPtr_ = &fvm.lookupObject<pointScalarField>(pointFldName);
+            const pointScalarField& pfld = fvm.lookupObject<pointScalarField>
+            (
+                pointFldName
+            );
+
+            if (!pfld.upToDate(*volFieldPtr_))
+            {
+                if (debug)
+                {
+                    Info<< "sampledIsoSurface::getIsoFields() :"
+                        << " updating pointField " << pointFldName << endl;
+                }
+                // Update the interpolated value
+                volPointInterpolation::New(fvm).interpolate
+                (
+                    *volFieldPtr_,
+                    const_cast<pointScalarField&>(pfld)
+                );
+            }
+
+            pointFieldPtr_ = &pfld;
         }
         else
         {
@@ -141,33 +175,23 @@ void Foam::sampledIsoSurface::getIsoFields() const
 
             if (debug)
             {
-                Info<< "sampledIsoSurface::getIsoFields() : "
-                    << "checking pointField " << pointFldName
-                    << " for same time " << fvm.time().timeName()
-                    << endl;
+                Info<< "sampledIsoSurface::getIsoFields() :"
+                    << " creating and storing pointField "
+                    << pointFldName << " for time "
+                    << fvm.time().timeName() << endl;
             }
 
-            if
+            tmp<pointScalarField> tpfld
             (
-                storedPointFieldPtr_.empty()
-             || (fvm.time().timeName() != storedPointFieldPtr_().instance())
-            )
-            {
-                if (debug)
-                {
-                    Info<< "sampledIsoSurface::getIsoFields() :"
-                        << " interpolating volField " << volFieldPtr_->name()
-                        << " to get pointField " << pointFldName << endl;
-                }
-
-                storedPointFieldPtr_.reset
+                volPointInterpolation::New(fvm).interpolate
                 (
-                    volPointInterpolation::New(fvm)
-                    .interpolate(*volFieldPtr_).ptr()
-                );
-                storedPointFieldPtr_->checkOut();
-                pointFieldPtr_ = storedPointFieldPtr_.operator->();
-            }
+                    *volFieldPtr_,
+                    pointFldName,
+                    false
+                )
+            );
+            pointFieldPtr_ = tpfld.ptr();
+            const_cast<pointScalarField*>(pointFieldPtr_)->store();
         }
 
 
@@ -233,8 +257,10 @@ void Foam::sampledIsoSurface::getIsoFields() const
 
         // Pointfield on submesh
 
-        word pointFldName =
-            "volPointInterpolate("
+        const word pointFldName =
+            "volPointInterpolate_"
+          + type()
+          + "("
           + volSubFieldPtr_->name()
           + ')';
 
@@ -245,11 +271,28 @@ void Foam::sampledIsoSurface::getIsoFields() const
                 Info<< "sampledIsoSurface::getIsoFields() :"
                     << " submesh lookup pointField " << pointFldName << endl;
             }
-            storedPointSubFieldPtr_.clear();
-            pointSubFieldPtr_ = &subFvm.lookupObject<pointScalarField>
+            const pointScalarField& pfld = subFvm.lookupObject<pointScalarField>
             (
                 pointFldName
             );
+
+            if (!pfld.upToDate(*volSubFieldPtr_))
+            {
+                if (debug)
+                {
+                    Info<< "sampledIsoSurface::getIsoFields() :"
+                        << " updating submesh pointField "
+                        << pointFldName << endl;
+                }
+                // Update the interpolated value
+                volPointInterpolation::New(subFvm).interpolate
+                (
+                    *volSubFieldPtr_,
+                    const_cast<pointScalarField&>(pfld)
+                );
+            }
+
+            pointFieldPtr_ = &pfld;
         }
         else
         {
@@ -260,15 +303,15 @@ void Foam::sampledIsoSurface::getIsoFields() const
                     << volSubFieldPtr_->name()
                     << " to get submesh pointField " << pointFldName << endl;
             }
-            storedPointSubFieldPtr_.reset
+            tmp<pointScalarField> tpfld
             (
                 volPointInterpolation::New
                 (
                     subFvm
-                ).interpolate(*volSubFieldPtr_).ptr()
+                ).interpolate(*volSubFieldPtr_)
             );
-            storedPointSubFieldPtr_->checkOut();
-            pointSubFieldPtr_ = storedPointSubFieldPtr_.operator->();
+            pointSubFieldPtr_ = tpfld.ptr();
+            const_cast<pointScalarField*>(pointSubFieldPtr_)->store();
         }
 
 
@@ -349,28 +392,34 @@ bool Foam::sampledIsoSurface::updateGeometry() const
 
     if (subMeshPtr_.valid())
     {
+        const volScalarField& vfld = *volSubFieldPtr_;
+
         surfPtr_.reset
         (
             new isoSurface
             (
-                *volSubFieldPtr_,
+                vfld,
                 *pointSubFieldPtr_,
                 isoVal_,
                 regularise_,
+                bounds_,
                 mergeTol_
             )
         );
     }
     else
     {
+        const volScalarField& vfld = *volFieldPtr_;
+
         surfPtr_.reset
         (
             new isoSurface
             (
-                *volFieldPtr_,
+                vfld,
                 *pointFieldPtr_,
                 isoVal_,
                 regularise_,
+                bounds_,
                 mergeTol_
             )
         );
@@ -412,6 +461,7 @@ Foam::sampledIsoSurface::sampledIsoSurface
     sampledSurface(name, mesh, dict),
     isoField_(dict.lookup("isoField")),
     isoVal_(readScalar(dict.lookup("isoValue"))),
+    bounds_(dict.lookupOrDefault("bounds", boundBox::greatBox)),
     mergeTol_(dict.lookupOrDefault("mergeTol", 1e-6)),
     regularise_(dict.lookupOrDefault("regularise", true)),
     average_(dict.lookupOrDefault("average", false)),
@@ -422,7 +472,6 @@ Foam::sampledIsoSurface::sampledIsoSurface
     prevTimeIndex_(-1),
     storedVolFieldPtr_(NULL),
     volFieldPtr_(NULL),
-    storedPointFieldPtr_(NULL),
     pointFieldPtr_(NULL)
 {
     if (!sampledSurface::interpolate())
diff --git a/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.H b/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.H
index 8cfd14c3c15cd3b0d26d2e21510d42acc89c96ec..488ba56452544309557a54de64611341025913d8 100644
--- a/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.H
+++ b/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.H
@@ -63,6 +63,9 @@ class sampledIsoSurface
         //- Iso value
         const scalar isoVal_;
 
+        //- Optional bounding box to trim triangles against
+        const boundBox bounds_;
+
         //- Merge tolerance
         const scalar mergeTol_;
 
@@ -94,7 +97,6 @@ class sampledIsoSurface
             mutable const volScalarField* volFieldPtr_;
 
             //- Cached pointfield
-            mutable autoPtr<pointScalarField> storedPointFieldPtr_;
             mutable const pointScalarField* pointFieldPtr_;
 
             // And on subsetted mesh
@@ -107,7 +109,6 @@ class sampledIsoSurface
                 mutable const volScalarField* volSubFieldPtr_;
 
                 //- Cached pointfield
-                mutable autoPtr<pointScalarField> storedPointSubFieldPtr_;
                 mutable const pointScalarField* pointSubFieldPtr_;
 
 
diff --git a/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceCell.C b/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceCell.C
index 239217a352c365316da312e91a14992ea8a2fd0c..4c21257ce7b07de49a65b131d687531b03e2d74d 100644
--- a/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceCell.C
+++ b/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceCell.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -148,7 +148,8 @@ bool Foam::sampledIsoSurfaceCell::updateGeometry() const
             cellAvg,
             pointFld().internalField(),
             isoVal_,
-            regularise_
+            regularise_,
+            bounds_
         );
 
         const_cast<sampledIsoSurfaceCell&>
@@ -166,7 +167,8 @@ bool Foam::sampledIsoSurfaceCell::updateGeometry() const
             cellFld.internalField(),
             pointFld().internalField(),
             isoVal_,
-            regularise_
+            regularise_,
+            bounds_
         );
 
         const_cast<sampledIsoSurfaceCell&>
@@ -185,6 +187,7 @@ bool Foam::sampledIsoSurfaceCell::updateGeometry() const
             << "    average        : " << average_ << nl
             << "    isoField       : " << isoField_ << nl
             << "    isoValue       : " << isoVal_ << nl
+            << "    bounds         : " << bounds_ << nl
             << "    points         : " << points().size() << nl
             << "    tris           : " << triSurface::size() << nl
             << "    cut cells      : " << meshCells_.size() << endl;
@@ -206,6 +209,7 @@ Foam::sampledIsoSurfaceCell::sampledIsoSurfaceCell
     sampledSurface(name, mesh, dict),
     isoField_(dict.lookup("isoField")),
     isoVal_(readScalar(dict.lookup("isoValue"))),
+    bounds_(dict.lookupOrDefault("bounds", boundBox::greatBox)),
     regularise_(dict.lookupOrDefault("regularise", true)),
     average_(dict.lookupOrDefault("average", true)),
     zoneKey_(keyType::null),
diff --git a/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceCell.H b/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceCell.H
index 7021bf0b97e35b941ab743cb83ea1b985a96fb86..0cfa6a7461a9ec02b6b022e989d24c961222f528 100644
--- a/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceCell.H
+++ b/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceCell.H
@@ -62,6 +62,9 @@ class sampledIsoSurfaceCell
         //- Iso value
         const scalar isoVal_;
 
+        //- Optional bounding box to trim triangles against
+        const boundBox bounds_;
+
         //- Whether to coarse
         const Switch regularise_;
 
diff --git a/src/sampling/sampledSurface/sampledCuttingPlane/sampledCuttingPlane.C b/src/sampling/sampledSurface/sampledCuttingPlane/sampledCuttingPlane.C
index 7da10d7a57db7ce97e6e7454106c6f444cbe696f..7030b20d5e62a97e4fe824b8ac2ebcc41b2230a2 100644
--- a/src/sampling/sampledSurface/sampledCuttingPlane/sampledCuttingPlane.C
+++ b/src/sampling/sampledSurface/sampledCuttingPlane/sampledCuttingPlane.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2012 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2014 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -230,6 +230,7 @@ void Foam::sampledCuttingPlane::createGeometry()
             pointDistance_,
             0.0,
             regularise_,
+            bounds_,
             mergeTol_
         )
         //new isoSurfaceCell
@@ -262,6 +263,7 @@ Foam::sampledCuttingPlane::sampledCuttingPlane
 :
     sampledSurface(name, mesh, dict),
     plane_(dict),
+    bounds_(dict.lookupOrDefault("bounds", boundBox::greatBox)),
     mergeTol_(dict.lookupOrDefault("mergeTol", 1e-6)),
     regularise_(dict.lookupOrDefault("regularise", true)),
     average_(dict.lookupOrDefault("average", false)),
diff --git a/src/sampling/sampledSurface/sampledCuttingPlane/sampledCuttingPlane.H b/src/sampling/sampledSurface/sampledCuttingPlane/sampledCuttingPlane.H
index a8aa477407fe466a140d6f1b695a6ccb4f0e6a33..308bdcd46a01aeb8bb5fa5aad007141ade2fd886 100644
--- a/src/sampling/sampledSurface/sampledCuttingPlane/sampledCuttingPlane.H
+++ b/src/sampling/sampledSurface/sampledCuttingPlane/sampledCuttingPlane.H
@@ -60,6 +60,9 @@ class sampledCuttingPlane
         //- Plane
         const plane plane_;
 
+        //- Optional bounding box to trim triangles against
+        const boundBox bounds_;
+
         //- Merge tolerance
         const scalar mergeTol_;
 
diff --git a/src/sampling/sampledSurface/sampledPatch/sampledPatch.C b/src/sampling/sampledSurface/sampledPatch/sampledPatch.C
index d07a6391f120f7a2a2154d547de6bb01be7f63a8..faeccd69a3f9669228860950d337026f0a25ba4f 100644
--- a/src/sampling/sampledSurface/sampledPatch/sampledPatch.C
+++ b/src/sampling/sampledSurface/sampledPatch/sampledPatch.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2014 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -84,11 +84,7 @@ const Foam::labelList& Foam::sampledPatch::patchIDs() const
 {
     if (patchIDs_.empty())
     {
-        patchIDs_ = mesh().boundaryMesh().patchSet
-        (
-            patchNames_,
-            false
-        ).sortedToc();
+        patchIDs_ = mesh().boundaryMesh().patchSet(patchNames_).sortedToc();
     }
     return patchIDs_;
 }
diff --git a/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.C b/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.C
index 47a9f9ebbc4d0e0e67bfb7b63e98c683c6eb56de..4e12874c2545f21c1f31f5a2aa4f8d7a4519dfbd 100644
--- a/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.C
+++ b/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.C
@@ -2,8 +2,8 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2015 OpenCFD Ltd
+    \\  /    A nd           | Copyright (C) 2011-2014 OpenFOAM Foundation
+     \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -162,19 +162,7 @@ void Foam::sampledSurfaces::write()
 
         const label nFields = classifyFields();
 
-        if (Pstream::master())
-        {
-            if (debug)
-            {
-                Pout<< "Creating directory "
-                    << outputPath_/obr_.time().timeName() << nl << endl;
-
-            }
-
-            mkDir(outputPath_/obr_.time().timeName());
-        }
-
-        // Write geometry first if required,
+        // write geometry first if required,
         // or when no fields would otherwise be written
         if (nFields == 0 || formatter_->separateGeometry())
         {
diff --git a/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.C b/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.C
index 094ae45cfcb488323910c412de721701d661b8af..654b3d438f23d3a100eee1d8499b6bfd3cc19e45 100644
--- a/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.C
+++ b/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.C
@@ -644,8 +644,25 @@ bool Foam::sampledTriSurfaceMesh::update()
         return false;
     }
 
+    // Calculate surface and mesh overlap bounding box
+    treeBoundBox bb
+    (
+        surface_.triSurface::points(),
+        surface_.triSurface::meshPoints()
+    );
+    bb.min() = max(bb.min(), mesh().bounds().min());
+    bb.max() = min(bb.max(), mesh().bounds().max());
+
+    // Extend a bit
+    const vector span(bb.span());
+
+    bb.min() -= 0.5*span;
+    bb.max() += 0.5*span;
+
+    bb.inflate(1e-6);
+
     // Mesh search engine, no triangulation of faces.
-    meshSearch meshSearcher(mesh(), polyMesh::FACE_PLANES);
+    meshSearch meshSearcher(mesh(), bb, polyMesh::FACE_PLANES);
 
     return update(meshSearcher);
 }