diff --git a/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.C b/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.C
index 7db0fb783e483323ef45baba870d1a49bdc1c8d8..3b225adc6a95f66db32891b98a337b0409b68f46 100644
--- a/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.C
+++ b/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.C
@@ -78,6 +78,32 @@ namespace Foam
 }
 
 
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+void Foam::sampledTriSurfaceMesh::setZoneMap
+(
+    const surfZoneList& zoneLst,
+    labelList& zoneIds
+)
+{
+    label sz = 0;
+    forAll(zoneLst, zonei)
+    {
+        const surfZone& zn = zoneLst[zonei];
+        sz += zn.size();
+    }
+
+    zoneIds.setSize(sz);
+    forAll(zoneLst, zonei)
+    {
+        const surfZone& zn = zoneLst[zonei];
+
+        // Assign sub-zone Ids
+        SubList<label>(zoneIds, zn.size(), zn.start()) = zonei;
+    }
+}
+
+
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 const Foam::indexedOctree<Foam::treeDataFace>&
@@ -146,16 +172,11 @@ bool Foam::sampledTriSurfaceMesh::update(const meshSearch& meshSearcher)
 
     // Global numbering for cells/faces - only used to uniquely identify local
     // elements
-    globalIndex globalCells
-    (
-        (sampleSource_ == cells || sampleSource_ == insideCells)
-      ? mesh().nCells()
-      : mesh().nFaces()
-    );
+    globalIndex globalCells(onBoundary() ? mesh().nFaces() : mesh().nCells());
 
     forAll(nearest, i)
     {
-        nearest[i].first() = GREAT;
+        nearest[i].first()  = GREAT;
         nearest[i].second() = labelMax;
     }
 
@@ -174,7 +195,7 @@ bool Foam::sampledTriSurfaceMesh::update(const meshSearch& meshSearcher)
             );
             if (nearInfo.hit())
             {
-                nearest[triI].first() = magSqr(nearInfo.hitPoint()-fc[triI]);
+                nearest[triI].first()  = magSqr(nearInfo.hitPoint()-fc[triI]);
                 nearest[triI].second() = globalCells.toGlobal(nearInfo.index());
             }
         }
@@ -192,7 +213,7 @@ bool Foam::sampledTriSurfaceMesh::update(const meshSearch& meshSearcher)
                 const label index = cellTree.findInside(fc[triI]);
                 if (index != -1)
                 {
-                    nearest[triI].first() = 0.0;
+                    nearest[triI].first()  = 0.0;
                     nearest[triI].second() = globalCells.toGlobal(index);
                 }
             }
@@ -216,7 +237,7 @@ bool Foam::sampledTriSurfaceMesh::update(const meshSearch& meshSearcher)
             );
             if (nearInfo.hit())
             {
-                nearest[triI].first() = magSqr(nearInfo.hitPoint()-fc[triI]);
+                nearest[triI].first()  = magSqr(nearInfo.hitPoint()-fc[triI]);
                 nearest[triI].second() = globalCells.toGlobal
                 (
                     bTree.shapes().faceLabels()[nearInfo.index()]
@@ -270,6 +291,37 @@ bool Foam::sampledTriSurfaceMesh::update(const meshSearch& meshSearcher)
     // From original point to compact points
     labelList reversePointMap(s.points().size(), -1);
 
+    // Handle region-wise sorting (makes things slightly more complicated)
+    zoneIds_.setSize(s.size(), -1);
+
+    // Better not to use triSurface::sortedZones here,
+    // since we'll sort ourselves
+
+    // Get zone/region sizes used, store under the original region Id
+    Map<label> zoneSizes;
+
+    // Recover region names from the input surface
+    Map<word> zoneNames;
+    {
+        const geometricSurfacePatchList& patches = s.patches();
+
+        forAll(patches, patchi)
+        {
+            zoneNames.set
+            (
+                patchi,
+                (
+                    patches[patchi].name().empty()
+                  ? Foam::name("patch%d", patchi)
+                  : patches[patchi].name()
+                )
+            );
+
+            zoneSizes.set(patchi, 0);
+        }
+    }
+
+
     {
         label newPointi = 0;
         label newFacei = 0;
@@ -278,57 +330,139 @@ bool Foam::sampledTriSurfaceMesh::update(const meshSearch& meshSearcher)
         {
             if (cellOrFaceLabels[facei] != -1)
             {
-                faceMap[newFacei++] = facei;
-
                 const triSurface::FaceType& f = s[facei];
+                const label regionid = f.region();
+
+                Map<label>::iterator fnd = zoneSizes.find(regionid);
+                if (fnd != zoneSizes.end())
+                {
+                    fnd()++;
+                }
+                else
+                {
+                    // This shouldn't happen
+                    zoneSizes.insert(regionid, 1);
+                    zoneNames.set
+                    (
+                        regionid,
+                        Foam::name("patch%d", regionid)
+                    );
+                }
+
+                // Store new faces compact
+                faceMap[newFacei] = facei;
+                zoneIds_[newFacei] = regionid;
+                ++newFacei;
+
+                // Renumber face points
                 forAll(f, fp)
                 {
-                    if (reversePointMap[f[fp]] == -1)
+                    const label labI = f[fp];
+
+                    if (reversePointMap[labI] == -1)
                     {
-                        pointMap[newPointi] = f[fp];
-                        reversePointMap[f[fp]] = newPointi++;
+                        pointMap[newPointi] = labI;
+                        reversePointMap[labI] = newPointi++;
                     }
                 }
             }
         }
+
+        // Trim
         faceMap.setSize(newFacei);
+        zoneIds_.setSize(newFacei);
         pointMap.setSize(newPointi);
     }
 
 
+    // Assign start/size (and name) to the newZones
+    // re-use the lookup to map (zoneId => zoneI)
+    surfZoneList zoneLst(zoneSizes.size());
+    label start = 0;
+    label zoneI = 0;
+    forAllIter(Map<label>, zoneSizes, iter)
+    {
+        // No negative regionids, so Map<label> sorts properly
+        const label regionid = iter.key();
+
+        word name;
+        Map<word>::const_iterator fnd = zoneNames.find(regionid);
+        if (fnd != zoneNames.end())
+        {
+            name = fnd();
+        }
+        if (name.empty())
+        {
+            name = ::Foam::name("patch%d", regionid);
+        }
+
+        zoneLst[zoneI] = surfZone
+        (
+            name,
+            0,           // initialize with zero size
+            start,
+            zoneI
+        );
+
+        // Adjust start for the next zone and save (zoneId => zoneI) mapping
+        start += iter();
+        iter() = zoneI++;
+    }
+
+
+    // At this stage:
+    // - faceMap to map the (unsorted) compact to original triangle
+    // - zoneIds for the next sorting
+    // - zoneSizes contains region -> count information
+
+    // Rebuild the faceMap for the sorted order
+    labelList sortedFaceMap(faceMap.size());
+
+    forAll(zoneIds_, facei)
+    {
+        label zonei = zoneIds_[facei];
+        label sortedFacei = zoneLst[zonei].start() + zoneLst[zonei].size()++;
+        sortedFaceMap[sortedFacei] = faceMap[facei];
+    }
+
+    // zoneIds are now simply flat values
+    setZoneMap(zoneLst, zoneIds_);
+
+    // Replace the faceMap with the properly sorted face map
+    faceMap.transfer(sortedFaceMap);
+
     if (keepIds_)
     {
         originalIds_ = faceMap;
     }
 
-    // Subset cellOrFaceLabels
+    // Subset cellOrFaceLabels (for compact faces)
     cellOrFaceLabels = UIndirectList<label>(cellOrFaceLabels, faceMap)();
 
     // Store any face per point (without using pointFaces())
     labelList pointToFace(pointMap.size());
 
     // Create faces and points for subsetted surface
-    faceList& faces = this->storedFaces();
-    faces.setSize(faceMap.size());
+    faceList& surfFaces = this->storedFaces();
+    surfFaces.setSize(faceMap.size());
 
-    labelList& zoneIds = this->storedZoneIds();
-    zoneIds.setSize(faceMap.size());
+    this->storedZones().transfer(zoneLst);
 
-    forAll(faceMap, i)
+    forAll(faceMap, facei)
     {
-        const labelledTri& f = s[faceMap[i]];
-        triFace newF
+        const labelledTri& origF = s[faceMap[facei]];
+        face& f = surfFaces[facei];
+
+        f = triFace
         (
-            reversePointMap[f[0]],
-            reversePointMap[f[1]],
-            reversePointMap[f[2]]
+            reversePointMap[origF[0]],
+            reversePointMap[origF[1]],
+            reversePointMap[origF[2]]
         );
-        faces[i]   = newF.triFaceFace();
-        zoneIds[i] = f.region(); // preserve zone information
 
-        forAll(newF, fp)
+        forAll(f, fp)
         {
-            pointToFace[newF[fp]] = i;
+            pointToFace[f[fp]] = facei;
         }
     }
 
@@ -418,7 +552,7 @@ bool Foam::sampledTriSurfaceMesh::update(const meshSearch& meshSearcher)
                 const point& pt = points()[pointi];
                 label facei = cellOrFaceLabels[pointToFace[pointi]];
                 sampleElements_[pointi] = facei;
-                samplePoints_[pointi] =  mesh().faces()[facei].nearestPoint
+                samplePoints_[pointi] = mesh().faces()[facei].nearestPoint
                 (
                     pt,
                     mesh().points()
@@ -429,16 +563,16 @@ bool Foam::sampledTriSurfaceMesh::update(const meshSearch& meshSearcher)
     else
     {
         // if sampleSource_ == cells:
-        //      samplePoints_   : n/a
         //      sampleElements_ : per surface triangle the cell
-        // if sampleSource_ == insideCells:
         //      samplePoints_   : n/a
+        // if sampleSource_ == insideCells:
         //      sampleElements_ : -1 or per surface triangle the cell
-        // else:
         //      samplePoints_   : n/a
+        // else:
         //      sampleElements_ : per surface triangle the boundary face
-        samplePoints_.clear();
+        //      samplePoints_   : n/a
         sampleElements_.transfer(cellOrFaceLabels);
+        samplePoints_.clear();
     }
 
 
@@ -448,77 +582,47 @@ bool Foam::sampledTriSurfaceMesh::update(const meshSearch& meshSearcher)
         OFstream str(mesh().time().path()/"surfaceToMesh.obj");
         Info<< "Dumping correspondence from local surface (points or faces)"
             << " to mesh (cells or faces) to " << str.name() << endl;
-        label vertI = 0;
+
+        const vectorField& centres =
+        (
+            onBoundary()
+          ? mesh().faceCentres()
+          : mesh().cellCentres()
+        );
 
         if (sampledSurface::interpolate())
         {
-            if (sampleSource_ == cells || sampleSource_ == insideCells)
+            label vertI = 0;
+            forAll(samplePoints_, pointi)
             {
-                forAll(samplePoints_, pointi)
-                {
-                    meshTools::writeOBJ(str, points()[pointi]);
-                    vertI++;
+                meshTools::writeOBJ(str, points()[pointi]);
+                vertI++;
 
-                    meshTools::writeOBJ(str, samplePoints_[pointi]);
-                    vertI++;
+                meshTools::writeOBJ(str, samplePoints_[pointi]);
+                vertI++;
 
-                    label celli = sampleElements_[pointi];
-                    meshTools::writeOBJ(str, mesh().cellCentres()[celli]);
-                    vertI++;
-                    str << "l " << vertI-2 << ' ' << vertI-1 << ' ' << vertI
-                        << nl;
-                }
-            }
-            else
-            {
-                forAll(samplePoints_, pointi)
-                {
-                    meshTools::writeOBJ(str, points()[pointi]);
-                    vertI++;
-
-                    meshTools::writeOBJ(str, samplePoints_[pointi]);
-                    vertI++;
-
-                    label facei = sampleElements_[pointi];
-                    meshTools::writeOBJ(str, mesh().faceCentres()[facei]);
-                    vertI++;
-                    str << "l " << vertI-2 << ' ' << vertI-1 << ' ' << vertI
-                        << nl;
-                }
+                label elemi = sampleElements_[pointi];
+                meshTools::writeOBJ(str, centres[elemi]);
+                vertI++;
+                str << "l " << vertI-2 << ' ' << vertI-1 << ' ' << vertI << nl;
             }
         }
         else
         {
-            if (sampleSource_ == cells || sampleSource_ == insideCells)
+            label vertI = 0;
+            forAll(sampleElements_, triI)
             {
-                forAll(sampleElements_, triI)
-                {
-                    meshTools::writeOBJ(str, faceCentres()[triI]);
-                    vertI++;
+                meshTools::writeOBJ(str, faceCentres()[triI]);
+                vertI++;
 
-                    label celli = sampleElements_[triI];
-                    meshTools::writeOBJ(str, mesh().cellCentres()[celli]);
-                    vertI++;
-                    str << "l " << vertI-1 << ' ' << vertI << nl;
-                }
-            }
-            else
-            {
-                forAll(sampleElements_, triI)
-                {
-                    meshTools::writeOBJ(str, faceCentres()[triI]);
-                    vertI++;
-
-                    label facei = sampleElements_[triI];
-                    meshTools::writeOBJ(str, mesh().faceCentres()[facei]);
-                    vertI++;
-                    str << "l " << vertI-1 << ' ' << vertI << nl;
-                }
+                label elemi = sampleElements_[triI];
+                meshTools::writeOBJ(str, centres[elemi]);
+                vertI++;
+                str << "l " << vertI-1 << ' ' << vertI << nl;
             }
         }
     }
 
-
     needsUpdate_ = false;
     return true;
 }
@@ -553,6 +657,7 @@ Foam::sampledTriSurfaceMesh::sampledTriSurfaceMesh
     needsUpdate_(true),
     keepIds_(false),
     originalIds_(),
+    zoneIds_(),
     sampleElements_(0),
     samplePoints_(0)
 {}
@@ -584,6 +689,7 @@ Foam::sampledTriSurfaceMesh::sampledTriSurfaceMesh
     needsUpdate_(true),
     keepIds_(dict.lookupOrDefault<Switch>("keepIds", false)),
     originalIds_(),
+    zoneIds_(),
     sampleElements_(0),
     samplePoints_(0)
 {}
@@ -617,6 +723,7 @@ Foam::sampledTriSurfaceMesh::sampledTriSurfaceMesh
     needsUpdate_(true),
     keepIds_(false),
     originalIds_(),
+    zoneIds_(),
     sampleElements_(0),
     samplePoints_(0)
 {}
@@ -646,6 +753,7 @@ bool Foam::sampledTriSurfaceMesh::expire()
 
     sampledSurface::clearGeom();
     MeshStorage::clear();
+    zoneIds_.clear();
 
     originalIds_.clear();
     boundaryTreePtr_.clear();
diff --git a/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.H b/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.H
index 6cd96a4770c0c49e8c19a7a871016fd3c6792e47..b46d7649f6bc9ed80b0ac98bfb41bcd3fd138a6d 100644
--- a/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.H
+++ b/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.H
@@ -62,6 +62,7 @@ Description
 
 SourceFiles
     sampledTriSurfaceMesh.C
+    sampledTriSurfaceMeshTemplates.C
 
 \*---------------------------------------------------------------------------*/
 
@@ -71,6 +72,7 @@ SourceFiles
 #include "sampledSurface.H"
 #include "triSurfaceMesh.H"
 #include "MeshedSurface.H"
+#include "MeshedSurfacesFwd.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -87,7 +89,7 @@ class meshSearch;
 class sampledTriSurfaceMesh
 :
     public sampledSurface,
-    public UnsortedMeshedSurface<face>
+    public meshedSurface
 {
 public:
         //- Types of communications
@@ -95,13 +97,13 @@ public:
         {
             cells,
             insideCells,
-            boundaryFaces,
+            boundaryFaces
         };
 
 private:
 
     //- Private typedefs for convenience
-        typedef UnsortedMeshedSurface<face> MeshStorage;
+        typedef meshedSurface MeshStorage;
 
 
     // Private data
@@ -127,6 +129,9 @@ private:
         //- Search tree for all non-coupled boundary faces
         mutable autoPtr<indexedOctree<treeDataFace>> boundaryTreePtr_;
 
+        //- For compatibility with the meshSurf interface
+        labelList zoneIds_;
+
         //- From local surface triangle to mesh cell/face.
         labelList sampleElements_;
 
@@ -194,6 +199,10 @@ public:
 
     // Member Functions
 
+        //- Set new zoneIds list based on the surfZoneList information
+        static void setZoneMap(const surfZoneList&, labelList& zoneIds);
+
+
         //- Does the surface need an update?
         virtual bool needsUpdate() const;
 
@@ -226,7 +235,7 @@ public:
         //- Const access to per-face zone/region information
         virtual const labelList& zoneIds() const
         {
-            return MeshStorage::zoneIds();
+            return zoneIds_;
         }
 
         //- Face area vectors
@@ -260,6 +269,12 @@ public:
             return originalIds_;
         }
 
+        //- Sampling boundary values instead of cell values
+        bool onBoundary() const
+        {
+            return sampleSource_ == boundaryFaces;
+        }
+
 
         //- Sample field on surface
         virtual tmp<scalarField> sample
@@ -323,7 +338,7 @@ public:
             const interpolation<tensor>&
         ) const;
 
-        //- Write
+        //- Write information
         virtual void print(Ostream&) const;
 };
 
diff --git a/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMeshTemplates.C b/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMeshTemplates.C
index 880b7fd5b72ba2abfb4eaa078923a8feef5358ba..9cfba3874c6811926f56f3961ed5e365e99ccf71 100644
--- a/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMeshTemplates.C
+++ b/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMeshTemplates.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -38,7 +38,7 @@ Foam::sampledTriSurfaceMesh::sampleField
     tmp<Field<Type>> tvalues(new Field<Type>(sampleElements_.size()));
     Field<Type>& values = tvalues.ref();
 
-    if (sampleSource_ == cells || sampleSource_ == insideCells)
+    if (!onBoundary())
     {
         // Sample cells
 
@@ -52,7 +52,7 @@ Foam::sampledTriSurfaceMesh::sampleField
         // Sample boundary faces
 
         const polyBoundaryMesh& pbm = mesh().boundaryMesh();
-        label nBnd = mesh().nFaces()-mesh().nInternalFaces();
+        const label nBnd = mesh().nFaces()-mesh().nInternalFaces();
 
         // Create flat boundary field
 
@@ -94,7 +94,7 @@ Foam::sampledTriSurfaceMesh::interpolateField
     tmp<Field<Type>> tvalues(new Field<Type>(sampleElements_.size()));
     Field<Type>& values = tvalues.ref();
 
-    if (sampleSource_ == cells || sampleSource_ == insideCells)
+    if (!onBoundary())
     {
         // Sample cells.