diff --git a/src/fileFormats/ensight/file/ensightCase.C b/src/fileFormats/ensight/file/ensightCase.C
index 1d7ff6fc31eba39f131593ff99b20ed12dcb3541..2338cfbf0de51a9c45f299ecfc34837fb11c40e6 100644
--- a/src/fileFormats/ensight/file/ensightCase.C
+++ b/src/fileFormats/ensight/file/ensightCase.C
@@ -138,7 +138,7 @@ Foam::scalar Foam::ensightCase::writeTimeset() const
 {
     const label ts = 1;
 
-    const labelList indices = timesUsed_.sortedToc();
+    const labelList indices(timesUsed_.sortedToc());
     label count = indices.size();
 
     // correct for negative starting values
diff --git a/src/fileFormats/ensight/file/ensightCase.H b/src/fileFormats/ensight/file/ensightCase.H
index 67835f2e7d693ee7248185270e3af957d72e603c..1b516eed0ac218917da8966528164fd93078a1b9 100644
--- a/src/fileFormats/ensight/file/ensightCase.H
+++ b/src/fileFormats/ensight/file/ensightCase.H
@@ -106,7 +106,7 @@ private:
         //- Record time indices when geometry is written.
         //  These values will be used to decide if timeset 1
         //  or a separate timeset are used.
-        //  The special index '-1' is used static geometry.
+        //  The special index '-1' is used for static geometry.
         mutable labelHashSet geomTimes_;
 
         //- Record time indices when clouds are written.
diff --git a/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.C b/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.C
index c1fcbe4adf138e16aeb44ea635a55372da686c55..721b684b6ce44a950a08224f2c79bc2e087186a7 100644
--- a/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.C
+++ b/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.C
@@ -135,6 +135,7 @@ Foam::sampledSurfaces::sampledSurfaces
     sampleFaceScheme_(word::null),
     sampleNodeScheme_(word::null),
     mergedList_(),
+    changedGeom_(),
     formatter_(nullptr)
 {
     if (Pstream::parRun())
@@ -168,6 +169,7 @@ Foam::sampledSurfaces::sampledSurfaces
     sampleFaceScheme_(word::null),
     sampleNodeScheme_(word::null),
     mergedList_(),
+    changedGeom_(),
     formatter_(nullptr)
 {
     read(dict);
@@ -219,11 +221,12 @@ bool Foam::sampledSurfaces::write()
 
     const label nFields = classifyFields();
 
-    // write geometry first if required,
+    // Write geometry first if required,
     // or when no fields would otherwise be written
-    if (nFields == 0 || formatter_->separateGeometry())
+    if (formatter_->separateGeometry() || !nFields)
     {
         writeGeometry();
+        changedGeom_ = false;
     }
 
     const IOobjectList objects(obr_, obr_.time().timeName());
@@ -246,9 +249,7 @@ bool Foam::sampledSurfaces::write()
 
 bool Foam::sampledSurfaces::read(const dictionary& dict)
 {
-    bool surfacesFound = dict.found("surfaces");
-
-    if (surfacesFound)
+    if (dict.found("surfaces"))
     {
         sampleFaceScheme_ = dict.lookupOrDefault<word>("sampleScheme", "cell");
 
@@ -304,6 +305,10 @@ bool Foam::sampledSurfaces::read(const dictionary& dict)
         Pout<< ")" << endl;
     }
 
+    // New geometry
+    changedGeom_.resize(size());
+    changedGeom_ = true;
+
     return true;
 }
 
@@ -369,6 +374,8 @@ bool Foam::sampledSurfaces::expire()
         }
     }
 
+    changedGeom_ = true;
+
     // true if any surfaces just expired
     return justExpired;
 }
@@ -388,9 +395,12 @@ bool Foam::sampledSurfaces::update()
     {
         forAll(*this, surfi)
         {
-            if (operator[](surfi).update())
+            sampledSurface& s = operator[](surfi);
+
+            if (s.update())
             {
                 updated = true;
+                changedGeom_[surfi] = true;
             }
         }
 
@@ -414,6 +424,7 @@ bool Foam::sampledSurfaces::update()
         if (s.update())
         {
             updated = true;
+            changedGeom_[surfi] = true;
             mergedList_[surfi].merge(s, mergeDim);
         }
     }
diff --git a/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.H b/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.H
index 590da3ed4b92eb84403525e4f21488a1bcc6c73a..16432d71653ff9b2d905f82f7da951c3f9ee356f 100644
--- a/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.H
+++ b/src/sampling/sampledSurface/sampledSurfaces/sampledSurfaces.H
@@ -151,6 +151,9 @@ class sampledSurfaces
         //- Merged meshed surfaces (parallel only)
         List<mergedSurf> mergedList_;
 
+        //- Track which surfaces have changed
+        List<bool> changedGeom_;
+
 
     // Calculated
 
diff --git a/src/sampling/sampledSurface/sampledSurfaces/sampledSurfacesTemplates.C b/src/sampling/sampledSurface/sampledSurfaces/sampledSurfacesTemplates.C
index f314d9381877918bb40a2cbdf9906fac27098bde..19ccc258a663dacdc46d1b100f24f389a0c7bb0d 100644
--- a/src/sampling/sampledSurface/sampledSurfaces/sampledSurfacesTemplates.C
+++ b/src/sampling/sampledSurface/sampledSurfaces/sampledSurfacesTemplates.C
@@ -42,6 +42,13 @@ void Foam::sampledSurfaces::writeSurface
 {
     const sampledSurface& s = operator[](surfi);
 
+    if (changedGeom_[surfi])
+    {
+        // Trigger any changes
+        formatter_->updateMesh(outputDir, s.name());
+        changedGeom_[surfi] = false;
+    }
+
     if (Pstream::parRun())
     {
         // Collect values from all processors
diff --git a/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriter.C b/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriter.C
index 77cdd19687ed66dcf49e8db5098f28ee3ff24422..ef6575a29d60d18687741b1b05ef4752e0d1e980 100644
--- a/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriter.C
+++ b/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriter.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2015-2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -36,6 +36,61 @@ namespace Foam
 }
 
 
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+void Foam::ensightSurfaceWriter::printTimeset
+(
+    OSstream& os,
+    const label ts,
+    const scalar& timeValue
+)
+{
+    os
+        << "time set:               " << ts << nl
+        << "number of steps:        " << 1 << nl;
+
+    // Assume to be contiguous numbering
+    os  << "filename start number:  0" << nl
+        << "filename increment:     1" << nl
+        << "time values:" << nl;
+
+    os  << "    " << timeValue
+        << nl << nl;
+}
+
+
+void Foam::ensightSurfaceWriter::printTimeset
+(
+    OSstream& os,
+    const label ts,
+    const UList<scalar>& values
+)
+{
+    label count = values.size();
+    os
+        << "time set:               " << ts << nl
+        << "number of steps:        " << count << nl;
+
+    // Assume to be contiguous numbering
+    os  << "filename start number:  0" << nl
+        << "filename increment:     1" << nl
+        << "time values:" << nl;
+
+    count = 0;
+    for (const scalar& t : values)
+    {
+        os << ' ' << setw(12) << t;
+
+        if (++count % 6 == 0)
+        {
+            os << nl;
+        }
+    }
+    os  << nl << nl;
+}
+
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 Foam::ensightSurfaceWriter::ensightSurfaceWriter()
@@ -75,6 +130,47 @@ bool Foam::ensightSurfaceWriter::separateGeometry() const
 }
 
 
+void Foam::ensightSurfaceWriter::updateMesh
+(
+    const fileName& outputDir,
+    const fileName& surfaceName
+) const
+{
+    if (collateTimes_ && Pstream::master())
+    {
+        const ensight::FileName surfName(surfaceName);
+
+        const fileName baseDir = outputDir.path()/surfName;
+        const fileName timeDir = outputDir.name();
+        const scalar timeValue = readScalar(timeDir);
+
+        if (!isDir(baseDir))
+        {
+            mkDir(baseDir);
+        }
+
+        dictionary dict;
+
+        if (isFile(baseDir/"fieldsDict"))
+        {
+            IFstream is(baseDir/"fieldsDict");
+            if (is.good() && dict.read(is))
+            {
+                dict.read(is);
+            }
+        }
+
+        dict.set("updateMesh", timeValue);
+
+        {
+            OFstream os(baseDir/"fieldsDict");
+            os << "// Summary of Ensight fields, times" << nl << nl;
+            dict.write(os, false);
+        }
+    }
+}
+
+
 Foam::fileName Foam::ensightSurfaceWriter::write
 (
     const fileName& outputDir,
@@ -92,8 +188,6 @@ Foam::fileName Foam::ensightSurfaceWriter::write
         mkDir(outputDir);
     }
 
-    const scalar timeValue = 0.0;
-
     OFstream osCase(outputDir/surfName + ".case");
     ensightGeoFile osGeom
     (
@@ -114,14 +208,9 @@ Foam::fileName Foam::ensightSurfaceWriter::write
         << "GEOMETRY" << nl
         << "model:        1     " << osGeom.name().name() << nl
         << nl
-        << "TIME" << nl
-        << "time set:                      1" << nl
-        << "number of steps:               1" << nl
-        << "filename start number:         0" << nl
-        << "filename increment:            1" << nl
-        << "time values:" << nl
-        << "    " << timeValue << nl
-        << nl;
+        << "TIME" << nl;
+
+    printTimeset(osCase, 1, 0.0);
 
     ensightPartFaces ensPart(0, osGeom.name().name(), points, faces, true);
     osGeom << ensPart;
diff --git a/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriter.H b/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriter.H
index 4086a1875d08e8ae61014dd687c1286f67b4bfb4..db5ef7adb7a163c8c9819ef254c2eceefd263eac 100644
--- a/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriter.H
+++ b/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriter.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2015-2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -79,6 +79,23 @@ class ensightSurfaceWriter
 
     // Private Member Functions
 
+        //- Print time-set for ensight case file
+        static void printTimeset
+        (
+            OSstream& os,
+            const label ts,
+            const scalar& timeValue
+        );
+
+        //- Print time-set for ensight case file
+        static void printTimeset
+        (
+            OSstream& os,
+            const label ts,
+            const UList<scalar>& times
+        );
+
+
         //- Templated write operation - one file per timestep
         template<class Type>
         fileName writeCollated
@@ -144,6 +161,13 @@ public:
         //  False if geometry and field must be in a single file
         virtual bool separateGeometry() const;
 
+        //- Trigger for geometry changes.
+        //  \note this is a stop-gap solution
+        virtual void updateMesh
+        (
+            const fileName& outputDir,
+            const fileName& surfaceName
+        ) const; // override
 
         //- Write single surface geometry to file.
         virtual fileName write
diff --git a/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriterTemplates.C b/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriterTemplates.C
index c1fe9ae7fad83f888a22f067c7920abe767ed3c1..f04011fe01df8ec2262f107535a219b810f77380 100644
--- a/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriterTemplates.C
+++ b/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriterTemplates.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2014 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2015-2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -29,7 +29,6 @@ License
 #include "ensightPartFaces.H"
 #include "ensightSerialOutput.H"
 #include "ensightPTraits.H"
-#include "StringStream.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -63,15 +62,13 @@ Foam::fileName Foam::ensightSurfaceWriter::writeUncollated
 
     const fileName baseDir = outputDir/varName;
     const fileName timeDir = outputDir.name();
+    const scalar timeValue = readScalar(timeDir);
 
     if (!isDir(baseDir))
     {
         mkDir(baseDir);
     }
 
-    // const scalar timeValue = Foam::name(this->mesh().time().timeValue());
-    const scalar timeValue = readScalar(timeDir);
-
     OFstream osCase(baseDir/surfName + ".case");
     ensightGeoFile osGeom
     (
@@ -109,14 +106,10 @@ Foam::fileName Foam::ensightSurfaceWriter::writeUncollated
         << setw(15) << varName
         << "   " << surfName.c_str() << ".********." << varName << nl
         << nl
-        << "TIME" << nl
-        << "time set:               1" << nl
-        << "number of steps:        1" << nl
-        << "filename start number:  0" << nl
-        << "filename increment:     1" << nl
-        << "time values:" << nl
-        << "    " << timeValue
-        << nl << nl << "# end" << nl;
+        << "TIME" << nl;
+
+    printTimeset(osCase, 1, timeValue);
+    osCase << "# end" << nl;
 
     ensightPartFaces ensPart
     (
@@ -171,20 +164,22 @@ Foam::fileName Foam::ensightSurfaceWriter::writeCollated
 
     const fileName baseDir = outputDir.path()/surfName;
     const fileName timeDir = outputDir.name();
+    const scalar timeValue = readScalar(timeDir);
+    scalar meshValue = 0;
 
     if (!isDir(baseDir))
     {
         mkDir(baseDir);
     }
 
-    // surfName already validated
-    const fileName meshFile(baseDir/surfName + ".000000.mesh");
-    const scalar timeValue = readScalar(timeDir);
-    label timeIndex = 0;
+    label meshIndex = 0, timeIndex = 0;
+
+    fileName meshFile;
 
     // Do case file
     {
         dictionary dict;
+        scalarList meshes;
         scalarList times;
         bool stateChanged = false;
 
@@ -193,26 +188,56 @@ Foam::fileName Foam::ensightSurfaceWriter::writeCollated
             IFstream is(baseDir/"fieldsDict");
             if (is.good() && dict.read(is))
             {
-                dict.lookup("times") >> times;
-                const scalar timeValue = readScalar(timeDir);
-                label index = findLower(times, timeValue);
-                timeIndex = index+1;
+                dict.readIfPresent("meshes", meshes);
+                dict.readIfPresent("times", times);
+
+                timeIndex = 1+findLower(times, timeValue);
+
+                if (dict.readIfPresent("updateMesh", meshValue))
+                {
+                    meshIndex = 1+findLower(meshes, meshValue);
+
+                    dict.remove("updateMesh");
+                    stateChanged = true;
+                }
+                else if (meshes.size())
+                {
+                    meshIndex = meshes.size()-1;
+                    meshValue = meshes.last();
+                }
+                else
+                {
+                    meshIndex = 0;
+                }
             }
         }
 
-
         // Update stored times list
-        times.setSize(timeIndex+1, -1);
+        meshes.resize(meshIndex+1, -1);
+        times.resize(timeIndex+1, -1);
 
+        if (meshes[meshIndex] != meshValue)
+        {
+            stateChanged = true;
+        }
         if (times[timeIndex] != timeValue)
         {
             stateChanged = true;
         }
+
+        meshes[meshIndex] = meshValue;
         times[timeIndex] = timeValue;
 
+        // surfName already validated
+        meshFile =
+        (
+            baseDir/"data"/word::printf("%06d", meshIndex)/"geometry"
+        );
+
 
         // Add my information to dictionary
         {
+            dict.set("meshes", meshes);
             dict.set("times", times);
             if (dict.found("fields"))
             {
@@ -252,7 +277,7 @@ Foam::fileName Foam::ensightSurfaceWriter::writeCollated
             }
             {
                 OFstream os(baseDir/"fieldsDict");
-                os << "// summary of ensight times/fields" << nl << nl;
+                os << "// Summary of Ensight fields, times" << nl << nl;
                 dict.write(os, false);
             }
 
@@ -268,7 +293,8 @@ Foam::fileName Foam::ensightSurfaceWriter::writeCollated
                 << "type: ensight gold" << nl
                 << nl
                 << "GEOMETRY" << nl
-                << "model:  1   " << meshFile.name() << nl
+                << "model:  2  " // time-set 2
+                << " data/******/geometry" << nl
                 << nl
                 << "VARIABLE" << nl;
 
@@ -298,24 +324,12 @@ Foam::fileName Foam::ensightSurfaceWriter::writeCollated
             osCase << nl;
 
             osCase
-                << "TIME" << nl
-                << "time set:               1" << nl
-                << "number of steps:        " << timeIndex+1 << nl
-                << "filename start number:  0" << nl
-                << "filename increment:     1" << nl
-                << "time values:" << nl;
-
-            label count = 0;
-            forAll(times, timei)
-            {
-                osCase << ' ' << setw(12) << times[timei];
+                << "TIME" << nl;
 
-                if (!(++count % 6))
-                {
-                    osCase << nl;
-                }
-            }
-            osCase << nl << nl << "# end" << nl;
+            printTimeset(osCase, 1, times);
+            printTimeset(osCase, 2, meshes);
+
+            osCase << "# end" << nl;
         }
     }
 
@@ -341,16 +355,8 @@ Foam::fileName Foam::ensightSurfaceWriter::writeCollated
     }
 
 
-    // Get string representation
-    string timeString;
-    {
-        OStringStream os;
-        os.stdStream().fill('0');
-        os << setw(6) << timeIndex;
-        timeString = os.str();
-    }
-
-    fileName dataDir = baseDir/"data"/timeString;
+    // Location for data
+    fileName dataDir = baseDir/"data"/word::printf("%06d", timeIndex);
 
     // As per mkdir -p "data/000000"
     mkDir(dataDir);
diff --git a/src/sampling/sampledSurface/writers/surfaceWriter.H b/src/sampling/sampledSurface/writers/surfaceWriter.H
index 2b9b9315238d59417d3b31a84cea4706181a14d1..e22fca297735fc38461717b96feb7fc43f720af4 100644
--- a/src/sampling/sampledSurface/writers/surfaceWriter.H
+++ b/src/sampling/sampledSurface/writers/surfaceWriter.H
@@ -113,6 +113,16 @@ public:
             return false;
         }
 
+        //- Trigger for geometry changes.
+        //  \note this is a stop-gap solution until the writing infrastructure
+        //  is improved.
+        virtual void updateMesh
+        (
+            const fileName& outputDir,
+            const fileName& surfaceName
+        ) const
+        {}
+
         //- Write single surface geometry to file.
         virtual fileName write
         (
diff --git a/tutorials/compressible/rhoSimpleFoam/squareBend/system/controlDict b/tutorials/compressible/rhoSimpleFoam/squareBend/system/controlDict
index b95b2cb2d2863fa1354e7f836db33c11a204d276..74ccb50c5a6f64c548fe6b612698394da1deea18 100644
--- a/tutorials/compressible/rhoSimpleFoam/squareBend/system/controlDict
+++ b/tutorials/compressible/rhoSimpleFoam/squareBend/system/controlDict
@@ -52,6 +52,7 @@ runTimeModifiable true;
 functions
 {
     #include "sampling"
+    // #include "samplingDebug"
 }
 
 
diff --git a/tutorials/compressible/rhoSimpleFoam/squareBend/system/samplingDebug b/tutorials/compressible/rhoSimpleFoam/squareBend/system/samplingDebug
index 796b038f1aeb99407fc6e8ca05c2bed11804f5da..19c0f2d5c6dd093c338dd6e516842864e96c5b55 100644
--- a/tutorials/compressible/rhoSimpleFoam/squareBend/system/samplingDebug
+++ b/tutorials/compressible/rhoSimpleFoam/squareBend/system/samplingDebug
@@ -21,6 +21,7 @@ debug
         ensight
         {
             collateTimes  true;
+            // collateTimes  false;
         }
     }