diff --git a/applications/utilities/mesh/generation/foamyMesh/Allwmake b/applications/utilities/mesh/generation/foamyMesh/Allwmake
index 4090d594e41a78e8f10f6d88a1edae5367ddbb0f..85f046473cbd3b9ada96efc73eaef278e9aa5be1 100755
--- a/applications/utilities/mesh/generation/foamyMesh/Allwmake
+++ b/applications/utilities/mesh/generation/foamyMesh/Allwmake
@@ -4,8 +4,8 @@ cd ${0%/*} || exit 1    # Run from this directory
 # Parse arguments for library compilation
 . $WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments
 
-if [ -d "$CGAL_ARCH_PATH/include/CGAL" ] || \
-   [ "${CGAL_ARCH_PATH##*-}" = system -a -d /usr/include/CGAL ]
+if [ -f "$CGAL_ARCH_PATH/include/CGAL/version.h" ] || \
+   [ "${CGAL_ARCH_PATH##*-}" = system -a -f /usr/include/CGAL/version.h ]
 then
     set -x
 
diff --git a/applications/utilities/mesh/manipulation/renumberMesh/Allwmake b/applications/utilities/mesh/manipulation/renumberMesh/Allwmake
index 3acf4a1da70abac63f3b9717d3da8e308f0cd901..fae482e08b088ce26faa1f02b6e63728adb3afa8 100755
--- a/applications/utilities/mesh/manipulation/renumberMesh/Allwmake
+++ b/applications/utilities/mesh/manipulation/renumberMesh/Allwmake
@@ -3,7 +3,6 @@ cd ${0%/*} || exit 1    # Run from this directory
 
 # Parse arguments for compilation (at least for error catching)
 . $WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments
-set -x
 
 export COMPILE_FLAGS=''
 export LINK_FLAGS=''
@@ -21,6 +20,7 @@ then
     export LINK_FLAGS="${LINK_FLAGS} -lzoltanRenumber -L${ZOLTAN_ARCH_PATH}/lib -lzoltan"
 fi
 
+set -x
 wmake $targetType
 
 #------------------------------------------------------------------------------
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/files b/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/files
index 421e8392b88501e3efa3ae9323578c59721d8012..044aa6ae43a0911e12dbc805adeeb202ad3ad864 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/files
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/files
@@ -1,5 +1,6 @@
-ensightMesh.C
-ensightCloud.C
+ensightOutputCloud.C
+meshSubsetHelper.C
+
 foamToEnsight.C
 
 EXE = $(FOAM_APPBIN)/foamToEnsight
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/options b/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/options
index e2fc5311ffe99a7d649b81856ec502200b5f9cd9..dc8f10f1f1ac5dd01a0c4f00e26c11bf6694e9ed 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/options
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/Make/options
@@ -3,14 +3,12 @@ EXE_INC = \
     -I$(LIB_SRC)/meshTools/lnInclude \
     -I$(LIB_SRC)/dynamicMesh/lnInclude \
     -I$(LIB_SRC)/fileFormats/lnInclude \
-    -I$(LIB_SRC)/sampling/lnInclude \
     -I$(LIB_SRC)/lagrangian/basic/lnInclude \
     -I$(LIB_SRC)/conversion/lnInclude
 
 EXE_LIBS = \
     -ldynamicMesh \
     -lfileFormats \
-    -lsampling \
     -lgenericPatchFields \
     -llagrangian \
     -lconversion
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/cellSets.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/cellSets.H
deleted file mode 100644
index 54887f662a2b560fdf8417bd8b8f1b33ac88cf55..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/cellSets.H
+++ /dev/null
@@ -1,112 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2013 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/>.
-
-Class
-    Foam::cellSets
-
-Description
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef cellSets_H
-#define cellSets_H
-
-#include "labelList.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-/*---------------------------------------------------------------------------*\
-                           Class cellSets Declaration
-\*---------------------------------------------------------------------------*/
-
-class cellSets
-{
-public:
-
-        label nTets;
-        label nPyrs;
-        label nPrisms;
-        label nHexesWedges;
-        label nPolys;
-
-        labelList tets;
-        labelList pyrs;
-        labelList prisms;
-        labelList wedges;
-        labelList hexes;
-        labelList polys;
-
-
-    // Constructors
-
-        //- Construct given the number ov cells
-        cellSets(const label nCells)
-        :
-            nTets(0),
-            nPyrs(0),
-            nPrisms(0),
-            nHexesWedges(0),
-            nPolys(0),
-
-            tets(nCells),
-            pyrs(nCells),
-            prisms(nCells),
-            wedges(nCells),
-            hexes(nCells),
-            polys(nCells)
-        {}
-
-
-    // Member Functions
-
-        void setSize(const label nCells)
-        {
-            nTets = 0;
-            nPyrs = 0;
-            nPrisms = 0;
-            nHexesWedges = 0;
-            nPolys = 0;
-
-            tets.setSize(nCells);
-            pyrs.setSize(nCells);
-            prisms.setSize(nCells);
-            wedges.setSize(nCells);
-            hexes.setSize(nCells);
-            polys.setSize(nCells);
-        }
-
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkMeshMoving.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkMeshMoving.H
index bda9220acbddf7feca356febe22a9724f7f27ce9..912f48b28ac7d8b9c653d0d1e03fe31f08117ee1 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkMeshMoving.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkMeshMoving.H
@@ -38,8 +38,7 @@ if (timeDirs.size() > 1 && Pstream::master())
 
     if (meshMoving)
     {
-        Info<< "found." << nl
-            << "    Writing meshes for every timestep." << endl;
+        Info<< "found. Writing meshes for every timestep." << endl;
     }
     else
     {
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightAsciiStream.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightAsciiStream.H
deleted file mode 100644
index ceccc987aeae269798cf88d87adbcb315f0455bf..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightAsciiStream.H
+++ /dev/null
@@ -1,153 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-Class
-    Foam::ensightAsciiStream
-
-Description
-
-SourceFiles
-    ensightAsciiStream.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef ensightAsciiStream_H
-#define ensightAsciiStream_H
-
-#include "ensightStream.H"
-#include "OFstream.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-/*---------------------------------------------------------------------------*\
-                         Class ensightAsciiStream Declaration
-\*---------------------------------------------------------------------------*/
-
-class ensightAsciiStream
-:
-    public ensightStream
-{
-    // Private data
-
-        //- Output file stream
-        OFstream str_;
-
-
-    // Private Member Functions
-
-        //- Disallow default bitwise copy construct
-        ensightAsciiStream(const ensightAsciiStream&) = delete;
-
-        //- Disallow default bitwise assignment
-        void operator=(const ensightAsciiStream&) = delete;
-
-
-public:
-
-    // Constructors
-
-        //- Construct from components
-        ensightAsciiStream(const fileName& f)
-        :
-            ensightStream(f),
-            str_
-            (
-                f,
-                IOstream::ASCII,
-                IOstream::currentVersion,
-                IOstream::UNCOMPRESSED
-            )
-        {
-
-            str_.setf(ios_base::scientific, ios_base::floatfield);
-            str_.precision(5);
-        }
-
-
-    //- Destructor
-    virtual ~ensightAsciiStream()
-    {}
-
-
-    // Member Functions
-
-        virtual bool ascii() const
-        {
-            return true;
-        }
-
-        virtual void write(const char* c)
-        {
-            str_ << c << nl;
-        }
-
-        virtual void write(const int v)
-        {
-            str_ << setw(10) << v << nl;
-        }
-
-        virtual void write(const scalarField& sf)
-        {
-            forAll(sf, i)
-            {
-                if (mag(sf[i]) >= scalar(floatScalarVSMALL))
-                {
-                    str_ << setw(12) << sf[i] << nl;
-                }
-                else
-                {
-                    str_ << setw(12) << scalar(0) << nl;
-                }
-            }
-        }
-
-        virtual void write(const List<int>& sf)
-        {
-            forAll(sf, i)
-            {
-                str_ << setw(10) << sf[i];
-            }
-            str_<< nl;
-        }
-
-        virtual void writePartHeader(const label partI)
-        {
-            str_<< "part" << nl
-                << setw(10) << partI << nl;
-        }
-
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightBinaryStream.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightBinaryStream.H
deleted file mode 100644
index d1c3d6e3b37aa7f9b10da495ae7612798845a23c..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightBinaryStream.H
+++ /dev/null
@@ -1,150 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-Class
-    Foam::ensightBinaryStream
-
-Description
-
-SourceFiles
-    ensightBinaryStream.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef ensightBinaryStream_H
-#define ensightBinaryStream_H
-
-#include "ensightStream.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-/*---------------------------------------------------------------------------*\
-                         Class ensightBinaryStream Declaration
-\*---------------------------------------------------------------------------*/
-
-class ensightBinaryStream
-:
-    public ensightStream
-{
-    // Private data
-
-        //- Output file stream
-        autoPtr<std::ofstream> str_;
-
-
-    // Private Member Functions
-
-        //- Disallow default bitwise copy construct
-        ensightBinaryStream(const ensightBinaryStream&) = delete;
-
-        //- Disallow default bitwise assignment
-        void operator=(const ensightBinaryStream&) = delete;
-
-
-public:
-
-    // Constructors
-
-        //- Construct from components
-        ensightBinaryStream(const fileName& f)
-        :
-            ensightStream(f),
-            str_
-            (
-                new std::ofstream
-                (
-                    f.c_str(),
-                    ios_base::out | ios_base::binary | ios_base::trunc
-                )
-            )
-        {}
-
-
-    //- Destructor
-    virtual ~ensightBinaryStream()
-    {}
-
-
-    // Member Functions
-
-        virtual void write(const char* val)
-        {
-            char buffer[80];
-            strncpy(buffer, val, 80);
-            str_().write(buffer, 80*sizeof(char));
-        }
-
-        virtual void write(const int val)
-        {
-            str_().write(reinterpret_cast<const char*>(&val), sizeof(int));
-        }
-
-        virtual void write(const scalarField& sf)
-        {
-            if (sf.size())
-            {
-                List<float> temp(sf.size());
-
-                forAll(sf, i)
-                {
-                    temp[i] = float(sf[i]);
-                }
-
-                str_().write
-                (
-                    reinterpret_cast<const char*>(temp.begin()),
-                    sf.size()*sizeof(float)
-                );
-            }
-        }
-
-        virtual void write(const List<int>& sf)
-        {
-            str_().write
-            (
-                reinterpret_cast<const char*>(sf.begin()),
-                sf.size()*sizeof(int)
-            );
-        }
-
-        virtual void writePartHeader(const label partI)
-        {
-            write("part");
-            write(partI);
-        }
-
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightCaseTail.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightCaseTail.H
deleted file mode 100644
index 5a18a953c70b0f634621a3d03c95a01bf3a1887b..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightCaseTail.H
+++ /dev/null
@@ -1,33 +0,0 @@
-if (Pstream::master())
-{
-    ensightCaseFile.setf(ios_base::scientific, ios_base::floatfield);
-    ensightCaseFile.precision(5);
-
-    ensightCaseFile << nl << "TIME" << nl
-        << "time set:                      " << 1 << nl
-        << "number of steps:               " << nTimeSteps << nl
-        << "filename start number:         " << 0 << nl
-        << "filename increment:            " << 1 << nl;
-
-    ensightCaseFile << "time values:" << nl;
-
-    label count = 0;
-    scalar Tcorr = 0.0;
-    if (timeDirs[0].value() < 0)
-    {
-        Tcorr = -timeDirs[0].value();
-        Info<< "Correcting time values. Adding " << Tcorr << endl;
-    }
-
-    forAll(timeDirs, n)
-    {
-        ensightCaseFile << setw(12) << timeDirs[n].value() + Tcorr << " ";
-
-        if (++count % 6 == 0)
-        {
-            ensightCaseFile << nl;
-        }
-    }
-
-    ensightCaseFile << nl;
-}
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightField.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightField.C
deleted file mode 100644
index 1755c7d2a1cab677c4aa0c2ce4b14c1bb9082202..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightField.C
+++ /dev/null
@@ -1,816 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "ensightFile.H"
-#include "ensightField.H"
-#include "fvMesh.H"
-#include "volFields.H"
-#include "OFstream.H"
-#include "IOmanip.H"
-#include "volPointInterpolation.H"
-#include "ensightBinaryStream.H"
-#include "ensightAsciiStream.H"
-#include "globalIndex.H"
-#include "ensightPTraits.H"
-#include "zeroGradientFvPatchField.H"
-
-using namespace Foam;
-
-// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
-
-template<class Type>
-tmp<GeometricField<Type, fvPatchField, volMesh>>
-volField
-(
-    const fvMeshSubset& meshSubsetter,
-    const GeometricField<Type, fvPatchField, volMesh>& vf
-)
-{
-    if (meshSubsetter.hasSubMesh())
-    {
-        tmp<GeometricField<Type, fvPatchField, volMesh>> tfld
-        (
-            meshSubsetter.interpolate(vf)
-        );
-        tfld.ref().checkOut();
-        tfld.ref().rename(vf.name());
-        return tfld;
-    }
-    else
-    {
-        return vf;
-    }
-}
-
-
-template<class Type>
-tmp<GeometricField<Type, fvPatchField, volMesh>>
-volField
-(
-    const fvMeshSubset& meshSubsetter,
-    const typename GeometricField<Type, fvPatchField, volMesh>::Internal& df
-)
-{
-    // Construct volField (with zeroGradient) from dimensioned field
-
-    IOobject io(df);
-    io.readOpt()  = IOobject::NO_READ;
-    io.writeOpt() = IOobject::NO_WRITE;
-    io.registerObject() = false;
-
-    tmp<GeometricField<Type, fvPatchField, volMesh>> tvf
-    (
-        new GeometricField<Type, fvPatchField, volMesh>
-        (
-            io,
-            df.mesh(),
-            dimensioned<Type>("0", df.dimensions(), Zero),
-            zeroGradientFvPatchField<Type>::typeName
-        )
-    );
-    tvf.ref().primitiveFieldRef() = df;
-    tvf.ref().correctBoundaryConditions();
-
-    if (meshSubsetter.hasSubMesh())
-    {
-        const GeometricField<Type, fvPatchField, volMesh>& vf = tvf();
-
-        tmp<GeometricField<Type, fvPatchField, volMesh>> tfld
-        (
-            meshSubsetter.interpolate(vf)
-        );
-        tfld.ref().checkOut();
-        tfld.ref().rename(vf.name());
-        return tfld;
-    }
-    else
-    {
-        return tvf;
-    }
-}
-
-
-//template<class Container>
-//void readAndConvertField
-//(
-//    const fvMeshSubset& meshSubsetter,
-//    const IOobject& io,
-//    const fvMesh& mesh,
-//    const ensightMesh& eMesh,
-//    const fileName& dataDir,
-//    const label timeIndex,
-//    const bool nodeValues,
-//    Ostream& ensightCaseFile
-//)
-//{
-//    Container fld(io, mesh);
-//    ensightField<typename Container::value_type>
-//    (
-//        volField<typename Container::value_type>(meshSubsetter, fld),
-//        eMesh,
-//        dataDir,
-//        timeIndex,
-//        nodeValues,
-//        ensightCaseFile
-//    );
-//}
-
-
-template<class Type>
-Field<Type> map
-(
-    const Field<Type>& vf,
-    const labelList& map1,
-    const labelList& map2
-)
-{
-    Field<Type> mf(map1.size() + map2.size());
-
-    forAll(map1, i)
-    {
-        mf[i] = vf[map1[i]];
-    }
-
-    label offset = map1.size();
-
-    forAll(map2, i)
-    {
-        mf[i + offset] = vf[map2[i]];
-    }
-
-    return mf;
-}
-
-
-template<class Type>
-void writeField
-(
-    const char* key,
-    const Field<Type>& vf,
-    ensightStream& os
-)
-{
-    if (returnReduce(vf.size(), sumOp<label>()) > 0)
-    {
-        if (Pstream::master())
-        {
-            os.write(key);
-
-            for (direction i=0; i < pTraits<Type>::nComponents; ++i)
-            {
-                label cmpt = ensightPTraits<Type>::componentOrder[i];
-
-                os.write(vf.component(cmpt));
-
-                for (int slave=1; slave<Pstream::nProcs(); slave++)
-                {
-                    IPstream fromSlave(Pstream::scheduled, slave);
-                    scalarField slaveData(fromSlave);
-                    os.write(slaveData);
-                }
-            }
-        }
-        else
-        {
-            for (direction i=0; i < pTraits<Type>::nComponents; ++i)
-            {
-                label cmpt = ensightPTraits<Type>::componentOrder[i];
-
-                OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
-                toMaster<< vf.component(cmpt);
-            }
-        }
-    }
-}
-
-
-template<class Type>
-bool writePatchField
-(
-    const Field<Type>& pf,
-    const label patchi,
-    const label ensightPatchi,
-    const faceSets& boundaryFaceSet,
-    const ensightMesh::nFacePrimitives& nfp,
-    ensightStream& os
-)
-{
-    if (nfp.nTris || nfp.nQuads || nfp.nPolys)
-    {
-        if (Pstream::master())
-        {
-            os.writePartHeader(ensightPatchi);
-        }
-
-        writeField
-        (
-            "tria3",
-            Field<Type>(pf, boundaryFaceSet.tris),
-            os
-        );
-
-        writeField
-        (
-            "quad4",
-            Field<Type>(pf, boundaryFaceSet.quads),
-            os
-        );
-
-        writeField
-        (
-            "nsided",
-            Field<Type>(pf, boundaryFaceSet.polys),
-            os
-        );
-
-        return true;
-    }
-    else
-    {
-        return false;
-    }
-}
-
-
-template<class Type>
-void writePatchField
-(
-    const word& fieldName,
-    const Field<Type>& pf,
-    const word& patchName,
-    const ensightMesh& eMesh,
-    const fileName& dataDir,
-    const label timeIndex,
-    Ostream& ensightCaseFile
-)
-{
-    const List<faceSets>& boundaryFaceSets = eMesh.boundaryFaceSets();
-    const wordList& allPatchNames = eMesh.allPatchNames();
-    const HashTable<ensightMesh::nFacePrimitives>&
-        nPatchPrims = eMesh.nPatchPrims();
-
-    label ensightPatchi = eMesh.patchPartOffset();
-
-    label patchi = -1;
-
-    forAll(allPatchNames, i)
-    {
-        if (allPatchNames[i] == patchName)
-        {
-            patchi = i;
-            break;
-        }
-        ensightPatchi++;
-    }
-
-    ensightStream* filePtr(nullptr);
-    if (Pstream::master())
-    {
-        // TODO: verify that these are indeed valid ensight variable names
-        const word varName = patchName + '.' + fieldName;
-        const fileName postFileName = ensightFile::subDir(timeIndex)/varName;
-
-        // the data/ITER subdirectory must exist
-        mkDir(dataDir/postFileName.path());
-
-        if (timeIndex == 0)
-        {
-            const fileName dirName = dataDir.name()/ensightFile::mask();
-
-            ensightCaseFile.setf(ios_base::left);
-            ensightCaseFile
-                << ensightPTraits<Type>::typeName << " per "
-                << setw(20)
-                << "element:"
-                << " 1  "
-                << setw(15)
-                << varName.c_str() << ' '
-                << (dirName/varName).c_str()
-                << nl;
-        }
-
-        if (eMesh.format() == IOstream::BINARY)
-        {
-            filePtr = new ensightBinaryStream
-            (
-                dataDir/postFileName
-            );
-        }
-        else
-        {
-            filePtr = new ensightAsciiStream
-            (
-                dataDir/postFileName
-            );
-        }
-
-        filePtr->write(ensightPTraits<Type>::typeName);
-    }
-
-    ensightStream& os = *filePtr;
-
-    if (patchi >= 0)
-    {
-        writePatchField
-        (
-            pf,
-            patchi,
-            ensightPatchi,
-            boundaryFaceSets[patchi],
-            nPatchPrims.find(patchName)(),
-            os
-        );
-    }
-    else
-    {
-        faceSets nullFaceSets;
-
-        writePatchField
-        (
-            Field<Type>(),
-            -1,
-            ensightPatchi,
-            nullFaceSets,
-            nPatchPrims.find(patchName)(),
-            os
-        );
-    }
-
-    if (filePtr) // on master only
-    {
-        delete filePtr;
-    }
-}
-
-
-template<class Type>
-void ensightField
-(
-    const GeometricField<Type, fvPatchField, volMesh>& vf,
-    const ensightMesh& eMesh,
-    const fileName& dataDir,
-    const label timeIndex,
-    Ostream& ensightCaseFile
-)
-{
-    Info<< ' ' << vf.name();
-
-    const fvMesh& mesh = eMesh.mesh();
-
-    const cellSets& meshCellSets = eMesh.meshCellSets();
-    const List<faceSets>& boundaryFaceSets = eMesh.boundaryFaceSets();
-    const wordList& allPatchNames = eMesh.allPatchNames();
-    const wordHashSet& patchNames = eMesh.patchNames();
-    const HashTable<ensightMesh::nFacePrimitives>&
-        nPatchPrims = eMesh.nPatchPrims();
-    const List<faceSets>& faceZoneFaceSets = eMesh.faceZoneFaceSets();
-    const wordHashSet& faceZoneNames = eMesh.faceZoneNames();
-    const HashTable<ensightMesh::nFacePrimitives>&
-        nFaceZonePrims = eMesh.nFaceZonePrims();
-
-    const labelList& tets = meshCellSets.tets;
-    const labelList& pyrs = meshCellSets.pyrs;
-    const labelList& prisms = meshCellSets.prisms;
-    const labelList& wedges = meshCellSets.wedges;
-    const labelList& hexes = meshCellSets.hexes;
-    const labelList& polys = meshCellSets.polys;
-
-    ensightStream* filePtr(nullptr);
-    if (Pstream::master())
-    {
-        const ensight::VarName varName(vf.name());
-        const fileName postFileName = ensightFile::subDir(timeIndex)/varName;
-
-        // the data/ITER subdirectory must exist
-        mkDir(dataDir/postFileName.path());
-
-        if (timeIndex == 0)
-        {
-            const fileName dirName = dataDir.name()/ensightFile::mask();
-
-            ensightCaseFile.setf(ios_base::left);
-            ensightCaseFile
-                << ensightPTraits<Type>::typeName
-                << " per element:     1  "
-                << setw(15)
-                << varName.c_str() << ' '
-                << (dirName/varName).c_str()
-                << nl;
-        }
-
-        if (eMesh.format() == IOstream::BINARY)
-        {
-            filePtr = new ensightBinaryStream
-            (
-                dataDir/postFileName
-            );
-        }
-        else
-        {
-            filePtr = new ensightAsciiStream
-            (
-                dataDir/postFileName
-            );
-        }
-
-        filePtr->write(ensightPTraits<Type>::typeName);
-    }
-
-    ensightStream& os = *filePtr;
-
-    if (patchNames.empty())
-    {
-        eMesh.barrier();
-
-        if (Pstream::master())
-        {
-            os.writePartHeader(1);
-        }
-
-        writeField
-        (
-            "hexa8",
-            map(vf, hexes, wedges),
-            os
-        );
-
-        writeField
-        (
-            "penta6",
-            Field<Type>(vf, prisms),
-            os
-        );
-
-        writeField
-        (
-            "pyramid5",
-            Field<Type>(vf, pyrs),
-            os
-        );
-
-        writeField
-        (
-            "tetra4",
-            Field<Type>(vf, tets),
-            os
-        );
-
-        writeField
-        (
-            "nfaced",
-            Field<Type>(vf, polys),
-            os
-        );
-    }
-
-    label ensightPatchi = eMesh.patchPartOffset();
-
-    forAll(allPatchNames, patchi)
-    {
-        const word& patchName = allPatchNames[patchi];
-
-        eMesh.barrier();
-
-        if (patchNames.empty() || patchNames.found(patchName))
-        {
-            if
-            (
-                writePatchField
-                (
-                    vf.boundaryField()[patchi],
-                    patchi,
-                    ensightPatchi,
-                    boundaryFaceSets[patchi],
-                    nPatchPrims.find(patchName)(),
-                    os
-                )
-            )
-            {
-                ensightPatchi++;
-            }
-        }
-    }
-
-    // write faceZones, if requested
-    if (faceZoneNames.size())
-    {
-        // Interpolates cell values to faces - needed only when exporting
-        // faceZones...
-        GeometricField<Type, fvsPatchField, surfaceMesh> sf
-        (
-            linearInterpolate(vf)
-        );
-
-        forAllConstIter(wordHashSet, faceZoneNames, iter)
-        {
-            const word& faceZoneName = iter.key();
-
-            eMesh.barrier();
-
-            const label zoneID = mesh.faceZones().findZoneID(faceZoneName);
-            const faceZone& fz = mesh.faceZones()[zoneID];
-
-            // Prepare data to write
-            label nIncluded = 0;
-            forAll(fz, i)
-            {
-                if (eMesh.faceToBeIncluded(fz[i]))
-                {
-                    ++nIncluded;
-                }
-            }
-
-            Field<Type> values(nIncluded);
-
-            // Loop on the faceZone and store the needed field values
-            label j = 0;
-            forAll(fz, i)
-            {
-                label facei = fz[i];
-                if (mesh.isInternalFace(facei))
-                {
-                    values[j] = sf[facei];
-                    ++j;
-                }
-                else
-                {
-                    if (eMesh.faceToBeIncluded(facei))
-                    {
-                        label patchi = mesh.boundaryMesh().whichPatch(facei);
-                        const polyPatch& pp = mesh.boundaryMesh()[patchi];
-                        label patchFacei = pp.whichFace(facei);
-                        Type value = sf.boundaryField()[patchi][patchFacei];
-                        values[j] = value;
-                        ++j;
-                    }
-                }
-            }
-
-            if
-            (
-                writePatchField
-                (
-                    values,
-                    zoneID,
-                    ensightPatchi,
-                    faceZoneFaceSets[zoneID],
-                    nFaceZonePrims.find(faceZoneName)(),
-                    os
-                )
-            )
-            {
-                ensightPatchi++;
-            }
-        }
-    }
-
-    if (filePtr) // on master only
-    {
-        delete filePtr;
-    }
-}
-
-
-template<class Type>
-void ensightPointField
-(
-    const GeometricField<Type, pointPatchField, pointMesh>& pf,
-    const ensightMesh& eMesh,
-    const fileName& dataDir,
-    const label timeIndex,
-    Ostream& ensightCaseFile
-)
-{
-    Info<< ' ' << pf.name();
-
-    const fvMesh& mesh = eMesh.mesh();
-    const wordList& allPatchNames = eMesh.allPatchNames();
-    const wordHashSet& patchNames = eMesh.patchNames();
-    const wordHashSet& faceZoneNames = eMesh.faceZoneNames();
-
-    ensightStream* filePtr(nullptr);
-    if (Pstream::master())
-    {
-        const ensight::VarName varName(pf.name());
-        const fileName postFileName = ensightFile::subDir(timeIndex)/varName;
-
-        // the data/ITER subdirectory must exist
-        mkDir(dataDir/postFileName.path());
-
-        if (timeIndex == 0)
-        {
-            const fileName dirName = dataDir.name()/ensightFile::mask();
-
-            ensightCaseFile.setf(ios_base::left);
-            ensightCaseFile
-                << ensightPTraits<Type>::typeName
-                << " per "
-                << setw(20)
-                << " node:"
-                << " 1  "
-                << setw(15)
-                << varName.c_str() << ' '
-                << (dirName/varName).c_str()
-                << nl;
-        }
-
-        if (eMesh.format() == IOstream::BINARY)
-        {
-            filePtr = new ensightBinaryStream
-            (
-                dataDir/postFileName
-            );
-        }
-        else
-        {
-            filePtr = new ensightAsciiStream
-            (
-                dataDir/postFileName
-            );
-        }
-
-        filePtr->write(ensightPTraits<Type>::typeName);
-    }
-
-    ensightStream& os = *filePtr;
-
-    if (eMesh.patchNames().empty())
-    {
-        eMesh.barrier();
-
-        if (Pstream::master())
-        {
-            os.writePartHeader(1);
-        }
-
-        writeField
-        (
-            "coordinates",
-            Field<Type>(pf.primitiveField(), eMesh.uniquePointMap()),
-            os
-        );
-    }
-
-
-    label ensightPatchi = eMesh.patchPartOffset();
-
-    forAll(allPatchNames, patchi)
-    {
-        const word& patchName = allPatchNames[patchi];
-
-        eMesh.barrier();
-
-        if (patchNames.empty() || patchNames.found(patchName))
-        {
-            const fvPatch& p = mesh.boundary()[patchi];
-
-            if (returnReduce(p.size(), sumOp<label>()) > 0)
-            {
-                // Renumber the patch points/faces into unique points
-                labelList pointToGlobal;
-                labelList uniqueMeshPointLabels;
-                autoPtr<globalIndex> globalPointsPtr =
-                mesh.globalData().mergePoints
-                (
-                    p.patch().meshPoints(),
-                    p.patch().meshPointMap(),
-                    pointToGlobal,
-                    uniqueMeshPointLabels
-                );
-
-                if (Pstream::master())
-                {
-                    os.writePartHeader(ensightPatchi);
-                }
-
-                writeField
-                (
-                    "coordinates",
-                    Field<Type>(pf.primitiveField(), uniqueMeshPointLabels),
-                    os
-                );
-
-                ensightPatchi++;
-            }
-        }
-    }
-
-    // write faceZones, if requested
-    if (faceZoneNames.size())
-    {
-        forAllConstIter(wordHashSet, faceZoneNames, iter)
-        {
-            const word& faceZoneName = iter.key();
-
-            eMesh.barrier();
-
-            const label zoneID = mesh.faceZones().findZoneID(faceZoneName);
-            const faceZone& fz = mesh.faceZones()[zoneID];
-
-            if (returnReduce(fz().nPoints(), sumOp<label>()) > 0)
-            {
-                // Renumber the faceZone points/faces into unique points
-                labelList pointToGlobal;
-                labelList uniqueMeshPointLabels;
-                autoPtr<globalIndex> globalPointsPtr =
-                    mesh.globalData().mergePoints
-                    (
-                        fz().meshPoints(),
-                        fz().meshPointMap(),
-                        pointToGlobal,
-                        uniqueMeshPointLabels
-                    );
-
-                if (Pstream::master())
-                {
-                    os.writePartHeader(ensightPatchi);
-                }
-
-                writeField
-                (
-                    "coordinates",
-                    Field<Type>
-                    (
-                        pf.primitiveField(),
-                        uniqueMeshPointLabels
-                    ),
-                    os
-                );
-
-                ensightPatchi++;
-            }
-        }
-    }
-
-    if (filePtr) // on master only
-    {
-        delete filePtr;
-    }
-}
-
-
-template<class Type>
-void ensightField
-(
-    const GeometricField<Type, fvPatchField, volMesh>& vf,
-    const ensightMesh& eMesh,
-    const fileName& dataDir,
-    const label timeIndex,
-    const bool nodeValues,
-    Ostream& ensightCaseFile
-)
-{
-    if (nodeValues)
-    {
-        tmp<GeometricField<Type, pointPatchField, pointMesh>> pfld
-        (
-            volPointInterpolation::New(vf.mesh()).interpolate(vf)
-        );
-        pfld.ref().rename(vf.name());
-
-        ensightPointField<Type>
-        (
-            pfld,
-            eMesh,
-            dataDir,
-            timeIndex,
-            ensightCaseFile
-        );
-    }
-    else
-    {
-        ensightField<Type>
-        (
-            vf,
-            eMesh,
-            dataDir,
-            timeIndex,
-            ensightCaseFile
-        );
-    }
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightField.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightField.H
deleted file mode 100644
index 3769f93714c9b99074e1bd4323b16e4e40d9279a..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightField.H
+++ /dev/null
@@ -1,102 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-InApplication
-    foamToEnsight
-
-Description
-
-SourceFiles
-    ensightField.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef ensightField_H
-#define ensightField_H
-
-#include "ensightMesh.H"
-#include "fvMeshSubset.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-//- Wrapper to get hold of the field or the subsetted field
-template<class Type>
-Foam::tmp<Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh>>
-volField
-(
-    const Foam::fvMeshSubset&,
-    const Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh>& vf
-);
-
-
-//- Wrapper to convert dimensionedInternalField to volField
-template<class Type>
-Foam::tmp<Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh>>
-volField
-(
-    const Foam::fvMeshSubset&,
-    const typename Foam::GeometricField
-    <
-        Type,
-        Foam::fvPatchField,
-        Foam::volMesh
-    >::Internal& df
-);
-
-
-template<class Type>
-void ensightField
-(
-    const Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh>& vf,
-    const Foam::ensightMesh& eMesh,
-    const Foam::fileName& dataDir,
-    const Foam::label timeIndex,
-    const bool nodeValues,
-    Foam::Ostream& ensightCaseFile
-);
-
-
-template<class Type>
-void writePatchField
-(
-    const Foam::word& fieldName,
-    const Foam::Field<Type>& pf,
-    const Foam::word& patchName,
-    const Foam::ensightMesh& eMesh,
-    const Foam::fileName& dataDir,
-    const Foam::label timeIndex,
-    Foam::Ostream& ensightCaseFile
-);
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#ifdef NoRepository
-    #include "ensightField.C"
-#endif
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightMesh.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightMesh.C
deleted file mode 100644
index 5efc64bca8cac9d55ad2df65cec4735471d9c810..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightMesh.C
+++ /dev/null
@@ -1,1326 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "ensightMesh.H"
-#include "argList.H"
-#include "Time.H"
-#include "fvMesh.H"
-#include "globalMeshData.H"
-#include "PstreamCombineReduceOps.H"
-#include "processorPolyPatch.H"
-#include "cellModeller.H"
-#include "IOmanip.H"
-#include "globalIndex.H"
-#include "mapDistribute.H"
-#include "stringListOps.H"
-
-#include "ensightFile.H"
-#include "ensightBinaryStream.H"
-#include "ensightAsciiStream.H"
-
-#include <fstream>
-
-// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
-
-const char* Foam::ensightMesh::geometryName = "geometry";
-
-
-// * * * * * * * * * * * * * Private Functions * * * * * * * * * * * * * * //
-
-void Foam::ensightMesh::correct()
-{
-    patchPartOffset_ = 2;
-    meshCellSets_.setSize(mesh_.nCells());
-
-    boundaryFaceSets_.setSize(mesh_.boundary().size());
-    boundaryFaceSets_ = faceSets(); // if number of patches changes
-    allPatchNames_.clear();
-    patchNames_.clear();
-    nPatchPrims_ = 0;
-    faceZoneFaceSets_.setSize(mesh_.faceZones().size());
-    faceZoneFaceSets_ = faceSets(); // if number of patches changes
-    faceZoneNames_.clear();
-    nFaceZonePrims_ = 0;
-    boundaryFaceToBeIncluded_.clear();
-
-    if (!noPatches_)
-    {
-        // Patches are output. Check that they're synced.
-        mesh_.boundaryMesh().checkParallelSync(true);
-
-        allPatchNames_ = mesh_.boundaryMesh().names();
-        if (Pstream::parRun())
-        {
-            allPatchNames_.setSize
-            (
-                mesh_.boundary().size()
-              - mesh_.globalData().processorPatches().size()
-            );
-        }
-
-        if (patches_)
-        {
-            if (patchPatterns_.empty())
-            {
-                forAll(allPatchNames_, nameI)
-                {
-                    patchNames_.insert(allPatchNames_[nameI]);
-                }
-            }
-            else
-            {
-                // Find patch names which match that requested at command-line
-                forAll(allPatchNames_, nameI)
-                {
-                    const word& patchName = allPatchNames_[nameI];
-                    if (findStrings(patchPatterns_, patchName))
-                    {
-                        patchNames_.insert(patchName);
-                    }
-                }
-            }
-        }
-    }
-
-    if (patchNames_.size())
-    {
-        // no internalMesh
-        patchPartOffset_ = 1;
-    }
-    else
-    {
-        const cellShapeList& cellShapes = mesh_.cellShapes();
-
-        const cellModel& tet = *(cellModeller::lookup("tet"));
-        const cellModel& pyr = *(cellModeller::lookup("pyr"));
-        const cellModel& prism = *(cellModeller::lookup("prism"));
-        const cellModel& wedge = *(cellModeller::lookup("wedge"));
-        const cellModel& hex = *(cellModeller::lookup("hex"));
-
-
-
-        // Count the shapes
-        labelList& tets = meshCellSets_.tets;
-        labelList& pyrs = meshCellSets_.pyrs;
-        labelList& prisms = meshCellSets_.prisms;
-        labelList& wedges = meshCellSets_.wedges;
-        labelList& hexes = meshCellSets_.hexes;
-        labelList& polys = meshCellSets_.polys;
-
-        label nTets = 0;
-        label nPyrs = 0;
-        label nPrisms = 0;
-        label nWedges = 0;
-        label nHexes = 0;
-        label nPolys = 0;
-
-        forAll(cellShapes, celli)
-        {
-            const cellShape& cellShape = cellShapes[celli];
-            const cellModel& cellModel = cellShape.model();
-
-            if (cellModel == tet)
-            {
-                tets[nTets++] = celli;
-            }
-            else if (cellModel == pyr)
-            {
-                pyrs[nPyrs++] = celli;
-            }
-            else if (cellModel == prism)
-            {
-                prisms[nPrisms++] = celli;
-            }
-            else if (cellModel == wedge)
-            {
-                wedges[nWedges++] = celli;
-            }
-            else if (cellModel == hex)
-            {
-                hexes[nHexes++] = celli;
-            }
-            else
-            {
-                polys[nPolys++] = celli;
-            }
-        }
-
-        tets.setSize(nTets);
-        pyrs.setSize(nPyrs);
-        prisms.setSize(nPrisms);
-        wedges.setSize(nWedges);
-        hexes.setSize(nHexes);
-        polys.setSize(nPolys);
-
-        meshCellSets_.nTets = nTets;
-        reduce(meshCellSets_.nTets, sumOp<label>());
-
-        meshCellSets_.nPyrs = nPyrs;
-        reduce(meshCellSets_.nPyrs, sumOp<label>());
-
-        meshCellSets_.nPrisms = nPrisms;
-        reduce(meshCellSets_.nPrisms, sumOp<label>());
-
-        meshCellSets_.nHexesWedges = nWedges+nHexes;
-        reduce(meshCellSets_.nHexesWedges, sumOp<label>());
-
-        meshCellSets_.nPolys = nPolys;
-        reduce(meshCellSets_.nPolys, sumOp<label>());
-
-
-        // Determine parallel shared points
-        globalPointsPtr_ = mesh_.globalData().mergePoints
-        (
-            pointToGlobal_,
-            uniquePointMap_
-        );
-    }
-
-    if (!noPatches_)
-    {
-        forAll(mesh_.boundary(), patchi)
-        {
-            if (mesh_.boundary()[patchi].size())
-            {
-                const polyPatch& p = mesh_.boundaryMesh()[patchi];
-
-                labelList& tris = boundaryFaceSets_[patchi].tris;
-                labelList& quads = boundaryFaceSets_[patchi].quads;
-                labelList& polys = boundaryFaceSets_[patchi].polys;
-
-                tris.setSize(p.size());
-                quads.setSize(p.size());
-                polys.setSize(p.size());
-
-                label nTris = 0;
-                label nQuads = 0;
-                label nPolys = 0;
-
-                forAll(p, facei)
-                {
-                    const face& f = p[facei];
-
-                    if (f.size() == 3)
-                    {
-                        tris[nTris++] = facei;
-                    }
-                    else if (f.size() == 4)
-                    {
-                        quads[nQuads++] = facei;
-                    }
-                    else
-                    {
-                        polys[nPolys++] = facei;
-                    }
-                }
-
-                tris.setSize(nTris);
-                quads.setSize(nQuads);
-                polys.setSize(nPolys);
-            }
-        }
-    }
-
-    forAll(allPatchNames_, patchi)
-    {
-        const word& patchName = allPatchNames_[patchi];
-        nFacePrimitives nfp;
-
-        if (patchNames_.empty() || patchNames_.found(patchName))
-        {
-            if (mesh_.boundary()[patchi].size())
-            {
-                nfp.nTris   = boundaryFaceSets_[patchi].tris.size();
-                nfp.nQuads  = boundaryFaceSets_[patchi].quads.size();
-                nfp.nPolys  = boundaryFaceSets_[patchi].polys.size();
-            }
-        }
-
-        reduce(nfp.nTris, sumOp<label>());
-        reduce(nfp.nQuads, sumOp<label>());
-        reduce(nfp.nPolys, sumOp<label>());
-
-        nPatchPrims_.insert(patchName, nfp);
-    }
-
-    // faceZones
-    if (faceZones_)
-    {
-        wordList faceZoneNamesAll = mesh_.faceZones().names();
-        // Need to sort the list of all face zones since the index may vary
-        // from processor to processor...
-        sort(faceZoneNamesAll);
-
-        // Find faceZone names which match that requested at command-line
-        forAll(faceZoneNamesAll, nameI)
-        {
-            const word& zoneName = faceZoneNamesAll[nameI];
-            if (findStrings(faceZonePatterns_, zoneName))
-            {
-                faceZoneNames_.insert(zoneName);
-            }
-        }
-
-        // Build list of boundary faces to be exported
-        boundaryFaceToBeIncluded_.setSize
-        (
-            mesh_.nFaces()
-          - mesh_.nInternalFaces(),
-            1
-        );
-
-        forAll(mesh_.boundaryMesh(), patchi)
-        {
-            const polyPatch& pp = mesh_.boundaryMesh()[patchi];
-            if
-            (
-                isA<processorPolyPatch>(pp)
-             && !refCast<const processorPolyPatch>(pp).owner()
-            )
-            {
-                label bFacei = pp.start()-mesh_.nInternalFaces();
-                forAll(pp, i)
-                {
-                    boundaryFaceToBeIncluded_[bFacei++] = 0;
-                }
-            }
-        }
-
-        // Count face types in each faceZone
-        forAll(faceZoneNamesAll, zoneI)
-        {
-            const word& zoneName = faceZoneNamesAll[zoneI];
-            const label faceZoneId = mesh_.faceZones().findZoneID(zoneName);
-
-            const faceZone& fz = mesh_.faceZones()[faceZoneId];
-
-            if (fz.size())
-            {
-                labelList& tris = faceZoneFaceSets_[faceZoneId].tris;
-                labelList& quads = faceZoneFaceSets_[faceZoneId].quads;
-                labelList& polys = faceZoneFaceSets_[faceZoneId].polys;
-
-                tris.setSize(fz.size());
-                quads.setSize(fz.size());
-                polys.setSize(fz.size());
-
-                label nTris = 0;
-                label nQuads = 0;
-                label nPolys = 0;
-
-                label faceCounter = 0;
-
-                forAll(fz, i)
-                {
-                    label facei = fz[i];
-
-                    // Avoid counting faces on processor boundaries twice
-                    if (faceToBeIncluded(facei))
-                    {
-                        const face& f = mesh_.faces()[facei];
-
-                        if (f.size() == 3)
-                        {
-                            tris[nTris++] = faceCounter;
-                        }
-                        else if (f.size() == 4)
-                        {
-                            quads[nQuads++] = faceCounter;
-                        }
-                        else
-                        {
-                            polys[nPolys++] = faceCounter;
-                        }
-
-                        ++faceCounter;
-                    }
-                }
-
-                tris.setSize(nTris);
-                quads.setSize(nQuads);
-                polys.setSize(nPolys);
-            }
-        }
-
-        forAll(faceZoneNamesAll, zoneI)
-        {
-            const word& zoneName = faceZoneNamesAll[zoneI];
-            nFacePrimitives nfp;
-            const label faceZoneId = mesh_.faceZones().findZoneID(zoneName);
-
-            if (faceZoneNames_.found(zoneName))
-            {
-                if
-                (
-                    faceZoneFaceSets_[faceZoneId].tris.size()
-                 || faceZoneFaceSets_[faceZoneId].quads.size()
-                 || faceZoneFaceSets_[faceZoneId].polys.size()
-                )
-                {
-                    nfp.nTris   = faceZoneFaceSets_[faceZoneId].tris.size();
-                    nfp.nQuads  = faceZoneFaceSets_[faceZoneId].quads.size();
-                    nfp.nPolys  = faceZoneFaceSets_[faceZoneId].polys.size();
-                }
-            }
-
-            reduce(nfp.nTris, sumOp<label>());
-            reduce(nfp.nQuads, sumOp<label>());
-            reduce(nfp.nPolys, sumOp<label>());
-
-            nFaceZonePrims_.insert(zoneName, nfp);
-        }
-    }
-}
-
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::ensightMesh::ensightMesh
-(
-    const fvMesh& mesh,
-    const bool noPatches,
-
-    const bool patches,
-    const wordReList& patchPatterns,
-
-    const bool faceZones,
-    const wordReList& faceZonePatterns,
-
-    const IOstream::streamFormat format
-)
-:
-    mesh_(mesh),
-    noPatches_(noPatches),
-    patches_(patches),
-    patchPatterns_(patchPatterns),
-    faceZones_(faceZones),
-    faceZonePatterns_(faceZonePatterns),
-    format_(format),
-    meshCellSets_(mesh.nCells())
-{
-    correct();
-}
-
-
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::ensightMesh::~ensightMesh()
-{}
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-bool Foam::ensightMesh::faceToBeIncluded(const label facei) const
-{
-    bool res = false;
-
-    if (mesh_.isInternalFace(facei))
-    {
-        res = true;
-    }
-    else
-    {
-        res = boundaryFaceToBeIncluded_[facei-mesh_.nInternalFaces()];
-    }
-
-    return res;
-}
-
-
-void Foam::ensightMesh::barrier()
-{
-    label appI = 0;
-    reduce(appI,maxOp<label>());
-}
-
-
-Foam::cellShapeList Foam::ensightMesh::map
-(
-    const cellShapeList& cellShapes,
-    const labelList& prims,
-    const labelList& pointToGlobal
-) const
-{
-    cellShapeList mcsl(prims.size());
-
-    forAll(prims, i)
-    {
-        mcsl[i] = cellShapes[prims[i]];
-        inplaceRenumber(pointToGlobal, mcsl[i]);
-    }
-
-    return mcsl;
-}
-
-
-Foam::cellShapeList Foam::ensightMesh::map
-(
-    const cellShapeList& cellShapes,
-    const labelList& hexes,
-    const labelList& wedges,
-    const labelList& pointToGlobal
-) const
-{
-    cellShapeList mcsl(hexes.size() + wedges.size());
-
-    forAll(hexes, i)
-    {
-        mcsl[i] = cellShapes[hexes[i]];
-        inplaceRenumber(pointToGlobal, mcsl[i]);
-    }
-
-    label offset = hexes.size();
-
-    const cellModel& hex = *(cellModeller::lookup("hex"));
-    labelList hexLabels(8);
-
-    forAll(wedges, i)
-    {
-        const cellShape& cellPoints = cellShapes[wedges[i]];
-
-        hexLabels[0] = cellPoints[0];
-        hexLabels[1] = cellPoints[1];
-        hexLabels[2] = cellPoints[0];
-        hexLabels[3] = cellPoints[2];
-        hexLabels[4] = cellPoints[3];
-        hexLabels[5] = cellPoints[4];
-        hexLabels[6] = cellPoints[6];
-        hexLabels[7] = cellPoints[5];
-
-        mcsl[i + offset] = cellShape(hex, hexLabels);
-        inplaceRenumber(pointToGlobal, mcsl[i + offset]);
-    }
-
-    return mcsl;
-}
-
-
-void Foam::ensightMesh::writePrims
-(
-    const cellShapeList& cellShapes,
-    ensightStream& ensightGeometryFile
-) const
-{
-    // Create a temp int array
-    if (cellShapes.size())
-    {
-        if (format_ == IOstream::ASCII)
-        {
-            // Workaround for paraview issue : write one cell per line
-
-            forAll(cellShapes, i)
-            {
-                const cellShape& cellPoints = cellShapes[i];
-
-                List<int> temp(cellPoints.size());
-
-                forAll(cellPoints, pointi)
-                {
-                    temp[pointi] = cellPoints[pointi] + 1;
-                }
-                ensightGeometryFile.write(temp);
-            }
-        }
-        else
-        {
-            // All the cellShapes have the same number of elements!
-            int numIntElem = cellShapes.size()*cellShapes[0].size();
-            List<int> temp(numIntElem);
-
-            int n = 0;
-
-            forAll(cellShapes, i)
-            {
-                const cellShape& cellPoints = cellShapes[i];
-
-                forAll(cellPoints, pointi)
-                {
-                    temp[n] = cellPoints[pointi] + 1;
-                    n++;
-                }
-            }
-            ensightGeometryFile.write(temp);
-        }
-    }
-}
-
-
-void Foam::ensightMesh::writePolysNFaces
-(
-    const labelList& polys,
-    const cellList& cellFaces,
-    ensightStream& ensightGeometryFile
-) const
-{
-    forAll(polys, i)
-    {
-        ensightGeometryFile.write(cellFaces[polys[i]].size());
-    }
-}
-
-
-void Foam::ensightMesh::writePolysNPointsPerFace
-(
-    const labelList& polys,
-    const cellList& cellFaces,
-    const faceList& faces,
-    ensightStream& ensightGeometryFile
-) const
-{
-    forAll(polys, i)
-    {
-        const labelList& cf = cellFaces[polys[i]];
-
-        forAll(cf, facei)
-        {
-            ensightGeometryFile.write(faces[cf[facei]].size());
-        }
-    }
-}
-
-
-void Foam::ensightMesh::writePolysPoints
-(
-    const labelList& polys,
-    const cellList& cellFaces,
-    const faceList& faces,
-    const labelList& faceOwner,
-    ensightStream& ensightGeometryFile
-) const
-{
-    forAll(polys, i)
-    {
-        const labelList& cf = cellFaces[polys[i]];
-
-        forAll(cf, facei)
-        {
-            const label faceId = cf[facei];
-            const face& f = faces[faceId];  // points of face (in global points)
-            const label np = f.size();
-            bool reverseOrder = false;
-            if (faceId >= faceOwner.size())
-            {
-                // Boundary face.
-                // Nothing should be done for processor boundary.
-                // The current cell always owns them. Given that we
-                // are reverting the
-                // order when the cell is the neighbour to the face,
-                // the orientation of
-                // all the boundaries, no matter if they are "real"
-                // or processorBoundaries, is consistent.
-            }
-            else
-            {
-                if (faceOwner[faceId] != polys[i])
-                {
-                    reverseOrder = true;
-                }
-            }
-
-            // If the face owner is the current cell, write the points
-            // in the standard order.
-            // If the face owner is not the current cell, write the points
-            // in reverse order.
-            // EnSight prefers to have all the faces of an nfaced cell
-            // oriented in the same way.
-            List<int> temp(np);
-            forAll(f, pointi)
-            {
-                if (reverseOrder)
-                {
-                    temp[np-1-pointi] = f[pointi] + 1;
-                }
-                else
-                {
-                    temp[pointi] = f[pointi] + 1;
-                }
-            }
-            ensightGeometryFile.write(temp);
-        }
-    }
-}
-
-
-void Foam::ensightMesh::writeAllPolys
-(
-    const labelList& pointToGlobal,
-    ensightStream& ensightGeometryFile
-) const
-{
-    if (meshCellSets_.nPolys)
-    {
-        const cellList& cellFaces = mesh_.cells();
-        const labelList& faceOwner = mesh_.faceOwner();
-
-        // Renumber faces to use global point numbers
-        faceList faces(mesh_.faces());
-        forAll(faces, i)
-        {
-            inplaceRenumber(pointToGlobal, faces[i]);
-        }
-
-        if (Pstream::master())
-        {
-            ensightGeometryFile.write("nfaced");
-            ensightGeometryFile.write(meshCellSets_.nPolys);
-        }
-
-        // Number of faces for each poly cell
-
-        if (Pstream::master())
-        {
-            // Master
-            writePolysNFaces
-            (
-                meshCellSets_.polys,
-                cellFaces,
-                ensightGeometryFile
-            );
-            // Slaves
-            for (int slave=1; slave<Pstream::nProcs(); slave++)
-            {
-                IPstream fromSlave(Pstream::scheduled, slave);
-                labelList polys(fromSlave);
-                cellList cellFaces(fromSlave);
-
-                writePolysNFaces
-                (
-                    polys,
-                    cellFaces,
-                    ensightGeometryFile
-                );
-            }
-        }
-        else
-        {
-            OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
-            toMaster<< meshCellSets_.polys << cellFaces;
-        }
-
-
-        // Number of points for each face of the above list
-        if (Pstream::master())
-        {
-            // Master
-            writePolysNPointsPerFace
-            (
-                meshCellSets_.polys,
-                cellFaces,
-                faces,
-                ensightGeometryFile
-            );
-            // Slaves
-            for (int slave=1; slave<Pstream::nProcs(); slave++)
-            {
-                IPstream fromSlave(Pstream::scheduled, slave);
-                labelList polys(fromSlave);
-                cellList cellFaces(fromSlave);
-                faceList faces(fromSlave);
-
-                writePolysNPointsPerFace
-                (
-                    polys,
-                    cellFaces,
-                    faces,
-                    ensightGeometryFile
-                );
-            }
-        }
-        else
-        {
-            OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
-            toMaster<< meshCellSets_.polys << cellFaces << faces;
-        }
-
-
-        // List of points id for each face of the above list
-        if (Pstream::master())
-        {
-            // Master
-            writePolysPoints
-            (
-                meshCellSets_.polys,
-                cellFaces,
-                faces,
-                faceOwner,
-                ensightGeometryFile
-            );
-            // Slaves
-            for (int slave=1; slave<Pstream::nProcs(); slave++)
-            {
-                IPstream fromSlave(Pstream::scheduled, slave);
-                labelList polys(fromSlave);
-                cellList cellFaces(fromSlave);
-                faceList faces(fromSlave);
-                labelList faceOwner(fromSlave);
-
-                writePolysPoints
-                (
-                    polys,
-                    cellFaces,
-                    faces,
-                    faceOwner,
-                    ensightGeometryFile
-                );
-            }
-        }
-        else
-        {
-            OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
-            toMaster<< meshCellSets_.polys << cellFaces << faces << faceOwner;
-        }
-    }
-}
-
-
-void Foam::ensightMesh::writeAllPrims
-(
-    const char* key,
-    const label nPrims,
-    const cellShapeList& cellShapes,
-    ensightStream& ensightGeometryFile
-) const
-{
-    if (nPrims)
-    {
-        if (Pstream::master())
-        {
-            ensightGeometryFile.write(key);
-            ensightGeometryFile.write(nPrims);
-
-            writePrims(cellShapes, ensightGeometryFile);
-
-            for (int slave=1; slave<Pstream::nProcs(); slave++)
-            {
-                IPstream fromSlave(Pstream::scheduled, slave);
-                cellShapeList cellShapes(fromSlave);
-
-                writePrims(cellShapes, ensightGeometryFile);
-            }
-        }
-        else
-        {
-            OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
-            toMaster<< cellShapes;
-        }
-    }
-}
-
-
-void Foam::ensightMesh::writeFacePrims
-(
-    const faceList& patchFaces,
-    ensightStream& ensightGeometryFile
-) const
-{
-    forAll(patchFaces, i)
-    {
-        const face& patchFace = patchFaces[i];
-
-        List<int> temp(patchFace.size());
-        forAll(patchFace, pointi)
-        {
-            temp[pointi] = patchFace[pointi] + 1;
-        }
-
-        ensightGeometryFile.write(temp);
-    }
-}
-
-
-void Foam::ensightMesh::writeAllFacePrims
-(
-    const char* key,
-    const labelList& prims,
-    const label nPrims,
-    const faceList& patchFaces,
-    ensightStream& ensightGeometryFile
-) const
-{
-    if (nPrims)
-    {
-        if (Pstream::master())
-        {
-            ensightGeometryFile.write(key);
-            ensightGeometryFile.write(nPrims);
-
-            writeFacePrims
-            (
-                UIndirectList<face>(patchFaces, prims)(),
-                ensightGeometryFile
-            );
-
-            for (int slave=1; slave<Pstream::nProcs(); slave++)
-            {
-                IPstream fromSlave(Pstream::scheduled, slave);
-                faceList patchFaces(fromSlave);
-
-                writeFacePrims(patchFaces, ensightGeometryFile);
-            }
-        }
-        else
-        {
-            OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
-            toMaster<< UIndirectList<face>(patchFaces, prims);
-        }
-    }
-}
-
-
-void Foam::ensightMesh::writeNSidedNPointsPerFace
-(
-    const faceList& patchFaces,
-    ensightStream& ensightGeometryFile
-) const
-{
-    forAll(patchFaces, i)
-    {
-        ensightGeometryFile.write(patchFaces[i].size());
-    }
-}
-
-
-void Foam::ensightMesh::writeNSidedPoints
-(
-    const faceList& patchFaces,
-    ensightStream& ensightGeometryFile
-) const
-{
-    writeFacePrims(patchFaces, ensightGeometryFile);
-}
-
-
-void Foam::ensightMesh::writeAllNSided
-(
-    const labelList& prims,
-    const label nPrims,
-    const faceList& patchFaces,
-    ensightStream& ensightGeometryFile
-) const
-{
-    if (nPrims)
-    {
-        if (Pstream::master())
-        {
-            ensightGeometryFile.write("nsided");
-            ensightGeometryFile.write(nPrims);
-        }
-
-        // Number of points for each face
-        if (Pstream::master())
-        {
-            writeNSidedNPointsPerFace
-            (
-                UIndirectList<face>(patchFaces, prims)(),
-                ensightGeometryFile
-            );
-
-            for (int slave=1; slave<Pstream::nProcs(); slave++)
-            {
-                IPstream fromSlave(Pstream::scheduled, slave);
-                faceList patchFaces(fromSlave);
-
-                writeNSidedNPointsPerFace
-                (
-                    patchFaces,
-                    ensightGeometryFile
-                );
-            }
-        }
-        else
-        {
-            OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
-            toMaster<< UIndirectList<face>(patchFaces, prims);
-        }
-
-        // List of points id for each face
-        if (Pstream::master())
-        {
-            writeNSidedPoints
-            (
-                UIndirectList<face>(patchFaces, prims)(),
-                ensightGeometryFile
-            );
-
-            for (int slave=1; slave<Pstream::nProcs(); slave++)
-            {
-                IPstream fromSlave(Pstream::scheduled, slave);
-                faceList patchFaces(fromSlave);
-
-                writeNSidedPoints(patchFaces, ensightGeometryFile);
-            }
-        }
-        else
-        {
-            OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
-            toMaster<< UIndirectList<face>(patchFaces, prims);
-        }
-    }
-}
-
-
-void Foam::ensightMesh::writeAllPoints
-(
-    const label ensightPartI,
-    const word& ensightPartName,
-    const pointField& uniquePoints,
-    const label nPoints,
-    ensightStream& ensightGeometryFile
-) const
-{
-    barrier();
-
-    if (Pstream::master())
-    {
-        ensightGeometryFile.writePartHeader(ensightPartI);
-        ensightGeometryFile.write(ensightPartName.c_str());
-        ensightGeometryFile.write("coordinates");
-        ensightGeometryFile.write(nPoints);
-
-        for (direction d=0; d<vector::nComponents; d++)
-        {
-            ensightGeometryFile.write(uniquePoints.component(d));
-            for (int slave=1; slave<Pstream::nProcs(); slave++)
-            {
-                IPstream fromSlave(Pstream::scheduled, slave);
-                scalarField patchPointsComponent(fromSlave);
-                ensightGeometryFile.write(patchPointsComponent);
-            }
-        }
-    }
-    else
-    {
-        for (direction d=0; d<vector::nComponents; d++)
-        {
-            OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
-            toMaster<< uniquePoints.component(d);
-        }
-    }
-}
-
-
-void Foam::ensightMesh::write
-(
-    const fileName& dataDir,
-    const label timeIndex,
-    const bool meshMoving,
-    Ostream& ensightCaseFile
-) const
-{
-    const cellShapeList& cellShapes = mesh_.cellShapes();
-
-    ensightStream* filePtr(nullptr);
-    if (Pstream::master())
-    {
-        // set the filename of the ensight file
-        fileName geoFileName = dataDir.path()/ensightMesh::geometryName;
-
-        if (meshMoving)
-        {
-            geoFileName =
-                dataDir/ensightFile::subDir(timeIndex)
-               /ensightMesh::geometryName;
-
-            mkDir(geoFileName.path());
-        }
-
-        if (format_ == IOstream::BINARY)
-        {
-            filePtr = new ensightBinaryStream
-            (
-                geoFileName
-            );
-            filePtr->write("C binary");
-        }
-        else
-        {
-            filePtr = new ensightAsciiStream
-            (
-                geoFileName
-            );
-        }
-    }
-
-    ensightStream& os = *filePtr;
-
-    if (Pstream::master())
-    {
-        string desc = string("written by OpenFOAM-") + Foam::FOAMversion;
-
-        os.write("EnSight Geometry File");
-        os.write(desc.c_str());
-        os.write("node id assign");
-        os.write("element id assign");
-    }
-
-    if (patchNames_.empty())
-    {
-        label nPoints = globalPoints().size();
-
-        const pointField uniquePoints(mesh_.points(), uniquePointMap_);
-
-        writeAllPoints
-        (
-            1,
-            "internalMesh",
-            uniquePoints,
-            nPoints,
-            os
-        );
-
-        writeAllPrims
-        (
-            "hexa8",
-            meshCellSets_.nHexesWedges,
-            map         // Rewrite cellShapes to global numbering
-            (
-                cellShapes,
-                meshCellSets_.hexes,
-                meshCellSets_.wedges,
-                pointToGlobal_
-            ),
-            os
-        );
-
-        writeAllPrims
-        (
-            "penta6",
-            meshCellSets_.nPrisms,
-            map(cellShapes, meshCellSets_.prisms, pointToGlobal_),
-            os
-        );
-
-        writeAllPrims
-        (
-            "pyramid5",
-            meshCellSets_.nPyrs,
-            map(cellShapes, meshCellSets_.pyrs, pointToGlobal_),
-            os
-        );
-
-        writeAllPrims
-        (
-            "tetra4",
-            meshCellSets_.nTets,
-            map(cellShapes, meshCellSets_.tets, pointToGlobal_),
-            os
-        );
-
-        writeAllPolys
-        (
-            pointToGlobal_,
-            os
-        );
-    }
-
-
-    label ensightPatchi = patchPartOffset_;
-
-    forAll(allPatchNames_, patchi)
-    {
-        const word& patchName = allPatchNames_[patchi];
-
-        if (patchNames_.empty() || patchNames_.found(patchName))
-        {
-            const nFacePrimitives& nfp = nPatchPrims_[patchName];
-
-            if (nfp.nTris || nfp.nQuads || nfp.nPolys)
-            {
-                const polyPatch& p = mesh_.boundaryMesh()[patchi];
-
-                const labelList& tris = boundaryFaceSets_[patchi].tris;
-                const labelList& quads = boundaryFaceSets_[patchi].quads;
-                const labelList& polys = boundaryFaceSets_[patchi].polys;
-
-                // Renumber the patch points/faces into unique points
-                labelList pointToGlobal;
-                labelList uniqueMeshPointLabels;
-                autoPtr<globalIndex> globalPointsPtr =
-                    mesh_.globalData().mergePoints
-                    (
-                        p.meshPoints(),
-                        p.meshPointMap(),
-                        pointToGlobal,
-                        uniqueMeshPointLabels
-                    );
-
-                pointField uniquePoints(mesh_.points(), uniqueMeshPointLabels);
-                // Renumber the patch faces
-                faceList patchFaces(p.localFaces());
-                forAll(patchFaces, i)
-                {
-                    inplaceRenumber(pointToGlobal, patchFaces[i]);
-                }
-
-                writeAllPoints
-                (
-                    ensightPatchi++,
-                    patchName,
-                    uniquePoints,
-                    globalPointsPtr().size(),
-                    os
-                );
-
-                writeAllFacePrims
-                (
-                    "tria3",
-                    tris,
-                    nfp.nTris,
-                    patchFaces,
-                    os
-                );
-
-                writeAllFacePrims
-                (
-                    "quad4",
-                    quads,
-                    nfp.nQuads,
-                    patchFaces,
-                    os
-                );
-
-                writeAllNSided
-                (
-                    polys,
-                    nfp.nPolys,
-                    patchFaces,
-                    os
-                );
-            }
-        }
-    }
-
-    // write faceZones, if requested
-    forAllConstIter(wordHashSet, faceZoneNames_, iter)
-    {
-        const word& faceZoneName = iter.key();
-
-        label faceID = mesh_.faceZones().findZoneID(faceZoneName);
-
-        const faceZone& fz = mesh_.faceZones()[faceID];
-
-        const nFacePrimitives& nfp = nFaceZonePrims_[faceZoneName];
-
-        if (nfp.nTris || nfp.nQuads || nfp.nPolys)
-        {
-            const labelList& tris = faceZoneFaceSets_[faceID].tris;
-            const labelList& quads = faceZoneFaceSets_[faceID].quads;
-            const labelList& polys = faceZoneFaceSets_[faceID].polys;
-
-            // Renumber the faceZone points/faces into unique points
-            labelList pointToGlobal;
-            labelList uniqueMeshPointLabels;
-            autoPtr<globalIndex> globalPointsPtr =
-                mesh_.globalData().mergePoints
-                (
-                    fz().meshPoints(),
-                    fz().meshPointMap(),
-                    pointToGlobal,
-                    uniqueMeshPointLabels
-                );
-
-            pointField uniquePoints(mesh_.points(), uniqueMeshPointLabels);
-
-            // Find the list of master faces belonging to the faceZone,
-            // in local numbering
-            faceList faceZoneFaces(fz().localFaces());
-
-            // Count how many master faces belong to the faceZone. Is there
-            // a better way of doing this?
-            label nMasterFaces = 0;
-
-            forAll(fz, facei)
-            {
-                if (faceToBeIncluded(fz[facei]))
-                {
-                    ++nMasterFaces;
-                }
-            }
-
-            // Create the faceList for the master faces only and fill it.
-            faceList faceZoneMasterFaces(nMasterFaces);
-
-            label currentFace = 0;
-
-            forAll(fz, facei)
-            {
-                if (faceToBeIncluded(fz[facei]))
-                {
-                    faceZoneMasterFaces[currentFace] = faceZoneFaces[facei];
-                    ++currentFace;
-                }
-            }
-
-            // Renumber the faceZone master faces
-            forAll(faceZoneMasterFaces, i)
-            {
-                inplaceRenumber(pointToGlobal, faceZoneMasterFaces[i]);
-            }
-
-            writeAllPoints
-            (
-                ensightPatchi++,
-                faceZoneName,
-                uniquePoints,
-                globalPointsPtr().size(),
-                os
-            );
-
-            writeAllFacePrims
-            (
-                "tria3",
-                tris,
-                nfp.nTris,
-                faceZoneMasterFaces,
-                os
-            );
-
-            writeAllFacePrims
-            (
-                "quad4",
-                quads,
-                nfp.nQuads,
-                faceZoneMasterFaces,
-                os
-            );
-
-            writeAllNSided
-            (
-                polys,
-                nfp.nPolys,
-                faceZoneMasterFaces,
-                os
-            );
-        }
-    }
-
-    if (filePtr) // only on master
-    {
-        delete filePtr;
-    }
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightMesh.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightMesh.H
deleted file mode 100644
index 47e27730fe01a93a799d1bec259f13539f76ae11..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightMesh.H
+++ /dev/null
@@ -1,398 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-Class
-    Foam::ensightMesh
-
-Description
-
-SourceFiles
-    ensightMesh.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef ensightMesh_H
-#define ensightMesh_H
-
-#include "cellSets.H"
-#include "faceSets.H"
-#include "HashTable.H"
-#include "HashSet.H"
-#include "PackedBoolList.H"
-#include "wordReList.H"
-#include "scalarField.H"
-#include "cellShapeList.H"
-#include "cellList.H"
-
-#include <fstream>
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-class fvMesh;
-class argList;
-class globalIndex;
-class ensightStream;
-
-/*---------------------------------------------------------------------------*\
-                         Class ensightMesh Declaration
-\*---------------------------------------------------------------------------*/
-
-class ensightMesh
-{
-public:
-
-    //- The name for geometry files
-    static const char* geometryName;
-
-        //- Helper class for managing face primitives
-        class nFacePrimitives
-        {
-        public:
-
-            label nTris;
-            label nQuads;
-            label nPolys;
-
-            nFacePrimitives()
-            :
-                nTris(0),
-                nQuads(0),
-                nPolys(0)
-            {}
-        };
-
-private:
-
-    // Private data
-
-        //- Reference to the OpenFOAM mesh
-        const fvMesh& mesh_;
-
-        //- Suppress patches
-        const bool noPatches_;
-
-        //- Output selected patches only
-        const bool patches_;
-        const wordReList patchPatterns_;
-
-        //- Output selected faceZones
-        const bool faceZones_;
-        const wordReList faceZonePatterns_;
-
-        //- Ascii/Binary file output
-        const IOstream::streamFormat format_;
-
-        //- The ensight part id for the first patch
-        label patchPartOffset_;
-
-        cellSets meshCellSets_;
-
-        List<faceSets> boundaryFaceSets_;
-
-        wordList allPatchNames_;
-
-        wordHashSet patchNames_;
-
-        HashTable<nFacePrimitives> nPatchPrims_;
-
-        // faceZone - related variables
-        List<faceSets> faceZoneFaceSets_;
-
-        wordHashSet faceZoneNames_;
-
-        HashTable<nFacePrimitives> nFaceZonePrims_;
-
-        //- Per boundary face whether to include or not
-        PackedBoolList boundaryFaceToBeIncluded_;
-
-
-        // Parallel merged points
-
-            //- Global numbering for merged points
-            autoPtr<globalIndex> globalPointsPtr_;
-
-            //- From mesh point to global merged point
-            labelList pointToGlobal_;
-
-            //- Local points that are unique
-            labelList uniquePointMap_;
-
-
-
-    // Private Member Functions
-
-        //- Disallow default bitwise copy construct
-        ensightMesh(const ensightMesh&) = delete;
-
-        //- Disallow default bitwise assignment
-        void operator=(const ensightMesh&) = delete;
-
-        void writePoints
-        (
-            const scalarField& pointsComponent,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-        cellShapeList map
-        (
-            const cellShapeList& cellShapes,
-            const labelList& prims,
-            const labelList& pointToGlobal
-        ) const;
-
-        cellShapeList map
-        (
-            const cellShapeList& cellShapes,
-            const labelList& hexes,
-            const labelList& wedges,
-            const labelList& pointToGlobal
-        ) const;
-
-        void writePrims
-        (
-            const cellShapeList& cellShapes,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-        void writePolysNFaces
-        (
-            const labelList& polys,
-            const cellList& cellFaces,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-        void writePolysNPointsPerFace
-        (
-            const labelList& polys,
-            const cellList& cellFaces,
-            const faceList& faces,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-        void writePolysPoints
-        (
-            const labelList& polys,
-            const cellList& cellFaces,
-            const faceList& faces,
-            const labelList& faceOwner,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-        void writeAllPolys
-        (
-            const labelList& pointToGlobal,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-        void writeAllPrims
-        (
-            const char* key,
-            const label nPrims,
-            const cellShapeList& cellShapes,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-        void writeFacePrims
-        (
-            const faceList& patchFaces,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-        void writeAllFacePrims
-        (
-            const char* key,
-            const labelList& prims,
-            const label nPrims,
-            const faceList& patchFaces,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-        void writeNSidedNPointsPerFace
-        (
-            const faceList& patchFaces,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-        void writeNSidedPoints
-        (
-            const faceList& patchFaces,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-        void writeAllNSided
-        (
-            const labelList& prims,
-            const label nPrims,
-            const faceList& patchFaces,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-        void writeAllPoints
-        (
-            const label ensightPartI,
-            const word& ensightPartName,
-            const pointField& uniquePoints,
-            const label nPoints,
-            ensightStream& ensightGeometryFile
-        ) const;
-
-public:
-
-    // Constructors
-
-        //- Construct from fvMesh
-        ensightMesh
-        (
-            const fvMesh& mesh,
-            const bool noPatches,
-            const bool patches,
-            const wordReList& patchPatterns,
-            const bool faceZones,
-            const wordReList& faceZonePatterns,
-            const IOstream::streamFormat format = IOstream::BINARY
-        );
-
-
-    //- Destructor
-    ~ensightMesh();
-
-
-    // Member Functions
-
-        // Access
-
-            const fvMesh& mesh() const
-            {
-                return mesh_;
-            }
-
-            IOstream::streamFormat format() const
-            {
-                return format_;
-            }
-
-            const cellSets& meshCellSets() const
-            {
-                return meshCellSets_;
-            }
-
-            const List<faceSets>& boundaryFaceSets() const
-            {
-                return boundaryFaceSets_;
-            }
-
-            const wordList& allPatchNames() const
-            {
-                return allPatchNames_;
-            }
-
-            const wordHashSet& patchNames() const
-            {
-                return patchNames_;
-            }
-
-            const HashTable<nFacePrimitives>& nPatchPrims() const
-            {
-                return nPatchPrims_;
-            }
-
-            const List<faceSets>& faceZoneFaceSets() const
-            {
-                return faceZoneFaceSets_;
-            }
-
-            const wordHashSet& faceZoneNames() const
-            {
-                return faceZoneNames_;
-            }
-
-            const HashTable<nFacePrimitives>& nFaceZonePrims() const
-            {
-                return nFaceZonePrims_;
-            }
-
-            //- The ensight part id for the first patch
-            label patchPartOffset() const
-            {
-                return patchPartOffset_;
-            }
-
-
-        // Parallel point merging
-
-            //- Global numbering for merged points
-            const globalIndex& globalPoints() const
-            {
-                return globalPointsPtr_();
-            }
-
-            //- From mesh point to global merged point
-            const labelList& pointToGlobal() const
-            {
-                return pointToGlobal_;
-            }
-
-            //- Local points that are unique
-            const labelList& uniquePointMap() const
-            {
-                return uniquePointMap_;
-            }
-
-
-    // Other
-
-        //- Update for new mesh
-        void correct();
-
-        //- When exporting faceZones, check if a given face has to be included
-        //  or not (i.e. faces on processor boundaries)
-        bool faceToBeIncluded(const label facei) const;
-
-        //- Helper to cause barrier. Necessary on Quadrics.
-        static void barrier();
-
-
-    // I-O
-
-        void write
-        (
-            const fileName& ensightDir,
-            const label timeIndex,
-            const bool meshMoving,
-            Ostream& ensightCaseFile
-        ) const;
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightCloud.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloud.C
similarity index 79%
rename from applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightCloud.C
rename to applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloud.C
index 08779ff0a8c4b7d7a34cfdf35a234b342c4b8503..a3ca62ee2221d2dfab204623f6a88a48aa056de4 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightCloud.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloud.C
@@ -23,8 +23,8 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "ensightCloud.H"
-#include "ensightFile.H"
+#include "ensightOutputCloud.H"
+
 #include "fvMesh.H"
 #include "passiveParticle.H"
 #include "Cloud.H"
@@ -32,30 +32,19 @@ License
 
 // * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
 
-void Foam::ensightParticlePositions
+void Foam::ensightCloud::writePositions
 (
     const fvMesh& mesh,
-    const fileName& dataDir,
-    const label timeIndex,
     const word& cloudName,
-    const bool dataExists,
-    IOstream::streamFormat format
+    const bool exists,
+    autoPtr<ensightFile>& output
 )
 {
-    if (dataExists)
-    {
-        Info<< " positions";
-    }
-    else
-    {
-        Info<< " positions{0}";
-    }
-
     // Total number of parcels on all processes
     label nTotParcels = 0;
     autoPtr<Cloud<passiveParticle>> cloudPtr;
 
-    if (dataExists)
+    if (exists)
     {
         cloudPtr.reset(new Cloud<passiveParticle>(mesh, cloudName, false));
         nTotParcels = cloudPtr().size();
@@ -64,29 +53,15 @@ void Foam::ensightParticlePositions
 
     if (Pstream::master())
     {
-        const fileName postFileName =
-            ensightFile::subDir(timeIndex)/cloud::prefix/cloudName/"positions";
-
-        // the ITER/lagrangian subdirectory must exist
-        mkDir(dataDir/postFileName.path());
-
-        ensightFile os(dataDir, postFileName, format);
-
-        // tag binary format (just like geometry files)
-        os.writeBinaryHeader();
-        os.write(postFileName); // description
-        os.newline();
-        os.write("particle coordinates");
-        os.newline();
-        os.write(nTotParcels, 8);   // unusual width
-        os.newline();
+        ensightFile& os = output();
 
+        os.beginParticleCoordinates(nTotParcels);
         if (!nTotParcels)
         {
             return;  // DONE
         }
 
-        if (format == IOstream::BINARY)
+        if (os.format() == IOstream::BINARY)
         {
             // binary write is Ensight6 - first ids, then positions
 
@@ -131,7 +106,7 @@ void Foam::ensightParticlePositions
             {
                 const point& p = elmnt().position();
 
-                os.write(++parcelId, 8);    // unusual width
+                os.write(++parcelId, 8); // unusual width
                 os.write(p.x());
                 os.write(p.y());
                 os.write(p.z());
@@ -148,7 +123,7 @@ void Foam::ensightParticlePositions
                 {
                     const point& p = points[pti];
 
-                    os.write(++parcelId, 8);    // unusual width
+                    os.write(++parcelId, 8); // unusual width
                     os.write(p.x());
                     os.write(p.y());
                     os.write(p.z());
@@ -171,10 +146,11 @@ void Foam::ensightParticlePositions
 
         {
             OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
-            toMaster<< points;
+            toMaster
+                << points;
         }
     }
-
 }
 
+
 // ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputFunctions.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloud.H
similarity index 59%
rename from applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputFunctions.H
rename to applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloud.H
index 0b02a997e659c32b5b9d14d16b996c3e8bad1d78..982790b2f64e21a3385ef438187c1c309a854b7e 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputFunctions.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloud.H
@@ -2,8 +2,8 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
-     \\/     M anipulation  |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -21,78 +21,73 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
+Namespace
+    ensightOutput
+
 Description
-    Miscellaneous collection of functions and template related to Ensight data
+    A collection of global functions for writing ensight file content.
 
 SourceFiles
-    ensightOutputFunctions.C
+    ensightOutputCloud.C
+    ensightOutputCloudTemplates.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef ensightOutputFunctions_H
-#define ensightOutputFunctions_H
+#ifndef ensightOutputCloud_H
+#define ensightOutputCloud_H
 
 #include "ensightFile.H"
-#include "Cloud.H"
-#include "polyMesh.H"
-#include "IOobject.H"
+#include "ensightMesh.H"
 
-namespace Foam
-{
+#include "autoPtr.H"
+#include "IOField.H"
+#include "volFields.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-void ensightCaseEntry
-(
-    OFstream& caseFile,
-    const string& ensightType,
-    const word& fieldName,
-    const fileName& dataMask,
-    const fileName& local=fileName::null,
-    const label cloudNo=-1,
-    const label timeSet=1
-);
 
+namespace Foam
+{
+namespace ensightCloud
+{
 
-void ensightParticlePositions
+//- Write cloud positions
+void writePositions
 (
-    const polyMesh& mesh,
-    const fileName& dataDir,
-    const fileName& subDir,
+    const fvMesh& mesh,
     const word& cloudName,
-    IOstream::streamFormat format
+    const bool exists,
+    autoPtr<ensightFile>& output
 );
 
 
-//- Write lagrangian parcels
+//- Write cloud field, returning true if the field is non-empty.
 template<class Type>
-void ensightLagrangianField
+bool writeCloudField
 (
-    const IOobject& fieldObject,
-    const fileName& dataDir,
-    const fileName& subDir,
-    const word& cloudName,
-    IOstream::streamFormat format
+    const IOField<Type>& field,
+    ensightFile& os
 );
 
-//- Write generalized field components
+
+//- Write cloud field from IOobject, always returning true.
 template<class Type>
-void ensightVolField
+bool writeCloudField
 (
-    const ensightParts& partsList,
     const IOobject& fieldObject,
-    const fvMesh& mesh,
-    const fileName& dataDir,
-    const fileName& subDir,
-    IOstream::streamFormat format
+    const bool exists,
+    autoPtr<ensightFile>& output
 );
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // namespace ensightCloud
 } // namespace Foam
 
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 #ifdef NoRepository
-    #include "ensightOutputFunctions.C"
+    #include "ensightOutputCloudTemplates.C"
 #endif
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightCloudTemplates.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloudTemplates.C
similarity index 62%
rename from applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightCloudTemplates.C
rename to applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloudTemplates.C
index ac2559f17cfbb66b78a53c52e2a405c6daee4b1e..1b2c006c62381a42dcf61811135e1e219481f750 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightCloudTemplates.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightOutputCloudTemplates.C
@@ -23,24 +23,26 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "ensightCloud.H"
-#include "ensightFile.H"
-#include "Time.H"
-#include "IOField.H"
-#include "OFstream.H"
-#include "IOmanip.H"
+#include "ensightOutputCloud.H"
 #include "ensightPTraits.H"
 
+#include "IOField.H"
+#include "Time.H"
+#include "globalIndex.H"
+
+
 // * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
 
 template<class Type>
-void Foam::writeCloudField
+bool Foam::ensightCloud::writeCloudField
 (
     const Foam::IOField<Type>& field,
     Foam::ensightFile& os
 )
 {
-    if (returnReduce(field.size(), sumOp<label>()) > 0)
+    const bool exists = (returnReduce(field.size(), sumOp<label>()) > 0);
+
+    if (exists)
     {
         if (Pstream::master())
         {
@@ -106,86 +108,30 @@ void Foam::writeCloudField
         else
         {
             OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
-            toMaster<< field;
+            toMaster
+                << field;
         }
     }
+
+    return exists;
 }
 
 
 template<class Type>
-void Foam::ensightCloudField
+bool Foam::ensightCloud::writeCloudField
 (
     const Foam::IOobject& fieldObject,
-    const Foam::fileName& dataDir,
-    const Foam::label timeIndex,
-    const Foam::word& cloudName,
-    const Foam::label cloudNo,
-    Foam::Ostream& ensightCaseFile,
-    const bool dataExists,
-    Foam::IOstream::streamFormat format
+    const bool exists,
+    Foam::autoPtr<Foam::ensightFile>& output
 )
 {
-    const ensight::VarName varName(fieldObject.name());
-
-    if (dataExists)
-    {
-        Info<< ' ' << fieldObject.name();
-    }
-    else
-    {
-        Info<< ' ' << fieldObject.name() << "{0}"; // ie, empty field
-    }
-
-    ensightFile* filePtr(nullptr);
-    if (Pstream::master())
-    {
-        const fileName postFileName =
-            ensightFile::subDir(timeIndex)/cloud::prefix/cloudName/varName;
-
-        // the ITER/lagrangian subdirectory must exist
-        // the ITER/lagrangian subdirectory was already created
-        // when writing positions
-
-        mkDir(dataDir/postFileName.path());
-
-        if (timeIndex == 0)
-        {
-            const fileName dirName =
-                dataDir.name()/ensightFile::mask()/cloud::prefix/cloudName;
-
-            ensightCaseFile.setf(ios_base::left);
-
-            // prefix variables with 'c' (cloud)
-            ensightCaseFile
-                << ensightPTraits<Type>::typeName << " per "
-                << setw(20)
-                << "measured node:"
-                << " 1  "
-                << setw(15)
-                << ("c" + Foam::name(cloudNo) + varName).c_str() << ' '
-                << (dirName/varName).c_str()
-                << nl;
-        }
-
-        filePtr = new ensightFile(dataDir, postFileName, format);
-        // description
-        filePtr->write
-        (
-            string(postFileName + " <" + pTraits<Type>::typeName + ">")
-        );
-        filePtr->newline();
-    }
-
-    if (dataExists)
+    if (exists)
     {
         IOField<Type> field(fieldObject);
-        writeCloudField(field, *filePtr);
+        writeCloudField(field, output.rawRef());
     }
 
-    if (filePtr) // on master only
-    {
-        delete filePtr;
-    }
+    return true;
 }
 
 
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightStream.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightStream.H
deleted file mode 100644
index 89146e11023a703e3cfe8087864f2f1e7a215935..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightStream.H
+++ /dev/null
@@ -1,110 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-Class
-    Foam::ensightStream
-
-Description
-    Abstract base class for writing Ensight data
-
-SourceFiles
-    ensightStream.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef ensightStream_H
-#define ensightStream_H
-
-#include "fileName.H"
-#include "scalarField.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-
-/*---------------------------------------------------------------------------*\
-                         Class ensightStream Declaration
-\*---------------------------------------------------------------------------*/
-
-class ensightStream
-{
-    // Private data
-
-        const fileName name_;
-
-    // Private Member Functions
-
-        //- Disallow default bitwise copy construct
-        ensightStream(const ensightStream&) = delete;
-
-        //- Disallow default bitwise assignment
-        void operator=(const ensightStream&) = delete;
-
-
-public:
-
-    // Constructors
-
-        //- Construct from components
-        ensightStream(const fileName& f)
-        :
-            name_(f)
-        {}
-
-
-    //- Destructor
-    virtual ~ensightStream()
-    {}
-
-
-    // Member Functions
-
-        const fileName& name() const
-        {
-            return name_;
-        }
-
-        virtual void write(const char*) = 0;
-
-        virtual void write(const int) = 0;
-
-        virtual void write(const scalarField&) = 0;
-
-        virtual void write(const List<int>&) = 0;
-
-        virtual void writePartHeader(const label) = 0;
-
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H
index 0f228f723fe1b355c109ba7220a2f64b07df9f27..a37bbb7c09b96c4e778ad4f403155b1f71befc3c 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H
@@ -50,7 +50,7 @@ if (timeDirs.size() && !noLagrangian)
 
                 forAllConstIter(IOobjectList, cloudObjs, fieldIter)
                 {
-                    const IOobject obj = *fieldIter();
+                    const IOobject& obj = *fieldIter();
 
                     // Add field and field type
                     cloudIter().insert
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C
index 654b14b868db0250eeec0cc6268c6365b5a5698b..1d0f6c3beb3d0e08ec4318c1af86605ad96ee29b 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C
@@ -61,6 +61,9 @@ Usage
       - \par -width \<n\>
         Width of EnSight data subdir (default: 8)
 
+      - \par -deprecatedOrder
+        Use older ordering for volume cells (hex prism pyr tet poly)
+
 Note
     Writes to \a EnSight directory to avoid collisions with
     foamToEnsightParts
@@ -73,20 +76,22 @@ Note
 #include "IOmanip.H"
 #include "OFstream.H"
 
+#include "fvc.H"
 #include "volFields.H"
 
 #include "labelIOField.H"
 #include "scalarIOField.H"
 #include "tensorIOField.H"
 
-#include "ensightFile.H"
+// file-format/conversion
+#include "ensightCase.H"
+#include "ensightGeoFile.H"
 #include "ensightMesh.H"
-#include "ensightField.H"
-#include "ensightCloud.H"
+#include "ensightOutput.H"
 
-#include "fvc.H"
-#include "cellSet.H"
-#include "fvMeshSubset.H"
+// local files
+#include "meshSubsetHelper.H"
+#include "ensightOutputCloud.H"
 
 #include "memInfo.H"
 
@@ -94,7 +99,12 @@ using namespace Foam;
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-bool inFileNameList(const fileNameList& nameList, const word& name)
+// file-scope helper
+static bool inFileNameList
+(
+    const fileNameList& nameList,
+    const word& name
+)
 {
     forAll(nameList, i)
     {
@@ -171,10 +181,16 @@ int main(int argc, char *argv[])
         "n",
         "width of ensight data subdir"
     );
+    argList::addBoolOption
+    (
+        "deprecatedOrder",
+        "Use old ordering (hex prism pyr tet poly) "
+        "instead of the ascending number of points "
+        "(tet pyr prism hex poly)."
+    );
 
-    // the volume field types that we handle
-    const label nVolFieldTypes = 10;
-    const word volFieldTypes[] =
+    // The volume field types that we handle
+    const wordList volFieldTypes
     {
         volScalarField::typeName,
         volVectorField::typeName,
@@ -203,180 +219,113 @@ int main(int argc, char *argv[])
 
     cpuTime timer;
     memInfo mem;
-    Info<< "Initial memory "
-        << mem.update().size() << " kB" << endl;
+    Info<< "Initial memory " << mem.update().size() << " kB" << endl;
 
     #include "createTime.H"
 
     instantList timeDirs = timeSelector::select0(runTime, args);
 
-    // adjust output width
-    if (args.optionFound("width"))
-    {
-        ensightFile::subDirWidth(args.optionRead<label>("width"));
-    }
-
-    // define sub-directory name to use for EnSight data
-    fileName ensightDir = "EnSight";
-    args.optionReadIfPresent("name", ensightDir);
-
-    // Path to EnSight directory at case level only
-    // - For parallel cases, data only written from master
-    if (!ensightDir.isAbsolute())
-    {
-        ensightDir = args.rootPath()/args.globalCaseName()/ensightDir;
-    }
-
-    const fileName dataDir  = ensightDir/"data";
-    const fileName dataMask = dataDir.name()/ensightFile::mask();
-
-    if (Pstream::master())
-    {
-        // EnSight and EnSight/data directories must exist
-        // - remove old data for a clean conversion of everything
-        if (isDir(ensightDir))
-        {
-            rmDir(ensightDir);
-        }
-
-        mkDir(dataDir);
-    }
-
     #include "createNamedMesh.H"
 
-    // Mesh instance (region0 gets filtered out)
-    fileName regionPrefix;
+    fileName regionPrefix; // Mesh instance (region0 gets filtered out)
     if (regionName != polyMesh::defaultRegion)
     {
         regionPrefix = regionName;
     }
 
-    // Start of case file header output
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    OFstream *ensightCaseFilePtr(nullptr);
-    if (Pstream::master())
-    {
-        fileName caseFileName = args.globalCaseName() + ".case";
+    //
+    // general (case) output options
+    //
+    ensightCase::options caseOpts(format);
 
-        Info<< "Converting " << timeDirs.size() << " time steps" << nl
-            << "Ensight case: " << caseFileName.c_str() << endl;
+    caseOpts.nodeValues(args.optionFound("nodeValues"));
+    caseOpts.width(args.optionLookupOrDefault<label>("width", 8));
+    caseOpts.overwrite(true); // remove existing output directory
 
-        // The case file is always ASCII
-        ensightCaseFilePtr = new OFstream
-        (
-            ensightDir/caseFileName,
-            IOstream::ASCII
-        );
+    // Can also have separate directory for lagrangian
+    // caseOpts.separateCloud(true);
 
-        ensightCaseFilePtr->setf(ios_base::left);
-        ensightCaseFilePtr->setf(ios_base::scientific, ios_base::floatfield);
-        ensightCaseFilePtr->precision(5);
 
-        *ensightCaseFilePtr
-            << "FORMAT" << nl
-            << "type: ensight gold" << nl << nl;
+    // Define sub-directory name to use for EnSight data.
+    // The path to the ensight directory is at case level only
+    // - For parallel cases, data only written from master
+    fileName ensightDir = args.optionLookupOrDefault<word>("name", "EnSight");
+    if (!ensightDir.isAbsolute())
+    {
+        ensightDir = args.rootPath()/args.globalCaseName()/ensightDir;
     }
 
-    OFstream& ensightCaseFile = *ensightCaseFilePtr;
 
-    // Construct the EnSight mesh
-    const bool selectedPatches = args.optionFound("patches");
-    wordReList patchPatterns;
-    if (selectedPatches)
+    //
+    // output configuration (geometry related)
+    //
+    ensightMesh::options writeOpts(format);
+    writeOpts.noPatches(args.optionFound("noPatches"));
+    writeOpts.deprecatedOrder(args.optionFound("deprecatedOrder"));
+
+    if (args.optionFound("patches"))
     {
-        patchPatterns = wordReList(args.optionLookup("patches")());
+        writeOpts.patchSelection(args.optionReadList<wordRe>("patches"));
     }
-    const bool selectedZones = args.optionFound("faceZones");
-    wordReList zonePatterns;
-    if (selectedZones)
+    if (args.optionFound("faceZones"))
     {
-        zonePatterns = wordReList(args.optionLookup("faceZones")());
+        writeOpts.faceZoneSelection(args.optionReadList<wordRe>("faceZones"));
     }
 
-    const bool selectedFields = args.optionFound("fields");
+    //
+    // output configuration (field related)
+    //
+    const bool noLagrangian = args.optionFound("noLagrangian");
+
     wordReList fieldPatterns;
-    if (selectedFields)
+    if (args.optionFound("fields"))
     {
-        fieldPatterns = wordReList(args.optionLookup("fields")());
+        fieldPatterns = args.optionReadList<wordRe>("fields");
     }
 
-    const bool noLagrangian = args.optionFound("noLagrangian");
-
     word cellZoneName;
-    const bool doCellZone = args.optionReadIfPresent("cellZone", cellZoneName);
-
-    fvMeshSubset meshSubsetter(mesh);
-    if (doCellZone)
+    if (args.optionReadIfPresent("cellZone", cellZoneName))
     {
         Info<< "Converting cellZone " << cellZoneName
             << " only (puts outside faces into patch "
-            << mesh.boundaryMesh()[0].name()
-            << ")" << endl;
-        const cellZone& cz = mesh.cellZones()[cellZoneName];
-        cellSet c0(mesh, "c0", labelHashSet(cz));
-        meshSubsetter.setLargeCellSubset(c0, 0);
+            << mesh.boundaryMesh()[0].name() << ")"
+            << endl;
     }
+    meshSubsetHelper myMesh(mesh, cellZoneName);
 
-    ensightMesh eMesh
+    //
+    // Open new ensight case file, initialize header etc.
+    //
+    ensightCase ensCase
     (
-        (
-            meshSubsetter.hasSubMesh()
-          ? meshSubsetter.subMesh()
-          : meshSubsetter.baseMesh()
-        ),
-        args.optionFound("noPatches"),
-        selectedPatches,
-        patchPatterns,
-        selectedZones,
-        zonePatterns,
-        format
+        ensightDir,
+        args.globalCaseName(),
+        caseOpts
     );
 
-    // Set Time to the last time before looking for the lagrangian objects
-    runTime.setTime(timeDirs.last(), timeDirs.size()-1);
 
-    IOobjectList objects(mesh, runTime.timeName());
-
-    #include "checkMeshMoving.H"
-    #include "findCloudFields.H"
+    // Construct the Ensight mesh
+    ensightMesh ensMesh(myMesh.mesh(), writeOpts);
 
     if (Pstream::master())
     {
-        // test the pre-check variable if there is a moving mesh
-        // time-set for geometries
-        // TODO: split off into separate time-set,
-        // but need to verify ensight spec
+        Info<< "Converting " << timeDirs.size() << " time steps" << nl;
+        ensCase.printInfo(Info) << endl;
+    }
 
-        if (meshMoving)
-        {
-            ensightCaseFile
-                << "GEOMETRY" << nl
-                << setw(16) << "model: 1"
-                << (dataMask/ensightMesh::geometryName).c_str() << nl;
-        }
-        else
-        {
-            ensightCaseFile
-                << "GEOMETRY" << nl
-                << setw(16) << "model:"
-                << ensightMesh::geometryName << nl;
-        }
 
+    // Set Time to the last time before looking for lagrangian objects
+    runTime.setTime(timeDirs.last(), timeDirs.size()-1);
 
-        // Add the name of the cloud(s) to the case file header
-        forAll(cloudNames, cloudNo)
-        {
-            const word& cloudName = cloudNames[cloudNo];
+    IOobjectList objects(mesh, runTime.timeName());
 
-            ensightCaseFile
-                << setw(16) << "measured: 1"
-                << fileName
-                (
-                    dataMask/cloud::prefix/cloudName/"positions"
-                ).c_str() << nl;
-        }
-    }
+    #include "checkMeshMoving.H"
+    #include "findCloudFields.H"
+
+    // test the pre-check variable if there is a moving mesh
+    // time-set for geometries
+    // TODO: split off into separate time-set,
+    // but need to verify ensight spec
 
     Info<< "Startup in "
         << timer.cpuTimeIncrement() << " s, "
@@ -387,63 +336,25 @@ int main(int argc, char *argv[])
     // ignore fields that are not available for all time-steps
     HashTable<bool> fieldsToUse;
 
-    label nTimeSteps = 0;
     forAll(timeDirs, timeIndex)
     {
-        ++nTimeSteps;
         runTime.setTime(timeDirs[timeIndex], timeIndex);
+        ensCase.nextTime(timeDirs[timeIndex]);
 
         Info<< "Time [" << timeIndex << "] = " << runTime.timeName() << nl;
 
-        if (Pstream::master())
-        {
-            // the data/ITER subdirectory must exist
-            // Note that data/ITER is indeed a valid ensight::FileName
-            const fileName subDir = ensightFile::subDir(timeIndex);
-            mkDir(dataDir/subDir);
-
-            // place a timestamp in the directory for future reference
-            OFstream timeStamp(dataDir/subDir/"time");
-            timeStamp
-                << "#   timestep time" << nl
-                << subDir.c_str() << " " << runTime.timeName() << nl;
-        }
-
         polyMesh::readUpdateState meshState = mesh.readUpdate();
-        if (timeIndex != 0 && meshSubsetter.hasSubMesh())
-        {
-            Info<< "Converting cellZone " << cellZoneName
-                << " only (puts outside faces into patch "
-                << mesh.boundaryMesh()[0].name()
-                << ")" << endl;
-            const cellZone& cz = mesh.cellZones()[cellZoneName];
-            cellSet c0(mesh, "c0", labelHashSet(cz));
-            meshSubsetter.setLargeCellSubset(c0, 0);
-        }
-
         if (meshState != polyMesh::UNCHANGED)
         {
-            eMesh.correct();
+            myMesh.correct();
+            ensMesh.expire();
+            ensMesh.correct();
         }
 
         if (timeIndex == 0 || meshMoving)
         {
-            eMesh.write
-            (
-                dataDir,
-                timeIndex,
-                meshMoving,
-                ensightCaseFile
-            );
-        }
-
-
-        // Start of field data output
-        // ~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-        if (timeIndex == 0 && Pstream::master())
-        {
-            ensightCaseFile<< nl << "VARIABLE" << nl;
+            autoPtr<ensightGeoFile> os = ensCase.newGeometry(meshMoving);
+            ensMesh.write(os);
         }
 
 
@@ -451,22 +362,20 @@ int main(int argc, char *argv[])
         // ~~~~~~~~~~~~~~~~~~~~~~
         Info<< "Write volume field (";
 
-        for (label i=0; i<nVolFieldTypes; ++i)
+        forAll(volFieldTypes, typei)
         {
-            wordList fieldNames = objects.names(volFieldTypes[i]);
+            const word& fieldType = volFieldTypes[typei];
+            wordList fieldNames = objects.names(fieldType);
 
-            forAll(fieldNames, j)
+            // Filter on name as required
+            if (!fieldPatterns.empty())
             {
-                const word& fieldName = fieldNames[j];
+                inplaceSubsetStrings(fieldPatterns, fieldNames);
+            }
 
-                // Check if the field has to be exported
-                if (selectedFields)
-                {
-                    if (!findStrings(fieldPatterns, fieldName))
-                    {
-                        continue;
-                    }
-                }
+            forAll(fieldNames, fieldi)
+            {
+                const word& fieldName = fieldNames[fieldi];
 
                 #include "checkData.H"
 
@@ -484,151 +393,206 @@ int main(int argc, char *argv[])
                     IOobject::NO_WRITE
                 );
 
-                if (volFieldTypes[i] == volScalarField::typeName)
+                bool wrote = false;
+                if (fieldType == volScalarField::typeName)
                 {
+                    autoPtr<ensightFile> os = ensCase.newData<scalar>
+                    (
+                        fieldName
+                    );
+
                     volScalarField vf(fieldObject, mesh);
-                    ensightField<scalar>
+                    wrote = ensightOutput::writeField<scalar>
                     (
-                        volField(meshSubsetter, vf),
-                        eMesh,
-                        dataDir,
-                        timeIndex,
-                        nodeValues,
-                        ensightCaseFile
+                        myMesh.interpolate(vf),
+                        ensMesh,
+                        os,
+                        nodeValues
                     );
                 }
-                else if (volFieldTypes[i] == volVectorField::typeName)
+                else if (fieldType == volVectorField::typeName)
                 {
+                    autoPtr<ensightFile> os = ensCase.newData<vector>
+                    (
+                        fieldName
+                    );
+
                     volVectorField vf(fieldObject, mesh);
-                    ensightField<vector>
+                    wrote = ensightOutput::writeField<vector>
                     (
-                        volField(meshSubsetter, vf),
-                        eMesh,
-                        dataDir,
-                        timeIndex,
-                        nodeValues,
-                        ensightCaseFile
+                        myMesh.interpolate(vf),
+                        ensMesh,
+                        os,
+                        nodeValues
                     );
                 }
-                else if (volFieldTypes[i] == volSphericalTensorField::typeName)
+                else if (fieldType == volSphericalTensorField::typeName)
                 {
+                    autoPtr<ensightFile> os = ensCase.newData<sphericalTensor>
+                    (
+                        fieldObject.name()
+                    );
+
                     volSphericalTensorField vf(fieldObject, mesh);
-                    ensightField<sphericalTensor>
+                    wrote = ensightOutput::writeField<sphericalTensor>
                     (
-                        volField(meshSubsetter, vf),
-                        eMesh,
-                        dataDir,
-                        timeIndex,
-                        nodeValues,
-                        ensightCaseFile
+                        myMesh.interpolate(vf),
+                        ensMesh,
+                        os,
+                        nodeValues
                     );
                 }
-                else if (volFieldTypes[i] == volSymmTensorField::typeName)
+                else if (fieldType == volSymmTensorField::typeName)
                 {
+                    autoPtr<ensightFile> os = ensCase.newData<symmTensor>
+                    (
+                        fieldName
+                    );
+
                     volSymmTensorField vf(fieldObject, mesh);
-                    ensightField<symmTensor>
+                    wrote = ensightOutput::writeField<symmTensor>
                     (
-                        volField(meshSubsetter, vf),
-                        eMesh,
-                        dataDir,
-                        timeIndex,
-                        nodeValues,
-                        ensightCaseFile
+                        myMesh.interpolate(vf),
+                        ensMesh,
+                        os,
+                        nodeValues
                     );
                 }
-                else if (volFieldTypes[i] == volTensorField::typeName)
+                else if (fieldType == volTensorField::typeName)
                 {
+                    autoPtr<ensightFile> os = ensCase.newData<tensor>
+                    (
+                        fieldName
+                    );
+
                     volTensorField vf(fieldObject, mesh);
-                    ensightField<tensor>
+                    wrote = ensightOutput::writeField<tensor>
                     (
-                        volField(meshSubsetter, vf),
-                        eMesh,
-                        dataDir,
-                        timeIndex,
-                        nodeValues,
-                        ensightCaseFile
+                        myMesh.interpolate(vf),
+                        ensMesh,
+                        os,
+                        nodeValues
                     );
                 }
                 // DimensionedFields
                 else if
                 (
-                    volFieldTypes[i] == volScalarField::Internal::typeName
+                    fieldType
+                 == volScalarField::Internal::typeName
                 )
                 {
-                    volScalarField::Internal df(fieldObject, mesh);
-                    ensightField<scalar>
+                    autoPtr<ensightFile> os = ensCase.newData<scalar>
+                    (
+                        fieldName
+                    );
+
+                    volScalarField::Internal df
+                    (
+                        fieldObject,
+                        mesh
+                    );
+                    wrote = ensightOutput::writeField<scalar>
                     (
-                        volField<scalar>(meshSubsetter, df),
-                        eMesh,
-                        dataDir,
-                        timeIndex,
-                        nodeValues,
-                        ensightCaseFile
+                        myMesh.interpolate<scalar>(df),
+                        ensMesh,
+                        os,
+                        nodeValues
                     );
                 }
                 else if
                 (
-                    volFieldTypes[i] == volVectorField::Internal::typeName
+                    fieldType
+                 == volVectorField::Internal::typeName
                 )
                 {
-                    volVectorField::Internal df(fieldObject, mesh);
-                    ensightField<vector>
+                    autoPtr<ensightFile> os = ensCase.newData<vector>
+                    (
+                        fieldName
+                    );
+
+                    volVectorField::Internal df
                     (
-                        volField<vector>(meshSubsetter, df),
-                        eMesh,
-                        dataDir,
-                        timeIndex,
-                        nodeValues,
-                        ensightCaseFile
+                        fieldObject,
+                        mesh
+                    );
+                    wrote = ensightOutput::writeField<vector>
+                    (
+                        myMesh.interpolate<vector>(df),
+                        ensMesh,
+                        os,
+                        nodeValues
                     );
                 }
                 else if
                 (
-                    volFieldTypes[i]
+                    fieldType
                  == volSphericalTensorField::Internal::typeName
                 )
                 {
-                    volSphericalTensorField::Internal df(fieldObject, mesh);
-                    ensightField<sphericalTensor>
+                    autoPtr<ensightFile> os = ensCase.newData<sphericalTensor>
                     (
-                        volField<sphericalTensor>(meshSubsetter, df),
-                        eMesh,
-                        dataDir,
-                        timeIndex,
-                        nodeValues,
-                        ensightCaseFile
+                        fieldName
+                    );
+
+                    volSphericalTensorField::Internal df
+                    (
+                        fieldObject,
+                        mesh
+                    );
+                    wrote = ensightOutput::writeField<sphericalTensor>
+                    (
+                        myMesh.interpolate<sphericalTensor>(df),
+                        ensMesh,
+                        os,
+                        nodeValues
                     );
                 }
                 else if
                 (
-                    volFieldTypes[i] == volSymmTensorField::Internal::typeName
+                    fieldType
+                 == volSymmTensorField::Internal::typeName
                 )
                 {
-                    volSymmTensorField::Internal df(fieldObject, mesh);
-                    ensightField<symmTensor>
+                    autoPtr<ensightFile> os = ensCase.newData<symmTensor>
+                    (
+                        fieldName
+                    );
+
+                    volSymmTensorField::Internal df
+                    (
+                        fieldObject,
+                        mesh
+                    );
+                    wrote = ensightOutput::writeField<symmTensor>
                     (
-                        volField<symmTensor>(meshSubsetter, df),
-                        eMesh,
-                        dataDir,
-                        timeIndex,
-                        nodeValues,
-                        ensightCaseFile
+                        myMesh.interpolate<symmTensor>(df),
+                        ensMesh,
+                        os,
+                        nodeValues
                     );
                 }
                 else if
                 (
-                    volFieldTypes[i] == volTensorField::Internal::typeName
+                    fieldType
+                 == volTensorField::Internal::typeName
                 )
                 {
-                    volTensorField::Internal df(fieldObject, mesh);
-                    ensightField<tensor>
+                    autoPtr<ensightFile> os = ensCase.newData<tensor>
+                    (
+                        fieldName
+                    );
+
+                    volTensorField::Internal df
+                    (
+                        fieldObject,
+                        mesh
+                    );
+                    wrote = ensightOutput::writeField<tensor>
                     (
-                        volField<tensor>(meshSubsetter, df),
-                        eMesh,
-                        dataDir,
-                        timeIndex,
-                        nodeValues,
-                        ensightCaseFile
+                        myMesh.interpolate<tensor>(df),
+                        ensMesh,
+                        os,
+                        nodeValues
                     );
                 }
                 else
@@ -636,6 +600,11 @@ int main(int argc, char *argv[])
                     // Do not currently handle this type - blacklist for the future.
                     fieldsToUse.set(fieldName, false);
                 }
+
+                if (wrote)
+                {
+                    Info<< ' ' << fieldName;
+                }
             }
         }
         Info<< " )" << nl;
@@ -660,15 +629,23 @@ int main(int argc, char *argv[])
             bool cloudExists = inFileNameList(currentCloudDirs, cloudName);
             reduce(cloudExists, orOp<bool>());
 
-            ensightParticlePositions
-            (
-                mesh,
-                dataDir,
-                timeIndex,
-                cloudName,
-                cloudExists,
-                format
-            );
+            {
+                autoPtr<ensightFile> os = ensCase.newCloud(cloudName);
+
+                ensightCloud::writePositions
+                (
+                    mesh,
+                    cloudName,
+                    cloudExists,
+                    os
+                );
+
+                Info<< " positions";
+                if (!cloudExists)
+                {
+                    Info<< "{0}"; // report empty field
+                }
+            }
 
             forAllConstIter(HashTable<word>, theseCloudFields, fieldIter)
             {
@@ -684,40 +661,46 @@ int main(int argc, char *argv[])
                     IOobject::MUST_READ
                 );
 
-                bool fieldExists = fieldObject.typeHeaderOk<IOField<scalar>>
-                (
-                    false
-                );
-                reduce(fieldExists, orOp<bool>());
+                // cannot have field without cloud positions
+                bool fieldExists = cloudExists;
+                if (cloudExists)
+                {
+                    fieldExists =
+                        fieldObject.typeHeaderOk<IOField<scalar>>(false);
 
+                    reduce(fieldExists, orOp<bool>());
+                }
+
+                bool wrote = false;
                 if (fieldType == scalarIOField::typeName)
                 {
-                    ensightCloudField<scalar>
+                    autoPtr<ensightFile> os =
+                        ensCase.newCloudData<scalar>(cloudName, fieldName);
+
+                    wrote = ensightCloud::writeCloudField<scalar>
                     (
-                        fieldObject,
-                        dataDir,
-                        timeIndex,
-                        cloudName,
-                        cloudNo,
-                        ensightCaseFile,
-                        fieldExists,
-                        format
+                        fieldObject, fieldExists, os
                     );
                 }
                 else if (fieldType == vectorIOField::typeName)
                 {
-                    ensightCloudField<vector>
+                    autoPtr<ensightFile> os =
+                        ensCase.newCloudData<vector>(cloudName, fieldName);
+
+                    wrote = ensightCloud::writeCloudField<vector>
                     (
-                        fieldObject,
-                        dataDir,
-                        timeIndex,
-                        cloudName,
-                        cloudNo,
-                        ensightCaseFile,
-                        fieldExists,
-                        format
+                        fieldObject, fieldExists, os
                     );
                 }
+
+                if (wrote)
+                {
+                    Info<< ' ' << fieldName;
+                    if (!fieldExists)
+                    {
+                        Info<< "{0}"; // report empty field
+                    }
+                }
             }
             Info<< " )" << nl;
         }
@@ -727,12 +710,7 @@ int main(int argc, char *argv[])
             << mem.update().size() << " kB" << nl << nl;
     }
 
-    #include "ensightCaseTail.H"
-
-    if (ensightCaseFilePtr) // on master only
-    {
-        delete ensightCaseFilePtr;
-    }
+    ensCase.write();
 
     Info<< "End: "
         << timer.elapsedCpuTime() << " s, "
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/meshSubsetHelper.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/meshSubsetHelper.C
new file mode 100644
index 0000000000000000000000000000000000000000..05bdc9420bb74411a78277f13d425798a14bcec9
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/meshSubsetHelper.C
@@ -0,0 +1,91 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "meshSubsetHelper.H"
+
+#include "cellSet.H"
+#include "cellZone.H"
+#include "Time.H"
+#include "IOstreams.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::meshSubsetHelper::meshSubsetHelper
+(
+    fvMesh& baseMesh,
+    const word& name,
+    const bool isCellSet
+)
+:
+    baseMesh_(baseMesh),
+    subsetter_(baseMesh),
+    name_(name),
+    type_(name_.empty() ? 0 : isCellSet ? 1 : 2)
+{
+    correct();
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::meshSubsetHelper::correct(bool verbose)
+{
+    if (type_ == 1)
+    {
+        if (verbose)
+        {
+            Info<< "Subsetting mesh based on cellSet " << name_ << endl;
+        }
+
+        cellSet subset(baseMesh_, name_);
+        subsetter_.setLargeCellSubset(subset);
+    }
+    else if (type_ == 2)
+    {
+        if (verbose)
+        {
+            Info<< "Subsetting mesh based on cellZone " << name_ << endl;
+        }
+
+        labelHashSet subset(baseMesh_.cellZones()[name_]);
+        subsetter_.setLargeCellSubset(subset, 0);
+    }
+}
+
+
+Foam::polyMesh::readUpdateState Foam::meshSubsetHelper::readUpdate()
+{
+    polyMesh::readUpdateState meshState = baseMesh_.readUpdate();
+
+    if (meshState != polyMesh::UNCHANGED)
+    {
+        correct(true);
+    }
+
+    return meshState;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/meshSubsetHelper.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/meshSubsetHelper.H
new file mode 100644
index 0000000000000000000000000000000000000000..43112a5a18a80f250c9617a653ebe28585033bba
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/meshSubsetHelper.H
@@ -0,0 +1,193 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::meshSubsetHelper
+
+Description
+    Simple helper to hold a mesh or mesh-subset and provide uniform access.
+
+SourceFiles
+    meshSubsetHelper.C
+    meshSubsetHelperTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef meshSubsetHelper_H
+#define meshSubsetHelper_H
+
+#include "fvMeshSubset.H"
+#include "zeroGradientFvPatchField.H"
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+class Time;
+
+/*---------------------------------------------------------------------------*\
+                      Class meshSubsetHelper Declaration
+\*---------------------------------------------------------------------------*/
+
+class meshSubsetHelper
+{
+    // Private data
+
+        //- Reference to mesh
+        fvMesh& baseMesh_;
+
+        //- Subsetting engine + sub-fvMesh
+        fvMeshSubset subsetter_;
+
+        //- Name of current cellSet/cellZone (or empty)
+        const word name_;
+
+        //- Internal book-keeping. 0 = unused, 1 = set, 2 = zone
+        const int type_;
+
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        meshSubsetHelper(const meshSubsetHelper&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const meshSubsetHelper&) = delete;
+
+
+public:
+
+    // Constructors
+
+        //- Construct from components
+        meshSubsetHelper
+        (
+            fvMesh& baseMesh,
+            const word& name = word::null,
+            const bool isCellSet = false
+        );
+
+
+    // Member Functions
+
+    // Access
+
+        //- The entire base mesh
+        inline const fvMesh& baseMesh() const
+        {
+            return baseMesh_;
+        }
+
+        //- The mesh subsetter
+        inline const fvMeshSubset& subsetter() const
+        {
+            return subsetter_;
+        }
+
+        //- Check if running a sub-mesh is being used
+        inline bool useSubMesh() const
+        {
+            return type_;
+        }
+
+        //- Access either mesh or submesh
+        inline const fvMesh& mesh() const
+        {
+            if (useSubMesh())
+            {
+                return subsetter_.subMesh();
+            }
+            else
+            {
+                return baseMesh_;
+            }
+        }
+
+
+    // Edit
+
+        //- Update mesh subset
+        void correct(bool verbose = false);
+
+        //- Read mesh
+        polyMesh::readUpdateState readUpdate();
+
+
+        //- Construct volField (with zeroGradient) from an internal field
+        template<class Type>
+        static tmp<GeometricField<Type, fvPatchField, volMesh>>
+        zeroGradientField
+        (
+            const typename GeometricField
+            <
+                Type,
+                fvPatchField,
+                volMesh
+            >::Internal& df
+        );
+
+
+        //- Wrapper for field or the subsetted field.
+        //  Map volume field (does in fact do very little interpolation;
+        //  just copied from fvMeshSubset)
+        template<class Type>
+        tmp<GeometricField<Type, fvPatchField, volMesh>>
+        interpolate
+        (
+            const GeometricField<Type, fvPatchField, volMesh>&
+        ) const;
+
+
+        //- Convert an internal field to a volume field
+        template<class Type>
+        tmp<GeometricField<Type, fvPatchField, volMesh>>
+        interpolate
+        (
+            const typename GeometricField
+            <
+                Type,
+                fvPatchField,
+                volMesh
+            >::Internal&
+        ) const;
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "meshSubsetHelperTemplates.C"
+#endif
+
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/meshSubsetHelperTemplates.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/meshSubsetHelperTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..d588118d0f0fa6bcfdface68ea0013f9008645df
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/meshSubsetHelperTemplates.C
@@ -0,0 +1,119 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "meshSubsetHelper.H"
+#include "fvMesh.H"
+#include "volFields.H"
+#include "globalIndex.H"
+#include "zeroGradientFvPatchField.H"
+
+
+// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
+
+template<class Type>
+Foam::tmp<Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh>>
+Foam::meshSubsetHelper::zeroGradientField
+(
+    const typename GeometricField
+    <
+        Type,
+        fvPatchField,
+        volMesh
+    >::Internal& df
+)
+{
+    IOobject io(df);
+    io.readOpt()  = IOobject::NO_READ;
+    io.writeOpt() = IOobject::NO_WRITE;
+    io.registerObject() = false;
+
+    tmp<GeometricField<Type, fvPatchField, volMesh>> tvf
+    (
+        new GeometricField<Type, fvPatchField, volMesh>
+        (
+            io,
+            df.mesh(),
+            dimensioned<Type>("0", df.dimensions(), Zero),
+            zeroGradientFvPatchField<Type>::typeName
+        )
+    );
+    tvf.ref().primitiveFieldRef() = df;
+    tvf.ref().correctBoundaryConditions();
+
+    return tvf;
+}
+
+
+template<class Type>
+Foam::tmp<Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh>>
+Foam::meshSubsetHelper::interpolate
+(
+    const GeometricField<Type, fvPatchField, volMesh>& vf
+) const
+{
+    if (subsetter_.hasSubMesh())
+    {
+        tmp<GeometricField<Type, fvPatchField, volMesh>> tfld
+        (
+            subsetter_.interpolate(vf)
+        );
+        tfld.ref().checkOut();
+        tfld.ref().rename(vf.name());
+        return tfld;
+    }
+    else
+    {
+        return vf;
+    }
+}
+
+
+template<class Type>
+Foam::tmp<Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh>>
+Foam::meshSubsetHelper::interpolate
+(
+    const typename GeometricField
+    <
+        Type,
+        fvPatchField,
+        volMesh
+    >::Internal& df
+) const
+{
+    tmp<GeometricField<Type, fvPatchField, volMesh>> tvf =
+        zeroGradientField<Type>(df);
+
+    if (subsetter_.hasSubMesh())
+    {
+        return interpolate<Type>(tvf());
+    }
+    else
+    {
+        return tvf;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/Make/files b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/Make/files
index 739c971551520b88f08aac2001229792eb1031c5..63e999847803d64d0d8c930e43a9a4afb09a50ef 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/Make/files
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/Make/files
@@ -1,3 +1,4 @@
+ensightOutputSerialCloud.C
 foamToEnsightParts.C
 
 EXE = $(FOAM_APPBIN)/foamToEnsightParts
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasMovingMesh.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkMeshMoving.H
similarity index 88%
rename from applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasMovingMesh.H
rename to applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkMeshMoving.H
index 15a4756949b36336a3f211896b70939341bf3a87..51c7a11e7337648272c889c477630eea44bd44a4 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkHasMovingMesh.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/checkMeshMoving.H
@@ -1,7 +1,7 @@
 // check for "points" in all of the result directories
 // - could restrict to the selected times
 
-bool hasMovingMesh = false;
+bool meshMoving = false;
 
 if (timeDirs.size() > 1 && Pstream::master())
 {
@@ -13,7 +13,7 @@ if (timeDirs.size() > 1 && Pstream::master())
     Info<< "Search for moving mesh ... " << flush;
     forAll(timeDirs, timeI)
     {
-        hasMovingMesh =
+        meshMoving =
         (
             isDir(baseDir/timeDirs[timeI].name()/polyMesh::meshSubDir)
          && IOobject
@@ -28,13 +28,13 @@ if (timeDirs.size() > 1 && Pstream::master())
             ).typeHeaderOk<pointIOField>(true)
         );
 
-        if (hasMovingMesh)
+        if (meshMoving)
         {
             break;
         }
     }
 
-    if (hasMovingMesh)
+    if (meshMoving)
     {
         Info<< "found." << nl
             << "    Writing meshes for every timestep." << endl;
@@ -45,4 +45,4 @@ if (timeDirs.size() > 1 && Pstream::master())
     }
 }
 
-reduce(hasMovingMesh, orOp<bool>());
+reduce(meshMoving, orOp<bool>());
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputCase.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputCase.H
deleted file mode 100644
index b0c3af822bbffb892c76a7be0241f086bd4f219e..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputCase.H
+++ /dev/null
@@ -1,270 +0,0 @@
-// write time values to case file
-
-scalar timeCorrection = 0;
-if (timeDirs[0].value() < 0)
-{
-    timeCorrection = - timeDirs[0].value();
-    Info<< "Correcting time values. Adding " << timeCorrection << endl;
-}
-
-// the case file is always ASCII
-Info<< "write case: " << caseFileName.c_str() << endl;
-
-OFstream caseFile(ensightDir/caseFileName, IOstream::ASCII);
-caseFile.setf(ios_base::left);
-
-caseFile.setf(ios_base::scientific, ios_base::floatfield);
-caseFile.precision(5);
-
-caseFile
-    << "FORMAT" << nl
-    << setw(16) << "type:" << "ensight gold" << nl << nl;
-
-// time-set for geometries
-// TODO: split off into separate time-set, but need to verify ensight spec
-if (geometryTimesUsed.size())
-{
-    caseFile
-        << "GEOMETRY" << nl
-        << setw(16) << "model: 1" << (dataMask/geometryName).c_str() << nl;
-}
-else
-{
-    caseFile
-        << "GEOMETRY" << nl
-        << setw(16) << "model:" << geometryName << nl;
-}
-
-
-// add information for clouds
-// multiple clouds currently require the same time index
-forAllConstIter(HashTable<HashTable<word>>, cloudFields, cloudIter)
-{
-    const word& cloudName = cloudIter.key();
-
-    caseFile
-        << setw(16) << "measured: 2"
-        << fileName(dataMask/cloud::prefix/cloudName/"positions").c_str()
-        << nl;
-}
-caseFile
-    << nl << "VARIABLE" << nl;
-
-forAllConstIter(HashTable<word>, volumeFields, fieldIter)
-{
-    const word& fieldName = fieldIter.key();
-    const word& fieldType = fieldIter();
-    string ensightType;
-
-    if (fieldType == volScalarField::typeName)
-    {
-        ensightType = ensightPTraits<scalar>::typeName;
-    }
-    else if (fieldType == volVectorField::typeName)
-    {
-        ensightType = ensightPTraits<vector>::typeName;
-    }
-    else if (fieldType == volSphericalTensorField::typeName)
-    {
-        ensightType = ensightPTraits<sphericalTensor>::typeName;
-    }
-    else if (fieldType == volSymmTensorField::typeName)
-    {
-        ensightType = ensightPTraits<symmTensor>::typeName;
-    }
-    else if (fieldType == volTensorField::typeName)
-    {
-        ensightType = ensightPTraits<tensor>::typeName;
-    }
-    else
-    {
-        continue;
-    }
-
-    ensightCaseEntry
-    (
-        caseFile,
-        ensightType,
-        fieldName,
-        dataMask
-    );
-}
-
-
-// TODO: allow similar/different time-steps for each cloud
-label cloudNo = 0;
-forAllConstIter(HashTable<HashTable<word>>, cloudFields, cloudIter)
-{
-    const word& cloudName = cloudIter.key();
-
-    forAllConstIter(HashTable<word>, cloudIter(), fieldIter)
-    {
-        const word& fieldName = fieldIter.key();
-        const word& fieldType = fieldIter();
-        string ensightType;
-
-        if (fieldType == scalarIOField::typeName)
-        {
-            ensightType = ensightPTraits<scalar>::typeName;
-        }
-        else if (fieldType == vectorIOField::typeName)
-        {
-            ensightType = ensightPTraits<vector>::typeName;
-        }
-        else if (fieldType == tensorIOField::typeName)
-        {
-            ensightType = ensightPTraits<tensor>::typeName;
-        }
-        else
-        {
-            continue;
-        }
-
-        ensightCaseEntry
-        (
-            caseFile,
-            ensightType,
-            fieldName,
-            dataMask,
-            cloud::prefix/cloudName,
-            cloudNo,
-            2
-        );
-    }
-    cloudNo++;
-}
-
-
-// add time values
-caseFile << nl << "TIME" << nl;
-
-// time set 1 - volume fields
-if (fieldTimesUsed.size())
-{
-    caseFile
-        << "time set:        " << 1 << nl
-        << "number of steps: " << fieldTimesUsed.size() << nl
-        << "filename numbers:" << nl;
-
-    label count = 0;
-    forAll(fieldTimesUsed, i)
-    {
-        caseFile
-            << " " << setw(12) << fieldTimesUsed[i];
-
-        if (++count % 6 == 0)
-        {
-            caseFile << nl;
-        }
-    }
-
-    caseFile
-        << nl << "time values:" << nl;
-
-    count = 0;
-    forAll(fieldTimesUsed, i)
-    {
-        const label index = fieldTimesUsed[i];
-        caseFile
-            << " " << setw(12) << timeIndices[index] + timeCorrection;
-
-        if (++count % 6 == 0)
-        {
-            caseFile << nl;
-        }
-    }
-    caseFile << nl << nl;
-}
-
-
-// time set 2 - geometry
-// THIS NEEDS MORE CHECKING
-#if 0
-if (geometryTimesUsed.size())
-{
-    caseFile
-        << "time set:        " << 2 << nl
-        << "number of steps: " << geometryTimesUsed.size() << nl
-        << "filename numbers:" << nl;
-
-    label count = 0;
-    forAll(geometryTimesUsed, i)
-    {
-        caseFile
-            << " " << setw(12) << geometryTimesUsed[i];
-
-        if (++count % 6 == 0)
-        {
-            caseFile << nl;
-        }
-    }
-
-    caseFile
-        << nl << "time values:" << nl;
-
-    count = 0;
-    forAll(geometryTimesUsed, i)
-    {
-        const label index = geometryTimesUsed[i];
-        caseFile
-            << " " << setw(12) << timeIndices[index] + timeCorrection;
-
-        if (++count % 6 == 0)
-        {
-            caseFile << nl;
-        }
-    }
-    caseFile << nl << nl;
-}
-#endif
-
-// time set - clouds
-// TODO: allow similar/different time-steps for each cloud
-cloudNo = 0;
-forAllConstIter(HashTable<DynamicList<label>>, cloudTimesUsed, cloudIter)
-{
-    // const word& cloudName = cloudIter.key();
-    const DynamicList<label>& timesUsed = cloudIter();
-
-    if (timesUsed.size() && cloudNo == 0)
-    {
-        caseFile
-            << "time set:        " << 2 << nl
-            << "number of steps: " << timesUsed.size() << nl
-            << "filename numbers:" << nl;
-
-        label count = 0;
-        forAll(timesUsed, i)
-        {
-            caseFile
-                << " " << setw(12) << timesUsed[i];
-
-            if (++count % 6 == 0)
-            {
-                caseFile << nl;
-            }
-        }
-
-        caseFile
-            << nl << "time values:" << nl;
-
-        count = 0;
-        forAll(timesUsed, i)
-        {
-            const label index = timesUsed[i];
-            caseFile
-                << " " << setw(12) << timeIndices[index] + timeCorrection;
-
-            if (++count % 6 == 0)
-            {
-                caseFile << nl;
-            }
-        }
-        caseFile << nl << nl;
-
-        cloudNo++;
-    }
-}
-
-caseFile << "# end" << nl;
-
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputFunctions.C b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputFunctions.C
deleted file mode 100644
index 148aa4014532744730f5f2c5e279c8f4609f3c51..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputFunctions.C
+++ /dev/null
@@ -1,245 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "ensightOutputFunctions.H"
-#include "ensightPTraits.H"
-
-#include "passiveParticle.H"
-#include "IOField.H"
-#include "volFields.H"
-#include "surfaceFields.H"
-
-#include "OFstream.H"
-#include "IOmanip.H"
-
-
-// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
-
-void Foam::ensightCaseEntry
-(
-    OFstream& caseFile,
-    const string& ensightType,
-    const word& fieldName,
-    const fileName& dataMask,
-    const fileName& local,
-    const label cloudNo,
-    const label timeSet
-)
-{
-    const ensight::VarName varName(fieldName);
-
-    caseFile.setf(ios_base::left);
-
-    fileName dirName(dataMask);
-    if (local.size())
-    {
-        dirName = dirName/local;
-    }
-
-    if (cloudNo >= 0)
-    {
-        label ts = 1;
-        if (timeSet > ts)
-        {
-            ts = timeSet;
-        }
-
-        // prefix variables with 'c' (cloud)
-        caseFile
-            << ensightType.c_str()
-            << " per measured node: " << ts << " "
-            << setw(15)
-            << ("c" + Foam::name(cloudNo) + varName).c_str()
-            << " "
-            << (dirName/varName).c_str()
-            << nl;
-    }
-    else
-    {
-        caseFile
-            << ensightType.c_str()
-            << " per element: "
-            << setw(15) << varName
-            << " "
-            << (dirName/varName).c_str()
-            << nl;
-    }
-}
-
-
-void Foam::ensightParticlePositions
-(
-    const polyMesh& mesh,
-    const fileName& dataDir,
-    const fileName& subDir,
-    const word& cloudName,
-    IOstream::streamFormat format
-)
-{
-    Cloud<passiveParticle> parcels(mesh, cloudName, false);
-
-    const fileName postFileName =
-        subDir/cloud::prefix/cloudName/"positions";
-
-    // the ITER/lagrangian subdirectory must exist
-    mkDir(dataDir/postFileName.path());
-    ensightFile os(dataDir, postFileName, format);
-
-    // tag binary format (just like geometry files)
-    os.writeBinaryHeader();
-    os.write(postFileName); // description
-    os.newline();
-    os.write("particle coordinates");
-    os.newline();
-    os.write(parcels.size(), 8);   // unusual width
-    os.newline();
-
-    // binary write is Ensight6 - first ids, then positions
-    if (format == IOstream::BINARY)
-    {
-        forAll(parcels, i)
-        {
-            os.write(i+1);
-        }
-
-        forAllConstIter(Cloud<passiveParticle>, parcels, elmnt)
-        {
-            const vector& p = elmnt().position();
-
-            os.write(p.x());
-            os.write(p.y());
-            os.write(p.z());
-        }
-    }
-    else
-    {
-        label nParcels = 0;
-
-        forAllConstIter(Cloud<passiveParticle>, parcels, elmnt)
-        {
-            const vector& p = elmnt().position();
-
-            os.write(++nParcels, 8);    // unusual width
-            os.write(p.x());
-            os.write(p.y());
-            os.write(p.z());
-            os.newline();
-        }
-    }
-}
-
-
-
-template<class Type>
-void Foam::ensightLagrangianField
-(
-    const IOobject& fieldObject,
-    const fileName& dataDir,
-    const fileName& subDir,
-    const word& cloudName,
-    IOstream::streamFormat format
-)
-{
-    Info<< " " << fieldObject.name() << flush;
-
-    const fileName postFileName =
-        subDir/cloud::prefix/cloudName
-        /ensight::VarName(fieldObject.name());
-
-    // the ITER/lagrangian subdirectory was already created
-    // when writing positions
-
-    ensightFile os(dataDir, postFileName, format);
-    // description
-    os.write(string(postFileName + " <" + pTraits<Type>::typeName + ">"));
-    os.newline();
-
-    IOField<Type> field(fieldObject);
-
-    // 6 values per line
-    label count = 0;
-
-    forAll(field, i)
-    {
-        Type val = field[i];
-
-        if (mag(val) < 1e-90)
-        {
-            val = Zero;
-        }
-
-        for (direction d=0; d < pTraits<Type>::nComponents; ++d)
-        {
-            label cmpt = ensightPTraits<Type>::componentOrder[d];
-            os.write(component(val, cmpt));
-
-            if (++count % 6 == 0)
-            {
-                os.newline();
-            }
-        }
-    }
-
-    // add final newline if required
-    if (count % 6)
-    {
-        os.newline();
-    }
-}
-
-
-template<class Type>
-void Foam::ensightVolField
-(
-    const ensightParts& partsList,
-    const IOobject& fieldObject,
-    const fvMesh& mesh,
-    const fileName& dataDir,
-    const fileName& subDir,
-    IOstream::streamFormat format
-)
-{
-    Info<< " " << fieldObject.name() << flush;
-
-    const fileName postFileName = subDir/ensight::VarName(fieldObject.name());
-
-    ensightFile os(dataDir, postFileName, format);
-    os.write(postFileName); // description
-    os.newline();
-
-    // ie, volField<Type>
-    partsList.writeField
-    (
-        os,
-        GeometricField<Type, fvPatchField, volMesh>
-        (
-            fieldObject,
-            mesh
-        )
-    );
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputSerialCloud.C b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputSerialCloud.C
new file mode 100644
index 0000000000000000000000000000000000000000..5cc4a45f5cb312a62badd5b467d8720acecbbcc0
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputSerialCloud.C
@@ -0,0 +1,95 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "ensightOutputSerialCloud.H"
+#include "ensightPTraits.H"
+
+#include "passiveParticle.H"
+#include "IOField.H"
+#include "volFields.H"
+#include "surfaceFields.H"
+
+// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
+
+void Foam::ensightSerialCloud::writePositions
+(
+    const polyMesh& mesh,
+    const word& cloudName,
+    autoPtr<ensightFile> output
+)
+{
+    label nTotParcels = 0;
+    autoPtr<Cloud<passiveParticle>> cloudPtr;
+
+    cloudPtr.reset(new Cloud<passiveParticle>(mesh, cloudName, false));
+    nTotParcels = cloudPtr().size();
+
+    Cloud<passiveParticle> parcels(mesh, cloudName, false);
+
+    if (Pstream::master())
+    {
+        ensightFile& os = output();
+        os.beginParticleCoordinates(nTotParcels);
+
+        // binary write is Ensight6 - first ids, then positions
+        if (os.format() == IOstream::BINARY)
+        {
+            // 1-index
+            for (label parcelId = 0; parcelId < nTotParcels; ++parcelId)
+            {
+                os.write(parcelId+1);
+            }
+
+
+            forAllConstIter(Cloud<passiveParticle>, cloudPtr(), elmnt)
+            {
+                const vector& p = elmnt().position();
+
+                os.write(p.x());
+                os.write(p.y());
+                os.write(p.z());
+            }
+        }
+        else
+        {
+            // ASCII id + position together
+
+            label parcelId = 0;
+            forAllConstIter(Cloud<passiveParticle>, cloudPtr(), elmnt)
+            {
+                const vector& p = elmnt().position();
+
+                os.write(++parcelId, 8); // unusual width
+                os.write(p.x());
+                os.write(p.y());
+                os.write(p.z());
+                os.newline();
+            }
+        }
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightCloud.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputSerialCloud.H
similarity index 75%
rename from applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightCloud.H
rename to applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputSerialCloud.H
index 14661506622e2919f1140bc2f1b6ed588c61c73d..ff7608be5c5c4781a6076e72d6a66515ce2f36fa 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/ensightCloud.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputSerialCloud.H
@@ -21,68 +21,65 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
-InApplication
-    foamToEnsight
-
 Description
+    Miscellaneous collection of functions and template related to Ensight data
 
 SourceFiles
-    ensightCloud.C
-    ensightCloudTemplates.C
+    ensightOutputFunctions.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef ensightCloud_H
-#define ensightCloud_H
+#ifndef ensightOutputSerialCloud_H
+#define ensightOutputSerialCloud_H
 
 #include "ensightFile.H"
-#include "fvMesh.H"
 #include "Cloud.H"
+#include "polyMesh.H"
 #include "IOobject.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+
 namespace Foam
 {
+namespace ensightSerialCloud
+{
 
-void ensightParticlePositions
+//- Write cloud positions
+void writePositions
 (
-    const fvMesh& mesh,
-    const fileName& dataDir,
-    const label timeIndex,
+    const polyMesh& mesh,
     const word& cloudName,
-    const bool dataExists,
-    const IOstream::streamFormat format
+    autoPtr<ensightFile> output
 );
 
 
+//- Write cloud field
 template<class Type>
-void ensightCloudField
+bool writeCloudField
 (
-    const IOobject& fieldObject,
-    const fileName& dataDir,
-    const label timeIndex,
-    const word& cloudName,
-    const label cloudNo,
-    Ostream& ensightCaseFile,
-    const bool dataExists,
-    const IOstream::streamFormat format
+    const IOField<Type>& field,
+    ensightFile& os
 );
 
 
+//- Write cloud field
 template<class Type>
-void writeCloudField
+bool writeCloudField
 (
-    const IOField<Type>& field,
-    ensightFile& os
+    const IOobject& fieldObject,
+    autoPtr<ensightFile> output
 );
 
-}
+
+} // namespace ensightSerialCloud
+} // namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+
 #ifdef NoRepository
-    #include "ensightCloudTemplates.C"
+    #include "ensightOutputSerialCloudTemplates.C"
 #endif
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/conversion/ensight/part/ensightPartTemplates.C b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputSerialCloudTemplates.C
similarity index 54%
rename from src/conversion/ensight/part/ensightPartTemplates.C
rename to applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputSerialCloudTemplates.C
index 13186460402ed81739c7856b4af8120470fb3385..42034d0a1e8420ff989702f5b549e68fffbad114 100644
--- a/src/conversion/ensight/part/ensightPartTemplates.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/ensightOutputSerialCloudTemplates.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-2016 OpenFOAM Foundation
      \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
@@ -21,56 +21,69 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
-Description
-    Template to write generalized field components
-
 \*---------------------------------------------------------------------------*/
 
-#include "ensightPart.H"
+#include "ensightOutputSerialCloud.H"
+#include "ensightSerialOutput.H"
 #include "ensightPTraits.H"
 
+#include "passiveParticle.H"
+#include "IOField.H"
+#include "volFields.H"
+#include "surfaceFields.H"
+
 // * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
 
 template<class Type>
-void Foam::ensightPart::writeField
+bool Foam::ensightSerialCloud::writeCloudField
 (
-    ensightFile& os,
-    const Field<Type>& field,
-    const bool perNode
-) const
+    const IOField<Type>& field,
+    ensightFile& os
+)
 {
-    if (this->size() && field.size())
+    // 6 values per line
+    label count = 0;
+
+    forAll(field, i)
     {
-        writeHeader(os);
+        Type val = field[i];
 
-        if (perNode)
+        if (mag(val) < 1e-90)
         {
-            os.writeKeyword("coordinates");
-            for (direction d=0; d < pTraits<Type>::nComponents; ++d)
-            {
-                label cmpt = ensightPTraits<Type>::componentOrder[d];
-                writeFieldList(os, field.component(cmpt), labelUList::null());
-            }
+            val = Zero;
         }
-        else
+
+        for (direction d=0; d < pTraits<Type>::nComponents; ++d)
         {
-            forAll(elementTypes(), elemI)
+            label cmpt = ensightPTraits<Type>::componentOrder[d];
+            os.write(component(val, cmpt));
+
+            if (++count % 6 == 0)
             {
-                const labelUList& idList = elemLists_[elemI];
-
-                if (idList.size())
-                {
-                    os.writeKeyword(elementTypes()[elemI]);
-
-                    for (direction d=0; d < pTraits<Type>::nComponents; ++d)
-                    {
-                        label cmpt = ensightPTraits<Type>::componentOrder[d];
-                        writeFieldList(os, field.component(cmpt), idList);
-                    }
-                }
+                os.newline();
             }
         }
     }
+
+    // add final newline if required
+    if (count % 6)
+    {
+        os.newline();
+    }
+
+    return true;
+}
+
+
+template<class Type>
+bool Foam::ensightSerialCloud::writeCloudField
+(
+    const IOobject& fieldObject,
+    autoPtr<ensightFile> output
+)
+{
+    IOField<Type> field(fieldObject);
+    return writeCloudField(field, output.rawRef());
 }
 
 
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C
index 8c0bfb376a0f8879fd7c46fa1e3e5c0c3558ab43..ab2e67e855e76b05d0753575cb18d612c93dee74 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C
@@ -78,8 +78,14 @@ Note
 #include "scalarIOField.H"
 #include "tensorIOField.H"
 
+// file-format/conversion
+#include "ensightCase.H"
+#include "ensightGeoFile.H"
 #include "ensightParts.H"
-#include "ensightOutputFunctions.H"
+#include "ensightSerialOutput.H"
+
+// local files
+#include "ensightOutputSerialCloud.H"
 
 #include "memInfo.H"
 
@@ -133,33 +139,25 @@ int main(int argc, char *argv[])
     );
 
     // The volume field types that we handle
-    wordHashSet volFieldTypes;
-    volFieldTypes.insert(volScalarField::typeName);
-    volFieldTypes.insert(volVectorField::typeName);
-    volFieldTypes.insert(volSphericalTensorField::typeName);
-    volFieldTypes.insert(volSymmTensorField::typeName);
-    volFieldTypes.insert(volTensorField::typeName);
+    const wordHashSet volFieldTypes
+    {
+        volScalarField::typeName,
+        volVectorField::typeName,
+        volSphericalTensorField::typeName,
+        volSymmTensorField::typeName,
+        volTensorField::typeName
+    };
 
     // The lagrangian field types that we handle
-    wordHashSet cloudFieldTypes;
-    cloudFieldTypes.insert(scalarIOField::typeName);
-    cloudFieldTypes.insert(vectorIOField::typeName);
-    cloudFieldTypes.insert(tensorIOField::typeName);
-
-    const char* geometryName = "geometry";
+    const wordHashSet cloudFieldTypes
+    {
+        scalarIOField::typeName,
+        vectorIOField::typeName,
+        tensorIOField::typeName
+    };
 
     #include "setRootCase.H"
 
-    cpuTime timer;
-    memInfo mem;
-    Info<< "Initial memory "
-        << mem.update().size() << " kB" << endl;
-
-    #include "createTime.H"
-
-    // Get times list
-    instantList timeDirs = timeSelector::select0(runTime, args);
-
     // Default to binary output, unless otherwise specified
     const IOstream::streamFormat format =
     (
@@ -168,101 +166,91 @@ int main(int argc, char *argv[])
       : IOstream::BINARY
     );
 
-    // Control for renumbering iterations
-    label indexingNumber = 0;
-    const bool optIndex = args.optionReadIfPresent("index", indexingNumber);
-    const bool noLagrangian = args.optionFound("noLagrangian");
+    cpuTime timer;
+    memInfo mem;
+    Info<< "Initial memory " << mem.update().size() << " kB" << endl;
 
-    // Always write the geometry, unless the -noMesh option is specified
-    bool optNoMesh = args.optionFound("noMesh");
+    #include "createTime.H"
+
+    instantList timeDirs = timeSelector::select0(runTime, args);
+
+    #include "createNamedMesh.H"
 
-    // Adjust output width
-    if (args.optionFound("width"))
+    fileName regionPrefix; // Mesh instance (region0 gets filtered out)
+    if (regionName != polyMesh::defaultRegion)
     {
-        ensightFile::subDirWidth(args.optionRead<label>("width"));
+        regionPrefix = regionName;
     }
 
-    // Define sub-directory name to use for Ensight data
-    fileName ensightDir = "Ensight";
-    args.optionReadIfPresent("name", ensightDir);
+    //
+    // general (case) output options
+    //
+    ensightCase::options caseOpts(format);
 
+    caseOpts.width(args.optionLookupOrDefault<label>("width", 8));
+    caseOpts.overwrite(false); // leave existing output directory
+
+    // Can also have separate directory for lagrangian
+    // caseOpts.separateCloud(true);
+
+    // Define sub-directory name to use for EnSight data.
+    // The path to the ensight directory is at case level only
+    // - For parallel cases, data only written from master
+    fileName ensightDir = args.optionLookupOrDefault<word>("name", "Ensight");
     if (!ensightDir.isAbsolute())
     {
         ensightDir = args.rootPath()/args.globalCaseName()/ensightDir;
     }
 
-    const fileName caseFileName = "Ensight.case";
-    const fileName dataDir  = ensightDir/"data";
-    const fileName dataMask = dataDir.name()/ensightFile::mask();
+    //
+    // Open new ensight case file, initialize header etc.
+    //
+    ensightCase ensCase
+    (
+        ensightDir,
+        "Ensight",  // args.globalCaseName(),
+        caseOpts
+    );
 
-    // Ensight and Ensight/data directories must exist
-    // do not remove old data - we might wish to convert new results
-    // or a particular time interval
-    if (isDir(ensightDir))
-    {
-        Info<<"Warning: re-using existing directory" << nl
-            << "    " << ensightDir << endl;
-    }
 
-    // As per mkdir -p "Ensight/data"
-    mkDir(ensightDir);
-    mkDir(dataDir);
+    //
+    // Miscellaneous output configuration
+    //
 
-    #include "createNamedMesh.H"
+    // Control for renumbering iterations
+    label indexingNumber = 0;
+    const bool optIndex = args.optionReadIfPresent("index", indexingNumber);
+    const bool noLagrangian = args.optionFound("noLagrangian");
 
-    // Mesh instance (region0 gets filtered out)
-    fileName regionPrefix;
+    // Always write the geometry, unless the -noMesh option is specified
+    bool optNoMesh = args.optionFound("noMesh");
 
-    if (regionName != polyMesh::defaultRegion)
-    {
-        regionPrefix = regionName;
-    }
-
-    if (Pstream::master())
-    {
-        Info<< "Converting " << timeDirs.size() << " time steps" << endl;
-    }
 
     // Construct the list of ensight parts for the entire mesh
     ensightParts partsList(mesh);
 
     // Write summary information
+    if (Pstream::master())
     {
-        OFstream partsInfoFile(ensightDir/"partsInfo");
+        Info<< "Converting " << timeDirs.size() << " time steps" << endl;
+
+        OFstream info(ensCase.path()/"partsInfo");
 
-        partsInfoFile
+        info
             << "// summary of ensight parts" << nl << nl;
-        partsList.writeSummary(partsInfoFile);
+        partsList.writeSummary(info);
     }
 
-    #include "checkHasMovingMesh.H"
+    #include "checkMeshMoving.H"
     #include "findFields.H"
 
-    if (hasMovingMesh && optNoMesh)
+    if (meshMoving && optNoMesh)
     {
         Info<< "mesh is moving: ignoring '-noMesh' option" << endl;
         optNoMesh = false;
     }
 
 
-    // Map times used
-    Map<scalar>  timeIndices;
-
-    // TODO: Track the time indices used by the geometry
-    DynamicList<label> geometryTimesUsed;
-
-    // Track the time indices used by the volume fields
-    DynamicList<label> fieldTimesUsed;
-
-    // Track the time indices used by each cloud
-    HashTable<DynamicList<label>> cloudTimesUsed;
-
-    // Create a new DynamicList for each cloud
-    forAllConstIter(HashTable<HashTable<word>>, cloudFields, cloudIter)
-    {
-        cloudTimesUsed.insert(cloudIter.key(), DynamicList<label>());
-    }
-
     Info<< "Startup in "
         << timer.cpuTimeIncrement() << " s, "
         << mem.update().size() << " kB" << nl << endl;
@@ -272,25 +260,10 @@ int main(int argc, char *argv[])
         runTime.setTime(timeDirs[timeI], timeI);
 
         #include "getTimeIndex.H"
-
-        // Remember the time index for the volume fields
-        fieldTimesUsed.append(timeIndex);
-
-        // The data/ITER subdirectory must exist
-        // Note that data/ITER is indeed a valid ensight::FileName
-        const fileName subDir = ensightFile::subDir(timeIndex);
-        mkDir(dataDir/subDir);
-
-        // Place a timestamp in the directory for future reference
-        {
-            OFstream timeStamp(dataDir/subDir/"time");
-            timeStamp
-                << "#   timestep time" << nl
-                << subDir.c_str() << " " << runTime.timeName() << nl;
-        }
-
         #include "moveMesh.H"
 
+        ensCase.setTime(timeDirs[timeI], timeIndex);
+
         if (timeI == 0 || mesh.moving())
         {
             if (mesh.moving())
@@ -300,19 +273,8 @@ int main(int argc, char *argv[])
 
             if (!optNoMesh)
             {
-                if (hasMovingMesh)
-                {
-                    // Remember the time index for the geometry
-                    geometryTimesUsed.append(timeIndex);
-                }
-
-                ensightGeoFile geoFile
-                (
-                    (hasMovingMesh ? dataDir/subDir : ensightDir),
-                    geometryName,
-                    format
-                );
-                partsList.writeGeometry(geoFile);
+                autoPtr<ensightGeoFile> os = ensCase.newGeometry(meshMoving);
+                partsList.write(os.rawRef());
             }
         }
 
@@ -332,69 +294,77 @@ int main(int argc, char *argv[])
                 IOobject::NO_WRITE
             );
 
+            bool wrote = false;
             if (fieldType == volScalarField::typeName)
             {
-                ensightVolField<scalar>
+                autoPtr<ensightFile> os = ensCase.newData<scalar>
                 (
-                    partsList,
-                    fieldObject,
-                    mesh,
-                    dataDir,
-                    subDir,
-                    format
+                    fieldName
                 );
 
+                volScalarField vf(fieldObject, mesh);
+                wrote = ensightSerialOutput::writeField<scalar>
+                (
+                    vf, partsList, os
+                );
             }
             else if (fieldType == volVectorField::typeName)
             {
-                ensightVolField<vector>
+                autoPtr<ensightFile> os = ensCase.newData<vector>
                 (
-                    partsList,
-                    fieldObject,
-                    mesh,
-                    dataDir,
-                    subDir,
-                    format
+                    fieldName
                 );
 
+                volVectorField vf(fieldObject, mesh);
+                wrote = ensightSerialOutput::writeField<vector>
+                (
+                    vf, partsList, os
+                );
             }
             else if (fieldType == volSphericalTensorField::typeName)
             {
-                ensightVolField<sphericalTensor>
+                autoPtr<ensightFile> os = ensCase.newData<sphericalTensor>
                 (
-                    partsList,
-                    fieldObject,
-                    mesh,
-                    dataDir,
-                    subDir,
-                    format
+                    fieldName
                 );
 
+                volSphericalTensorField vf(fieldObject, mesh);
+                wrote = ensightSerialOutput::writeField<sphericalTensor>
+                (
+                    vf, partsList, os
+                );
             }
             else if (fieldType == volSymmTensorField::typeName)
             {
-                ensightVolField<symmTensor>
+                autoPtr<ensightFile> os = ensCase.newData<symmTensor>
                 (
-                    partsList,
-                    fieldObject,
-                    mesh,
-                    dataDir,
-                    subDir,
-                    format
+                    fieldName
+                );
+
+                volSymmTensorField vf(fieldObject, mesh);
+                wrote = ensightSerialOutput::writeField<symmTensor>
+                (
+                    vf, partsList, os
                 );
             }
             else if (fieldType == volTensorField::typeName)
             {
-                ensightVolField<tensor>
+                autoPtr<ensightFile> os = ensCase.newData<tensor>
+                (
+                    fieldName
+                );
+
+                volTensorField vf(fieldObject, mesh);
+                wrote = ensightSerialOutput::writeField<tensor>
                 (
-                    partsList,
-                    fieldObject,
-                    mesh,
-                    dataDir,
-                    subDir,
-                    format
+                    vf, partsList, os
                 );
             }
+
+            if (wrote)
+            {
+                Info<< " " << fieldObject.name() << flush;
+            }
         }
         Info<< " )" << endl;
 
@@ -422,16 +392,16 @@ int main(int argc, char *argv[])
                 continue;
             }
 
-            Info<< "Write " << cloudName << " ( positions" << flush;
+            Info<< "Write " << cloudName << " (" << flush;
 
-            ensightParticlePositions
+            ensightSerialCloud::writePositions
             (
                 mesh,
-                dataDir,
-                subDir,
                 cloudName,
-                format
+                ensCase.newCloud(cloudName)
             );
+            Info<< " positions";
+
 
             forAllConstIter(HashTable<word>, cloudIter(), fieldIter)
             {
@@ -449,48 +419,39 @@ int main(int argc, char *argv[])
                     continue;
                 }
 
+                bool wrote = false;
                 if (fieldType == scalarIOField::typeName)
                 {
-                    ensightLagrangianField<scalar>
+                    wrote = ensightSerialCloud::writeCloudField<scalar>
                     (
                         *fieldObject,
-                        dataDir,
-                        subDir,
-                        cloudName,
-                        format
+                        ensCase.newCloudData<scalar>(cloudName, fieldName)
                     );
-
                 }
                 else if (fieldType == vectorIOField::typeName)
                 {
-                    ensightLagrangianField<vector>
+                    wrote = ensightSerialCloud::writeCloudField<vector>
                     (
                         *fieldObject,
-                        dataDir,
-                        subDir,
-                        cloudName,
-                        format
+                        ensCase.newCloudData<vector>(cloudName, fieldName)
                     );
-
                 }
                 else if (fieldType == tensorIOField::typeName)
                 {
-                    ensightLagrangianField<tensor>
+                    wrote = ensightSerialCloud::writeCloudField<tensor>
                     (
                         *fieldObject,
-                        dataDir,
-                        subDir,
-                        cloudName,
-                        format
+                        ensCase.newCloudData<tensor>(cloudName, fieldName)
                     );
+                }
 
+                if (wrote)
+                {
+                    Info<< " " << fieldObject->name();
                 }
             }
 
             Info<< " )" << endl;
-
-            // Remember the time index
-            cloudTimesUsed[cloudName].append(timeIndex);
         }
 
         Info<< "Wrote in "
@@ -498,7 +459,7 @@ int main(int argc, char *argv[])
             << mem.update().size() << " kB" << endl;
     }
 
-    #include "ensightOutputCase.H"
+    ensCase.write();
 
     Info<< "\nEnd: "
         << timer.elapsedCpuTime() << " s, "
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/getTimeIndex.H b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/getTimeIndex.H
index 9d8e93dcd145b3c37eca3ed4aa16b06646d3dce3..a55e44e136420eafff0c92454fe786c2cfecc07b 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/getTimeIndex.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/getTimeIndex.H
@@ -38,6 +38,6 @@
         }
     }
 
-    timeIndices.insert(timeIndex, timeDirs[timeI].value());
     Info<< nl << "Time [" << timeIndex << "] = " << runTime.timeName() << nl;
 
+// end-of-file
diff --git a/applications/utilities/surface/surfaceBooleanFeatures/Allwmake b/applications/utilities/surface/surfaceBooleanFeatures/Allwmake
index 98d3d2035c07f8b2ae3ffe6dd6e4169edc4a4a4c..660a2e59b52039d526cc498cfab408d32a4cc953 100755
--- a/applications/utilities/surface/surfaceBooleanFeatures/Allwmake
+++ b/applications/utilities/surface/surfaceBooleanFeatures/Allwmake
@@ -4,8 +4,8 @@ set -x
 
 unset COMPILE_FLAGS LINK_FLAGS
 
-if [ -d "$CGAL_ARCH_PATH/include/CGAL" ] || \
-   [ "${CGAL_ARCH_PATH##*-}" = system -a -d /usr/include/CGAL ]
+if [ -f "$CGAL_ARCH_PATH/include/CGAL/version.h" ] || \
+   [ "${CGAL_ARCH_PATH##*-}" = system -a -f /usr/include/CGAL/version.h ]
 then
     wmake PolyhedronReader
     export COMPILE_FLAGS='-IPolyhedronReader'
diff --git a/applications/utilities/surface/surfaceBooleanFeatures/PolyhedronReader/Make/options b/applications/utilities/surface/surfaceBooleanFeatures/PolyhedronReader/Make/options
index 6603adda0ff4df4762f57ce04094904a0f32664b..424f89a8aba98e7eae709757dcc68d0a3471ec1e 100644
--- a/applications/utilities/surface/surfaceBooleanFeatures/PolyhedronReader/Make/options
+++ b/applications/utilities/surface/surfaceBooleanFeatures/PolyhedronReader/Make/options
@@ -1,7 +1,6 @@
 EXE_NDEBUG = -DNDEBUG
 /* EXE_NDEBUG = -g -O0 -DFULLDEBUG */
 
-
 c++CGALWARN = -Wno-old-style-cast
 
 /*-- Define CGAL_INEXACT to use inexact CGAL constructions */
@@ -21,5 +20,5 @@ EXE_INC = \
     -I/usr/include/Qt
 
 LIB_LIBS = \
-    -L${CGAL_ARCH_PATH}/lib \
+    -L$(CGAL_ARCH_PATH)/lib$(WM_COMPILER_LIB_ARCH) \
     -ltriSurface
diff --git a/applications/utilities/surface/surfaceMeshConvertTesting/surfaceMeshConvertTesting.C b/applications/utilities/surface/surfaceMeshConvertTesting/surfaceMeshConvertTesting.C
index e0dcfcf0cc334cf5d1bca1510bfc9d02ce2eaf3c..edb8527698e8ec8f19ec9bb151072239d1f4bed9 100644
--- a/applications/utilities/surface/surfaceMeshConvertTesting/surfaceMeshConvertTesting.C
+++ b/applications/utilities/surface/surfaceMeshConvertTesting/surfaceMeshConvertTesting.C
@@ -161,7 +161,8 @@ int main(int argc, char *argv[])
 
         Info<< "Read surface:" << endl;
         surf.writeStats(Info);
-        Info<< endl;
+        Info<< "Area         : " << sum(surf.magSf()) << nl
+            << endl;
 
         // check: output to ostream, construct from istream
         {
@@ -205,7 +206,8 @@ int main(int argc, char *argv[])
             Info<< " with scaling " << scaleFactor << endl;
             surf.scalePoints(scaleFactor);
             surf.writeStats(Info);
-            Info<< endl;
+            Info<< "Area         : " << sum(surf.magSf()) << nl
+                << endl;
         }
 
         if (optStdout)
@@ -224,7 +226,8 @@ int main(int argc, char *argv[])
 
         Info<< "Read surface:" << endl;
         surf.writeStats(Info);
-        Info<< endl;
+        Info<< "Area         : " << sum(surf.magSf()) << nl
+            << endl;
 
         // check: output to ostream, construct from istream
         {
@@ -268,7 +271,8 @@ int main(int argc, char *argv[])
             Info<< " with scaling " << scaleFactor << endl;
             surf.scalePoints(scaleFactor);
             surf.writeStats(Info);
-            Info<< endl;
+            Info<< "Area         : " << sum(surf.magSf()) << nl
+                << endl;
         }
 
         if (optStdout)
@@ -286,7 +290,8 @@ int main(int argc, char *argv[])
 
         Info<< "Read surface:" << endl;
         surf.writeStats(Info);
-        Info<< endl;
+        Info<< "Area         : " << sum(surf.magSf()) << nl
+            << endl;
 
         // check: output to ostream, construct from istream
         {
@@ -330,7 +335,8 @@ int main(int argc, char *argv[])
             Info<< " with scaling " << scaleFactor << endl;
             surf.scalePoints(scaleFactor);
             surf.writeStats(Info);
-            Info<< endl;
+            Info<< "Area         : " << sum(surf.magSf()) << nl
+                << endl;
         }
 
         if (optStdout)
@@ -348,7 +354,8 @@ int main(int argc, char *argv[])
 
         Info<< "Read surface:" << endl;
         surf.writeStats(Info);
-        Info<< endl;
+        Info<< "Area         : " << sum(surf.magSf()) << nl
+            << endl;
 
         // check: output to ostream, construct from istream
         {
@@ -392,7 +399,8 @@ int main(int argc, char *argv[])
             Info<< " with scaling " << scaleFactor << endl;
             surf.scalePoints(scaleFactor);
             surf.writeStats(Info);
-            Info<< endl;
+            Info<< "Area         : " << sum(surf.magSf()) << nl
+                << endl;
         }
 
         if (optStdout)
diff --git a/etc/config.csh/CGAL b/etc/config.csh/CGAL
index 2fd06120eb67550b22e6a5ad752a89238c22abc8..84bc71bda6099e176d517c47763a95398a6d51d4 100644
--- a/etc/config.csh/CGAL
+++ b/etc/config.csh/CGAL
@@ -68,12 +68,12 @@ endif
 
 set ending="${BOOST_ARCH_PATH:t}"
 if ( "$ending" != "boost-none" && "$ending" != "boost-system" ) then
-    _foamAddLib $BOOST_ARCH_PATH/lib
+    _foamAddLib $BOOST_ARCH_PATH/lib$WM_COMPILER_LIB_ARCH
 endif
 
 set ending="${CGAL_ARCH_PATH:t}"
 if ( "$ending" != "cgal-none" && "$ending" != "cgal-system" ) then
-    _foamAddLib $CGAL_ARCH_PATH/lib
+    _foamAddLib $CGAL_ARCH_PATH/lib$WM_COMPILER_LIB_ARCH
 endif
 
 unset boost_version cgal_version ending
diff --git a/etc/config.sh/CGAL b/etc/config.sh/CGAL
index e23164d2c920402a636f6921a2500c5f89461434..044327109f64ec5c4762546ff1214e3c04b2c2fb 100644
--- a/etc/config.sh/CGAL
+++ b/etc/config.sh/CGAL
@@ -72,13 +72,13 @@ then
     ending="${BOOST_ARCH_PATH##*-}"
     if [ "$ending" != none -a "$ending" != system ]
     then
-        _foamAddLib $BOOST_ARCH_PATH/lib
+        _foamAddLib $BOOST_ARCH_PATH/lib$WM_COMPILER_LIB_ARCH
     fi
 
     ending="${CGAL_ARCH_PATH##*-}"
     if [ "$ending" != none -a "$ending" != system ]
     then
-        _foamAddLib $CGAL_ARCH_PATH/lib
+        _foamAddLib $CGAL_ARCH_PATH/lib$WM_COMPILER_LIB_ARCH
     fi
 
     unset boost_version cgal_version ending
diff --git a/src/OpenFOAM/db/IOobject/IOobjectTemplates.C b/src/OpenFOAM/db/IOobject/IOobjectTemplates.C
index b1e39564a5b8136fcfe8b8fda76cf87eb6c3661e..1ef06e3415e7902bfc452126f4c54fe71c339701 100644
--- a/src/OpenFOAM/db/IOobject/IOobjectTemplates.C
+++ b/src/OpenFOAM/db/IOobject/IOobjectTemplates.C
@@ -69,9 +69,12 @@ bool Foam::IOobject::typeHeaderOk(const bool checkType)
             {
                 if (checkType && headerClassName_ != Type::typeName)
                 {
-                    IOWarningInFunction(*isPtr)
-                        << "unexpected class name " << headerClassName_
-                        << " expected " << Type::typeName << endl;
+                    if (debug)
+                    {
+                        IOWarningInFunction(*isPtr)
+                            << "unexpected class name " << headerClassName_
+                            << " expected " << Type::typeName << endl;
+                    }
 
                     ok = false;
                 }
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatch.C b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatch.C
index 04c3f9e62a5630bdb4ca800b5ecbedb2f30d1835..fdff5f05c3a198a06b588a1ba043dd4456b5d69b 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatch.C
+++ b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatch.C
@@ -58,6 +58,8 @@ PrimitivePatch
     localPointsPtr_(nullptr),
     localPointOrderPtr_(nullptr),
     faceCentresPtr_(nullptr),
+    faceAreasPtr_(nullptr),
+    magFaceAreasPtr_(nullptr),
     faceNormalsPtr_(nullptr),
     pointNormalsPtr_(nullptr)
 {}
@@ -94,6 +96,8 @@ PrimitivePatch
     localPointsPtr_(nullptr),
     localPointOrderPtr_(nullptr),
     faceCentresPtr_(nullptr),
+    faceAreasPtr_(nullptr),
+    magFaceAreasPtr_(nullptr),
     faceNormalsPtr_(nullptr),
     pointNormalsPtr_(nullptr)
 {}
@@ -131,6 +135,8 @@ PrimitivePatch
     localPointsPtr_(nullptr),
     localPointOrderPtr_(nullptr),
     faceCentresPtr_(nullptr),
+    faceAreasPtr_(nullptr),
+    magFaceAreasPtr_(nullptr),
     faceNormalsPtr_(nullptr),
     pointNormalsPtr_(nullptr)
 {}
@@ -167,6 +173,8 @@ PrimitivePatch
     localPointsPtr_(nullptr),
     localPointOrderPtr_(nullptr),
     faceCentresPtr_(nullptr),
+    faceAreasPtr_(nullptr),
+    magFaceAreasPtr_(nullptr),
     faceNormalsPtr_(nullptr),
     pointNormalsPtr_(nullptr)
 {}
@@ -524,6 +532,46 @@ faceCentres() const
 }
 
 
+template
+<
+    class Face,
+    template<class> class FaceList,
+    class PointField,
+    class PointType
+>
+const Foam::Field<PointType>&
+Foam::PrimitivePatch<Face, FaceList, PointField, PointType>::
+faceAreas() const
+{
+    if (!faceAreasPtr_)
+    {
+        calcFaceAreas();
+    }
+
+    return *faceAreasPtr_;
+}
+
+
+template
+<
+    class Face,
+    template<class> class FaceList,
+    class PointField,
+    class PointType
+>
+const Foam::Field<Foam::scalar>&
+Foam::PrimitivePatch<Face, FaceList, PointField, PointType>::
+magFaceAreas() const
+{
+    if (!magFaceAreasPtr_)
+    {
+        calcMagFaceAreas();
+    }
+
+    return *magFaceAreasPtr_;
+}
+
+
 template
 <
     class Face,
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatch.H b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatch.H
index 5668e8f064ef665ae418ab67925078767031376a..6e732b9fd824f72b34273fc0100e983f214e3dc5 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatch.H
+++ b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatch.H
@@ -168,6 +168,12 @@ private:
         //- Face centres
         mutable Field<PointType>* faceCentresPtr_;
 
+        //- Face area vectors
+        mutable Field<PointType>* faceAreasPtr_;
+
+        //- Mag face area
+        mutable Field<scalar>* magFaceAreasPtr_;
+
         //- Face unit normals
         mutable Field<PointType>* faceNormalsPtr_;
 
@@ -210,6 +216,12 @@ private:
         //- Calculate face centres
         void calcFaceCentres() const;
 
+        //- Calculate face area vectors
+        void calcFaceAreas() const;
+
+        //- Calculate face area magnitudes
+        void calcMagFaceAreas() const;
+
         //- Calculate unit face normals
         void calcFaceNormals() const;
 
@@ -381,7 +393,13 @@ public:
             //- Return face centres for patch
             const Field<PointType>& faceCentres() const;
 
-            //- Return face normals for patch
+            //- Return face area vectors for patch
+            const Field<PointType>& faceAreas() const;
+
+            //- Return face area magnitudes for patch
+            const Field<scalar>& magFaceAreas() const;
+
+            //- Return face unit normals for patch
             const Field<PointType>& faceNormals() const;
 
             //- Return point normals for patch
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchClear.C b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchClear.C
index 3ac89f2c61e6a493481e34584917b0402033d1f9..3a226c385d53b1f11c6ce3344324e1c60c8a5a60 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchClear.C
+++ b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchClear.C
@@ -47,6 +47,8 @@ clearGeom()
 
     deleteDemandDrivenData(localPointsPtr_);
     deleteDemandDrivenData(faceCentresPtr_);
+    deleteDemandDrivenData(faceAreasPtr_);
+    deleteDemandDrivenData(magFaceAreasPtr_);
     deleteDemandDrivenData(faceNormalsPtr_);
     deleteDemandDrivenData(pointNormalsPtr_);
 }
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchMeshData.C b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchMeshData.C
index 10f758c6485ec0c40eea2d701c241148f553f30f..50e4222be0a54fee5b911ae385cacf592d34ce6f 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchMeshData.C
+++ b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchMeshData.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -52,7 +52,7 @@ calcMeshData() const
     if (meshPointsPtr_ || localFacesPtr_)
     {
         FatalErrorInFunction
-            << "meshPointsPtr_ or localFacesPtr_already allocated"
+            << "meshPointsPtr_ or localFacesPtr_ already allocated"
             << abort(FatalError);
     }
 
@@ -210,7 +210,7 @@ calcLocalPoints() const
     if (localPointsPtr_)
     {
         FatalErrorInFunction
-            << "localPointsPtr_already allocated"
+            << "localPointsPtr_ already allocated"
             << abort(FatalError);
     }
 
@@ -259,7 +259,7 @@ calcPointNormals() const
     if (pointNormalsPtr_)
     {
         FatalErrorInFunction
-            << "pointNormalsPtr_already allocated"
+            << "pointNormalsPtr_ already allocated"
             << abort(FatalError);
     }
 
@@ -323,7 +323,7 @@ calcFaceCentres() const
     if (faceCentresPtr_)
     {
         FatalErrorInFunction
-            << "faceCentresPtr_already allocated"
+            << "faceCentresPtr_ already allocated"
             << abort(FatalError);
     }
 
@@ -346,6 +346,98 @@ calcFaceCentres() const
 }
 
 
+template
+<
+    class Face,
+    template<class> class FaceList,
+    class PointField,
+    class PointType
+>
+void
+Foam::PrimitivePatch<Face, FaceList, PointField, PointType>::
+calcMagFaceAreas() const
+{
+    if (debug)
+    {
+        Pout<< "PrimitivePatch<Face, FaceList, PointField, PointType>::"
+               "calcMagFaceAreas() : "
+               "calculating magFaceAreas in PrimitivePatch"
+            << endl;
+    }
+
+    // It is an error to calculate these more than once.
+    if (magFaceAreasPtr_)
+    {
+        FatalErrorInFunction
+            << "magFaceAreasPtr_ already allocated"
+            << abort(FatalError);
+    }
+
+    magFaceAreasPtr_ = new Field<scalar>(this->size());
+    Field<scalar>& a = *magFaceAreasPtr_;
+
+    forAll(a, facei)
+    {
+        a[facei] = this->operator[](facei).mag(points_);
+    }
+
+    if (debug)
+    {
+        Pout<< "PrimitivePatch<Face, FaceList, PointField, PointType>::"
+               "calcMagFaceAreas() : "
+               "finished calculating magFaceAreas in PrimitivePatch"
+            << endl;
+    }
+}
+
+
+template
+<
+    class Face,
+    template<class> class FaceList,
+    class PointField,
+    class PointType
+>
+void
+Foam::PrimitivePatch<Face, FaceList, PointField, PointType>::
+calcFaceAreas() const
+{
+    if (debug)
+    {
+        Pout<< "PrimitivePatch<Face, FaceList, PointField, PointType>::"
+               "calcFaceAreas() : "
+               "calculating faceAreas in PrimitivePatch"
+            << endl;
+    }
+
+    // It is considered an error to attempt to recalculate faceNormals
+    // if they have already been calculated.
+    if (faceAreasPtr_)
+    {
+        FatalErrorInFunction
+            << "faceAreasPtr_ already allocated"
+            << abort(FatalError);
+    }
+
+    faceAreasPtr_ = new Field<PointType>(this->size());
+
+    Field<PointType>& n = *faceAreasPtr_;
+
+    forAll(n, facei)
+    {
+        n[facei] = this->operator[](facei).normal(points_);
+    }
+
+    if (debug)
+    {
+        Pout<< "PrimitivePatch<Face, FaceList, PointField, PointType>::"
+               "calcFaceAreas() : "
+               "finished calculating faceAreas in PrimitivePatch"
+            << endl;
+    }
+}
+
+
 template
 <
     class Face,
@@ -370,7 +462,7 @@ calcFaceNormals() const
     if (faceNormalsPtr_)
     {
         FatalErrorInFunction
-            << "faceNormalsPtr_already allocated"
+            << "faceNormalsPtr_ already allocated"
             << abort(FatalError);
     }
 
diff --git a/src/conversion/Make/files b/src/conversion/Make/files
index bbf86cf8591cf5de9273507b3dbc32432d7e7c95..19af831aeb5a682c329d131f838512a8654cbedf 100644
--- a/src/conversion/Make/files
+++ b/src/conversion/Make/files
@@ -7,16 +7,14 @@ common/writer/meshWriter.C
 common/tables/boundaryRegion.C
 common/tables/cellTable.C
 
-ensight/file/ensightFile.C
-ensight/file/ensightGeoFile.C
-ensight/readFile/ensightReadFile.C
+ensight/mesh/ensightMesh.C
+ensight/mesh/ensightMeshIO.C
+ensight/mesh/ensightMeshOptions.C
 ensight/part/ensightPart.C
-ensight/part/ensightPartIO.C
 ensight/part/ensightPartCells.C
 ensight/part/ensightPartFaces.C
 ensight/part/ensightParts.C
 
-
 starcd/STARCDMeshReader.C
 starcd/STARCDMeshWriter.C
 
diff --git a/src/conversion/common/reader/createPolyBoundary.C b/src/conversion/common/reader/createPolyBoundary.C
index 7279b73c4135b8e98aabbd9c0ff706fd882ed027..645c90f6b5a7abed22eef3509d3ccc19b8395dec 100644
--- a/src/conversion/common/reader/createPolyBoundary.C
+++ b/src/conversion/common/reader/createPolyBoundary.C
@@ -439,14 +439,26 @@ Foam::meshReader::polyBoundaryPatches(const polyMesh& mesh)
         }
         dictionary& patchDict = patchDicts[patchi];
 
-        // add but not overwrite type
-        patchDict.add("type", patchTypes_[patchi], false);
-        if (patchPhysicalTypes_.size() && patchPhysicalTypes_[patchi].size())
+        // Add but not override 'type'
+        if (!patchDict.found("type"))
         {
-            patchDict.add("startFace", patchPhysicalTypes_[patchi], false);
+            patchDict.add("type", patchTypes_[patchi], false);
         }
 
-        // overwrite sizes and start
+        // Add but not override 'physicalType' but only if it differs
+        // from 'type'
+        if
+        (
+            patchi < patchPhysicalTypes_.size()
+         && patchPhysicalTypes_[patchi].size()
+         && patchPhysicalTypes_[patchi] != patchTypes_[patchi]
+         && !patchDict.found("physicalType")
+        )
+        {
+            patchDict.add("physicalType", patchPhysicalTypes_[patchi], false);
+        }
+
+        // Overwrite sizes and start
         patchDict.add("nFaces", patchSizes_[patchi], true);
         patchDict.add("startFace", patchStarts_[patchi], true);
     }
diff --git a/src/conversion/ensight/mesh/ensightMesh.C b/src/conversion/ensight/mesh/ensightMesh.C
new file mode 100644
index 0000000000000000000000000000000000000000..c10721d51e8799a33aa47b672eac769ad09a010a
--- /dev/null
+++ b/src/conversion/ensight/mesh/ensightMesh.C
@@ -0,0 +1,434 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "ensightMesh.H"
+#include "fvMesh.H"
+#include "globalMeshData.H"
+#include "PstreamCombineReduceOps.H"
+#include "processorPolyPatch.H"
+#include "mapDistribute.H"
+#include "stringListOps.H"
+
+#include "ensightFile.H"
+#include "ensightGeoFile.H"
+#include "demandDrivenData.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::ensightMesh::clear()
+{
+    meshCells_.clear();
+    boundaryPatchFaces_.clear();
+    faceZoneFaces_.clear();
+    patchLookup_.clear();
+    globalPointsPtr_.clear();
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::ensightMesh::ensightMesh
+(
+    const fvMesh& mesh,
+    const ensightMesh::options& opts
+)
+:
+    options_(new options(opts)),
+    mesh_(mesh),
+    needsUpdate_(true)
+{
+    if (!option().lazy())
+    {
+        correct();
+    }
+}
+
+
+Foam::ensightMesh::ensightMesh
+(
+    const fvMesh& mesh,
+    const IOstream::streamFormat format
+)
+:
+    options_(new options(format)),
+    mesh_(mesh),
+    needsUpdate_(true)
+{
+    if (!option().lazy())
+    {
+        correct();
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::ensightMesh::~ensightMesh()
+{
+    deleteDemandDrivenData(options_);
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::ensightMesh::needsUpdate() const
+{
+    return needsUpdate_;
+}
+
+
+bool Foam::ensightMesh::expire()
+{
+    clear();
+
+    // already marked as expired
+    if (needsUpdate_)
+    {
+        return false;
+    }
+
+    needsUpdate_ = true;
+    return true;
+}
+
+
+void Foam::ensightMesh::correct()
+{
+    clear();
+
+    // First see if patches are allowed/disallowed
+    // and if only particular patches should be selected
+
+    label nParts = 1;  // provisionally (for internalMesh)
+
+    if (option().usePatches())
+    {
+        // Patches are output. Check that they are synced.
+        mesh_.boundaryMesh().checkParallelSync(true);
+
+        wordList patchNames = mesh_.boundaryMesh().names();
+        if (Pstream::parRun())
+        {
+            patchNames.setSize
+            (
+                mesh_.boundary().size()
+              - mesh_.globalData().processorPatches().size()
+            );
+        }
+
+        labelList matched;
+
+        bool useAll = true;
+        const wordReList& matcher = option().patchSelection();
+        if (notNull(matcher))
+        {
+            nParts = 0; // no internalMesh
+
+            if (!matcher.empty())
+            {
+                useAll = false;
+                matched = findMatchingStrings
+                (
+                    wordReListMatcher(matcher),
+                    patchNames
+                );
+            }
+        }
+
+        if (useAll)
+        {
+            matched = identity(patchNames.size());
+        }
+
+        forAll(matched, matchi)
+        {
+            const label patchId   = matched[matchi];
+            const word& patchName = patchNames[patchId];
+
+            // use fvPatch (not polyPatch) to automatically remove empty patches
+            const fvPatch& p = mesh_.boundary()[patchId];
+
+            // yes we most likely want this patch.
+            // - can use insert or set, since hash was cleared before
+            boundaryPatchFaces_.set(patchName, ensightFaces());
+            ensightFaces& ensFaces = boundaryPatchFaces_[patchName];
+
+            if (p.size())
+            {
+                // use local face addressing (offset = 0),
+                // since this is what we'll need later when writing fields
+                ensFaces.classify(p.patch());
+            }
+            else
+            {
+                // patch is empty (on this processor)
+                // or the patch is 'empty' (as fvPatch type)
+                ensFaces.clear();
+            }
+
+            // finalize
+            ensFaces.reduce();
+
+            if (ensFaces.total())
+            {
+                patchLookup_.set(patchId, patchName);
+                ensFaces.index() = nParts++;
+            }
+            else
+            {
+                boundaryPatchFaces_.erase(patchName);
+            }
+        }
+
+        // At this point,
+        // * patchLookup_        is a map of (patchId, name)
+        // * boundaryPatchFaces_ is a lookup by name for the faces elements
+    }
+
+    if (useInternalMesh())
+    {
+        meshCells_.index() = 0;
+        meshCells_.classify(mesh_);
+
+        // Determine parallel shared points
+        globalPointsPtr_ = mesh_.globalData().mergePoints
+        (
+            pointToGlobal_,
+            uniquePointMap_
+        );
+    }
+
+    meshCells_.reduce();
+
+    // faceZones
+    if (option().useFaceZones())
+    {
+        // Mark boundary faces to be excluded from export
+        PackedBoolList excludeFace(mesh_.nFaces()); // all false
+
+        forAll(mesh_.boundaryMesh(), patchi)
+        {
+            const polyPatch& pp = mesh_.boundaryMesh()[patchi];
+            if
+            (
+                isA<processorPolyPatch>(pp)
+             && !refCast<const processorPolyPatch>(pp).owner()
+            )
+            {
+                label bFaceI = pp.start();
+                forAll(pp, i)
+                {
+                    excludeFace.set(bFaceI++);
+                }
+            }
+        }
+
+        const wordReList& matcher = option().faceZoneSelection();
+
+        wordList selectZones = mesh_.faceZones().names();
+        inplaceSubsetMatchingStrings
+        (
+            wordReListMatcher(matcher),
+            selectZones
+        );
+
+        // have same order as later with sortedToc()
+        Foam::sort(selectZones);
+
+        // Count face types in each selected faceZone
+        forAll(selectZones, zoneI)
+        {
+            const word& zoneName = selectZones[zoneI];
+            const label zoneID = mesh_.faceZones().findZoneID(zoneName);
+            const faceZone& fz = mesh_.faceZones()[zoneID];
+
+            // yes we most likely want this zone
+            // - can use insert or set, since hash was cleared before
+            faceZoneFaces_.set(zoneName, ensightFaces());
+            ensightFaces& ensFaces = faceZoneFaces_[zoneName];
+
+            if (fz.size())
+            {
+                ensFaces.classify
+                (
+                    mesh_.faces(),
+                    fz,
+                    fz.flipMap(),
+                    excludeFace
+                );
+            }
+
+            // finalize
+            ensFaces.reduce();
+
+            if (ensFaces.total())
+            {
+                ensFaces.index() = nParts++;
+            }
+            else
+            {
+                faceZoneFaces_.erase(zoneName);
+            }
+        }
+    }
+
+    needsUpdate_ = false;
+}
+
+
+void Foam::ensightMesh::write(ensightGeoFile& os) const
+{
+    if (useInternalMesh())
+    {
+        label nPoints = globalPoints().size();
+
+        const pointField uniquePoints(mesh_.points(), uniquePointMap_);
+
+        // writePartHeader(os, 0, "internalMesh");
+        // beginCoordinates(os, nPoints);
+        writeAllPoints
+        (
+            meshCells_.index(),
+            "internalMesh",
+            nPoints,
+            uniquePoints,
+            os
+        );
+
+        writeCellConnectivity(meshCells_, pointToGlobal_, os);
+    }
+
+
+    //
+    // write patches
+    // use sortedToc for extra safety
+    //
+    const labelList patchIds = patchLookup_.sortedToc();
+    forAll(patchIds, listi)
+    {
+        const label patchId   = patchIds[listi];
+        const word& patchName = patchLookup_[patchId];
+        const ensightFaces& ensFaces = boundaryPatchFaces_[patchName];
+
+        const polyPatch& pp = mesh_.boundaryMesh()[patchId];
+
+        // Renumber the patch points/faces into unique points
+        labelList pointToGlobal;
+        labelList uniqueMeshPointLabels;
+        autoPtr<globalIndex> globalPointsPtr =
+            mesh_.globalData().mergePoints
+            (
+                pp.meshPoints(),
+                pp.meshPointMap(),
+                pointToGlobal,
+                uniqueMeshPointLabels
+            );
+
+        pointField uniquePoints(mesh_.points(), uniqueMeshPointLabels);
+        // Renumber the patch faces
+        faceList patchFaces(pp.localFaces());
+        forAll(patchFaces, i)
+        {
+            inplaceRenumber(pointToGlobal, patchFaces[i]);
+        }
+
+        writeAllPoints
+        (
+            ensFaces.index(),
+            patchName,
+            globalPointsPtr().size(),
+            uniquePoints,
+            os
+        );
+
+        writeFaceConnectivity(ensFaces, patchFaces, os);
+    }
+
+
+    //
+    // write faceZones, if requested
+    //
+    const wordList zoneNames = faceZoneFaces_.sortedToc();
+    forAll(zoneNames, zonei)
+    {
+        const word& zoneName = zoneNames[zonei];
+        const ensightFaces& ensFaces = faceZoneFaces_[zoneName];
+
+        label zoneId = mesh_.faceZones().findZoneID(zoneName);
+        const faceZone& fz = mesh_.faceZones()[zoneId];
+
+        // Renumber the faceZone points/faces into unique points
+        labelList pointToGlobal;
+        labelList uniqueMeshPointLabels;
+        autoPtr<globalIndex> globalPointsPtr =
+            mesh_.globalData().mergePoints
+            (
+                fz().meshPoints(),
+                fz().meshPointMap(),
+                pointToGlobal,
+                uniqueMeshPointLabels
+            );
+
+        pointField uniquePoints(mesh_.points(), uniqueMeshPointLabels);
+
+        primitiveFacePatch facePatch
+        (
+            faceList(mesh_.faces(), ensFaces.faceIds()),
+            mesh_.points()
+        );
+
+        const boolList& flip = ensFaces.flipMap();
+        forAll(facePatch[faceI], faceI)
+        {
+            if (flip[faceI])
+            {
+                facePatch[faceI].flip();
+            }
+        }
+
+        // Faces belonging to the faceZone, in local numbering
+        faceList localFaces(facePatch.localFaces());
+
+        // Renumber the faceZone master faces
+        forAll(localFaces, i)
+        {
+            inplaceRenumber(pointToGlobal, localFaces[i]);
+        }
+
+        writeAllPoints
+        (
+            ensFaces.index(),
+            zoneName,
+            globalPointsPtr().size(),
+            uniquePoints,
+            os
+        );
+
+        writeFaceConnectivity(ensFaces, localFaces, os, true);
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/mesh/ensightMesh.H b/src/conversion/ensight/mesh/ensightMesh.H
new file mode 100644
index 0000000000000000000000000000000000000000..41ebb07aa7786c428d46fdc0645b0309d6de2767
--- /dev/null
+++ b/src/conversion/ensight/mesh/ensightMesh.H
@@ -0,0 +1,453 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::ensightMesh
+
+Description
+    Encapsulation of volume meshes for writing in ensight format.
+
+SourceFiles
+    ensightMesh.C
+    ensightMeshIO.C
+    ensightMeshOptions.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ensightMesh_H
+#define ensightMesh_H
+
+#include "ensightCells.H"
+#include "ensightFaces.H"
+#include "ensightGeoFile.H"
+#include "cellList.H"
+#include "faceList.H"
+#include "cellShapeList.H"
+#include "HashTable.H"
+#include "Map.H"
+#include "scalarField.H"
+#include "wordReList.H"
+#include "globalIndex.H"
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declarations
+class fvMesh;
+class ensightMesh;
+
+/*---------------------------------------------------------------------------*\
+                         Class ensightMesh Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightMesh
+{
+public:
+    // Forward declarations
+    class options;
+
+
+private:
+
+    // Private data
+
+        //- Writer options
+        const options* options_;
+
+        //- Reference to the OpenFOAM mesh
+        const fvMesh& mesh_;
+
+        //- The volume cells (internalMesh)
+        ensightCells meshCells_;
+
+        //- Face elements per patch
+        HashTable<ensightFaces> boundaryPatchFaces_;
+
+        //- Face elements per faceZone
+        HashTable<ensightFaces> faceZoneFaces_;
+
+        //- The list of patches to be output
+        Map<word> patchLookup_;
+
+        //- Track if it needs an update
+        mutable bool needsUpdate_;
+
+
+        // Parallel merged points
+
+            //- Global numbering for merged points
+            autoPtr<globalIndex> globalPointsPtr_;
+
+            //- From mesh point to global merged point
+            labelList pointToGlobal_;
+
+            //- Local points that are unique
+            labelList uniquePointMap_;
+
+
+    // Private Member Functions
+
+        //- Clear some storage
+        void clear();
+
+
+        //- Inplace renumber of cell-shapes
+        static cellShapeList& renumberShapes
+        (
+            cellShapeList&,
+            const labelUList& pointToGlobal
+        );
+
+        static cellShapeList map
+        (
+            const cellShapeList&,
+            const labelUList& prims,
+            const labelUList& pointToGlobal
+        );
+
+        //- Write list of faces
+        static void writeFaceList
+        (
+            const faceList&,
+            ensightGeoFile&
+        );
+
+        //- Write list of faces
+        static void writeFaceList
+        (
+            const UIndirectList<face>&,
+            ensightGeoFile&
+        );
+
+        //- Write sizes of faces in the list
+        static void writeFaceSizes
+        (
+            const faceList&,
+            ensightGeoFile&
+        );
+
+        //- Write sizes of faces in the list
+        static void writeFaceSizes
+        (
+            const UIndirectList<face>&,
+            ensightGeoFile&
+        );
+
+        //- Write cell connectivity via shell shapes
+        static void writeCellShapes
+        (
+            const cellShapeList&,
+            ensightGeoFile&
+        );
+
+        void writePolysNFaces
+        (
+            const labelList& polys,
+            const cellList& cellFaces,
+            ensightGeoFile&
+        ) const;
+
+        void writePolysNPointsPerFace
+        (
+            const labelList& polys,
+            const cellList& cellFaces,
+            const faceList& faces,
+            ensightGeoFile&
+        ) const;
+
+        void writePolysPoints
+        (
+            const labelList& polys,
+            const cellList& cellFaces,
+            const faceList& faces,
+            const labelList& faceOwner,
+            ensightGeoFile&
+        ) const;
+
+        void writePolysConnectivity
+        (
+            const labelList& addr,
+            const labelList& pointToGlobal,
+            ensightGeoFile&
+        ) const;
+
+        void writeCellConnectivity
+        (
+            const ensightCells&,
+            const labelList& pointToGlobal,
+            ensightGeoFile&
+        ) const;
+
+        void writeCellConnectivity
+        (
+            ensightCells::elemType elemType,
+            const ensightCells&,
+            const labelList& pointToGlobal,
+            ensightGeoFile&
+        ) const;
+
+        void writeFaceConnectivity
+        (
+            ensightFaces::elemType elemType,
+            const label nTotal,
+            const faceList& faceLst,
+            const labelList& addr,
+            ensightGeoFile&
+        ) const;
+
+
+        void writeFaceConnectivity
+        (
+            ensightFaces::elemType elemType,
+            const label nTotal,
+            const faceList& faceLst,
+            ensightGeoFile&
+        ) const;
+
+
+        void writeFaceConnectivity
+        (
+            const ensightFaces&,
+            const faceList& faceLst,
+            ensightGeoFile&,
+            const bool raw = false
+        ) const;
+
+
+        void writeAllPoints
+        (
+            const label partId,
+            const word& ensightPartName,
+            const label nTotal,
+            const pointField& uniquePoints,
+            ensightGeoFile&
+        ) const;
+
+
+        //- Disallow default bitwise copy construct
+        ensightMesh(const ensightMesh&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const ensightMesh&) = delete;
+
+
+public:
+
+    // Constructors
+
+        //- Construct from components
+        ensightMesh
+        (
+            const fvMesh& mesh,
+            const options& opts
+        );
+
+        //- Construct from fvMesh with all default options
+        ensightMesh
+        (
+            const fvMesh& mesh,
+            const IOstream::streamFormat format = IOstream::BINARY
+        );
+
+
+    //- Destructor
+    ~ensightMesh();
+
+
+    // Member Functions
+
+    // Access
+
+        //- Reference to the underlying fvMesh
+        inline const fvMesh& mesh() const;
+
+        //- Reference to the writer/mesh options
+        inline const ensightMesh::options& option() const;
+
+        //- Ascii/Binary file output
+        inline IOstream::streamFormat format() const;
+
+        //- Using internalMesh?
+        inline bool useInternalMesh() const;
+
+        //- Using deprecated order? (hex prism pyr tet poly)
+        inline bool deprecatedOrder() const;
+
+        //- The volume cells (internalMesh)
+        inline const ensightCells& meshCells() const;
+
+        //- The list of patches to be output
+        inline const Map<word>& patches() const;
+
+        //- Face elements per selected patch
+        inline const HashTable<ensightFaces>& boundaryPatchFaces() const;
+
+        //- Face elements per selected faceZone.
+        //  To be output in sorted order.
+        inline const HashTable<ensightFaces>& faceZoneFaces() const;
+
+
+    // Parallel point merging
+
+        //- Global numbering for merged points
+        const globalIndex& globalPoints() const
+        {
+            return globalPointsPtr_();
+        }
+
+        //- From mesh point to global merged point
+        const labelList& pointToGlobal() const
+        {
+            return pointToGlobal_;
+        }
+
+        //- Local points that are unique
+        const labelList& uniquePointMap() const
+        {
+            return uniquePointMap_;
+        }
+
+
+    // Other
+
+        //- Does the content need an update?
+        bool needsUpdate() const;
+
+        //- Mark as needing an update.
+        //  May also free up unneeded data.
+        //  Return false if already marked as expired.
+        bool expire();
+
+
+        //- Update for new mesh
+        void correct();
+
+
+    // I-O
+
+        //- Write to file
+        inline void write(autoPtr<ensightGeoFile>& os) const;
+
+        //- Write to file
+        void write(ensightGeoFile& os) const;
+
+};
+
+
+//- Configuration options for the ensightMesh
+class ensightMesh::options
+{
+    //- Ascii/Binary file output
+    IOstream::streamFormat format_;
+
+    //- Create in 'expired' mode
+    bool lazy_;
+
+    //- Suppress patches
+    bool noPatches_;
+
+    //- Using deprecated order (hex prism pyr tet poly)
+    bool deprecatedOrder_;
+
+    //- Output selected patches only
+    autoPtr<wordReList> patchPatterns_;
+
+    //- Output selected faceZones
+    autoPtr<wordReList> faceZonePatterns_;
+
+public:
+
+    // Constructors
+
+        //- Construct with the specified format (default is binary)
+        options(IOstream::streamFormat format = IOstream::BINARY);
+
+
+    // Member Functions
+
+    // Access
+
+        //- Ascii/Binary file output
+        IOstream::streamFormat format() const;
+
+        //- Lazy creation? (ie, ensightMesh starts as needsUpdate)
+        bool lazy() const;
+
+        //- Using internalMesh?
+        bool useInternalMesh() const;
+
+        //- Using deprecated order? (hex prism pyr tet poly)
+        bool deprecatedOrder() const;
+
+        //- Using patches?
+        bool usePatches() const;
+
+        //- Using faceZones?
+        bool useFaceZones() const;
+
+        //- Selection of patches in effect?
+        bool usePatchSelection() const;
+
+        //- Selection of patches - null reference if not available
+        const wordReList& patchSelection() const;
+
+        //- Selection of faceZones - null reference if not available
+        const wordReList& faceZoneSelection() const;
+
+
+    // Edit
+
+        //- Reset to defaults
+        void reset();
+
+        //- Lazy creation - ensightMesh starts as needsUpdate.
+        void lazy(const bool);
+
+        //- Alter deprecated order.
+        void deprecatedOrder(const bool);
+
+        //- Alter the patches/no-patches state
+        void noPatches(const bool);
+
+        //- Define patch selection matcher
+        void patchSelection(const wordReList&);
+
+        //- Define faceZone selection matcher
+        void faceZoneSelection(const wordReList&);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "ensightMeshI.H"
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/mesh/ensightMeshI.H b/src/conversion/ensight/mesh/ensightMeshI.H
new file mode 100644
index 0000000000000000000000000000000000000000..1f0bc4a14662b0eb75eb381e7d231e6ee763e1dd
--- /dev/null
+++ b/src/conversion/ensight/mesh/ensightMeshI.H
@@ -0,0 +1,90 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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/>.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+inline const Foam::fvMesh& Foam::ensightMesh::mesh() const
+{
+    return mesh_;
+}
+
+
+inline const Foam::ensightMesh::options& Foam::ensightMesh::option() const
+{
+    return *options_;
+}
+
+
+inline Foam::IOstream::streamFormat Foam::ensightMesh::format() const
+{
+    return options_->format();
+}
+
+
+inline bool Foam::ensightMesh::useInternalMesh() const
+{
+    return options_->useInternalMesh();
+}
+
+
+inline bool Foam::ensightMesh::deprecatedOrder() const
+{
+    return options_->deprecatedOrder();
+}
+
+
+inline const Foam::ensightCells& Foam::ensightMesh::meshCells() const
+{
+    return meshCells_;
+}
+
+
+inline const Foam::Map<Foam::word>& Foam::ensightMesh::patches() const
+{
+    return patchLookup_;
+}
+
+
+inline const Foam::HashTable<Foam::ensightFaces>&
+Foam::ensightMesh::boundaryPatchFaces() const
+{
+    return boundaryPatchFaces_;
+}
+
+
+inline const Foam::HashTable<Foam::ensightFaces>&
+Foam::ensightMesh::faceZoneFaces() const
+{
+    return faceZoneFaces_;
+}
+
+
+inline void Foam::ensightMesh::write(autoPtr<ensightGeoFile>& os) const
+{
+    write(os.rawRef());
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/mesh/ensightMeshIO.C b/src/conversion/ensight/mesh/ensightMeshIO.C
new file mode 100644
index 0000000000000000000000000000000000000000..406697d94296f5ea076f3edd14115c08d2891742
--- /dev/null
+++ b/src/conversion/ensight/mesh/ensightMeshIO.C
@@ -0,0 +1,698 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "ensightMesh.H"
+#include "fvMesh.H"
+#include "globalMeshData.H"
+#include "PstreamCombineReduceOps.H"
+#include "processorPolyPatch.H"
+#include "mapDistribute.H"
+#include "stringListOps.H"
+
+#include "ensightFile.H"
+#include "ensightGeoFile.H"
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+Foam::cellShapeList& Foam::ensightMesh::renumberShapes
+(
+    cellShapeList& shapes,
+    const labelUList& pointToGlobal
+)
+{
+    forAll(shapes, i)
+    {
+        inplaceRenumber(pointToGlobal, shapes[i]);
+    }
+
+    return shapes;
+}
+
+
+Foam::cellShapeList Foam::ensightMesh::map
+(
+    const cellShapeList& shapes,
+    const labelUList& addr,
+    const labelUList& pointToGlobal
+)
+{
+    cellShapeList lst(addr.size());
+
+    forAll(addr, i)
+    {
+        lst[i] = shapes[addr[i]];
+        inplaceRenumber(pointToGlobal, lst[i]);
+    }
+
+    return lst;
+}
+
+
+void Foam::ensightMesh::writeFaceList
+(
+    const faceList& faceLst,
+    ensightGeoFile& os
+)
+{
+    forAll(faceLst, i)
+    {
+        const face& f = faceLst[i];
+
+        forAll(f, fp)
+        {
+            os.write(f[fp] + 1);
+        }
+
+        os.newline();
+    }
+}
+
+
+void Foam::ensightMesh::writeFaceList
+(
+    const UIndirectList<face>& faceLst,
+    ensightGeoFile& os
+)
+{
+    forAll(faceLst, i)
+    {
+        const face& f = faceLst[i];
+
+        forAll(f, fp)
+        {
+            os.write(f[fp] + 1);
+        }
+
+        os.newline();
+    }
+}
+
+
+void Foam::ensightMesh::writeFaceSizes
+(
+    const faceList& faceLst,
+    ensightGeoFile& os
+)
+{
+    forAll(faceLst, i)
+    {
+        const face& f = faceLst[i];
+
+        os.write(f.size());
+    }
+}
+
+
+void Foam::ensightMesh::writeFaceSizes
+(
+    const UIndirectList<face>& faceLst,
+    ensightGeoFile& os
+)
+{
+    forAll(faceLst, i)
+    {
+        const face& f = faceLst[i];
+
+        os.write(f.size());
+    }
+}
+
+
+void Foam::ensightMesh::writeCellShapes
+(
+    const cellShapeList& shapes,
+    ensightGeoFile& os
+)
+{
+    forAll(shapes, i)
+    {
+        const cellShape& cellPoints = shapes[i];
+
+        // convert global -> local index
+        // (note: Ensight indices start with 1)
+
+        // In ASCII, write one cell per line
+        forAll(cellPoints, pointI)
+        {
+            os.write(cellPoints[pointI] + 1);
+        }
+
+        os.newline();
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::ensightMesh::writePolysNFaces
+(
+    const labelList& addr,
+    const cellList&  cellFaces,
+    ensightGeoFile& os
+) const
+{
+    forAll(addr, i)
+    {
+        const labelList& cf = cellFaces[addr[i]];
+        os.write(cf.size());
+    }
+}
+
+
+void Foam::ensightMesh::writePolysNPointsPerFace
+(
+    const labelList& addr,
+    const cellList& cellFaces,
+    const faceList& faces,
+    ensightGeoFile& os
+) const
+{
+    forAll(addr, i)
+    {
+        const labelList& cf = cellFaces[addr[i]];
+
+        forAll(cf, faceI)
+        {
+            os.write(faces[cf[faceI]].size());
+        }
+    }
+}
+
+
+void Foam::ensightMesh::writePolysPoints
+(
+    const labelList& addr,
+    const cellList& cellFaces,
+    const faceList& faces,
+    const labelList& faceOwner,
+    ensightGeoFile& os
+) const
+{
+    forAll(addr, i)
+    {
+        const label cellId = addr[i];
+        const labelList& cf = cellFaces[cellId];
+
+        forAll(cf, faceI)
+        {
+            const label faceId = cf[faceI];
+            const face& f = faces[faceId];  // face points (in global points)
+
+            if (faceId < faceOwner.size() && faceOwner[faceId] != cellId)
+            {
+                // internal face, neighbour
+                //
+                // as per face::reverseFace(), but without copying
+
+                os.write(f[0] + 1);
+                for (label ptI = f.size()-1; ptI > 0; --ptI)
+                {
+                    os.write(f[ptI] + 1);
+                }
+            }
+            else
+            {
+                forAll(f, ptI)
+                {
+                    os.write(f[ptI] + 1);
+                }
+            }
+
+            os.newline();
+        }
+    }
+}
+
+
+void Foam::ensightMesh::writePolysConnectivity
+(
+    const labelList& addr,
+    const labelList& pointToGlobal,
+    ensightGeoFile& os
+) const
+{
+    const cellList&  cellFaces = mesh_.cells();
+    const faceList&  meshFaces = mesh_.faces();
+    const labelList& faceOwner = mesh_.faceOwner();
+
+    if (Pstream::master())
+    {
+        // Number of faces for each poly cell
+
+        // Master
+        writePolysNFaces(addr, cellFaces, os);
+
+        // Slaves
+        for (int slave=1; slave<Pstream::nProcs(); ++slave)
+        {
+            IPstream fromSlave(Pstream::scheduled, slave);
+            labelList addr(fromSlave);
+            cellList  cellFaces(fromSlave);
+
+            writePolysNFaces(addr, cellFaces, os);
+        }
+    }
+    else
+    {
+        OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
+        toMaster
+            << addr
+            << cellFaces;
+    }
+
+    // Number of points for each face of the above list
+    if (Pstream::master())
+    {
+        // Master
+        writePolysNPointsPerFace
+        (
+            addr,
+            cellFaces,
+            meshFaces,
+            os
+        );
+        // Slaves
+        for (int slave=1; slave<Pstream::nProcs(); ++slave)
+        {
+            IPstream fromSlave(Pstream::scheduled, slave);
+            labelList addr(fromSlave);
+            cellList  cellFaces(fromSlave);
+            faceList  meshFaces(fromSlave);
+
+            writePolysNPointsPerFace
+            (
+                addr,
+                cellFaces,
+                meshFaces,
+                os
+            );
+        }
+    }
+    else
+    {
+        OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
+        toMaster
+            << addr
+            << cellFaces
+            << meshFaces;
+    }
+
+
+    // Renumber faces to use global point numbers
+    faceList faces(mesh_.faces());
+    forAll(faces, i)
+    {
+        inplaceRenumber(pointToGlobal, faces[i]);
+    }
+
+    // List of points id for each face of the above list
+    if (Pstream::master())
+    {
+        // Master
+        writePolysPoints
+        (
+            addr,
+            cellFaces,
+            faces,
+            faceOwner,
+            os
+        );
+        // Slaves
+        for (int slave=1; slave<Pstream::nProcs(); ++slave)
+        {
+            IPstream fromSlave(Pstream::scheduled, slave);
+            labelList addr(fromSlave);
+            cellList  cellFaces(fromSlave);
+            faceList  faces(fromSlave);
+            labelList faceOwner(fromSlave);
+
+            writePolysPoints
+            (
+                addr,
+                cellFaces,
+                faces,
+                faceOwner,
+                os
+            );
+        }
+    }
+    else
+    {
+        OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
+        toMaster
+            << addr
+            << cellFaces
+            << faces
+            << faceOwner;
+    }
+}
+
+
+void Foam::ensightMesh::writeCellConnectivity
+(
+    const ensightCells::elemType elemType,
+    const ensightCells& ensCells,
+    const labelList& pointToGlobal,
+    ensightGeoFile& os
+) const
+{
+    const label nTotal = ensCells.total(elemType);
+
+    if (nTotal)
+    {
+        const labelUList& addr = ensCells.cellIds(elemType);
+
+        if (Pstream::master())
+        {
+            os.writeKeyword(ensightCells::key(elemType));
+            os.write(nTotal);
+            os.newline();
+        }
+
+        if (elemType == ensightCells::NFACED)
+        {
+            writePolysConnectivity
+            (
+                addr,
+                pointToGlobal,
+                os
+            );
+        }
+        else
+        {
+            const cellShapeList shapes = map
+            (
+                mesh_.cellShapes(),
+                addr,
+                pointToGlobal
+            );
+
+
+            if (Pstream::master())
+            {
+                writeCellShapes(shapes, os);
+
+                for (int slave=1; slave<Pstream::nProcs(); ++slave)
+                {
+                    IPstream fromSlave(Pstream::scheduled, slave);
+                    cellShapeList received(fromSlave);
+
+                    writeCellShapes(received, os);
+                }
+            }
+            else
+            {
+                OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
+                toMaster
+                    << shapes;
+            }
+        }
+    }
+}
+
+
+void Foam::ensightMesh::writeCellConnectivity
+(
+    const ensightCells& ensCells,
+    const labelList& pointToGlobal,
+    ensightGeoFile& os
+) const
+{
+    if (deprecatedOrder())
+    {
+        // element ordering used in older versions
+        ensightCells::elemType oldOrder[5] =
+        {
+            ensightCells::HEXA8,
+            ensightCells::PENTA6,
+            ensightCells::PYRAMID5,
+            ensightCells::TETRA4,
+            ensightCells::NFACED
+        };
+
+        for (int i=0; i < 5; ++i)
+        {
+            const ensightCells::elemType& what = oldOrder[i];
+
+            writeCellConnectivity(what, ensCells, pointToGlobal, os);
+        }
+    }
+    else
+    {
+        const List<ensightCells::elemType> enums =
+            ensightCells::elemEnum.enums();
+
+        forAllConstIter(List<ensightCells::elemType>, enums, iter)
+        {
+            const ensightCells::elemType what = *iter;
+
+            writeCellConnectivity(what, ensCells, pointToGlobal, os);
+        }
+    }
+}
+
+
+void Foam::ensightMesh::writeFaceConnectivity
+(
+    ensightFaces::elemType elemType,
+    const label nTotal,
+    const faceList& faces,
+    ensightGeoFile& os
+) const
+{
+    if (nTotal)
+    {
+        if (Pstream::master())
+        {
+            os.writeKeyword(ensightFaces::key(elemType));
+            os.write(nTotal);
+            os.newline();
+        }
+
+        if (elemType == ensightFaces::NSIDED)
+        {
+            // Number of points per face
+
+            if (Pstream::master())
+            {
+                writeFaceSizes(faces, os);
+
+                for (int slave=1; slave<Pstream::nProcs(); ++slave)
+                {
+                    IPstream fromSlave(Pstream::scheduled, slave);
+                    faceList received(fromSlave);
+
+                    writeFaceSizes(received, os);
+                }
+            }
+            else
+            {
+                OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
+                toMaster
+                    << faces;
+            }
+        }
+
+
+        // List of points id for each face
+        if (Pstream::master())
+        {
+            writeFaceList(faces, os);
+
+            for (int slave=1; slave<Pstream::nProcs(); ++slave)
+            {
+                IPstream fromSlave(Pstream::scheduled, slave);
+                faceList received(fromSlave);
+
+                writeFaceList(received, os);
+            }
+        }
+        else
+        {
+            OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
+            toMaster
+                << faces;
+        }
+    }
+}
+
+
+void Foam::ensightMesh::writeFaceConnectivity
+(
+    ensightFaces::elemType elemType,
+    const label nTotal,
+    const faceList& faceLst,
+    const labelList& addr,
+    ensightGeoFile& os
+) const
+{
+    if (nTotal)
+    {
+        if (Pstream::master())
+        {
+            os.writeKeyword(ensightFaces::key(elemType));
+            os.write(nTotal);
+            os.newline();
+        }
+
+        const UIndirectList<face> faces(faceLst, addr);
+
+        if (elemType == ensightFaces::NSIDED)
+        {
+            // Number of points per face
+
+            if (Pstream::master())
+            {
+                writeFaceSizes(faces, os);
+
+                for (int slave=1; slave<Pstream::nProcs(); ++slave)
+                {
+                    IPstream fromSlave(Pstream::scheduled, slave);
+                    faceList received(fromSlave);
+
+                    writeFaceSizes(received, os);
+                }
+            }
+            else
+            {
+                OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
+                toMaster
+                    << faces;
+            }
+        }
+
+        // List of points id per face
+        if (Pstream::master())
+        {
+            writeFaceList(faces, os);
+
+            for (int slave=1; slave<Pstream::nProcs(); ++slave)
+            {
+                IPstream fromSlave(Pstream::scheduled, slave);
+                faceList received(fromSlave);
+
+                writeFaceList(received, os);
+            }
+        }
+        else
+        {
+            OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
+            toMaster
+                << faces;
+        }
+    }
+}
+
+
+void Foam::ensightMesh::writeFaceConnectivity
+(
+    const ensightFaces& ensFaces,
+    const faceList& faceLst,
+    ensightGeoFile& os,
+    const bool raw
+) const
+{
+    const List<ensightFaces::elemType> enums = ensightFaces::elemEnum.enums();
+
+    if (raw)
+    {
+        forAllConstIter(List<ensightFaces::elemType>, enums, iter)
+        {
+            const ensightFaces::elemType what = *iter;
+
+            writeFaceConnectivity
+            (
+                what,
+                ensFaces.total(what),
+                SubList<face>
+                (
+                    faceLst,
+                    ensFaces.faceIds(what).size(),
+                    ensFaces.offset(what)
+                ),
+                os
+            );
+        }
+    }
+    else
+    {
+        forAllConstIter(List<ensightFaces::elemType>, enums, iter)
+        {
+            const ensightFaces::elemType what = *iter;
+
+            writeFaceConnectivity
+            (
+                what,
+                ensFaces.total(what),
+                faceLst,
+                ensFaces.faceIds(what),
+                os
+            );
+        }
+    }
+}
+
+
+void Foam::ensightMesh::writeAllPoints
+(
+    const label partId,
+    const word& ensightPartName,
+    const label nPoints,
+    const pointField& uniquePoints,
+    ensightGeoFile& os
+) const
+{
+    if (Pstream::master())
+    {
+        os.beginPart(partId, ensightPartName);
+
+        // write points
+        os.beginCoordinates(nPoints);
+
+        for (direction cmpt=0; cmpt < point::nComponents; ++cmpt)
+        {
+            os.writeList(uniquePoints.component(cmpt));
+
+            for (int slave=1; slave<Pstream::nProcs(); ++slave)
+            {
+                IPstream fromSlave(Pstream::scheduled, slave);
+                scalarField received(fromSlave);
+                os.writeList(received);
+            }
+        }
+    }
+    else
+    {
+        for (direction cmpt=0; cmpt < point::nComponents; ++cmpt)
+        {
+            OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
+            toMaster
+                << uniquePoints.component(cmpt);
+        }
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/mesh/ensightMeshOptions.C b/src/conversion/ensight/mesh/ensightMeshOptions.C
new file mode 100644
index 0000000000000000000000000000000000000000..ea89d43993999898820409389742f57eace694c6
--- /dev/null
+++ b/src/conversion/ensight/mesh/ensightMeshOptions.C
@@ -0,0 +1,174 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "ensightMesh.H"
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::ensightMesh::options::options(IOstream::streamFormat format)
+:
+    format_(format),
+    lazy_(false),
+    noPatches_(false),
+    deprecatedOrder_(false),
+    patchPatterns_(),
+    faceZonePatterns_()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::IOstream::streamFormat Foam::ensightMesh::options::format() const
+{
+    return format_;
+}
+
+
+bool Foam::ensightMesh::options::lazy() const
+{
+    return lazy_;
+}
+
+
+bool Foam::ensightMesh::options::useInternalMesh() const
+{
+    return noPatches_ ? true : !patchPatterns_.valid();
+}
+
+
+bool Foam::ensightMesh::options::deprecatedOrder() const
+{
+    return deprecatedOrder_;
+}
+
+
+bool Foam::ensightMesh::options::usePatches() const
+{
+    return !noPatches_;
+}
+
+
+bool Foam::ensightMesh::options::useFaceZones() const
+{
+    return faceZonePatterns_.valid();
+}
+
+
+bool Foam::ensightMesh::options::usePatchSelection() const
+{
+    return noPatches_ ? false : patchPatterns_.valid();
+}
+
+
+void Foam::ensightMesh::options::reset()
+{
+    noPatches_ = false;
+    patchPatterns_.clear();
+    faceZonePatterns_.clear();
+}
+
+
+void Foam::ensightMesh::options::lazy(const bool b)
+{
+    lazy_ = b;
+}
+
+
+void Foam::ensightMesh::options::deprecatedOrder(const bool b)
+{
+    deprecatedOrder_ = b;
+}
+
+
+void Foam::ensightMesh::options::noPatches(const bool b)
+{
+    noPatches_ = b;
+
+    if (noPatches_ && patchPatterns_.valid())
+    {
+        WarningInFunction
+            << " existing patch selection disabled"
+            << endl;
+
+        patchPatterns_.clear();
+    }
+}
+
+
+void Foam::ensightMesh::options::patchSelection
+(
+    const wordReList& patterns
+)
+{
+    if (noPatches_)
+    {
+        WarningInFunction
+            << " patch selection specified, but noPatches was already active"
+            << endl;
+    }
+    else
+    {
+        patchPatterns_.reset(new wordReList(patterns));
+    }
+}
+
+
+void Foam::ensightMesh::options::faceZoneSelection
+(
+    const wordReList& patterns
+)
+{
+    faceZonePatterns_.reset(new wordReList(patterns));
+}
+
+
+const Foam::wordReList& Foam::ensightMesh::options::patchSelection() const
+{
+    if (usePatchSelection())
+    {
+        return patchPatterns_();
+    }
+    else
+    {
+        return wordReList::null();
+    }
+}
+
+
+const Foam::wordReList& Foam::ensightMesh::options::faceZoneSelection() const
+{
+    if (faceZonePatterns_.valid())
+    {
+        return faceZonePatterns_();
+    }
+    else
+    {
+        return wordReList::null();
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/output/ensightOutput.H b/src/conversion/ensight/output/ensightOutput.H
new file mode 100644
index 0000000000000000000000000000000000000000..5fec26bbf8c35c1c804070522fe3dc14b296bb45
--- /dev/null
+++ b/src/conversion/ensight/output/ensightOutput.H
@@ -0,0 +1,151 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::ensightOutput
+
+Description
+    A collection of functions for writing ensight file content in parallel.
+
+SourceFiles
+    ensightOutput.C
+    ensightOutputTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ensightOutput_H
+#define ensightOutput_H
+
+#include "ensightFile.H"
+#include "ensightMesh.H"
+#include "autoPtr.H"
+#include "volFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class ensightOutput Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightOutput
+{
+    // Private Methods
+
+    template<class Type>
+    static void writeField
+    (
+        const char* key,
+        const Field<Type>& fld,
+        ensightFile& os
+    );
+
+    template<class Type>
+    static bool writePatchField
+    (
+        const Field<Type>& pf,
+        const ensightFaces& ensFaces,
+        ensightFile& os
+    );
+
+    template<class Type>
+    static bool writeVolField
+    (
+        const Field<Type>& vf,
+        const ensightCells& ensCells,
+        ensightFile& os,
+        const bool deprecatedOrder = false
+    );
+
+
+    //- Write volume field component-wise
+    template<class Type>
+    static bool writeField
+    (
+        const GeometricField<Type, fvPatchField, volMesh>& vf,
+        const ensightMesh& ensMesh,
+        ensightFile& os
+    );
+
+    //- Write point field component-wise
+    template<class Type>
+    static bool ensightPointField
+    (
+        const GeometricField<Type, pointPatchField, pointMesh>& pf,
+        const ensightMesh& ensMesh,
+        ensightFile& os
+    );
+
+
+    //- Disallow null constructor
+    ensightOutput() = delete;
+
+public:
+
+    // Public Methods
+
+
+    //- Write volume field component-wise
+    template<class Type>
+    static bool writeField
+    (
+        const GeometricField<Type, fvPatchField, volMesh>&,
+        const ensightMesh& ensMesh,
+        ensightFile& os,
+        const bool nodeValues
+    );
+
+
+    //- Write volume field component-wise
+    template<class Type>
+    static inline bool writeField
+    (
+        const GeometricField<Type, fvPatchField, volMesh>& vf,
+        const ensightMesh& ensMesh,
+        autoPtr<ensightFile>& output,
+        const bool nodeValues = false
+    )
+    {
+        return writeField(vf, ensMesh, output.rawRef(), nodeValues);
+    }
+
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "ensightOutputTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/output/ensightOutputTemplates.C b/src/conversion/ensight/output/ensightOutputTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..a68058faf76a904ca823a167a091752c49f9e05d
--- /dev/null
+++ b/src/conversion/ensight/output/ensightOutputTemplates.C
@@ -0,0 +1,461 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "ensightFile.H"
+#include "ensightOutput.H"
+#include "ensightPTraits.H"
+
+#include "fvMesh.H"
+#include "volFields.H"
+#include "IOField.H"
+#include "OFstream.H"
+#include "IOmanip.H"
+#include "Time.H"
+#include "volPointInterpolation.H"
+#include "globalIndex.H"
+#include "uindirectPrimitivePatch.H"
+#include "interpolation.H"
+#include "linear.H"
+
+// * * * * * * * * * * Static Private Member Functions * * * * * * * * * * * //
+
+template<class Type>
+void Foam::ensightOutput::writeField
+(
+    const char* key,
+    const Field<Type>& fld,
+    ensightFile& os
+)
+{
+    if (returnReduce(fld.size(), sumOp<label>()) > 0)
+    {
+        if (Pstream::master())
+        {
+            os.writeKeyword(key);
+
+            for (direction d=0; d < pTraits<Type>::nComponents; ++d)
+            {
+                const label cmpt = ensightPTraits<Type>::componentOrder[d];
+
+                os.writeList(fld.component(cmpt));
+
+                for (int slave=1; slave<Pstream::nProcs(); ++slave)
+                {
+                    IPstream fromSlave(Pstream::scheduled, slave);
+                    scalarField received(fromSlave);
+                    os.writeList(received);
+                }
+            }
+        }
+        else
+        {
+            for (direction d=0; d < pTraits<Type>::nComponents; ++d)
+            {
+                const label cmpt = ensightPTraits<Type>::componentOrder[d];
+
+                OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
+                toMaster
+                    << fld.component(cmpt);
+            }
+        }
+    }
+}
+
+
+template<class Type>
+bool Foam::ensightOutput::writePatchField
+(
+    const Field<Type>& pf,
+    const ensightFaces& ensFaces,
+    Foam::ensightFile& os
+)
+{
+    if (ensFaces.total())
+    {
+        if (Pstream::master())
+        {
+            os.beginPart(ensFaces.index());
+        }
+
+        const List<ensightFaces::elemType> enums =
+            ensightFaces::elemEnum.enums();
+
+        forAllConstIter(List<ensightFaces::elemType>, enums, iter)
+        {
+            const ensightFaces::elemType& what = *iter;
+
+            writeField
+            (
+                ensightFaces::key(what),
+                Field<Type>(pf, ensFaces.faceIds(what)),
+                os
+            );
+        }
+
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+
+template<class Type>
+bool Foam::ensightOutput::writeVolField
+(
+    const Field<Type>& vf,
+    const ensightCells& ensCells,
+    ensightFile& os,
+    const bool deprecatedOrder
+)
+{
+    if (ensCells.total())
+    {
+        if (Pstream::master())
+        {
+            os.beginPart(ensCells.index());
+        }
+
+        if (deprecatedOrder)
+        {
+            // element ordering used in older versions
+            ensightCells::elemType oldOrder[5] =
+            {
+                ensightCells::HEXA8,
+                ensightCells::PENTA6,
+                ensightCells::PYRAMID5,
+                ensightCells::TETRA4,
+                ensightCells::NFACED
+            };
+
+            for (int i=0; i < 5; ++i)
+            {
+                const ensightCells::elemType& what = oldOrder[i];
+
+                writeField
+                (
+                    ensightCells::key(what),
+                    Field<Type>(vf, ensCells.cellIds(what)),
+                    os
+                );
+            }
+        }
+        else
+        {
+            const List<ensightCells::elemType> enums =
+                ensightCells::elemEnum.enums();
+
+            forAllConstIter(List<ensightCells::elemType>, enums, iter)
+            {
+                const ensightCells::elemType& what = *iter;
+
+                writeField
+                (
+                    ensightCells::key(what),
+                    Field<Type>(vf, ensCells.cellIds(what)),
+                    os
+                );
+            }
+        }
+
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+
+template<class Type>
+bool Foam::ensightOutput::writeField
+(
+    const GeometricField<Type, fvPatchField, volMesh>& vf,
+    const ensightMesh& ensMesh,
+    ensightFile& os
+)
+{
+    const fvMesh& mesh = ensMesh.mesh();
+    const ensightCells& meshCells = ensMesh.meshCells();
+    const Map<word>&  patchLookup = ensMesh.patches();
+    const HashTable<ensightFaces>& patchFaces = ensMesh.boundaryPatchFaces();
+    const HashTable<ensightFaces>&  zoneFaces = ensMesh.faceZoneFaces();
+
+    //
+    // write internalMesh, unless patch-selection was requested
+    //
+    if (ensMesh.useInternalMesh())
+    {
+        writeVolField(vf, meshCells, os, ensMesh.deprecatedOrder());
+    }
+
+    //
+    // write patches
+    // use sortedToc for extra safety
+    //
+    const labelList patchIds = patchLookup.sortedToc();
+    forAll(patchIds, listi)
+    {
+        const label patchId   = patchIds[listi];
+        const word& patchName = patchLookup[listi];
+        const ensightFaces& ensFaces = patchFaces[patchName];
+
+        writePatchField
+        (
+            vf.boundaryField()[patchId],
+            ensFaces,
+            os
+        );
+    }
+
+
+    //
+    // write faceZones, if requested
+    // use sortedToc for extra safety
+    //
+    const wordList zoneNames = zoneFaces.sortedToc();
+    if (!zoneNames.empty())
+    {
+        // Interpolates cell values to faces - needed only when exporting
+        // faceZones...
+        GeometricField<Type, fvsPatchField, surfaceMesh> sf
+        (
+            Foam::linearInterpolate(vf)
+        );
+
+        // flat boundary field
+        // as per volPointInterpolation::flatBoundaryField()
+
+        Field<Type> flat(mesh.nFaces() - mesh.nInternalFaces());
+
+        const fvBoundaryMesh& bm = mesh.boundary();
+        forAll(vf.boundaryField(), patchI)
+        {
+            const polyPatch& pp = bm[patchI].patch();
+            const label bFaceI = pp.start() - mesh.nInternalFaces();
+
+            if
+            (
+                isA<emptyFvPatch>(bm[patchI])
+             || vf.boundaryField()[patchI].coupled()
+            )
+            {
+                SubList<Type>
+                (
+                    flat,
+                    pp.size(),
+                    bFaceI
+                ) = Zero;
+            }
+            else
+            {
+                SubList<Type>
+                (
+                    flat,
+                    vf.boundaryField()[patchI].size(),
+                    bFaceI
+                ) = vf.boundaryField()[patchI];
+            }
+        }
+
+        forAll(zoneNames, zonei)
+        {
+            const word& zoneName = zoneNames[zonei];
+            const ensightFaces& ensFaces = zoneFaces[zoneName];
+
+            // field (local size)
+            Field<Type> values(ensFaces.size());
+
+            // Loop over face ids to store the needed field values
+            // - internal faces use linear interpolation
+            // - boundary faces use the corresponding patch value
+            forAll(ensFaces, i)
+            {
+                label faceId = ensFaces[i];
+                values[i] =
+                (
+                    mesh.isInternalFace(faceId)
+                  ? sf[faceId]
+                  : flat[faceId - mesh.nInternalFaces()]
+                );
+            }
+
+            writePatchField(values, ensFaces, os);
+        }
+    }
+
+    return true;
+}
+
+
+template<class Type>
+bool Foam::ensightOutput::ensightPointField
+(
+    const GeometricField<Type, pointPatchField, pointMesh>& pf,
+    const ensightMesh& ensMesh,
+    ensightFile& os
+)
+{
+    const fvMesh& mesh = ensMesh.mesh();
+    const Map<word>& patchLookup  = ensMesh.patches();
+
+    const HashTable<ensightFaces>& patchFaces = ensMesh.boundaryPatchFaces();
+    const HashTable<ensightFaces>&  zoneFaces = ensMesh.faceZoneFaces();
+
+    //
+    // write internalMesh, unless patch-selection was requested
+    //
+    if (ensMesh.useInternalMesh())
+    {
+        if (Pstream::master())
+        {
+            os.beginPart(0); // 0 = internalMesh
+        }
+
+        writeField
+        (
+            "coordinates",
+            Field<Type>(pf.internalField(), ensMesh.uniquePointMap()),
+            os
+        );
+    }
+
+    //
+    // write patches
+    // use sortedToc for extra safety
+    //
+    const labelList patchIds = patchLookup.sortedToc();
+    forAll(patchIds, listi)
+    {
+        const label patchId   = patchIds[listi];
+        const word& patchName = patchLookup[patchId];
+        const ensightFaces& ensFaces = patchFaces[patchName];
+
+        const fvPatch& p = mesh.boundary()[patchId];
+
+        // Renumber the patch points/faces into unique points
+        labelList pointToGlobal;
+        labelList uniqueMeshPointLabels;
+        autoPtr<globalIndex> globalPointsPtr =
+            mesh.globalData().mergePoints
+            (
+                p.patch().meshPoints(),
+                p.patch().meshPointMap(),
+                pointToGlobal,
+                uniqueMeshPointLabels
+            );
+
+        if (Pstream::master())
+        {
+            os.beginPart(ensFaces.index());
+        }
+
+        writeField
+        (
+            "coordinates",
+            Field<Type>(pf.internalField(), uniqueMeshPointLabels),
+            os
+        );
+    }
+
+    //
+    // write faceZones, if requested
+    //
+    const wordList zoneNames = zoneFaces.sortedToc();
+    forAll(zoneNames, zonei)
+    {
+        const word& zoneName = zoneNames[zonei];
+        const ensightFaces& ensFaces = zoneFaces[zoneName];
+
+        uindirectPrimitivePatch p
+        (
+            UIndirectList<face>
+            (
+                mesh.faces(),
+                ensFaces.faceIds()
+            ),
+            mesh.points()
+        );
+
+        // Renumber the patch points/faces into unique points
+        labelList pointToGlobal;
+        labelList uniqueMeshPointLabels;
+        autoPtr<globalIndex> globalPointsPtr =
+            mesh.globalData().mergePoints
+            (
+                p.meshPoints(),
+                p.meshPointMap(),
+                pointToGlobal,
+                uniqueMeshPointLabels
+            );
+
+        if (Pstream::master())
+        {
+            os.beginPart(ensFaces.index());
+        }
+
+        writeField
+        (
+            "coordinates",
+            Field<Type>(pf.internalField(), uniqueMeshPointLabels),
+            os
+        );
+    }
+
+    return true;
+}
+
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+template<class Type>
+bool Foam::ensightOutput::writeField
+(
+    const GeometricField<Type, fvPatchField, volMesh>& vf,
+    const ensightMesh& ensMesh,
+    ensightFile& os,
+    const bool nodeValues
+)
+{
+    if (nodeValues)
+    {
+        tmp<GeometricField<Type, pointPatchField, pointMesh>> pfld
+        (
+            volPointInterpolation::New(vf.mesh()).interpolate(vf)
+        );
+        pfld.ref().checkOut();
+        pfld.ref().rename(vf.name());
+
+        return ensightPointField<Type>(pfld, ensMesh, os);
+    }
+    else
+    {
+        return writeField<Type>(vf, ensMesh, os);
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/output/ensightSerialOutput.H b/src/conversion/ensight/output/ensightSerialOutput.H
new file mode 100644
index 0000000000000000000000000000000000000000..8fcbc3025fe6fd0370e03a9762121ad7744e39e8
--- /dev/null
+++ b/src/conversion/ensight/output/ensightSerialOutput.H
@@ -0,0 +1,146 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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/>.
+
+Class
+    Foam::ensightSerialOutput
+
+Description
+    A collection of functions for writing ensight file content in serial.
+    Can be considered transitional and may eventually merge with ensightOutput.
+
+SourceFiles
+    ensightSerialOutputTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ensightSerialOutput_H
+#define ensightSerialOutput_H
+
+#include "ensightPart.H"
+#include "ensightPartFaces.H"
+#include "ensightPartCells.H"
+#include "ensightParts.H"
+#include "volFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                     Class ensightSerialOutput Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightSerialOutput
+{
+    // Private Methods
+
+    //- Write field component-wise
+    template<class Type>
+    static void writeField
+    (
+        const word& key,
+        const Field<Type>& field,
+        ensightFile& os
+    );
+
+
+    //- Disallow null constructor
+    ensightSerialOutput() = delete;
+
+public:
+
+    // Public Methods
+
+    //- Write field component-wise
+    template<class Type>
+    static bool writeField
+    (
+        const Field<Type>&,
+        const ensightPartFaces& part,
+        ensightFile& os,
+        const bool nodeValues
+    );
+
+
+    //- Write volume field component-wise
+    template<class Type>
+    static bool writeField
+    (
+        const GeometricField<Type, fvPatchField, volMesh>&,
+        const ensightPartCells& part,
+        ensightFile& os
+    );
+
+
+    //- Write volume field component-wise
+    template<class Type>
+    static bool writeField
+    (
+        const GeometricField<Type, fvPatchField, volMesh>&,
+        const ensightParts& list,
+        ensightFile& os
+    );
+
+
+    //- Write volume field component-wise
+    template<class Type>
+    static inline bool writeField
+    (
+        const GeometricField<Type, fvPatchField, volMesh>& vf,
+        const ensightPartCells& part,
+        autoPtr<ensightFile>& output
+    )
+    {
+        return writeField(vf, part, output.rawRef());
+    }
+
+
+    //- Write volume field component-wise
+    template<class Type>
+    static inline bool writeField
+    (
+        const GeometricField<Type, fvPatchField, volMesh>& vf,
+        const ensightParts& list,
+        autoPtr<ensightFile>& output
+    )
+    {
+        return writeField(vf, list, output.rawRef());
+    }
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "ensightSerialOutputTemplates.C"
+#endif
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/output/ensightSerialOutputTemplates.C b/src/conversion/ensight/output/ensightSerialOutputTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..31f4ad9370d9669bbd9a2ba4a8d1a576912671dc
--- /dev/null
+++ b/src/conversion/ensight/output/ensightSerialOutputTemplates.C
@@ -0,0 +1,178 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "ensightPart.H"
+#include "ensightParts.H"
+#include "ensightPTraits.H"
+#include "direction.H"
+#include "typeInfo.H"
+
+// * * * * * * * * * * Static Private Member Functions * * * * * * * * * * * //
+
+template<class Type>
+void Foam::ensightSerialOutput::writeField
+(
+    const word& key,
+    const Field<Type>& fld,
+    ensightFile& os
+)
+{
+    if (fld.size())
+    {
+        os.writeKeyword(key);
+
+        for (direction d=0; d < pTraits<Type>::nComponents; ++d)
+        {
+            const label cmpt = ensightPTraits<Type>::componentOrder[d];
+
+            os.writeList(fld.component(cmpt));
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+template<class Type>
+bool Foam::ensightSerialOutput::writeField
+(
+    const Field<Type>& fld,
+    const ensightPartFaces& part,
+    ensightFile& os,
+    const bool nodeValues
+)
+{
+    if (part.size() && fld.size())
+    {
+        if (nodeValues)
+        {
+            os.beginPart(part.index());
+
+            os.writeKeyword("coordinates");
+            for (direction d=0; d < pTraits<Type>::nComponents; ++d)
+            {
+                const label cmpt = ensightPTraits<Type>::componentOrder[d];
+
+                os.writeList(fld.component(cmpt));
+            }
+        }
+        else
+        {
+            os.beginPart(part.index());
+
+            const List<ensightFaces::elemType> enums =
+                ensightFaces::elemEnum.enums();
+
+            forAllConstIter(List<ensightFaces::elemType>, enums, iter)
+            {
+                const ensightFaces::elemType what = *iter;
+
+                writeField
+                (
+                    ensightFaces::key(what),
+                    Field<Type>(fld, part.faceIds(what)),
+                    os
+                );
+            }
+        }
+    }
+
+    return true;
+}
+
+
+template<class Type>
+bool Foam::ensightSerialOutput::writeField
+(
+    const GeometricField<Type, fvPatchField, volMesh>& fld,
+    const ensightPartCells& part,
+    ensightFile& os
+)
+{
+    if (part.size() && fld.size())
+    {
+        os.beginPart(part.index());
+
+        const List<ensightCells::elemType> enums =
+            ensightCells::elemEnum.enums();
+
+        forAllConstIter(List<ensightCells::elemType>, enums, iter)
+        {
+            const ensightCells::elemType what = *iter;
+
+            writeField
+            (
+                ensightCells::key(what),
+                Field<Type>(fld, part.cellIds(what)),
+                os
+            );
+        }
+    }
+
+    return true;
+}
+
+
+template<class Type>
+bool Foam::ensightSerialOutput::writeField
+(
+    const GeometricField<Type, fvPatchField, volMesh>& vf,
+    const ensightParts& list,
+    ensightFile& os
+)
+{
+    forAllConstIter(ensightParts::StorageType, list, iter)
+    {
+        if (isA<ensightPartFaces>(*iter))
+        {
+            const ensightPartFaces& part =
+                dynamicCast<const ensightPartFaces&>(*iter);
+
+            const label patchi = part.patchIndex();
+            if (patchi >= 0 && patchi < vf.boundaryField().size())
+            {
+                writeField
+                (
+                    vf.boundaryField()[patchi],
+                    part,
+                    os,
+                    false
+                );
+            }
+        }
+        else
+        {
+            const ensightPartCells& part =
+                dynamicCast<const ensightPartCells&>(*iter);
+
+            writeField(vf, part, os);
+        }
+    }
+
+    return true;
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightPart.C b/src/conversion/ensight/part/ensightPart.C
index d06c64e55964eb192ccdeabee6651f721830aef1..2e7fc02c233ebc38e215fe03a246fb56a8c8f139 100644
--- a/src/conversion/ensight/part/ensightPart.C
+++ b/src/conversion/ensight/part/ensightPart.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.
@@ -24,164 +24,63 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "ensightPart.H"
-#include "dictionary.H"
-#include "ListOps.H"
-#include "addToRunTimeSelectionTable.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
 namespace Foam
 {
     defineTypeNameAndDebug(ensightPart, 0);
-    defineTemplateTypeNameAndDebug(IOPtrList<ensightPart>, 0);
-    defineRunTimeSelectionTable(ensightPart, istream);
 }
 
-const Foam::List<Foam::word> Foam::ensightPart::elemTypes_(0);
-
 
 // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
 
-bool Foam::ensightPart::isFieldDefined(const List<scalar>& field) const
+// TODO - move elsewhere
+#if 0
+bool Foam::ensightPart::isFieldDefined
+(
+    const List<scalar>& field
+    // const labelUList& addr = cellIds() or faceIds()
+) const
 {
-    forAll(elemLists_, elemI)
+    forAll(addr, elemI)
     {
-        const labelUList& idList = elemLists_[elemI];
+        const label id = addr[i];
 
-        forAll(idList, i)
+        if (id >= field.size() || std::isnan(field[id]))
         {
-            const label id = idList[i];
-
-            if (id >= field.size() || std::isnan(field[id]))
-            {
-                return false;
-            }
+            return false;
         }
     }
     return true;
 }
+#endif
 
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::ensightPart::ensightPart
-()
+Foam::ensightPart::ensightPart(const string& description)
 :
-    number_(0),
-    name_(""),
-    elemLists_(0),
-    offset_(0),
-    size_(0),
-    isCellData_(true),
-    matId_(0),
-    points_(pointField::null())
+    name_(description)
 {}
 
 
-Foam::ensightPart::ensightPart
-(
-    label partNumber,
-    const string& partDescription
-)
-:
-    number_(partNumber),
-    name_(partDescription),
-    elemLists_(0),
-    offset_(0),
-    size_(0),
-    isCellData_(true),
-    matId_(0),
-    points_(pointField::null())
-{}
-
-
-Foam::ensightPart::ensightPart
-(
-    label partNumber,
-    const string& partDescription,
-    const pointField& points
-)
-:
-    number_(partNumber),
-    name_(partDescription),
-    elemLists_(0),
-    offset_(0),
-    size_(0),
-    isCellData_(true),
-    matId_(0),
-    points_(points)
-{}
-
-
-Foam::ensightPart::ensightPart(const ensightPart& part)
-:
-    number_(part.number_),
-    name_(part.name_),
-    elemLists_(part.elemLists_),
-    offset_(part.offset_),
-    size_(part.size_),
-    isCellData_(part.isCellData_),
-    matId_(part.matId_),
-    points_(part.points_)
-{}
-
-
-// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
-
-Foam::autoPtr<Foam::ensightPart> Foam::ensightPart::New(Istream& is)
-{
-    const word partType(is);
-
-    istreamConstructorTable::iterator cstrIter =
-        istreamConstructorTablePtr_->find(partType);
-
-    if (cstrIter == istreamConstructorTablePtr_->end())
-    {
-        FatalIOErrorInFunction
-        (
-            is
-        )   << "unknown ensightPart type "
-            << partType << nl << nl
-            << "Valid ensightPart types are :" << endl
-            << istreamConstructorTablePtr_->sortedToc()
-            << exit(FatalIOError);
-    }
-
-    return autoPtr<ensightPart>(cstrIter()(is));
-}
-
-
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 Foam::ensightPart::~ensightPart()
 {}
 
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
 
-void Foam::ensightPart::renumber(const labelUList& origId)
+Foam::ensightGeoFile& Foam::operator<<
+(
+    ensightGeoFile& os,
+    const ensightPart& part
+)
 {
-    // transform to global values first
-    if (offset_)
-    {
-        forAll(elemLists_, elemI)
-        {
-            labelList& idList = elemLists_[elemI];
-            forAll(idList, i)
-            {
-                idList[i] += offset_;
-            }
-        }
-
-        offset_ = 0;
-    }
-
-    if (origId.size())
-    {
-        forAll(elemLists_, elemI)
-        {
-            inplaceRenumber(origId, elemLists_[elemI]);
-        }
-    }
+    part.write(os);
+    return os;
 }
 
 
diff --git a/src/conversion/ensight/part/ensightPart.H b/src/conversion/ensight/part/ensightPart.H
index 170b0e763d2c9fc22c06d71fa1c71ed92f89932f..0a7f8d2679936ec11990deacfcb50d3fe771ebda 100644
--- a/src/conversion/ensight/part/ensightPart.H
+++ b/src/conversion/ensight/part/ensightPart.H
@@ -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.
@@ -29,21 +29,17 @@ Description
 
 SourceFiles
     ensightPart.C
-    ensightPartIO.C
-    ensightPartTemplates.C
 
 \*---------------------------------------------------------------------------*/
 
 #ifndef ensightPart_H
 #define ensightPart_H
 
-#include "ensightFile.H"
 #include "ensightGeoFile.H"
 #include "typeInfo.H"
 #include "labelList.H"
 #include "polyMesh.H"
 #include "Field.H"
-#include "IOPtrList.H"
 #include "IOstream.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -54,8 +50,6 @@ namespace Foam
 // Forward declaration of friend functions and operators
 
 class ensightPart;
-
-Ostream& operator<<(Ostream&, const ensightPart&);
 ensightGeoFile& operator<<(ensightGeoFile&, const ensightPart&);
 
 
@@ -65,40 +59,22 @@ ensightGeoFile& operator<<(ensightGeoFile&, const ensightPart&);
 
 class ensightPart
 {
-    // Private data
-
-        // Static data members
-        static const List<word> elemTypes_;
-
-
-protected:
-
-    // Protected data
-
-        //- Part number
-        label number_;
+    // Private Data
 
         //- Part name (or description)
         string name_;
 
-        //- Simple labelList with a name
-        labelListList elemLists_;
 
-        //- Start offset for elemLists_
-        label offset_;
+    // Private Member Functions
 
-        //- Number of elements in this part
-        label size_;
+        //- Disallow default bitwise copy construct
+        ensightPart(const ensightPart&) = delete;
 
-        //- Cell or face data
-        bool isCellData_;
-
-        //- Material id (numeric)
-        label matId_;
+        //- Disallow default bitwise assignment
+        void operator=(const ensightPart&) = delete;
 
-        //- pointField referenced
-        const pointField& points_;
 
+protected:
 
     // Protected Classes
 
@@ -127,46 +103,6 @@ protected:
             {}
         };
 
-
-    // Protected Member Functions
-
-        //- Reconstruct part characteristics (eg, element types) from Istream
-        //  A part reconstructed in this manner can be used when writing fields,
-        //  but cannot be used to write a new geometry
-        void reconstruct(Istream&);
-
-        //- Check for fully defined fields
-        bool isFieldDefined(const List<scalar>&) const;
-
-        //- Write the part header
-        void writeHeader(ensightFile&, bool withDescription=false) const;
-
-        //- Write a scalar field for idList
-        //  A null reference for idList writes the perNode values
-        void writeFieldList
-        (
-            ensightFile& os,
-            const List<scalar>& field,
-            const labelUList& idList
-        ) const;
-
-        //- Track points used
-        virtual localPoints calcLocalPoints() const
-        {
-            return localPoints();
-        }
-
-        //- Write connectivities
-        virtual void writeConnectivity
-        (
-            ensightGeoFile&,
-            const word& key,
-            const labelUList& idList,
-            const labelUList& pointMap
-        ) const
-        {}
-
-
 public:
 
     //- Runtime type information
@@ -175,85 +111,23 @@ public:
 
     // Constructors
 
-        //- Construct null
-        ensightPart();
-
-        //- Construct empty part with number and description
-        ensightPart(label partNumber, const string& partDescription);
-
-        //- Construct part with number, description and points reference
-        ensightPart
-        (
-            label partNumber,
-            const string& partDescription,
-            const pointField& points
-        );
-
-        //- Construct as copy
-        ensightPart(const ensightPart&);
-
-
-    // Selectors
-
-        // Declare run-time constructor selection table
-        declareRunTimeSelectionTable
-        (
-            autoPtr,
-            ensightPart,
-            istream,
-            (
-                Istream& is
-            ),
-            (is)
-        );
-
-        //- Construct and return clone
-        autoPtr<ensightPart> clone() const
-        {
-            return autoPtr<ensightPart>(new ensightPart(*this));
-        };
-
-        //- Reconstruct part characteristics on freestore from Istream
-        //  \sa reconstruct
-        static autoPtr<ensightPart> New(Istream&);
+        //- Construct with description
+        ensightPart(const string& description);
 
 
     //- Destructor
     virtual ~ensightPart();
 
 
-    // Static members
-
-        virtual const List<word>& elementTypes() const
-        {
-            return elemTypes_;
-        }
-
-
     // Access
 
-        //- Number of elements in this part
-        label size() const
-        {
-            return size_;
-        }
-
-        //- Represents cell data
-        bool isCellData() const
-        {
-            return isCellData_;
-        }
-
-        //- Represents face data
-        bool isFaceData() const
-        {
-            return !isCellData_;
-        }
+        //- Part index (0-based)
+        virtual label index() const = 0;
 
-        //- Part number
-        label number() const
+        //- Number of elements in this part
+        virtual label size() const
         {
-            return number_;
+            return 0;
         }
 
         //- Part name or description
@@ -262,80 +136,35 @@ public:
             return name_;
         }
 
-        //- Material id
-        label materialId() const
-        {
-            return matId_;
-        }
-
         //- non-const access to part name or description
         void name(const string& value)
         {
             name_ = value;
         }
 
-        //- non-const access to material id
-        void materialId(const label value)
-        {
-            matId_ = value;
-        }
 
-        //- Simple labelList with a name
-        const labelListList& elemLists() const
-        {
-            return elemLists_;
-        }
-
-        //- Offset for element ids
-        label offset() const
-        {
-            return offset_;
-        }
-
-
-    // Edit
-
-        //- Renumber elements
-        void renumber(const labelUList&);
-
-        //- Write summary information about the object
-        bool writeSummary(Ostream&) const;
-
-        //- Write reconstruction information for the object
-        bool writeData(Ostream&) const;
+    // Output
 
         //- Write geometry
-        virtual void writeGeometry(ensightGeoFile&) const
-        {}
+        virtual void write(ensightGeoFile&) const = 0;
 
-        //- Helper: write geometry given the pointField
-        void writeGeometry(ensightGeoFile&, const pointField&) const;
-
-        //- Write generalized field components
-        //  optionally write data per node
-        template<class Type>
-        void writeField
+        //- Helper: write geometry with given pointField
+        virtual void write
         (
-            ensightFile&,
-            const Field<Type>&,
-            const bool perNode = false
-        ) const;
+            ensightGeoFile&,
+            const pointField&
+        ) const = 0;
 
 
-    // Member Operators
+        //- Write summary information about the object
+        virtual void writeSummary(Ostream&) const = 0;
 
-        //- Disallow default bitwise assignment
-        void operator=(const ensightPart&)
-        {
-            NotImplemented;
-        }
+        //- Print various types of debugging information
+        virtual void dumpInfo(Ostream&) const = 0;
 
 
     // IOstream Operators
 
-        //- Write data (reconstruction information)
-        friend Ostream& operator<<(Ostream&, const ensightPart&);
-
         //- Write geometry
         friend ensightGeoFile& operator<<(ensightGeoFile&, const ensightPart&);
 
@@ -348,12 +177,6 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-#ifdef NoRepository
-    #include "ensightPartTemplates.C"
-#endif
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
 #endif
 
 // ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightPartCells.C b/src/conversion/ensight/part/ensightPartCells.C
index 82ef148e036d746dccbbfe3ecad76ce6c43b7fd0..cfd5c9482fc84ccde70aced8fcc826e7b63995de 100644
--- a/src/conversion/ensight/part/ensightPartCells.C
+++ b/src/conversion/ensight/part/ensightPartCells.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.
@@ -24,152 +24,57 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "ensightPartCells.H"
-#include "IOstream.H"
-#include "IStringStream.H"
-#include "dictionary.H"
-#include "cellModeller.H"
-#include "addToRunTimeSelectionTable.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
 namespace Foam
 {
     defineTypeNameAndDebug(ensightPartCells, 0);
-    addToRunTimeSelectionTable(ensightPart, ensightPartCells, istream);
 }
 
-const Foam::List<Foam::word> Foam::ensightPartCells::elemTypes_
-(
-    IStringStream
-    (
-        "(tetra4 pyramid5 penta6 hexa8 nfaced)"
-    )()
-);
-
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-void Foam::ensightPartCells::classify
-(
-    const polyMesh& mesh,
-    const labelUList& idList
-)
+Foam::ensightPart::localPoints Foam::ensightPartCells::calcLocalPoints() const
 {
-    // References to cell shape models
-    const cellModel& tet   = *(cellModeller::lookup("tet"));
-    const cellModel& pyr   = *(cellModeller::lookup("pyr"));
-    const cellModel& prism = *(cellModeller::lookup("prism"));
-    const cellModel& hex   = *(cellModeller::lookup("hex"));
-
-    const cellShapeList& cellShapes = mesh.cellShapes();
+    localPoints ptList(mesh_.points());
+    labelList& usedPoints = ptList.list;
+    label nPoints = 0;
 
-    offset_ = 0;
-    size_ = mesh.nCells();
+    // add all points from cells
+    const labelUList& idList = this->cellIds();
 
-    bool limited = false;
-    if (notNull(idList))
+    forAll(idList, i)
     {
-        limited = true;
-        size_ = idList.size();
-    }
-
-    // count the shapes
-    label nTet   = 0;
-    label nPyr   = 0;
-    label nPrism = 0;
-    label nHex   = 0;
-    label nPoly  = 0;
+        const label id = idList[i];
+        const labelUList& cFaces = mesh_.cells()[id];
 
-    for (label listI = 0; listI < size_; ++listI)
-    {
-        label cellId = listI;
-        if (limited)
+        forAll(cFaces, cFacei)
         {
-            cellId = idList[listI];
-        }
+            const face& f = mesh_.faces()[cFaces[cFacei]];
 
-        const cellShape& cellShape = cellShapes[cellId];
-        const cellModel& cellModel = cellShape.model();
-
-        if (cellModel == tet)
-        {
-            nTet++;
-        }
-        else if (cellModel == pyr)
-        {
-            nPyr++;
-        }
-        else if (cellModel == prism)
-        {
-            nPrism++;
-        }
-        else if (cellModel == hex)
-        {
-            nHex++;
-        }
-        else
-        {
-            nPoly++;
+            forAll(f, fp)
+            {
+                if (usedPoints[f[fp]] == -1)
+                {
+                    usedPoints[f[fp]] = nPoints++;
+                }
+            }
         }
     }
 
-
-    // we can avoid double looping, but at the cost of allocation
-    labelList tetCells(nTet);
-    labelList pyramidCells(nPyr);
-    labelList prismCells(nPrism);
-    labelList hexCells(nHex);
-    labelList polyCells(nPoly);
-
-    nTet   = 0,
-    nPyr   = 0;
-    nPrism = 0;
-    nHex   = 0;
-    nPoly  = 0;
-
-    // classify the shapes
-    for (label listI = 0; listI < size_; ++listI)
+    // this is not absolutely necessary, but renumber anyhow
+    nPoints = 0;
+    forAll(usedPoints, ptI)
     {
-        label cellId = listI;
-        if (limited)
-        {
-            cellId = idList[listI];
-        }
-
-        const cellShape& cellShape = cellShapes[cellId];
-        const cellModel& cellModel = cellShape.model();
-
-        if (cellModel == tet)
-        {
-            tetCells[nTet++] = cellId;
-        }
-        else if (cellModel == pyr)
-        {
-            pyramidCells[nPyr++] = cellId;
-        }
-        else if (cellModel == prism)
-        {
-            prismCells[nPrism++] = cellId;
-        }
-        else if (cellModel == hex)
-        {
-            hexCells[nHex++] = cellId;
-        }
-        else
+        if (usedPoints[ptI] > -1)
         {
-            polyCells[nPoly++] = cellId;
+            usedPoints[ptI] = nPoints++;
         }
     }
 
-
-    // MUST match with elementTypes
-    elemLists_.setSize(elementTypes().size());
-
-    elemLists_[tetra4Elements].transfer(tetCells);
-    elemLists_[pyramid5Elements].transfer(pyramidCells);
-    elemLists_[penta6Elements].transfer(prismCells);
-    elemLists_[hexa8Elements].transfer(hexCells);
-    elemLists_[nfacedElements].transfer(polyCells);
+    ptList.nPoints = nPoints;
+    return ptList;
 }
 
 
@@ -177,22 +82,12 @@ void Foam::ensightPartCells::classify
 
 Foam::ensightPartCells::ensightPartCells
 (
-    label partNumber,
-    const string& partDescription
-)
-:
-    ensightPart(partNumber, partDescription),
-    mesh_(*reinterpret_cast<polyMesh*>(0))
-{}
-
-
-Foam::ensightPartCells::ensightPartCells
-(
-    label partNumber,
+    label partIndex,
     const polyMesh& mesh
 )
 :
-    ensightPart(partNumber, "cells", mesh.points()),
+    ensightCells(partIndex),
+    ensightPart("cells"),
     mesh_(mesh)
 {
     classify(mesh);
@@ -201,12 +96,13 @@ Foam::ensightPartCells::ensightPartCells
 
 Foam::ensightPartCells::ensightPartCells
 (
-    label partNumber,
+    label partIndex,
     const polyMesh& mesh,
     const labelUList& idList
 )
 :
-    ensightPart(partNumber, "cells", mesh.points()),
+    ensightCells(partIndex),
+    ensightPart("cells"),
     mesh_(mesh)
 {
     classify(mesh, idList);
@@ -215,34 +111,19 @@ Foam::ensightPartCells::ensightPartCells
 
 Foam::ensightPartCells::ensightPartCells
 (
-    label partNumber,
+    label partIndex,
     const polyMesh& mesh,
     const cellZone& cZone
 )
 :
-    ensightPart(partNumber, cZone.name(), mesh.points()),
+    ensightCells(partIndex),
+    ensightPart(cZone.name()),
     mesh_(mesh)
 {
     classify(mesh, cZone);
 }
 
 
-Foam::ensightPartCells::ensightPartCells(const ensightPartCells& part)
-:
-    ensightPart(part),
-    mesh_(part.mesh_)
-{}
-
-
-Foam::ensightPartCells::ensightPartCells(Istream& is)
-:
-    ensightPart(),
-    mesh_(*reinterpret_cast<polyMesh*>(0))
-{
-    reconstruct(is);
-}
-
-
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 Foam::ensightPartCells::~ensightPartCells()
@@ -251,52 +132,6 @@ Foam::ensightPartCells::~ensightPartCells()
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-Foam::ensightPart::localPoints Foam::ensightPartCells::calcLocalPoints() const
-{
-    localPoints ptList(points_);
-    labelList& usedPoints = ptList.list;
-    label nPoints = 0;
-
-    forAll(elemLists_, typeI)
-    {
-        const labelUList& idList = elemLists_[typeI];
-
-        // add all points from cells
-        forAll(idList, i)
-        {
-            const label id = idList[i] + offset_;
-            const labelUList& cFaces = mesh_.cells()[id];
-
-            forAll(cFaces, cFacei)
-            {
-                const face& f = mesh_.faces()[cFaces[cFacei]];
-
-                forAll(f, fp)
-                {
-                    if (usedPoints[f[fp]] == -1)
-                    {
-                        usedPoints[f[fp]] = nPoints++;
-                    }
-                }
-            }
-        }
-    }
-
-    // this is not absolutely necessary, but renumber anyhow
-    nPoints = 0;
-    forAll(usedPoints, ptI)
-    {
-        if (usedPoints[ptI] > -1)
-        {
-            usedPoints[ptI] = nPoints++;
-        }
-    }
-
-    ptList.nPoints = nPoints;
-    return ptList;
-}
-
-
 void Foam::ensightPartCells::writeConnectivity
 (
     ensightGeoFile& os,
@@ -305,6 +140,8 @@ void Foam::ensightPartCells::writeConnectivity
     const labelUList& pointMap
 ) const
 {
+    if (idList.empty()) return;
+
     os.writeKeyword(key);
     os.write(idList.size());
     os.newline();
@@ -318,7 +155,7 @@ void Foam::ensightPartCells::writeConnectivity
         // write the number of faces per element
         forAll(idList, i)
         {
-            const label id = idList[i] + offset_;
+            const label id = idList[i];
             const labelUList& cFace = mesh_.cells()[id];
 
             os.write(cFace.size());
@@ -328,7 +165,7 @@ void Foam::ensightPartCells::writeConnectivity
         // write the number of points per element face
         forAll(idList, i)
         {
-            const label id = idList[i] + offset_;
+            const label id = idList[i];
             const labelUList& cFace = mesh_.cells()[id];
 
             forAll(cFace, facei)
@@ -343,7 +180,7 @@ void Foam::ensightPartCells::writeConnectivity
         // write the points describing each element face
         forAll(idList, i)
         {
-            const label id = idList[i] + offset_;
+            const label id = idList[i];
             const labelUList& cFace = mesh_.cells()[id];
 
             forAll(cFace, cFacei)
@@ -380,12 +217,12 @@ void Foam::ensightPartCells::writeConnectivity
     else
     {
         // write primitive
-        const cellShapeList& cellShapes = mesh_.cellShapes();
+        const cellShapeList& shapes = mesh_.cellShapes();
 
         forAll(idList, i)
         {
-            const label id = idList[i] + offset_;
-            const cellShape& cellPoints = cellShapes[id];
+            const label id = idList[i];
+            const cellShape& cellPoints = shapes[id];
 
             // convert global -> local index
             // (note: Ensight indices start with 1)
@@ -399,9 +236,97 @@ void Foam::ensightPartCells::writeConnectivity
 }
 
 
-void Foam::ensightPartCells::writeGeometry(ensightGeoFile& os) const
+void Foam::ensightPartCells::write
+(
+    ensightGeoFile& os,
+    const pointField& points
+) const
+{
+    if (size())
+    {
+        const localPoints ptList = calcLocalPoints();
+        const labelUList& pointMap = ptList.list;
+
+        os.beginPart(index(), name());
+        os.beginCoordinates(ptList.nPoints);
+
+        for (direction cmpt=0; cmpt < point::nComponents; ++cmpt)
+        {
+            forAll(pointMap, ptI)
+            {
+                if (pointMap[ptI] > -1)
+                {
+                    os.write(points[ptI].component(cmpt));
+                    os.newline();
+                }
+            }
+        }
+
+        // write each element type
+        const List<ensightCells::elemType> enums =
+            ensightCells::elemEnum.enums();
+
+        forAllConstIter(List<ensightCells::elemType>, enums, iter)
+        {
+            const ensightCells::elemType what = *iter;
+
+            writeConnectivity
+            (
+                os,
+                ensightCells::key(what),
+                cellIds(what),
+                pointMap
+            );
+        }
+    }
+}
+
+
+void Foam::ensightPartCells::write(ensightGeoFile& os) const
+{
+    this->write(os, mesh_.points());
+}
+
+
+void Foam::ensightPartCells::writeSummary(Ostream& os) const
+{
+    os.beginBlock(type());
+
+    os.writeEntry("id",     index()+1); // Ensight starts with 1
+    os.writeEntry("name",   name());
+    os.writeEntry("size",   size());
+
+    os.endBlock() << flush;
+}
+
+
+void Foam::ensightPartCells::dumpInfo(Ostream& os) const
 {
-    ensightPart::writeGeometry(os, points_);
+    os.beginBlock(type());
+
+    os.writeEntry("id",     index()+1); // Ensight starts with 1
+    os.writeEntry("name",   name());
+    os.writeEntry("size",   size());
+
+    const List<ensightCells::elemType> enums = ensightCells::elemEnum.enums();
+    forAllConstIter(List<ensightCells::elemType>, enums, iter)
+    {
+        const ensightCells::elemType what = *iter;
+        const labelUList& addr = this->cellIds(what);
+
+        os.writeKeyword(ensightCells::key(what));
+
+        // DIY flat output
+        os << addr.size() << '(';
+        forAll(addr, i)
+        {
+            if (i) os << ' ';
+            os << addr[i];
+        }
+        os << ')' << endEntry;
+    }
+
+    os.endBlock() << flush;
 }
 
 
diff --git a/src/conversion/ensight/part/ensightPartCells.H b/src/conversion/ensight/part/ensightPartCells.H
index d1b3bcb72dbaf6bd307b5e5bd5b462910d29db8c..f256a4800f0d55f011160c2747b68fbf80c720ca 100644
--- a/src/conversion/ensight/part/ensightPartCells.H
+++ b/src/conversion/ensight/part/ensightPartCells.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -36,6 +36,7 @@ SourceFiles
 #define ensightPartCells_H
 
 #include "ensightPart.H"
+#include "ensightCells.H"
 #include "typeInfo.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -49,28 +50,22 @@ namespace Foam
 
 class ensightPartCells
 :
+    public ensightCells,
     public ensightPart
 {
-    // Private Member Functions
+    // Private data
 
-        //- Disallow default bitwise assignment
-        void operator=(const ensightPartCells&);
+        //- Mesh referenced
+        const polyMesh& mesh_;
 
-        //- Classify the cell types, set elemLists.
-        void classify
-        (
-            const polyMesh&,
-            const labelUList& idLabels = labelUList::null()
-        );
 
-        //- Track points used
-        virtual localPoints calcLocalPoints() const;
+    // Private Member Functions
 
-        //- Track the points used
-        // virtual void makeLocalPointMap();
+        //- Track points used
+        localPoints calcLocalPoints() const;
 
         //- Element connectivity
-        virtual void writeConnectivity
+        void writeConnectivity
         (
             ensightGeoFile&,
             const word& key,
@@ -79,28 +74,11 @@ class ensightPartCells
         ) const;
 
 
-protected:
+        //- Disallow default bitwise copy construct
+        ensightPartCells(const ensightPartCells&) = delete;
 
-        //- Addressable ensight element types
-        enum elemType
-        {
-            tetra4Elements,
-            pyramid5Elements,
-            penta6Elements,
-            hexa8Elements,
-            nfacedElements
-        };
-
-
-    // Static data members
-
-        static const List<word> elemTypes_;
-
-
-    // Protected data
-
-        //- Mesh referenced
-        const polyMesh& mesh_;
+        //- Disallow default bitwise assignment
+        void operator=(const ensightPartCells&) = delete;
 
 
 public:
@@ -110,16 +88,17 @@ public:
 
     // Constructors
 
-        //- Construct empty part with number and description
-        ensightPartCells(label partNumber, const string& partDescription);
-
         //- Construct from polyMesh without zones
-        ensightPartCells(label partNumber, const polyMesh&);
+        ensightPartCells
+        (
+            label partIndex,
+            const polyMesh&
+        );
 
         //- Construct from polyMesh and list of (non-zoned) cells
         ensightPartCells
         (
-            label partNumber,
+            label partIndex,
             const polyMesh&,
             const labelUList&
         );
@@ -127,26 +106,11 @@ public:
         //- Construct from polyMesh and cellZone
         ensightPartCells
         (
-            label partNumber,
+            label partIndex,
             const polyMesh&,
             const cellZone&
         );
 
-        //- Construct as copy
-        ensightPartCells(const ensightPartCells&);
-
-        //- Reconstruct part characteristics (eg, element types) from Istream
-        //  A part reconstructed in this manner can be used when writing fields,
-        //  but cannot be used to write a new geometry
-        //  \sa Foam::ensightPart::reconstruct
-        ensightPartCells(Istream&);
-
-        //- Reconstruct part characteristics on freestore from Istream
-        static autoPtr<ensightPartCells> New(Istream& is)
-        {
-            return autoPtr<ensightPartCells>(new ensightPartCells(is));
-        }
-
 
     //- Destructor
     virtual ~ensightPartCells();
@@ -154,14 +118,36 @@ public:
 
     // Member Functions
 
-        //- Write geometry
-        virtual void writeGeometry(ensightGeoFile&) const;
+    // Access
 
-        //- Static listing of the element types
-        virtual const List<word>& elementTypes() const
+        //- Part index (0-based)
+        virtual label index() const
         {
-            return elemTypes_;
+            return ensightCells::index();
         }
+
+        //- Number of elements in this part
+        virtual label size() const
+        {
+            return ensightCells::size();
+        }
+
+
+    // Output
+
+        //- Write geometry
+        virtual void write(ensightGeoFile&) const;
+
+        //- Helper: write geometry given the pointField
+        virtual void write(ensightGeoFile&, const pointField&) const;
+
+
+        //- Write summary information about the object
+        virtual void writeSummary(Ostream&) const;
+
+        //- Print various types of debugging information
+        virtual void dumpInfo(Ostream&) const;
+
 };
 
 
diff --git a/src/conversion/ensight/part/ensightPartFaces.C b/src/conversion/ensight/part/ensightPartFaces.C
index ba28b3a13cdb32b0991bf40c6ef5d7e73d3701cd..4875b19cfbfcce79779f6666f37bf012f5ba8cf2 100644
--- a/src/conversion/ensight/part/ensightPartFaces.C
+++ b/src/conversion/ensight/part/ensightPartFaces.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.
@@ -24,94 +24,61 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "ensightPartFaces.H"
-#include "IOstreams.H"
-#include "IStringStream.H"
-#include "dictionary.H"
-#include "addToRunTimeSelectionTable.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
 namespace Foam
 {
     defineTypeNameAndDebug(ensightPartFaces, 0);
-    addToRunTimeSelectionTable(ensightPart, ensightPartFaces, istream);
 }
 
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-const Foam::List<Foam::word> Foam::ensightPartFaces::elemTypes_
-(
-    IStringStream
-    (
-        "(tria3 quad4 nsided)"
-    )()
-);
-
+Foam::ensightPart::localPoints Foam::ensightPartFaces::calcLocalPoints() const
+{
+    if (contiguousPoints_)
+    {
+        localPoints ptList;
+        ptList.list = identity(points_.size());
+        ptList.nPoints = points_.size();
+        return ptList;
+    }
 
-// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+    localPoints ptList(points_);
+    labelList& usedPoints = ptList.list;
+    label nPoints = 0;
 
-void Foam::ensightPartFaces::classify(const faceList& faces)
-{
-    // count the shapes
-    label nTri  = 0;
-    label nQuad = 0;
-    label nPoly = 0;
+    // add all points from faces
+    const labelUList& idList = this->faceIds();
 
-    forAll(faces, facei)
+    // add all points from faces
+    forAll(idList, i)
     {
-        const face& f = faces[facei];
+        const label id = idList[i] + start_;
+        const face& f = faces_[id];
 
-        if (f.size() == 3)
-        {
-            nTri++;
-        }
-        else if (f.size() == 4)
-        {
-            nQuad++;
-        }
-        else
+        forAll(f, fp)
         {
-            nPoly++;
+            if (usedPoints[f[fp]] == -1)
+            {
+                usedPoints[f[fp]] = nPoints++;
+            }
         }
     }
 
-    // we can avoid double looping, but at the cost of allocation
-
-    labelList triCells(nTri);
-    labelList quadCells(nQuad);
-    labelList polygonCells(nPoly);
 
-    nTri  = 0;
-    nQuad = 0;
-    nPoly = 0;
-
-    // classify the shapes
-    forAll(faces, facei)
+    // this is not absolutely necessary, but renumber anyhow
+    nPoints = 0;
+    forAll(usedPoints, ptI)
     {
-        const face& f = faces[facei];
-
-        if (f.size() == 3)
-        {
-            triCells[nTri++] = facei;
-        }
-        else if (f.size() == 4)
-        {
-            quadCells[nQuad++] = facei;
-        }
-        else
+        if (usedPoints[ptI] > -1)
         {
-            polygonCells[nPoly++] = facei;
+            usedPoints[ptI] = nPoints++;
         }
     }
 
-
-    // MUST match with elementTypes
-    elemLists_.setSize(elementTypes().size());
-
-    elemLists_[tria3Elements].transfer(triCells);
-    elemLists_[quad4Elements].transfer(quadCells);
-    elemLists_[nsidedElements].transfer(polygonCells);
-
-    size_ = faces.size();
+    ptList.nPoints = nPoints;
+    return ptList;
 }
 
 
@@ -119,37 +86,21 @@ void Foam::ensightPartFaces::classify(const faceList& faces)
 
 Foam::ensightPartFaces::ensightPartFaces
 (
-    label partNumber,
-    const string& partDescription
-)
-:
-    ensightPart(partNumber, partDescription),
-    faces_(faceList::null()),
-    contiguousPoints_(false)
-{
-    isCellData_ = false;
-    offset_ = 0;
-    size_ = 0;
-}
-
-
-Foam::ensightPartFaces::ensightPartFaces
-(
-    label partNumber,
-    const string& partDescription,
+    label partIndex,
+    const string& description,
     const pointField& points,
     const faceList& faces,
     const bool contiguousPoints
 )
 :
-    ensightPart(partNumber, partDescription, points),
+    ensightFaces(partIndex),
+    ensightPart(description),
+    start_(0),
+    patchIndex_(-1),
     faces_(faces),
+    points_(points),
     contiguousPoints_(contiguousPoints)
 {
-    isCellData_ = false;
-    offset_ = 0;
-    size_ = 0;
-
     // classify the face shapes
     classify(faces);
 }
@@ -157,42 +108,24 @@ Foam::ensightPartFaces::ensightPartFaces
 
 Foam::ensightPartFaces::ensightPartFaces
 (
-    label partNumber,
+    label partIndex,
     const polyMesh& mesh,
     const polyPatch& patch
 )
 :
-    ensightPart(partNumber, patch.name(), mesh.points()),
+    ensightFaces(partIndex),
+    ensightPart(patch.name()),
+    start_(patch.start()),
+    patchIndex_(patch.index()),
     faces_(mesh.faces()),
+    points_(mesh.points()),
     contiguousPoints_(false)
 {
-    isCellData_ = false;
-    offset_ = patch.start();
-
     // classify the face shapes
     classify(patch);
 }
 
 
-Foam::ensightPartFaces::ensightPartFaces(const ensightPartFaces& part)
-:
-    ensightPart(part),
-    faces_(part.faces_),
-    contiguousPoints_(part.contiguousPoints_)
-{}
-
-
-Foam::ensightPartFaces::ensightPartFaces(Istream& is)
-:
-    ensightPart(),
-    faces_(faceList::null()),
-    contiguousPoints_(false)
-{
-    isCellData_ = false;
-    reconstruct(is);
-}
-
-
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 Foam::ensightPartFaces::~ensightPartFaces()
@@ -201,55 +134,6 @@ Foam::ensightPartFaces::~ensightPartFaces()
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-Foam::ensightPart::localPoints Foam::ensightPartFaces::calcLocalPoints() const
-{
-    if (contiguousPoints_)
-    {
-        localPoints ptList;
-        ptList.list = identity(points_.size());
-        ptList.nPoints = points_.size();
-        return ptList;
-    }
-
-    localPoints ptList(points_);
-    labelList& usedPoints = ptList.list;
-    label nPoints = 0;
-
-    forAll(elemLists_, typeI)
-    {
-        const labelUList& idList = elemLists_[typeI];
-
-        // add all points from faces
-        forAll(idList, i)
-        {
-            const label id = idList[i] + offset_;
-            const face& f = faces_[id];
-
-            forAll(f, fp)
-            {
-                if (usedPoints[f[fp]] == -1)
-                {
-                    usedPoints[f[fp]] = nPoints++;
-                }
-            }
-        }
-    }
-
-    // this is not absolutely necessary, but renumber anyhow
-    nPoints = 0;
-    forAll(usedPoints, ptI)
-    {
-        if (usedPoints[ptI] > -1)
-        {
-            usedPoints[ptI] = nPoints++;
-        }
-    }
-
-    ptList.nPoints = nPoints;
-    return ptList;
-}
-
-
 void Foam::ensightPartFaces::writeConnectivity
 (
     ensightGeoFile& os,
@@ -259,6 +143,8 @@ void Foam::ensightPartFaces::writeConnectivity
     const labelUList& pointMap
 ) const
 {
+    if (idList.empty()) return;
+
     os.writeKeyword(key);
     os.write(idList.size());
     os.newline();
@@ -269,7 +155,7 @@ void Foam::ensightPartFaces::writeConnectivity
         // write the number of points per face
         forAll(idList, i)
         {
-            const label id = idList[i] + offset_;
+            const label id = idList[i] + start_;
             const face& f = faces[id];
 
             os.write(f.size());
@@ -280,7 +166,7 @@ void Foam::ensightPartFaces::writeConnectivity
     // write the points describing the face
     forAll(idList, i)
     {
-        const label id = idList[i] + offset_;
+        const label id = idList[i] + start_;
         const face& f = faces[id];
 
         // convert global -> local index
@@ -313,9 +199,99 @@ void Foam::ensightPartFaces::writeConnectivity
 }
 
 
-void Foam::ensightPartFaces::writeGeometry(ensightGeoFile& os) const
+void Foam::ensightPartFaces::write
+(
+    ensightGeoFile& os,
+    const pointField& points
+) const
+{
+    if (ensightPart::size())
+    {
+        const localPoints ptList = calcLocalPoints();
+        const labelUList& pointMap = ptList.list;
+
+        os.beginPart(index(), name());
+        os.beginCoordinates(ptList.nPoints);
+
+        for (direction cmpt=0; cmpt < point::nComponents; ++cmpt)
+        {
+            forAll(pointMap, ptI)
+            {
+                if (pointMap[ptI] > -1)
+                {
+                    os.write(points[ptI].component(cmpt));
+                    os.newline();
+                }
+            }
+        }
+
+        // write part
+        const List<ensightFaces::elemType> enums =
+            ensightFaces::elemEnum.enums();
+
+        forAllConstIter(List<ensightFaces::elemType>, enums, iter)
+        {
+            const ensightFaces::elemType what = *iter;
+
+            writeConnectivity
+            (
+                os,
+                ensightFaces::key(what),
+                faceIds(what),
+                pointMap
+            );
+        }
+    }
+}
+
+
+void Foam::ensightPartFaces::write(ensightGeoFile& os) const
+{
+    this->write(os, points_);
+}
+
+
+void Foam::ensightPartFaces::writeSummary(Ostream& os) const
+{
+    os.beginBlock(type());
+
+    os.writeEntry("id",     index()+1); // Ensight starts with 1
+    os.writeEntry("name",   name());
+    os.writeEntry("start",  start_);
+    os.writeEntry("size",   size());
+
+    os.endBlock() << flush;
+}
+
+
+void Foam::ensightPartFaces::dumpInfo(Ostream& os) const
 {
-    ensightPart::writeGeometry(os, points_);
+    os.beginBlock(type());
+
+    os.writeEntry("id",     index()+1); // Ensight starts with 1
+    os.writeEntry("name",   name());
+    os.writeEntry("start",  start_);
+    os.writeEntry("size",   size());
+
+    const List<ensightFaces::elemType> enums = ensightFaces::elemEnum.enums();
+    forAllConstIter(List<ensightFaces::elemType>, enums, iter)
+    {
+        const ensightFaces::elemType what = *iter;
+        const labelUList& addr = this->faceIds(what);
+
+        os.writeKeyword(ensightFaces::key(what));
+
+        // DIY flat output
+        os << addr.size() << '(';
+        forAll(addr, i)
+        {
+            if (i) os << ' ';
+            os << addr[i];
+        }
+        os << ')' << endEntry;
+    }
+
+    os.endBlock() << flush;
 }
 
 
diff --git a/src/conversion/ensight/part/ensightPartFaces.H b/src/conversion/ensight/part/ensightPartFaces.H
index ea27d0cf51e832a17b543cb50839070ac1b970a6..974ca68a055783cb702077a64320b59becbe9ff2 100644
--- a/src/conversion/ensight/part/ensightPartFaces.H
+++ b/src/conversion/ensight/part/ensightPartFaces.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -25,7 +25,7 @@ Class
     Foam::ensightPartFaces
 
 Description
-    An implementation of ensightPart to hold volume mesh faces.
+    An implementation of ensightPart to hold mesh faces.
 
 SourceFiles
     ensightPartFaces.C
@@ -36,6 +36,8 @@ SourceFiles
 #define ensightPartFaces_H
 
 #include "ensightPart.H"
+#include "ensightFaces.H"
+#include "typeInfo.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -43,23 +45,39 @@ namespace Foam
 {
 
 /*---------------------------------------------------------------------------*\
-                     Class ensightPartFaces Declaration
+                      Class ensightPartFaces Declaration
 \*---------------------------------------------------------------------------*/
 
 class ensightPartFaces
 :
+    public ensightFaces,
     public ensightPart
 {
-    // Private Member Functions
+    // Private data
 
-        //- Disallow default bitwise assignment
-        void operator=(const ensightPartFaces&);
+        //- Start offset for patch
+        const label start_;
+
+        //- Patch index
+        const label patchIndex_;
+
+        //- Faces referenced
+        const faceList& faces_;
+
+        //- pointField referenced
+        const pointField& points_;
+
+        //- Can skip local point renumbering when points are contiguous
+        const bool contiguousPoints_;
+
+
+    // Private Member Functions
 
         //- Track points used
-        virtual localPoints calcLocalPoints() const;
+        localPoints calcLocalPoints() const;
 
         //- Element connectivity
-        virtual void writeConnectivity
+        void writeConnectivity
         (
             ensightGeoFile&,
             const word& key,
@@ -68,36 +86,6 @@ class ensightPartFaces
         ) const;
 
 
-protected:
-
-        //- Addressable ensight element types
-        enum elemType
-        {
-            tria3Elements,
-            quad4Elements,
-            nsidedElements
-        };
-
-
-    // Static data members
-
-        static const List<word> elemTypes_;
-
-
-    // Protected data
-
-        //- Faces referenced
-        const faceList& faces_;
-
-        //- Can skip local point renumbering when points are contiguous
-        const bool contiguousPoints_;
-
-
-    // Protected Member Functions
-
-        //- Classify the face shapes, set elemLists.
-        void classify(const faceList&);
-
         //- Helper: write connectivity
         void writeConnectivity
         (
@@ -109,22 +97,27 @@ protected:
         ) const;
 
 
+        //- Disallow default bitwise copy construct
+        ensightPartFaces(const ensightPartFaces&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const ensightPartFaces&) = delete;
+
+
 public:
 
     //- Runtime type information
     TypeName("ensightFaces");
 
-    // Constructors
 
-        //- Construct empty part with number and description
-        ensightPartFaces(label partNumber, const string& partDescription);
+    // Constructors
 
-        //- Construct part with number, description, points and faces
+        //- Construct part with 0-based index, description, points and faces
         //  Can skip local point renumbering when points are contiguous
         ensightPartFaces
         (
-            label partNumber,
-            const string& partDescription,
+            label partIndex,
+            const string& description,
             const pointField&,
             const faceList&,
             const bool contiguousPoints = false
@@ -133,41 +126,56 @@ public:
         //- Construct from polyMesh and polyPatch
         ensightPartFaces
         (
-            label partNumber,
+            label partIndex,
             const polyMesh&,
             const polyPatch&
         );
 
-        //- Construct as copy
-        ensightPartFaces(const ensightPartFaces&);
 
-        //- Reconstruct part characteristics (eg, element types) from Istream
-        //  A part reconstructed in this manner can be used when writing fields,
-        //  but cannot be used to write a new geometry
-        //  \sa Foam::ensightPart::reconstruct
-        ensightPartFaces(Istream&);
+    //- Destructor
+    virtual ~ensightPartFaces();
 
-        //- Reconstruct part characteristics on freestore from Istream
-        static autoPtr<ensightPartFaces> New(Istream& is)
+
+    // Member Functions
+
+    // Access
+
+        //- Part index (0-based)
+        virtual label index() const
         {
-            return autoPtr<ensightPartFaces>(new ensightPartFaces(is));
+            return ensightFaces::index();
         }
 
 
-    //- Destructor
-    virtual ~ensightPartFaces();
+        //- Number of elements in this part
+        virtual label size() const
+        {
+            return ensightFaces::size();
+        }
 
 
-    // Member Functions
+        //- Return the patch index, -1 when not in use.
+        inline label patchIndex() const
+        {
+            return patchIndex_;
+        }
+
+
+    // Output
+
+        //- Write summary information about the object
+        virtual void writeSummary(Ostream&) const;
 
         //- Write geometry
-        virtual void writeGeometry(ensightGeoFile&) const;
+        virtual void write(ensightGeoFile&) const;
+
+        //- Helper: write geometry given the pointField
+        virtual void write(ensightGeoFile&, const pointField&) const;
+
+
+        //- Print various types of debugging information
+        virtual void dumpInfo(Ostream&) const;
 
-        //- Static listing of the element types
-        virtual const List<word>& elementTypes() const
-        {
-            return elemTypes_;
-        }
 };
 
 
diff --git a/src/conversion/ensight/part/ensightPartIO.C b/src/conversion/ensight/part/ensightPartIO.C
deleted file mode 100644
index 4e21d6dd62b8bfbea7d8caeadab33267f3455632..0000000000000000000000000000000000000000
--- a/src/conversion/ensight/part/ensightPartIO.C
+++ /dev/null
@@ -1,240 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-Description
-    Output for ensightPart
-
-\*---------------------------------------------------------------------------*/
-
-#include "ensightPart.H"
-#include "dictionary.H"
-#include "IOstreams.H"
-
-// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
-
-void Foam::ensightPart::writeHeader
-(
-    ensightFile& os,
-    bool withDescription
-) const
-{
-    os.write("part");
-    os.newline();
-
-    os.write(number() + 1);   // Ensight starts with 1
-    os.newline();
-
-    if (withDescription)
-    {
-        os.write(name());
-        os.newline();
-    }
-}
-
-
-void Foam::ensightPart::writeFieldList
-(
-    ensightFile& os,
-    const List<scalar>& field,
-    const labelUList& idList
-) const
-{
-    if (notNull(idList))
-    {
-        forAll(idList, i)
-        {
-            if (idList[i] >= field.size() || std::isnan(field[idList[i]]))
-            {
-                os.writeUndef();
-            }
-            else
-            {
-                os.write(field[idList[i]]);
-            }
-
-            os.newline();
-        }
-    }
-    else
-    {
-        // no idList => perNode
-        forAll(field, i)
-        {
-            if (std::isnan(field[i]))
-            {
-                os.writeUndef();
-            }
-            else
-            {
-                os.write(field[i]);
-            }
-
-            os.newline();
-        }
-    }
-}
-
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-void Foam::ensightPart::reconstruct(Istream& is)
-{
-    dictionary dict(is);
-    dict.lookup("id") >> number_;
-    dict.lookup("name") >> name_;
-
-    offset_ = 0;
-    dict.readIfPresent("offset", offset_);
-
-    // populate elemLists_
-    elemLists_.setSize(elementTypes().size());
-
-    forAll(elementTypes(), elemI)
-    {
-        word key(elementTypes()[elemI]);
-
-        elemLists_[elemI].clear();
-        dict.readIfPresent(key, elemLists_[elemI]);
-
-        size_ += elemLists_[elemI].size();
-    }
-
-    is.check("ensightPart::reconstruct(Istream&)");
-}
-
-
-bool Foam::ensightPart::writeSummary(Ostream& os) const
-{
-    os  << indent << type() << nl
-        << indent << token::BEGIN_BLOCK << incrIndent << nl;
-
-    // Ensight starts with 1
-    os.writeKeyword("id") << (number() + 1) << token::END_STATEMENT << nl;
-    os.writeKeyword("name") << name() << token::END_STATEMENT << nl;
-    os.writeKeyword("offset") << offset() << token::END_STATEMENT << nl;
-    os.writeKeyword("size") << size() << token::END_STATEMENT << nl;
-
-    os  << decrIndent << indent << token::END_BLOCK << nl << endl;
-
-    return true;
-}
-
-
-bool Foam::ensightPart::writeData(Ostream& os) const
-{
-    os  << indent << type() << nl
-        << indent << token::BEGIN_BLOCK << incrIndent << nl;
-
-    os.writeKeyword("id") << number() << token::END_STATEMENT << nl;
-    os.writeKeyword("name") << name() << token::END_STATEMENT << nl;
-    os.writeKeyword("offset") << offset() << token::END_STATEMENT << nl;
-
-    forAll(elementTypes(), typeI)
-    {
-        word key(elementTypes()[typeI]);
-        if (elemLists_[typeI].size())
-        {
-            elemLists_[typeI].writeEntry(key, os);
-        }
-    }
-
-    os  << decrIndent << indent << token::END_BLOCK << nl << endl;
-
-    return true;
-}
-
-
-void Foam::ensightPart::writeGeometry
-(
-    ensightGeoFile& os,
-    const pointField& points
-) const
-{
-    if (size())
-    {
-        const localPoints ptList = calcLocalPoints();
-        const labelUList& pointMap = ptList.list;
-
-        writeHeader(os, true);
-
-        // write points
-        os.writeKeyword("coordinates");
-        os.write(ptList.nPoints);
-        os.newline();
-
-        for (direction cmpt=0; cmpt < point::nComponents; ++cmpt)
-        {
-            forAll(pointMap, ptI)
-            {
-                if (pointMap[ptI] > -1)
-                {
-                    os.write(points[ptI].component(cmpt));
-                    os.newline();
-                }
-            }
-        }
-
-        // write parts
-        forAll(elementTypes(), elemI)
-        {
-            if (elemLists_[elemI].size())
-            {
-                writeConnectivity
-                (
-                    os,
-                    elementTypes()[elemI],
-                    elemLists_[elemI],
-                    pointMap
-                );
-            }
-        }
-    }
-}
-
-
-// * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
-
-Foam::Ostream& Foam::operator<<
-(
-    Ostream& os,
-    const ensightPart& part
-)
-{
-    part.writeData(os);
-    return os;
-}
-
-
-Foam::ensightGeoFile& Foam::operator<<
-(
-    ensightGeoFile& os,
-    const ensightPart& part
-)
-{
-    part.writeGeometry(os);
-    return os;
-}
-
-
-// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightParts.C b/src/conversion/ensight/part/ensightParts.C
index c6f81160686a91cf503e16dfafbb5b4e3e5e7bff..2bcf5b96854c7ffaa8c2ed3fbf3edded80a56c03 100644
--- a/src/conversion/ensight/part/ensightParts.C
+++ b/src/conversion/ensight/part/ensightParts.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.
@@ -29,21 +29,12 @@ License
 
 Foam::ensightParts::ensightParts(const polyMesh& mesh)
 :
-    partsList_()
+    StorageType()
 {
     recalculate(mesh);
 }
 
 
-Foam::ensightParts::ensightParts(const IOobject& ioObj)
-:
-    partsList_()
-{
-    IOPtrList<ensightPart> ioList(ioObj);
-    partsList_.transfer(ioList);
-}
-
-
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 Foam::ensightParts::~ensightParts()
@@ -54,19 +45,9 @@ Foam::ensightParts::~ensightParts()
 
 void Foam::ensightParts::recalculate(const polyMesh& mesh)
 {
-    partsList_.clear();
-
-    // extra space for unzoned cells
-    label nPart =
-    (
-        mesh.cellZones().size()
-      + mesh.boundaryMesh().size()
-      + 1
-    );
-
-    partsList_.setSize(nPart);
-    nPart = 0;
+    StorageType::clear();
 
+    label nPart = 0;
     label nZoneCells = 0;
 
     // do cell zones
@@ -77,13 +58,7 @@ void Foam::ensightParts::recalculate(const polyMesh& mesh)
 
         if (cZone.size())
         {
-            partsList_.set
-            (
-                nPart,
-                new ensightPartCells(nPart, mesh, cZone)
-            );
-
-            nPart++;
+            this->append(new ensightPartCells(nPart++, mesh, cZone));
         }
     }
 
@@ -92,13 +67,7 @@ void Foam::ensightParts::recalculate(const polyMesh& mesh)
     // special case: no zones at all - do entire mesh
     if (nZoneCells == 0)
     {
-        partsList_.set
-        (
-            nPart,
-            new ensightPartCells(nPart, mesh)
-        );
-
-        nPart++;
+        this->append(new ensightPartCells(nPart++, mesh));
     }
     else if (mesh.nCells() > nZoneCells)
     {
@@ -128,13 +97,7 @@ void Foam::ensightParts::recalculate(const polyMesh& mesh)
 
         if (unzoned.size())
         {
-            partsList_.set
-            (
-                nPart,
-                new ensightPartCells(nPart, mesh, unzoned)
-            );
-
-            nPart++;
+            this->append(new ensightPartCells(nPart++, mesh, unzoned));
         }
     }
 
@@ -145,96 +108,41 @@ void Foam::ensightParts::recalculate(const polyMesh& mesh)
         const polyPatch& patch = mesh.boundaryMesh()[patchi];
         if (patch.size() && !isA<processorPolyPatch>(patch))
         {
-            partsList_.set
-            (
-                nPart,
-                new ensightPartFaces(nPart, mesh, patch)
-            );
-
-            nPart++;
+            this->append(new ensightPartFaces(nPart++, mesh, patch));
         }
     }
-
-    // truncate to correct size
-    partsList_.setSize(nPart);
 }
 
 
-void Foam::ensightParts::renumber
-(
-    const labelUList& origCellId,
-    const labelUList& origFaceId
-)
+void Foam::ensightParts::write(ensightGeoFile& os) const
 {
-    forAll(partsList_, partI)
-    {
-        if (partsList_[partI].isCellData())
-        {
-            partsList_[partI].renumber(origCellId);
-        }
-        else
-        {
-            partsList_[partI].renumber(origFaceId);
-        }
-    }
-}
-
+    // Some feedback
+    Info<< "Write geometry part (" << flush;
 
-void Foam::ensightParts::writeGeometry(ensightGeoFile& os) const
-{
-    // with some feedback
-    Info<< "write geometry part (" << flush;
-
-    forAll(partsList_, partI)
+    forAllConstIter(StorageType, *this, iter)
     {
-        Info<< " " << partI << flush;
-        partsList_[partI].writeGeometry(os);
+        Info<< ' ' << (*iter).index() << flush;
+        (*iter).write(os);
     }
     Info<< " )" << endl;
 }
 
 
-bool Foam::ensightParts::writeSummary(Ostream& os) const
+void Foam::ensightParts::writeSummary(Ostream& os) const
 {
-    forAll(partsList_, partI)
+    forAllConstIter(StorageType, *this, iter)
     {
-        partsList_[partI].writeSummary(os);
+        (*iter).writeSummary(os);
     }
-
-    return true;
 }
 
 
-void Foam::ensightParts::writeData(Ostream& os) const
+void Foam::ensightParts::dumpInfo(Ostream& os) const
 {
-    // Begin write list
-    os  << nl << partsList_.size()
-        << nl << token::BEGIN_LIST;
-
-    // Write list contents
-    forAll(partsList_, i)
+    forAllConstIter(StorageType, *this, iter)
     {
-        os  << nl << partsList_[i];
+        (*iter).dumpInfo(os);
     }
-
-    // End write list
-    os  << nl << token::END_LIST << nl;
-
-    // Check state of IOstream
-    os.check("ensightParts::writeData(Ostream&)");
-}
-
-
-// * * * * * * * * * * * * * * * *  IOStream operators * * * * * * * * * * * //
-
-Foam::ensightGeoFile& Foam::operator<<
-(
-    ensightGeoFile& os,
-    const ensightParts& parts
-)
-{
-    parts.writeGeometry(os);
-    return os;
 }
 
 
diff --git a/src/conversion/ensight/part/ensightParts.H b/src/conversion/ensight/part/ensightParts.H
index 84fc47fae99862dcad1bdc6531a20d821e379ddd..e51e53135783c8a1f92df68ba11aac1862440c96 100644
--- a/src/conversion/ensight/part/ensightParts.H
+++ b/src/conversion/ensight/part/ensightParts.H
@@ -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.
@@ -29,13 +29,13 @@ Description
 
 SourceFiles
     ensightParts.C
-    ensightPartsTemplates.C
 
 \*---------------------------------------------------------------------------*/
 
 #ifndef ensightParts_H
 #define ensightParts_H
 
+#include "SLPtrList.H"
 #include "ensightPart.H"
 #include "ensightPartFaces.H"
 #include "ensightPartCells.H"
@@ -46,43 +46,34 @@ SourceFiles
 namespace Foam
 {
 
-// Forward declaration of friend functions and operators
-
-class ensightParts;
-
-ensightGeoFile& operator<<(ensightGeoFile&, const ensightParts&);
-
-
 /*---------------------------------------------------------------------------*\
-                       Class ensightParts Declaration
+                        Class ensightParts Declaration
 \*---------------------------------------------------------------------------*/
 
 class ensightParts
+:
+    public SLPtrList<ensightPart>
 {
-    // Private Data
-
-        //- List of parts
-        PtrList<ensightPart> partsList_;
-
     // Private Member Functions
 
         //- Disallow default bitwise copy construct
-        ensightParts(const ensightParts&);
+        ensightParts(const ensightParts&) = delete;
 
         //- Disallow default bitwise assignment
-        void operator=(const ensightParts&);
+        void operator=(const ensightParts&) = delete;
 
 
 public:
 
+    //- Storage type used
+    typedef SLPtrList<ensightPart> StorageType;
+
+
     // Constructors
 
         //- Construct from polyMesh
         ensightParts(const polyMesh&);
 
-        //- Construct from IOobject
-        ensightParts(const IOobject&);
-
 
     //- Destructor
     ~ensightParts();
@@ -93,41 +84,19 @@ public:
         //- Clear old information and construct anew from polyMesh
         void recalculate(const polyMesh&);
 
-        //- Renumber elements
-        void renumber
-        (
-            const labelUList& origCellId,
-            const labelUList& origFaceId
-        );
-
         //- Number of parts
-        label size() const
-        {
-            return partsList_.size();
-        }
+        using StorageType::size;
+
 
         //- Write the geometry
-        void writeGeometry(ensightGeoFile&) const;
+        void write(ensightGeoFile&) const;
 
         //- Write summary information about the objects
-        bool writeSummary(Ostream&) const;
-
-        //- Write the lists
-        void writeData(Ostream&) const;
+        void writeSummary(Ostream&) const;
 
-        //- Write generalized volume field components
-        template<class Type>
-        void writeField
-        (
-            ensightFile&,
-            const GeometricField<Type, fvPatchField, volMesh>&
-        ) const;
+        //- Print various types of debugging information
+        void dumpInfo(Ostream&) const;
 
-
-    // Friend Operators
-
-        //- Write geometry
-        friend ensightGeoFile& operator<<(ensightGeoFile&, const ensightParts&);
 };
 
 
@@ -137,10 +106,6 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-#ifdef NoRepository
-    #include "ensightPartsTemplates.C"
-#endif
-
 #endif
 
 // ************************************************************************* //
diff --git a/src/fileFormats/Make/files b/src/fileFormats/Make/files
index 642d53dbade4266c5669ba640d92760bb34bb811..c972fde32e70d577dd7bc1f49fcdd51d1e61d8f0 100644
--- a/src/fileFormats/Make/files
+++ b/src/fileFormats/Make/files
@@ -1,3 +1,12 @@
+ensight/file/ensightCase.C
+ensight/file/ensightCaseOptions.C
+ensight/file/ensightFile.C
+ensight/file/ensightGeoFile.C
+ensight/part/ensightCells.C
+ensight/part/ensightFaces.C
+ensight/read/ensightReadFile.C
+ensight/type/ensightPTraits.C
+
 vtk/vtkUnstructuredReader.C
 nas/NASCore.C
 starcd/STARCDCore.C
@@ -8,7 +17,6 @@ setWriters = sampledSetWriters
 
 $(setWriters)/writers.C
 $(setWriters)/ensight/ensightSetWriterRunTime.C
-$(setWriters)/ensight/ensightPTraits.C
 $(setWriters)/gnuplot/gnuplotSetWriterRunTime.C
 $(setWriters)/jplot/jplotSetWriterRunTime.C
 $(setWriters)/raw/rawSetWriterRunTime.C
diff --git a/src/fileFormats/ensight/file/ensightCase.C b/src/fileFormats/ensight/file/ensightCase.C
new file mode 100644
index 0000000000000000000000000000000000000000..dc803f5f990c393b791286dc55b2e5489d9ce57f
--- /dev/null
+++ b/src/fileFormats/ensight/file/ensightCase.C
@@ -0,0 +1,742 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "ensightCase.H"
+#include "stringListOps.H"
+#include "Time.H"
+#include "cloud.H"
+#include "IOmanip.H"
+#include "globalIndex.H"
+
+#include "ensightFile.H"
+#include "ensightGeoFile.H"
+#include "demandDrivenData.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+const char* Foam::ensightCase::dataDirName  = "data";
+const char* Foam::ensightCase::geometryName = "geometry";
+
+
+// * * * * * * * * * * * * * Private Functions * * * * * * * * * * * * * * //
+
+Foam::fileName Foam::ensightCase::dataDir() const
+{
+    return ensightDir_/dataDirName;
+}
+
+
+void Foam::ensightCase::initialize()
+{
+    if (Pstream::master())
+    {
+        // EnSight and EnSight/data directories must exist
+
+        // We may wish to retain old data
+        // eg, convert new results or a particular time interva
+        // OR remove everything
+
+        if (isDir(ensightDir_))
+        {
+            if (options_->overwrite())
+            {
+                Foam::rmDir(ensightDir_);
+            }
+            else
+            {
+                Info<<"Warning: re-using existing directory" << nl
+                    << "    " << ensightDir_ << endl;
+            }
+        }
+
+        // Create ensight and data directories
+        mkDir(dataDir());
+
+        // The case file is always ASCII
+        os_ = new OFstream(ensightDir_/caseName_, IOstream::ASCII);
+
+        // Format options
+        os_->setf(ios_base::left);
+        os_->setf(ios_base::scientific, ios_base::floatfield);
+        os_->precision(5);
+
+        writeHeader();
+    }
+}
+
+
+Foam::label Foam::ensightCase::checkTimeset(const labelHashSet& lookup) const
+{
+    // assume the worst
+    label ts = -1;
+
+    // work on a copy
+    labelHashSet tsTimes(lookup);
+    tsTimes.erase(-1);
+
+    if (tsTimes.empty())
+    {
+        // no times needed
+        ts = 0;
+    }
+    else if (tsTimes.size() == timesUsed_.size())
+    {
+        forAllConstIter(Map<scalar>, timesUsed_, iter)
+        {
+            tsTimes.erase(iter.key());
+        }
+
+        // OR
+        // tsTimes -= timesUsed_.toc();
+        // tsTimes -= timesUsed_;
+
+        if (tsTimes.empty())
+        {
+            ts = 1; // can use timeset 1
+        }
+    }
+
+    return ts;
+}
+
+
+void Foam::ensightCase::writeHeader() const
+{
+    if (os_)  // master only
+    {
+        this->rewind();
+        *os_
+            << "FORMAT" << nl
+            << "type: ensight gold" << nl;
+    }
+}
+
+
+Foam::scalar Foam::ensightCase::writeTimeset() const
+{
+    const label ts = 1;
+
+    const labelList indices = timesUsed_.sortedToc();
+    label count = indices.size();
+
+    // correct for negative starting values
+    scalar timeCorrection = timesUsed_[indices[0]];
+    if (timeCorrection < 0)
+    {
+        timeCorrection = -timeCorrection;
+        Info<< "Correcting time values. Adding " << timeCorrection << endl;
+    }
+    else
+    {
+        timeCorrection = 0;
+    }
+
+
+    *os_
+        << "time set:               " << ts << nl
+        << "number of steps:        " << count << nl;
+
+    if (indices[0] == 0 && indices[count-1] == count-1)
+    {
+        // looks to be contiguous numbering
+        *os_
+            << "filename start number:  " << 0 << nl
+            << "filename increment:     " << 1 << nl;
+    }
+    else
+    {
+        *os_
+            << "filename numbers:" << nl;
+
+        count = 0;
+        forAll(indices, idx)
+        {
+            *os_ << " " << setw(12) << indices[idx];
+
+            if (++count % 6 == 0)
+            {
+                *os_ << nl;
+            }
+        }
+
+        if (count)
+        {
+            *os_ << nl;
+        }
+    }
+
+
+    *os_ << "time values:" << nl;
+
+    count = 0;
+    forAll(indices, idx)
+    {
+        *os_ << " " << setw(12) << timesUsed_[indices[idx]] + timeCorrection;
+
+        if (++count % 6 == 0)
+        {
+            *os_ << nl;
+        }
+    }
+    if (count)
+    {
+        *os_ << nl;
+    }
+
+    return timeCorrection;
+}
+
+
+void Foam::ensightCase::writeTimeset
+(
+    const label ts,
+    const labelHashSet& lookup,
+    const scalar timeCorrection
+) const
+{
+    // make a copy
+    labelHashSet hashed(lookup);
+    hashed.erase(-1);
+
+    const labelList indices = hashed.sortedToc();
+    label count = indices.size();
+
+    *os_
+        << "time set:               " << ts << nl
+        << "number of steps:        " << count  << nl
+        << "filename numbers:" << nl;
+
+    count = 0;
+    forAll(indices, idx)
+    {
+        *os_ << " " << setw(12) << indices[idx];
+
+        if (++count % 6 == 0)
+        {
+            *os_ << nl;
+        }
+    }
+
+    if (count)
+    {
+        *os_ << nl;
+    }
+
+    *os_ << "time values:" << nl;
+
+    count = 0;
+    forAll(indices, idx)
+    {
+        *os_ << " " << setw(12) << timesUsed_[indices[idx]] + timeCorrection;
+
+        if (++count % 6 == 0)
+        {
+            *os_ << nl;
+        }
+    }
+    if (count)
+    {
+        *os_ << nl;
+    }
+}
+
+
+void Foam::ensightCase::noteGeometry(const bool moving) const
+{
+    if (moving)
+    {
+        geomTimes_.insert(timeIndex_);
+    }
+    else
+    {
+        geomTimes_.insert(-1);
+    }
+
+    changed_ = true;
+}
+
+
+void Foam::ensightCase::noteCloud(const word& cloudName) const
+{
+    if (!cloudVars_.found(cloudName))
+    {
+        cloudVars_.insert(cloudName, HashTable<string>());
+    }
+    cloudTimes_.insert(timeIndex_);
+
+    changed_ = true;
+}
+
+
+void Foam::ensightCase::noteCloud
+(
+    const word& cloudName,
+    const word& varName,
+    const char* ensightType
+) const
+{
+    if (cloudVars_.found(cloudName))
+    {
+        if (cloudVars_[cloudName].insert(varName, ensightType))
+        {
+            changed_ = true;
+        }
+    }
+    else
+    {
+        FatalErrorInFunction
+            << "Tried to add a cloud variable for writing without having added a cloud"
+            << abort(FatalError);
+    }
+}
+
+
+void Foam::ensightCase::noteVariable
+(
+    const word& varName,
+    const char* ensightType
+) const
+{
+    if (variables_.insert(varName, ensightType))
+    {
+        changed_ = true;
+    }
+}
+
+
+Foam::autoPtr<Foam::ensightFile>
+Foam::ensightCase::createDataFile
+(
+    const word& name
+) const
+{
+    autoPtr<ensightFile> output;
+
+    if (Pstream::master())
+    {
+        // the data/ITER subdirectory must exist
+        // Note that data/ITER is indeed a valid ensight::FileName
+        const fileName outdir = dataDir()/padded(timeIndex_);
+        mkDir(outdir);
+
+        output.reset(new ensightFile(outdir, name, format()));
+    }
+
+    return output;
+}
+
+
+Foam::autoPtr<Foam::ensightFile>
+Foam::ensightCase::createCloudFile
+(
+    const word& cloudName,
+    const word& name
+) const
+{
+    autoPtr<Foam::ensightFile> output;
+
+    if (Pstream::master())
+    {
+        // Write
+        // eg -> "data/********/lagrangian/<cloudName>/positions"
+        // or -> "lagrangian/<cloudName>/********/positions"
+        // TODO? check that cloudName is a valid ensight filename
+        const fileName outdir =
+        (
+            separateCloud()
+          ? (ensightDir_ / cloud::prefix / cloudName / padded(timeIndex_))
+          : (dataDir() / padded(timeIndex_) / cloud::prefix / cloudName)
+        );
+
+        mkDir(outdir); // should be unnecessary after newCloud()
+
+        output.reset(new ensightFile(outdir, name, format()));
+    }
+
+    return output;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::ensightCase::ensightCase
+(
+    const fileName& ensightDir,
+    const word& caseName,
+    const ensightCase::options& opts
+)
+:
+    options_(new options(opts)),
+    ensightDir_(ensightDir),
+    caseName_(caseName + ".case"),
+    os_(nullptr),
+    changed_(false),
+    timeIndex_(0),
+    timeValue_(0),
+    timesUsed_(),
+    geomTimes_(),
+    cloudTimes_(),
+    variables_(),
+    cloudVars_()
+{
+    initialize();
+}
+
+
+Foam::ensightCase::ensightCase
+(
+    const fileName& ensightDir,
+    const word& caseName,
+    const IOstream::streamFormat format
+)
+:
+    options_(new options(format)),
+    ensightDir_(ensightDir),
+    caseName_(caseName + ".case"),
+    os_(nullptr),
+    changed_(false),
+    timeIndex_(0),
+    timeValue_(0),
+    timesUsed_(),
+    geomTimes_(),
+    cloudTimes_(),
+    variables_(),
+    cloudVars_()
+{
+    initialize();
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::ensightCase::~ensightCase()
+{
+    deleteDemandDrivenData(options_);
+    deleteDemandDrivenData(os_);
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::ensightCase::nextTime(const scalar value)
+{
+    // use next available index
+    setTime(value, timesUsed_.size());
+}
+
+
+void Foam::ensightCase::nextTime(const instant& t)
+{
+    nextTime(t.value());
+}
+
+
+void Foam::ensightCase::setTime(const scalar value, const label index)
+{
+    timeIndex_ = index;
+    timeValue_ = value;
+
+    if (Pstream::master())
+    {
+        // The data/ITER subdirectory must exist
+        // Note that data/ITER is indeed a valid ensight::FileName
+
+        const fileName outdir = dataDir()/padded(timeIndex_);
+        mkDir(outdir);
+
+        // place a timestamp in the directory for future reference
+        OFstream timeStamp(outdir/"time");
+        timeStamp
+            << "#  index  time" << nl
+            << outdir.name() << ' ' << timeValue_ << nl;
+    }
+
+    // Record of time index/value used
+    timesUsed_.set(index, value);
+}
+
+
+void Foam::ensightCase::setTime(const instant& t, const label index)
+{
+    setTime(t.value(), index);
+}
+
+
+void Foam::ensightCase::write() const
+{
+    if (!os_) return; // master only
+
+    // geometry timeset
+    bool staticGeom = (geomTimes_.size() == 1 && geomTimes_.found(-1));
+    label tsGeom = staticGeom ? 0 : checkTimeset(geomTimes_);
+
+    // cloud timeset
+    label tsCloud = checkTimeset(cloudTimes_);
+
+    // increment time-sets to the correct indices
+    if (tsGeom < 0)
+    {
+        tsGeom = 2;             // next available timeset
+    }
+    if (tsCloud < 0)
+    {
+        tsCloud = tsGeom + 1;   // next available timeset
+    }
+
+    writeHeader();
+
+
+    // data mask: eg "data/******"
+    const fileName dataMask = (dataDirName/mask());
+
+    //
+    // GEOMETRY
+    //
+    if (!geomTimes_.empty() || !cloudTimes_.empty())
+    {
+        // start of variables
+        *os_
+            << nl
+            << "GEOMETRY" << nl;
+    }
+
+    if (staticGeom)
+    {
+        // steady
+        *os_
+            << setw(16)  << "model:"
+            << geometryName
+            << nl;
+    }
+    else if (!geomTimes_.empty())
+    {
+        // moving
+        *os_
+            << Foam::name("model: %-9d", tsGeom)        // width 16
+            << (dataMask/geometryName).c_str()
+            << nl;
+    }
+
+    // clouds and cloud variables
+    const wordList cloudNames = cloudVars_.sortedToc();
+    forAll(cloudNames, cloudNo)
+    {
+        const word& cloudName = cloudNames[cloudNo];
+
+        const fileName masked =
+        (
+            separateCloud()
+          ? (cloud::prefix / cloudName / mask())
+          : (dataMask / cloud::prefix / cloudName)
+        );
+
+        *os_
+            << Foam::name("measured: %-6d", tsCloud)    // width 16
+            << (masked/"positions").c_str()
+            << nl;
+    }
+
+
+    //
+    // VARIABLE
+    //
+    if (variables_.size() || cloudVars_.size())
+    {
+        // start of variables
+        *os_
+            << nl
+            << "VARIABLE" << nl;
+    }
+
+
+    // field variables (always use timeset 1)
+    const wordList varNames = variables_.sortedToc();
+    forAll(varNames, vari)
+    {
+        const word&   varName = varNames[vari];
+        const string& ensType = variables_[varName];
+
+        *os_
+            << ensType.c_str()
+            <<
+            (
+                nodeValues()
+              ? " per node:    1  "  // time-set 1
+              : " per element: 1  "  // time-set 1
+            )
+            << setw(15) << varName << ' '
+            << (dataMask/varName).c_str() << nl;
+    }
+
+
+    // clouds and cloud variables (using cloud timeset)
+    // Write
+    // as -> "data/********/lagrangian/<cloudName>/positions"
+    // or -> "lagrangian/<cloudName>/********/positions"
+    forAll(cloudNames, cloudNo)
+    {
+        const word& cloudName = cloudNames[cloudNo];
+        const fileName masked =
+        (
+            separateCloud()
+          ? (cloud::prefix / cloudName / mask())
+          : (dataMask / cloud::prefix / cloudName)
+        );
+
+        const HashTable<string>& vars = cloudVars_[cloudName];
+        const wordList tocVars = vars.sortedToc();
+
+        forAll(tocVars, vari)
+        {
+            const word&   varName = tocVars[vari];
+            const string& ensType = vars[varName];
+
+            // prefix variables with 'c' (cloud) and cloud index
+            *os_
+                << ensType.c_str() << " per "
+                << Foam::name("measured node: %-5d", tsCloud) // width 20
+                << setw(15)
+                << ("c" + Foam::name(cloudNo) + varName).c_str() << ' '
+                << (masked/varName).c_str()
+                << nl;
+        }
+    }
+
+
+    //
+    // TIME
+    //
+
+    if (!timesUsed_.empty())
+    {
+        *os_
+            << nl << "TIME" << nl;
+
+        // timeset 1
+        const scalar timeCorrection = writeTimeset();
+
+        // timeset geometry
+        if (tsGeom > 1)
+        {
+            writeTimeset(tsGeom, geomTimes_, timeCorrection);
+        }
+
+        // timeset cloud
+        if (tsCloud > 1)
+        {
+            writeTimeset(tsCloud, cloudTimes_, timeCorrection);
+        }
+
+        *os_
+            << "# end" << nl;
+    }
+
+    *os_ << flush;
+    changed_ = false;
+}
+
+
+Foam::autoPtr<Foam::ensightGeoFile>
+Foam::ensightCase::newGeometry
+(
+    const bool moving
+) const
+{
+    autoPtr<Foam::ensightGeoFile> output;
+
+    if (Pstream::master())
+    {
+        // set the path of the ensight file
+        fileName path;
+
+        if (moving)
+        {
+            // Moving mesh: write as "data/********/geometry"
+            path = dataDir()/padded(timeIndex_);
+            mkDir(path);
+        }
+        else
+        {
+            // Static mesh: write as "geometry"
+            path = ensightDir_;
+        }
+
+        output.reset(new ensightGeoFile(path, geometryName, format()));
+
+        noteGeometry(moving);   // note for later use
+    }
+
+    return output;
+}
+
+
+Foam::autoPtr<Foam::ensightFile>
+Foam::ensightCase::newCloud
+(
+    const word& cloudName
+) const
+{
+    autoPtr<Foam::ensightFile> output;
+
+    if (Pstream::master())
+    {
+        output = createCloudFile(cloudName, "positions");
+
+        // tag binary format (just like geometry files)
+        output().writeBinaryHeader();
+
+        // description
+        output().write(cloud::prefix/cloudName);
+        output().newline();
+
+        noteCloud(cloudName);   // note for later use
+    }
+
+    return output;
+}
+
+
+void Foam::ensightCase::rewind() const
+{
+    if (os_)  // master only
+    {
+        os_->stdStream().seekp(0, std::ios_base::beg);
+    }
+}
+
+
+Foam::Ostream& Foam::ensightCase::printInfo(Ostream& os) const
+{
+    os  << "Ensight case:" << nl
+        << "   path: "   << ensightDir_ << nl
+        << "   name: "   << caseName_   << nl
+        << "   format: " << format()    << nl
+        << "   values per " << (nodeValues() ? "node" : "element") << nl;
+
+    return os;
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/ensight/file/ensightCase.H b/src/fileFormats/ensight/file/ensightCase.H
new file mode 100644
index 0000000000000000000000000000000000000000..e6603d9a104e85a76c8d5258def631282f7c4b21
--- /dev/null
+++ b/src/fileFormats/ensight/file/ensightCase.H
@@ -0,0 +1,405 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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/>.
+
+Class
+    Foam::ensightCase
+
+Description
+    Supports writing of ensight cases as well as providing common factory
+    methods to open new files.
+
+SourceFiles
+    ensightCase.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ensightCase_H
+#define ensightCase_H
+
+#include "autoPtr.H"
+#include "HashSet.H"
+#include "InfoProxy.H"
+#include "Map.H"
+#include "OSspecific.H"
+#include "Pstream.H"
+
+#include "ensightGeoFile.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declarations
+class ensightCase;
+class instant;
+class Time;
+
+/*---------------------------------------------------------------------------*\
+                         Class ensightCase Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightCase
+{
+public:
+
+    // Forward declarations
+    class options;
+
+    // Public Data
+
+        //- The name for "data" subdirectory
+        static const char* dataDirName;
+
+        //- The name for geometry files
+        static const char* geometryName;
+
+private:
+
+    // Private data
+
+        //- Case writing options
+        const options* options_;
+
+        //- Output path (absolute)
+        fileName ensightDir_;
+
+        //- Case name (with ".case" ending)
+        word caseName_;
+
+        //- Output stream
+        mutable OFstream* os_;
+
+        //- Track state changes since last write
+        mutable bool changed_;
+
+        //- Time index (timeset 1)
+        label timeIndex_;
+
+        //- Time value (timeset 1)
+        scalar timeValue_;
+
+        //- Record of time index/value used (eg, field values).
+        //  These values will be used for timeset 1.
+        Map<scalar> timesUsed_;
+
+        //- 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.
+        mutable labelHashSet geomTimes_;
+
+        //- Record time indices when clouds are written.
+        //  These values will be used to decide if timeset 1
+        //  or a separate timeset are used.
+        mutable labelHashSet cloudTimes_;
+
+        //- Fields/Variables with the ensight type
+        mutable HashTable<string> variables_;
+
+        //- Cloud names and variables
+        mutable HashTable<HashTable<string>> cloudVars_;
+
+
+    // Private Member Functions
+
+        //- The data directory
+        fileName dataDir() const;
+
+        //- Initial file management (master only)
+        void initialize();
+
+        //- Check if timeset uses different times than from time-set 1
+        label checkTimeset(const labelHashSet& lookup) const;
+
+        //- Write the header into the case file.
+        void writeHeader() const;
+
+        //- Write the timeset 1 into the case file.
+        //  Return the time correction in effect
+        scalar writeTimeset() const;
+
+        //- Write the timeset into the case file.
+        void writeTimeset
+        (
+            const label ts,
+            const labelHashSet& lookup,
+            const scalar timeCorrection = 0
+        ) const;
+
+
+        //- Note geometry being used
+        void noteGeometry(const bool moving) const;
+
+        //- Note cloud being used
+        void noteCloud(const word& cloudName) const;
+
+        //- Note cloud/variable being used
+        void noteCloud
+        (
+            const word& cloudName,
+            const word& varName,
+            const char* ensightType
+        ) const;
+
+        //- Note field variable being used
+        void noteVariable
+        (
+            const word& varName,
+            const char* ensightType
+        ) const;
+
+
+        //- Open stream for new data file (on master), using the current index.
+        //  File is without initial description lines.
+        autoPtr<ensightFile> createDataFile(const word&) const;
+
+        //- Open stream for new cloud file (on master).
+        //  File is without initial description lines.
+        autoPtr<ensightFile> createCloudFile
+        (
+            const word& cloudName,
+            const word& name
+        ) const;
+
+
+        //- Disallow default bitwise copy construct
+        ensightCase(const ensightCase&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const ensightCase&) = delete;
+
+
+public:
+
+
+    // Constructors
+
+        //- Construct from components
+        ensightCase
+        (
+            const fileName& ensightDir,
+            const word& caseName,
+            const options& opts
+        );
+
+        //- Construct from components with all default options
+        ensightCase
+        (
+            const fileName& ensightDir,
+            const word& caseName,
+            const IOstream::streamFormat format = IOstream::BINARY
+        );
+
+
+
+    //- Destructor
+    ~ensightCase();
+
+
+    // Member Functions
+
+    // Access
+
+        //- Reference to the case options
+        inline const ensightCase::options& option() const;
+
+        //- Ascii/Binary file output
+        inline IOstream::streamFormat format() const;
+
+        //- The nominal path to the case file
+        inline const fileName& path() const;
+
+        //- The output '*' mask
+        inline const word& mask() const;
+
+        //- Consistent zero-padded integer value
+        inline word padded(const label i) const;
+
+        //- Use values per nodes instead of per element
+        inline bool nodeValues() const;
+
+        //- Write clouds into their own directory instead in "data" directory
+        inline bool separateCloud() const;
+
+
+    // Edit
+
+        //- Set time for time-set 1, using next available index.
+        //  Create corresponding sub-directory.
+        //  Do not mix between nextTime and setTime in an application.
+        void nextTime(const scalar t);
+
+        //- Set time for time-set 1, using next available index.
+        //  Create corresponding sub-directory.
+        //  Do not mix between nextTime and setTime in an application.
+        void nextTime(const instant& t);
+
+        //- Set current index and time for time-set 1.
+        //  Create corresponding sub-directory
+        //  Do not mix between nextTime and setTime in an application.
+        void setTime(const scalar t, const label index);
+
+        //- Set current index and time for time-set 1.
+        //  Create corresponding sub-directory
+        //  Do not mix between nextTime and setTime in an application.
+        void setTime(const instant& t, const label index);
+
+
+    // Addition of entries to case file
+
+        //- Open stream for new geometry file (on master).
+        autoPtr<ensightGeoFile> newGeometry(const bool moving = false) const;
+
+
+        //- Open stream for new cloud positions (on master).
+        //  Note the use of ensightFile, not ensightGeoFile.
+        autoPtr<ensightFile> newCloud
+        (
+            const word& cloudName
+        ) const;
+
+
+        //- Open stream for new data file (on master), using the current index.
+        template<class Type>
+        autoPtr<ensightFile> newData(const word& varName) const;
+
+
+        //- Open stream for new cloud data file (on master), using the current index.
+        template<class Type>
+        autoPtr<ensightFile> newCloudData
+        (
+            const word& cloudName,
+            const word& varName
+        ) const;
+
+
+    // Output
+
+        //- Rewind the output stream (master only).
+        void rewind() const;
+
+        //- Write the case file
+        void write() const;
+
+        //- Output stream (master only).
+        inline Ostream& operator()() const;
+
+        //- Print some general information.
+        Ostream& printInfo(Ostream&) const;
+};
+
+
+//- Configuration options for the ensightCase
+class ensightCase::options
+{
+private:
+
+    //- Ascii/Binary file output
+    IOstream::streamFormat format_;
+
+    //- Width of mask for subdirectories
+    label width_;
+
+    //- The '*' mask appropriate for subdirectories
+    word mask_;
+
+    //- The printf format for zero-padded subdirectory numbers
+    string printf_;
+
+    //- Remove existing directory and sub-directories on creation
+    bool overwrite_;
+
+    //- Write values at nodes
+    bool nodeValues_;
+
+    //- Write clouds into their own directory
+    bool separateCloud_;
+
+public:
+
+    // Constructors
+
+        //- Construct with the specified format (default is binary)
+        options(IOstream::streamFormat format = IOstream::BINARY);
+
+
+    // Member Functions
+
+    // Access
+
+        //- Ascii/Binary file output
+        IOstream::streamFormat format() const;
+
+        //- The '*' mask appropriate for sub-directories
+        const word& mask() const;
+
+        //- Consistent zero-padded integer value
+        word padded(const label i) const;
+
+        //- Return current width of mask and padded.
+        label width() const;
+
+        //- Remove existing directory and sub-directories on creation
+        bool overwrite() const;
+
+        //- Use values per nodes instead of per element
+        bool nodeValues() const;
+
+        //- Write clouds into their own directory instead in "data" directory
+        bool separateCloud() const;
+
+
+    // Edit
+
+        //- Set width of mask and padded.
+        //  Default width is 8 digits, max width is 31 digits.
+        void width(const label i);
+
+        //- Remove existing directory and sub-directories on creation
+        void overwrite(bool);
+
+        //- Use values per nodes instead of per element
+        void nodeValues(bool);
+
+        //- Write clouds into their own directory instead in "data" directory
+        void separateCloud(bool);
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "ensightCaseI.H"
+
+#ifdef NoRepository
+    #include "ensightCaseTemplates.C"
+#endif
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/faceSets.H b/src/fileFormats/ensight/file/ensightCaseI.H
similarity index 59%
rename from applications/utilities/postProcessing/dataConversion/foamToEnsight/faceSets.H
rename to src/fileFormats/ensight/file/ensightCaseI.H
index 8b09bc7f39f789d0f2667b3e028699f2ed24f264..b386f677b5b6e596b8d076d0bb3f08975f2adc96 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/faceSets.H
+++ b/src/fileFormats/ensight/file/ensightCaseI.H
@@ -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) 2016 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -21,58 +21,58 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
-Class
-    Foam::faceSets
+\*---------------------------------------------------------------------------*/
 
-Description
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-\*---------------------------------------------------------------------------*/
+inline const Foam::ensightCase::options& Foam::ensightCase::option() const
+{
+    return *options_;
+}
 
-#ifndef faceSets_H
-#define faceSets_H
 
-#include "labelList.H"
+inline Foam::IOstream::streamFormat Foam::ensightCase::format() const
+{
+    return options_->format();
+}
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-namespace Foam
+inline const Foam::fileName& Foam::ensightCase::path() const
 {
+    return ensightDir_;
+}
 
-/*---------------------------------------------------------------------------*\
-                           Class faceSets Declaration
-\*---------------------------------------------------------------------------*/
 
-class faceSets
+inline const Foam::word& Foam::ensightCase::mask() const
 {
-public:
+    return options_->mask();
+}
 
-        label nTris;
-        label nQuads;
-        label nPolys;
 
-        labelList tris;
-        labelList quads;
-        labelList polys;
+inline Foam::word Foam::ensightCase::padded(const label i) const
+{
+    return options_->padded(i);
+}
 
 
-    // Constructors
+inline bool Foam::ensightCase::nodeValues() const
+{
+    return options_->nodeValues();
+}
 
-        //- Construct null
-        faceSets()
-        :
-            nTris(0),
-            nQuads(0),
-            nPolys(0)
-        {}
-};
 
+inline bool Foam::ensightCase::separateCloud() const
+{
+    return options_->separateCloud();
+}
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-} // End namespace Foam
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+inline Foam::Ostream& Foam::ensightCase::operator()() const
+{
+    return *os_;
+}
 
-#endif
 
 // ************************************************************************* //
diff --git a/src/fileFormats/ensight/file/ensightCaseOptions.C b/src/fileFormats/ensight/file/ensightCaseOptions.C
new file mode 100644
index 0000000000000000000000000000000000000000..7977334466c94fe98d43bf0aa6b38489a6fb0adc
--- /dev/null
+++ b/src/fileFormats/ensight/file/ensightCaseOptions.C
@@ -0,0 +1,129 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "ensightCase.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::ensightCase::options::options(IOstream::streamFormat format)
+:
+    format_(format),
+    width_(0),
+    mask_(),
+    printf_(),
+    overwrite_(false),
+    nodeValues_(false),
+    separateCloud_(false)
+{
+    width(8); // ensures that the mask and printf-format are also resized
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::IOstream::streamFormat Foam::ensightCase::options::format() const
+{
+    return format_;
+}
+
+const Foam::word& Foam::ensightCase::options::mask() const
+{
+    return mask_;
+}
+
+
+Foam::word Foam::ensightCase::options::padded(const label i) const
+{
+    // As per Foam::name, but with fixed length
+    char buf[32];
+
+    ::snprintf(buf, 32, printf_.c_str(), i);
+    buf[31] = 0;
+
+    // no stripping required
+    return word(buf, false);
+}
+
+
+Foam::label Foam::ensightCase::options::width() const
+{
+    return width_;
+}
+
+
+void Foam::ensightCase::options::width(const label n)
+{
+    // enforce min/max sanity limits
+    if (n < 1 || n > 31)
+    {
+        return;
+    }
+
+    // set mask accordingly
+    mask_.resize(n, '*');
+
+    // appropriate printf format
+    printf_ = "%0" + Foam::name(n) + "d";
+}
+
+
+
+bool Foam::ensightCase::options::overwrite() const
+{
+    return overwrite_;
+}
+
+
+void Foam::ensightCase::options::overwrite(bool b)
+{
+    overwrite_ = b;
+}
+
+
+bool Foam::ensightCase::options::nodeValues() const
+{
+    return nodeValues_;
+}
+
+
+void Foam::ensightCase::options::nodeValues(bool b)
+{
+    nodeValues_ = b;
+}
+
+
+bool Foam::ensightCase::options::separateCloud() const
+{
+    return separateCloud_;
+}
+
+
+void Foam::ensightCase::options::separateCloud(bool b)
+{
+    separateCloud_ = b;
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/ensight/file/ensightCaseTemplates.C b/src/fileFormats/ensight/file/ensightCaseTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..48d7c03ec37e28de08a134aefded863721cd9869
--- /dev/null
+++ b/src/fileFormats/ensight/file/ensightCaseTemplates.C
@@ -0,0 +1,99 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "cloud.H"
+#include "ensightPTraits.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+
+template<class Type>
+Foam::autoPtr<Foam::ensightFile>
+Foam::ensightCase::newData
+(
+    const word& name
+) const
+{
+    autoPtr<ensightFile> output;
+
+    if (Pstream::master())
+    {
+        const ensight::VarName varName(name);
+        output = createDataFile(varName);
+
+        // description
+        output().write
+        (
+            string
+            (
+                padded(timeIndex_) / varName
+              + " <" + pTraits<Type>::typeName + ">"
+            )
+        );
+        output().newline();
+
+        // note variable for later use
+        noteVariable(varName, ensightPTraits<Type>::typeName);
+    }
+
+    return output;
+}
+
+
+template<class Type>
+Foam::autoPtr<Foam::ensightFile>
+Foam::ensightCase::newCloudData
+(
+    const word& cloudName,
+    const word& name
+) const
+{
+    autoPtr<Foam::ensightFile> output;
+
+    if (Pstream::master())
+    {
+        const ensight::VarName varName(name);
+        output = createCloudFile(cloudName, varName);
+
+        // description
+        output().write
+        (
+            string
+            (
+                padded(timeIndex_) / cloudName / varName
+              + " <" + pTraits<Type>::typeName + ">"
+            )
+        );
+        output().newline();
+
+        // note cloud variable for later use
+        noteCloud(cloudName, varName, ensightPTraits<Type>::typeName);
+    }
+
+    return output;
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/file/ensightFile.C b/src/fileFormats/ensight/file/ensightFile.C
similarity index 84%
rename from src/conversion/ensight/file/ensightFile.C
rename to src/fileFormats/ensight/file/ensightFile.C
index 05003b2a0029dc54cb5661ecfc6ee04c1e4dbc3a..b106c6ecf4cbc22b7b6577929ef7a45bbfd9fab2 100644
--- a/src/conversion/ensight/file/ensightFile.C
+++ b/src/fileFormats/ensight/file/ensightFile.C
@@ -25,6 +25,7 @@ License
 
 #include "ensightFile.H"
 #include "error.H"
+#include "UList.H"
 
 #include <cstring>
 #include <sstream>
@@ -307,4 +308,76 @@ Foam::Ostream& Foam::ensightFile::writeBinaryHeader()
 }
 
 
+//
+// Convenience Output Methods
+//
+
+void Foam::ensightFile::beginPart(const label index)
+{
+    write("part");
+    newline();
+    write(index+1); // Ensight starts with 1
+    newline();
+}
+
+
+void Foam::ensightFile::beginParticleCoordinates(const label nparticles)
+{
+    write("particle coordinates");
+    newline();
+    write(nparticles, 8); // unusual width
+    newline();
+}
+
+
+void Foam::ensightFile::writeList
+(
+    const UList<scalar>& field
+)
+{
+    forAll(field, i)
+    {
+        if (std::isnan(field[i]))
+        {
+            writeUndef();
+        }
+        else
+        {
+            write(field[i]);
+        }
+
+        newline();
+    }
+}
+
+
+void Foam::ensightFile::writeList
+(
+    const UList<scalar>& field,
+    const labelUList& idList
+)
+{
+    if (notNull(idList))
+    {
+        forAll(idList, i)
+        {
+            if (idList[i] >= field.size() || std::isnan(field[idList[i]]))
+            {
+                writeUndef();
+            }
+            else
+            {
+                write(field[idList[i]]);
+            }
+
+            newline();
+        }
+    }
+    else
+    {
+        // no idList => perNode
+        writeList(field);
+    }
+}
+
 // ************************************************************************* //
diff --git a/src/conversion/ensight/file/ensightFile.H b/src/fileFormats/ensight/file/ensightFile.H
similarity index 85%
rename from src/conversion/ensight/file/ensightFile.H
rename to src/fileFormats/ensight/file/ensightFile.H
index 03cbdcd7032503bb33039ffc9d879ead298ab2d1..78b09904e10bb6429004f55a9ea84c84509ceb45 100644
--- a/src/conversion/ensight/file/ensightFile.H
+++ b/src/fileFormats/ensight/file/ensightFile.H
@@ -38,6 +38,7 @@ Description
 
 #include "ensightFileName.H"
 #include "ensightVarName.H"
+#include "UList.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -80,9 +81,13 @@ class ensightFile
 
 public:
 
-    // Forward declarations
-    class FileName;
-    class VarName;
+    // Static Member Functions
+
+        //- Return a null ensightFile
+        inline static const ensightFile& null()
+        {
+            return NullObjectRef<ensightFile>();
+        }
 
 
     // Constructors
@@ -172,6 +177,28 @@ public:
 
         //- Add carriage return to ascii stream
         void newline();
+
+
+    // Convenience Output Methods
+
+        //- Begin a part (0-based index).
+        void beginPart(const label index);
+
+        //- Begin a "particle coordinates" block (measured data)
+        void beginParticleCoordinates(const label nparticles);
+
+        //- Write a list of floats as "%12.5e" or as binary
+        //  With carriage return after each value (ascii stream)
+        void writeList(const UList<scalar>& field);
+
+        //- Write an indirect list of scalars as "%12.5e" or as binary
+        //  With carriage return after each value (ascii stream)
+        void writeList
+        (
+            const UList<scalar>& field,
+            const labelUList& idList
+        );
+
 };
 
 
diff --git a/src/conversion/ensight/file/ensightGeoFile.C b/src/fileFormats/ensight/file/ensightGeoFile.C
similarity index 76%
rename from src/conversion/ensight/file/ensightGeoFile.C
rename to src/fileFormats/ensight/file/ensightGeoFile.C
index 0119087e70f9dd17f8c009991a02ed20eeb88d92..27ce98282f764efd8d83adf4022c2ddd1955fb1a 100644
--- a/src/conversion/ensight/file/ensightGeoFile.C
+++ b/src/fileFormats/ensight/file/ensightGeoFile.C
@@ -35,17 +35,25 @@ License
 
 void Foam::ensightGeoFile::initialize()
 {
+    writeBinaryHeader();
+
+    // Description line 1
+    write("Ensight Geometry File");
+    newline();
+
+    // Description line 2
     #ifdef OPENFOAM_PLUS
-    string desc2("Written by OpenFOAM+ " STRING_QUOTE(OPENFOAM_PLUS));
+    write(string("Written by OpenFOAM+ " STRING_QUOTE(OPENFOAM_PLUS)));
     #else
-    string desc2("Written by OpenFOAM-" + string(Foam::FOAMversion));
+    write(string("Written by OpenFOAM-" + string(Foam::FOAMversion)));
     #endif
 
-    writeBinaryHeader();
-    write("Ensight Geometry File");  newline(); // description line 1
-    write(desc2);                    newline(); // description line 2
-    write("node id assign");         newline();
-    write("element id assign");      newline();
+    newline();
+    write("node id assign");
+    newline();
+
+    write("element id assign");
+    newline();
 }
 
 
@@ -87,10 +95,36 @@ Foam::ensightGeoFile::~ensightGeoFile()
 Foam::Ostream& Foam::ensightGeoFile::writeKeyword(const keyType& key)
 {
     // ensure we get ensightFile::write(const string&)
-    write(static_cast<const string&>(key)); newline();
+    write(static_cast<const string&>(key));
+    newline();
 
     return *this;
 }
 
 
+//
+// Convenience Output Methods
+//
+
+void Foam::ensightGeoFile::beginPart
+(
+    const label index,
+    const string& description
+)
+{
+    beginPart(index);
+    write(description);
+    newline();
+}
+
+
+void Foam::ensightGeoFile::beginCoordinates(const label npoints)
+{
+    write("coordinates");
+    newline();
+    write(npoints);
+    newline();
+}
+
+
 // ************************************************************************* //
diff --git a/src/conversion/ensight/file/ensightGeoFile.H b/src/fileFormats/ensight/file/ensightGeoFile.H
similarity index 85%
rename from src/conversion/ensight/file/ensightGeoFile.H
rename to src/fileFormats/ensight/file/ensightGeoFile.H
index 75cef26cd98407f5df7554c8e8c7ada04b37cc75..6b60c6e419554e12a5c4bfb404bd2493c06f95cc 100644
--- a/src/conversion/ensight/file/ensightGeoFile.H
+++ b/src/fileFormats/ensight/file/ensightGeoFile.H
@@ -61,6 +61,15 @@ class ensightGeoFile
 
 public:
 
+    // Static Member Functions
+
+        //- Return a null ensightGeoFile
+        inline static const ensightGeoFile& null()
+        {
+            return NullObjectRef<ensightGeoFile>();
+        }
+
+
     // Constructors
 
         //- Construct from pathname.
@@ -89,6 +98,18 @@ public:
 
         //- Write keyword with trailing newline
         virtual Ostream& writeKeyword(const keyType& key);
+
+
+    // Convenience Output Methods
+
+        using ensightFile::beginPart;
+
+        //- Begin a "part" (0-based index), with a description.
+        void beginPart(const label index, const string& description);
+
+        //- Begin a "coordinates" block
+        void beginCoordinates(const label npoints);
+
 };
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/conversion/ensight/name/ensightFileName.H b/src/fileFormats/ensight/name/ensightFileName.H
similarity index 88%
rename from src/conversion/ensight/name/ensightFileName.H
rename to src/fileFormats/ensight/name/ensightFileName.H
index 550a86f68c4d7745bcea4611358f24c47ebcaeb7..1452730107ae2772e89bf972f2ead996cc1c74d5 100644
--- a/src/conversion/ensight/name/ensightFileName.H
+++ b/src/fileFormats/ensight/name/ensightFileName.H
@@ -28,7 +28,7 @@ Description
     Specification of a valid Ensight file-name.
 
     Spaces must be quoted,
-    no '*' wildcards, not '%' (structured block continuation).
+    no '*' wildcards, no '%' (structured block continuation).
 
     Overall line length within case file is limited to 1024, but this is not
     yet addresssed.
@@ -80,15 +80,16 @@ public:
         //- Is this character valid for an ensight file-name
         inline static bool valid(char);
 
+
     // Member operators
 
-        // Assignment
+    // Assignment (disabled)
 
-            void operator=(const fileName&) = delete;
-            void operator=(const word&) = delete;
-            void operator=(const string&) = delete;
-            void operator=(const std::string&) = delete;
-            void operator=(const char*) = delete;
+        void operator=(const fileName&) = delete;
+        void operator=(const word&) = delete;
+        void operator=(const string&) = delete;
+        void operator=(const std::string&) = delete;
+        void operator=(const char*) = delete;
 
 };
 
diff --git a/src/conversion/ensight/name/ensightFileNameI.H b/src/fileFormats/ensight/name/ensightFileNameI.H
similarity index 100%
rename from src/conversion/ensight/name/ensightFileNameI.H
rename to src/fileFormats/ensight/name/ensightFileNameI.H
diff --git a/src/conversion/ensight/name/ensightVarName.H b/src/fileFormats/ensight/name/ensightVarName.H
similarity index 92%
rename from src/conversion/ensight/name/ensightVarName.H
rename to src/fileFormats/ensight/name/ensightVarName.H
index fe2c57aefbf50812b36e107c790c3e28a14db959..2ffff6ae193f930adeb188716cbdd38dee2c0cf9 100644
--- a/src/conversion/ensight/name/ensightVarName.H
+++ b/src/fileFormats/ensight/name/ensightVarName.H
@@ -63,10 +63,8 @@ class VarName
         //- Strip invalid characters
         inline void stripInvalid();
 
-
 public:
 
-
     // Constructors
 
         //- Construct as copy
@@ -87,12 +85,11 @@ public:
 
     // Member operators
 
-        // Assignment
-
-            void operator=(const word&) = delete;
-            void operator=(const string&) = delete;
-            void operator=(const std::string&) = delete;
-            void operator=(const char*) = delete;
+    // Assignment (disabled)
+        void operator=(const word&) = delete;
+        void operator=(const string&) = delete;
+        void operator=(const std::string&) = delete;
+        void operator=(const char*) = delete;
 
 };
 
diff --git a/src/conversion/ensight/name/ensightVarNameI.H b/src/fileFormats/ensight/name/ensightVarNameI.H
similarity index 100%
rename from src/conversion/ensight/name/ensightVarNameI.H
rename to src/fileFormats/ensight/name/ensightVarNameI.H
diff --git a/src/fileFormats/ensight/part/ensightCells.C b/src/fileFormats/ensight/part/ensightCells.C
new file mode 100644
index 0000000000000000000000000000000000000000..8db55a927ab557891357aa8726d9cfb3e0b8484d
--- /dev/null
+++ b/src/fileFormats/ensight/part/ensightCells.C
@@ -0,0 +1,288 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "ensightCells.H"
+#include "error.H"
+#include "polyMesh.H"
+#include "cellModeller.H"
+#include "demandDrivenData.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+const Foam::label Foam::ensightCells::nTypes = 5;
+
+namespace Foam
+{
+    template<>
+    const char* Foam::NamedEnum
+    <
+        Foam::ensightCells::elemType,
+        5
+    >::names[] = { "tetra4", "pyramid5", "penta6", "hexa8", "nfaced" };
+}
+
+const Foam::NamedEnum<Foam::ensightCells::elemType, 5>
+    Foam::ensightCells::elemEnum;
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+inline Foam::label Foam::ensightCells::offset
+(
+    const enum elemType what,
+    const label i
+) const
+{
+    label n = i;
+    for (label typeI = 0; typeI < label(what); ++typeI)
+    {
+        n += sizes_[typeI];
+    }
+
+    return n;
+}
+
+
+void Foam::ensightCells::resize()
+{
+    // overall required size
+    label n = 0;
+    forAll(sizes_, typeI)
+    {
+        n += sizes_[typeI];
+    }
+    address_.setSize(n, Zero);
+
+    // assign corresponding sub-lists
+    n = 0;
+    forAll(sizes_, typeI)
+    {
+        deleteDemandDrivenData(lists_[typeI]);
+
+        lists_[typeI] = new SubList<label>(address_, sizes_[typeI], n);
+
+        n += sizes_[typeI];
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::ensightCells::ensightCells(const label partIndex)
+:
+    index_(partIndex),
+    address_(),
+    sizes_(Zero),
+    lists_()
+{
+    // Ensure sub-lists are properly initialized to nullptr
+    forAll(lists_, typeI)
+    {
+        lists_[typeI] = nullptr;
+    }
+
+    resize();   // adjust allocation
+}
+
+
+Foam::ensightCells::ensightCells(const ensightCells& obj)
+:
+    index_(obj.index_),
+    address_(obj.address_),
+    sizes_(),
+    lists_()
+{
+    // Ensure sub-lists are properly initialized to nullptr
+    forAll(lists_, typeI)
+    {
+        lists_[typeI] = nullptr;
+    }
+
+    // Total (reduced) sizes
+    FixedList<label, 5> totSizes = obj.sizes_;
+
+    // Local sizes
+    this->sizes_ = obj.sizes();
+
+    resize();   // adjust allocation
+
+    // Restore total (reduced) sizes
+    this->sizes_ = totSizes;
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::ensightCells::~ensightCells()
+{
+    forAll(lists_, typeI)
+    {
+        deleteDemandDrivenData(lists_[typeI]);
+    }
+    address_.clear();
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::FixedList<Foam::label, 5> Foam::ensightCells::sizes() const
+{
+    FixedList<label, 5> count;
+    forAll(lists_, typeI)
+    {
+        count[typeI] = lists_[typeI]->size();
+    }
+
+    return count;
+}
+
+
+Foam::label Foam::ensightCells::total() const
+{
+    label n = 0;
+    forAll(sizes_, typeI)
+    {
+        n += sizes_[typeI];
+    }
+    return n;
+}
+
+
+void Foam::ensightCells::clear()
+{
+    sizes_ = Zero;  // reset sizes
+    resize();
+}
+
+
+void Foam::ensightCells::reduce()
+{
+    forAll(sizes_, typeI)
+    {
+        sizes_[typeI] = lists_[typeI]->size();
+        Foam::reduce(sizes_[typeI], sumOp<label>());
+    }
+}
+
+
+void Foam::ensightCells::sort()
+{
+    forAll(lists_, typeI)
+    {
+        if (lists_[typeI])
+        {
+            Foam::sort(*(lists_[typeI]));
+        }
+    }
+}
+
+
+void Foam::ensightCells::classify
+(
+    const polyMesh& mesh,
+    const labelUList& addressing
+)
+{
+    // References to cell shape models
+    const cellModel& tet   = *(cellModeller::lookup("tet"));
+    const cellModel& pyr   = *(cellModeller::lookup("pyr"));
+    const cellModel& prism = *(cellModeller::lookup("prism"));
+    const cellModel& hex   = *(cellModeller::lookup("hex"));
+
+    const cellShapeList& shapes = mesh.cellShapes();
+
+    const bool indirect = notNull(addressing);
+    const label sz = indirect ? addressing.size() : mesh.nCells();
+
+    // Count the shapes
+    // Can avoid double looping, but only at the expense of allocation
+
+    sizes_ = Zero;  // reset sizes
+    for (label listI = 0; listI < sz; ++listI)
+    {
+        const label id = indirect ? addressing[listI] : listI;
+        const cellModel& model = shapes[id].model();
+
+        enum elemType what = NFACED;
+        if (model == tet)
+        {
+            what = TETRA4;
+        }
+        else if (model == pyr)
+        {
+            what = PYRAMID5;
+        }
+        else if (model == prism)
+        {
+            what = PENTA6;
+        }
+        else if (model == hex)
+        {
+            what = HEXA8;
+        }
+
+        sizes_[what]++;
+    }
+
+    resize();       // adjust allocation
+    sizes_ = Zero;  // reset sizes
+
+    // Assign cell-id per shape type
+    for (label listI = 0; listI < sz; ++listI)
+    {
+        const label id = indirect ? addressing[listI] : listI;
+        const cellModel& model = shapes[id].model();
+
+        enum elemType what = NFACED;
+        if (model == tet)
+        {
+            what = TETRA4;
+        }
+        else if (model == pyr)
+        {
+            what = PYRAMID5;
+        }
+        else if (model == prism)
+        {
+            what = PENTA6;
+        }
+        else if (model == hex)
+        {
+            what = HEXA8;
+        }
+
+        // eg, the processor local cellId
+        lists_[what]->operator[](sizes_[what]++) = id;
+    }
+}
+
+
+Foam::label Foam::ensightCells::offset(const enum elemType what) const
+{
+    return offset(what, 0);
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/ensight/part/ensightCells.H b/src/fileFormats/ensight/part/ensightCells.H
new file mode 100644
index 0000000000000000000000000000000000000000..a84de2ce9c27ea66951c84932976f079b8e20b42
--- /dev/null
+++ b/src/fileFormats/ensight/part/ensightCells.H
@@ -0,0 +1,206 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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/>.
+
+Class
+    Foam::ensightCells
+
+Description
+    Sorting/classification of cells (3D) into corresponding ensight element
+    types.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ensightCells_H
+#define ensightCells_H
+
+#include "labelList.H"
+#include "FixedList.H"
+#include "SubList.H"
+#include "NamedEnum.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+class polyMesh;
+
+/*---------------------------------------------------------------------------*\
+                        Class ensightCells Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightCells
+{
+public:
+
+    // Public data
+
+        //- Addressable ensight element types
+        enum elemType
+        {
+            TETRA4,
+            PYRAMID5,
+            PENTA6,
+            HEXA8,
+            NFACED
+        };
+
+        //- Number of element types (5)
+        static const label nTypes;
+
+        //- The Ensight names for each element type
+        static const NamedEnum<elemType, 5> elemEnum;
+
+
+    // Static Member Functions
+
+        //- Return the ensight element name for the specified type
+        inline static const char* key(const enum elemType);
+
+
+private:
+
+    // Private data
+
+        //- Location within a list.
+        //  The ensight part number is typically this value +1.
+        label index_;
+
+        //- Linear list of ids, sub-sectioned per element type via SubLists
+        labelList address_;
+
+        //- List of sizes for each element type
+        FixedList<label, 5> sizes_;
+
+        //- List of ids for each element type
+        //  Managed via pointers, since a SubList cannot be relocated/resized.
+        FixedList<SubList<label>*, 5> lists_;
+
+
+    // Private Member Functions
+
+        //- Low-level offset routine
+        inline label offset(const enum elemType what, const label i) const;
+
+        //- Use current sizes to redimension the element lists
+        void resize();
+
+        //- Disallow default bitwise assignment
+        void operator=(const ensightCells&) = delete;
+
+
+public:
+
+    // Constructors
+
+        //- Construct null, optionally with index
+        ensightCells(label partIndex = 0);
+
+        //- Copy constructor. Needed for lists etc.
+        ensightCells(const ensightCells&);
+
+
+    //- Destructor
+    ~ensightCells();
+
+
+    // Member Functions
+
+    // Access
+
+        //- The index in a list.
+        inline label index() const;
+
+        //- The index in a list, non-const access.
+        inline label& index();
+
+        //- The processor local size of all elements.
+        inline label size() const;
+
+        //- The global number of the specified element type.
+        //  This value is only meaningful after a reduce operation.
+        inline label total(const enum elemType) const;
+
+        //- The global number of all element types.
+        //  This value is only meaningful after a reduce operation.
+        label total() const;
+
+        //- The processor local sizes per element type.
+        FixedList<label, 5> sizes() const;
+
+        //- The global numbers per element type.
+        //  This value is only meaningful after a reduce operation.
+        inline const FixedList<label, 5>& totals() const;
+
+
+        //- Return the (local) cell ids of the specified element type
+        inline const labelUList& cellIds(const enum elemType) const;
+
+        //- Return the cell ids of all elements
+        inline const labelUList& cellIds() const;
+
+        //- Starting offset of element type.
+        label offset(const enum elemType what) const;
+
+
+    // Edit
+
+        //- Classify cell types and set the element lists.
+        //  The optional indirect addressing can be used when classifying
+        //  groups of cells (eg, from a cellZone etc).
+        void classify
+        (
+            const polyMesh&,
+            const labelUList& addressing = labelUList::null()
+        );
+
+
+        //- Set addressable sizes to zero, free up addressing memory.
+        void clear();
+
+        //- Sum element counts across all processes.
+        void reduce();
+
+        //- Sort element lists numerically.
+        void sort();
+
+
+    // Member operators
+
+        //- Return id from linear list of addressing.
+        inline label operator[](const label i) const;
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "ensightCellsI.H"
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/fileFormats/ensight/part/ensightCellsI.H b/src/fileFormats/ensight/part/ensightCellsI.H
new file mode 100644
index 0000000000000000000000000000000000000000..88e016832220ff94ee17033a2da7d06be4adc51e
--- /dev/null
+++ b/src/fileFormats/ensight/part/ensightCellsI.H
@@ -0,0 +1,95 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "error.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+inline const char* Foam::ensightCells::key(const enum elemType what)
+{
+    return elemEnum[what];
+}
+
+
+inline Foam::label Foam::ensightCells::index() const
+{
+    return index_;
+}
+
+
+inline Foam::label& Foam::ensightCells::index()
+{
+    return index_;
+}
+
+
+inline Foam::label Foam::ensightCells::size() const
+{
+    return address_.size();
+}
+
+
+inline const Foam::FixedList<Foam::label,5>& Foam::ensightCells::totals() const
+{
+    return sizes_;
+}
+
+
+inline Foam::label Foam::ensightCells::total(const enum elemType what) const
+{
+    return sizes_[what];
+}
+
+
+inline const Foam::labelUList& Foam::ensightCells::cellIds
+(
+    const enum elemType what
+) const
+{
+    if (!lists_[what])
+    {
+        FatalErrorInFunction
+            << "Accessing unallocated sublist for elem-type: "
+            << elemEnum[what]
+            << exit(FatalError);
+    }
+
+    return *(lists_[what]);
+}
+
+
+inline const Foam::labelUList& Foam::ensightCells::cellIds() const
+{
+    return address_;
+}
+
+
+inline Foam::label Foam::ensightCells::operator[](const label i) const
+{
+    return address_[i];
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/ensight/part/ensightFaces.C b/src/fileFormats/ensight/part/ensightFaces.C
new file mode 100644
index 0000000000000000000000000000000000000000..e1e67153fdb6206d9dc69fe1b963816df376e74b
--- /dev/null
+++ b/src/fileFormats/ensight/part/ensightFaces.C
@@ -0,0 +1,363 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "ensightFaces.H"
+#include "error.H"
+#include "polyMesh.H"
+#include "ListOps.H"
+#include "demandDrivenData.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+const Foam::label Foam::ensightFaces::nTypes = 3;
+
+namespace Foam
+{
+    template<>
+    const char* Foam::NamedEnum
+    <
+        Foam::ensightFaces::elemType,
+        3
+    >::names[] = { "tria3", "quad4", "nsided" };
+}
+
+const Foam::NamedEnum<Foam::ensightFaces::elemType, 3>
+    Foam::ensightFaces::elemEnum;
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+// only used in this file-scope
+inline Foam::ensightFaces::elemType
+Foam::ensightFaces::whatType(const face& f)
+{
+    return
+    (
+        f.size() == 3
+      ? Foam::ensightFaces::elemType::TRIA3
+      : f.size() == 4
+      ? Foam::ensightFaces::elemType::QUAD4
+      : Foam::ensightFaces::elemType::NSIDED
+    );
+}
+
+
+// only used in this file-scope
+inline void Foam::ensightFaces::add
+(
+    const face& f,
+    const label id,
+    const bool flip
+)
+{
+    const enum elemType what = whatType(f);
+
+    label n = sizes_[what]++;
+    lists_[what]->operator[](n) = id;
+
+    if (flipMap_.size())
+    {
+        flipMap_[offset(what, n)] = flip;
+    }
+}
+
+
+// only used in this file-scope
+inline Foam::label Foam::ensightFaces::offset
+(
+    const enum elemType what,
+    const label i
+) const
+{
+    label n = i;
+    for (label typeI = 0; typeI < label(what); ++typeI)
+    {
+        n += sizes_[typeI];
+    }
+
+    return n;
+}
+
+
+void Foam::ensightFaces::resize()
+{
+    // overall required size
+    label n = 0;
+    forAll(sizes_, typeI)
+    {
+        n += sizes_[typeI];
+    }
+    address_.setSize(n, Zero);
+
+    // assign corresponding sub-lists
+    n = 0;
+    forAll(sizes_, typeI)
+    {
+        deleteDemandDrivenData(lists_[typeI]);
+
+        lists_[typeI] = new SubList<label>(address_, sizes_[typeI], n);
+
+        n += sizes_[typeI];
+    }
+
+    // normally assume no flipMap
+    flipMap_.clear();
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::ensightFaces::ensightFaces(label partIndex)
+:
+    index_(partIndex),
+    address_(),
+    flipMap_(),
+    sizes_(Zero),
+    lists_()
+{
+    // Ensure sub-lists are properly initialized to nullptr
+    forAll(lists_, typeI)
+    {
+        lists_[typeI] = nullptr;
+    }
+
+    resize();   // adjust allocation
+}
+
+
+Foam::ensightFaces::ensightFaces(const ensightFaces& obj)
+:
+    index_(obj.index_),
+    address_(obj.address_),
+    flipMap_(obj.flipMap_),
+    sizes_(),
+    lists_()
+{
+    // Ensure sub-lists are properly initialized to nullptr
+    forAll(lists_, typeI)
+    {
+        lists_[typeI] = nullptr;
+    }
+
+    // Total (reduced) sizes
+    FixedList<label, 3> totSizes = obj.sizes_;
+
+    // Local sizes
+    this->sizes_ = obj.sizes();
+
+    resize();   // adjust allocation
+
+    // Restore total (reduced) sizes
+    this->sizes_ = totSizes;
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::ensightFaces::~ensightFaces()
+{
+    forAll(lists_, typeI)
+    {
+        deleteDemandDrivenData(lists_[typeI]);
+    }
+    address_.clear();
+    flipMap_.clear();
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::FixedList<Foam::label, 3> Foam::ensightFaces::sizes() const
+{
+    FixedList<label, 3> count;
+    forAll(lists_, typeI)
+    {
+        count[typeI] = lists_[typeI]->size();
+    }
+
+    return count;
+}
+
+
+Foam::label Foam::ensightFaces::total() const
+{
+    label n = 0;
+    forAll(sizes_, typeI)
+    {
+        n += sizes_[typeI];
+    }
+    return n;
+}
+
+
+void Foam::ensightFaces::clear()
+{
+    sizes_ = Zero;  // reset sizes
+    resize();
+}
+
+
+void Foam::ensightFaces::reduce()
+{
+    forAll(sizes_, typeI)
+    {
+        sizes_[typeI] = lists_[typeI]->size();
+        Foam::reduce(sizes_[typeI], sumOp<label>());
+    }
+}
+
+
+void Foam::ensightFaces::sort()
+{
+    if (flipMap_.size() == address_.size())
+    {
+        // sort flip too
+
+        labelList order;
+        label start = 0;
+
+        forAll(lists_, typeI)
+        {
+            if (lists_[typeI])
+            {
+                SubList<label>& idLst = *(lists_[typeI]);
+                const label sz = idLst.size();
+
+                if (sz)
+                {
+                    SubList<bool> flip(flipMap_, sz, start);
+                    start += sz; // for next sub-list
+
+                    sortedOrder(idLst, order);
+
+                    idLst = reorder<labelList>(order, idLst);
+                    flip  = reorder<boolList>(order,  flip);
+                }
+            }
+        }
+    }
+    else
+    {
+        // no flip-maps, simpler to sort
+        forAll(lists_, typeI)
+        {
+            if (lists_[typeI])
+            {
+                SubList<label>& idLst = *(lists_[typeI]);
+                const label sz = idLst.size();
+                if (sz)
+                {
+                    Foam::sort(idLst);
+                }
+            }
+        }
+    }
+}
+
+
+void Foam::ensightFaces::classify(const faceList& faces)
+{
+    const label sz = faces.size();
+
+    // Count the shapes
+    // Can avoid double looping, but only at the expense of allocation
+
+    sizes_ = Zero;  // reset sizes
+    for (label listI = 0; listI < sz; ++listI)
+    {
+        const enum elemType what = whatType(faces[listI]);
+        sizes_[what]++;
+    }
+
+    resize();       // adjust allocation
+    sizes_ = Zero;  // reset sizes
+
+    // Assign face-id per shape type
+    for (label listI = 0; listI < sz; ++listI)
+    {
+        add(faces[listI], listI);
+    }
+}
+
+
+void Foam::ensightFaces::classify
+(
+    const faceList& faces,
+    const labelUList& addressing,
+    const boolList& flipMap,
+    const PackedBoolList& exclude
+)
+{
+    // Note: Since PackedList::operator[] returns zero (false) for out-of-range
+    // indices, can skip our own bounds checking here.
+
+    const label sz = addressing.size();
+    const bool useFlip = (addressing.size() == flipMap.size());
+
+    // Count the shapes
+    // Can avoid double looping, but only at the expense of allocation
+
+    sizes_ = Zero;  // reset sizes
+    for (label listI = 0; listI < sz; ++listI)
+    {
+        const label faceId = addressing[listI];
+
+        if (!exclude[faceId])
+        {
+            const enum elemType what = whatType(faces[faceId]);
+            sizes_[what]++;
+        }
+    }
+
+    resize();       // adjust allocation
+    sizes_ = Zero;  // reset sizes
+
+    if (useFlip)
+    {
+        flipMap_.setSize(address_.size(), false);
+        flipMap_ = false;
+    }
+
+    // Assign face-id per shape type
+    for (label listI = 0; listI < sz; ++listI)
+    {
+        const label faceId = addressing[listI];
+        const bool flip = useFlip && flipMap[listI];
+
+        if (!exclude[faceId])
+        {
+            add(faces[faceId], faceId, flip);
+        }
+    }
+}
+
+
+Foam::label Foam::ensightFaces::offset(const enum elemType what) const
+{
+    return offset(what, 0);
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/ensight/part/ensightFaces.H b/src/fileFormats/ensight/part/ensightFaces.H
new file mode 100644
index 0000000000000000000000000000000000000000..dfb16859c0732da4edb5efa1b54231da46978a46
--- /dev/null
+++ b/src/fileFormats/ensight/part/ensightFaces.H
@@ -0,0 +1,225 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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/>.
+
+Class
+    Foam::ensightFaces
+
+Description
+    Sorting/classification of faces (2D) into corresponding ensight types
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ensightFaces_H
+#define ensightFaces_H
+
+#include "boolList.H"
+#include "labelList.H"
+#include "faceList.H"
+#include "FixedList.H"
+#include "PackedBoolList.H"
+#include "NamedEnum.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class ensightFaces Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightFaces
+{
+public:
+
+    // Public data
+
+        //- Addressable ensight element types
+        enum elemType
+        {
+            TRIA3,
+            QUAD4,
+            NSIDED
+        };
+
+        //- Number of element types (3)
+        static const label nTypes;
+
+        //- The Ensight names for each element type
+        static const NamedEnum<elemType, 3> elemEnum;
+
+
+    // Static Member Functions
+
+        //- Return the ensight element name for the specified type
+        static inline const char* key(const enum elemType);
+
+
+private:
+
+    // Private data
+
+        //- Location within a list.
+        //  The ensight part number is typically this value +1.
+        label index_;
+
+        //- Linear list of ids, sub-sectioned per element type via SubLists
+        labelList address_;
+
+        //- Linear list of face-flips
+        boolList flipMap_;
+
+        //- List of global sizes for each element type
+        FixedList<label, 3> sizes_;
+
+        //- SubLists of ids for each element type.
+        //  Managed via pointers, since a SubList cannot be relocated/resized.
+        FixedList<SubList<label>*, 3> lists_;
+
+
+    // Private Member Functions
+
+        //- Simple classifier
+        inline static elemType whatType(const face&);
+
+        //- Low-level addition routine
+        inline void add(const face&, const label id, const bool flip = false);
+
+        //- Low-level offset routine
+        inline label offset(const enum elemType what, const label i) const;
+
+        //- Use current sizes to redimension the element lists
+        void resize();
+
+        //- Disallow default bitwise assignment
+        void operator=(const ensightFaces&) = delete;
+
+
+public:
+
+    // Constructors
+
+        //- Construct null, optionally with index
+        ensightFaces(label partIndex = 0);
+
+        //- Copy constructor. Needed for lists etc.
+        ensightFaces(const ensightFaces&);
+
+
+    //- Destructor
+    ~ensightFaces();
+
+
+    // Member Functions
+
+    // Access
+
+        //- The index in a list.
+        inline label index() const;
+
+        //- The index in a list, non-const access.
+        inline label& index();
+
+        //- The processor local size of all elements.
+        inline label size() const;
+
+        //- The global number of the specified element type.
+        //  This value is only meaningful after a reduce operation.
+        inline label total(const enum elemType) const;
+
+        //- The global number of all element types.
+        //  This value is only meaningful after a reduce operation.
+        label total() const;
+
+
+        //- The processor local sizes per element type.
+        FixedList<label, 3> sizes() const;
+
+        //- The global numbers per element type.
+        //  This value is only meaningful after a reduce operation.
+        const FixedList<label, 3>& totals() const;
+
+
+        //- Return the (local) face ids of the specified element type
+        inline const labelUList& faceIds(const enum elemType) const;
+
+        //- Return the face ids of all elements
+        inline const labelUList& faceIds() const;
+
+        //- Return the flip-map of all elements
+        inline const boolList& flipMap() const;
+
+
+        //- Starting offset of element type.
+        label offset(const enum elemType what) const;
+
+
+    // Edit
+
+        //- Classify the face types, set element list.
+        void classify(const faceList& faces);
+
+
+        //- Classify the face types, set element list.
+        //  The indirect addressing can be used when classifying groups of
+        //  face (eg, from a faceZone etc) with an optional flipMap.
+        //  The optional exclude marker can be used to skip faces on particular
+        //  boundary types or regions.
+        void classify
+        (
+            const faceList& faces,
+            const labelUList& addressing,
+            const boolList& flipMap = boolList(),
+            const PackedBoolList& exclude = PackedBoolList()
+        );
+
+
+        //- Set addressable sizes to zero, free up addressing memory.
+        void clear();
+
+        //- Sum element counts across all processes.
+        void reduce();
+
+        //- Sort element lists numerically.
+        void sort();
+
+
+    // Member operators
+
+        //- Return element from linear-list.
+        inline label operator[](const label i) const;
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "ensightFacesI.H"
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/fileFormats/ensight/part/ensightFacesI.H b/src/fileFormats/ensight/part/ensightFacesI.H
new file mode 100644
index 0000000000000000000000000000000000000000..4b32a373dbe23082fde720b58a3c6568396fca68
--- /dev/null
+++ b/src/fileFormats/ensight/part/ensightFacesI.H
@@ -0,0 +1,101 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "error.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+inline const char* Foam::ensightFaces::key(const enum elemType what)
+{
+    return elemEnum[what];
+}
+
+
+inline Foam::label Foam::ensightFaces::index() const
+{
+    return index_;
+}
+
+
+inline Foam::label& Foam::ensightFaces::index()
+{
+    return index_;
+}
+
+
+inline Foam::label Foam::ensightFaces::size() const
+{
+    return address_.size();
+}
+
+
+inline const Foam::FixedList<Foam::label,3>& Foam::ensightFaces::totals() const
+{
+    return sizes_;
+}
+
+
+inline Foam::label Foam::ensightFaces::total(const enum elemType what) const
+{
+    return sizes_[what];
+}
+
+
+inline const Foam::labelUList& Foam::ensightFaces::faceIds
+(
+    const enum elemType what
+) const
+{
+    if (!lists_[what])
+    {
+        FatalErrorInFunction
+            << "Accessing unallocated sublist for elem-type: "
+            << elemEnum[what]
+            << exit(FatalError);
+    }
+
+    return *(lists_[what]);
+}
+
+
+inline const Foam::labelUList& Foam::ensightFaces::faceIds() const
+{
+    return address_;
+}
+
+
+inline const Foam::boolList& Foam::ensightFaces::flipMap() const
+{
+    return flipMap_;
+}
+
+
+inline Foam::label Foam::ensightFaces::operator[](const label i) const
+{
+    return address_[i];
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/readFile/ensightReadFile.C b/src/fileFormats/ensight/read/ensightReadFile.C
similarity index 100%
rename from src/conversion/ensight/readFile/ensightReadFile.C
rename to src/fileFormats/ensight/read/ensightReadFile.C
diff --git a/src/conversion/ensight/readFile/ensightReadFile.H b/src/fileFormats/ensight/read/ensightReadFile.H
similarity index 100%
rename from src/conversion/ensight/readFile/ensightReadFile.H
rename to src/fileFormats/ensight/read/ensightReadFile.H
diff --git a/src/fileFormats/sampledSetWriters/ensight/ensightPTraits.C b/src/fileFormats/ensight/type/ensightPTraits.C
similarity index 77%
rename from src/fileFormats/sampledSetWriters/ensight/ensightPTraits.C
rename to src/fileFormats/ensight/type/ensightPTraits.C
index bf29a96820d70ccf36fac64c36a6817f0fdb7f92..a6b70129af593741cf9382e8878be3629a9968c6 100644
--- a/src/fileFormats/sampledSetWriters/ensight/ensightPTraits.C
+++ b/src/fileFormats/ensight/type/ensightPTraits.C
@@ -28,56 +28,51 @@ License
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
 template<>
-const char* const Foam::ensightPTraits<Foam::scalar>::typeName =
-    Foam::pTraits<Foam::scalar>::typeName;
+const char* const
+Foam::ensightPTraits<Foam::scalar>::typeName = "scalar";
 
 template<>
 const Foam::direction
 Foam::ensightPTraits<Foam::scalar>::componentOrder[] = {0};
 
+
 template<>
-const char* const Foam::ensightPTraits<Foam::vector>::typeName =
-    Foam::pTraits<Foam::vector>::typeName;
+const char* const
+Foam::ensightPTraits<Foam::vector>::typeName = "vector";
 
 template<>
 const Foam::direction
 Foam::ensightPTraits<Foam::vector>::componentOrder[] = {0, 1, 2};
 
+
+// use mag(sphericalTensor) instead
 template<>
-const char* const Foam::ensightPTraits<Foam::sphericalTensor>::typeName =
-    Foam::pTraits<Foam::scalar>::typeName;
+const char* const
+Foam::ensightPTraits<Foam::sphericalTensor>::typeName = "scalar";
+
 
 template<>
 const Foam::direction
 Foam::ensightPTraits<Foam::sphericalTensor>::componentOrder[] = {0};
 
 template<>
-const char* const Foam::ensightPTraits<Foam::symmTensor>::typeName =
-    "tensor symm";
+const char* const
+Foam::ensightPTraits<Foam::symmTensor>::typeName = "tensor symm";
 
 
 template<>
 const Foam::direction
 Foam::ensightPTraits<Foam::symmTensor>::componentOrder[] = {0, 3, 5, 1, 2, 4};
 
+
 template<>
-const char* const Foam::ensightPTraits<Foam::tensor>::typeName =
-    "tensor asym";
+const char* const
+Foam::ensightPTraits<Foam::tensor>::typeName = "tensor asym";
 
 template<>
 const Foam::direction
 Foam::ensightPTraits<Foam::tensor>::componentOrder[] =
-{
-    0,
-    1,
-    2,
-    3,
-    4,
-    5,
-    6,
-    7,
-    8
-};
+    { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
 
 
 // ************************************************************************* //
diff --git a/src/fileFormats/sampledSetWriters/ensight/ensightPTraits.H b/src/fileFormats/ensight/type/ensightPTraits.H
similarity index 100%
rename from src/fileFormats/sampledSetWriters/ensight/ensightPTraits.H
rename to src/fileFormats/ensight/type/ensightPTraits.H
diff --git a/src/functionObjects/field/blendingFactor/blendingFactor.C b/src/functionObjects/field/blendingFactor/blendingFactor.C
index f631b7e851ec9a0a8333d7fb2993301b2ca1b63e..3861e809a2d0382108fcd105a326233164d7b4b9 100644
--- a/src/functionObjects/field/blendingFactor/blendingFactor.C
+++ b/src/functionObjects/field/blendingFactor/blendingFactor.C
@@ -114,6 +114,7 @@ Foam::functionObjects::blendingFactor::~blendingFactor()
 bool Foam::functionObjects::blendingFactor::read(const dictionary& dict)
 {
     fieldExpression::read(dict);
+    writeFile::read(dict);
 
     phiName_ = dict.lookupOrDefault<word>("phi", "phi");
     dict.readIfPresent("tolerance", tolerance_);
diff --git a/src/functionObjects/field/externalCoupled/externalCoupled.C b/src/functionObjects/field/externalCoupled/externalCoupled.C
index 727aa595f5d2302cc6a2cb7e05c56c2b15b1f758..999e311f202ce4c9092d4ff5e1e06a453f154aae 100644
--- a/src/functionObjects/field/externalCoupled/externalCoupled.C
+++ b/src/functionObjects/field/externalCoupled/externalCoupled.C
@@ -936,37 +936,33 @@ bool Foam::functionObjects::externalCoupled::read(const dictionary& dict)
     }
 
 
-    // Print a bit
-    if (log)
+    Info<< type() << ": Communicating with regions:" << endl;
+    forAll(regionGroupNames_, rgi)
     {
-        Info<< type() << ": Communicating with regions:" << endl;
-        forAll(regionGroupNames_, rgi)
-        {
-            //const wordList& regionNames = regionGroupRegions_[rgi];
-            const word& compName = regionGroupNames_[rgi];
+        //const wordList& regionNames = regionGroupRegions_[rgi];
+        const word& compName = regionGroupNames_[rgi];
 
-            Info<< "Region: " << compName << endl << incrIndent;
-            const labelList& groups = regionToGroups_[compName];
-            forAll(groups, i)
-            {
-                label groupi = groups[i];
-                const wordRe& groupName = groupNames_[groupi];
+        Info<< "Region: " << compName << endl << incrIndent;
+        const labelList& groups = regionToGroups_[compName];
+        forAll(groups, i)
+        {
+            label groupi = groups[i];
+            const wordRe& groupName = groupNames_[groupi];
 
-                Info<< indent << "patchGroup: " << groupName << "\t"
-                    << endl
-                    << incrIndent
-                    << indent << "Reading fields: "
-                    << groupReadFields_[groupi]
-                    << endl
-                    << indent << "Writing fields: "
-                    << groupWriteFields_[groupi]
-                    << endl
-                    << decrIndent;
-            }
-            Info<< decrIndent;
+            Info<< indent << "patchGroup: " << groupName << "\t"
+                << endl
+                << incrIndent
+                << indent << "Reading fields: "
+                << groupReadFields_[groupi]
+                << endl
+                << indent << "Writing fields: "
+                << groupWriteFields_[groupi]
+                << endl
+                << decrIndent;
         }
-        Info<< endl;
+        Info<< decrIndent;
     }
+    Info<< endl;
 
 
     // Note: we should not have to make directories since the geometry
diff --git a/src/functionObjects/field/fieldAverage/fieldAverage.C b/src/functionObjects/field/fieldAverage/fieldAverage.C
index d7cd691bf224be836685d70b21da89c5d8287e24..46c30fbc973859f7faa505f2072aff4badb523f2 100644
--- a/src/functionObjects/field/fieldAverage/fieldAverage.C
+++ b/src/functionObjects/field/fieldAverage/fieldAverage.C
@@ -108,8 +108,7 @@ void Foam::functionObjects::fieldAverage::initialize()
 
 void Foam::functionObjects::fieldAverage::restart()
 {
-    Log
-        << "    Restarting averaging at time " << obr_.time().timeName()
+    Log << "    Restarting averaging at time " << obr_.time().timeName()
         << nl << endl;
 
     totalIter_.clear();
@@ -159,8 +158,7 @@ void Foam::functionObjects::fieldAverage::calcAverages()
         restart();
     }
 
-    Log
-        << type() << " " << name() << " write:" << nl
+    Log << type() << " " << name() << " write:" << nl
         << "    Calculating averages" << nl;
 
     addMeanSqrToPrime2Mean<scalar, scalar>();
@@ -221,14 +219,14 @@ void Foam::functionObjects::fieldAverage::readAveragingProperties()
     totalTime_.clear();
     totalTime_.setSize(faItems_.size(), obr_.time().deltaTValue());
 
-    if ((restartOnRestart_ || restartOnOutput_) && log)
+    if (restartOnRestart_ || restartOnOutput_)
     {
         Info<< "    Starting averaging at time " << obr_.time().timeName()
             << nl;
     }
     else
     {
-        Log << "    Restarting averaging for fields:" << nl;
+        Info<< "    Restarting averaging for fields:" << nl;
 
 
         forAll(faItems_, fieldi)
@@ -242,15 +240,13 @@ void Foam::functionObjects::fieldAverage::readAveragingProperties()
                 totalIter_[fieldi] = readLabel(fieldDict.lookup("totalIter"));
                 totalTime_[fieldi] = readScalar(fieldDict.lookup("totalTime"));
 
-                Log
-                    << "        " << fieldName
+                Info<< "        " << fieldName
                     << " iters = " << totalIter_[fieldi]
                     << " time = " << totalTime_[fieldi] << nl;
             }
             else
             {
-                Log
-                    << "        " << fieldName
+                Info<< "        " << fieldName
                     << ": starting averaging at time "
                     << obr_.time().timeName() << endl;
             }
@@ -299,7 +295,7 @@ bool Foam::functionObjects::fieldAverage::read(const dictionary& dict)
 
     initialised_ = false;
 
-    Log << type() << " " << name() << ":" << nl;
+    Info<< type() << " " << name() << ":" << nl;
 
     dict.readIfPresent("restartOnRestart", restartOnRestart_);
     dict.readIfPresent("restartOnOutput", restartOnOutput_);
@@ -309,8 +305,7 @@ bool Foam::functionObjects::fieldAverage::read(const dictionary& dict)
     if (periodicRestart_)
     {
         dict.lookup("restartPeriod") >> restartPeriod_;
-        Log
-            << "    Restart period " << restartPeriod_
+        Info<< "    Restart period " << restartPeriod_
             << nl << endl;
     }
 
@@ -324,15 +319,14 @@ bool Foam::functionObjects::fieldAverage::read(const dictionary& dict)
         }
         else
         {
-            Log
-                << "    Restart scheduled at time " << restartTime_
+            Info<< "    Restart scheduled at time " << restartTime_
                 << nl << endl;
         }
     }
 
     readAveragingProperties();
 
-    Log << endl;
+    Info<< endl;
 
     return true;
 }
diff --git a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C
index 4d16100f9212601fb387cdca1eb0485b2c5975a7..c9aabb275c4653da6204d7014bc30eaeca1ac207 100644
--- a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C
+++ b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C
@@ -60,7 +60,7 @@ fieldCoordinateSystemTransform
 {
     read(dict);
 
-    Log << type() << " " << name << ":" << nl
+    Info<< type() << " " << name << ":" << nl
         << "   Applying transformation from global Cartesian to local "
         << coordSys_ << nl << endl;
 }
diff --git a/src/functionObjects/field/fieldMinMax/fieldMinMax.C b/src/functionObjects/field/fieldMinMax/fieldMinMax.C
index 5c6f4f4d6af66c8c35ec7c1199a48753ccf40892..c2f6b643a6333f72891d7a480bc2179dded645a0 100644
--- a/src/functionObjects/field/fieldMinMax/fieldMinMax.C
+++ b/src/functionObjects/field/fieldMinMax/fieldMinMax.C
@@ -122,6 +122,7 @@ Foam::functionObjects::fieldMinMax::~fieldMinMax()
 bool Foam::functionObjects::fieldMinMax::read(const dictionary& dict)
 {
     fvMeshFunctionObject::read(dict);
+    writeFile::read(dict);
 
     location_ = dict.lookupOrDefault<Switch>("location", true);
 
diff --git a/src/functionObjects/field/fieldValues/fieldValueDelta/fieldValueDelta.C b/src/functionObjects/field/fieldValues/fieldValueDelta/fieldValueDelta.C
index 90010c4669e97062a2698e1ab6144ac0411ac69a..ca24bdad368348cce2d594a8c14ea327cd21bb27 100644
--- a/src/functionObjects/field/fieldValues/fieldValueDelta/fieldValueDelta.C
+++ b/src/functionObjects/field/fieldValues/fieldValueDelta/fieldValueDelta.C
@@ -128,7 +128,6 @@ bool Foam::functionObjects::fieldValues::fieldValueDelta::read
 )
 {
     fvMeshFunctionObject::read(dict);
-
     writeFile::read(dict);
 
     region1Ptr_.reset
@@ -210,9 +209,9 @@ bool Foam::functionObjects::fieldValues::fieldValueDelta::write()
         applyOperation<symmTensor>(type1, name1, name2, entry1, entry2, found);
         applyOperation<tensor>(type1, name1, name2, entry1, entry2, found);
 
-        if (log && !found)
+        if (!found)
         {
-            Info<< "Operation between "
+            Log << "Operation between "
                 << name1 << " with result " << entry1 << " and "
                 << name2 << " with result " << entry2 << " not applied"
                 << endl;
diff --git a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C
index 907d365d5c97ff67b0751a263d095cd3f57dfb45..578cf6884bd1be5d5ca673270268091eac4706a8 100644
--- a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C
+++ b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C
@@ -488,7 +488,7 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::initialise
         if (weightFieldName_ == "none")
         {
             dict.lookup("orientedWeightField") >>  weightFieldName_;
-            Log << "    weight field = " << weightFieldName_ << nl;
+            Info<< "    weight field = " << weightFieldName_ << nl;
             orientWeightField_ = true;
         }
         else
diff --git a/src/functionObjects/field/flowType/flowType.C b/src/functionObjects/field/flowType/flowType.C
index 1451154bb0d7bbb693a5d4b2ce6e81b136627858..b74616a7f3b54fd8b9b84dec98633ea9755a556e 100644
--- a/src/functionObjects/field/flowType/flowType.C
+++ b/src/functionObjects/field/flowType/flowType.C
@@ -21,28 +21,6 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
-Class
-    flowType
-
-Group
-    grpPostProcessingUtilities
-
-Description
-    Calculates and writes the flowType of velocity field U.
-
-    The -noWrite option has no meaning.
-
-    The flow type parameter is obtained according to the following equation:
-    \verbatim
-                 |D| - |Omega|
-        lambda = -------------
-                 |D| + |Omega|
-
-        -1 = rotational flow
-         0 = simple shear flow
-         1 = planar extensional flow
-    \endverbatim
-
 \*---------------------------------------------------------------------------*/
 
 #include "flowType.H"
diff --git a/src/functionObjects/field/fluxSummary/fluxSummary.C b/src/functionObjects/field/fluxSummary/fluxSummary.C
index deb45d77f19c753c2f8a6cae59f4093b9fbca2c8..7a27f185272e0a30c783392827006f3726ba3107 100644
--- a/src/functionObjects/field/fluxSummary/fluxSummary.C
+++ b/src/functionObjects/field/fluxSummary/fluxSummary.C
@@ -727,22 +727,18 @@ bool Foam::functionObjects::fluxSummary::read(const dictionary& dict)
         }
     }
 
-    // Provide some output
-    if (log)
-    {
-        Info<< type() << " " << name() << " output:" << nl;
+    Info<< type() << " " << name() << " output:" << nl;
 
-        forAll(faceZoneName_, zonei)
-        {
-            const word& zoneName = faceZoneName_[zonei];
-            scalar zoneArea = faceArea_[zonei];
-
-            Info<< "    Zone: " << zoneName << ", area: " << zoneArea << nl;
-        }
+    forAll(faceZoneName_, zonei)
+    {
+        const word& zoneName = faceZoneName_[zonei];
+        scalar zoneArea = faceArea_[zonei];
 
-        Info<< endl;
+        Info<< "    Zone: " << zoneName << ", area: " << zoneArea << nl;
     }
 
+    Info<< endl;
+
     return true;
 }
 
diff --git a/src/functionObjects/field/histogram/histogram.C b/src/functionObjects/field/histogram/histogram.C
index 63e2abcf0a88239f9db45cfa8ea08dfe9a87d6b7..064fb9dded1917aae67d973ca1f2f8293f888e4a 100644
--- a/src/functionObjects/field/histogram/histogram.C
+++ b/src/functionObjects/field/histogram/histogram.C
@@ -93,6 +93,7 @@ Foam::functionObjects::histogram::~histogram()
 bool Foam::functionObjects::histogram::read(const dictionary& dict)
 {
     fvMeshFunctionObject::read(dict);
+    writeFile::read(dict);
 
     dict.lookup("field") >> fieldName_;
     dict.lookup("max") >> max_;
diff --git a/src/functionObjects/field/mapFields/mapFields.C b/src/functionObjects/field/mapFields/mapFields.C
index 3f3ff47ab58d25d13f4f73b8fd98979826ffdb51..00a387ad6e32265cda85d875f4275cdc722230e9 100644
--- a/src/functionObjects/field/mapFields/mapFields.C
+++ b/src/functionObjects/field/mapFields/mapFields.C
@@ -55,7 +55,7 @@ void Foam::functionObjects::mapFields::createInterpolation
     const fvMesh& meshTarget = mesh_;
     const word mapRegionName(dict.lookup("mapRegion"));
 
-    Log << name() << ':' << nl
+    Info<< name() << ':' << nl
         << "    Reading mesh " << mapRegionName << endl;
 
     mapRegionPtr_.reset
@@ -97,12 +97,12 @@ void Foam::functionObjects::mapFields::createInterpolation
     // Optionally override
     if (dict.readIfPresent("patchMapMethod", patchMapMethodName))
     {
-        Log << "    Patch mapping method: " << patchMapMethodName << endl;
+        Info<< "    Patch mapping method: " << patchMapMethodName << endl;
     }
 
     bool consistent = readBool(dict.lookup("consistent"));
 
-    Log << "    Creating mesh to mesh interpolation" << endl;
+    Info<< "    Creating mesh to mesh interpolation" << endl;
 
     if (consistent)
     {
diff --git a/src/functionObjects/field/nearWallFields/nearWallFields.C b/src/functionObjects/field/nearWallFields/nearWallFields.C
index 1cb3f0684ecca3188b8cda80d44c8238749bf227..061aca85e974e041d74c8ed818ccac9c94089305 100644
--- a/src/functionObjects/field/nearWallFields/nearWallFields.C
+++ b/src/functionObjects/field/nearWallFields/nearWallFields.C
@@ -281,7 +281,7 @@ bool Foam::functionObjects::nearWallFields::read(const dictionary& dict)
         reverseFieldMap_.insert(sampleFldName, fldName);
     }
 
-    Log  << type() << " " << name()
+    Info<< type() << " " << name()
         << ": Sampling " << fieldMap_.size() << " fields" << endl;
 
     // Do analysis
diff --git a/src/functionObjects/field/reactionSensitivityAnalysis/reactionsSensitivityAnalysis.C b/src/functionObjects/field/reactionSensitivityAnalysis/reactionsSensitivityAnalysis.C
index 8664497061df151553461d0a33447ff3c80cd8db..939de3548f02ec872f71952cbd063946f323fd88 100644
--- a/src/functionObjects/field/reactionSensitivityAnalysis/reactionsSensitivityAnalysis.C
+++ b/src/functionObjects/field/reactionSensitivityAnalysis/reactionsSensitivityAnalysis.C
@@ -138,10 +138,10 @@ writeSpeciesRR()
     prodFilePtr_() << "delta T : "<< mesh_.time().deltaT().value() << nl << nl;
 
     consIntFilePtr_() << "start time : " << startTime_ << tab
-            << "end time :" <<  endTime_ << nl;
+        << "end time :" <<  endTime_ << nl;
 
     prodIntFilePtr_() << "start time : " << startTime_ << tab
-            << "end time :" <<  endTime_ << nl;
+        << "end time :" <<  endTime_ << nl;
 
     for (label reactioni = 0; reactioni < nReactions_; ++reactioni)
     {
@@ -202,7 +202,7 @@ reactionsSensitivityAnalysis
     if (mesh_.nCells() != 1)
     {
         FatalErrorInFunction
-            << "Function object only applicable to single cell cases "
+            << "Function object only applicable to single cell cases"
             << abort(FatalError);
     }
 
@@ -243,9 +243,9 @@ reactionsSensitivityAnalysis
     }
     else
     {
-         FatalErrorInFunction
-            << " Not chemistry model found. "
-            << " Object available are : " << mesh_.names()
+        FatalErrorInFunction
+            << " No chemistry model found. "
+            << " Objects available are : " << mesh_.names()
             << exit(FatalError);
     }
 }
diff --git a/src/functionObjects/field/readFields/readFieldsTemplates.C b/src/functionObjects/field/readFields/readFieldsTemplates.C
index fee32c56272a9ce7727890226de7c464f82c82bc..07d73044c796d8e54dc70c286dc832a1a003cfcd 100644
--- a/src/functionObjects/field/readFields/readFieldsTemplates.C
+++ b/src/functionObjects/field/readFields/readFieldsTemplates.C
@@ -60,7 +60,7 @@ bool Foam::functionObjects::readFields::loadField(const word& fieldName)
             IOobject::NO_WRITE
         );
 
-        if (fieldHeader.typeHeaderOk<VolFieldType>(false))
+        if (fieldHeader.typeHeaderOk<VolFieldType>(true))
         {
             // Store field on mesh database
             Log << "    Reading " << fieldName << endl;
@@ -68,7 +68,7 @@ bool Foam::functionObjects::readFields::loadField(const word& fieldName)
             mesh_.objectRegistry::store(vfPtr);
             return true;
         }
-        else if (fieldHeader.typeHeaderOk<SurfaceFieldType>(false))
+        else if (fieldHeader.typeHeaderOk<SurfaceFieldType>(true))
         {
             // Store field on mesh database
             Log << "    Reading " << fieldName << endl;
diff --git a/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.C b/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.C
index fccc1b9cd168750ab4e42f4dc99974f6a4cf59dc..48504de23d74eb317d493b6ae58719f18b6b07ee 100644
--- a/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.C
+++ b/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.C
@@ -354,6 +354,7 @@ Foam::functionObjects::regionSizeDistribution::~regionSizeDistribution()
 bool Foam::functionObjects::regionSizeDistribution::read(const dictionary& dict)
 {
     fvMeshFunctionObject::read(dict);
+    writeFile::read(dict);
 
     dict.lookup("field") >> alphaName_;
     dict.lookup("patches") >> patchNames_;
@@ -371,7 +372,7 @@ bool Foam::functionObjects::regionSizeDistribution::read(const dictionary& dict)
     {
         coordSysPtr_.reset(new coordinateSystem(obr_, dict));
 
-        Log << "Transforming all vectorFields with coordinate system "
+        Info<< "Transforming all vectorFields with coordinate system "
             << coordSysPtr_().name() << endl;
     }
 
diff --git a/src/functionObjects/field/streamLine/streamLine.C b/src/functionObjects/field/streamLine/streamLine.C
index 1edbba13e6a0be9e083b0fd921cb37d3bfe1bb45..8f0bd5cc9ae875bd6bf2688b555981f9c9c4d27c 100644
--- a/src/functionObjects/field/streamLine/streamLine.C
+++ b/src/functionObjects/field/streamLine/streamLine.C
@@ -162,7 +162,7 @@ bool Foam::functionObjects::streamLine::read(const dictionary& dict)
             nSubCycle_ = max(nSubCycle_, 1);
 
 
-            Log << "    automatic track length specified through"
+            Info<< "    automatic track length specified through"
                 << " number of sub cycles : " << nSubCycle_ << nl
                 << endl;
         }
diff --git a/src/functionObjects/field/turbulenceFields/turbulenceFields.C b/src/functionObjects/field/turbulenceFields/turbulenceFields.C
index 29c1facb0e8aa22aa8b31867bc598c7b4b07dddd..b09c20ad5f37a58d61e5ee2347933f361683be13 100644
--- a/src/functionObjects/field/turbulenceFields/turbulenceFields.C
+++ b/src/functionObjects/field/turbulenceFields/turbulenceFields.C
@@ -157,19 +157,19 @@ bool Foam::functionObjects::turbulenceFields::read(const dictionary& dict)
         fieldSet_.insert(wordList(dict.lookup("fields")));
     }
 
-    Log << type() << " " << name() << ": ";
+    Info<< type() << " " << name() << ": ";
     if (fieldSet_.size())
     {
-        Log << "storing fields:" << nl;
+        Info<< "storing fields:" << nl;
         forAllConstIter(wordHashSet, fieldSet_, iter)
         {
-            Log << "    " << modelName << ':' << iter.key() << nl;
+            Info<< "    " << modelName << ':' << iter.key() << nl;
         }
-        Log << endl;
+        Info<< endl;
     }
     else
     {
-        Log << "no fields requested to be stored" << nl << endl;
+        Info<< "no fields requested to be stored" << nl << endl;
     }
 
     return true;
diff --git a/src/functionObjects/field/wallShearStress/wallShearStress.C b/src/functionObjects/field/wallShearStress/wallShearStress.C
index 39b4a5ed3d56326d51f0cc238796920fc7c3ab60..13911234410e4df35e54c11a9cd641d08d3ca1ee 100644
--- a/src/functionObjects/field/wallShearStress/wallShearStress.C
+++ b/src/functionObjects/field/wallShearStress/wallShearStress.C
@@ -143,7 +143,7 @@ bool Foam::functionObjects::wallShearStress::read(const dictionary& dict)
             wordReList(dict.lookupOrDefault("patches", wordReList()))
         );
 
-    Log << type() << " " << name() << ":" << nl;
+    Info<< type() << " " << name() << ":" << nl;
 
     if (patchSet_.empty())
     {
@@ -155,7 +155,7 @@ bool Foam::functionObjects::wallShearStress::read(const dictionary& dict)
             }
         }
 
-        Log << "    processing all wall patches" << nl << endl;
+        Info<< "    processing all wall patches" << nl << endl;
     }
     else
     {
@@ -177,7 +177,7 @@ bool Foam::functionObjects::wallShearStress::read(const dictionary& dict)
             }
         }
 
-        Log << endl;
+        Info<< endl;
 
         patchSet_ = filteredPatchSet;
     }
diff --git a/src/functionObjects/forces/forces/forces.C b/src/functionObjects/forces/forces/forces.C
index 573c25671fd52e2ff4eeae382b8d26317afae0c4..97de38581f28c37ba7fa76e93f8996b639b82cf2 100644
--- a/src/functionObjects/forces/forces/forces.C
+++ b/src/functionObjects/forces/forces/forces.C
@@ -846,7 +846,7 @@ bool Foam::functionObjects::forces::read(const dictionary& dict)
 
     initialised_ = false;
 
-    Info << type() << " " << name() << ":" << nl;
+    Info<< type() << " " << name() << ":" << nl;
 
     directForceDensity_ = dict.lookupOrDefault("directForceDensity", false);
 
@@ -889,11 +889,11 @@ bool Foam::functionObjects::forces::read(const dictionary& dict)
     dict.readIfPresent("porosity", porosity_);
     if (porosity_)
     {
-        Info << "    Including porosity effects" << endl;
+        Info<< "    Including porosity effects" << endl;
     }
     else
     {
-        Info << "    Not including porosity effects" << endl;
+        Info<< "    Not including porosity effects" << endl;
     }
 
     if (dict.found("binData"))
@@ -924,7 +924,7 @@ bool Foam::functionObjects::forces::read(const dictionary& dict)
 
     if (writeFields_)
     {
-        Info << "    Fields will be written" << endl;
+        Info<< "    Fields will be written" << endl;
 
         volVectorField* forcePtr
         (
diff --git a/src/functionObjects/lagrangian/icoUncoupledKinematicCloud/icoUncoupledKinematicCloud.C b/src/functionObjects/lagrangian/icoUncoupledKinematicCloud/icoUncoupledKinematicCloud.C
index c37307c377fe1bcf7c66a8ffa7ace5f2f52dec3e..4cce300a4d0fd9ad8779de412c5c862956983b74 100644
--- a/src/functionObjects/lagrangian/icoUncoupledKinematicCloud/icoUncoupledKinematicCloud.C
+++ b/src/functionObjects/lagrangian/icoUncoupledKinematicCloud/icoUncoupledKinematicCloud.C
@@ -120,9 +120,7 @@ bool Foam::functionObjects::icoUncoupledKinematicCloud::read
     const dictionary& dict
 )
 {
-    fvMeshFunctionObject::read(dict);
-
-    return true;
+    return fvMeshFunctionObject::read(dict);
 }
 
 
diff --git a/src/functionObjects/utilities/Make/files b/src/functionObjects/utilities/Make/files
index dbf879893867177d305fbb7b1a982e8a4b812415..e2f72c06cfe35edc354c239f6006bd35fb00082c 100644
--- a/src/functionObjects/utilities/Make/files
+++ b/src/functionObjects/utilities/Make/files
@@ -1,6 +1,7 @@
 abort/abort.C
 
 codedFunctionObject/codedFunctionObject.C
+ensightWrite/ensightWrite.C
 
 removeRegisteredObject/removeRegisteredObject.C
 
diff --git a/src/functionObjects/utilities/Make/options b/src/functionObjects/utilities/Make/options
index 0efefc46fce4978407baeee2f03a9e49a038733c..9e14e74355ba6987440ab51398b328e938322075 100644
--- a/src/functionObjects/utilities/Make/options
+++ b/src/functionObjects/utilities/Make/options
@@ -1,5 +1,7 @@
 EXE_INC = \
     -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/fileFormats/lnInclude \
+    -I$(LIB_SRC)/conversion/lnInclude \
     -I$(LIB_SRC)/sampling/lnInclude \
     -I$(LIB_SRC)/ODE/lnInclude \
     -I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
@@ -7,6 +9,8 @@ EXE_INC = \
 
 LIB_LIBS = \
     -lfiniteVolume \
+    -lconversion \
+    -lsampling \
     -lfluidThermophysicalModels \
     -lcompressibleTransportModels \
     -lODE
diff --git a/src/functionObjects/utilities/ensightWrite/ensightWrite.C b/src/functionObjects/utilities/ensightWrite/ensightWrite.C
new file mode 100644
index 0000000000000000000000000000000000000000..02a17215a71cb8ccc98d2b50c45e30b0dbbd0dbe
--- /dev/null
+++ b/src/functionObjects/utilities/ensightWrite/ensightWrite.C
@@ -0,0 +1,329 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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 "ensightWrite.H"
+#include "Time.H"
+#include "polyMesh.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace functionObjects
+{
+    defineTypeNameAndDebug(ensightWrite, 0);
+
+    addToRunTimeSelectionTable
+    (
+        functionObject,
+        ensightWrite,
+        dictionary
+    );
+}
+}
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::functionObjects::ensightWrite::uniqWords(wordReList& lst)
+{
+    boolList retain(lst.size());
+    wordHashSet uniq;
+    forAll(lst, i)
+    {
+        const wordRe& select = lst[i];
+
+        retain[i] =
+        (
+            select.isPattern()
+         || uniq.insert(static_cast<const word&>(select))
+        );
+    }
+
+    inplaceSubset(retain, lst);
+}
+
+
+int Foam::functionObjects::ensightWrite::process(const word& fieldName)
+{
+    int state = 0;
+
+    writeVolField<scalar>(fieldName, state);
+    writeVolField<vector>(fieldName, state);
+    writeVolField<sphericalTensor>(fieldName, state);
+    writeVolField<symmTensor>(fieldName, state);
+    writeVolField<tensor>(fieldName, state);
+
+    return state;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::functionObjects::ensightWrite::ensightWrite
+(
+    const word& name,
+    const Time& runTime,
+    const dictionary& dict
+)
+:
+    fvMeshFunctionObject(name, runTime, dict),
+    writeOpts_
+    (
+        dict.found("format")
+      ? IOstream::formatEnum(dict.lookup("format"))
+      : runTime.writeFormat()
+    ),
+    caseOpts_(writeOpts_.format()),
+    selectFields_(),
+    dirName_("ensightWrite"),
+    consecutive_(false)
+{
+    read(dict);
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::functionObjects::ensightWrite::~ensightWrite()
+{
+    if (ensCase_.valid())
+    {
+        // finalize case
+        ensCase().write();
+        ensCase_.clear();
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::functionObjects::ensightWrite::read(const dictionary& dict)
+{
+    fvMeshFunctionObject::read(dict);
+
+    //
+    // writer options
+    //
+    writeOpts_.noPatches
+    (
+        dict.lookupOrDefault<Switch>("noPatches", false)
+    );
+
+    writeOpts_.deprecatedOrder
+    (
+        dict.lookupOrDefault<Switch>("deprecatedOrder", false)
+    );
+
+    if (dict.found("patches"))
+    {
+        wordReList lst(dict.lookup("patches"));
+        uniqWords(lst);
+
+        writeOpts_.patchSelection(lst);
+    }
+
+    if (dict.found("faceZones"))
+    {
+        wordReList lst(dict.lookup("faceZones"));
+        uniqWords(lst);
+
+        writeOpts_.faceZoneSelection(lst);
+    }
+
+
+    //
+    // case options
+    //
+    caseOpts_.width(dict.lookupOrDefault<label>("width", 8));
+
+    // remove existing output directory
+    caseOpts_.overwrite(dict.lookupOrDefault<Switch>("overwrite", false));
+
+
+    //
+    // other options
+    //
+    dict.readIfPresent("directory", dirName_);
+    consecutive_ = dict.lookupOrDefault<Switch>("consecutive", false);
+
+
+    //
+    // output fields
+    //
+    dict.lookup("fields") >> selectFields_;
+    uniqWords(selectFields_);
+
+    return true;
+}
+
+
+bool Foam::functionObjects::ensightWrite::execute()
+{
+    return true;
+}
+
+
+bool Foam::functionObjects::ensightWrite::write()
+{
+    const Time& t = obr_.time();
+
+    if (!ensCase_.valid())
+    {
+        // Define sub-directory name to use for EnSight data.
+        // The path to the ensight directory is at case level only
+        // - For parallel cases, data only written from master
+
+        fileName ensightDir = dirName_;
+        if (!ensightDir.isAbsolute())
+        {
+            ensightDir = t.rootPath()/t.globalCaseName()/ensightDir;
+        }
+
+        ensCase_.reset
+        (
+            new ensightCase
+            (
+                ensightDir,
+                t.globalCaseName(),
+                caseOpts_
+            )
+        );
+    }
+
+    if (!ensMesh_.valid())
+    {
+        ensMesh_.reset(new ensightMesh(mesh_, writeOpts_));
+
+        if (ensMesh_().needsUpdate())
+        {
+            ensMesh_().correct();
+        }
+
+        // assume static geometry - need to fix later
+        autoPtr<ensightGeoFile> os = ensCase_().newGeometry(false);
+        ensMesh_().write(os);
+    }
+    else if (ensMesh_().needsUpdate())
+    {
+        // appears to have moved
+        ensMesh_().correct();
+
+        autoPtr<ensightGeoFile> os = ensCase_().newGeometry(true);
+        ensMesh_().write(os);
+    }
+
+    Log << type() << " " << name() << " write: (";
+
+    if (consecutive_)
+    {
+        ensCase().nextTime(t.value());
+    }
+    else
+    {
+        ensCase().setTime(t.value(), t.timeIndex());
+    }
+
+    wordHashSet candidates = subsetStrings(selectFields_, mesh_.names());
+    DynamicList<word> missing(selectFields_.size());
+    DynamicList<word> ignored(selectFields_.size());
+
+    // check exact matches first
+    forAll(selectFields_, i)
+    {
+        const wordRe& select = selectFields_[i];
+        if (!select.isPattern())
+        {
+            const word& fieldName = static_cast<const word&>(select);
+
+            if (!candidates.erase(fieldName))
+            {
+                missing.append(fieldName);
+            }
+            else if (process(fieldName) < 1)
+            {
+                ignored.append(fieldName);
+            }
+        }
+    }
+
+    forAllConstIter(wordHashSet, candidates, iter)
+    {
+        process(iter.key());
+    }
+
+    Log << " )" << endl;
+
+    if (missing.size())
+    {
+        WarningInFunction
+            << "Missing field " << missing << endl;
+    }
+    if (ignored.size())
+    {
+        WarningInFunction
+            << "Unprocessed field " << ignored << endl;
+    }
+
+    return true;
+}
+
+
+bool Foam::functionObjects::ensightWrite::end()
+{
+    if (ensCase_.valid())
+    {
+        // finalize case
+        ensCase().write();
+        ensCase_.clear();
+    }
+
+    return true;
+}
+
+
+void Foam::functionObjects::ensightWrite::updateMesh(const mapPolyMesh& mpm)
+{
+    // fvMeshFunctionObject::updateMesh(mpm);
+
+    if (ensMesh_.valid())
+    {
+        ensMesh_().expire();
+    }
+}
+
+
+void Foam::functionObjects::ensightWrite::movePoints(const polyMesh& mpm)
+{
+    // fvMeshFunctionObject::updateMesh(mpm);
+
+    if (ensMesh_.valid())
+    {
+        ensMesh_().expire();
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/functionObjects/utilities/ensightWrite/ensightWrite.H b/src/functionObjects/utilities/ensightWrite/ensightWrite.H
new file mode 100644
index 0000000000000000000000000000000000000000..edba7c8535a7cafaf3571fbff0b4a4e7497d92a2
--- /dev/null
+++ b/src/functionObjects/utilities/ensightWrite/ensightWrite.H
@@ -0,0 +1,227 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     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/>.
+
+Class
+    Foam::functionObjects::ensightWrite
+
+Group
+    grpUtilitiesFunctionObjects
+
+Description
+    Writes fields in ensight format.
+
+    Example of function object specification:
+    \verbatim
+    ensight
+    {
+        type            ensightWrite;
+        libs            ("libutilityFunctionObjects.so");
+        writeControl    writeTime;
+        writeInterval   1;
+        format          binary;
+
+        overwrite       true;
+        width           12;
+        directory       "EnSight";
+
+        fields
+        (
+            U
+            p
+        );
+    }
+    \endverbatim
+
+    \heading Function object usage
+    \table
+        Property     | Description                  | Required  | Default value
+        type         | Type name: ensightWrite      | yes       |
+        fields       | Fields to output             | yes       |
+        writeControl | Output control               | recommended | timeStep
+        directory    | The output directory name    | no        | "ensightWrite"
+        overwrite    | Remove existing directory    | no        | false
+        format       | ASCII or binary format       | no        | same as simulation
+        width        | Mask width for \c data/XXXX  | no        | 8
+        noPatches    | Suppress writing patches     | no        | false
+        patches      | Select patches to write      | no        |
+        faceZones    | Select faceZones to write    | no        |
+        deprecatedOrder | Old ordering of volume cells  | no    | false
+        consecutive  | Consecutive output numbering | no    | false
+    \endtable
+
+    Note that if the \c patches entry is an empty list, this will select all
+    patches and suppress writing the internalMesh.
+    Consecutive output numbering can be used in conjunction with \c overwrite.
+
+SourceFiles
+    ensightWrite.C
+    ensightWriteTemplates.C
+
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef functionObjects_ensightWrite_H
+#define functionObjects_ensightWrite_H
+
+#include "fvMeshFunctionObject.H"
+#include "ensightCase.H"
+#include "ensightMesh.H"
+
+#include "wordReList.H"
+#include "interpolation.H"
+#include "volFields.H"
+#include "surfaceFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+class dictionary;
+
+namespace functionObjects
+{
+
+/*---------------------------------------------------------------------------*\
+                         Class ensightWrite Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightWrite
+:
+    public fvMeshFunctionObject
+{
+    // Private data
+
+        //- Writer options
+        ensightMesh::options writeOpts_;
+        ensightCase::options caseOpts_;
+
+        //- Name of fields to process
+        wordReList selectFields_;
+
+        //- Output directory name
+        fileName dirName_;
+
+        //- Consecutive output numbering
+        bool consecutive_;
+
+        //- Ensight case handler
+        autoPtr<ensightCase> ensCase_;
+
+        //- Ensight mesh handler
+        autoPtr<ensightMesh> ensMesh_;
+
+
+    // Private Member Functions
+
+        //- Eliminate duplicate 'word' entries
+        static void uniqWords(wordReList&);
+
+        //- Ensight case handler
+        ensightCase& ensCase()
+        {
+            return ensCase_();
+        }
+
+        //- Ensight mesh handler
+        ensightMesh& ensMesh()
+        {
+            return ensMesh_();
+        }
+
+
+        //- Apply for the volume field type
+        template<class Type>
+        int writeVolField(const word& inputName, int& state);
+
+
+        //- Process by trying to apply for various volume field types.
+        int process(const word& inputName);
+
+
+        //- Disallow default bitwise copy construct
+        ensightWrite(const ensightWrite&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const ensightWrite&) = delete;
+
+public:
+
+    //- Runtime type information
+    TypeName("ensightWrite");
+
+
+    // Constructors
+
+        //- Construct from runTime and dictionary.
+        ensightWrite
+        (
+            const word& name,
+            const Time& runTime,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~ensightWrite();
+
+
+    // Member Functions
+
+        //- Read the ensightWrite specification
+        virtual bool read(const dictionary&);
+
+        //- Do nothing
+        virtual bool execute();
+
+        //- Write fields
+        virtual bool write();
+
+        //- Execute at the final time-loop, flush case file
+        virtual bool end();
+
+        //- Update for changes of mesh
+        virtual void updateMesh(const mapPolyMesh&);
+
+        //- Update for mesh point-motion
+        virtual void movePoints(const polyMesh&);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace functionObjects
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "ensightWriteTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/part/ensightPartsTemplates.C b/src/functionObjects/utilities/ensightWrite/ensightWriteTemplates.C
similarity index 53%
rename from src/conversion/ensight/part/ensightPartsTemplates.C
rename to src/functionObjects/utilities/ensightWrite/ensightWriteTemplates.C
index fe2f712a0b4e9f40d4b1d76cf6129eddc4eb039b..e9ff3a98eba98f4c00d11bba624af35adb3a726b 100644
--- a/src/conversion/ensight/part/ensightPartsTemplates.C
+++ b/src/functionObjects/utilities/ensightWrite/ensightWriteTemplates.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -21,54 +21,41 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
-Description
-    Template to write generalized field components
-
 \*---------------------------------------------------------------------------*/
 
-#include "ensightParts.H"
+#include "Time.H"
+#include "ensightOutput.H"
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 template<class Type>
-void Foam::ensightParts::writeField
+int Foam::functionObjects::ensightWrite::writeVolField
 (
-    ensightFile& os,
-    const GeometricField<Type, fvPatchField, volMesh>& field
-) const
+    const word& inputName,
+    int& state
+)
 {
-    // find offset to patch parts (ie, the first face data)
-    label patchOffset = 0;
-    forAll(partsList_, partI)
+    // State: return 0 (not-processed), -1 (skip), +1 ok
+    typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
+
+    // Already done, or not available
+    if (state || !foundObject<VolFieldType>(inputName))
     {
-        if (partsList_[partI].isFaceData())
-        {
-            patchOffset = partI;
-            break;
-        }
+        return state;
     }
 
-    forAll(partsList_, partI)
-    {
-        label patchi = partI - patchOffset;
+    autoPtr<ensightFile> os = ensCase().newData<Type>(inputName);
+    ensightOutput::writeField<Type>
+    (
+        lookupObject<VolFieldType>(inputName),
+        ensMesh(),
+        os
+    );
 
-        if (partsList_[partI].isCellData())
-        {
-            partsList_[partI].writeField
-            (
-                os,
-                field
-            );
-        }
-        else if (patchi < field.boundaryField().size())
-        {
-            partsList_[partI].writeField
-            (
-                os,
-                field.boundaryField()[patchi]
-            );
-        }
-    }
+    Log << " " << inputName;
+
+    state = +1;
+    return state;
 }
 
 
diff --git a/src/functionObjects/utilities/timeActivatedFileUpdate/timeActivatedFileUpdate.C b/src/functionObjects/utilities/timeActivatedFileUpdate/timeActivatedFileUpdate.C
index d6dc1d10400199b608e1e4e3795d0402a6f0fddd..640fb58d103aefb545140843697c98872c00a6ea 100644
--- a/src/functionObjects/utilities/timeActivatedFileUpdate/timeActivatedFileUpdate.C
+++ b/src/functionObjects/utilities/timeActivatedFileUpdate/timeActivatedFileUpdate.C
@@ -111,7 +111,7 @@ bool Foam::functionObjects::timeActivatedFileUpdate::read
     lastIndex_ = -1;
     fileToUpdate_.expand();
 
-    Log << type() << " " << name() << " output:" << nl
+    Info<< type() << " " << name() << " output:" << nl
         << "    time vs file list:" << endl;
 
     forAll(timeVsFile_, i)
@@ -124,7 +124,7 @@ bool Foam::functionObjects::timeActivatedFileUpdate::read
                 << nl << exit(FatalError);
         }
 
-        Log << "    " << timeVsFile_[i].first() << tab
+        Info<< "    " << timeVsFile_[i].first() << tab
             << timeVsFile_[i].second() << endl;
     }
 
diff --git a/src/parallel/decompose/Allwmake b/src/parallel/decompose/Allwmake
index 6652ef62867774d8a062aef9799e73ea61fbfbc5..9be81484758a98b4a90dcfd10a735bf4f1ee719b 100755
--- a/src/parallel/decompose/Allwmake
+++ b/src/parallel/decompose/Allwmake
@@ -4,8 +4,21 @@ cd ${0%/*} || exit 1    # Run from this directory
 # Parse arguments for library compilation
 . $WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments
 
+unset METIS_ARCH_PATH SCOTCH_ARCH_PATH
+
+# get METIS_VERSION, METIS_ARCH_PATH
+if settings=$($WM_PROJECT_DIR/bin/foamEtcFile config.sh/metis)
+then
+    . $settings
+    echo "using METIS_ARCH_PATH=$METIS_ARCH_PATH"
+else
+    echo
+    echo "Error: no config.sh/metis settings"
+    echo
+fi
+
 # get SCOTCH_VERSION, SCOTCH_ARCH_PATH
-if settings=`$WM_PROJECT_DIR/bin/foamEtcFile config.sh/scotch`
+if settings=$($WM_PROJECT_DIR/bin/foamEtcFile config.sh/scotch)
 then
     . $settings
     echo "using SCOTCH_ARCH_PATH=$SCOTCH_ARCH_PATH"
@@ -45,21 +58,12 @@ set -x
 
 wmakeLnInclude decompositionMethods
 
-if [ -n "$SCOTCH_ARCH_PATH" ]
+if [ -f $SCOTCH_ARCH_PATH/include/scotch.h \
+  -a -r $FOAM_EXT_LIBBIN/libscotch.so ]
 then
     wmake $targetType scotchDecomp
-
     if [ -d "$FOAM_LIBBIN/$FOAM_MPI" ]
     then
-        #- Bit of a hack: ptscotch 6 requires scotch linked as well as. Can be
-        #  removed once ptscotch declares dependency on scotch itself.
-        case "$SCOTCH_VERSION" in
-        scotch_6.*)
-            export LINK_FLAGS="-lscotch"
-            ;;
-        esac
-
-
         wmakeMpiLib ptscotchDecomp
     fi
 else
@@ -69,8 +73,15 @@ else
 fi
 
 
-# Try and build metisDecomp (has own logic)
-(cd metisDecomp && ./Allwmake $targetType)
+if [ -f $METIS_ARCH_PATH/include/metis.h \
+  -a -r $FOAM_EXT_LIBBIN/libmetis.so ]
+then
+    wmake $targetType metisDecomp
+else
+    echo
+    echo "Skipping metisDecomp: metis not installed"
+    echo
+fi
 
 
 wmake $targetType decompositionMethods
diff --git a/src/parallel/decompose/metisDecomp/Allwmake b/src/parallel/decompose/metisDecomp/Allwmake
deleted file mode 100755
index 2f666aba2bb31c2c61e2d945562732b074b8bc2f..0000000000000000000000000000000000000000
--- a/src/parallel/decompose/metisDecomp/Allwmake
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/sh
-cd ${0%/*} || exit 1    # Run from this directory
-
-# Parse arguments for library compilation
-. $WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments
-
-# get METIS_VERSION, METIS_ARCH_PATH
-if settings=`$WM_PROJECT_DIR/bin/foamEtcFile config.sh/metis`
-then
-    . $settings
-    echo "using METIS_ARCH_PATH=$METIS_ARCH_PATH"
-    if [ -r $METIS_ARCH_PATH/lib/libmetis.so ]
-    then
-        wmake $targetType
-    fi
-else
-    echo
-    echo "Error: no config.sh/metis settings"
-    echo
-fi
-
-
-#------------------------------------------------------------------------------
diff --git a/src/parallel/decompose/metisDecomp/Make/options b/src/parallel/decompose/metisDecomp/Make/options
index 8acd678fd3f2dacf7f6fdceb5aa7b120ba19876a..fdb35bf1e2708ee79d78d32fa176b3c28e864d6f 100644
--- a/src/parallel/decompose/metisDecomp/Make/options
+++ b/src/parallel/decompose/metisDecomp/Make/options
@@ -4,4 +4,5 @@ EXE_INC = \
     -I../decompositionMethods/lnInclude
 
 LIB_LIBS = \
-    -L$(METIS_ARCH_PATH)/lib -lmetis
+    -L$(FOAM_EXT_LIBBIN) \
+    -lmetis
diff --git a/src/parallel/decompose/ptscotchDecomp/Make/options b/src/parallel/decompose/ptscotchDecomp/Make/options
index cb407ec6b5c8646d634e0d4bc169a3e40c4946b5..37286e91aa0141ba5cb8ca0dd7e918e583ce3d6d 100644
--- a/src/parallel/decompose/ptscotchDecomp/Make/options
+++ b/src/parallel/decompose/ptscotchDecomp/Make/options
@@ -8,8 +8,12 @@ EXE_INC = \
     -I/usr/include/scotch \
     -I../decompositionMethods/lnInclude
 
+/*
+ * The '-lscotch' is a slight hack:
+ * ptscotch 6 requires scotch linked in, but does not declare the dependency
+ */
 LIB_LIBS = \
-    -L$(SCOTCH_ARCH_PATH)/lib \
+    -L$(FOAM_EXT_LIBBIN) \
     -L$(FOAM_EXT_LIBBIN)/$(FOAM_MPI) \
     -lptscotch \
     -lptscotcherrexit \
diff --git a/src/parallel/decompose/scotchDecomp/Make/options b/src/parallel/decompose/scotchDecomp/Make/options
index d2cc770692ce384821691c05ef08cd3d47e9a9a5..4bee67053c2708e0acf1a5f9626c526d1d15bc1e 100644
--- a/src/parallel/decompose/scotchDecomp/Make/options
+++ b/src/parallel/decompose/scotchDecomp/Make/options
@@ -12,7 +12,6 @@ EXE_INC = \
     -I../decompositionMethods/lnInclude
 
 LIB_LIBS = \
-    -L$(SCOTCH_ARCH_PATH)/lib \
     -L$(FOAM_EXT_LIBBIN) \
     -lscotch \
     -lscotcherrexit \
diff --git a/src/randomProcesses/noise/noiseModels/surfaceNoise/surfaceNoise.C b/src/randomProcesses/noise/noiseModels/surfaceNoise/surfaceNoise.C
index 860aafdae3184e3b71c3aa9d1d869c1427bf60ad..407473632f933ed6f49f4c6b1e1f7af7197bde00 100644
--- a/src/randomProcesses/noise/noiseModels/surfaceNoise/surfaceNoise.C
+++ b/src/randomProcesses/noise/noiseModels/surfaceNoise/surfaceNoise.C
@@ -301,14 +301,8 @@ Foam::scalar surfaceNoise::writeSurfaceData
                 false
             );
 
-            // TODO: Move faceAreas to demand-driven function in MeshedSurface
-            // scalarField faceAreas(surf.faces().size());
-            // forAll(faceAreas, i)
-            // {
-            //     faceAreas[i] = surf.faces()[i].mag(surf.points());
-            // }
-            //
-            // areaAverage = sum(allData*faceAreas)/sum(faceAreas);
+            // TO BE VERIFIED: area-averaged values
+            // areaAverage = sum(allData*surf.magSf())/sum(surf.magSf());
             areaAverage = sum(allData)/allData.size();
         }
         Pstream::scatter(areaAverage);
@@ -330,14 +324,8 @@ Foam::scalar surfaceNoise::writeSurfaceData
             false
         );
 
-        // TODO: Move faceAreas to demand-driven function in MeshedSurface
-        // scalarField faceAreas(surf.faces().size());
-        // forAll(faceAreas, i)
-        // {
-        //     faceAreas[i] = surf.faces()[i].mag(surf.points());
-        // }
-        //
-        // return sum(data*faceAreas)/sum(faceAreas);
+        // TO BE VERIFIED: area-averaged values
+        // return sum(data*surf.magSf())/sum(surf.magSf());
         return sum(data)/data.size();
     }
 }
@@ -387,14 +375,8 @@ Foam::scalar surfaceNoise::surfaceAverage
                 }
             }
 
-            // TODO: Move faceAreas to demand-driven function in MeshedSurface
-            scalarField faceAreas(surf.faces().size());
-            forAll(faceAreas, i)
-            {
-                faceAreas[i] = surf.faces()[i].mag(surf.points());
-            }
-
-//            areaAverage = sum(allData*faceAreas)/sum(faceAreas);
+            // TO BE VERIFIED: area-averaged values
+            // areaAverage = sum(allData*surf.magSf())/sum(surf.magSf());
             areaAverage = sum(allData)/allData.size();
         }
         Pstream::scatter(areaAverage);
@@ -405,14 +387,8 @@ Foam::scalar surfaceNoise::surfaceAverage
     {
         const meshedSurface& surf = readerPtr_->geometry();
 
-        // TODO: Move faceAreas to demand-driven function in MeshedSurface
-        scalarField faceAreas(surf.faces().size());
-        forAll(faceAreas, i)
-        {
-            faceAreas[i] = surf.faces()[i].mag(surf.points());
-        }
-
-//        return sum(data*faceAreas)/sum(faceAreas);
+        // TO BE VERIFIED: area-averaged values
+        // return sum(data*surf.magSf())/sum(surf.magSf());
         return sum(data)/data.size();
     }
 }
@@ -550,9 +526,6 @@ void surfaceNoise::calculate()
             surfPSD13f[freqI][faceI] = PSD13f.y()[freqI];
             surfPrms13f2[freqI][faceI] = Prms13f2.y()[freqI];
         }
-
-        // Free the storage for p
-//        p.clear();
     }
 
     // Output directory for graphs
diff --git a/src/renumber/Allwmake b/src/renumber/Allwmake
index 14191c9526787f66f030515498760be4613ae226..66d9bfd5366c8f66e74b55adda50298aafeaf50e 100755
--- a/src/renumber/Allwmake
+++ b/src/renumber/Allwmake
@@ -20,8 +20,8 @@ set -x
 
 wmake $targetType renumberMethods
 
-if [ -d "$BOOST_ARCH_PATH/include/boost" ] || \
-   [ "${BOOST_ARCH_PATH##*-}" = system -a -d /usr/include/boost ]
+if [ -f "$BOOST_ARCH_PATH/include/boost/version.hpp" ] || \
+   [ "${BOOST_ARCH_PATH##*-}" = system -a -f /usr/include/boost/version.hpp ]
 then
     wmake $targetType SloanRenumber
 else
diff --git a/src/renumber/SloanRenumber/Make/options b/src/renumber/SloanRenumber/Make/options
index cf6e548615177465eba855341de032020bd5c2b4..2c8f956a611718051304f5c066175e83e469ea3c 100644
--- a/src/renumber/SloanRenumber/Make/options
+++ b/src/renumber/SloanRenumber/Make/options
@@ -5,7 +5,7 @@ EXE_INC = \
     -I$(LIB_SRC)/renumber/renumberMethods/lnInclude
 
 LIB_LIBS = \
-    -L$(BOOST_ARCH_PATH)/lib -lboost_system \
+    -L$(BOOST_ARCH_PATH)/lib$(WM_COMPILER_LIB_ARCH) -lboost_system \
     -lmeshTools \
     -ldecompositionMethods \
     -lrenumberMethods
diff --git a/src/sampling/meshToMesh/calcMethod/meshToMeshMethod/meshToMeshMethod.C b/src/sampling/meshToMesh/calcMethod/meshToMeshMethod/meshToMeshMethod.C
index 2614f81db674ba1c48f31957ac882ce79a57f2b1..63c8a58d7a4fff2585e39bb6626ca9c0a9ad54aa 100644
--- a/src/sampling/meshToMesh/calcMethod/meshToMeshMethod/meshToMeshMethod.C
+++ b/src/sampling/meshToMesh/calcMethod/meshToMeshMethod/meshToMeshMethod.C
@@ -205,7 +205,7 @@ bool Foam::meshToMeshMethod::initialise
     {
         if (debug)
         {
-            Pout<< "mesh interpolation: hhave " << src_.nCells() << " source "
+            Pout<< "mesh interpolation: have " << src_.nCells() << " source "
                 << " cells but no target cells" << endl;
         }
 
diff --git a/src/sampling/sampledSurface/distanceSurface/distanceSurface.H b/src/sampling/sampledSurface/distanceSurface/distanceSurface.H
index 755eb818e487d80537efc1488d2aa1010192f964..407e8914dbafd0a1c961041c115a26e0ceb4ece4 100644
--- a/src/sampling/sampledSurface/distanceSurface/distanceSurface.H
+++ b/src/sampling/sampledSurface/distanceSurface/distanceSurface.H
@@ -193,6 +193,25 @@ public:
             return facesPtr_;
         }
 
+        //- Face area vectors
+        virtual const vectorField& Sf() const
+        {
+            return surface().Sf();
+        }
+
+        //- Face area magnitudes
+        virtual const scalarField& magSf() const
+        {
+            return surface().magSf();
+        }
+
+        //- Face centres
+        virtual const vectorField& Cf() const
+        {
+            return surface().Cf();
+        }
+
+
         const triSurface& surface() const
         {
             if (cell_)
diff --git a/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.H b/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.H
index a0ea5063372400010a10e310ab82d7b9d3f13917..19efe340b74e93e7da7b7835c638b82c1cdbc5c9 100644
--- a/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.H
+++ b/src/sampling/sampledSurface/isoSurface/sampledIsoSurface.H
@@ -158,6 +158,11 @@ public:
 
     // Member Functions
 
+        const isoSurface& surface() const
+        {
+            return surfPtr_();
+        }
+
         //- Does the surface need an update?
         virtual bool needsUpdate() const;
 
@@ -194,16 +199,32 @@ public:
             return facesPtr_;
         }
 
+        //- Face area magnitudes
+        virtual const vectorField& Sf() const
+        {
+            return surface().Sf();
+        }
 
-        const isoSurface& surface() const
+        //- Face area magnitudes
+        virtual const scalarField& magSf() const
         {
-            return surfPtr_();
+            return surface().magSf();
         }
 
-        //- Lookup or read isoField. Sets volFieldPtr_ and pointFieldPtr_.
+        //- Face centres
+        virtual const vectorField& Cf() const
+        {
+            return surface().Cf();
+        }
+
+
+        //- Lookup or read isoField.
+        //  Sets volFieldPtr_ and pointFieldPtr_.
         void getIsoField();
 
 
+    // Sample
+
         //- Sample field on surface
         virtual tmp<scalarField> sample
         (
@@ -235,6 +256,8 @@ public:
         ) const;
 
 
+    // Interpolate
+
         //- Interpolate field on surface
         virtual tmp<scalarField> interpolate
         (
@@ -265,6 +288,9 @@ public:
             const interpolation<tensor>&
         ) const;
 
+
+    // Output
+
         //- Write
         virtual void print(Ostream&) const;
 };
diff --git a/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceCell.H b/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceCell.H
index b404976ee07192b091a75b838decf47eb09d98a7..f7a267aa9db38555b92823c4db7f7dd112055c5e 100644
--- a/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceCell.H
+++ b/src/sampling/sampledSurface/isoSurface/sampledIsoSurfaceCell.H
@@ -54,6 +54,9 @@ class sampledIsoSurfaceCell
     public sampledSurface,
     public triSurface
 {
+    //- Private typedef for convenience
+    typedef triSurface MeshStorage;
+
     // Private data
 
         //- Field to get isoSurface of
@@ -145,7 +148,7 @@ public:
         //- Points of surface
         virtual const pointField& points() const
         {
-            return triSurface::points();
+            return MeshStorage::points();
         }
 
         //- Faces of surface
@@ -165,6 +168,24 @@ public:
             return facesPtr_;
         }
 
+        //- Face area magnitudes
+        virtual const vectorField& Sf() const
+        {
+            return MeshStorage::Sf();
+        }
+
+        //- Face area magnitudes
+        virtual const scalarField& magSf() const
+        {
+            return MeshStorage::magSf();
+        }
+
+        //- Face centres
+        virtual const vectorField& Cf() const
+        {
+            return MeshStorage::Cf();
+        }
+
 
         //- Sample field on surface
         virtual tmp<scalarField> sample
diff --git a/src/sampling/sampledSurface/sampledCuttingPlane/sampledCuttingPlane.H b/src/sampling/sampledSurface/sampledCuttingPlane/sampledCuttingPlane.H
index eb50106b59a5732d45b425bce607e6756a38813a..c4fb497767c36a6ed99cfe857bbbef375c4aaa35 100644
--- a/src/sampling/sampledSurface/sampledCuttingPlane/sampledCuttingPlane.H
+++ b/src/sampling/sampledSurface/sampledCuttingPlane/sampledCuttingPlane.H
@@ -141,6 +141,12 @@ public:
 
     // Member Functions
 
+        //const isoSurfaceCell& surface() const
+        const isoSurface& surface() const
+        {
+            return isoSurfPtr_();
+        }
+
         //- Does the surface need an update?
         virtual bool needsUpdate() const;
 
@@ -176,13 +182,27 @@ public:
             return facesPtr_;
         }
 
+        //- Face area magnitudes
+        virtual const vectorField& Sf() const
+        {
+            return surface().Sf();
+        }
 
-        //const isoSurfaceCell& surface() const
-        const isoSurface& surface() const
+        //- Face area magnitudes
+        virtual const scalarField& magSf() const
         {
-            return isoSurfPtr_();
+            return surface().magSf();
         }
 
+        //- Face centres
+        virtual const vectorField& Cf() const
+        {
+            return surface().Cf();
+        }
+
+
+    // Sample
+
         //- Sample field on surface
         virtual tmp<scalarField> sample
         (
@@ -214,6 +234,8 @@ public:
         ) const;
 
 
+    // Interpolate
+
         //- Interpolate field on surface
         virtual tmp<scalarField> interpolate
         (
@@ -244,6 +266,9 @@ public:
             const interpolation<tensor>&
         ) const;
 
+
+    // Output
+
         //- Write
         virtual void print(Ostream&) const;
 };
diff --git a/src/sampling/sampledSurface/sampledPatch/sampledPatch.H b/src/sampling/sampledSurface/sampledPatch/sampledPatch.H
index b16ddef634e82ec3667fa609a5137109dbaa29b6..e47d7494ba194528c47865f0202f7c47e9b1167b 100644
--- a/src/sampling/sampledSurface/sampledPatch/sampledPatch.H
+++ b/src/sampling/sampledSurface/sampledPatch/sampledPatch.H
@@ -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.
@@ -180,8 +180,27 @@ public:
             return MeshStorage::faces();
         }
 
+        //- Face area vectors
+        virtual const vectorField& Sf() const
+        {
+            return MeshStorage::Sf();
+        }
+
+        //- Face area magnitudes
+        virtual const scalarField& magSf() const
+        {
+            return MeshStorage::magSf();
+        }
+
+        //- Face centres
+        virtual const vectorField& Cf() const
+        {
+            return MeshStorage::Cf();
+        }
+
 
         // Sample
+
             //- Sample field on surface
             virtual tmp<scalarField> sample
             (
diff --git a/src/sampling/sampledSurface/sampledPlane/sampledPlane.H b/src/sampling/sampledSurface/sampledPlane/sampledPlane.H
index 6746361c1ed6788bda0a175d89210737fcee8219..6269d39d9a69c605f603c920c46d82ddfb632b32 100644
--- a/src/sampling/sampledSurface/sampledPlane/sampledPlane.H
+++ b/src/sampling/sampledSurface/sampledPlane/sampledPlane.H
@@ -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.
@@ -140,6 +140,25 @@ public:
             return cuttingPlane::faces();
         }
 
+        //- Face area magnitudes
+        virtual const vectorField& Sf() const
+        {
+            return cuttingPlane::Sf();
+        }
+
+        //- Face area magnitudes
+        virtual const scalarField& magSf() const
+        {
+            return cuttingPlane::magSf();
+        }
+
+        //- Face centres
+        virtual const vectorField& Cf() const
+        {
+            return cuttingPlane::Cf();
+        }
+
+
         //- For every face original cell in mesh
         const labelList& meshCells() const
         {
diff --git a/src/sampling/sampledSurface/sampledSurface/sampledSurface.C b/src/sampling/sampledSurface/sampledSurface/sampledSurface.C
index d1281cfb457cd542804eb1213faebdcc7771e3f9..ddaea516a07d549cbcca84d743481d154d6c2d4d 100644
--- a/src/sampling/sampledSurface/sampledSurface/sampledSurface.C
+++ b/src/sampling/sampledSurface/sampledSurface/sampledSurface.C
@@ -41,76 +41,10 @@ namespace Foam
 
 void Foam::sampledSurface::clearGeom() const
 {
-    deleteDemandDrivenData(SfPtr_);
-    deleteDemandDrivenData(magSfPtr_);
-    deleteDemandDrivenData(CfPtr_);
     area_ = -1;
 }
 
 
-void Foam::sampledSurface::makeSf() const
-{
-    // It is an error to recalculate if the pointer is already set
-    if (SfPtr_)
-    {
-        FatalErrorInFunction
-            << "face area vectors already exist"
-            << abort(FatalError);
-    }
-
-    const faceList& theFaces = faces();
-    SfPtr_ = new vectorField(theFaces.size());
-
-    vectorField& values = *SfPtr_;
-    forAll(theFaces, facei)
-    {
-        values[facei] = theFaces[facei].normal(points());
-    }
-}
-
-
-void Foam::sampledSurface::makeMagSf() const
-{
-    // It is an error to recalculate if the pointer is already set
-    if (magSfPtr_)
-    {
-        FatalErrorInFunction
-            << "mag face areas already exist"
-            << abort(FatalError);
-    }
-
-    const faceList& theFaces = faces();
-    magSfPtr_ = new scalarField(theFaces.size());
-
-    scalarField& values = *magSfPtr_;
-    forAll(theFaces, facei)
-    {
-        values[facei] = theFaces[facei].mag(points());
-    }
-}
-
-
-void Foam::sampledSurface::makeCf() const
-{
-    // It is an error to recalculate if the pointer is already set
-    if (CfPtr_)
-    {
-        FatalErrorInFunction
-            << "face centres already exist"
-            << abort(FatalError);
-    }
-
-    const faceList& theFaces = faces();
-    CfPtr_ = new vectorField(theFaces.size());
-
-    vectorField& values = *CfPtr_;
-    forAll(theFaces, facei)
-    {
-        values[facei] = theFaces[facei].centre(points());
-    }
-}
-
-
 // * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
 
 Foam::autoPtr<Foam::sampledSurface> Foam::sampledSurface::New
@@ -156,9 +90,6 @@ Foam::sampledSurface::sampledSurface
     name_(name),
     mesh_(mesh),
     interpolate_(interpolate),
-    SfPtr_(nullptr),
-    magSfPtr_(nullptr),
-    CfPtr_(nullptr),
     area_(-1)
 {}
 
@@ -173,9 +104,6 @@ Foam::sampledSurface::sampledSurface
     name_(name),
     mesh_(mesh),
     interpolate_(dict.lookupOrDefault("interpolate", false)),
-    SfPtr_(nullptr),
-    magSfPtr_(nullptr),
-    CfPtr_(nullptr),
     area_(-1)
 {
     dict.readIfPresent("name", name_);
@@ -192,39 +120,6 @@ Foam::sampledSurface::~sampledSurface()
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-const Foam::vectorField& Foam::sampledSurface::Sf() const
-{
-    if (!SfPtr_)
-    {
-        makeSf();
-    }
-
-    return *SfPtr_;
-}
-
-
-const Foam::scalarField& Foam::sampledSurface::magSf() const
-{
-    if (!magSfPtr_)
-    {
-        makeMagSf();
-    }
-
-    return *magSfPtr_;
-}
-
-
-const Foam::vectorField& Foam::sampledSurface::Cf() const
-{
-    if (!CfPtr_)
-    {
-        makeCf();
-    }
-
-    return *CfPtr_;
-}
-
-
 Foam::scalar Foam::sampledSurface::area() const
 {
     if (area_ < 0)
diff --git a/src/sampling/sampledSurface/sampledSurface/sampledSurface.H b/src/sampling/sampledSurface/sampledSurface/sampledSurface.H
index b0a19707a96dc7ed50f0c2460d68e95b524ddb4c..3ddf4c29804166b6aa8d141edf21f803d27c1056 100644
--- a/src/sampling/sampledSurface/sampledSurface/sampledSurface.H
+++ b/src/sampling/sampledSurface/sampledSurface/sampledSurface.H
@@ -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.
@@ -98,31 +98,10 @@ class sampledSurface
 
     // Demand-driven data
 
-        //- Face area vectors
-        mutable vectorField* SfPtr_;
-
-        //- Mag face area vectors
-        mutable scalarField* magSfPtr_;
-
-        //- Face centres
-        mutable vectorField* CfPtr_;
-
         //- Total surface area
         mutable scalar area_;
 
 
-    // Make geometric data
-
-        //- Make Sf
-        void makeSf() const;
-
-        //- Make magSf
-        void makeMagSf() const;
-
-        //- Make Cf
-        void makeCf() const;
-
-
     // Service methods
 
         //- Check field size matches surface size
@@ -284,18 +263,19 @@ public:
         //- Faces of surface
         virtual const faceList& faces() const = 0;
 
-        //- Return face area vectors
-        virtual const vectorField& Sf() const;
+        //- Face area vectors
+        virtual const vectorField& Sf() const = 0;
 
-        //- Return face area magnitudes
-        virtual const scalarField& magSf() const;
+        //- Face area magnitudes
+        virtual const scalarField& magSf() const = 0;
 
-        //- Return face centres as vectorField
-        virtual const vectorField& Cf() const;
+        //- Face centres
+        virtual const vectorField& Cf() const = 0;
 
         //- The total surface area
         scalar area() const;
 
+
         //- Integration of a field across the surface
         template<class Type>
         Type integrate(const Field<Type>&) const;
diff --git a/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.H b/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.H
index 6a41255075237d01ec63bac6dc6a290733949695..1d62d0a02aa5399c90cfab0ac80e8579d3a4622a 100644
--- a/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.H
+++ b/src/sampling/sampledSurface/sampledTriSurfaceMesh/sampledTriSurfaceMesh.H
@@ -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.
@@ -216,6 +216,24 @@ public:
             return MeshStorage::faces();
         }
 
+        //- Face area vectors
+        virtual const vectorField& Sf() const
+        {
+            return MeshStorage::Sf();
+        }
+
+        //- Face area magnitudes
+        virtual const scalarField& magSf() const
+        {
+            return MeshStorage::magSf();
+        }
+
+        //- Face centres
+        virtual const vectorField& Cf() const
+        {
+            return MeshStorage::Cf();
+        }
+
 
         //- Sample field on surface
         virtual tmp<scalarField> sample
diff --git a/src/sampling/sampledSurface/thresholdCellFaces/sampledThresholdCellFaces.H b/src/sampling/sampledSurface/thresholdCellFaces/sampledThresholdCellFaces.H
index 840a9920ad1c1a051c62afd256656ea3ae6055ff..2fa91d2345848146025ac7cbc2768580ab76d53c 100644
--- a/src/sampling/sampledSurface/thresholdCellFaces/sampledThresholdCellFaces.H
+++ b/src/sampling/sampledSurface/thresholdCellFaces/sampledThresholdCellFaces.H
@@ -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.
@@ -148,6 +148,25 @@ public:
             return MeshStorage::faces();
         }
 
+        //- Face area vectors (normals)
+        virtual const vectorField& Sf() const
+        {
+            return MeshStorage::Sf();
+        }
+
+        //- Face area magnitudes
+        virtual const scalarField& magSf() const
+        {
+            return MeshStorage::magSf();
+        }
+
+        //- Face centres
+        virtual const vectorField& Cf() const
+        {
+            return MeshStorage::Cf();
+        }
+
+
         //- Sample field on surface
         virtual tmp<scalarField> sample(const volScalarField&) const;
 
diff --git a/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriterTemplates.C b/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriterTemplates.C
index 41c404deb6e96c53e5ae1f3f3098eb16b0295f41..01a0716a9d47458935ef47d2056b21171633b4d0 100644
--- a/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriterTemplates.C
+++ b/src/sampling/sampledSurface/writers/ensight/ensightSurfaceWriterTemplates.C
@@ -28,6 +28,7 @@ License
 #include "OFstream.H"
 #include "OSspecific.H"
 #include "ensightPartFaces.H"
+#include "ensightSerialOutput.H"
 #include "ensightPTraits.H"
 #include "OStringStream.H"
 #include "regExp.H"
@@ -121,7 +122,13 @@ Foam::fileName Foam::ensightSurfaceWriter::writeUncollated
 
     // Write field
     osField.writeKeyword(ensightPTraits<Type>::typeName);
-    ensPart.writeField(osField, values, isNodeValues);
+    ensightSerialOutput::writeField
+    (
+        values,
+        ensPart,
+        osField,
+        isNodeValues
+    );
 
     return osCase.name();
 }
@@ -337,12 +344,21 @@ Foam::fileName Foam::ensightSurfaceWriter::writeCollated
         varName,
         writeFormat_
     );
+
     if (verbose)
     {
         Info<< "Writing field file to " << osField.name() << endl;
     }
+
+    // Write field
     osField.writeKeyword(ensightPTraits<Type>::typeName);
-    ensPart.writeField(osField, values, isNodeValues);
+    ensightSerialOutput::writeField
+    (
+        values,
+        ensPart,
+        osField,
+        isNodeValues
+    );
 
     // place a timestamp in the directory for future reference
     {
diff --git a/src/surfMesh/MeshedSurface/MeshedSurface.C b/src/surfMesh/MeshedSurface/MeshedSurface.C
index 825949ebd43313b6079531a5f1a026df39117271..e6cd3985057e3ef740e201062992f30dcb624db5 100644
--- a/src/surfMesh/MeshedSurface/MeshedSurface.C
+++ b/src/surfMesh/MeshedSurface/MeshedSurface.C
@@ -431,7 +431,9 @@ Foam::MeshedSurface<Face>::MeshedSurface
 
 template<class Face>
 Foam::MeshedSurface<Face>::~MeshedSurface()
-{}
+{
+    clear();
+}
 
 
 // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
@@ -500,6 +502,9 @@ void Foam::MeshedSurface<Face>::clear()
 template<class Face>
 void Foam::MeshedSurface<Face>::movePoints(const pointField& newPoints)
 {
+    // Changes areas, normals etc.
+    ParentType::clearGeom();
+
     // Adapt for new point position
     ParentType::movePoints(newPoints);
 
@@ -511,9 +516,12 @@ void Foam::MeshedSurface<Face>::movePoints(const pointField& newPoints)
 template<class Face>
 void Foam::MeshedSurface<Face>::scalePoints(const scalar scaleFactor)
 {
-    // avoid bad scaling
+    // Avoid bad scaling
     if (scaleFactor > 0 && scaleFactor != 1.0)
     {
+        // Changes areas, normals etc.
+        ParentType::clearGeom();
+
         pointField newPoints(scaleFactor*this->points());
 
         // Adapt for new point position
@@ -586,7 +594,7 @@ void Foam::MeshedSurface<Face>::reset
 template<class Face>
 void Foam::MeshedSurface<Face>::cleanup(const bool verbose)
 {
-    // merge points (already done for STL, TRI)
+    // Merge points (already done for STL, TRI)
     stitchFaces(SMALL, verbose);
 
     checkFaces(verbose);
@@ -943,8 +951,6 @@ Foam::label Foam::MeshedSurface<Face>::triangulate
 }
 
 
-
-
 template<class Face>
 Foam::MeshedSurface<Face> Foam::MeshedSurface<Face>::subsetMesh
 (
diff --git a/src/surfMesh/MeshedSurface/MeshedSurface.H b/src/surfMesh/MeshedSurface/MeshedSurface.H
index 1362197d8c1c1c5c3d988e24718f57c1863ce5a6..9f3a34a80a012d4bdcd5ebb1787bd54b011a6a43 100644
--- a/src/surfMesh/MeshedSurface/MeshedSurface.H
+++ b/src/surfMesh/MeshedSurface/MeshedSurface.H
@@ -339,6 +339,31 @@ public:
                 return zones_;
             }
 
+            //- Face area vectors (normals)
+            inline const vectorField& Sf() const
+            {
+                return ParentType::faceAreas();
+            }
+
+            //- Face area magnitudes
+            inline const scalarField& magSf() const
+            {
+                return ParentType::magFaceAreas();
+            }
+
+            //- Face centres
+            inline const vectorField& Cf() const
+            {
+                return ParentType::faceCentres();
+            }
+
+
+        // Edit
+
+            //- Clear all storage
+            virtual void clear();
+
+
             //- Add surface zones
             virtual void addZones
             (
@@ -365,11 +390,6 @@ public:
             virtual void removeZones();
 
 
-        // Edit
-
-            //- Clear all storage
-            virtual void clear();
-
             //- Move points
             virtual void movePoints(const pointField&);
 
diff --git a/src/surfMesh/surfMesh/surfMesh.H b/src/surfMesh/surfMesh/surfMesh.H
index d8bbff5fe4f561822a2beaf420100a363209c392..f936d3f46d0bd6232994e9fd6bf65a9ccdfce9f2 100644
--- a/src/surfMesh/surfMesh/surfMesh.H
+++ b/src/surfMesh/surfMesh/surfMesh.H
@@ -233,6 +233,25 @@ public:
             //- Check the surface zone definitions
             void checkZones();
 
+
+            //- Return face area vectors (normals)
+            inline const vectorField& Sf() const
+            {
+                return MeshReference::faceAreas();
+            }
+
+            //- Return face area magnitudes
+            inline const scalarField& magSf() const
+            {
+                return MeshReference::magFaceAreas();
+            }
+
+            //- Face centres
+            inline const vectorField& Cf() const
+            {
+                return MeshReference::faceCentres();
+            }
+
             //- Add surface zones
             void addZones
             (
diff --git a/src/surfMesh/surfMesh/surfMeshClear.C b/src/surfMesh/surfMesh/surfMeshClear.C
index 179f202c2d5c589aa01718ef5d1147db45a08cf9..39bef03a02d153906b0a6b3ef64f507f34173b77 100644
--- a/src/surfMesh/surfMesh/surfMeshClear.C
+++ b/src/surfMesh/surfMesh/surfMeshClear.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.
@@ -69,6 +69,8 @@ void Foam::surfMesh::clearAddressing()
 
 void Foam::surfMesh::clearOut()
 {
+    MeshReference::clearOut();
+
     clearGeom();
     clearAddressing();
 }
diff --git a/src/surfMesh/surfMesh/surfMeshIO.C b/src/surfMesh/surfMesh/surfMeshIO.C
index 5e7072e3a44480aa5a7f2d2a51c74331c3848eeb..f2a5c54245ab0bc8420b71db062b68bb3e497cad 100644
--- a/src/surfMesh/surfMesh/surfMeshIO.C
+++ b/src/surfMesh/surfMesh/surfMeshIO.C
@@ -168,7 +168,7 @@ Foam::surfMesh::readUpdateState Foam::surfMesh::readUpdate()
             Info<< "Point motion" << endl;
         }
 
-        clearGeom();
+        clearOut();
         storedIOPoints().instance() = pointsInst;
 
         storedIOPoints() = pointIOField
diff --git a/src/triSurface/triSurface/triSurface.H b/src/triSurface/triSurface/triSurface.H
index c892fb22c0e19d6fa55e4f02cc5774dc8bc2ca67..0383c14a2b30ff01373d4067608b0ae2258b739d 100644
--- a/src/triSurface/triSurface/triSurface.H
+++ b/src/triSurface/triSurface/triSurface.H
@@ -335,6 +335,25 @@ public:
             const labelList& edgeOwner() const;
 
 
+            //- Face area vectors (normals)
+            inline const vectorField& Sf() const
+            {
+                return ParentType::faceAreas();
+            }
+
+            //- Face area magnitudes
+            inline const scalarField& magSf() const
+            {
+                return ParentType::magFaceAreas();
+            }
+
+            //- Face centres
+            inline const vectorField& Cf() const
+            {
+                return ParentType::faceCentres();
+            }
+
+
         // Edit
 
             //- Move points
diff --git a/tutorials/incompressible/simpleFoam/motorBike/system/controlDict b/tutorials/incompressible/simpleFoam/motorBike/system/controlDict
index 5678be2ee3f8aed358a484f2c612885235cd0972..d728f0be9c3d7a85c8ae660c9530b9b9a66386b6 100644
--- a/tutorials/incompressible/simpleFoam/motorBike/system/controlDict
+++ b/tutorials/incompressible/simpleFoam/motorBike/system/controlDict
@@ -50,6 +50,7 @@ functions
     #include "wallBoundedStreamLines"
     #include "cuttingPlane"
     #include "forceCoeffs"
+    #include "ensightWrite"
 }
 
 
diff --git a/tutorials/incompressible/simpleFoam/motorBike/system/ensightWrite b/tutorials/incompressible/simpleFoam/motorBike/system/ensightWrite
new file mode 100644
index 0000000000000000000000000000000000000000..34e7b14d71b4f1e12eea04845ba07454a9f3264b
--- /dev/null
+++ b/tutorials/incompressible/simpleFoam/motorBike/system/ensightWrite
@@ -0,0 +1,17 @@
+// -*- C++ -*-
+// Minimal example of using the ensight write function object.
+// Many more options possible
+ensightWrite
+{
+    type    ensightWrite;
+    libs    ("libutilityFunctionObjects.so");
+    log     true;
+
+    // Fields to output (words or regex)
+    fields  (U p "(k|epsilon|omega)");
+
+    writeControl writeTime;
+    writeIterval 1;
+}
+
+// ************************************************************************* //
diff --git a/wmake/rules/General/CGAL b/wmake/rules/General/CGAL
index fd1965e656e351412c3d1b34cb53e89cce56e08b..83e8b1df1e9edcf44233b08cc898d79da5ff6797 100644
--- a/wmake/rules/General/CGAL
+++ b/wmake/rules/General/CGAL
@@ -8,6 +8,6 @@ CGAL_INC = \
 CGAL_LIBS = \
     -L$(MPFR_ARCH_PATH)/lib$(WM_COMPILER_LIB_ARCH) \
     -L$(GMP_ARCH_PATH)/lib$(WM_COMPILER_LIB_ARCH) \
-    -L$(BOOST_ARCH_PATH)/lib \
-    -L$(CGAL_ARCH_PATH)/lib \
+    -L$(BOOST_ARCH_PATH)/lib$(WM_COMPILER_LIB_ARCH) \
+    -L$(CGAL_ARCH_PATH)/lib$(WM_COMPILER_LIB_ARCH) \
     -lCGAL