diff --git a/applications/utilities/mesh/manipulation/setSet/Make/files b/applications/utilities/mesh/manipulation/setSet/Make/files
index e6da558d1db1d047602ccb934d17d2a94d462431..75c578a1e54aefab9c857379dc148d97746adb56 100644
--- a/applications/utilities/mesh/manipulation/setSet/Make/files
+++ b/applications/utilities/mesh/manipulation/setSet/Make/files
@@ -1,7 +1,3 @@
-writePointSet.C
-writeFuns.C
-writePatch.C
 setSet.C
 
 EXE = $(FOAM_APPBIN)/setSet
-
diff --git a/applications/utilities/mesh/manipulation/setSet/Make/options b/applications/utilities/mesh/manipulation/setSet/Make/options
index febadade7b4bed3e02b5fef45eed79f404ab0453..7c01749935ced7aef267f83ae15977f8e0cccb51 100644
--- a/applications/utilities/mesh/manipulation/setSet/Make/options
+++ b/applications/utilities/mesh/manipulation/setSet/Make/options
@@ -1,4 +1,5 @@
 EXE_INC = \
+    -I$(LIB_SRC)/fileFormats/lnInclude \
     -I$(LIB_SRC)/meshTools/lnInclude \
     $(COMP_FLAGS)
 
diff --git a/applications/utilities/mesh/manipulation/setSet/setSet.C b/applications/utilities/mesh/manipulation/setSet/setSet.C
index 1dffb5849e9efee00bb84be724b5a1fe96a08265..8ce92fc9b752a4443d0a3739ea643f1c128afd99 100644
--- a/applications/utilities/mesh/manipulation/setSet/setSet.C
+++ b/applications/utilities/mesh/manipulation/setSet/setSet.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) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -44,8 +44,9 @@ Description
 #include "OFstream.H"
 #include "IFstream.H"
 #include "demandDrivenData.H"
-#include "writePatch.H"
-#include "writePointSet.H"
+#include "foamVtkWriteCellSetFaces.H"
+#include "foamVtkWriteFaceSet.H"
+#include "foamVtkWritePointSet.H"
 #include "IOobjectList.H"
 #include "cellZoneSet.H"
 #include "faceZoneSet.H"
@@ -75,104 +76,39 @@ void writeVTK
 (
     const polyMesh& mesh,
     const topoSet& currentSet,
-    const fileName& vtkName
+    const fileName& vtkBaseName
 )
 {
     if (isA<faceSet>(currentSet))
     {
         // Faces of set with OpenFOAM faceID as value
-
-        faceList setFaces(currentSet.size());
-        labelList faceValues(currentSet.size());
-        label setFacei = 0;
-
-        forAllConstIter(topoSet, currentSet, iter)
-        {
-            setFaces[setFacei] = mesh.faces()[iter.key()];
-            faceValues[setFacei] = iter.key();
-            setFacei++;
-        }
-
-        primitiveFacePatch fp(setFaces, mesh.points());
-
-        writePatch
+        vtk::writeFaceSet
         (
-            true,
-            currentSet.name(),
-            fp,
-            "faceID",
-            faceValues,
-            mesh.time().path()/vtkName
+            mesh,
+            currentSet,
+            mesh.time().path()/vtkBaseName,
+            vtk::formatType::LEGACY_BINARY
         );
     }
     else if (isA<cellSet>(currentSet))
     {
         // External faces of cellset with OpenFOAM cellID as value
-
-        Map<label> cellFaces(currentSet.size());
-
-        forAllConstIter(cellSet, currentSet, iter)
-        {
-            label celli = iter.key();
-
-            const cell& cFaces = mesh.cells()[celli];
-
-            forAll(cFaces, i)
-            {
-                label facei = cFaces[i];
-
-                if (mesh.isInternalFace(facei))
-                {
-                    label otherCelli = mesh.faceOwner()[facei];
-
-                    if (otherCelli == celli)
-                    {
-                        otherCelli = mesh.faceNeighbour()[facei];
-                    }
-
-                    if (!currentSet.found(otherCelli))
-                    {
-                        cellFaces.insert(facei, celli);
-                    }
-                }
-                else
-                {
-                    cellFaces.insert(facei, celli);
-                }
-            }
-        }
-
-        faceList setFaces(cellFaces.size());
-        labelList faceValues(cellFaces.size());
-        label setFacei = 0;
-
-        forAllConstIter(Map<label>, cellFaces, iter)
-        {
-            setFaces[setFacei] = mesh.faces()[iter.key()];
-            faceValues[setFacei] = iter();              // Cell ID
-            setFacei++;
-        }
-
-        primitiveFacePatch fp(setFaces, mesh.points());
-
-        writePatch
+        vtk::writeCellSetFaces
         (
-            true,
-            currentSet.name(),
-            fp,
-            "cellID",
-            faceValues,
-            mesh.time().path()/vtkName
+            mesh,
+            currentSet,
+            mesh.time().path()/vtkBaseName,
+            vtk::formatType::LEGACY_BINARY
         );
     }
     else if (isA<pointSet>(currentSet))
     {
-        writePointSet
+        vtk::writePointSet
         (
-            true,
             mesh,
             currentSet,
-            mesh.time().path()/vtkName
+            mesh.time().path()/vtkBaseName,
+            vtk::formatType::LEGACY_BINARY
         );
     }
     else
@@ -187,58 +123,58 @@ void writeVTK
 void printHelp(Ostream& os)
 {
     os  << "Please type 'help', 'list', 'quit', 'time ddd'"
-        << " or a set command after prompt." << endl
-        << "'list' will show all current cell/face/point sets." << endl
-        << "'time ddd' will change the current time." << endl
-        << endl
-        << "A set command should be of the following form" << endl
-        << endl
+        << " or a set command after prompt." << nl
+        << "'list' will show all current cell/face/point sets." << nl
+        << "'time ddd' will change the current time." << nl
+        << nl
+        << "A set command should be of the following form" << nl
+        << nl
         << "    cellSet|faceSet|pointSet <setName> <action> <source>"
-        << endl
-        << endl
-        << "The <action> is one of" << endl
-        << "    list            - prints the contents of the set" << endl
-        << "    clear           - clears the set" << endl
-        << "    invert          - inverts the set" << endl
-        << "    remove          - remove the set" << endl
-        << "    new <source>    - sets to set to the source set" << endl
-        << "    add <source>    - adds all elements from the source set" << endl
-        << "    delete <source> - deletes      ,," << endl
+        << nl
+        << nl
+        << "The <action> is one of" << nl
+        << "    list            - prints the contents of the set" << nl
+        << "    clear           - clears the set" << nl
+        << "    invert          - inverts the set" << nl
+        << "    remove          - remove the set" << nl
+        << "    new <source>    - sets to set to the source set" << nl
+        << "    add <source>    - adds all elements from the source set" << nl
+        << "    delete <source> - deletes      ,," << nl
         << "    subset <source> - combines current set with the source set"
-        << endl
-        << endl
+        << nl
+        << nl
         << "The sources come in various forms. Type a wrong source"
-        << " to see all the types available." << endl
-        << endl
+        << " to see all the types available." << nl
+        << nl
         << "Example: pick up all cells connected by point or face to patch"
-        << " movingWall" << endl
-        << endl
-        << "Pick up all faces of patch:" << endl
-        << "    faceSet f0 new patchToFace movingWall" << endl
-        << "Add faces 0,1,2:" << endl
-        << "    faceSet f0 add labelToFace (0 1 2)" << endl
-        << "Pick up all points used by faces in faceSet f0:" << endl
-        << "    pointSet p0 new faceToPoint f0 all" << endl
-        << "Pick up cell which has any face in f0:" << endl
-        << "    cellSet c0 new faceToCell f0 any" << endl
-        << "Add cells which have any point in p0:" << endl
-        << "    cellSet c0 add pointToCell p0 any" << endl
-        << "List set:" << endl
-        << "    cellSet c0 list" << endl
-        << endl
-        << "Zones can be set using zoneSets from corresponding sets:" << endl
-        << "    cellZoneSet c0Zone new setToCellZone c0" << endl
-        << "    faceZoneSet f0Zone new setToFaceZone f0" << endl
-        << endl
-        << "or if orientation is important:" << endl
-        << "    faceZoneSet f0Zone new setsToFaceZone f0 c0" << endl
-        << endl
-        << "ZoneSets can be manipulated using the general actions:" << endl
-        << "    list            - prints the contents of the set" << endl
-        << "    clear           - clears the set" << endl
+        << " movingWall" << nl
+        << nl
+        << "Pick up all faces of patch:" << nl
+        << "    faceSet f0 new patchToFace movingWall" << nl
+        << "Add faces 0,1,2:" << nl
+        << "    faceSet f0 add labelToFace (0 1 2)" << nl
+        << "Pick up all points used by faces in faceSet f0:" << nl
+        << "    pointSet p0 new faceToPoint f0 all" << nl
+        << "Pick up cell which has any face in f0:" << nl
+        << "    cellSet c0 new faceToCell f0 any" << nl
+        << "Add cells which have any point in p0:" << nl
+        << "    cellSet c0 add pointToCell p0 any" << nl
+        << "List set:" << nl
+        << "    cellSet c0 list" << nl
+        << nl
+        << "Zones can be set using zoneSets from corresponding sets:" << nl
+        << "    cellZoneSet c0Zone new setToCellZone c0" << nl
+        << "    faceZoneSet f0Zone new setToFaceZone f0" << nl
+        << nl
+        << "or if orientation is important:" << nl
+        << "    faceZoneSet f0Zone new setsToFaceZone f0 c0" << nl
+        << nl
+        << "ZoneSets can be manipulated using the general actions:" << nl
+        << "    list            - prints the contents of the set" << nl
+        << "    clear           - clears the set" << nl
         << "    invert          - inverts the set (undefined orientation)"
-        << endl
-        << "    remove          - remove the set" << endl
+        << nl
+        << "    remove          - remove the set" << nl
         << endl;
 }
 
@@ -577,7 +513,6 @@ bool doCommand
                         "VTK"/currentSet.name()/currentSet.name()
                       + "_"
                       + name(mesh.time().timeIndex())
-                      + ".vtk"
                     );
 
                     Info<< "    Writing " << currentSet.name()
diff --git a/applications/utilities/mesh/manipulation/setSet/writeFuns.C b/applications/utilities/mesh/manipulation/setSet/writeFuns.C
deleted file mode 100644
index 2a104cb01ecfa72cbb1c2a41f1bbaec0275c3be0..0000000000000000000000000000000000000000
--- a/applications/utilities/mesh/manipulation/setSet/writeFuns.C
+++ /dev/null
@@ -1,225 +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/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "writeFuns.H"
-#include "endian.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-void Foam::writeFuns::swapWord(int32_t& word32)
-{
-    char* mem = reinterpret_cast<char*>(&word32);
-
-    char a = mem[0];
-    mem[0] = mem[3];
-    mem[3] = a;
-
-    a = mem[1];
-    mem[1] = mem[2];
-    mem[2] = a;
-}
-
-
-void Foam::writeFuns::swapWords(const label nWords, int32_t* words32)
-{
-    for (label i=0; i<nWords; i++)
-    {
-        swapWord(words32[i]);
-    }
-}
-
-
-void Foam::writeFuns::write
-(
-    std::ostream& os,
-    const bool binary,
-    List<floatScalar>& fField
-)
-{
-    if (binary)
-    {
-        #ifdef WM_LITTLE_ENDIAN
-        swapWords(fField.size(), reinterpret_cast<int32_t*>(fField.begin()));
-        #endif
-
-        os.write
-        (
-            reinterpret_cast<char*>(fField.begin()),
-            fField.size()*sizeof(float)
-        );
-
-        os  << std::endl;
-    }
-    else
-    {
-        forAll(fField, i)
-        {
-            os  << fField[i] << ' ';
-
-            if (i > 0 && (i % 10) == 0)
-            {
-                os  << std::endl;
-            }
-        }
-        os  << std::endl;
-    }
-}
-
-
-void Foam::writeFuns::write
-(
-    std::ostream& os,
-    const bool binary,
-    DynamicList<floatScalar>& fField
-)
-{
-    List<floatScalar>& fld = fField.shrink();
-    write(os, binary, fld);
-}
-
-
-void Foam::writeFuns::write
-(
-    std::ostream& os,
-    const bool binary,
-    labelList& elems
-)
-{
-    if (binary)
-    {
-        #ifdef WM_LITTLE_ENDIAN
-        swapWords
-        (
-            (sizeof(label)/4)*elems.size(),
-            reinterpret_cast<int32_t*>(elems.begin())
-        );
-        #endif
-        os.write
-        (
-            reinterpret_cast<char*>(elems.begin()),
-            elems.size()*sizeof(label)
-        );
-
-        os  << std::endl;
-    }
-    else
-    {
-        forAll(elems, i)
-        {
-            os  << elems[i] << ' ';
-
-            if (i > 0 && (i % 10) == 0)
-            {
-                os  << std::endl;
-            }
-        }
-        os  << std::endl;
-    }
-}
-
-
-void Foam::writeFuns::write
-(
-    std::ostream& os,
-    const bool binary,
-    DynamicList<label>& elems
-)
-{
-    labelList& fld = elems.shrink();
-    write(os, binary, fld);
-}
-
-
-void Foam::writeFuns::insert(const point& pt, DynamicList<floatScalar>& dest)
-{
-    dest.append(float(pt.x()));
-    dest.append(float(pt.y()));
-    dest.append(float(pt.z()));
-}
-
-
-void Foam::writeFuns::insert(const labelList& source, DynamicList<label>& dest)
-{
-    forAll(source, i)
-    {
-        dest.append(source[i]);
-    }
-}
-
-
-void Foam::writeFuns::insert
-(
-    const List<scalar>& source,
-    DynamicList<floatScalar>& dest
-)
-{
-    forAll(source, i)
-    {
-        dest.append(float(source[i]));
-    }
-}
-
-
-void Foam::writeFuns::insert
-(
-    const labelList& map,
-    const List<scalar>& source,
-    DynamicList<floatScalar>& dest
-)
-{
-    forAll(map, i)
-    {
-        dest.append(float(source[map[i]]));
-    }
-}
-
-
-void Foam::writeFuns::insert
-(
-    const List<point>& source,
-    DynamicList<floatScalar>& dest
-)
-{
-    forAll(source, i)
-    {
-       insert(source[i], dest);
-    }
-}
-
-void Foam::writeFuns::insert
-(
-    const labelList& map,
-    const List<point>& source,
-    DynamicList<floatScalar>& dest
-)
-{
-    forAll(map, i)
-    {
-       insert(source[map[i]], dest);
-    }
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/mesh/manipulation/setSet/writeFuns.H b/applications/utilities/mesh/manipulation/setSet/writeFuns.H
deleted file mode 100644
index 51c1ed8509fb0027d435848c1cf5f05b5a8d96b0..0000000000000000000000000000000000000000
--- a/applications/utilities/mesh/manipulation/setSet/writeFuns.H
+++ /dev/null
@@ -1,127 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2014 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::writeFuns
-
-Description
-    Various functions for collecting and writing binary data.
-
-    The LITTLE_ENDIAN is based on 32bit words.
-    It is not clear how 64bit labels should be handled, currently they are
-    split into two 32bit words and swapWord applied to these two.
-
-    writeFuns should be a namespace rather than a class.
-
-SourceFiles
-    writeFuns.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef writeFuns_H
-#define writeFuns_H
-
-#include "labelList.H"
-#include "floatScalar.H"
-#include "OFstream.H"
-#include "DynamicList.H"
-#include "point.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-/*---------------------------------------------------------------------------*\
-                           Class writeFuns Declaration
-\*---------------------------------------------------------------------------*/
-
-class writeFuns
-{
-    // Private member functions
-
-        //- Swap halves of word
-        static void swapWord(int32_t& word32);
-
-        //- Swap halves of word
-        static void swapWords(const label nWords, int32_t* words32);
-
-
-public:
-
-    //- Write floats ascii or binary.
-    //  If binary optionally in-place swaps argument
-    static void write(std::ostream&, const bool, DynamicList<floatScalar>&);
-
-    //- Write labels ascii or binary.
-    //  If binary optionally in-place swaps argument
-    static void write(std::ostream&, const bool, DynamicList<label>&);
-
-    //- Write floats ascii or binary.
-    //  If binary optionally in-place swaps argument
-    static void write(std::ostream&, const bool, List<floatScalar>&);
-
-    //- Write labels ascii or binary.
-    //  If binary optionally in-place swaps argument
-    static void write(std::ostream&, const bool, labelList&);
-
-    //- Append point to given DynamicList
-    static void insert(const point&, DynamicList<floatScalar>& dest);
-
-    //- Append elements of labelList to given DynamicList
-    static void insert(const labelList&, DynamicList<label>&);
-
-    //- Append elements of scalarList to given DynamicList
-    static void insert(const List<scalar>&, DynamicList<floatScalar>&);
-
-    //- Append elements of scalarList to given DynamicList using map
-    static void insert
-    (
-        const labelList& map,
-        const List<scalar>& source,
-        DynamicList<floatScalar>&
-    );
-
-    //- Append points to given DynamicList of floats
-    static void insert(const List<point>& source, DynamicList<floatScalar>&);
-
-    //- Append points to given DynamicList of floats using map
-    static void insert
-    (
-        const labelList& map,
-        const List<point>& source,
-        DynamicList<floatScalar>&
-    );
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/applications/utilities/mesh/manipulation/setSet/writePatch.C b/applications/utilities/mesh/manipulation/setSet/writePatch.C
deleted file mode 100644
index 6a3269956662854835e10013e0a3e53fc927a85c..0000000000000000000000000000000000000000
--- a/applications/utilities/mesh/manipulation/setSet/writePatch.C
+++ /dev/null
@@ -1,127 +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/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "writePatch.H"
-#include "OFstream.H"
-#include "writeFuns.H"
-#include "primitiveFacePatch.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
-
-void writePatch
-(
-    const bool binary,
-    const word& setName,
-    const primitiveFacePatch& fp,
-    const word& fieldName,
-    labelList& fieldValues,
-    const fileName& fileName
-)
-{
-    std::ofstream pStream(fileName.c_str());
-
-    pStream
-        << "# vtk DataFile Version 2.0" << std::endl
-        << setName << std::endl;
-    if (binary)
-    {
-        pStream << "BINARY" << std::endl;
-    }
-    else
-    {
-        pStream << "ASCII" << std::endl;
-    }
-    pStream << "DATASET POLYDATA" << std::endl;
-
-
-    //------------------------------------------------------------------
-    //
-    // Write topology
-    //
-    //------------------------------------------------------------------
-
-
-    // Write points and faces as polygons
-
-    pStream << "POINTS " << fp.nPoints() << " float" << std::endl;
-
-    DynamicList<floatScalar> ptField(3*fp.nPoints());
-
-    writeFuns::insert(fp.localPoints(), ptField);
-
-    writeFuns::write(pStream, binary, ptField);
-
-
-    label nFaceVerts = 0;
-
-    forAll(fp.localFaces(), facei)
-    {
-        nFaceVerts += fp.localFaces()[facei].size() + 1;
-    }
-    pStream << "POLYGONS " << fp.size() << ' ' << nFaceVerts
-        << std::endl;
-
-
-    DynamicList<label> vertLabels(nFaceVerts);
-
-    forAll(fp.localFaces(), facei)
-    {
-        const face& f = fp.localFaces()[facei];
-
-        vertLabels.append(f.size());
-
-        writeFuns::insert(f, vertLabels);
-    }
-    writeFuns::write(pStream, binary, vertLabels);
-
-
-    //-----------------------------------------------------------------
-    //
-    // Write data
-    //
-    //-----------------------------------------------------------------
-
-    // Write faceID
-
-    pStream
-        << "CELL_DATA " << fp.size() << std::endl
-        << "FIELD attributes 1" << std::endl;
-
-    // Cell ids first
-    pStream << fieldName << " 1 " << fp.size() << " int" << std::endl;
-
-    writeFuns::write(pStream, binary, fieldValues);
-}
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// ************************************************************************* //
diff --git a/applications/utilities/mesh/manipulation/setSet/writePointSet.C b/applications/utilities/mesh/manipulation/setSet/writePointSet.C
deleted file mode 100644
index 653839da35de5be73f6220cdfce0cc1e581d3b2b..0000000000000000000000000000000000000000
--- a/applications/utilities/mesh/manipulation/setSet/writePointSet.C
+++ /dev/null
@@ -1,105 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "writePointSet.H"
-#include "OFstream.H"
-#include "writeFuns.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
-
-void writePointSet
-(
-    const bool binary,
-    const primitiveMesh& mesh,
-    const topoSet& set,
-    const fileName& fileName
-)
-{
-    std::ofstream pStream(fileName.c_str());
-
-    pStream
-        << "# vtk DataFile Version 2.0" << std::endl
-        << set.name() << std::endl;
-    if (binary)
-    {
-        pStream << "BINARY" << std::endl;
-    }
-    else
-    {
-        pStream << "ASCII" << std::endl;
-    }
-    pStream << "DATASET POLYDATA" << std::endl;
-
-
-    //------------------------------------------------------------------
-    //
-    // Write topology
-    //
-    //------------------------------------------------------------------
-
-
-    labelList pointLabels(set.toc());
-
-    pointField setPoints(mesh.points(), pointLabels);
-
-    // Write points
-
-    pStream << "POINTS " << pointLabels.size() << " float" << std::endl;
-
-    DynamicList<floatScalar> ptField(3*pointLabels.size());
-
-    writeFuns::insert(setPoints, ptField);
-
-    writeFuns::write(pStream, binary, ptField);
-
-
-    //-----------------------------------------------------------------
-    //
-    // Write data
-    //
-    //-----------------------------------------------------------------
-
-    // Write pointID
-
-    pStream
-        << "POINT_DATA " << pointLabels.size() << std::endl
-        << "FIELD attributes 1" << std::endl;
-
-    // Cell ids first
-    pStream << "pointID 1 " << pointLabels.size() << " int" << std::endl;
-
-    writeFuns::write(pStream, binary, pointLabels);
-}
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C
index 705c8e6650438da90a436c50c5a3f7410ebe6de2..bf15ffef0aa542b36f3e73cd1e86a235c159ab04 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C
@@ -173,8 +173,7 @@ int main(int argc, char *argv[])
     (
         "name",
         "subdir",
-        "define sub-directory name to use for ensight data "
-        "(default: 'EnSight')"
+        "sub-directory name for ensight output (default: 'EnSight')"
     );
     argList::addOption
     (
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C
index ab2e67e855e76b05d0753575cb18d612c93dee74..f6fdfae977fa30a64eb97c7af50d9c4b90628d5c 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsightParts/foamToEnsightParts.C
@@ -128,8 +128,7 @@ int main(int argc, char *argv[])
     (
         "name",
         "subdir",
-        "define sub-directory name to use for Ensight data "
-        "(default: \"Ensight\")"
+        "sub-directory name for ensight output (default: 'Ensight')"
     );
     argList::addOption
     (
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/Allwmake b/applications/utilities/postProcessing/dataConversion/foamToVTK/Allwmake
deleted file mode 100755
index 81e0196f99b5ec655b542da25f8471c882e135fd..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/Allwmake
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-cd ${0%/*} || exit 1    # Run from this directory
-
-# Parse arguments for library compilation
-. $WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments
-
-wmake $targetType foamToVTK
-wmake $targetType
-
-#------------------------------------------------------------------------------
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/Make/files b/applications/utilities/postProcessing/dataConversion/foamToVTK/Make/files
index f10482758a05b8e8333e0cea08e1c2c52d71edf4..aaec9f26ab05eec617f82b9c505be4af6616b175 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/Make/files
+++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/Make/files
@@ -1,3 +1,4 @@
+foamVtkLagrangianWriter.C
 foamToVTK.C
 
 EXE = $(FOAM_APPBIN)/foamToVTK
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/Make/options b/applications/utilities/postProcessing/dataConversion/foamToVTK/Make/options
index c2445fd549946f440c1fa285d82253acae97ac3e..541ffa86aeb80f7e4034004d2d545ef581454bb3 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/Make/options
+++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/Make/options
@@ -1,12 +1,13 @@
 EXE_INC = \
-    -IfoamToVTK/lnInclude \
+    -I$(LIB_SRC)/fileFormats/lnInclude \
+    -I$(LIB_SRC)/conversion/lnInclude \
     -I$(LIB_SRC)/lagrangian/basic/lnInclude \
     -I$(LIB_SRC)/finiteVolume/lnInclude \
     -I$(LIB_SRC)/dynamicMesh/lnInclude \
     -I$(LIB_SRC)/meshTools/lnInclude
 
 EXE_LIBS = \
-    -lfoamToVTK \
+    -lconversion \
     -ldynamicMesh \
     -llagrangian \
     -lgenericPatchFields
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C
index dcf612a663ef2440b4b53943ce2c3ab24f4ab796..a012136f01328080fe6f2b3ecb56c829c5fea2ea 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.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  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,7 +28,7 @@ Group
     grpPostProcessingUtilities
 
 Description
-    Legacy VTK file format writer.
+    VTK file format writer.
 
     - Handles volFields, pointFields, surfaceScalarField, surfaceVectorField
       fields.
@@ -46,6 +46,9 @@ Usage
       - \par -ascii
         Write VTK data in ASCII format instead of binary.
 
+      - \par -xml
+        Write VTK data in XML format instead of legacy format
+
       - \par -mesh \<name\>
         Use a different mesh name (instead of -region)
 
@@ -103,7 +106,7 @@ Usage
         use the time index in the VTK file name instead of the time index
 
 Note
-    mesh subset is handled by vtkMesh. Slight inconsistency in
+    mesh subset is handled by meshSubsetHelper. Slight inconsistency in
     interpolation: on the internal field it interpolates the whole volField
     to the whole-mesh pointField and then selects only those values it
     needs for the subMesh (using the fvMeshSubset cellMap(), pointMap()
@@ -119,10 +122,7 @@ Note
 
     \verbatim
       <?xml version="1.0"?>
-      <VTKFile type="Collection"
-           version="0.1"
-           byte_order="LittleEndian"
-           compressor="vtkZLibDataCompressor">
+      <VTKFile type="Collection" version="0.1" byte_order="LittleEndian">
         <Collection>
           <DataSet timestep="50" file="pitzDaily_2.vtu"/>
           <DataSet timestep="100" file="pitzDaily_3.vtu"/>
@@ -154,25 +154,26 @@ Note
 #include "passiveParticle.H"
 #include "stringListOps.H"
 
-#include "vtkMesh.H"
+#include "meshSubsetHelper.H"
 #include "readFields.H"
-#include "writeFuns.H"
-
-#include "internalWriter.H"
-#include "patchWriter.H"
-#include "lagrangianWriter.H"
-
-#include "writeFaceSet.H"
-#include "writePointSet.H"
-#include "surfaceMeshWriter.H"
-#include "writeSurfFields.H"
+#include "faceSet.H"
+#include "pointSet.H"
+
+#include "foamVtkOutputOptions.H"
+#include "foamVtkInternalWriter.H"
+#include "foamVtkPatchWriter.H"
+#include "foamVtkSurfaceMeshWriter.H"
+#include "foamVtkLagrangianWriter.H"
+#include "foamVtkWriteFaceSet.H"
+#include "foamVtkWritePointSet.H"
+#include "foamVtkWriteSurfFields.H"
 
 #include "memInfo.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 template<class GeoField>
-void print(const char* msg, Ostream& os, const PtrList<const GeoField>& flds)
+void print(const char* msg, Ostream& os, const UPtrList<const GeoField>& flds)
 {
     if (flds.size())
     {
@@ -234,17 +235,78 @@ labelList getSelectedPatches
 }
 
 
+//
+// Process args for output options
+// Default from foamVtkOutputOptions is inline ASCII xml
+//
+vtk::outputOptions getOutputOptions(const argList& args)
+{
+    vtk::outputOptions opts;
+
+    if (args.optionFound("xml"))
+    {
+        opts.ascii(args.optionFound("ascii"));
+    }
+    else
+    {
+        opts.legacy(true);
+
+        if (!args.optionFound("ascii"))
+        {
+            if (sizeof(floatScalar) != 4 || sizeof(label) != 4)
+            {
+                opts.ascii(true);
+
+                WarningInFunction
+                    << "Using ASCII rather than legacy binary VTK format since "
+                    << "floatScalar and/or label are not 4 bytes in size."
+                    << nl << endl;
+            }
+            else
+            {
+                opts.ascii(false);
+            }
+        }
+    }
+
+    return opts;
+}
+
+
+fileName relativeName(const fileName& parent, const fileName& file)
+{
+    string::size_type next = parent.size();
+    if
+    (
+        file.startsWith(parent)
+     && next < file.size()
+     && file[next] == '/'
+    )
+    {
+        return file.substr(next+1);
+    }
+    else
+    {
+        return file;
+    }
+}
+
+
+fileName relativeName(const Time& runTime, const fileName& file)
+{
+    return relativeName(runTime.path(), file);
+}
+
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 int main(int argc, char *argv[])
 {
-    argList::addNote
-    (
-        "legacy VTK file format writer"
-    );
+    argList::addNote("VTK file format writer");
     timeSelector::addOptions();
 
     #include "addRegionOption.H"
+
     argList::addOption
     (
         "fields",
@@ -275,6 +337,11 @@ int main(int argc, char *argv[])
         "write in ASCII format instead of binary"
     );
     argList::addBoolOption
+    (
+        "xml",
+        "write VTK xml instead of legacy format"
+    );
+    argList::addBoolOption
     (
         "poly",
         "write polyhedral cells without tet/pyramid decomposition"
@@ -299,7 +366,6 @@ int main(int argc, char *argv[])
         "noLagrangian",
         "suppress writing lagrangian positions and fields"
     );
-
     argList::addBoolOption
     (
         "noPointValues",
@@ -329,7 +395,13 @@ int main(int argc, char *argv[])
     argList::addBoolOption
     (
         "useTimeName",
-        "use the time name instead of the time index when naming the files"
+        "use time name instead of the time index when naming files"
+    );
+    argList::addOption
+    (
+        "name",
+        "subdir",
+        "sub-directory name for VTK output (default: 'VTK')"
     );
 
     #include "setRootCase.H"
@@ -345,23 +417,11 @@ int main(int argc, char *argv[])
     const bool doWriteInternal = !args.optionFound("noInternal");
     const bool doFaceZones     = !args.optionFound("noFaceZones");
     const bool doLinks         = !args.optionFound("noLinks");
-    bool binary                = !args.optionFound("ascii");
     const bool useTimeName     = args.optionFound("useTimeName");
     const bool noLagrangian    = args.optionFound("noLagrangian");
+    const bool nearCellValue   = args.optionFound("nearCellValue");
 
-    // Decomposition of polyhedral cells into tets/pyramids cells
-    vtkTopo::decomposePoly     = decomposePoly;
-
-    if (binary && (sizeof(floatScalar) != 4 || sizeof(label) != 4))
-    {
-        WarningInFunction
-            << "Using ASCII rather than binary VTK format because "
-               "floatScalar and/or label are not 4 bytes in size."
-            << nl << endl;
-        binary = false;
-    }
-
-    const bool nearCellValue = args.optionFound("nearCellValue");
+    const vtk::outputOptions fmtType = getOutputOptions(args);
 
     if (nearCellValue)
     {
@@ -374,8 +434,9 @@ int main(int argc, char *argv[])
 
     if (noPointValues)
     {
-        WarningInFunction
-            << "Outputting cell values only" << nl << endl;
+        Info<< "Outputting cell values only."
+            << " Point fields disabled by '-noPointValues' option"
+            << nl;
     }
 
     const bool allPatches = args.optionFound("allPatches");
@@ -388,11 +449,9 @@ int main(int argc, char *argv[])
         Info<< "Not including patches " << excludePatches << nl << endl;
     }
 
-    word cellSetName;
-    word faceSetName;
-    word pointSetName;
     string vtkName = runTime.caseName();
 
+    word cellSetName;
     if (args.optionReadIfPresent("cellSet", cellSetName))
     {
         vtkName = cellSetName;
@@ -407,14 +466,20 @@ int main(int argc, char *argv[])
             vtkName = vtkName.substr(i);
         }
     }
+
+    word faceSetName;
     args.optionReadIfPresent("faceSet", faceSetName);
+
+    word pointSetName;
     args.optionReadIfPresent("pointSet", pointSetName);
 
+    // Define sub-directory name to use for VTK data.
+    const word vtkDirName = args.optionLookupOrDefault<word>("name", "VTK");
 
     #include "createNamedMesh.H"
 
     // VTK/ directory in the case
-    fileName fvPath(runTime.path()/"VTK");
+    fileName fvPath(runTime.path()/vtkDirName);
 
     // Directory of mesh (region0 gets filtered out)
     fileName regionPrefix;
@@ -450,9 +515,11 @@ int main(int argc, char *argv[])
 
     instantList timeDirs = timeSelector::select0(runTime, args);
 
-
     // Mesh wrapper: does subsetting and decomposition
-    vtkMesh vMesh(mesh, cellSetName);
+    meshSubsetHelper meshRef(mesh, meshSubsetHelper::SET, cellSetName);
+
+    // Collect decomposition information etc.
+    vtk::vtuCells vtuMeshCells(fmtType, decomposePoly);
 
     Info<< "VTK mesh topology: "
         << timer.cpuTimeIncrement() << " s, "
@@ -471,20 +538,19 @@ int main(int argc, char *argv[])
 
         // Check for new polyMesh/ and update mesh, fvMeshSubset and cell
         // decomposition.
-        polyMesh::readUpdateState meshState = vMesh.readUpdate();
-
-        const fvMesh& mesh = vMesh.mesh();
+        polyMesh::readUpdateState meshState = meshRef.readUpdate();
 
+        const fvMesh& mesh = meshRef.mesh();
         if
         (
             meshState == polyMesh::TOPO_CHANGE
          || meshState == polyMesh::TOPO_PATCH_CHANGE
         )
         {
-            Info<< "    Read new mesh" << nl << endl;
+            // Trigger change for vtk cells too
+            vtuMeshCells.clear();
         }
 
-
         // If faceSet: write faceSet only (as polydata)
         if (faceSetName.size())
         {
@@ -499,12 +565,17 @@ int main(int argc, char *argv[])
                 fvPath/set.name()/set.name()
               + "_"
               + timeDesc
-              + ".vtk"
             );
+            Info<< "    faceSet   : "
+                << relativeName(runTime, outputName) << nl;
 
-            Info<< "    faceSet   : " << outputName << endl;
-
-            writeFaceSet(binary, vMesh.mesh(), set, outputName);
+            vtk::writeFaceSet
+            (
+                meshRef.mesh(),
+                set,
+                outputName,
+                fmtType
+            );
             continue;
         }
 
@@ -522,12 +593,17 @@ int main(int argc, char *argv[])
                 fvPath/set.name()/set.name()
               + "_"
               + timeDesc
-              + ".vtk"
             );
+            Info<< "    pointSet  : "
+                << relativeName(runTime, outputName) << nl;
 
-            Info<< "    pointSet   : " << outputName << endl;
-
-            writePointSet(binary, vMesh.mesh(), set, outputName);
+            vtk::writePointSet
+            (
+                meshRef.mesh(),
+                set,
+                outputName,
+                fmtType
+            );
             continue;
         }
 
@@ -536,7 +612,7 @@ int main(int argc, char *argv[])
         IOobjectList objects(mesh, runTime.timeName());
 
         HashSet<word> selectedFields;
-        bool specifiedFields = args.optionReadIfPresent
+        const bool specifiedFields = args.optionReadIfPresent
         (
             "fields",
             selectedFields
@@ -544,247 +620,303 @@ int main(int argc, char *argv[])
 
         // Construct the vol fields (on the original mesh if subsetted)
 
-        PtrList<const volScalarField> vsf;
-        PtrList<const volVectorField> vvf;
-        PtrList<const volSphericalTensorField> vSpheretf;
-        PtrList<const volSymmTensorField> vSymmtf;
-        PtrList<const volTensorField> vtf;
+        PtrList<const volScalarField> vScalarFld;
+        PtrList<const volVectorField> vVectorFld;
+        PtrList<const volSphericalTensorField> vSphTensorf;
+        PtrList<const volSymmTensorField> vSymTensorFld;
+        PtrList<const volTensorField> vTensorFld;
 
         if (!specifiedFields || selectedFields.size())
         {
-            readFields(vMesh, vMesh.baseMesh(), objects, selectedFields, vsf);
-            print("    volScalarFields            :", Info, vsf);
+            readFields
+            (
+                meshRef,
+                meshRef.baseMesh(),
+                objects,
+                selectedFields,
+                vScalarFld
+            );
+            print("    volScalar            :", Info, vScalarFld);
 
-            readFields(vMesh, vMesh.baseMesh(), objects, selectedFields, vvf);
-            print("    volVectorFields            :", Info, vvf);
+            readFields
+            (
+                meshRef,
+                meshRef.baseMesh(),
+                objects,
+                selectedFields,
+                vVectorFld
+            );
+            print("    volVector            :", Info, vVectorFld);
 
             readFields
             (
-                vMesh,
-                vMesh.baseMesh(),
+                meshRef,
+                meshRef.baseMesh(),
                 objects,
                 selectedFields,
-                vSpheretf
+                vSphTensorf
             );
-            print("    volSphericalTensorFields   :", Info, vSpheretf);
+            print("    volSphericalTensor   :", Info, vSphTensorf);
 
             readFields
             (
-                vMesh,
-                vMesh.baseMesh(),
+                meshRef,
+                meshRef.baseMesh(),
                 objects,
                 selectedFields,
-                vSymmtf
+                vSymTensorFld
             );
-            print("    volSymmTensorFields        :", Info, vSymmtf);
+            print("    volSymmTensor        :", Info, vSymTensorFld);
 
-            readFields(vMesh, vMesh.baseMesh(), objects, selectedFields, vtf);
-            print("    volTensorFields            :", Info, vtf);
+            readFields
+            (
+                meshRef,
+                meshRef.baseMesh(),
+                objects,
+                selectedFields,
+                vTensorFld
+            );
+            print("    volTensor            :", Info, vTensorFld);
         }
 
-        label nVolFields =
-                vsf.size()
-              + vvf.size()
-              + vSpheretf.size()
-              + vSymmtf.size()
-              + vtf.size();
+        const label nVolFields =
+        (
+            vScalarFld.size()
+          + vVectorFld.size()
+          + vSphTensorf.size()
+          + vSymTensorFld.size()
+          + vTensorFld.size()
+        );
 
 
         // Construct dimensioned fields
-        PtrList<const volScalarField::Internal> dsf;
-        PtrList<const volVectorField::Internal> dvf;
-        PtrList<const volSphericalTensorField::Internal> dSpheretf;
-        PtrList<const volSymmTensorField::Internal> dSymmtf;
-        PtrList<const volTensorField::Internal> dtf;
+        PtrList<const volScalarField::Internal> dScalarFld;
+        PtrList<const volVectorField::Internal> dVectorFld;
+        PtrList<const volSphericalTensorField::Internal> dSphTensorFld;
+        PtrList<const volSymmTensorField::Internal> dSymTensorFld;
+        PtrList<const volTensorField::Internal> dTensorFld;
 
         if (!specifiedFields || selectedFields.size())
         {
-            readFields(vMesh, vMesh.baseMesh(), objects, selectedFields, dsf);
-            print("    volScalarFields::Internal          :", Info, dsf);
+            readFields
+            (
+                meshRef,
+                meshRef.baseMesh(),
+                objects,
+                selectedFields,
+                dScalarFld
+            );
+            print("    volScalar::Internal          :", Info, dScalarFld);
 
-            readFields(vMesh, vMesh.baseMesh(), objects, selectedFields, dvf);
-            print("    volVectorFields::Internal          :", Info, dvf);
+            readFields
+            (
+                meshRef,
+                meshRef.baseMesh(),
+                objects,
+                selectedFields,
+                dVectorFld
+            );
+            print("    volVector::Internal          :", Info, dVectorFld);
 
             readFields
             (
-                vMesh,
-                vMesh.baseMesh(),
+                meshRef,
+                meshRef.baseMesh(),
                 objects,
                 selectedFields,
-                dSpheretf
+                dSphTensorFld
             );
-            print("    volSphericalTensorFields::Internal :", Info, dSpheretf);
+            print("    volSphericalTensor::Internal :", Info, dSphTensorFld);
 
             readFields
             (
-                vMesh,
-                vMesh.baseMesh(),
+                meshRef,
+                meshRef.baseMesh(),
                 objects,
                 selectedFields,
-                dSymmtf
+                dSymTensorFld
             );
-            print("    volSymmTensorFields::Internal      :", Info, dSymmtf);
+            print("    volSymmTensor::Internal      :", Info, dSymTensorFld);
 
-            readFields(vMesh, vMesh.baseMesh(), objects, selectedFields, dtf);
-            print("    volTensorFields::Internal          :", Info, dtf);
+            readFields
+            (
+                meshRef,
+                meshRef.baseMesh(),
+                objects,
+                selectedFields,
+                dTensorFld
+            );
+            print("    volTensor::Internal          :", Info, dTensorFld);
         }
 
-        label nDimFields =
-                dsf.size()
-              + dvf.size()
-              + dSpheretf.size()
-              + dSymmtf.size()
-              + dtf.size();
-
+        const label nDimFields =
+        (
+            dScalarFld.size()
+          + dVectorFld.size()
+          + dSphTensorFld.size()
+          + dSymTensorFld.size()
+          + dTensorFld.size()
+        );
 
-        // Construct pointMesh only if necessary since constructs edge
-        // addressing (expensive on polyhedral meshes)
-        if (noPointValues)
-        {
-            Info<< "    pointScalarFields : switched off"
-                << " (\"-noPointValues\" (at your option)\n";
-            Info<< "    pointVectorFields : switched off"
-                << " (\"-noPointValues\" (at your option)\n";
-        }
 
-        PtrList<const pointScalarField> psf;
-        PtrList<const pointVectorField> pvf;
-        PtrList<const pointSphericalTensorField> pSpheretf;
-        PtrList<const pointSymmTensorField> pSymmtf;
-        PtrList<const pointTensorField> ptf;
+        PtrList<const pointScalarField> pScalarFld;
+        PtrList<const pointVectorField> pVectorFld;
+        PtrList<const pointSphericalTensorField> pSphTensorFld;
+        PtrList<const pointSymmTensorField> pSymTensorFld;
+        PtrList<const pointTensorField> pTensorFld;
 
+        // Construct pointMesh only if necessary since it constructs edge
+        // addressing (expensive on polyhedral meshes)
         if (!noPointValues && !(specifiedFields && selectedFields.empty()))
         {
             readFields
             (
-                vMesh,
-                pointMesh::New(vMesh.baseMesh()),
+                meshRef,
+                pointMesh::New(meshRef.baseMesh()),
                 objects,
                 selectedFields,
-                psf
+                pScalarFld
             );
-            print("    pointScalarFields          :", Info, psf);
+            print("    pointScalar          :", Info, pScalarFld);
 
             readFields
             (
-                vMesh,
-                pointMesh::New(vMesh.baseMesh()),
+                meshRef,
+                pointMesh::New(meshRef.baseMesh()),
                 objects,
                 selectedFields,
-                pvf
+                pVectorFld
             );
-            print("    pointVectorFields          :", Info, pvf);
+            print("    pointVector          :", Info, pVectorFld);
 
             readFields
             (
-                vMesh,
-                pointMesh::New(vMesh.baseMesh()),
+                meshRef,
+                pointMesh::New(meshRef.baseMesh()),
                 objects,
                 selectedFields,
-                pSpheretf
+                pSphTensorFld
             );
-            print("    pointSphericalTensorFields :", Info, pSpheretf);
+            print("    pointSphTensor       : ", Info, pSphTensorFld);
 
             readFields
             (
-                vMesh,
-                pointMesh::New(vMesh.baseMesh()),
+                meshRef,
+                pointMesh::New(meshRef.baseMesh()),
                 objects,
                 selectedFields,
-                pSymmtf
+                pSymTensorFld
             );
-            print("    pointSymmTensorFields      :", Info, pSymmtf);
+            print("    pointSymmTensor      :", Info, pSymTensorFld);
 
             readFields
             (
-                vMesh,
-                pointMesh::New(vMesh.baseMesh()),
+                meshRef,
+                pointMesh::New(meshRef.baseMesh()),
                 objects,
                 selectedFields,
-                ptf
+                pTensorFld
             );
-            print("    pointTensorFields          :", Info, ptf);
+            print("    pointTensor          :", Info, pTensorFld);
         }
-        Info<< endl;
 
-        label nPointFields =
-            psf.size()
-          + pvf.size()
-          + pSpheretf.size()
-          + pSymmtf.size()
-          + ptf.size();
+        const label nPointFields =
+            pScalarFld.size()
+          + pVectorFld.size()
+          + pSphTensorFld.size()
+          + pSymTensorFld.size()
+          + pTensorFld.size();
 
         if (doWriteInternal)
         {
+            if (vtuMeshCells.empty())
+            {
+                vtuMeshCells.reset(meshRef.mesh());
+
+                // Convert cellMap, addPointCellLabels to global cell ids
+                if (meshRef.useSubMesh())
+                {
+                    vtuMeshCells.renumberCells
+                    (
+                        meshRef.subsetter().cellMap()
+                    );
+                }
+            }
+
             // Create file and write header
-            fileName vtkFileName
+            fileName outputName
             (
                 fvPath/vtkName
               + "_"
               + timeDesc
-              + ".vtk"
             );
-
-            Info<< "    Internal  : " << vtkFileName << endl;
+            Info<< "    Internal  : "
+                << relativeName(runTime, outputName) << endl;
 
             // Write mesh
-            internalWriter writer(vMesh, binary, vtkFileName);
-
-            // VolFields + cellID
-            writeFuns::writeCellDataHeader
+            vtk::internalWriter writer
             (
-                writer.os(),
-                vMesh.nFieldCells(),
-                1 + nVolFields + nDimFields
+                meshRef.baseMesh(),
+                vtuMeshCells,
+                outputName,
+                fmtType
             );
 
-            // Write cellID field
-            writer.writeCellIDs();
-
-            // Write volFields
-            writer.write(vsf);
-            writer.write(vvf);
-            writer.write(vSpheretf);
-            writer.write(vSymmtf);
-            writer.write(vtf);
-
-            // Write dimensionedFields
-            writer.write<scalar, volMesh>(dsf);
-            writer.write<vector, volMesh>(dvf);
-            writer.write<sphericalTensor, volMesh>(dSpheretf);
-            writer.write<symmTensor, volMesh>(dSymmtf);
-            writer.write<tensor, volMesh>(dtf);
+            // CellData
+            {
+                writer.beginCellData(1 + nVolFields + nDimFields);
+
+                // Write cellID field
+                writer.writeCellIDs();
+
+                // Write volFields
+                writer.write(vScalarFld);
+                writer.write(vVectorFld);
+                writer.write(vSphTensorf);
+                writer.write(vSymTensorFld);
+                writer.write(vTensorFld);
+
+                // Write dimensionedFields
+                writer.write(dScalarFld);
+                writer.write(dVectorFld);
+                writer.write(dSphTensorFld);
+                writer.write(dSymTensorFld);
+                writer.write(dTensorFld);
+
+                writer.endCellData();
+            }
 
+            // PointData
             if (!noPointValues)
             {
-                writeFuns::writePointDataHeader
-                (
-                    writer.os(),
-                    vMesh.nFieldPoints(),
-                    nVolFields + nDimFields + nPointFields
-                );
+                writer.beginPointData(nVolFields + nDimFields + nPointFields);
 
                 // pointFields
-                writer.write(psf);
-                writer.write(pvf);
-                writer.write(pSpheretf);
-                writer.write(pSymmtf);
-                writer.write(ptf);
+                writer.write(pScalarFld);
+                writer.write(pVectorFld);
+                writer.write(pSphTensorFld);
+                writer.write(pSymTensorFld);
+                writer.write(pTensorFld);
 
                 // Interpolated volFields
                 volPointInterpolation pInterp(mesh);
-                writer.write(pInterp, vsf);
-                writer.write(pInterp, vvf);
-                writer.write(pInterp, vSpheretf);
-                writer.write(pInterp, vSymmtf);
-                writer.write(pInterp, vtf);
-
-                writer.write<scalar, volMesh>(pInterp, dsf);
-                writer.write<vector, volMesh>(pInterp, dvf);
-                writer.write<sphericalTensor, volMesh>(pInterp, dSpheretf);
-                writer.write<symmTensor, volMesh>(pInterp, dSymmtf);
-                writer.write<tensor, volMesh>(pInterp, dtf);
+
+                writer.write(pInterp, vScalarFld);
+                writer.write(pInterp, vVectorFld);
+                writer.write(pInterp, vSphTensorf);
+                writer.write(pInterp, vSymTensorFld);
+                writer.write(pInterp, vTensorFld);
+
+                writer.write(pInterp, dScalarFld);
+                writer.write(pInterp, dVectorFld);
+                writer.write(pInterp, dSphTensorFld);
+                writer.write(pInterp, dSymTensorFld);
+                writer.write(pInterp, dTensorFld);
+
+                writer.endPointData();
             }
+
+            writer.writeFooter();
         }
 
         //---------------------------------------------------------------------
@@ -795,63 +927,65 @@ int main(int argc, char *argv[])
 
         if (args.optionFound("surfaceFields"))
         {
-            PtrList<const surfaceScalarField> ssf;
+            PtrList<const surfaceScalarField> sScalarFld;
             readFields
             (
-                vMesh,
-                vMesh.baseMesh(),
+                meshRef,
+                meshRef.baseMesh(),
                 objects,
                 selectedFields,
-                ssf
+                sScalarFld
             );
-            print("    surfScalarFields  :", Info, ssf);
+            print("    surfScalar  :", Info, sScalarFld);
 
-            PtrList<const surfaceVectorField> svf;
+            PtrList<const surfaceVectorField> sVectorFld;
             readFields
             (
-                vMesh,
-                vMesh.baseMesh(),
+                meshRef,
+                meshRef.baseMesh(),
                 objects,
                 selectedFields,
-                svf
+                sVectorFld
             );
-            print("    surfVectorFields  :", Info, svf);
+            print("    surfVector  :", Info, sVectorFld);
 
-            if (ssf.size() + svf.size() > 0)
+            if (sScalarFld.size())
             {
-                // Rework the scalar fields into vectorfields.
-                label sz = svf.size();
+                // Rework the scalar fields into vector fields.
+                const label sz = sVectorFld.size();
 
-                svf.setSize(sz+ssf.size());
+                sVectorFld.setSize(sz + sScalarFld.size());
 
                 surfaceVectorField n(mesh.Sf()/mesh.magSf());
 
-                forAll(ssf, i)
+                forAll(sScalarFld, i)
                 {
-                    surfaceVectorField* ssfiPtr = (ssf[i]*n).ptr();
-                    ssfiPtr->rename(ssf[i].name());
-                    svf.set(sz+i, ssfiPtr);
+                    surfaceVectorField* ssfPtr = (sScalarFld[i]*n).ptr();
+                    ssfPtr->rename(sScalarFld[i].name());
+                    sVectorFld.set(sz+i, ssfPtr);
                 }
-                ssf.clear();
+                sScalarFld.clear();
+            }
 
+            if (sVectorFld.size())
+            {
                 mkDir(fvPath / "surfaceFields");
 
-                fileName surfFileName
+                fileName outputName
                 (
                     fvPath
-                   /"surfaceFields"
-                   /"surfaceFields"
-                   + "_"
-                   + timeDesc
-                   + ".vtk"
+                  / "surfaceFields"
+                  / "surfaceFields"
+                  + "_"
+                  + timeDesc
                 );
 
-                writeSurfFields
+                vtk::writeSurfFields
                 (
-                    binary,
-                    vMesh.mesh(),
-                    surfFileName,
-                    svf
+                    meshRef.mesh(),
+                    outputName,
+                    fmtType,
+                    sVectorFld
                 );
             }
         }
@@ -869,73 +1003,61 @@ int main(int argc, char *argv[])
         {
             mkDir(fvPath/"allPatches");
 
-            fileName outputName;
-
-            if (vMesh.useSubMesh())
-            {
-                outputName =
-                    fvPath/"allPatches"/cellSetName
-                  + "_"
-                  + timeDesc
-                  + ".vtk";
-            }
-            else
-            {
-                outputName =
-                    fvPath/"allPatches"/"allPatches"
-                  + "_"
-                  + timeDesc
-                  + ".vtk";
-            }
-
-            Info<< "    Combined patches     : " << outputName << endl;
+            fileName outputName
+            (
+                fvPath/"allPatches"
+              / (meshRef.useSubMesh() ? cellSetName : "allPatches")
+              + "_"
+              + timeDesc
+            );
+            Info<< "    Combined patches     : "
+                << relativeName(runTime, outputName) << nl;
 
-            patchWriter writer
+            vtk::patchWriter writer
             (
-                vMesh.mesh(),
-                binary,
-                nearCellValue,
+                meshRef.mesh(),
                 outputName,
+                fmtType,
+                nearCellValue,
                 getSelectedPatches(patches, excludePatches)
             );
 
-            // VolFields + patchID
-            writeFuns::writeCellDataHeader
-            (
-                writer.os(),
-                writer.nFaces(),
-                1+nVolFields
-            );
+            // CellData
+            {
+                writer.beginCellData(1 + nVolFields);
 
-            // Write patchID field
-            writer.writePatchIDs();
+                // Write patchID field
+                writer.writePatchIDs();
 
-            // Write volFields
-            writer.write(vsf);
-            writer.write(vvf);
-            writer.write(vSpheretf);
-            writer.write(vSymmtf);
-            writer.write(vtf);
+                // Write volFields
+                writer.write(vScalarFld);
+                writer.write(vVectorFld);
+                writer.write(vSphTensorf);
+                writer.write(vSymTensorFld);
+                writer.write(vTensorFld);
 
+                writer.endCellData();
+            }
+
+            // PointData
             if (!noPointValues)
             {
-                writeFuns::writePointDataHeader
-                (
-                    writer.os(),
-                    writer.nPoints(),
-                    nPointFields
-                );
+                writer.beginPointData(nPointFields);
 
                 // Write pointFields
-                writer.write(psf);
-                writer.write(pvf);
-                writer.write(pSpheretf);
-                writer.write(pSymmtf);
-                writer.write(ptf);
-
-                // no interpolated volFields since I cannot be bothered to
-                // create the patchInterpolation for all subpatches.
+                writer.write(pScalarFld);
+                writer.write(pVectorFld);
+                writer.write(pSphTensorFld);
+                writer.write(pSymTensorFld);
+                writer.write(pTensorFld);
+
+                // no interpolated volFields to avoid creating
+                // patchInterpolation for all subpatches.
+
+                writer.endPointData();
             }
+
+            writer.writeFooter();
         }
         else
         {
@@ -943,91 +1065,78 @@ int main(int argc, char *argv[])
             {
                 const polyPatch& pp = patches[patchi];
 
-                if (!findStrings(excludePatches, pp.name()))
+                if (findStrings(excludePatches, pp.name()))
                 {
-                    mkDir(fvPath/pp.name());
+                    // Skip excluded patch
+                    continue;
+                }
 
-                    fileName outputName;
+                mkDir(fvPath/pp.name());
 
-                    if (vMesh.useSubMesh())
-                    {
-                        outputName =
-                            fvPath/pp.name()/cellSetName
-                          + "_"
-                          + timeDesc
-                          + ".vtk";
-                    }
-                    else
-                    {
-                        outputName =
-                            fvPath/pp.name()/pp.name()
-                          + "_"
-                          + timeDesc
-                          + ".vtk";
-                    }
+                fileName outputName
+                (
+                    fvPath/pp.name()
+                  / (meshRef.useSubMesh() ? cellSetName : pp.name())
+                  + "_"
+                  + timeDesc
+                );
+                Info<< "    Patch     : "
+                    << relativeName(runTime, outputName) << nl;
+
+                vtk::patchWriter writer
+                (
+                    meshRef.mesh(),
+                    outputName,
+                    fmtType,
+                    nearCellValue,
+                    labelList{patchi}
+                );
 
-                    Info<< "    Patch     : " << outputName << endl;
+                if (!isA<emptyPolyPatch>(pp))
+                {
+                    // VolFields + patchID
+                    writer.beginCellData(1+nVolFields);
 
-                    patchWriter writer
-                    (
-                        vMesh.mesh(),
-                        binary,
-                        nearCellValue,
-                        outputName,
-                        labelList{patchi}
-                    );
+                    // Write patchID field
+                    writer.writePatchIDs();
 
-                    if (!isA<emptyPolyPatch>(pp))
+                    // Write volFields
+                    writer.write(vScalarFld);
+                    writer.write(vVectorFld);
+                    writer.write(vSphTensorf);
+                    writer.write(vSymTensorFld);
+                    writer.write(vTensorFld);
+
+                    writer.endCellData();
+
+                    if (!noPointValues)
                     {
-                        // VolFields + patchID
-                        writeFuns::writeCellDataHeader
+                        writer.beginPointData(nVolFields + nPointFields);
+
+                        // Write pointFields
+                        writer.write(pScalarFld);
+                        writer.write(pVectorFld);
+                        writer.write(pSphTensorFld);
+                        writer.write(pSymTensorFld);
+                        writer.write(pTensorFld);
+
+                        PrimitivePatchInterpolation<primitivePatch> pInter
                         (
-                            writer.os(),
-                            writer.nFaces(),
-                            1+nVolFields
+                            pp
                         );
 
-                        // Write patchID field
-                        writer.writePatchIDs();
-
-                        // Write volFields
-                        writer.write(vsf);
-                        writer.write(vvf);
-                        writer.write(vSpheretf);
-                        writer.write(vSymmtf);
-                        writer.write(vtf);
-
-                        if (!noPointValues)
-                        {
-                            writeFuns::writePointDataHeader
-                            (
-                                writer.os(),
-                                writer.nPoints(),
-                                nVolFields
-                              + nPointFields
-                            );
-
-                            // Write pointFields
-                            writer.write(psf);
-                            writer.write(pvf);
-                            writer.write(pSpheretf);
-                            writer.write(pSymmtf);
-                            writer.write(ptf);
-
-                            PrimitivePatchInterpolation<primitivePatch> pInter
-                            (
-                                pp
-                            );
-
-                            // Write interpolated volFields
-                            writer.write(pInter, vsf);
-                            writer.write(pInter, vvf);
-                            writer.write(pInter, vSpheretf);
-                            writer.write(pInter, vSymmtf);
-                            writer.write(pInter, vtf);
-                        }
+                        // Write interpolated volFields
+                        writer.write(pInter, vScalarFld);
+                        writer.write(pInter, vVectorFld);
+                        writer.write(pInter, vSphTensorf);
+                        writer.write(pInter, vSymTensorFld);
+                        writer.write(pInter, vTensorFld);
+
+                        writer.endPointData();
                     }
                 }
+
+                writer.writeFooter();
             }
         }
 
@@ -1039,27 +1148,27 @@ int main(int argc, char *argv[])
 
         if (doFaceZones)
         {
-            PtrList<const surfaceScalarField> ssf;
+            PtrList<const surfaceScalarField> sScalarFld;
             readFields
             (
-                vMesh,
-                vMesh.baseMesh(),
+                meshRef,
+                meshRef.baseMesh(),
                 objects,
                 selectedFields,
-                ssf
+                sScalarFld
             );
-            print("    surfScalarFields  :", Info, ssf);
+            print("    surfScalar  :", Info, sScalarFld);
 
-            PtrList<const surfaceVectorField> svf;
+            PtrList<const surfaceVectorField> sVectorFld;
             readFields
             (
-                vMesh,
-                vMesh.baseMesh(),
+                meshRef,
+                meshRef.baseMesh(),
                 objects,
                 selectedFields,
-                svf
+                sVectorFld
             );
-            print("    surfVectorFields  :", Info, svf);
+            print("    surfVector  :", Info, sVectorFld);
 
             const faceZoneMesh& zones = mesh.faceZones();
 
@@ -1069,26 +1178,15 @@ int main(int argc, char *argv[])
 
                 mkDir(fvPath/fz.name());
 
-                fileName outputName;
-
-                if (vMesh.useSubMesh())
-                {
-                    outputName =
-                        fvPath/fz.name()/cellSetName
-                      + "_"
-                      + timeDesc
-                      + ".vtk";
-                }
-                else
-                {
-                    outputName =
-                        fvPath/fz.name()/fz.name()
-                      + "_"
-                      + timeDesc
-                      + ".vtk";
-                }
-
-                Info<< "    FaceZone  : " << outputName << endl;
+                fileName outputName =
+                (
+                    fvPath/fz.name()
+                  / (meshRef.useSubMesh() ? cellSetName : fz.name())
+                  + "_"
+                  + timeDesc
+                );
+                Info<< "    FaceZone  : "
+                    << relativeName(runTime, outputName) << nl;
 
                 indirectPrimitivePatch pp
                 (
@@ -1096,29 +1194,27 @@ int main(int argc, char *argv[])
                     mesh.points()
                 );
 
-                surfaceMeshWriter writer
+                vtk::surfaceMeshWriter writer
                 (
-                    binary,
                     pp,
                     fz.name(),
-                    outputName
+                    outputName,
+                    fmtType
                 );
 
                 // Number of fields
-                writeFuns::writeCellDataHeader
-                (
-                    writer.os(),
-                    pp.size(),
-                    ssf.size()+svf.size()
-                );
+                writer.beginCellData(sScalarFld.size() + sVectorFld.size());
+
+                writer.write(sScalarFld);
+                writer.write(sVectorFld);
+
+                writer.endCellData();
 
-                writer.write(ssf);
-                writer.write(svf);
+                writer.writeFooter();
             }
         }
 
 
-
         //---------------------------------------------------------------------
         //
         // Write lagrangian data
@@ -1135,10 +1231,10 @@ int main(int argc, char *argv[])
             fileName outputName
             (
                 fvPath/cloud::prefix/cloudName/cloudName
-              + "_" + timeDesc + ".vtk"
+              + "_" + timeDesc
             );
-
-            Info<< "    Lagrangian: " << outputName << endl;
+            Info<< "    Lagrangian: "
+                << relativeName(runTime, outputName) << nl;
 
             IOobjectList sprayObjs
             (
@@ -1185,17 +1281,16 @@ int main(int argc, char *argv[])
                 Info<< "        tensors           :";
                 print(Info, tensorNames);
 
-                lagrangianWriter writer
+                vtk::lagrangianWriter writer
                 (
-                    vMesh.mesh(),
-                    binary,
-                    outputName,
+                    meshRef.mesh(),
                     cloudName,
-                    false
+                    outputName,
+                    fmtType
                 );
 
                 // Write number of fields
-                writer.writeParcelHeader
+                writer.beginParcelData
                 (
                     labelNames.size()
                   + scalarNames.size()
@@ -1212,20 +1307,28 @@ int main(int argc, char *argv[])
                 writer.writeIOField<sphericalTensor>(sphereNames);
                 writer.writeIOField<symmTensor>(symmNames);
                 writer.writeIOField<tensor>(tensorNames);
+
+                writer.endParcelData();
+
+                writer.writeFooter();
             }
             else
             {
-                lagrangianWriter writer
+                vtk::lagrangianWriter writer
                 (
-                    vMesh.mesh(),
-                    binary,
-                    outputName,
+                    meshRef.mesh(),
                     cloudName,
+                    outputName,
+                    fmtType,
                     true
                 );
 
                 // Write number of fields
-                writer.writeParcelHeader(0);
+                writer.beginParcelData(0);
+
+                writer.endParcelData();
+
+                writer.writeFooter();
             }
         }
 
@@ -1243,18 +1346,19 @@ int main(int argc, char *argv[])
 
     if (Pstream::parRun() && doLinks)
     {
-        mkDir(runTime.path()/".."/"VTK");
-        chDir(runTime.path()/".."/"VTK");
+        mkDir(runTime.path()/".."/vtkDirName);
+        chDir(runTime.path()/".."/vtkDirName);
 
-        Info<< "Linking all processor files to " << runTime.path()/".."/"VTK"
+        Info<< "Linking all processor files to "
+            << runTime.path()/".."/vtkDirName
             << endl;
 
         // Get list of vtk files
         fileName procVTK
         (
             fileName("..")
-           /"processor" + name(Pstream::myProcNo())
-           /"VTK"
+          / "processor" + Foam::name(Pstream::myProcNo())
+          / vtkDirName
         );
 
         fileNameList dirs(readDir(procVTK, fileName::DIRECTORY));
@@ -1272,17 +1376,21 @@ int main(int argc, char *argv[])
 
                 if (exists(procFile))
                 {
-                    string cmd
-                    (
-                        "ln -s "
-                      + procFile
-                      + " "
-                      + "processor"
-                      + name(Pstream::myProcNo())
-                      + "_"
-                      + procFile.name()
-                    );
-                    if (Foam::system(cmd.c_str()) == -1)
+                    // Could likely also use Foam::ln() directly
+                    List<string> cmd
+                    {
+                        "ln",
+                        "-s",
+                        procFile,
+                        (
+                            "processor"
+                          + Foam::name(Pstream::myProcNo())
+                          + "_"
+                          + procFile.name()
+                        )
+                    };
+
+                    if (Foam::system(cmd) == -1)
                     {
                         WarningInFunction
                             << "Could not execute command " << cmd << endl;
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/Make/files b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/Make/files
deleted file mode 100644
index 02de5b47e6254aab58ae3557c2f7e2342b7df753..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/Make/files
+++ /dev/null
@@ -1,13 +0,0 @@
-surfaceMeshWriter.C
-internalWriter.C
-lagrangianWriter.C
-patchWriter.C
-writeFuns.C
-writeFaceSet.C
-writePointSet.C
-writeSurfFields.C
-vtkTopo.C
-
-writeVTK/writeVTK.C
-
-LIB = $(FOAM_LIBBIN)/libfoamToVTK
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/Make/options b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/Make/options
deleted file mode 100644
index f10e4ec1d6bc0688e938d10ec287995f5efb0119..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/Make/options
+++ /dev/null
@@ -1,10 +0,0 @@
-EXE_INC = \
-    -I$(LIB_SRC)/lagrangian/basic/lnInclude \
-    -I$(LIB_SRC)/finiteVolume/lnInclude \
-    -I$(LIB_SRC)/dynamicMesh/lnInclude \
-    -I$(LIB_SRC)/meshTools/lnInclude
-
-LIB_LIBS = \
-    -ldynamicMesh \
-    -llagrangian \
-    -lgenericPatchFields
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/internalWriter.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/internalWriter.C
deleted file mode 100644
index 4db9f9c06938a851a387505af3adb8b6cbd24ab0..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/internalWriter.C
+++ /dev/null
@@ -1,165 +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/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "internalWriter.H"
-#include "writeFuns.H"
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::internalWriter::internalWriter
-(
-    const vtkMesh& vMesh,
-    const bool binary,
-    const fileName& fName
-)
-:
-    vMesh_(vMesh),
-    binary_(binary),
-    fName_(fName),
-    os_(fName.c_str())
-{
-    const fvMesh& mesh = vMesh_.mesh();
-    const vtkTopo& topo = vMesh_.topo();
-
-    // Write header
-    writeFuns::writeHeader(os_, binary_, mesh.time().caseName());
-    os_ << "DATASET UNSTRUCTURED_GRID" << std::endl;
-
-
-    //------------------------------------------------------------------
-    //
-    // Write topology
-    //
-    //------------------------------------------------------------------
-
-    const labelList& addPointCellLabels = topo.addPointCellLabels();
-    const label nTotPoints = mesh.nPoints() + addPointCellLabels.size();
-
-    os_ << "POINTS " << nTotPoints << " float" << std::endl;
-
-    DynamicList<floatScalar> ptField(3*nTotPoints);
-
-    writeFuns::insert(mesh.points(), ptField);
-
-    const pointField& ctrs = mesh.cellCentres();
-    forAll(addPointCellLabels, api)
-    {
-        writeFuns::insert(ctrs[addPointCellLabels[api]], ptField);
-    }
-    writeFuns::write(os_, binary_, ptField);
-
-
-    //
-    // Write cells
-    //
-
-    const labelListList& vtkVertLabels = topo.vertLabels();
-
-    // Count total number of vertices referenced.
-    label nFaceVerts = 0;
-
-    forAll(vtkVertLabels, celli)
-    {
-        nFaceVerts += vtkVertLabels[celli].size() + 1;
-    }
-
-    os_ << "CELLS " << vtkVertLabels.size() << ' ' << nFaceVerts << std::endl;
-
-    DynamicList<label> vertLabels(nFaceVerts);
-
-    forAll(vtkVertLabels, celli)
-    {
-        const labelList& vtkVerts = vtkVertLabels[celli];
-
-        vertLabels.append(vtkVerts.size());
-
-        writeFuns::insert(vtkVerts, vertLabels);
-    }
-    writeFuns::write(os_, binary_, vertLabels);
-
-
-    const labelList& vtkCellTypes = topo.cellTypes();
-
-    os_ << "CELL_TYPES " << vtkCellTypes.size() << std::endl;
-
-    // Make copy since writing might swap stuff.
-    DynamicList<label> cellTypes(vtkCellTypes.size());
-
-    writeFuns::insert(vtkCellTypes, cellTypes);
-
-    writeFuns::write(os_, binary_, cellTypes);
-}
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-void Foam::internalWriter::writeCellIDs()
-{
-    const fvMesh& mesh = vMesh_.mesh();
-    const vtkTopo& topo = vMesh_.topo();
-    const labelList& vtkCellTypes = topo.cellTypes();
-    const labelList& superCells = topo.superCells();
-
-    // Cell ids first
-    os_ << "cellID 1 " << vtkCellTypes.size() << " int" << std::endl;
-
-    labelList cellId(vtkCellTypes.size());
-    label labelI = 0;
-
-
-    if (vMesh_.useSubMesh())
-    {
-        const labelList& cMap = vMesh_.subsetter().cellMap();
-
-        forAll(mesh.cells(), celli)
-        {
-            cellId[labelI++] = cMap[celli];
-        }
-        forAll(superCells, superCelli)
-        {
-            label origCelli = cMap[superCells[superCelli]];
-
-            cellId[labelI++] = origCelli;
-        }
-    }
-    else
-    {
-        forAll(mesh.cells(), celli)
-        {
-            cellId[labelI++] = celli;
-        }
-        forAll(superCells, superCelli)
-        {
-            label origCelli = superCells[superCelli];
-
-            cellId[labelI++] = origCelli;
-        }
-    }
-
-    writeFuns::write(os_, binary_, cellId);
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/internalWriterTemplates.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/internalWriterTemplates.C
deleted file mode 100644
index f5e3b1aa39507e7bf3d7c76fb5a8695564d8161f..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/internalWriterTemplates.C
+++ /dev/null
@@ -1,99 +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/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "internalWriter.H"
-#include "writeFuns.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-template<class Type, template<class> class PatchField, class GeoMesh>
-void Foam::internalWriter::write
-(
-    const UPtrList<const GeometricField<Type, PatchField, GeoMesh>>& flds
-)
-{
-    forAll(flds, i)
-    {
-        writeFuns::write(os_, binary_, flds[i], vMesh_);
-    }
-}
-
-
-template<class Type, class GeoMesh>
-void Foam::internalWriter::write
-(
-    const PtrList<const DimensionedField<Type, volMesh>>& flds
-)
-{
-    forAll(flds, i)
-    {
-        writeFuns::write(os_, binary_, flds[i], vMesh_);
-    }
-}
-
-
-template<class Type>
-void Foam::internalWriter::write
-(
-    const volPointInterpolation& pInterp,
-    const UPtrList<const GeometricField<Type, fvPatchField, volMesh>>& flds
-)
-{
-    forAll(flds, i)
-    {
-        writeFuns::write
-        (
-            os_,
-            binary_,
-            flds[i],
-            pInterp.interpolate(flds[i])(),
-            vMesh_
-        );
-    }
-}
-
-
-template<class Type, class GeoMesh>
-void Foam::internalWriter::write
-(
-    const volPointInterpolation& pInterp,
-    const PtrList<const DimensionedField<Type, volMesh>>& flds
-)
-{
-    forAll(flds, i)
-    {
-        writeFuns::write
-        (
-            os_,
-            binary_,
-            flds[i],
-            pInterp.interpolate(flds[i])(),
-            vMesh_
-        );
-    }
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/lagrangianWriter.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/lagrangianWriter.C
deleted file mode 100644
index 6eab8f164666e4767559491354f705df14cc4418..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/lagrangianWriter.C
+++ /dev/null
@@ -1,87 +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 "lagrangianWriter.H"
-#include "writeFuns.H"
-#include "Cloud.H"
-#include "passiveParticle.H"
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::lagrangianWriter::lagrangianWriter
-(
-    const fvMesh& mesh,
-    const bool binary,
-    const fileName& fName,
-    const word& cloudName,
-    const bool dummyCloud
-)
-:
-    mesh_(mesh),
-    binary_(binary),
-    fName_(fName),
-    cloudName_(cloudName),
-    os_(fName.c_str())
-{
-    // Write header
-    writeFuns::writeHeader(os_, binary_, mesh_.time().caseName());
-    os_ << "DATASET POLYDATA" << std::endl;
-
-    if (dummyCloud)
-    {
-        nParcels_ = 0;
-
-        os_ << "POINTS " << nParcels_ << " float" << std::endl;
-    }
-    else
-    {
-        Cloud<passiveParticle> parcels(mesh, cloudName_, false);
-
-        nParcels_ = parcels.size();
-
-        os_ << "POINTS " << nParcels_ << " float" << std::endl;
-
-        DynamicList<floatScalar> partField(3*parcels.size());
-
-        forAllConstIter(Cloud<passiveParticle>, parcels, elmnt)
-        {
-            writeFuns::insert(elmnt().position(), partField);
-        }
-        writeFuns::write(os_, binary_, partField);
-    }
-}
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-void Foam::lagrangianWriter::writeParcelHeader(const label nFields)
-{
-    os_ << "POINT_DATA " << nParcels_ << std::endl
-        << "FIELD attributes " << nFields
-        << std::endl;
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/lagrangianWriterTemplates.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/lagrangianWriterTemplates.C
deleted file mode 100644
index 86cec10dc3ee015598988d5ee2b71c5ed036fc0c..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/lagrangianWriterTemplates.C
+++ /dev/null
@@ -1,65 +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 "lagrangianWriter.H"
-#include "writeFuns.H"
-#include "IOField.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-template<class Type>
-void Foam::lagrangianWriter::writeIOField(const wordList& objects)
-{
-    forAll(objects, i)
-    {
-        const word& object = objects[i];
-
-        IOobject header
-        (
-            object,
-            mesh_.time().timeName(),
-            cloud::prefix/cloudName_,
-            mesh_,
-            IOobject::MUST_READ,
-            IOobject::NO_WRITE,
-            false
-        );
-
-        IOField<Type> fld(header);
-
-        os_ << object << ' '
-            << int(pTraits<Type>::nComponents) << ' '
-            << fld.size() << " float" << std::endl;
-
-        DynamicList<floatScalar> fField(pTraits<Type>::nComponents*fld.size());
-
-        writeFuns::insert(fld, fField);
-
-        writeFuns::write(os_, binary_, fField);
-    }
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/patchWriter.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/patchWriter.C
deleted file mode 100644
index d099745aa259b8f59f9029a52af2b1725a8859c3..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/patchWriter.C
+++ /dev/null
@@ -1,136 +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 "patchWriter.H"
-#include "writeFuns.H"
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::patchWriter::patchWriter
-(
-    const fvMesh& mesh,
-    const bool binary,
-    const bool nearCellValue,
-    const fileName& fName,
-    const labelList& patchIDs
-)
-:
-    mesh_(mesh),
-    binary_(binary),
-    nearCellValue_(nearCellValue),
-    fName_(fName),
-    patchIDs_(patchIDs),
-    os_(fName.c_str())
-{
-    const polyBoundaryMesh& patches = mesh.boundaryMesh();
-
-    // Write header
-    if (patchIDs_.size() == 1)
-    {
-        writeFuns::writeHeader(os_, binary_, patches[patchIDs_[0]].name());
-    }
-    else
-    {
-        writeFuns::writeHeader(os_, binary_, "patches");
-    }
-    os_ << "DATASET POLYDATA" << std::endl;
-
-    // Write topology
-    nPoints_ = 0;
-    nFaces_ = 0;
-    label nFaceVerts = 0;
-
-    forAll(patchIDs_, i)
-    {
-        const polyPatch& pp = patches[patchIDs_[i]];
-
-        nPoints_ += pp.nPoints();
-        nFaces_ += pp.size();
-
-        forAll(pp, facei)
-        {
-            nFaceVerts += pp[facei].size() + 1;
-        }
-    }
-
-    os_ << "POINTS " << nPoints_ << " float" << std::endl;
-
-    DynamicList<floatScalar> ptField(3*nPoints_);
-
-    forAll(patchIDs_, i)
-    {
-        const polyPatch& pp = patches[patchIDs_[i]];
-
-        writeFuns::insert(pp.localPoints(), ptField);
-    }
-    writeFuns::write(os_, binary_, ptField);
-
-    os_ << "POLYGONS " << nFaces_ << ' ' << nFaceVerts << std::endl;
-
-    DynamicList<label> vertLabels(nFaceVerts);
-
-    label offset = 0;
-
-    forAll(patchIDs_, i)
-    {
-        const polyPatch& pp = patches[patchIDs_[i]];
-
-        forAll(pp, facei)
-        {
-            const face& f = pp.localFaces()[facei];
-
-            vertLabels.append(f.size());
-            writeFuns::insert(f + offset, vertLabels);
-        }
-        offset += pp.nPoints();
-    }
-    writeFuns::write(os_, binary_, vertLabels);
-}
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-void Foam::patchWriter::writePatchIDs()
-{
-    DynamicList<floatScalar> fField(nFaces_);
-
-    os_ << "patchID 1 " << nFaces_ << " float" << std::endl;
-
-    forAll(patchIDs_, i)
-    {
-        label patchi = patchIDs_[i];
-
-        const polyPatch& pp = mesh_.boundaryMesh()[patchi];
-
-        if (!isA<emptyPolyPatch>(pp))
-        {
-            writeFuns::insert(scalarField(pp.size(), patchi), fField);
-        }
-    }
-    writeFuns::write(os_, binary_, fField);
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/patchWriter.H b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/patchWriter.H
deleted file mode 100644
index aab8075da87052a6ebc22fdc00cbf041e8aede05..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/patchWriter.H
+++ /dev/null
@@ -1,153 +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::patchWriter
-
-Description
-    Write patch fields
-
-SourceFiles
-    patchWriter.C
-    patchWriterTemplates.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef patchWriter_H
-#define patchWriter_H
-
-#include "pointMesh.H"
-#include "OFstream.H"
-#include "volFields.H"
-#include "pointFields.H"
-#include "indirectPrimitivePatch.H"
-#include "PrimitivePatchInterpolation.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-class volPointInterpolation;
-
-/*---------------------------------------------------------------------------*\
-                           Class patchWriter Declaration
-\*---------------------------------------------------------------------------*/
-
-class patchWriter
-{
-    //- Reference to the OpenFOAM mesh (or subset)
-    const fvMesh& mesh_;
-
-    const bool binary_;
-
-    const bool nearCellValue_;
-
-    const fileName fName_;
-
-    const labelList patchIDs_;
-
-    std::ofstream os_;
-
-    label nPoints_;
-
-    label nFaces_;
-
-public:
-
-    // Constructors
-
-        //- Construct from components
-        patchWriter
-        (
-            const fvMesh&,
-            const bool binary,
-            const bool nearCellValue,
-            const fileName&,
-            const labelList& patchIDs
-        );
-
-
-    // Member Functions
-
-        std::ofstream& os()
-        {
-            return os_;
-        }
-
-        label nPoints() const
-        {
-            return nPoints_;
-        }
-
-        label nFaces() const
-        {
-            return nFaces_;
-        }
-
-        //- Write cellIDs
-        void writePatchIDs();
-
-        //- Write volFields
-        template<class Type>
-        void write
-        (
-            const UPtrList<const GeometricField<Type, fvPatchField, volMesh>>&
-        );
-
-        //- Write pointFields
-        template<class Type>
-        void write
-        (
-            const UPtrList
-            <
-                const GeometricField<Type, pointPatchField, pointMesh>
-            >&
-        );
-
-        //- Interpolate and write volFields
-        template<class Type>
-        void write
-        (
-            const PrimitivePatchInterpolation<primitivePatch>&,
-            const UPtrList<const GeometricField<Type, fvPatchField, volMesh>>&
-        );
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#ifdef NoRepository
-    #include "patchWriterTemplates.C"
-#endif
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/patchWriterTemplates.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/patchWriterTemplates.C
deleted file mode 100644
index 567b1db68c65aa2d558817cd6f459b4feb2d3b9b..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/patchWriterTemplates.C
+++ /dev/null
@@ -1,145 +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 "patchWriter.H"
-#include "writeFuns.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-template<class Type>
-void Foam::patchWriter::write
-(
-    const UPtrList<const GeometricField<Type, fvPatchField, volMesh>>& flds
-)
-{
-    forAll(flds, fieldi)
-    {
-        const GeometricField<Type, fvPatchField, volMesh>& fld = flds[fieldi];
-
-        os_ << fld.name() << ' '
-            << int(pTraits<Type>::nComponents) << ' '
-            << nFaces_ << " float" << std::endl;
-
-        DynamicList<floatScalar> fField(pTraits<Type>::nComponents*nFaces_);
-
-        forAll(patchIDs_, j)
-        {
-            label patchi = patchIDs_[j];
-
-            const fvPatchField<Type>& pfld = fld.boundaryField()[patchi];
-
-            if (nearCellValue_)
-            {
-                writeFuns::insert(pfld.patchInternalField()(), fField);
-            }
-            else
-            {
-                writeFuns::insert(pfld, fField);
-            }
-        }
-        writeFuns::write(os_, binary_, fField);
-    }
-}
-
-
-template<class Type>
-void Foam::patchWriter::write
-(
-    const UPtrList<const GeometricField<Type, pointPatchField, pointMesh>>& flds
-)
-{
-    forAll(flds, fieldi)
-    {
-        const GeometricField<Type, pointPatchField, pointMesh>& fld =
-            flds[fieldi];
-
-        os_ << fld.name() << ' '
-            << int(pTraits<Type>::nComponents) << ' '
-            << nPoints_ << " float" << std::endl;
-
-        DynamicList<floatScalar> fField(pTraits<Type>::nComponents*nPoints_);
-
-        forAll(patchIDs_, j)
-        {
-            label patchi = patchIDs_[j];
-
-            const pointPatchField<Type>& pfld = fld.boundaryField()[patchi];
-
-            writeFuns::insert(pfld.patchInternalField()(), fField);
-        }
-        writeFuns::write(os_, binary_, fField);
-    }
-}
-
-
-template<class Type>
-void Foam::patchWriter::write
-(
-    const PrimitivePatchInterpolation<primitivePatch>& pInter,
-    const UPtrList<const GeometricField<Type, fvPatchField, volMesh>>& flds
-)
-{
-    forAll(flds, fieldi)
-    {
-        const GeometricField<Type, fvPatchField, volMesh>& fld = flds[fieldi];
-
-        os_ << fld.name() << ' '
-            << int(pTraits<Type>::nComponents) << ' '
-            << nPoints_ << " float" << std::endl;
-
-        DynamicList<floatScalar> fField(pTraits<Type>::nComponents*nPoints_);
-
-        forAll(patchIDs_, j)
-        {
-            label patchi = patchIDs_[j];
-
-            const fvPatchField<Type>& pfld = fld.boundaryField()[patchi];
-
-            if (nearCellValue_)
-            {
-                writeFuns::insert
-                (
-                    pInter.faceToPointInterpolate
-                    (
-                        pfld.patchInternalField()()
-                    )(),
-                    fField
-                );
-            }
-            else
-            {
-                writeFuns::insert
-                (
-                    pInter.faceToPointInterpolate(pfld)(),
-                    fField
-                );
-            }
-        }
-        writeFuns::write(os_, binary_, fField);
-    }
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/vtkMesh.H b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/vtkMesh.H
deleted file mode 100644
index f0a80db4ead04f7e4e1c13d77c488225d5acb809..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/vtkMesh.H
+++ /dev/null
@@ -1,137 +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::vtkMesh
-
-Description
-    Encapsulation of VTK mesh data. Holds mesh or meshsubset and
-    polyhedral-cell decomposition on it.
-
-SourceFiles
-    vtkMesh.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef vtkMesh_H
-#define vtkMesh_H
-
-#include "meshSubsetHelper.H"
-#include "vtkTopo.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-/*---------------------------------------------------------------------------*\
-                           Class vtkMesh Declaration
-\*---------------------------------------------------------------------------*/
-
-class vtkMesh
-:
-    public meshSubsetHelper
-{
-    // Private data
-
-        //- Current decomposition of topology
-        mutable autoPtr<vtkTopo> topoPtr_;
-
-
-    // Private Member Functions
-
-        //- Disallow default bitwise copy construct
-        vtkMesh(const vtkMesh&) = delete;
-
-        //- Disallow default bitwise assignment
-        void operator=(const vtkMesh&) = delete;
-
-
-public:
-
-    // Constructors
-
-        //- Construct from components
-        vtkMesh(fvMesh& baseMesh, const word& setName = word::null)
-        :
-            meshSubsetHelper(baseMesh, meshSubsetHelper::SET, setName)
-        {}
-
-
-    // Member Functions
-
-        // Access
-
-            //- Topology
-            const vtkTopo& topo() const
-            {
-                if (topoPtr_.empty())
-                {
-                    topoPtr_.reset(new vtkTopo(mesh()));
-                }
-                return topoPtr_();
-            }
-
-
-            //- Number of field cells
-            label nFieldCells() const
-            {
-                return topo().cellTypes().size();
-            }
-
-
-            //- Number of field points
-            label nFieldPoints() const
-            {
-                return mesh().nPoints() + topo().addPointCellLabels().size();
-            }
-
-
-        // Edit
-
-            //- Read mesh, forcing topo update if necessary
-            polyMesh::readUpdateState readUpdate()
-            {
-                polyMesh::readUpdateState meshState
-                    = meshSubsetHelper::readUpdate();
-
-                if (meshState != polyMesh::UNCHANGED)
-                {
-                    topoPtr_.clear();
-                }
-
-                return meshState;
-            }
-
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/vtkTopo.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/vtkTopo.C
deleted file mode 100644
index dc6ece136be09e7b2d4fa2171099b75e6526a2f9..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/vtkTopo.C
+++ /dev/null
@@ -1,373 +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
-    Note: bug in vtk displaying wedges? Seems to display ok if we decompose
-    them. Should be thoroughly tested!
-    (they appear rarely in polyhedral meshes, do appear in some cut meshes)
-
-\*---------------------------------------------------------------------------*/
-
-#include "vtkTopo.H"
-#include "polyMesh.H"
-#include "cellShape.H"
-#include "cellModeller.H"
-#include "Swap.H"
-
-// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
-
-bool Foam::vtkTopo::decomposePoly = true;
-
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::vtkTopo::vtkTopo(const polyMesh& mesh)
-:
-    mesh_(mesh),
-    vertLabels_(),
-    cellTypes_(),
-    addPointCellLabels_(),
-    superCells_()
-{
-    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& tetWedge = *(cellModeller::lookup("tetWedge"));
-    const cellModel& hex = *(cellModeller::lookup("hex"));
-
-    const cellShapeList& cellShapes = mesh_.cellShapes();
-
-    // Number of additional points needed by the decomposition of polyhedra
-    label nAddPoints = 0;
-
-    // Number of additional cells generated by the decomposition of polyhedra
-    label nAddCells = 0;
-
-    // face owner is needed to determine the face orientation
-    const labelList& owner = mesh.faceOwner();
-
-    // Scan for cells which need to be decomposed and count additional points
-    // and cells
-    if (decomposePoly)
-    {
-        forAll(cellShapes, celli)
-        {
-            const cellModel& model = cellShapes[celli].model();
-
-            if
-            (
-                model != hex
-             && model != wedge    // See above.
-             && model != prism
-             && model != pyr
-             && model != tet
-             && model != tetWedge
-            )
-            {
-                const cell& cFaces = mesh_.cells()[celli];
-
-                forAll(cFaces, cFacei)
-                {
-                    const face& f = mesh_.faces()[cFaces[cFacei]];
-
-                    label nQuads = 0;
-                    label nTris = 0;
-                    f.nTrianglesQuads(mesh_.points(), nTris, nQuads);
-
-                    nAddCells += nQuads + nTris;
-                }
-
-                nAddCells--;
-                nAddPoints++;
-            }
-        }
-    }
-
-
-    // Set size of additional point addressing array
-    // (from added point to original cell)
-    addPointCellLabels_.setSize(nAddPoints);
-
-    // Set size of additional cells mapping array
-    // (from added cell to original cell)
-    superCells_.setSize(nAddCells);
-
-    // List of vertex labels in VTK ordering
-    vertLabels_.setSize(cellShapes.size() + nAddCells);
-
-    // Label of vtk type
-    cellTypes_.setSize(cellShapes.size() + nAddCells);
-
-    // Set counters for additional points and additional cells
-    label addPointi = 0, addCelli = 0;
-
-    forAll(cellShapes, celli)
-    {
-        const cellShape& cellShape = cellShapes[celli];
-        const cellModel& cellModel = cellShape.model();
-
-        labelList& vtkVerts = vertLabels_[celli];
-
-        if (cellModel == tet)
-        {
-            vtkVerts = cellShape;
-
-            cellTypes_[celli] = VTK_TETRA;
-        }
-        else if (cellModel == pyr)
-        {
-            vtkVerts = cellShape;
-
-            cellTypes_[celli] = VTK_PYRAMID;
-        }
-        else if (cellModel == prism)
-        {
-            // VTK has a different node order for VTK_WEDGE
-            // their triangles point outwards!
-            vtkVerts = cellShape;
-
-            Foam::Swap(vtkVerts[1], vtkVerts[2]);
-            Foam::Swap(vtkVerts[4], vtkVerts[5]);
-
-            cellTypes_[celli] = VTK_WEDGE;
-        }
-        else if (cellModel == tetWedge && decomposePoly)
-        {
-            // Treat as squeezed prism (VTK_WEDGE)
-            vtkVerts.setSize(6);
-            vtkVerts[0] = cellShape[0];
-            vtkVerts[1] = cellShape[2];
-            vtkVerts[2] = cellShape[1];
-            vtkVerts[3] = cellShape[3];
-            vtkVerts[4] = cellShape[4];
-            vtkVerts[5] = cellShape[3];
-
-            cellTypes_[celli] = VTK_WEDGE;
-        }
-        else if (cellModel == wedge)
-        {
-            // Treat as squeezed hex
-            vtkVerts.setSize(8);
-            vtkVerts[0] = cellShape[0];
-            vtkVerts[1] = cellShape[1];
-            vtkVerts[2] = cellShape[2];
-            vtkVerts[3] = cellShape[2];
-            vtkVerts[4] = cellShape[3];
-            vtkVerts[5] = cellShape[4];
-            vtkVerts[6] = cellShape[5];
-            vtkVerts[7] = cellShape[6];
-
-            cellTypes_[celli] = VTK_HEXAHEDRON;
-        }
-        else if (cellModel == hex)
-        {
-            vtkVerts = cellShape;
-
-            cellTypes_[celli] = VTK_HEXAHEDRON;
-        }
-        else if (decomposePoly)
-        {
-            // Polyhedral cell. Decompose into tets + pyramids.
-
-            // Mapping from additional point to cell
-            addPointCellLabels_[addPointi] = celli;
-
-            // The new vertex from the cell-centre
-            const label newVertexLabel = mesh_.nPoints() + addPointi;
-
-            // Whether to insert cell in place of original or not.
-            bool substituteCell = true;
-
-            const labelList& cFaces = mesh_.cells()[celli];
-            forAll(cFaces, cFacei)
-            {
-                const face& f = mesh_.faces()[cFaces[cFacei]];
-                const bool isOwner = (owner[cFaces[cFacei]] == celli);
-
-                // Number of triangles and quads in decomposition
-                label nTris = 0;
-                label nQuads = 0;
-                f.nTrianglesQuads(mesh_.points(), nTris, nQuads);
-
-                // Do actual decomposition into triFcs and quadFcs.
-                faceList triFcs(nTris);
-                faceList quadFcs(nQuads);
-                label trii = 0;
-                label quadi = 0;
-                f.trianglesQuads(mesh_.points(), trii, quadi, triFcs, quadFcs);
-
-                forAll(quadFcs, quadI)
-                {
-                    label thisCelli;
-
-                    if (substituteCell)
-                    {
-                        thisCelli = celli;
-                        substituteCell = false;
-                    }
-                    else
-                    {
-                        thisCelli = mesh_.nCells() + addCelli;
-                        superCells_[addCelli++] = celli;
-                    }
-
-                    labelList& addVtkVerts = vertLabels_[thisCelli];
-
-                    addVtkVerts.setSize(5);
-
-                    const face& quad = quadFcs[quadI];
-
-                    // Ensure we have the correct orientation for the
-                    // base of the primitive cell shape.
-                    // If the cell is face owner, the orientation needs to be
-                    // flipped.
-                    // At the moment, VTK doesn't actually seem to care if
-                    // negative cells are defined, but we'll do it anyhow
-                    // (for safety).
-                    if (isOwner)
-                    {
-                        addVtkVerts[0] = quad[3];
-                        addVtkVerts[1] = quad[2];
-                        addVtkVerts[2] = quad[1];
-                        addVtkVerts[3] = quad[0];
-                    }
-                    else
-                    {
-                        addVtkVerts[0] = quad[0];
-                        addVtkVerts[1] = quad[1];
-                        addVtkVerts[2] = quad[2];
-                        addVtkVerts[3] = quad[3];
-                    }
-                    addVtkVerts[4] = newVertexLabel;
-
-                    cellTypes_[thisCelli] = VTK_PYRAMID;
-                }
-
-                forAll(triFcs, triI)
-                {
-                    label thisCelli;
-
-                    if (substituteCell)
-                    {
-                        thisCelli = celli;
-                        substituteCell = false;
-                    }
-                    else
-                    {
-                        thisCelli = mesh_.nCells() + addCelli;
-                        superCells_[addCelli++] = celli;
-                    }
-
-
-                    labelList& addVtkVerts = vertLabels_[thisCelli];
-
-                    const face& tri = triFcs[triI];
-
-                    addVtkVerts.setSize(4);
-
-                    // See note above about the orientation.
-                    if (isOwner)
-                    {
-                        addVtkVerts[0] = tri[2];
-                        addVtkVerts[1] = tri[1];
-                        addVtkVerts[2] = tri[0];
-                    }
-                    else
-                    {
-                        addVtkVerts[0] = tri[0];
-                        addVtkVerts[1] = tri[1];
-                        addVtkVerts[2] = tri[2];
-                    }
-                    addVtkVerts[3] = newVertexLabel;
-
-                    cellTypes_[thisCelli] = VTK_TETRA;
-                }
-            }
-
-            addPointi++;
-        }
-        else
-        {
-            // Polyhedral cell - not decomposed
-            cellTypes_[celli] = VTK_POLYHEDRON;
-
-            const labelList& cFaces = mesh_.cells()[celli];
-
-            // space for the number of faces and size of each face
-            label nData = 1 + cFaces.size();
-
-            // count total number of face points
-            forAll(cFaces, cFacei)
-            {
-                const face& f = mesh.faces()[cFaces[cFacei]];
-                nData += f.size();   // space for the face labels
-            }
-
-            vtkVerts.setSize(nData);
-
-            nData = 0;
-            vtkVerts[nData++] = cFaces.size();
-
-            // build face stream
-            forAll(cFaces, cFacei)
-            {
-                const face& f = mesh.faces()[cFaces[cFacei]];
-                const bool isOwner = (owner[cFaces[cFacei]] == celli);
-
-                // number of labels for this face
-                vtkVerts[nData++] = f.size();
-
-                if (isOwner)
-                {
-                    forAll(f, fp)
-                    {
-                        vtkVerts[nData++] = f[fp];
-                    }
-                }
-                else
-                {
-                    // fairly immaterial if we reverse the list
-                    // or use face::reverseFace()
-                    forAllReverse(f, fp)
-                    {
-                        vtkVerts[nData++] = f[fp];
-                    }
-                }
-            }
-        }
-    }
-
-    if (decomposePoly)
-    {
-        Pout<< "    Original cells:" << mesh_.nCells()
-            << " points:" << mesh_.nPoints()
-            << "   Additional cells:" << superCells_.size()
-            << "  additional points:" << addPointCellLabels_.size()
-            << nl << endl;
-    }
-
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/vtkTopo.H b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/vtkTopo.H
deleted file mode 100644
index c6f9a4eea9ab2fc45c7cc599a2c69d89938fa43c..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/vtkTopo.H
+++ /dev/null
@@ -1,139 +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/>.
-
-Class
-    Foam::vtkTopo
-
-Description
-    Polyhedral cell decomposition for VTK.
-
-SourceFiles
-    vtkTopo.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef vtkTopo_H
-#define vtkTopo_H
-
-#include "labelList.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-// Forward declaration of classes
-class polyMesh;
-
-/*---------------------------------------------------------------------------*\
-                           Class vtkTopo Declaration
-\*---------------------------------------------------------------------------*/
-
-class vtkTopo
-{
-    // Private data
-
-        const polyMesh& mesh_;
-
-        //- Vertices per cell (including added cells) in vtk ordering
-        labelListList vertLabels_;
-
-        //- Cell types (including added cells) in vtk numbering
-        labelList cellTypes_;
-
-        labelList addPointCellLabels_;
-
-        labelList superCells_;
-
-
-    // Private Member Functions
-
-        //- Disallow default bitwise copy construct
-        vtkTopo(const vtkTopo&);
-
-        //- Disallow default bitwise assignment
-        void operator=(const vtkTopo&);
-
-
-public:
-
-   // Public static data
-
-        //- Equivalent to enumeration in "vtkCellType.h"
-        enum vtkTypes
-        {
-            VTK_TRIANGLE   = 5,
-            VTK_POLYGON    = 7,
-            VTK_QUAD       = 9,
-
-            VTK_TETRA      = 10,
-            VTK_HEXAHEDRON = 12,
-            VTK_WEDGE      = 13,
-            VTK_PYRAMID    = 14,
-            VTK_POLYHEDRON = 42
-        };
-
-    //- Enable/disable polyhedron decomposition. Default = true
-    static bool decomposePoly;
-
-
-    // Constructors
-
-        //- Construct from components
-        vtkTopo(const polyMesh&);
-
-    // Member Functions
-
-        // Access
-
-            const labelListList& vertLabels() const
-            {
-                return vertLabels_;
-            }
-
-            const labelList& cellTypes() const
-            {
-                return cellTypes_;
-            }
-
-            const labelList& addPointCellLabels() const
-            {
-                return addPointCellLabels_;
-            }
-
-            const labelList& superCells() const
-            {
-                return superCells_;
-            }
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFaceSet.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFaceSet.C
deleted file mode 100644
index 0556b7aaf27e0022b82cbb587dea9f818f9409e3..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFaceSet.C
+++ /dev/null
@@ -1,127 +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 "writeFaceSet.H"
-#include "OFstream.H"
-#include "writeFuns.H"
-
-// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
-
-void Foam::writeFaceSet
-(
-    const bool binary,
-    const fvMesh& mesh,
-    const faceSet& set,
-    const fileName& fileName
-)
-{
-    const faceList& faces = mesh.faces();
-
-    std::ofstream ostr(fileName.c_str());
-
-    writeFuns::writeHeader
-    (
-        ostr,
-        binary,
-        set.name()
-    );
-
-    ostr<< "DATASET POLYDATA" << std::endl;
-
-    //------------------------------------------------------------------
-    //
-    // Write topology
-    //
-    //------------------------------------------------------------------
-
-
-    // Construct primitivePatch of faces in faceSet.
-
-    faceList setFaces(set.size());
-    labelList setFaceLabels(set.size());
-    label setFacei = 0;
-
-    forAllConstIter(faceSet, set, iter)
-    {
-        setFaceLabels[setFacei] = iter.key();
-        setFaces[setFacei] = faces[iter.key()];
-        setFacei++;
-    }
-    primitiveFacePatch fp(setFaces, mesh.points());
-
-
-    // Write points and faces as polygons
-
-    ostr<< "POINTS " << fp.nPoints() << " float" << std::endl;
-
-    DynamicList<floatScalar> ptField(3*fp.nPoints());
-
-    writeFuns::insert(fp.localPoints(), ptField);
-
-    writeFuns::write(ostr, binary, ptField);
-
-
-    label nFaceVerts = 0;
-
-    forAll(fp.localFaces(), facei)
-    {
-        nFaceVerts += fp.localFaces()[facei].size() + 1;
-    }
-    ostr<< "POLYGONS " << fp.size() << ' ' << nFaceVerts << std::endl;
-
-
-    DynamicList<label> vertLabels(nFaceVerts);
-
-    forAll(fp.localFaces(), facei)
-    {
-        const face& f = fp.localFaces()[facei];
-
-        vertLabels.append(f.size());
-
-        writeFuns::insert(f, vertLabels);
-    }
-    writeFuns::write(ostr, binary, vertLabels);
-
-
-    //-----------------------------------------------------------------
-    //
-    // Write data
-    //
-    //-----------------------------------------------------------------
-
-    // Write faceID
-
-    ostr
-        << "CELL_DATA " << fp.size() << std::endl
-        << "FIELD attributes 1" << std::endl;
-
-    // Cell ids first
-    ostr<< "faceID 1 " << fp.size() << " int" << std::endl;
-
-    writeFuns::write(ostr, binary, setFaceLabels);
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFuns.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFuns.C
deleted file mode 100644
index 24eef341f641234798bf037d68f45b757178d7b7..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFuns.C
+++ /dev/null
@@ -1,264 +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/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "writeFuns.H"
-#include "vtkTopo.H"
-#include "endian.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-void Foam::writeFuns::swapWord(label& word32)
-{
-    char* mem = reinterpret_cast<char*>(&word32);
-
-    char a = mem[0];
-    mem[0] = mem[3];
-    mem[3] = a;
-
-    a = mem[1];
-    mem[1] = mem[2];
-    mem[2] = a;
-}
-
-
-void Foam::writeFuns::swapWords(const label nWords, label* words32)
-{
-    for (label i = 0; i < nWords; i++)
-    {
-        swapWord(words32[i]);
-    }
-}
-
-
-void Foam::writeFuns::write
-(
-    std::ostream& os,
-    const bool binary,
-    List<floatScalar>& fField
-)
-{
-    if (binary)
-    {
-        #ifdef WM_LITTLE_ENDIAN
-        swapWords(fField.size(), reinterpret_cast<label*>(fField.begin()));
-        #endif
-        os.write
-        (
-            reinterpret_cast<char*>(fField.begin()),
-            fField.size()*sizeof(float)
-        );
-
-        os  << std::endl;
-    }
-    else
-    {
-        forAll(fField, i)
-        {
-            os  << fField[i];
-
-            if (i > 0 && (i % 10) == 0)
-            {
-                os  << std::endl;
-            }
-            else
-            {
-                os  << ' ';
-            }
-        }
-        os << std::endl;
-    }
-}
-
-
-void Foam::writeFuns::write
-(
-    std::ostream& os,
-    const bool binary,
-    DynamicList<floatScalar>& fField
-)
-{
-    List<floatScalar>& fld = fField.shrink();
-
-    write(os, binary, fld);
-}
-
-
-void Foam::writeFuns::write
-(
-    std::ostream& os,
-    const bool binary,
-    labelList& elems
-)
-{
-    if (binary)
-    {
-        #ifdef WM_LITTLE_ENDIAN
-        swapWords(elems.size(), reinterpret_cast<label*>(elems.begin()));
-        #endif
-        os.write
-        (
-            reinterpret_cast<char*>(elems.begin()),
-            elems.size()*sizeof(label)
-        );
-
-        os  << std::endl;
-    }
-    else
-    {
-        forAll(elems, i)
-        {
-            os  << elems[i];
-
-            if (i > 0 && (i % 10) == 0)
-            {
-                os  << std::endl;
-            }
-            else
-            {
-                os  << ' ';
-            }
-        }
-        os  << std::endl;
-    }
-}
-
-
-void Foam::writeFuns::write
-(
-    std::ostream& os,
-    const bool binary,
-    DynamicList<label>& elems
-)
-{
-    labelList& fld = elems.shrink();
-
-    write(os, binary, fld);
-}
-
-
-void Foam::writeFuns::writeHeader
-(
-    std::ostream& os,
-    const bool binary,
-    const std::string& title
-)
-{
-    os  << "# vtk DataFile Version 2.0" << std::endl
-        << title << std::endl;
-
-    if (binary)
-    {
-        os  << "BINARY" << std::endl;
-    }
-    else
-    {
-        os  << "ASCII" << std::endl;
-    }
-}
-
-
-void Foam::writeFuns::writeCellDataHeader
-(
-    std::ostream& os,
-    const label nCells,
-    const label nFields
-)
-{
-    os  << "CELL_DATA " << nCells << std::endl
-        << "FIELD attributes " << nFields << std::endl;
-}
-
-
-void Foam::writeFuns::writePointDataHeader
-(
-    std::ostream& os,
-    const label nPoints,
-    const label nFields
-)
-{
-    os  << "POINT_DATA  " << nPoints << std::endl
-        << "FIELD attributes " << nFields << std::endl;
-}
-
-
-void Foam::writeFuns::insert(const scalar src, DynamicList<floatScalar>& dest)
-{
-    dest.append(float(src));
-}
-
-
-void Foam::writeFuns::insert(const vector& src, DynamicList<floatScalar>& dest)
-{
-    for (direction cmpt = 0; cmpt < vector::nComponents; ++cmpt)
-    {
-        dest.append(float(src[cmpt]));
-    }
-}
-
-
-void Foam::writeFuns::insert
-(
-    const sphericalTensor& src,
-    DynamicList<floatScalar>& dest
-)
-{
-    for (direction cmpt = 0; cmpt < sphericalTensor::nComponents; ++cmpt)
-    {
-        dest.append(float(src[cmpt]));
-    }
-}
-
-
-void Foam::writeFuns::insert
-(
-    const symmTensor& src,
-    DynamicList<floatScalar>& dest
-)
-{
-    dest.append(float(src.xx()));
-    dest.append(float(src.yy()));
-    dest.append(float(src.zz()));
-    dest.append(float(src.xy()));
-    dest.append(float(src.yz()));
-    dest.append(float(src.xz()));
-}
-
-
-void Foam::writeFuns::insert(const tensor& src, DynamicList<floatScalar>& dest)
-{
-    for (direction cmpt = 0; cmpt < tensor::nComponents; ++cmpt)
-    {
-        dest.append(float(src[cmpt]));
-    }
-}
-
-
-void Foam::writeFuns::insert(const labelList& src, DynamicList<label>& dest)
-{
-    dest.append(src);
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFuns.H b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFuns.H
deleted file mode 100644
index 60fe2a6d01034da4ee0de19da4cecd93b346e354..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFuns.H
+++ /dev/null
@@ -1,161 +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/>.
-
-Class
-    Foam::writeFuns
-
-Description
-    Various functions for collecting and writing binary data.
-
-SourceFiles
-    writeFuns.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef writeFuns_H
-#define writeFuns_H
-
-#include "floatScalar.H"
-#include "DynamicList.H"
-#include "volFieldsFwd.H"
-#include "pointFieldsFwd.H"
-#include "vtkMesh.H"
-#include "volPointInterpolation.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-/*---------------------------------------------------------------------------*\
-                           Class writeFuns Declaration
-\*---------------------------------------------------------------------------*/
-
-class writeFuns
-{
-    // Private Member Functions
-
-        // Swap halves of word.
-
-            static void swapWord(label& word32);
-            static void swapWords(const label nWords, label* words32);
-
-
-public:
-
-    // Write ascii or binary. If binary optionally in-place swaps argument
-
-        static void write(std::ostream&, const bool, List<floatScalar>&);
-        static void write(std::ostream&, const bool, DynamicList<floatScalar>&);
-        static void write(std::ostream&, const bool, labelList&);
-        static void write(std::ostream&, const bool, DynamicList<label>&);
-
-
-    // Write header
-
-        static void writeHeader
-        (
-            std::ostream&,
-            const bool isBinary,
-            const std::string& title
-        );
-        static void writeCellDataHeader
-        (
-            std::ostream&,
-            const label nCells,
-            const label nFields
-        );
-        static void writePointDataHeader
-        (
-            std::ostream&,
-            const label nPoints,
-            const label nFields
-        );
-
-
-    // Convert to VTK and store
-
-        static void insert(const scalar, DynamicList<floatScalar>&);
-        static void insert(const point&, DynamicList<floatScalar>&);
-        static void insert(const sphericalTensor&, DynamicList<floatScalar>&);
-        static void insert(const symmTensor&, DynamicList<floatScalar>&);
-        static void insert(const tensor&, DynamicList<floatScalar>&);
-
-
-    //- Append elements to DynamicList
-    static void insert(const labelList&, DynamicList<label>&);
-
-    template<class Type>
-    static void insert(const List<Type>&, DynamicList<floatScalar>&);
-
-    //- Write volField with cell values (including decomposed cells)
-    template<class Type>
-    static void write
-    (
-        std::ostream&,
-        const bool binary,
-        const DimensionedField<Type, volMesh>&,
-        const vtkMesh&
-    );
-
-    //- Write pointField on all mesh points. Interpolate to cell centre
-    //  for decomposed cell centres.
-    template<class Type>
-    static void write
-    (
-        std::ostream&,
-        const bool binary,
-        const GeometricField<Type, pointPatchField, pointMesh>&,
-        const vtkMesh&
-    );
-
-    //- Write interpolated field on points and original cell values on
-    //  decomposed cell centres.
-    template<class Type>
-    static void write
-    (
-        std::ostream&,
-        const bool binary,
-        const DimensionedField<Type, volMesh>&,
-        const DimensionedField<Type, pointMesh>&,
-        const vtkMesh&
-    );
-
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#ifdef NoRepository
-    #include "writeFunsTemplates.C"
-#endif
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFunsTemplates.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFunsTemplates.C
deleted file mode 100644
index 8929a1ad80eeab28e2509d1964b2f6d22d3a18a5..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFunsTemplates.C
+++ /dev/null
@@ -1,146 +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 "writeFuns.H"
-#include "interpolatePointToCell.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-// Store List in dest
-template<class Type>
-void Foam::writeFuns::insert
-(
-    const List<Type>& source,
-    DynamicList<floatScalar>& dest
-)
-{
-    forAll(source, i)
-    {
-        insert(source[i], dest);
-    }
-}
-
-
-template<class Type>
-void Foam::writeFuns::write
-(
-    std::ostream& os,
-    const bool binary,
-    const DimensionedField<Type, volMesh>& df,
-    const vtkMesh& vMesh
-)
-{
-    const fvMesh& mesh = vMesh.mesh();
-
-    const labelList& superCells = vMesh.topo().superCells();
-
-    label nValues = mesh.nCells() + superCells.size();
-
-    os  << df.name() << ' '
-        << int(pTraits<Type>::nComponents) << ' '
-        << nValues << " float" << std::endl;
-
-    DynamicList<floatScalar> fField(pTraits<Type>::nComponents*nValues);
-
-    insert(df.field(), fField);
-
-    forAll(superCells, superCelli)
-    {
-        label origCelli = superCells[superCelli];
-
-        insert(df[origCelli], fField);
-    }
-    write(os, binary, fField);
-}
-
-
-template<class Type>
-void Foam::writeFuns::write
-(
-    std::ostream& os,
-    const bool binary,
-    const GeometricField<Type, pointPatchField, pointMesh>& pvf,
-    const vtkMesh& vMesh
-)
-{
-    const fvMesh& mesh = vMesh.mesh();
-    const vtkTopo& topo = vMesh.topo();
-
-    const labelList& addPointCellLabels = topo.addPointCellLabels();
-    const label nTotPoints = mesh.nPoints() + addPointCellLabels.size();
-
-    os  << pvf.name() << ' '
-        << int(pTraits<Type>::nComponents) << ' '
-        << nTotPoints << " float" << std::endl;
-
-    DynamicList<floatScalar> fField(pTraits<Type>::nComponents*nTotPoints);
-
-    insert(pvf, fField);
-
-    forAll(addPointCellLabels, api)
-    {
-        label origCelli = addPointCellLabels[api];
-
-        insert(interpolatePointToCell(pvf, origCelli), fField);
-    }
-    write(os, binary, fField);
-}
-
-
-template<class Type>
-void Foam::writeFuns::write
-(
-    std::ostream& os,
-    const bool binary,
-    const DimensionedField<Type, volMesh>& vvf,
-    const DimensionedField<Type, pointMesh>& pvf,
-    const vtkMesh& vMesh
-)
-{
-    const fvMesh& mesh = vMesh.mesh();
-    const vtkTopo& topo = vMesh.topo();
-
-    const labelList& addPointCellLabels = topo.addPointCellLabels();
-    const label nTotPoints = mesh.nPoints() + addPointCellLabels.size();
-
-    os  << vvf.name() << ' '
-        << int(pTraits<Type>::nComponents) << ' '
-        << nTotPoints << " float" << std::endl;
-
-    DynamicList<floatScalar> fField(pTraits<Type>::nComponents*nTotPoints);
-
-    insert(pvf, fField);
-
-    forAll(addPointCellLabels, api)
-    {
-        label origCelli = addPointCellLabels[api];
-
-        insert(vvf[origCelli], fField);
-    }
-    write(os, binary, fField);
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writePointSet.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writePointSet.C
deleted file mode 100644
index e5fffb536671144a864004b16ee89eac11416612..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writePointSet.C
+++ /dev/null
@@ -1,103 +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/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "writePointSet.H"
-#include "OFstream.H"
-#include "writeFuns.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
-
-void writePointSet
-(
-    const bool binary,
-    const fvMesh& mesh,
-    const pointSet& set,
-    const fileName& fileName
-)
-{
-    std::ofstream ostr(fileName.c_str());
-
-    writeFuns::writeHeader
-    (
-        ostr,
-        binary,
-        set.name()
-    );
-
-    ostr<< "DATASET POLYDATA" << std::endl;
-
-    //------------------------------------------------------------------
-    //
-    // Write topology
-    //
-    //------------------------------------------------------------------
-
-
-    // Write points
-
-    ostr<< "POINTS " << set.size() << " float" << std::endl;
-
-    DynamicList<floatScalar> ptField(3*set.size());
-
-    writeFuns::insert
-    (
-        UIndirectList<point>(mesh.points(), set.toc())(),
-        ptField
-    );
-
-    writeFuns::write(ostr, binary, ptField);
-
-
-    //-----------------------------------------------------------------
-    //
-    // Write data
-    //
-    //-----------------------------------------------------------------
-
-    // Write faceID
-
-    ostr
-        << "POINT_DATA " << set.size() << std::endl
-        << "FIELD attributes 1" << std::endl;
-
-    // Cell ids first
-    ostr<< "pointID 1 " << set.size() << " int" << std::endl;
-
-    labelList pointIDs(set.toc());
-
-    writeFuns::write(ostr, binary, pointIDs);
-}
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writePointSet.H b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writePointSet.H
deleted file mode 100644
index d1ad15efe6d7b7b95946f479e695765eebb3aea8..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writePointSet.H
+++ /dev/null
@@ -1,63 +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/>.
-
-InClass
-    Foam::writePointSet
-
-Description
-    Write pointSet to vtk polydata file. Only one data which is original
-    pointID.
-
-SourceFiles
-    writePointSet.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef writePointSet_H
-#define writePointSet_H
-
-#include "fvMesh.H"
-#include "pointSet.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-// Write lagrangian fields.
-void writePointSet
-(
-    const bool binary,
-    const fvMesh& mesh,
-    const pointSet& set,
-    const fileName& fileName
-);
-
-} // End namespace Foam
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeSurfFields.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeSurfFields.C
deleted file mode 100644
index 9dc889adf4be77423e75cb965625c3cc7b52c590..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeSurfFields.C
+++ /dev/null
@@ -1,113 +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 "writeSurfFields.H"
-#include "OFstream.H"
-#include "floatScalar.H"
-#include "writeFuns.H"
-#include "emptyFvsPatchFields.H"
-#include "fvsPatchFields.H"
-
-// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
-
-void Foam::writeSurfFields
-(
-    const bool binary,
-    const fvMesh& mesh,
-    const fileName& fileName,
-    const UPtrList<const surfaceVectorField>& surfVectorFields
-)
-{
-    std::ofstream str(fileName.c_str());
-
-    writeFuns::writeHeader
-    (
-        str,
-        binary,
-        "surfaceFields"
-    );
-
-    str << "DATASET POLYDATA" << std::endl;
-
-    const pointField& fc = mesh.faceCentres();
-
-    str << "POINTS " << mesh.nFaces() << " float" << std::endl;
-
-    DynamicList<floatScalar> pField(3*mesh.nFaces());
-
-    for (label facei = 0; facei < mesh.nFaces(); facei++)
-    {
-        writeFuns::insert(fc[facei], pField);
-    }
-
-    writeFuns::write(str, binary, pField);
-
-    str << "POINT_DATA " << mesh.nFaces() << std::endl
-        << "FIELD attributes " << surfVectorFields.size() << std::endl;
-
-    // surfVectorFields
-    forAll(surfVectorFields, fieldi)
-    {
-        const surfaceVectorField& svf = surfVectorFields[fieldi];
-
-        str << svf.name() << " 3 "
-            << mesh.nFaces() << " float" << std::endl;
-
-        DynamicList<floatScalar> fField(3*mesh.nFaces());
-
-        for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
-        {
-            writeFuns::insert(svf[facei], fField);
-        }
-
-        forAll(svf.boundaryField(), patchi)
-        {
-            const fvsPatchVectorField& pf = svf.boundaryField()[patchi];
-
-            const fvPatch& pp = mesh.boundary()[patchi];
-
-            if (isA<emptyFvsPatchVectorField>(pf))
-            {
-                // Note: loop over polypatch size, not fvpatch size.
-                forAll(pp.patch(), i)
-                {
-                    writeFuns::insert(vector::zero, fField);
-                }
-            }
-            else
-            {
-                forAll(pf, i)
-                {
-                    writeFuns::insert(pf[i], fField);
-                }
-            }
-        }
-
-        writeFuns::write(str, binary, fField);
-    }
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeVTK/controlDict b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeVTK/controlDict
deleted file mode 100644
index 2888266a2ff183dbfe84755dd70695941550f7f0..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeVTK/controlDict
+++ /dev/null
@@ -1,81 +0,0 @@
-/*--------------------------------*- C++ -*----------------------------------*\
-| =========                 |                                                 |
-| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
-|  \\    /   O peration     | Version:  plus                                  |
-|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
-|    \\/     M anipulation  |                                                 |
-\*---------------------------------------------------------------------------*/
-FoamFile
-{
-    version     2.0;
-    format      ascii;
-    class       dictionary;
-    object      controlDict;
-}
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-// So we get a decent warning if we have multiple functionObject entries
-// with the same name.
-#inputMode error;
-
-application     icoFoam;
-
-startFrom       startTime;
-
-startTime       0;
-
-stopAt          endTime;
-
-endTime         0.5;
-
-deltaT          0.005;
-
-writeControl    timeStep;
-
-writeInterval   20;
-
-purgeWrite      0;
-
-writeFormat     ascii;
-
-writePrecision  6;
-
-writeCompression off;
-
-timeFormat      general;
-
-timePrecision   6;
-
-runTimeModifiable yes;
-
-functions
-{
-    writeVTK
-    {
-        type            writeVTK;
-
-        // Where to load it from
-        libs ("libfoamToVTK.so");
-
-        // When to write:
-        //  timeStep            (with optional writeInterval)
-        //  writeTime          (with optional writeInterval)
-        //  adjustableTime
-        //  runTime
-        //  clockTime
-        //  cpuTime
-        writeControl   writeTime;
-
-        // Write every writeInterval (only valid for timeStemp, writeTime)
-        writeInterval  1;
-
-        // Interval of time (valid for adjustableTime, runTime, clockTime,
-        //  cpuTime)
-        writeInterval   1;
-
-        // Objects to write
-        objectNames    ();
-    }
-}
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeVTK/writeVTK.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeVTK/writeVTK.C
deleted file mode 100644
index 2e7fa177c3f64ad8ba3e2e54f19555c70ab308e6..0000000000000000000000000000000000000000
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeVTK/writeVTK.C
+++ /dev/null
@@ -1,156 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 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/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "writeVTK.H"
-#include "dictionary.H"
-#include "Time.H"
-#include "vtkMesh.H"
-#include "internalWriter.H"
-#include "addToRunTimeSelectionTable.H"
-
-// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
-
-namespace Foam
-{
-namespace functionObjects
-{
-    defineTypeNameAndDebug(writeVTK, 0);
-    addToRunTimeSelectionTable(functionObject, writeVTK, dictionary);
-}
-}
-
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::functionObjects::writeVTK::writeVTK
-(
-    const word& name,
-    const Time& runTime,
-    const dictionary& dict
-)
-:
-    fvMeshFunctionObject(name, runTime, dict),
-    objectNames_()
-{
-    read(dict);
-}
-
-
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::functionObjects::writeVTK::~writeVTK()
-{}
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-bool Foam::functionObjects::writeVTK::read(const dictionary& dict)
-{
-    dict.lookup("objects") >> objectNames_;
-
-    return true;
-}
-
-
-bool Foam::functionObjects::writeVTK::execute()
-{
-    return true;
-}
-
-
-bool Foam::functionObjects::writeVTK::write()
-{
-    Info<< type() << " " << name() << " output:" << nl;
-
-    Info<< "Time: " << time_.timeName() << endl;
-
-    word timeDesc = time_.timeName();
-
-    // VTK/ directory in the case
-    fileName fvPath(time_.path()/"VTK");
-
-    mkDir(fvPath);
-
-    string vtkName = time_.caseName();
-
-    if (Pstream::parRun())
-    {
-        // Strip off leading casename, leaving just processor_DDD ending.
-        string::size_type i = vtkName.rfind("processor");
-
-        if (i != string::npos)
-        {
-            vtkName = vtkName.substr(i);
-        }
-    }
-
-    // Create file and write header
-    fileName vtkFileName
-    (
-        fvPath/vtkName
-      + "_"
-      + timeDesc
-      + ".vtk"
-    );
-
-    Info<< "    Internal  : " << vtkFileName << endl;
-
-    vtkMesh vMesh(const_cast<fvMesh&>(mesh_));
-
-    // Write mesh
-    internalWriter writer(vMesh, false, vtkFileName);
-
-    UPtrList<const volScalarField> vsf(lookupFields<volScalarField>());
-    UPtrList<const volVectorField> vvf(lookupFields<volVectorField>());
-    UPtrList<const volSphericalTensorField> vsptf
-    (
-        lookupFields<volSphericalTensorField>()
-    );
-    UPtrList<const volSymmTensorField> vstf(lookupFields<volSymmTensorField>());
-    UPtrList<const volTensorField> vtf(lookupFields<volTensorField>());
-
-    // Write header for cellID and volFields
-    writeFuns::writeCellDataHeader
-    (
-        writer.os(),
-        vMesh.nFieldCells(),
-        1 + vsf.size() + vvf.size() + vsptf.size() + vstf.size() + vtf.size()
-    );
-
-    // Write cellID field
-    writer.writeCellIDs();
-
-    // Write volFields
-    writer.write(vsf);
-    writer.write(vvf);
-    writer.write(vsptf);
-    writer.write(vstf);
-    writer.write(vtf);
-
-    return true;
-}
-
-
-// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.C
new file mode 100644
index 0000000000000000000000000000000000000000..959485fb1985279c91a269d8fa08e312ab5848bd
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.C
@@ -0,0 +1,279 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "foamVtkLagrangianWriter.H"
+#include "Cloud.H"
+#include "passiveParticle.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::vtk::lagrangianWriter::beginPiece()
+{
+    if (!legacy_)
+    {
+        if (useVerts_)
+        {
+            format()
+                .openTag(vtk::fileTag::PIECE)
+                .xmlAttr(fileAttr::NUMBER_OF_POINTS, nParcels_)
+                .xmlAttr(fileAttr::NUMBER_OF_VERTS,  nParcels_)
+                .closeTag();
+        }
+        else
+        {
+            format()
+                .openTag(vtk::fileTag::PIECE)
+                .xmlAttr(fileAttr::NUMBER_OF_POINTS, nParcels_)
+                .closeTag();
+        }
+    }
+}
+
+
+void Foam::vtk::lagrangianWriter::writePoints()
+{
+    Cloud<passiveParticle> parcels(mesh_, cloudName_, false);
+    nParcels_ = parcels.size();
+
+    const uint64_t payLoad = (nParcels_ * 3 * sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::beginPoints(os_, nParcels_);
+    }
+    else
+    {
+        beginPiece(); // Tricky - hide in here
+
+        format().tag(vtk::fileTag::POINTS)
+            .openDataArray<float,3>(vtk::dataArrayAttr::POINTS)
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+
+    forAllConstIters(parcels, iter)
+    {
+        const point& pt = iter().position();
+
+        vtk::write(format(), pt);
+    }
+    format().flush();
+
+    if (!legacy_)
+    {
+        format()
+            .endDataArray()
+            .endTag(vtk::fileTag::POINTS);
+    }
+}
+
+
+void Foam::vtk::lagrangianWriter::writeVertsLegacy()
+{
+    os_ << "VERTICES " << nParcels_ << ' ' << 2*nParcels_ << nl;
+
+    // legacy has cells + connectivity together
+    // count the number of vertices referenced
+
+    for (label i=0; i < nParcels_; ++i)
+    {
+        format().write(1);  // Number of vertices for this cell (==1)
+        format().write(i);
+    }
+    format().flush();
+}
+
+
+void Foam::vtk::lagrangianWriter::writeVerts()
+{
+    format().tag(vtk::fileTag::VERTS);
+
+    // Same payload throughout
+    const uint64_t payLoad = (nParcels_ * sizeof(label));
+
+    //
+    // 'connectivity'
+    // = linear mapping onto points
+    //
+    {
+        format().openDataArray<label>(vtk::dataArrayAttr::CONNECTIVITY)
+            .closeTag();
+
+        format().writeSize(payLoad);
+        for (label i=0; i < nParcels_; ++i)
+        {
+            format().write(i);
+        }
+        format().flush();
+
+        format().endDataArray();
+    }
+
+
+    //
+    // 'offsets'  (connectivity offsets)
+    // = linear mapping onto points (with 1 offset)
+    //
+    {
+        format().openDataArray<label>(vtk::dataArrayAttr::OFFSETS)
+            .closeTag();
+
+        format().writeSize(payLoad);
+        for (label i=0; i < nParcels_; ++i)
+        {
+            format().write(i+1);
+        }
+        format().flush();
+
+        format().endDataArray();
+    }
+
+    format().endTag(vtk::fileTag::VERTS);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::vtk::lagrangianWriter::lagrangianWriter
+(
+    const fvMesh& mesh,
+    const word& cloudName,
+    const fileName& baseName,
+    const vtk::outputOptions outOpts,
+    const bool dummyCloud
+)
+:
+    mesh_(mesh),
+    legacy_(outOpts.legacy()),
+    useVerts_(false),
+    format_(),
+    cloudName_(cloudName),
+    os_(),
+    nParcels_(0)
+{
+
+    outputOptions opts(outOpts);
+    opts.append(false);  // No append supported
+
+    os_.open((baseName + (legacy_ ? ".vtk" : ".vtp")).c_str());
+    format_ = opts.newFormatter(os_);
+
+    const auto& title = mesh_.time().caseName();
+
+    if (legacy_)
+    {
+        legacy::fileHeader(format(), title, vtk::fileTag::POLY_DATA);
+
+        if (dummyCloud)
+        {
+            legacy::beginPoints(os_, nParcels_);
+        }
+        else
+        {
+            writePoints();
+            if (useVerts_) writeVertsLegacy();
+        }
+    }
+    else
+    {
+        // XML (inline)
+
+        format()
+            .xmlHeader()
+            .xmlComment(title)
+            .beginVTKFile(vtk::fileTag::POLY_DATA, "0.1");
+
+        if (dummyCloud)
+        {
+            beginPiece();
+        }
+        else
+        {
+            writePoints();
+            if (useVerts_) writeVerts();
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::vtk::lagrangianWriter::~lagrangianWriter()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::vtk::lagrangianWriter::beginParcelData(label nFields)
+{
+    const vtk::fileTag dataType =
+    (
+        useVerts_
+      ? vtk::fileTag::CELL_DATA
+      : vtk::fileTag::POINT_DATA
+    );
+
+    if (legacy_)
+    {
+        legacy::dataHeader(os_, dataType, nParcels_, nFields);
+    }
+    else
+    {
+        format().tag(dataType);
+    }
+}
+
+
+void Foam::vtk::lagrangianWriter::endParcelData()
+{
+    const vtk::fileTag dataType =
+    (
+        useVerts_
+      ? vtk::fileTag::CELL_DATA
+      : vtk::fileTag::POINT_DATA
+    );
+
+    if (!legacy_)
+    {
+        format().endTag(dataType);
+    }
+}
+
+
+void Foam::vtk::lagrangianWriter::writeFooter()
+{
+    if (!legacy_)
+    {
+        // slight cheat. </Piece> too
+        format().endTag(vtk::fileTag::PIECE);
+
+        format().endTag(vtk::fileTag::POLY_DATA)
+            .endVTKFile();
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/lagrangianWriter.H b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.H
similarity index 56%
rename from applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/lagrangianWriter.H
rename to applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.H
index 24dd4a322872c92eb6f2dfa32474c7c676e728d3..5457ce8c605808ee295644f32313294f7b0b916d 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/lagrangianWriter.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriter.H
@@ -22,7 +22,7 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    Foam::lagrangianWriter
+    Foam::vtk::lagrangianWriter
 
 Description
     Write fields (internal).
@@ -33,38 +33,70 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef lagrangianWriter_H
-#define lagrangianWriter_H
+#ifndef foamVtkLagrangianWriter_H
+#define foamVtkLagrangianWriter_H
 
 #include "OFstream.H"
 #include "Cloud.H"
 #include "volFields.H"
 #include "pointFields.H"
+#include "foamVtkOutputOptions.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
-
 class volPointInterpolation;
 
+namespace vtk
+{
+
 /*---------------------------------------------------------------------------*\
-                           Class lagrangianWriter Declaration
+                      Class lagrangianWriter Declaration
 \*---------------------------------------------------------------------------*/
 
 class lagrangianWriter
 {
-    const fvMesh& mesh_;
+    // Private Member Data
+
+        //- Reference to the OpenFOAM mesh (or subset)
+        const fvMesh& mesh_;
+
+        //- Commonly used query
+        const bool legacy_;
+
+        //- Write lagrangian as cell data (verts) or point data?
+        const bool useVerts_;
+
+        autoPtr<vtk::formatter> format_;
+
+        const word cloudName_;
+
+        std::ofstream os_;
+
+        label nParcels_;
+
+
+    // Private Member Functions
 
-    const bool binary_;
+        //- Begin piece
+        void beginPiece();
 
-    const fileName fName_;
+        //- Write positions
+        void writePoints();
 
-    const word cloudName_;
+        //- Write vertex (cells)
+        void writeVertsLegacy();
 
-    std::ofstream os_;
+        //- Write vertex (cells)
+        void writeVerts();
 
-    label nParcels_;
+
+        //- Disallow default bitwise copy construct
+        lagrangianWriter(const lagrangianWriter&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const lagrangianWriter&) = delete;
 
 
 public:
@@ -74,37 +106,56 @@ public:
         //- Construct from components
         lagrangianWriter
         (
-            const fvMesh&,
-            const bool binary,
-            const fileName&,
-            const word&,
-            const bool dummyCloud
+            const fvMesh& mesh,
+            const word& cloudName,
+            const fileName& baseName,
+            const vtk::outputOptions outOpts,
+            const bool dummyCloud = false
         );
 
 
+    //- Destructor
+    ~lagrangianWriter();
+
+
     // Member Functions
 
-        std::ofstream& os()
+        inline std::ofstream& os()
         {
             return os_;
         }
 
-        void writeParcelHeader(const label nFields);
+        inline vtk::formatter& format()
+        {
+            return format_();
+        }
+
+        inline label nParcels() const
+        {
+            return nParcels_;
+        }
+
+        void beginParcelData(label nFields);
+        void endParcelData();
+
+        //- Write file footer
+        void writeFooter();
 
         //- Write IOField
         template<class Type>
-        void writeIOField(const wordList&);
+        void writeIOField(const wordList& objectNames);
 };
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace vtk
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 #ifdef NoRepository
-    #include "lagrangianWriterTemplates.C"
+    #include "foamVtkLagrangianWriterTemplates.C"
 #endif
 
 
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriterTemplates.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriterTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..bc3a2fd63084c8bdef404b89557312948ab570fc
--- /dev/null
+++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamVtkLagrangianWriterTemplates.C
@@ -0,0 +1,110 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "foamVtkLagrangianWriter.H"
+#include "IOField.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+void Foam::vtk::lagrangianWriter::writeIOField
+(
+    const wordList& objectNames
+)
+{
+    const int nCmpt(pTraits<Type>::nComponents);
+
+    const bool useIntField =
+        std::is_integral<typename pTraits<Type>::cmptType>();
+
+    for (const word& fldName : objectNames)
+    {
+        IOobject header
+        (
+            fldName,
+            mesh_.time().timeName(),
+            cloud::prefix/cloudName_,
+            mesh_,
+            IOobject::MUST_READ,
+            IOobject::NO_WRITE,
+            false  // no register
+        );
+
+        IOField<Type> fld(header);
+
+        if (useIntField)
+        {
+            const uint64_t payLoad(fld.size() * nCmpt * sizeof(label));
+
+            if (legacy_)
+            {
+                legacy::intField(os(), fldName, nCmpt, fld.size());
+            }
+            else
+            {
+                format().openDataArray<label, nCmpt>(fldName)
+                    .closeTag();
+            }
+
+            format().writeSize(payLoad);
+
+            // Ensure consistent output width
+            for (const Type& val : fld)
+            {
+                for (int cmpt=0; cmpt < nCmpt; ++cmpt)
+                {
+                    format().write(label(component(val, cmpt)));
+                }
+            }
+        }
+        else
+        {
+            const uint64_t payLoad(fld.size() * nCmpt * sizeof(float));
+
+            if (legacy_)
+            {
+                legacy::floatField(os(), fldName, nCmpt, fld.size());
+            }
+            else
+            {
+                format().openDataArray<float, nCmpt>(fldName)
+                    .closeTag();
+            }
+
+            format().writeSize(payLoad);
+            vtk::writeList(format(), fld);
+        }
+
+        format().flush();
+
+        if (!legacy_)
+        {
+            format().endDataArray();
+        }
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/readFields.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/readFields.C
similarity index 100%
rename from applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/readFields.C
rename to applications/utilities/postProcessing/dataConversion/foamToVTK/readFields.C
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/readFields.H b/applications/utilities/postProcessing/dataConversion/foamToVTK/readFields.H
similarity index 98%
rename from applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/readFields.H
rename to applications/utilities/postProcessing/dataConversion/foamToVTK/readFields.H
index 510bd11d2536419dea3c29bfce016e2dbd5ddd8e..085570d6855aa8c8a80dcd94cebecec692a2e15f 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/readFields.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/readFields.H
@@ -48,7 +48,7 @@ namespace Foam
 template<class GeoField>
 void readFields
 (
-    const meshSubsetHelper&,
+    const meshSubsetHelper& helper,
     const typename GeoField::Mesh& mesh,
     const IOobjectList& objects,
     const HashSet<word>& selectedFields,
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/CMakeLists.txt b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/CMakeLists.txt
index ce13bed97aa657f75ad7cfb49f190c5c78ed5971..f2fd631fd1be82cf9a709cc513d42d9d034f0b16 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/CMakeLists.txt
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/CMakeLists.txt
@@ -12,6 +12,7 @@ link_directories(
 include_directories(
     $ENV{WM_PROJECT_DIR}/src/OpenFOAM/lnInclude
     $ENV{WM_PROJECT_DIR}/src/OSspecific/$ENV{WM_OSTYPE}/lnInclude
+    $ENV{WM_PROJECT_DIR}/src/conversion/lnInclude
     $ENV{WM_PROJECT_DIR}/src/finiteVolume/lnInclude
     ${PROJECT_SOURCE_DIR}/../vtkPVFoam
     ${PROJECT_SOURCE_DIR}/../../foamPv/lnInclude
@@ -64,6 +65,7 @@ target_link_libraries(
     LINK_PUBLIC
     vtkPVFoam-pv${PARAVIEW_VERSION_MAJOR}.${PARAVIEW_VERSION_MINOR}
     foamPv-pv${PARAVIEW_VERSION_MAJOR}.${PARAVIEW_VERSION_MINOR}
+    conversion
     finiteVolume
     OpenFOAM
 )
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/PVFoamReader_SM.xml b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/PVFoamReader_SM.xml
index a82c81850fa35a282bd566069b67469b21018d01..7daa151df4183f9d93a55e01cdb078341b7dbaf0 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/PVFoamReader_SM.xml
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/PVFoamReader_SM.xml
@@ -27,6 +27,8 @@
       </Documentation>
     </DoubleVectorProperty>
 
+<!-- General Controls -->
+
     <!-- Refresh (push button) -->
     <Property
       name="Refresh"
@@ -35,12 +37,10 @@
       <Documentation>Rescan for updated times/fields.</Documentation>
     </Property>
 
-<!-- General Controls -->
-
     <!-- Skip Zero Time (check-box) -->
     <IntVectorProperty animateable="0"
       name="ZeroTime"
-      label="Skip Zero Time"
+      label="Skip 0/ time"
       command="SetSkipZeroTime"
       default_values="1"
       number_of_elements="1"
@@ -54,26 +54,28 @@
     <!-- Include Sets (check-box) -->
     <IntVectorProperty animateable="0"
       name="IncludeSets"
+      label="With Sets"
       command="SetIncludeSets"
       default_values="0"
       number_of_elements="1"
       panel_visibility="default">
       <BooleanDomain name="bool"/>
       <Documentation>
-        Search the polyMesh/sets/ directory
+        Search the polyMesh/sets/ directory for {cell,face,point} sets
       </Documentation>
     </IntVectorProperty>
 
     <!-- Include Zones (check-box) -->
     <IntVectorProperty animateable="0"
       name="IncludeZones"
+      label="With Zones"
       command="SetIncludeZones"
       default_values="0"
       number_of_elements="1"
       panel_visibility="default">
       <BooleanDomain name="bool"/>
       <Documentation>
-        ZoneMesh information is used to find {cell,face,point}Zones.
+        ZoneMesh information is used to find {cell,face,point} zones.
         The polyMesh/ directory is only checked on startup.
       </Documentation>
     </IntVectorProperty>
@@ -88,7 +90,7 @@
       panel_visibility="default">
       <BooleanDomain name="bool"/>
       <Documentation>
-        Show patchGroups only.
+        Display patchGroups only instead of individual patches.
       </Documentation>
     </IntVectorProperty>
 
@@ -109,6 +111,7 @@
     <!-- Interpolate Fields (check-box) -->
     <IntVectorProperty animateable="0"
       name="InterpolateFields"
+      label="cell-to-point"
       command="SetInterpolateVolFields"
       default_values="1"
       number_of_elements="1"
@@ -122,6 +125,7 @@
     <!-- Extrapolate Patches (check-box) -->
     <IntVectorProperty animateable="0"
       name="ExtrapolatePatches"
+      label="field-to-patch"
       command="SetExtrapolatePatches"
       default_values="0"
       number_of_elements="1"
@@ -132,7 +136,7 @@
       </Documentation>
     </IntVectorProperty>
 
-    <!-- Force GUI update (check-box) -->
+    <!-- Force GUI update (push button) -->
     <IntVectorProperty animateable="0"
       name="UpdateGUI"
       command="SetUpdateGUI"
@@ -148,7 +152,7 @@
     <!-- Use VTK Polyhedron (check-box) -->
     <IntVectorProperty animateable="0"
       name="UseVTKPolyhedron"
-      label="Use VTK Polyhedron"
+      label="VTK Polyhedra"
       command="SetUseVTKPolyhedron"
       default_values="0"
       number_of_elements="1"
@@ -159,16 +163,22 @@
       </Documentation>
     </IntVectorProperty>
 
-    <!-- Cache Mesh (check-box) -->
+    <!-- Mesh Caching (combo-box) -->
     <IntVectorProperty animateable="0"
-      name="CacheMesh"
-      command="SetCacheMesh"
-      default_values="1"
+      name="MeshCaching"
+      command="SetMeshCaching"
+      default_values="3"
       number_of_elements="1"
       panel_visibility="default">
-      <BooleanDomain name="bool"/>
+      <EnumerationDomain name="enum">
+        <Entry text="No caching" value="0" />
+        <Entry text="Cache fvMesh" value="1" />
+        <Entry text="Cache vtk,fvMesh" value="3" />
+      </EnumerationDomain>
       <Documentation>
-        Cache the fvMesh in memory.
+        Mesh caching styles.
+        Caching the OpenFOAM fvMesh reduces disk access.
+        Caching the VTK mesh reduces transcription overhead.
       </Documentation>
     </IntVectorProperty>
 
@@ -185,7 +195,7 @@
     <Property name="ShowPatchNames"/>
     <Property name="UpdateGUI"/>
     <Property name="UseVTKPolyhedron"/>
-    <Property name="CacheMesh"/>
+    <Property name="MeshCaching"/>
   </PropertyGroup>
 
 <!-- Parts Selections -->
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/pqFoamReaderControls.cxx b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/pqFoamReaderControls.cxx
index 3b6fe3da972e3c0e8d2b5607122c23a7ab5bacee..3cc3b19577317e86908f4902b457d91f2c0621e0 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/pqFoamReaderControls.cxx
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/pqFoamReaderControls.cxx
@@ -26,6 +26,7 @@ License
 #include "pqFoamReaderControls.h"
 
 #include <QCheckBox>
+#include <QComboBox>
 #include <QFrame>
 #include <QGridLayout>
 #include <QPushButton>
@@ -37,18 +38,31 @@ License
 #include "vtkSMIntVectorProperty.h"
 #include "vtkSMPropertyGroup.h"
 #include "vtkSMSourceProxy.h"
+#include "vtkSMEnumerationDomain.h"
 
 
 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
 // file-scope
-static QAbstractButton* setButtonProperties
+// Add horizontal divider to layout
+static void addHline(QGridLayout* layout, int row, int nCols)
+{
+    QFrame* hline = new QFrame(layout->parentWidget());
+    hline->setFrameStyle(QFrame::HLine | QFrame::Sunken);
+
+    layout->addWidget(hline, row, 0, 1, nCols);
+}
+
+
+// file-scope
+// Widget properties
+static QWidget* setWidgetProperties
 (
-    QAbstractButton* b,
+    QWidget* widget,
     vtkSMProperty* prop
 )
 {
-    QString tip;
+    widget->setFocusPolicy(Qt::NoFocus); // avoid dotted border
 
     vtkSMDocumentation* doc = prop->GetDocumentation();
     if (doc)
@@ -56,21 +70,33 @@ static QAbstractButton* setButtonProperties
         const char* txt = doc->GetDescription();
         if (txt)
         {
-            tip = QString(txt).simplified();
+            QString tip = QString(txt).simplified();
+            if (tip.size())
+            {
+               widget->setToolTip(tip);
+            }
         }
     }
 
+    return widget;
+}
+
+
+// file-scope
+// Button properties
+static QAbstractButton* setButtonProperties
+(
+    QAbstractButton* b,
+    vtkSMProperty* prop
+)
+{
+    setWidgetProperties(b, prop);
     b->setText(prop->GetXMLLabel());
-    if (tip.size())
-    {
-        b->setToolTip(tip);
-    }
-    b->setFocusPolicy(Qt::NoFocus); // avoid dotted border
 
     vtkSMIntVectorProperty* intProp =
        vtkSMIntVectorProperty::SafeDownCast(prop);
 
-    // initial checked state for integer (bool) properties
+    // Initial checked state for integer (bool) properties
     if (intProp)
     {
         b->setChecked(intProp->GetElement(0));
@@ -80,6 +106,66 @@ static QAbstractButton* setButtonProperties
 }
 
 
+// file-scope
+// Fill combo-box from XML enumeration
+static QComboBox* setComboBoxContent
+(
+    QComboBox* b,
+    vtkSMIntVectorProperty* prop
+)
+{
+    vtkSMEnumerationDomain* propEnum =
+        vtkSMEnumerationDomain::SafeDownCast
+        (
+            prop->FindDomain("vtkSMEnumerationDomain")
+        );
+
+    if (propEnum)
+    {
+        unsigned int n = propEnum->GetNumberOfEntries();
+        for (unsigned int idx=0; idx < n; ++idx)
+        {
+            const int val   = propEnum->GetEntryValue(idx);
+            const char* txt = propEnum->GetEntryText(idx);
+
+            b->insertItem(val, txt);
+        }
+
+        // Set default
+        const int val = prop->GetElement(0);
+        unsigned int idx = 0;
+        if (!propEnum->IsInDomain(val, idx))
+        {
+            idx = 0;
+        }
+        b->setCurrentIndex(idx);
+    }
+
+    return b;
+}
+
+
+// file-scope
+// Translate a combo-box index to a lookup value
+static int comboBoxValue(vtkSMIntVectorProperty* prop, int idx)
+{
+    vtkSMEnumerationDomain* propEnum =
+        vtkSMEnumerationDomain::SafeDownCast
+        (
+            prop->FindDomain("vtkSMEnumerationDomain")
+        );
+
+    if (propEnum)
+    {
+        return propEnum->GetEntryValue(idx);
+    }
+    else
+    {
+        return idx;
+    }
+}
+
+
 static vtkSMIntVectorProperty* lookupIntProp
 (
     vtkSMPropertyGroup* group,
@@ -102,12 +188,12 @@ static vtkSMIntVectorProperty* lookupIntProp
 void pqFoamReaderControls::fireCommand
 (
     vtkSMIntVectorProperty* prop,
-    bool checked
+    int val
 )
 {
     vtkSMProxy* pxy = this->proxy();
 
-    prop->SetElement(0, checked); // Toogle bool
+    prop->SetElement(0, val); // Set int value, toogle bool, etc
 
     // Fire off command
     prop->Modified();
@@ -140,9 +226,9 @@ void pqFoamReaderControls::refreshPressed()
 }
 
 
-void pqFoamReaderControls::cacheMesh(bool checked)
+void pqFoamReaderControls::cacheMesh(int idx)
 {
-    fireCommand(cacheMesh_, checked);
+    fireCommand(meshCaching_, comboBoxValue(meshCaching_, idx));
 }
 
 
@@ -196,12 +282,14 @@ pqFoamReaderControls::pqFoamReaderControls
     showGroupsOnly_(lookupIntProp(group, "ShowGroupsOnly")),
     includeSets_(lookupIntProp(group, "IncludeSets")),
     includeZones_(lookupIntProp(group, "IncludeZones")),
-    cacheMesh_(lookupIntProp(group, "CacheMesh"))
+    meshCaching_(lookupIntProp(group, "MeshCaching"))
 {
     typedef vtkSMIntVectorProperty intProp;
 
     QGridLayout* form = new QGridLayout(this);
 
+    const int nCols = 3;
+
     // ROW
     // ~~~
     int row = 0;
@@ -222,17 +310,14 @@ pqFoamReaderControls::pqFoamReaderControls
         setButtonProperties(b, zeroTime);
         form->addWidget(b, row, 1, Qt::AlignLeft);
 
-        addPropertyLink(b, "checked", SIGNAL(toggled(bool)), zeroTime);
+        addPropertyLink
+        (
+            b, "checked", SIGNAL(toggled(bool)), zeroTime
+        );
     }
 
     // LINE
-    // ~~~~
-    ++row;
-    {
-        QFrame* hline = new QFrame(this);
-        hline->setFrameStyle(QFrame::HLine | QFrame::Sunken);
-        form->addWidget(hline, row, 0, 1, 4);
-    }
+    addHline(form, ++row, nCols);
 
     // ROW
     // ~~~
@@ -244,8 +329,14 @@ pqFoamReaderControls::pqFoamReaderControls
         setButtonProperties(b, includeSets_);
         form->addWidget(b, row, 0, Qt::AlignLeft);
 
-        addPropertyLink(b, "checked", SIGNAL(toggled(bool)), includeSets_);
-        connect(b, SIGNAL(toggled(bool)), this, SLOT(includeSets(bool)));
+        addPropertyLink
+        (
+            b, "checked", SIGNAL(toggled(bool)), includeSets_
+        );
+        connect
+        (
+            b, SIGNAL(toggled(bool)), this, SLOT(includeSets(bool))
+        );
     }
 
     if (showGroupsOnly_)
@@ -254,8 +345,14 @@ pqFoamReaderControls::pqFoamReaderControls
         setButtonProperties(b, showGroupsOnly_);
         form->addWidget(b, row, 1, Qt::AlignLeft);
 
-        addPropertyLink(b, "checked", SIGNAL(toggled(bool)), showGroupsOnly_);
-        connect(b, SIGNAL(toggled(bool)), this, SLOT(showGroupsOnly(bool)));
+        addPropertyLink
+        (
+            b, "checked", SIGNAL(toggled(bool)), showGroupsOnly_
+        );
+        connect
+        (
+            b, SIGNAL(toggled(bool)), this, SLOT(showGroupsOnly(bool))
+        );
     }
 
 
@@ -269,8 +366,14 @@ pqFoamReaderControls::pqFoamReaderControls
         setButtonProperties(b, includeZones_);
         form->addWidget(b, row, 0, Qt::AlignLeft);
 
-        addPropertyLink(b, "checked", SIGNAL(toggled(bool)), includeZones_);
-        connect(b, SIGNAL(toggled(bool)), this, SLOT(includeZones(bool)));
+        addPropertyLink
+        (
+            b, "checked", SIGNAL(toggled(bool)), includeZones_
+        );
+        connect
+        (
+            b, SIGNAL(toggled(bool)), this, SLOT(includeZones(bool))
+        );
     }
 
     if (showPatchNames_)
@@ -279,17 +382,14 @@ pqFoamReaderControls::pqFoamReaderControls
         setButtonProperties(b, showPatchNames_);
         form->addWidget(b, row, 1, Qt::AlignLeft);
 
-        connect(b, SIGNAL(toggled(bool)), this, SLOT(showPatchNames(bool)));
+        connect
+        (
+            b, SIGNAL(toggled(bool)), this, SLOT(showPatchNames(bool))
+        );
     }
 
     // LINE
-    // ~~~~
-    ++row;
-    {
-        QFrame* hline = new QFrame(this);
-        hline->setFrameStyle(QFrame::HLine | QFrame::Sunken);
-        form->addWidget(hline, row, 0, 1, 4);
-    }
+    addHline(form, ++row, nCols);
 
     // ROW
     // ~~~
@@ -302,7 +402,10 @@ pqFoamReaderControls::pqFoamReaderControls
         setButtonProperties(b, interpolate);
         form->addWidget(b, row, 0, Qt::AlignLeft);
 
-        addPropertyLink(b, "checked", SIGNAL(toggled(bool)), interpolate);
+        addPropertyLink
+        (
+            b, "checked", SIGNAL(toggled(bool)), interpolate
+        );
     }
 
     intProp* extrapolate = lookupIntProp(group, "ExtrapolatePatches");
@@ -312,17 +415,14 @@ pqFoamReaderControls::pqFoamReaderControls
         setButtonProperties(b, extrapolate);
         form->addWidget(b, row, 1, Qt::AlignLeft);
 
-        addPropertyLink(b, "checked", SIGNAL(toggled(bool)), extrapolate);
+        addPropertyLink
+        (
+            b, "checked", SIGNAL(toggled(bool)), extrapolate
+        );
     }
 
     // LINE
-    // ~~~~
-    ++row;
-    {
-        QFrame* hline = new QFrame(this);
-        hline->setFrameStyle(QFrame::HLine | QFrame::Sunken);
-        form->addWidget(hline, row, 0, 1, 4);
-    }
+    addHline(form, ++row, nCols);
 
     // ROW
     // ~~~
@@ -335,7 +435,10 @@ pqFoamReaderControls::pqFoamReaderControls
         setButtonProperties(b, updateGui);
         form->addWidget(b, row, 0, Qt::AlignLeft);
 
-        addPropertyLink(b, "checked", SIGNAL(clicked()), updateGui);
+        addPropertyLink
+        (
+            b, "checked", SIGNAL(clicked()), updateGui
+        );
     }
 
     intProp* usePolyhedron = lookupIntProp(group, "UseVTKPolyhedron");
@@ -345,16 +448,29 @@ pqFoamReaderControls::pqFoamReaderControls
         setButtonProperties(b, usePolyhedron);
         form->addWidget(b, row, 1, Qt::AlignLeft);
 
-        addPropertyLink(b, "checked", SIGNAL(toggled(bool)), usePolyhedron);
+        addPropertyLink
+        (
+            b, "checked", SIGNAL(toggled(bool)), usePolyhedron
+        );
     }
 
-    if (cacheMesh_)
+    if (meshCaching_)
     {
-        QCheckBox* b = new QCheckBox(this);
-        setButtonProperties(b, cacheMesh_);
+        QComboBox* b = new QComboBox(this);
         form->addWidget(b, row, 2, Qt::AlignLeft);
 
-        connect(b, SIGNAL(toggled(bool)), this, SLOT(cacheMesh(bool)));
+        setWidgetProperties(b, meshCaching_);
+        setComboBoxContent(b, meshCaching_);
+
+        addPropertyLink
+        (
+            b, "indexChanged", SIGNAL(currentIndexChanged(int)), meshCaching_
+        );
+
+        connect
+        (
+            b, SIGNAL(currentIndexChanged(int)), this, SLOT(cacheMesh(int))
+        );
     }
 }
 
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/pqFoamReaderControls.h b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/pqFoamReaderControls.h
index fc3c8d4044b7eca2ba4cb6ffccf73f6dc5624d64..ba0a7a9f6718be5eb153aa826333a0d93a983682 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/pqFoamReaderControls.h
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/pqFoamReaderControls.h
@@ -69,8 +69,8 @@ class pqFoamReaderControls
         //- IncludeZones (bool property)
         vtkSMIntVectorProperty* includeZones_;
 
-        //- CacheMesh (bool property)
-        vtkSMIntVectorProperty* cacheMesh_;
+        //- MeshCaching (enum property)
+        vtkSMIntVectorProperty* meshCaching_;
 
 
     // Private Member Functions
@@ -78,8 +78,8 @@ class pqFoamReaderControls
     //- Update property
     void fireCommand(vtkSMProperty* prop);
 
-    //- Toggle and update bool property
-    void fireCommand(vtkSMIntVectorProperty* prop, bool checked);
+    //- Update int property or toggle bool property
+    void fireCommand(vtkSMIntVectorProperty* prop, int val);
 
 
     //- Disallow default bitwise copy construct
@@ -102,7 +102,7 @@ protected slots:
     // Protected Member Functions
 
     void refreshPressed();
-    void cacheMesh(bool checked);
+    void cacheMesh(int idx);
     void showPatchNames(bool checked);
     void showGroupsOnly(bool checked);
     void includeSets(bool checked);
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/vtkPVFoamReader.cxx b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/vtkPVFoamReader.cxx
index 46c01d92f7dfb5bff0a28e31fb9dd764374eda30..c6ec1e676cd5fa567bee9614c8237c870ec17a6c 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/vtkPVFoamReader.cxx
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/vtkPVFoamReader.cxx
@@ -39,6 +39,7 @@ License
 #include "vtkSMRenderViewProxy.h"
 #include "vtkStreamingDemandDrivenPipeline.h"
 #include "vtkStringArray.h"
+#include "vtkSmartPointer.h"
 
 // OpenFOAM includes
 #include "vtkPVFoam.H"
@@ -46,7 +47,7 @@ License
 // STL includes
 #include <vector>
 
-#undef EXPERIMENTAL_TIME_CACHING
+#undef VTKPVFOAM_DUALPORT
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -61,27 +62,26 @@ vtkPVFoamReader::vtkPVFoamReader()
     vtkDebugMacro(<<"Constructor");
 
     SetNumberOfInputPorts(0);
-
     FileName = nullptr;
     backend_ = nullptr;
-    output0_ = nullptr;
 
 #ifdef VTKPVFOAM_DUALPORT
     // Add second output for the Lagrangian
     this->SetNumberOfOutputPorts(2);
-    vtkMultiBlockDataSet *lagrangian = vtkMultiBlockDataSet::New();
+
+    auto lagrangian = vtkSmartPointer<vtkMultiBlockDataSet>::New();
+
     lagrangian->ReleaseData();
 
     this->GetExecutive()->SetOutputData(1, lagrangian);
-    lagrangian->Delete();
 #endif
 
     TimeStepRange[0] = 0;
     TimeStepRange[1] = 0;
 
-    CacheMesh = true;
+    MeshCaching = 3;  // fvMesh+vtk
 
-    SkipZeroTime = false;
+    SkipZeroTime = true;
     ExtrapolatePatches = false;
     UseVTKPolyhedron = false;
     IncludeSets = false;
@@ -146,15 +146,9 @@ vtkPVFoamReader::~vtkPVFoamReader()
 
     if (FileName)
     {
-        delete [] FileName;
-    }
-
-    if (output0_)
-    {
-        output0_->Delete();
+        delete[] FileName;
     }
 
-
     PartSelection->RemoveAllObservers();
     VolFieldSelection->RemoveAllObservers();
     PointFieldSelection->RemoveAllObservers();
@@ -218,7 +212,7 @@ int vtkPVFoamReader::RequestInformation
     {
         vtkErrorMacro("could not find valid OpenFOAM mesh");
 
-        // delete foamData and flag it as fatal error
+        // delete backend handler and flag it as fatal error
         delete backend_;
         backend_ = nullptr;
         return 0;
@@ -255,7 +249,7 @@ int vtkPVFoamReader::RequestInformation
                 <<"time-range " << times.front() << ':' << times.back() << "\n"
                 <<"times " << times.size() << "(";
 
-            for (const double& val : times)
+            for (auto val : times)
             {
                 cout<< ' ' << val;
             }
@@ -291,12 +285,12 @@ int vtkPVFoamReader::RequestData
 
     if (!FileName)
     {
-        vtkErrorMacro("FileName has to be specified!");
+        vtkErrorMacro("FileName must be specified!");
         return 0;
     }
     if (!backend_)
     {
-        // catch some previous error
+        // Catch some previous error
         vtkErrorMacro("Reader failed - perhaps no mesh?");
         return 0;
     }
@@ -326,7 +320,8 @@ int vtkPVFoamReader::RequestData
     {
         vtkInformation *outInfo = outputVector->GetInformationObject(infoI);
 
-        int nsteps = outInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
+        const int nsteps =
+            outInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
 
         if
         (
@@ -361,76 +356,23 @@ int vtkPVFoamReader::RequestData
         )
     );
 
-    if (Foam::vtkPVFoam::debug)
-    {
-        cout<< "update output with "
-            << output->GetNumberOfBlocks() << " blocks\n";
-    }
-
-
-#ifdef EXPERIMENTAL_TIME_CACHING
-    bool needsUpdate = false;
-
-    if (!output0_)
-    {
-        output0_ = vtkMultiBlockDataSet::New();
-        needsUpdate = true;
-    }
-
-    // This experimental bit of code seems to work for the geometry,
-    // but trashes the fields and still triggers the GeometryFilter
-    if (needsUpdate)
-    {
-        backend_->Update(output);
-        output0_->ShallowCopy(output);
-    }
-    else
-    {
-        output->ShallowCopy(output0_);
-    }
-
-    if (Foam::vtkPVFoam::debug)
-    {
-        if (needsUpdate)
-        {
-            cout<< "full UPDATE ---------\n";
-        }
-        else
-        {
-            cout<< "cached UPDATE ---------\n";
-        }
-
-        cout<< "UPDATED output: ";
-        output->Print(cout);
-
-        cout<< "UPDATED output0_: ";
-        output0_->Print(cout);
-    }
-
-#else
-
 #ifdef VTKPVFOAM_DUALPORT
-    backend_->Update
+    vtkMultiBlockDataSet* output1 = vtkMultiBlockDataSet::SafeDownCast
     (
-        output,
-        vtkMultiBlockDataSet::SafeDownCast
+        outputVector->GetInformationObject(1)->Get
         (
-            outputVector->GetInformationObject(1)->Get
-            (
-                vtkMultiBlockDataSet::DATA_OBJECT()
-            )
-        );
+            vtkMultiBlockDataSet::DATA_OBJECT()
+        )
     );
+
+    backend_->Update(output, output1);
 #else
-    backend_->Update(output, output);
+    backend_->Update(output, nullptr);
 #endif
 
     updatePatchNamesView(ShowPatchNames);
 
-#endif
-
-    // Do any cleanup on the OpenFOAM side
-    backend_->CleanUp();
+    backend_->UpdateFinalize();
 
     return 1;
 }
@@ -525,13 +467,11 @@ void vtkPVFoamReader::updatePatchNamesView(const bool show)
     }
 
     // Get all the pqRenderView instances
-    QList<pqRenderView*> renderViews = smModel->findItems<pqRenderView*>();
-
-    for (int viewI=0; viewI < renderViews.size(); ++viewI)
+    for (auto view : smModel->findItems<pqRenderView*>())
     {
         backend_->renderPatchNames
         (
-            renderViews[viewI]->getRenderViewProxy()->GetRenderer(),
+            view->getRenderViewProxy()->GetRenderer(),
             show
         );
     }
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/vtkPVFoamReader.h b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/vtkPVFoamReader.h
index 0de09a5547b4da6319fa38959f4a7955fd08d56f..550c1167bbb887c1bfc8c81b607e3cf72e634b8a 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/vtkPVFoamReader.h
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/vtkPVFoamReader.h
@@ -46,6 +46,7 @@ SourceFiles
 // VTK forward declarations
 class vtkDataArraySelection;
 class vtkCallbackCommand;
+template<class T> class vtkSmartPointer;
 
 // OpenFOAM forward declarations
 namespace Foam
@@ -82,9 +83,9 @@ public:
     virtual void PrintInfo();
 
     // Description:
-    // OpenFOAM mesh caching control
-    vtkSetMacro(CacheMesh, bool);
-    vtkGetMacro(CacheMesh, bool);
+    // Mesh caching control (0:none,1:fvMesh,3:fvMesh+vtk)
+    vtkSetMacro(MeshCaching, int);
+    vtkGetMacro(MeshCaching, int);
 
     // Description:
     // OpenFOAM refresh times/fields
@@ -231,7 +232,7 @@ private:
     void updatePatchNamesView(const bool show);
 
     int TimeStepRange[2];
-    bool CacheMesh;
+    int MeshCaching;
     bool SkipZeroTime;
 
     bool ExtrapolatePatches;
@@ -250,9 +251,6 @@ private:
     vtkDataArraySelection* PointFieldSelection;
     vtkDataArraySelection* LagrangianFieldSelection;
 
-    //- Cached data for output port0 (experimental!)
-    vtkMultiBlockDataSet* output0_;
-
     //- Backend portion of the reader
     Foam::vtkPVFoam* backend_;
 };
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoam.C b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoam.C
index c20a9655780968ec46788d4a6850eff433777dd0..67857bc0bf1a87d049bc137026b9ab263ad2f498 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoam.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoam.C
@@ -37,40 +37,67 @@ License
 #include "vtkRenderer.h"
 #include "vtkTextActor.h"
 #include "vtkTextProperty.h"
+#include "vtkSmartPointer.h"
+#include "vtkInformation.h"
+
+// Templates (only needed here)
+#include "vtkPVFoamUpdateTemplates.C"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
 namespace Foam
 {
     defineTypeNameAndDebug(vtkPVFoam, 0);
+
+    // file-scope
+    static word updateStateName(polyMesh::readUpdateState state)
+    {
+        switch (state)
+        {
+            case polyMesh::UNCHANGED:      return "UNCHANGED";
+            case polyMesh::POINTS_MOVED:   return "POINTS_MOVED";
+            case polyMesh::TOPO_CHANGE:    return "TOPO_CHANGE";
+            case polyMesh::TOPO_PATCH_CHANGE: return "TOPO_PATCH_CHANGE";
+        };
+
+        return "UNKNOWN";
+    }
 }
 
 
 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
-vtkTextActor* Foam::vtkPVFoam::createTextActor
-(
-    const string& s,
-    const point& pt
-)
+namespace Foam
 {
-    vtkTextActor* txt = vtkTextActor::New();
-    txt->SetInput(s.c_str());
-
-    // Set text properties
-    vtkTextProperty* tprop = txt->GetTextProperty();
-    tprop->SetFontFamilyToArial();
-    tprop->BoldOn();
-    tprop->ShadowOff();
-    tprop->SetLineSpacing(1.0);
-    tprop->SetFontSize(14);
-    tprop->SetColor(1.0, 0.0, 1.0);
-    tprop->SetJustificationToCentered();
-
-    txt->GetPositionCoordinate()->SetCoordinateSystemToWorld();
-    txt->GetPositionCoordinate()->SetValue(pt.x(), pt.y(), pt.z());
-
-    return txt;
+    // file-scope
+
+    //- Create a text actor
+    vtkSmartPointer<vtkTextActor> createTextActor
+    (
+        const std::string& s,
+        const Foam::point& pt
+    )
+    {
+        vtkSmartPointer<vtkTextActor> txt =
+            vtkSmartPointer<vtkTextActor>::New();
+
+        txt->SetInput(s.c_str());
+
+        // Set text properties
+        vtkTextProperty* tprop = txt->GetTextProperty();
+        tprop->SetFontFamilyToArial();
+        tprop->BoldOn();
+        tprop->ShadowOff();
+        tprop->SetLineSpacing(1.0);
+        tprop->SetFontSize(14);
+        tprop->SetColor(1.0, 0.0, 1.0);
+        tprop->SetJustificationToCentered();
+
+        txt->GetPositionCoordinate()->SetCoordinateSystemToWorld();
+        txt->GetPositionCoordinate()->SetValue(pt.x(), pt.y(), pt.z());
+
+        return txt;
+    }
 }
 
 
@@ -79,40 +106,79 @@ vtkTextActor* Foam::vtkPVFoam::createTextActor
 void Foam::vtkPVFoam::resetCounters()
 {
     // Reset array range information (ids and sizes)
-    arrayRangeVolume_.reset();
-    arrayRangePatches_.reset();
-    arrayRangeLagrangian_.reset();
-    arrayRangeCellZones_.reset();
-    arrayRangeFaceZones_.reset();
-    arrayRangePointZones_.reset();
-    arrayRangeCellSets_.reset();
-    arrayRangeFaceSets_.reset();
-    arrayRangePointSets_.reset();
+    rangeVolume_.reset();
+    rangePatches_.reset();
+    rangeLagrangian_.reset();
+    rangeCellZones_.reset();
+    rangeFaceZones_.reset();
+    rangePointZones_.reset();
+    rangeCellSets_.reset();
+    rangeFaceSets_.reset();
+    rangePointSets_.reset();
 }
 
 
-void Foam::vtkPVFoam::reduceMemory()
+template<class Container>
+bool Foam::vtkPVFoam::addOutputBlock
+(
+    vtkMultiBlockDataSet* output,
+    const HashTable<Container, string>& cache,
+    const arrayRange& selector,
+    const bool singleDataset
+) const
 {
-    forAll(regionPolyDecomp_, i)
-    {
-        regionPolyDecomp_[i].clear();
-    }
+    const auto blockNo = output->GetNumberOfBlocks();
+    vtkSmartPointer<vtkMultiBlockDataSet> block;
+    int datasetNo = 0;
 
-    forAll(zonePolyDecomp_, i)
+    for (auto partId : selector)
     {
-        zonePolyDecomp_[i].clear();
-    }
+        if (selectedPartIds_.found(partId))
+        {
+            const auto& longName = selectedPartIds_[partId];
+            const word shortName = getFoamName(longName);
 
-    forAll(csetPolyDecomp_, i)
-    {
-        csetPolyDecomp_[i].clear();
-    }
+            auto iter = cache.find(longName);
+            if (iter.found() && iter.object().dataset)
+            {
+                auto dataset = iter.object().dataset;
 
-    if (!reader_->GetCacheMesh())
-    {
-        delete meshPtr_;
-        meshPtr_ = nullptr;
+                if (singleDataset)
+                {
+                    output->SetBlock(blockNo, dataset);
+                    output->GetMetaData(blockNo)->Set
+                    (
+                        vtkCompositeDataSet::NAME(),
+                        shortName.c_str()
+                    );
+
+                    ++datasetNo;
+                    break;
+                }
+                else if (datasetNo == 0)
+                {
+                    block = vtkSmartPointer<vtkMultiBlockDataSet>::New();
+                    output->SetBlock(blockNo, block);
+                    output->GetMetaData(blockNo)->Set
+                    (
+                        vtkCompositeDataSet::NAME(),
+                        selector.name()
+                    );
+                }
+
+                block->SetBlock(datasetNo, dataset);
+                block->GetMetaData(datasetNo)->Set
+                (
+                    vtkCompositeDataSet::NAME(),
+                    shortName.c_str()
+                );
+
+                ++datasetNo;
+            }
+        }
     }
+
+    return datasetNo;
 }
 
 
@@ -151,27 +217,14 @@ int Foam::vtkPVFoam::setTime(int nRequest, const double requestTimes[])
             << ", nearestIndex = " << nearestIndex << endl;
     }
 
-
-    // see what has changed
+    // See what has changed
     if (timeIndex_ != nearestIndex)
     {
         timeIndex_ = nearestIndex;
         runTime.setTime(Times[nearestIndex], nearestIndex);
 
-        // the fields change each time
-        fieldsChanged_ = true;
-
-        if (meshPtr_)
-        {
-            if (meshPtr_->readUpdate() != polyMesh::UNCHANGED)
-            {
-                meshChanged_ = true;
-            }
-        }
-        else
-        {
-            meshChanged_ = true;
-        }
+        // When the changes, so do the fields
+        meshState_ = meshPtr_ ? meshPtr_->readUpdate() : polyMesh::TOPO_CHANGE;
 
         reader_->UpdateProgress(0.05);
 
@@ -184,63 +237,16 @@ int Foam::vtkPVFoam::setTime(int nRequest, const double requestTimes[])
         Info<< "<end> setTime() - selectedTime="
             << Times[nearestIndex].name() << " index=" << timeIndex_
             << "/" << Times.size()
-            << " meshChanged=" << Switch(meshChanged_)
-            << " fieldsChanged=" << Switch(fieldsChanged_) << endl;
+            << " meshUpdateState=" << updateStateName(meshState_) << endl;
     }
 
     return nearestIndex;
 }
 
 
-void Foam::vtkPVFoam::updateMeshPartsStatus()
+Foam::word Foam::vtkPVFoam::getReaderPartName(const int partId) const
 {
-    if (debug)
-    {
-        Info<< "<beg> updateMeshPartsStatus" << endl;
-    }
-
-    vtkDataArraySelection* selection = reader_->GetPartSelection();
-    label nElem = selection->GetNumberOfArrays();
-
-    if (partStatus_.size() != nElem)
-    {
-        partStatus_.setSize(nElem);
-        partStatus_ = false;
-        meshChanged_ = true;
-    }
-
-    // this needs fixing if we wish to re-use the datasets
-    partDataset_.setSize(nElem);
-    partDataset_ = -1;
-
-    // Read the selected mesh parts (zones, patches ...) and add to list
-    forAll(partStatus_, partId)
-    {
-        const int setting = selection->GetArraySetting(partId);
-
-        if (partStatus_[partId] != setting)
-        {
-            partStatus_[partId] = setting;
-            meshChanged_ = true;
-        }
-
-        if (debug > 1)
-        {
-            Info<< "  part[" << partId << "] = "
-                << partStatus_[partId]
-                << " : " << selection->GetArrayName(partId) << endl;
-        }
-    }
-    if (debug)
-    {
-        Info<< "<end> updateMeshPartsStatus" << endl;
-    }
-}
-
-
-Foam::word Foam::vtkPVFoam::getPartName(const int partId)
-{
-    return getFirstWord(reader_->GetPartArrayName(partId));
+    return getFoamName(reader_->GetPartArrayName(partId));
 }
 
 
@@ -258,17 +264,17 @@ Foam::vtkPVFoam::vtkPVFoam
     meshRegion_(polyMesh::defaultRegion),
     meshDir_(polyMesh::meshSubDir),
     timeIndex_(-1),
-    meshChanged_(true),
-    fieldsChanged_(true),
-    arrayRangeVolume_("unzoned"),
-    arrayRangePatches_("patches"),
-    arrayRangeLagrangian_("lagrangian"),
-    arrayRangeCellZones_("cellZone"),
-    arrayRangeFaceZones_("faceZone"),
-    arrayRangePointZones_("pointZone"),
-    arrayRangeCellSets_("cellSet"),
-    arrayRangeFaceSets_("faceSet"),
-    arrayRangePointSets_("pointSet")
+    decomposePoly_(false),
+    meshState_(polyMesh::TOPO_CHANGE),
+    rangeVolume_("unzoned"),
+    rangePatches_("patch"),
+    rangeLagrangian_("lagrangian"),
+    rangeCellZones_("cellZone"),
+    rangeFaceZones_("faceZone"),
+    rangePointZones_("pointZone"),
+    rangeCellSets_("cellSet"),
+    rangeFaceSets_("faceSet"),
+    rangePointSets_("pointSet")
 {
     if (debug)
     {
@@ -393,16 +399,16 @@ void Foam::vtkPVFoam::updateInfo()
     // time of the vtkDataArraySelection, but the qt/paraview proxy
     // layer doesn't care about that anyhow.
 
-    stringList enabledEntries;
+    HashSet<string> enabled;
     if (!partSelection->GetNumberOfArrays() && !meshPtr_)
     {
-        // enable 'internalMesh' on the first call
-        enabledEntries = { "internalMesh" };
+        // Fake enable 'internalMesh' on the first call
+        enabled = { "internalMesh" };
     }
     else
     {
         // preserve the enabled selections
-        enabledEntries = getSelectedArrayEntries(partSelection);
+        enabled = getSelectedArraySet(partSelection);
     }
 
     // Clear current mesh parts list
@@ -410,21 +416,27 @@ void Foam::vtkPVFoam::updateInfo()
 
     // Update mesh parts list - add Lagrangian at the bottom
     updateInfoInternalMesh(partSelection);
-    updateInfoPatches(partSelection, enabledEntries);
+    updateInfoPatches(partSelection, enabled);
     updateInfoSets(partSelection);
     updateInfoZones(partSelection);
     updateInfoLagrangian(partSelection);
 
-    // restore the enabled selections
-    setSelectedArrayEntries(partSelection, enabledEntries);
-
-    if (meshChanged_)
-    {
-        fieldsChanged_ = true;
-    }
+    // Adjust/restore the enabled selections
+    setSelectedArrayEntries(partSelection, enabled);
 
     // Update volume, point and lagrangian fields
-    updateInfoFields();
+    updateInfoFields<fvPatchField, volMesh>
+    (
+        reader_->GetVolFieldSelection()
+    );
+    updateInfoFields<pointPatchField, pointMesh>
+    (
+        reader_->GetPointFieldSelection()
+    );
+    updateInfoLagrangianFields
+    (
+        reader_->GetLagrangianFieldSelection()
+    );
 
     if (debug)
     {
@@ -433,135 +445,220 @@ void Foam::vtkPVFoam::updateInfo()
 }
 
 
-void Foam::vtkPVFoam::updateFoamMesh()
+void Foam::vtkPVFoam::Update
+(
+    vtkMultiBlockDataSet* output,
+    vtkMultiBlockDataSet* outputLagrangian
+)
 {
     if (debug)
     {
-        Info<< "<beg> updateFoamMesh" << endl;
+        cout<< "<beg> Foam::vtkPVFoam::Update\n";
+        output->Print(cout);
+        if (outputLagrangian) outputLagrangian->Print(cout);
         printMemory();
     }
+    reader_->UpdateProgress(0.1);
 
-    if (!reader_->GetCacheMesh())
-    {
-        delete meshPtr_;
-        meshPtr_ = nullptr;
-    }
+    const int caching = reader_->GetMeshCaching();
+    const bool oldDecomp = decomposePoly_;
+    decomposePoly_ = !reader_->GetUseVTKPolyhedron();
 
-    // Check to see if the OpenFOAM mesh has been created
-    if (!meshPtr_)
+    // Set up mesh parts selection(s)
+    // Update cached, saved, unneed values.
     {
-        if (debug)
+        vtkDataArraySelection* selection = reader_->GetPartSelection();
+        const int n = selection->GetNumberOfArrays();
+
+        selectedPartIds_.clear();
+        HashSet<string> nowActive;
+
+        for (int id=0; id < n; ++id)
         {
-            Info<< "Creating OpenFOAM mesh for region " << meshRegion_
-                << " at time=" << dbPtr_().timeName()
-                << endl;
+            const string str(selection->GetArrayName(id));
+            const bool status = selection->GetArraySetting(id);
+
+            if (status)
+            {
+                selectedPartIds_.set(id, str); // id -> name
+                nowActive.set(str);
+            }
 
+            if (debug > 1)
+            {
+                Info<< "  part[" << id << "] = " << status
+                    << " : " << str << nl;
+            }
         }
 
-        meshPtr_ = new fvMesh
-        (
-            IOobject
-            (
-                meshRegion_,
-                dbPtr_().timeName(),
-                dbPtr_(),
-                IOobject::MUST_READ
-            )
-        );
+        // Dispose of unneeded components
+        cachedVtp_.retain(nowActive);
+        cachedVtu_.retain(nowActive);
 
-        meshChanged_ = true;
-    }
-    else
-    {
-        if (debug)
+        if
+        (
+            !caching
+         || meshState_ == polyMesh::TOPO_CHANGE
+         || meshState_ == polyMesh::TOPO_PATCH_CHANGE
+        )
         {
-            Info<< "Using existing OpenFOAM mesh" << endl;
+            // Eliminate cached values that would be unreliable
+            forAllIters(cachedVtp_, iter)
+            {
+                iter.object().clearGeom();
+                iter.object().clear();
+            }
+            forAllIters(cachedVtu_, iter)
+            {
+                iter.object().clearGeom();
+                iter.object().clear();
+            }
+        }
+        else if (oldDecomp != decomposePoly_)
+        {
+            // poly-decompose changed - dispose of cached values
+            forAllIters(cachedVtu_, iter)
+            {
+                iter.object().clearGeom();
+                iter.object().clear();
+            }
         }
     }
 
-    if (debug)
+    reader_->UpdateProgress(0.15);
+
+    // Update the OpenFOAM mesh
     {
-        Info<< "<end> updateFoamMesh" << endl;
-        printMemory();
-    }
-}
+        if (debug)
+        {
+            Info<< "<beg> updateFoamMesh" << endl;
+            printMemory();
+        }
 
+        if (!caching)
+        {
+            delete meshPtr_;
+            meshPtr_ = nullptr;
+        }
 
-void Foam::vtkPVFoam::Update
-(
-    vtkMultiBlockDataSet* output,
-    vtkMultiBlockDataSet* lagrangianOutput
-)
-{
-    if (debug)
-    {
-        cout<< "<beg> Foam::vtkPVFoam::Update - output with "
-            << output->GetNumberOfBlocks() << " and "
-            << lagrangianOutput->GetNumberOfBlocks() << " blocks\n";
-        output->Print(cout);
-        lagrangianOutput->Print(cout);
-        printMemory();
-    }
-    reader_->UpdateProgress(0.1);
+        // Check to see if the OpenFOAM mesh has been created
+        if (!meshPtr_)
+        {
+            if (debug)
+            {
+                Info<< "Creating OpenFOAM mesh for region " << meshRegion_
+                    << " at time=" << dbPtr_().timeName() << endl;
+            }
 
-    // Set up mesh parts selection(s)
-    updateMeshPartsStatus();
+            meshPtr_ = new fvMesh
+            (
+                IOobject
+                (
+                    meshRegion_,
+                    dbPtr_().timeName(),
+                    dbPtr_(),
+                    IOobject::MUST_READ
+                )
+            );
+
+            meshState_ = polyMesh::TOPO_CHANGE; // New mesh
+        }
+        else
+        {
+            if (debug)
+            {
+                Info<< "Using existing OpenFOAM mesh" << endl;
+            }
+        }
 
-    reader_->UpdateProgress(0.15);
+        if (debug)
+        {
+            Info<< "<end> updateFoamMesh" << endl;
+            printMemory();
+        }
+    }
 
-    // Update the OpenFOAM mesh
-    updateFoamMesh();
     reader_->UpdateProgress(0.4);
 
-    // Convert meshes - start port0 at block=0
-    int blockNo = 0;
-
-    convertMeshVolume(output, blockNo);
-    convertMeshPatches(output, blockNo);
+    convertMeshVolume();
+    convertMeshPatches();
     reader_->UpdateProgress(0.6);
 
     if (reader_->GetIncludeZones())
     {
-        convertMeshCellZones(output, blockNo);
-        convertMeshFaceZones(output, blockNo);
-        convertMeshPointZones(output, blockNo);
+        convertMeshCellZones();
+        convertMeshFaceZones();
+        convertMeshPointZones();
         reader_->UpdateProgress(0.65);
     }
 
     if (reader_->GetIncludeSets())
     {
-        convertMeshCellSets(output, blockNo);
-        convertMeshFaceSets(output, blockNo);
-        convertMeshPointSets(output, blockNo);
+        convertMeshCellSets();
+        convertMeshFaceSets();
+        convertMeshPointSets();
         reader_->UpdateProgress(0.7);
     }
 
-#ifdef VTKPVFOAM_DUALPORT
-    // restart port1 at block=0
-    blockNo = 0;
-#endif
-    convertMeshLagrangian(lagrangianOutput, blockNo);
+    convertMeshLagrangian();
 
     reader_->UpdateProgress(0.8);
 
     // Update fields
-    convertVolFields(output);
-    convertPointFields(output);
-    convertLagrangianFields(lagrangianOutput);
+    convertVolFields();
+    convertPointFields();
+    convertLagrangianFields();
+
+
+    // Assemble multiblock output
+    addOutputBlock(output, cachedVtu_, rangeVolume_, true); // One dataset
+    addOutputBlock(output, cachedVtp_, rangePatches_);
+    addOutputBlock(output, cachedVtu_, rangeCellZones_);
+    addOutputBlock(output, cachedVtp_, rangeFaceZones_);
+    addOutputBlock(output, cachedVtp_, rangePointZones_);
+    addOutputBlock(output, cachedVtu_, rangeCellSets_);
+    addOutputBlock(output, cachedVtp_, rangeFaceSets_);
+    addOutputBlock(output, cachedVtp_, rangePointSets_);
+    addOutputBlock
+    (
+        (outputLagrangian ? outputLagrangian : output),
+        cachedVtp_,
+        rangeLagrangian_
+    );
+
     if (debug)
     {
         Info<< "done reader part" << nl << endl;
     }
     reader_->UpdateProgress(0.95);
 
-    meshChanged_ = fieldsChanged_ = false;
+    meshState_ = polyMesh::UNCHANGED;
+
+    if (caching & 2)
+    {
+        // Suppress caching of Lagrangian since it normally always changes.
+        cachedVtp_.filterKeys
+        (
+            [](const word& k){ return k.startsWith("lagrangian/"); },
+            true // prune
+        );
+    }
+    else
+    {
+        cachedVtp_.clear();
+        cachedVtu_.clear();
+    }
 }
 
 
-void Foam::vtkPVFoam::CleanUp()
+void Foam::vtkPVFoam::UpdateFinalize()
 {
-    // reclaim some memory
-    reduceMemory();
+    if (!reader_->GetMeshCaching())
+    {
+        delete meshPtr_;
+        meshPtr_ = nullptr;
+    }
+
     reader_->UpdateProgress(1.0);
 }
 
@@ -640,20 +737,19 @@ void Foam::vtkPVFoam::renderPatchNames
 {
     // always remove old actors first
 
-    forAll(patchTextActorsPtrs_, patchi)
+    forAll(patchTextActors_, patchi)
     {
-        renderer->RemoveViewProp(patchTextActorsPtrs_[patchi]);
-        patchTextActorsPtrs_[patchi]->Delete();
+        renderer->RemoveViewProp(patchTextActors_[patchi]);
     }
-    patchTextActorsPtrs_.clear();
+    patchTextActors_.clear();
 
     if (show && meshPtr_)
     {
-        // get the display patches, strip off any suffix
+        // get the display patches, strip off any prefix/suffix
         hashedWordList selectedPatches = getSelected
         (
             reader_->GetPartSelection(),
-            arrayRangePatches_
+            rangePatches_
         );
 
         if (selectedPatches.empty())
@@ -750,7 +846,7 @@ void Foam::vtkPVFoam::renderPatchNames
         }
 
         // Set the size of the patch labels to max number of zones
-        patchTextActorsPtrs_.setSize(displayZoneI);
+        patchTextActors_.setSize(displayZoneI);
 
         if (debug)
         {
@@ -783,7 +879,7 @@ void Foam::vtkPVFoam::renderPatchNames
                 }
 
                 // Into a list for later removal
-                patchTextActorsPtrs_[displayZoneI++] = createTextActor
+                patchTextActors_[displayZoneI++] = createTextActor
                 (
                     pp.name(),
                     zoneCentre[patchi][globalZoneI]
@@ -792,13 +888,13 @@ void Foam::vtkPVFoam::renderPatchNames
         }
 
         // Resize the patch names list to the actual number of patch names added
-        patchTextActorsPtrs_.setSize(displayZoneI);
+        patchTextActors_.setSize(displayZoneI);
     }
 
     // Add text to each renderer
-    forAll(patchTextActorsPtrs_, actori)
+    forAll(patchTextActors_, actori)
     {
-        renderer->AddViewProp(patchTextActorsPtrs_[actori]);
+        renderer->AddViewProp(patchTextActors_[actori]);
     }
 }
 
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoam.H b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoam.H
index 3f0a1ad55d700ca1d6df81dbb4bac32e427bbe52..55ec9d73e1e3916ea309d99687662028d039e677 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoam.H
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoam.H
@@ -25,7 +25,25 @@ Class
     Foam::vtkPVFoam
 
 Description
-    Provides a reader interface for OpenFOAM to VTK interaction.
+    The backend for the vtkPVFoamReader reader module -
+    providing a paraview reader interface for OpenFOAM meshes and fields.
+
+    Similar, and sometimes better, functionality may be provided by the
+    native VTK OpenFOAM reader. OpenCFD has recently (2017) been working
+    on improving the native VTK OpenFOAM reader for the benefit of everyone.
+
+    In some areas the reader module lacks compared to the native reader
+    (notably the ability to work on decomosed datasets), but provides
+    additional handling of sets,zones,groups. Some features have also since
+    been adapted to the native reader. Additionally, the reader module
+    provides a useful platform for testing new ideas.
+
+Note
+    The reader module allows two levels of caching. The OpenFOAM fvMesh
+    can be cached in memory, for faster loading of fields. Additionally,
+    the translated VTK geometries are held in a local cache. The cached
+    VTK geometries should incur no additional overhead since they use
+    the VTK reference counting for their storage management.
 
 SourceFiles
     vtkPVFoam.C
@@ -35,7 +53,6 @@ SourceFiles
     vtkPVFoamMeshVolume.C
     vtkPVFoamTemplates.C
     vtkPVFoamUpdateInfo.C
-    vtkPVFoamUtils.C
     vtkPVFoamFieldTemplates.C
     vtkPVFoamUpdateTemplates.C
 
@@ -55,22 +72,24 @@ SourceFiles
 #include "PrimitivePatchInterpolation.H"
 #include "volPointInterpolation.H"
 #include "foamPvCore.H"
+#include "foamVtkMeshMaps.H"
 
-#undef VTKPVFOAM_DUALPORT
+#include "vtkPoints.h"
+#include "vtkPolyData.h"
+#include "vtkSmartPointer.h"
+#include "vtkUnstructuredGrid.h"
 
 // * * * * * * * * * * * * * Forward Declarations  * * * * * * * * * * * * * //
 
+class vtkCellArray;
 class vtkDataArraySelection;
 class vtkDataSet;
 class vtkFloatArray;
-class vtkPoints;
+class vtkIndent;
+class vtkMultiBlockDataSet;
 class vtkPVFoamReader;
 class vtkRenderer;
 class vtkTextActor;
-class vtkMultiBlockDataSet;
-class vtkPolyData;
-class vtkUnstructuredGrid;
-class vtkIndent;
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -83,6 +102,7 @@ class Time;
 class fvMesh;
 class IOobjectList;
 class polyPatch;
+class fvMeshSubset;
 
 template<class Type> class IOField;
 template<class Type> class Field;
@@ -102,66 +122,101 @@ class vtkPVFoam
 
     // Private classes
 
-        //- Bookkeeping for polyhedral cell decomposition
-        //  hide in extra pointMap (cellSet/cellZone) for now
-        class polyDecomp
+        //- Bookkeeping for internal caching.
+        //  Retain an original copy of the geometry as well as a shallow copy
+        //  with the output fields.
+        //  The original copy is reused for different timestep
+        template<class DataType>
+        class foamVtkCaching
         {
-            labelList superCells_;
-            labelList addPointCellLabels_;
-            labelList pointMap_;
-
         public:
+            typedef DataType dataType;
 
-            polyDecomp()
-            {}
+            //- The geometry, without any cell/point data
+            vtkSmartPointer<dataType> vtkgeom;
 
-            //- Label of original cell for decomposed cells
-            labelList& superCells()
-            {
-                return superCells_;
-            }
+            //- The shallow-copy of geometry, plus additional data
+            vtkSmartPointer<dataType> dataset;
 
-            //- Label of original cell for decomposed cells
-            const labelList& superCells() const
+            //- Number of points associated with geometry
+            inline uint64_t nPoints() const
             {
-                return superCells_;
+                return vtkgeom ? vtkgeom->GetNumberOfPoints() : 0;
             }
 
-            //- Cell-centre labels for additional points of decomposed cells
-            labelList& addPointCellLabels()
+            //- Clear geometry and dataset
+            void clearGeom()
             {
-                return addPointCellLabels_;
+                vtkgeom = nullptr;
+                dataset = nullptr;
             }
 
-            //- Cell-centre labels for additional points of decomposed cells
-            const labelList& addPointCellLabels() const
+            //- Return a shallow copy of vtkgeom for manipulation
+            vtkSmartPointer<dataType> getCopy() const
             {
-                return addPointCellLabels_;
+                auto copy = vtkSmartPointer<dataType>::New();
+                copy->ShallowCopy(vtkgeom);
+                return copy;
             }
 
-            //- Point labels for subsetted meshes
-            labelList& pointMap()
+            //- Make a shallow copy of vtkgeom into dataset
+            void reuse()
             {
-                return pointMap_;
+                dataset = vtkSmartPointer<dataType>::New();
+                dataset->ShallowCopy(vtkgeom);
             }
 
-            //- Point labels for subsetted meshes
-            const labelList& pointMap() const
+            //- Set the geometry and make a shallow copy to dataset
+            void set(vtkSmartPointer<dataType> geom)
             {
-                return pointMap_;
+                vtkgeom = geom;
+                reuse();
             }
 
-
-            //- Clear
-            void clear()
+            //- Report basic information to output
+            void PrintSelf(std::ostream& os) const
             {
-                superCells_.clear();
-                addPointCellLabels_.clear();
-                pointMap_.clear();
+                os << "geom" << nl;
+                if (vtkgeom)
+                {
+                    vtkgeom->PrintSelf(std::cout, vtkIndent(2));
+                }
+                else
+                {
+                    os << "nullptr";
+                }
+                os << nl;
+
+                os << "copy" << nl;
+                if (dataset)
+                {
+                    dataset->PrintSelf(std::cout, vtkIndent(2));
+                }
+                else
+                {
+                    os << "nullptr";
+                }
+                os << nl;
             }
         };
 
 
+        //- Bookkeeping for vtkPolyData
+        class foamVtpData
+        :
+            public foamVtkCaching<vtkPolyData>,
+            public foamVtkMeshMaps
+        {};
+
+
+        //- Bookkeeping for vtkUnstructuredGrid
+        class foamVtuData
+        :
+            public foamVtkCaching<vtkUnstructuredGrid>,
+            public foamVtkMeshMaps
+        {};
+
+
     // Private Data
 
         //- Access to the controlling vtkPVFoamReader
@@ -182,72 +237,74 @@ class vtkPVFoam
         //- The time index
         int timeIndex_;
 
+        //- Previous/current decomposition request
+        bool decomposePoly_;
+
         //- Track changes in mesh geometry
-        bool meshChanged_;
+        enum polyMesh::readUpdateState meshState_;
 
-        //- Track changes in fields
-        bool fieldsChanged_;
+        //- The index of selected parts mapped to their names
+        Map<string> selectedPartIds_;
 
-        //- Selected geometrical parts (internalMesh, patches, ...)
-        boolList partStatus_;
+        //- Any information for 2D (VTP) geometries
+        HashTable<foamVtpData, string> cachedVtp_;
 
-        //- Datasets corresponding to selected geometrical pieces
-        //  a negative number indicates that no vtkmesh exists for this piece
-        labelList partDataset_;
+        //- Cell maps and other information for 3D (VTU) geometries
+        HashTable<foamVtuData, string> cachedVtu_;
 
         //- First instance and size of various mesh parts
-        //  used to index into partStatus_ and partDataset_
-        arrayRange arrayRangeVolume_;
-        arrayRange arrayRangePatches_;
-        arrayRange arrayRangeLagrangian_;
-        arrayRange arrayRangeCellZones_;
-        arrayRange arrayRangeFaceZones_;
-        arrayRange arrayRangePointZones_;
-        arrayRange arrayRangeCellSets_;
-        arrayRange arrayRangeFaceSets_;
-        arrayRange arrayRangePointSets_;
-
-        //- Decomposed cells information (mesh regions)
-        //  TODO: regions
-        List<polyDecomp> regionPolyDecomp_;
-
-        //- Decomposed cells information (cellZone meshes)
-        List<polyDecomp> zonePolyDecomp_;
-
-        //- Decomposed cells information (cellSet meshes)
-        List<polyDecomp> csetPolyDecomp_;
+        //  used to index into selectedPartIds and thus indirectly into
+        //  cachedVtp, cachedVtu
+        arrayRange rangeVolume_;
+        arrayRange rangePatches_;
+        arrayRange rangeLagrangian_;
+        arrayRange rangeCellZones_;
+        arrayRange rangeFaceZones_;
+        arrayRange rangePointZones_;
+        arrayRange rangeCellSets_;
+        arrayRange rangeFaceSets_;
+        arrayRange rangePointSets_;
 
         //- List of patch names for rendering to window
-        List<vtkTextActor*> patchTextActorsPtrs_;
+        List<vtkSmartPointer<vtkTextActor>> patchTextActors_;
 
 
     // Private Member Functions
 
-        //- Create a text actor
-        static vtkTextActor* createTextActor(const string& s, const point& pt);
+        template<class Container>
+        bool addOutputBlock
+        (
+            vtkMultiBlockDataSet* output,
+            const HashTable<Container, string>& cache,
+            const arrayRange& selector,
+            const bool singleDataset = false
+        ) const;
+
 
         //- Reset data counters
         void resetCounters();
 
       // Update information helper functions
 
-        //- Update the mesh parts selected in the GUI
-        void updateMeshPartsStatus();
-
         //- Internal mesh info
-        void updateInfoInternalMesh(vtkDataArraySelection*);
+        void updateInfoInternalMesh(vtkDataArraySelection* select);
 
         //- Lagrangian info
-        void updateInfoLagrangian(vtkDataArraySelection*);
+        void updateInfoLagrangian(vtkDataArraySelection* select);
 
-        //- Patch info
-        void updateInfoPatches(vtkDataArraySelection*, stringList&);
+        //- Patch info, modifies enabledEntries
+        void updateInfoPatches
+        (
+            vtkDataArraySelection* select,
+            HashSet<string>& enabledEntries
+        );
 
         //- Set info
-        void updateInfoSets(vtkDataArraySelection*);
+        void updateInfoSets(vtkDataArraySelection* select);
 
         //- Zone info
-        void updateInfoZones(vtkDataArraySelection*);
+        void updateInfoZones(vtkDataArraySelection* select);
+
 
         //- Get non-empty zone names for zoneType from file
         wordList getZoneNames(const word& zoneType) const;
@@ -259,9 +316,6 @@ class vtkPVFoam
             const ZoneMesh<ZoneType, polyMesh>& zmesh
         );
 
-        //- Field (volume, point, lagrangian) info
-        void updateInfoFields();
-
         //- Field info
         template<template<class> class patchType, class meshType>
         void updateInfoFields
@@ -273,105 +327,171 @@ class vtkPVFoam
         void updateInfoLagrangianFields(vtkDataArraySelection* select);
 
 
-      // Update helper functions
-
-        //- OpenFOAM mesh
-        void updateFoamMesh();
-
-        //- Reduce memory footprint after conversion
-        void reduceMemory();
-
-
       // Mesh conversion functions
 
-        //- Convert volume mesh
-        void convertMeshVolume(vtkMultiBlockDataSet* output, int& blockNo);
+        //- Convert InternalMesh
+        void convertMeshVolume();
 
         //- Convert Lagrangian points
-        void convertMeshLagrangian(vtkMultiBlockDataSet* output, int& blockNo);
+        void convertMeshLagrangian();
 
-        //- Convert mesh patches
-        void convertMeshPatches(vtkMultiBlockDataSet* output, int& blockNo);
+        //- Convert mesh patches.
+        //  The additionalIds (cached data) contain the patch Ids.
+        //  There will be several for groups, but only one for regular patches.
+        void convertMeshPatches();
 
         //- Convert cell zones
-        void convertMeshCellZones(vtkMultiBlockDataSet* output, int& blockNo);
-
-        //- Convert face zones
-        void convertMeshFaceZones(vtkMultiBlockDataSet* output, int& blockNo);
-
-        //- Convert point zones
-        void convertMeshPointZones(vtkMultiBlockDataSet* output, int& blockNo);
+        void convertMeshCellZones();
 
         //- Convert cell sets
-        void convertMeshCellSets(vtkMultiBlockDataSet* output, int& blockNo);
+        void convertMeshCellSets();
+
+        //- Convert face zones
+        void convertMeshFaceZones();
 
         //- Convert face sets
-        void convertMeshFaceSets(vtkMultiBlockDataSet* output, int& blockNo);
+        //  The cellMap (cached data) contains the face-labels.
+        void convertMeshFaceSets();
+
+        //- Convert point zones
+        //  The pointMap (cached data) contains the point-labels.
+        void convertMeshPointZones();
 
         //- Convert point sets
-        void convertMeshPointSets(vtkMultiBlockDataSet* output, int& blockNo);
+        //  The pointMap (cached data) contains the point-labels.
+        void convertMeshPointSets();
 
 
       // Add mesh functions
 
-        //- Volume meshes as vtkUnstructuredGrid
-        vtkUnstructuredGrid* volumeVTKMesh
+        //- Generate vtk points for the current mesh points/decomposition
+        static vtkSmartPointer<vtkPoints> movePoints
+        (
+            const fvMesh& mesh,
+            const foamVtuData& vtuData
+        );
+
+        //- Generate vtk points for the current mesh points/decomposition,
+        //  using the provided pointMap
+        static vtkSmartPointer<vtkPoints> movePoints
+        (
+            const fvMesh& mesh,
+            const foamVtuData& vtuData,
+            const labelUList& pointMap
+        );
+
+        //- Volume mesh as vtkUnstructuredGrid
+        static vtkSmartPointer<vtkUnstructuredGrid> volumeVTKMesh
         (
             const fvMesh& mesh,
-            polyDecomp& decompInfo
+            foamVtuData& vtuData,
+            const bool decompPoly
         );
 
+        //- Subsetted mesh as vtkUnstructuredGrid
+        static vtkSmartPointer<vtkUnstructuredGrid> volumeVTKSubsetMesh
+        (
+            const fvMeshSubset& subsetter,
+            foamVtuData& vtuData,
+            const bool decompPoly
+        );
+
+        //- Volume mesh as vtkUnstructuredGrid
+        vtkSmartPointer<vtkUnstructuredGrid> volumeVTKMesh
+        (
+            const fvMesh& mesh,
+            foamVtuData& vtuData
+        ) const;
+
+        //- Subsetted mesh as vtkUnstructuredGrid
+        vtkSmartPointer<vtkUnstructuredGrid> volumeVTKSubsetMesh
+        (
+            const fvMeshSubset& subsetter,
+            foamVtuData& vtuData
+        ) const;
+
         //- Lagrangian positions as vtkPolyData
-        vtkPolyData* lagrangianVTKMesh
+        vtkSmartPointer<vtkPolyData> lagrangianVTKMesh
         (
             const polyMesh& mesh,
             const word& cloudName
+        ) const;
+
+        //- Patch points
+        template<class PatchType>
+        static vtkSmartPointer<vtkPoints> movePatchPoints
+        (
+            const PatchType& p
+        );
+
+        //- Patch faces as vtk-cells
+        template<class PatchType>
+        static vtkSmartPointer<vtkCellArray> patchFacesVTKCells
+        (
+            const PatchType& p
         );
 
         //- Patches (mesh or primitive) as vtkPolyData
         template<class PatchType>
-        vtkPolyData* patchVTKMesh
+        static vtkSmartPointer<vtkPolyData> patchVTKMesh
         (
-            const word& name,
             const PatchType& p
         );
 
 
       // Field conversion functions
 
-        //- Convert Field to VTK field
+        //- Copy list to pre-allocated vtk array.
+        //  \return number of input items copied
+        template<class Type>
+        static label transcribeFloatData
+        (
+            vtkFloatArray* array,
+            const UList<Type>& input,
+            const label start = 0
+        );
+
+        //- Create named field initialized to zero
         template<class Type>
-        vtkFloatArray* convertFieldToVTK
+        static vtkSmartPointer<vtkFloatArray> zeroVTKField
         (
             const word& name,
-            const Field<Type>& fld
+            const label size
         );
 
+        //- Convert float data to VTK field
+        template<class Type>
+        vtkSmartPointer<vtkFloatArray> convertFieldToVTK
+        (
+            const word& name,
+            const UList<Type>& fld
+        ) const;
+
         //- Face set/zone field
         template<class Type>
-        vtkFloatArray* convertFaceFieldToVTK
+        vtkSmartPointer<vtkFloatArray> convertFaceFieldToVTK
         (
             const GeometricField<Type, fvPatchField, volMesh>& fld,
             const labelUList& faceLabels
-        );
+        ) const;
 
         //- Volume field
         template<class Type>
-        vtkFloatArray* convertVolFieldToVTK
+        vtkSmartPointer<vtkFloatArray> convertVolFieldToVTK
         (
             const GeometricField<Type, fvPatchField, volMesh>& fld,
-            const polyDecomp& decompInfo
-        );
+            const foamVtuData& vtuData
+        ) const;
 
 
         //- Convert volume fields
-        void convertVolFields(vtkMultiBlockDataSet* output);
+        void convertVolFields();
 
         //- Convert point fields
-        void convertPointFields(vtkMultiBlockDataSet* output);
+        void convertPointFields();
 
         //- Convert Lagrangian fields
-        void convertLagrangianFields(vtkMultiBlockDataSet* output);
+        void convertLagrangianFields();
 
 
       // Convert OpenFOAM fields
@@ -381,8 +501,7 @@ class vtkPVFoam
         void convertVolField
         (
             const PtrList<patchInterpolator>& patchInterpList,
-            const GeometricField<Type, fvPatchField, volMesh>& fld,
-            vtkMultiBlockDataSet* output
+            const GeometricField<Type, fvPatchField, volMesh>& fld
         );
 
         //- Volume fields - all types
@@ -391,8 +510,7 @@ class vtkPVFoam
         (
             const fvMesh& mesh,
             const PtrList<patchInterpolator>& patchInterpList,
-            const IOobjectList& objects,
-            vtkMultiBlockDataSet* output
+            const IOobjectList& objects
         );
 
         //- Volume internal fields (DimensionedField)- all types
@@ -401,8 +519,7 @@ class vtkPVFoam
         (
             const fvMesh& mesh,
             const PtrList<patchInterpolator>& patchInterpList,
-            const IOobjectList& objects,
-            vtkMultiBlockDataSet* output
+            const IOobjectList& objects
         );
 
         //- Volume field - all selected parts
@@ -411,9 +528,7 @@ class vtkPVFoam
         (
             const GeometricField<Type, fvPatchField, volMesh>& fld,
             autoPtr<GeometricField<Type, pointPatchField, pointMesh>>& ptfPtr,
-            vtkMultiBlockDataSet* output,
-            const arrayRange& range,
-            const List<polyDecomp>& decompLst
+            const arrayRange& range
         );
 
         //- Lagrangian fields - all types
@@ -421,8 +536,7 @@ class vtkPVFoam
         void convertLagrangianFields
         (
             const IOobjectList& objects,
-            vtkMultiBlockDataSet* output,
-            const label datasetNo
+            vtkPolyData* vtkmesh
         );
 
         //- Point fields - all types
@@ -430,8 +544,7 @@ class vtkPVFoam
         void convertPointFields
         (
             const pointMesh& pMesh,
-            const IOobjectList& objects,
-            vtkMultiBlockDataSet* output
+            const IOobjectList& objectst
         );
 
         //- Point field - all selected parts
@@ -439,33 +552,23 @@ class vtkPVFoam
         void convertPointFieldBlock
         (
             const GeometricField<Type, pointPatchField, pointMesh>& pfld,
-            vtkMultiBlockDataSet* output,
-            const arrayRange& range,
-            const List<polyDecomp>& decompLst
+            const arrayRange& range
         );
 
         //- Point field
         template<class Type>
-        void convertPointField
+        vtkSmartPointer<vtkFloatArray> convertPointField
         (
-            vtkUnstructuredGrid* vtkmesh,
             const GeometricField<Type, pointPatchField, pointMesh>& pfld,
             const GeometricField<Type, fvPatchField, volMesh>& vfld,
-            const polyDecomp& decomp
+            const foamVtuData& vtuData
         );
 
 
       // GUI selection helper functions
 
-        //- Only retain specified fields
-        static void pruneObjectList
-        (
-            IOobjectList& objects,
-            const hashedWordList& retain
-        );
-
         //- Get the first word from the reader 'parts' selection
-        word getPartName(const int partId);
+        word getReaderPartName(const int partId) const;
 
 
     // Constructors
@@ -506,19 +609,19 @@ public:
         void Update
         (
             vtkMultiBlockDataSet* output,
-            vtkMultiBlockDataSet* lagrangianOutput
+            vtkMultiBlockDataSet* outputLagrangian
         );
 
-        //- Clean any storage
-        void CleanUp();
+        //- Final part of Update(), after any last minute rendering.
+        void UpdateFinalize();
+
+        //- Add/remove patch names to/from the view
+        void renderPatchNames(vtkRenderer* renderer, const bool show);
 
         //- Return a list of selected times.
         //  Use STL container since these values are used by the plugin
         std::vector<double> findTimes(const bool skipZero = false) const;
 
-        //- Add/remove patch names to/from the view
-        void renderPatchNames(vtkRenderer*, const bool show);
-
         //- Set the runTime to the first plausible request time,
         //  returns the timeIndex
         //  sets to "constant" on error
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamFieldTemplates.C b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamFieldTemplates.C
index c6b9e3b86c211b6bfb3d9a37cff8ac574e8ecd9f..fdab4abe23ba496bce96e8885cb57cc2e3f22ba4 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamFieldTemplates.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamFieldTemplates.C
@@ -30,6 +30,7 @@ InClass
 #define vtkPVFoamFieldTemplates_C
 
 // OpenFOAM includes
+#include "error.H"
 #include "emptyFvPatchField.H"
 #include "wallPolyPatch.H"
 #include "faceSet.H"
@@ -42,6 +43,7 @@ InClass
 #include "vtkFloatArray.h"
 #include "vtkCellData.h"
 #include "vtkPointData.h"
+#include "vtkSmartPointer.h"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 //
@@ -52,8 +54,7 @@ template<class Type>
 void Foam::vtkPVFoam::convertVolField
 (
     const PtrList<patchInterpolator>& patchInterpList,
-    const GeometricField<Type, fvPatchField, volMesh>& fld,
-    vtkMultiBlockDataSet* output
+    const GeometricField<Type, fvPatchField, volMesh>& fld
 )
 {
     const fvMesh& mesh = fld.mesh();
@@ -77,138 +78,129 @@ void Foam::vtkPVFoam::convertVolField
         );
     }
 
-    // Convert activated internalMesh regions
-    convertVolFieldBlock
-    (
-        fld,
-        ptfPtr,
-        output,
-        arrayRangeVolume_,
-        regionPolyDecomp_
-    );
-
-    // Convert activated cellZones
-    convertVolFieldBlock
-    (
-        fld,
-        ptfPtr,
-        output,
-        arrayRangeCellZones_,
-        zonePolyDecomp_
-    );
-
-    // Convert activated cellSets
-    convertVolFieldBlock
-    (
-        fld,
-        ptfPtr,
-        output,
-        arrayRangeCellSets_,
-        csetPolyDecomp_
-    );
-
-
-    //
-    // Convert patches - if activated
-    //
-    for
-    (
-        int partId = arrayRangePatches_.start();
-        partId < arrayRangePatches_.end();
-        ++partId
-    )
-    {
-        const word patchName = getPartName(partId);
-        const label datasetNo = partDataset_[partId];
-        const label patchId = patches.findPatchID(patchName);
+    convertVolFieldBlock(fld, ptfPtr, rangeVolume_);    // internalMesh
+    convertVolFieldBlock(fld, ptfPtr, rangeCellZones_); // cellZones
+    convertVolFieldBlock(fld, ptfPtr, rangeCellSets_);  // cellSets
 
-        if (!partStatus_[partId] || patchId < 0)
+    // Patches - currently skip field conversion for groups
+    for (auto partId : rangePatches_)
+    {
+        if (!selectedPartIds_.found(partId))
         {
             continue;
         }
+        const auto& longName = selectedPartIds_[partId];
 
-        vtkPolyData* vtkmesh = getDataFromBlock<vtkPolyData>
-        (
-            output, arrayRangePatches_, datasetNo
-        );
+        auto iter = cachedVtp_.find(longName);
+        if (!iter.found() || !iter.object().dataset)
+        {
+            // Should not happen, but for safety require a vtk geometry
+            continue;
+        }
+        foamVtpData& vtpData = iter.object();
+        auto dataset = vtpData.dataset;
 
-        if (!vtkmesh)
+        const labelList& patchIds = vtpData.additionalIds();
+        if (patchIds.empty())
         {
             continue;
         }
 
-        const fvPatchField<Type>& ptf = fld.boundaryField()[patchId];
+        // This is slightly roundabout, but we deal with groups and with
+        // single patches.
+        // For groups (spanning several patches) it is fairly messy to
+        // get interpolated point fields. We would need to create a indirect
+        // patch each time to obtain the mesh points. We thus skip that.
+        //
+        // To improve code reuse, we allocate the CellData as a zeroed-field
+        // ahead of time.
 
-        if
+        vtkSmartPointer<vtkFloatArray> cdata = zeroVTKField<Type>
         (
-            isType<emptyFvPatchField<Type>>(ptf)
-         ||
-            (
-                extrapPatch
-             && !polyPatch::constraintType(patches[patchId].type())
-            )
-        )
-        {
-            fvPatch p(ptf.patch().patch(), mesh.boundary());
+            fld.name(),
+            dataset->GetNumberOfPolys()
+        );
 
-            tmp<Field<Type>> tpptf
-            (
-                fvPatchField<Type>(p, fld).patchInternalField()
-            );
+        vtkSmartPointer<vtkFloatArray> pdata;
+        const bool allowPdata = (interpField && patchIds.size() == 1);
 
-            vtkFloatArray* cdata = convertFieldToVTK(fld.name(), tpptf());
-            vtkmesh->GetCellData()->AddArray(cdata);
-            cdata->Delete();
+        label coffset = 0; // the write offset into cell-data
+        for (label patchId : patchIds)
+        {
+            const fvPatchField<Type>& ptf = fld.boundaryField()[patchId];
 
-            if (patchId < patchInterpList.size())
+            if
+            (
+                isType<emptyFvPatchField<Type>>(ptf)
+             ||
+                (
+                    extrapPatch
+                 && !polyPatch::constraintType(patches[patchId].type())
+                )
+            )
             {
-                vtkFloatArray* pdata = convertFieldToVTK
+                fvPatch p(ptf.patch().patch(), mesh.boundary());
+
+                tmp<Field<Type>> tpptf
                 (
-                    fld.name(),
-                    patchInterpList[patchId].faceToPointInterpolate(tpptf)()
+                    fvPatchField<Type>(p, fld).patchInternalField()
                 );
 
-                vtkmesh->GetPointData()->AddArray(pdata);
-                pdata->Delete();
-            }
-        }
-        else
-        {
-            vtkFloatArray* cdata = convertFieldToVTK(fld.name(), ptf);
-            vtkmesh->GetCellData()->AddArray(cdata);
-            cdata->Delete();
+                coffset += transcribeFloatData(cdata, tpptf(), coffset);
 
-            if (patchId < patchInterpList.size())
+                if (allowPdata && patchId < patchInterpList.size())
+                {
+                    pdata = convertFieldToVTK
+                    (
+                        fld.name(),
+                        patchInterpList[patchId].faceToPointInterpolate(tpptf)()
+                    );
+                }
+            }
+            else
             {
-                vtkFloatArray* pdata = convertFieldToVTK
-                (
-                    fld.name(),
-                    patchInterpList[patchId].faceToPointInterpolate(ptf)()
-                );
-
-                vtkmesh->GetPointData()->AddArray(pdata);
-                pdata->Delete();
+                coffset += transcribeFloatData(cdata, ptf, coffset);
+
+                if (allowPdata && patchId < patchInterpList.size())
+                {
+                    pdata = convertFieldToVTK
+                    (
+                        fld.name(),
+                        patchInterpList[patchId].faceToPointInterpolate(ptf)()
+                    );
+                }
             }
         }
+
+        if (cdata)
+        {
+            dataset->GetCellData()->AddArray(cdata);
+        }
+        if (pdata)
+        {
+            dataset->GetPointData()->AddArray(pdata);
+        }
     }
 
-    //
-    // Convert face zones - if activated
-    //
-    for
-    (
-        int partId = arrayRangeFaceZones_.start();
-        partId < arrayRangeFaceZones_.end();
-        ++partId
-    )
+
+    // Face Zones
+    for (auto partId : rangeFaceZones_)
     {
-        const word zoneName = getPartName(partId);
-        const label datasetNo = partDataset_[partId];
+        if (!selectedPartIds_.found(partId))
+        {
+            continue;
+        }
+        const auto& longName = selectedPartIds_[partId];
+        const word zoneName = getFoamName(longName);
 
-        if (!partStatus_[partId] || datasetNo < 0)
+        auto iter = cachedVtp_.find(longName);
+        if (!iter.found() || !iter.object().dataset)
         {
+            // Should not happen, but for safety require a vtk geometry
             continue;
         }
+        foamVtpData& vtpData = iter.object();
+        auto dataset = vtpData.dataset;
 
         const faceZoneMesh& zMesh = mesh.faceZones();
         const label zoneId = zMesh.findZoneID(zoneName);
@@ -218,66 +210,47 @@ void Foam::vtkPVFoam::convertVolField
             continue;
         }
 
-        vtkPolyData* vtkmesh = getDataFromBlock<vtkPolyData>
-        (
-            output, arrayRangeFaceZones_, datasetNo
-        );
-
-        if (vtkmesh)
-        {
-            vtkFloatArray* cdata = convertFaceFieldToVTK
+        vtkSmartPointer<vtkFloatArray> cdata =
+            convertFaceFieldToVTK
             (
                 fld,
                 zMesh[zoneId]
             );
 
-            vtkmesh->GetCellData()->AddArray(cdata);
-            cdata->Delete();
-        }
+        dataset->GetCellData()->AddArray(cdata);
 
-        // TODO: points
+        // TODO: point data
     }
 
-    //
-    // Convert face sets - if activated
-    //
-    for
-    (
-        int partId = arrayRangeFaceSets_.start();
-        partId < arrayRangeFaceSets_.end();
-        ++partId
-    )
-    {
-        const word selectName = getPartName(partId);
-        const label datasetNo = partDataset_[partId];
 
-        if (!partStatus_[partId])
+    // Face Sets
+    for (auto partId : rangeFaceSets_)
+    {
+        if (!selectedPartIds_.found(partId))
         {
             continue;
         }
+        const auto& longName = selectedPartIds_[partId];
+        const word selectName = getFoamName(longName);
 
-        vtkPolyData* vtkmesh = getDataFromBlock<vtkPolyData>
-        (
-            output, arrayRangeFaceSets_, datasetNo
-        );
-
-        if (!vtkmesh)
+        auto iter = cachedVtp_.find(longName);
+        if (!iter.found() || !iter.object().dataset)
         {
+            // Should not happen, but for safety require a vtk geometry
             continue;
         }
+        foamVtpData& vtpData = iter.object();
+        auto dataset = vtpData.dataset;
 
-        const faceSet fSet(mesh, selectName);
-
-        vtkFloatArray* cdata = convertFaceFieldToVTK
+        vtkSmartPointer<vtkFloatArray> cdata = convertFaceFieldToVTK
         (
             fld,
-            fSet.sortedToc()
+            vtpData.cellMap()
         );
 
-        vtkmesh->GetCellData()->AddArray(cdata);
-        cdata->Delete();
+        dataset->GetCellData()->AddArray(cdata);
 
-        // TODO: points
+        // TODO: point data
     }
 }
 
@@ -287,31 +260,24 @@ void Foam::vtkPVFoam::convertVolFields
 (
     const fvMesh& mesh,
     const PtrList<patchInterpolator>& patchInterpList,
-    const IOobjectList& objects,
-    vtkMultiBlockDataSet* output
+    const IOobjectList& objects
 )
 {
-    forAllConstIter(IOobjectList, objects, iter)
+    typedef GeometricField<Type, fvPatchField, volMesh> FieldType;
+
+    forAllConstIters(objects, iter)
     {
-        // restrict to GeometricField<Type, ...>
-        if
-        (
-            iter()->headerClassName()
-         != GeometricField<Type, fvPatchField, volMesh>::typeName
-        )
-        {
-            continue;
-        }
+        // Restrict to GeometricField<Type, ...>
+        const auto& ioobj = *(iter.object());
 
-        // Load field
-        GeometricField<Type, fvPatchField, volMesh> fld
-        (
-            *iter(),
-            mesh
-        );
+        if (ioobj.headerClassName() == FieldType::typeName)
+        {
+            // Load field
+            FieldType fld(ioobj, mesh);
 
-        // Convert
-        convertVolField(patchInterpList, fld, output);
+            // Convert
+            convertVolField(patchInterpList, fld);
+        }
     }
 }
 
@@ -321,26 +287,24 @@ void Foam::vtkPVFoam::convertDimFields
 (
     const fvMesh& mesh,
     const PtrList<patchInterpolator>& patchInterpList,
-    const IOobjectList& objects,
-    vtkMultiBlockDataSet* output
+    const IOobjectList& objects
 )
 {
+    typedef DimensionedField<Type, volMesh> FieldType;
     typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
 
-    forAllConstIter(IOobjectList, objects, iter)
+    forAllConstIters(objects, iter)
     {
-        // restrict to DimensionedField<Type, ...>
-        if
-        (
-            iter()->headerClassName()
-         != DimensionedField<Type, volMesh>::typeName
-        )
+        // Restrict to DimensionedField<Type, ...>
+        const auto& ioobj = *(iter.object());
+
+        if (ioobj.headerClassName() != FieldType::typeName)
         {
             continue;
         }
 
         // Load field
-        DimensionedField<Type, volMesh> dimFld(*iter(), mesh);
+        FieldType dimFld(ioobj, mesh);
 
         // Construct volField with zero-gradient patch fields
 
@@ -372,7 +336,7 @@ void Foam::vtkPVFoam::convertDimFields
         );
         volFld.correctBoundaryConditions();
 
-        convertVolField(patchInterpList, volFld, output);
+        convertVolField(patchInterpList, volFld);
     }
 }
 
@@ -382,70 +346,70 @@ void Foam::vtkPVFoam::convertVolFieldBlock
 (
     const GeometricField<Type, fvPatchField, volMesh>& fld,
     autoPtr<GeometricField<Type, pointPatchField, pointMesh>>& ptfPtr,
-    vtkMultiBlockDataSet* output,
-    const arrayRange& range,
-    const List<polyDecomp>& decompLst
+    const arrayRange& range
 )
 {
-    for (int partId = range.start(); partId < range.end(); ++partId)
+    for (auto partId : range)
     {
-        const label datasetNo = partDataset_[partId];
-
-        if (!partStatus_[partId])
+        if (!selectedPartIds_.found(partId))
         {
             continue;
         }
+        const auto& longName = selectedPartIds_[partId];
 
-        vtkUnstructuredGrid* vtkmesh =
-            getDataFromBlock<vtkUnstructuredGrid>(output, range, datasetNo);
-
-        if (!vtkmesh)
+        auto iter = cachedVtu_.find(longName);
+        if (!iter.found() || !iter.object().dataset)
         {
+            // Should not happen, but for safety require a vtk geometry
             continue;
         }
+        foamVtuData& vtuData = iter.object();
+        auto dataset = vtuData.dataset;
 
-        vtkFloatArray* cdata = convertVolFieldToVTK
+        vtkSmartPointer<vtkFloatArray> cdata = convertVolFieldToVTK
         (
             fld,
-            decompLst[datasetNo]
+            vtuData
         );
-
-        vtkmesh->GetCellData()->AddArray(cdata);
-        cdata->Delete();
+        dataset->GetCellData()->AddArray(cdata);
 
         if (ptfPtr.valid())
         {
-            convertPointField(vtkmesh, ptfPtr(), fld, decompLst[datasetNo]);
+            vtkSmartPointer<vtkFloatArray> pdata = convertPointField
+            (
+                ptfPtr(),
+                fld,
+                vtuData
+            );
+            dataset->GetPointData()->AddArray(pdata);
         }
     }
 }
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 //
 // point-fields
 //
-
 template<class Type>
 void Foam::vtkPVFoam::convertPointFields
 (
     const pointMesh& pMesh,
-    const IOobjectList& objects,
-    vtkMultiBlockDataSet* output
+    const IOobjectList& objects
 )
 {
     const polyMesh& mesh = pMesh.mesh();
-    const polyBoundaryMesh& patches = mesh.boundaryMesh();
 
-    forAllConstIter(IOobjectList, objects, iter)
+    typedef GeometricField<Type, pointPatchField, pointMesh> FieldType;
+
+    forAllConstIters(objects, iter)
     {
-        const word& fieldName = iter()->name();
-        // restrict to this GeometricField<Type, ...>
-        if
-        (
-            iter()->headerClassName()
-         != GeometricField<Type, pointPatchField, pointMesh>::typeName
-        )
+        // Restrict to this GeometricField<Type, ...>
+        const auto& ioobj = *(iter.object());
+
+        const word& fieldName = ioobj.name();
+        if (ioobj.headerClassName() != FieldType::typeName)
         {
             continue;
         }
@@ -455,112 +419,88 @@ void Foam::vtkPVFoam::convertPointFields
             Info<< "convertPointFields : " << fieldName << endl;
         }
 
-        GeometricField<Type, pointPatchField, pointMesh> pfld(*iter(), pMesh);
+        FieldType pfld(ioobj, pMesh);
 
+        convertPointFieldBlock(pfld, rangeVolume_);     // internalMesh
+        convertPointFieldBlock(pfld, rangeCellZones_);  // cellZones
+        convertPointFieldBlock(pfld, rangeCellSets_);   // cellSets
 
-        // Convert activated internalMesh regions
-        convertPointFieldBlock
-        (
-            pfld,
-            output,
-            arrayRangeVolume_,
-            regionPolyDecomp_
-        );
-
-        // Convert activated cellZones
-        convertPointFieldBlock
-        (
-            pfld,
-            output,
-            arrayRangeCellZones_,
-            zonePolyDecomp_
-        );
-
-        // Convert activated cellSets
-        convertPointFieldBlock
-        (
-            pfld,
-            output,
-            arrayRangeCellSets_,
-            csetPolyDecomp_
-        );
-
-
-        //
-        // Convert patches - if activated
-        //
-        for
-        (
-            int partId = arrayRangePatches_.start();
-            partId < arrayRangePatches_.end();
-            ++partId
-        )
+        // Patches - currently skip field conversion for groups
+        for (auto partId : rangePatches_)
         {
-            const word patchName = getPartName(partId);
-            const label datasetNo = partDataset_[partId];
-            const label patchId = patches.findPatchID(patchName);
+            if (!selectedPartIds_.found(partId))
+            {
+                continue;
+            }
+            const auto& longName = selectedPartIds_[partId];
+
+            auto iter = cachedVtp_.find(longName);
+            if (!iter.found() || !iter.object().dataset)
+            {
+                // Should not happen, but for safety require a vtk geometry
+                continue;
+            }
+            foamVtpData& vtpData = iter.object();
+            auto dataset = vtpData.dataset;
 
-            if (!partStatus_[partId] || patchId < 0)
+            const labelList& patchIds = vtpData.additionalIds();
+            if (patchIds.size() != 1)
             {
                 continue;
             }
 
-            vtkPolyData* vtkmesh = getDataFromBlock<vtkPolyData>
+            const label patchId = patchIds[0];
+
+            vtkSmartPointer<vtkFloatArray> pdata = convertFieldToVTK
             (
-                output, arrayRangePatches_, datasetNo
+                fieldName,
+                pfld.boundaryField()[patchId].patchInternalField()()
             );
 
-            if (vtkmesh)
+            dataset->GetPointData()->AddArray(pdata);
+        }
+
+        // Face Zones
+        for (auto partId : rangeFaceZones_)
+        {
+            if (!selectedPartIds_.found(partId))
             {
-                vtkFloatArray* pdata = convertFieldToVTK
-                (
-                    fieldName,
-                    pfld.boundaryField()[patchId].patchInternalField()()
-                );
+                continue;
+            }
+            const auto& longName = selectedPartIds_[partId];
+            const word zoneName = getFoamName(longName);
 
-                vtkmesh->GetPointData()->AddArray(pdata);
-                pdata->Delete();
+            auto iter = cachedVtp_.find(longName);
+            if (!iter.found() || !iter.object().dataset)
+            {
+                // Should not happen, but for safety require a vtk geometry
+                continue;
             }
-        }
+            foamVtpData& vtpData = iter.object();
+            auto dataset = vtpData.dataset;
 
-        //
-        // Convert faceZones - if activated
-        //
-        for
-        (
-            int partId = arrayRangeFaceZones_.start();
-            partId < arrayRangeFaceZones_.end();
-            ++partId
-        )
-        {
-            const word zoneName = getPartName(partId);
-            const label datasetNo = partDataset_[partId];
             const label zoneId = mesh.faceZones().findZoneID(zoneName);
 
-            if (!partStatus_[partId] || zoneId < 0)
+            if (zoneId < 0)
             {
                 continue;
             }
 
-            vtkPolyData* vtkmesh = getDataFromBlock<vtkPolyData>
+            // Extract the field on the zone
+            Field<Type> znfld
             (
-                output, arrayRangeFaceZones_, datasetNo
+                pfld.primitiveField(),
+                mesh.faceZones()[zoneId]().meshPoints()
             );
 
-            if (vtkmesh)
-            {
-                // Extract the field on the zone
-                Field<Type> znfld
+            vtkSmartPointer<vtkFloatArray> pdata =
+                convertFieldToVTK
                 (
-                    pfld.primitiveField(),
-                    mesh.faceZones()[zoneId]().meshPoints()
+                    fieldName,
+                    znfld
                 );
 
-                vtkFloatArray* pdata = convertFieldToVTK(fieldName, znfld);
-
-                vtkmesh->GetPointData()->AddArray(pdata);
-                pdata->Delete();
-            }
+            dataset->GetPointData()->AddArray(pdata);
         }
     }
 }
@@ -570,75 +510,67 @@ template<class Type>
 void Foam::vtkPVFoam::convertPointFieldBlock
 (
     const GeometricField<Type, pointPatchField, pointMesh>& pfld,
-    vtkMultiBlockDataSet* output,
-    const arrayRange& range,
-    const List<polyDecomp>& decompLst
+    const arrayRange& range
 )
 {
-   for (int partId = range.start(); partId < range.end(); ++partId)
-   {
-       const label datasetNo = partDataset_[partId];
-
-       if (!partStatus_[partId])
-       {
-           continue;
-       }
-
-       vtkUnstructuredGrid* vtkmesh = getDataFromBlock<vtkUnstructuredGrid>
-       (
-           output, range, datasetNo
-       );
-
-       if (vtkmesh)
-       {
-           convertPointField
-           (
-               vtkmesh,
-               pfld,
-               GeometricField<Type, fvPatchField, volMesh>::null(),
-               decompLst[datasetNo]
-           );
-       }
-   }
+    for (auto partId : range)
+    {
+        if (!selectedPartIds_.found(partId))
+        {
+            continue;
+        }
+        const auto& longName = selectedPartIds_[partId];
+
+        auto iter = cachedVtu_.find(longName);
+        if (!iter.found() || !iter.object().dataset)
+        {
+            // Should not happen, but for safety require a vtk geometry
+            continue;
+        }
+        foamVtuData& vtuData = iter.object();
+        auto dataset = vtuData.dataset;
+
+        vtkSmartPointer<vtkFloatArray> pdata = convertPointField
+        (
+            pfld,
+            GeometricField<Type, fvPatchField, volMesh>::null(),
+            vtuData
+        );
+
+        dataset->GetPointData()->AddArray(pdata);
+    }
 }
 
 
 template<class Type>
-void Foam::vtkPVFoam::convertPointField
+vtkSmartPointer<vtkFloatArray> Foam::vtkPVFoam::convertPointField
 (
-    vtkUnstructuredGrid* vtkmesh,
     const GeometricField<Type, pointPatchField, pointMesh>& pfld,
     const GeometricField<Type, fvPatchField, volMesh>& vfld,
-    const polyDecomp& decomp
+    const foamVtuData& vtuData
 )
 {
-    if (!vtkmesh)
-    {
-        return;
-    }
-
-    const label nComp = pTraits<Type>::nComponents;
-    const labelUList& addPointCellLabels = decomp.addPointCellLabels();
-    const labelUList& pointMap = decomp.pointMap();
+    const int nComp(pTraits<Type>::nComponents);
+    const labelUList& addPointCellLabels = vtuData.additionalIds();
+    const labelUList& pointMap = vtuData.pointMap();
 
-    // use a pointMap or address directly into mesh
+    // Use a pointMap or address directly into mesh
     const label nPoints = (pointMap.size() ? pointMap.size() : pfld.size());
 
-    vtkFloatArray* fldData = vtkFloatArray::New();
-    fldData->SetNumberOfTuples(nPoints + addPointCellLabels.size());
-    fldData->SetNumberOfComponents(nComp);
-    fldData->Allocate(nComp*(nPoints + addPointCellLabels.size()));
+    auto data = vtkSmartPointer<vtkFloatArray>::New();
+    data->SetNumberOfComponents(nComp);
+    data->SetNumberOfTuples(nPoints + addPointCellLabels.size());
 
     // Note: using the name of the original volField
     // not the name generated by the interpolation "volPointInterpolate(<name>)"
 
-    if (&vfld != &GeometricField<Type, fvPatchField, volMesh>::null())
+    if (notNull(vfld))
     {
-        fldData->SetName(vfld.name().c_str());
+        data->SetName(vfld.name().c_str());
     }
     else
     {
-        fldData->SetName(pfld.name().c_str());
+        data->SetName(pfld.name().c_str());
     }
 
     if (debug)
@@ -652,6 +584,7 @@ void Foam::vtkPVFoam::convertPointField
 
     float vec[nComp];
 
+    label pointi = 0;
     if (pointMap.size())
     {
         forAll(pointMap, i)
@@ -663,7 +596,7 @@ void Foam::vtkPVFoam::convertPointField
             }
             foamPvFields::remapTuple<Type>(vec);
 
-            fldData->InsertTuple(i, vec);
+            data->SetTuple(pointi++, vec);
         }
     }
     else
@@ -677,14 +610,13 @@ void Foam::vtkPVFoam::convertPointField
             }
             foamPvFields::remapTuple<Type>(vec);
 
-            fldData->InsertTuple(i, vec);
+            data->SetTuple(pointi++, vec);
         }
     }
 
-    // continue insertion from here
-    label i = nPoints;
+    // Continue with additional points
 
-    if (&vfld != &GeometricField<Type, fvPatchField, volMesh>::null())
+    if (notNull(vfld))
     {
         forAll(addPointCellLabels, apI)
         {
@@ -695,7 +627,7 @@ void Foam::vtkPVFoam::convertPointField
             }
             foamPvFields::remapTuple<Type>(vec);
 
-            fldData->InsertTuple(i++, vec);
+            data->SetTuple(pointi++, vec);
         }
     }
     else
@@ -709,12 +641,11 @@ void Foam::vtkPVFoam::convertPointField
             }
             foamPvFields::remapTuple<Type>(vec);
 
-            fldData->InsertTuple(i++, vec);
+            data->SetTuple(pointi++, vec);
         }
     }
 
-    vtkmesh->GetPointData()->AddArray(fldData);
-    fldData->Delete();
+    return data;
 }
 
 
@@ -727,28 +658,28 @@ template<class Type>
 void Foam::vtkPVFoam::convertLagrangianFields
 (
     const IOobjectList& objects,
-    vtkMultiBlockDataSet* output,
-    const label datasetNo
+    vtkPolyData* vtkmesh
 )
 {
-    const arrayRange& range = arrayRangeLagrangian_;
-
-    forAllConstIter(IOobjectList, objects, iter)
+    forAllConstIters(objects, iter)
     {
-        // restrict to this IOField<Type>
-        if (iter()->headerClassName() == IOField<Type>::typeName)
+        // Restrict to IOField<Type>
+        const auto& ioobj = *(iter.object());
+
+        if (ioobj.headerClassName() == IOField<Type>::typeName)
         {
-            vtkPolyData* vtkmesh =
-                getDataFromBlock<vtkPolyData>(output, range, datasetNo);
+            IOField<Type> fld(ioobj);
 
-            if (vtkmesh)
-            {
-                IOField<Type> fld(*iter());
+            vtkSmartPointer<vtkFloatArray> data =
+                convertFieldToVTK
+                (
+                    ioobj.name(),
+                    fld
+                );
 
-                vtkFloatArray* fldData = convertFieldToVTK(fld.name(), fld);
-                vtkmesh->GetPointData()->AddArray(fldData);
-                fldData->Delete();
-            }
+            // Provide identical data as cell and as point data
+            vtkmesh->GetCellData()->AddArray(data);
+            vtkmesh->GetPointData()->AddArray(data);
         }
     }
 }
@@ -760,87 +691,160 @@ void Foam::vtkPVFoam::convertLagrangianFields
 //
 
 template<class Type>
-vtkFloatArray* Foam::vtkPVFoam::convertFieldToVTK
+vtkSmartPointer<vtkFloatArray>
+Foam::vtkPVFoam::zeroVTKField
 (
     const word& name,
-    const Field<Type>& fld
+    const label size
 )
 {
-    if (debug)
+    auto data = vtkSmartPointer<vtkFloatArray>::New();
+
+    data->SetName(name.c_str());
+    data->SetNumberOfComponents(int(pTraits<Type>::nComponents));
+    data->SetNumberOfTuples(size);
+
+    data->Fill(0);
+
+    return data;
+}
+
+
+template<class Type>
+Foam::label Foam::vtkPVFoam::transcribeFloatData
+(
+    vtkFloatArray* array,
+    const UList<Type>& input,
+    const label start
+)
+{
+    const int nComp(pTraits<Type>::nComponents);
+
+    if (array->GetNumberOfComponents() != nComp)
     {
-        Info<< "convert Field<" << pTraits<Type>::typeName << "> "
-            << name
-            << " size="  << fld.size()
-            << " nComp=" << label(pTraits<Type>::nComponents) << endl;
+        FatalErrorInFunction
+            << "vtk array '" << array->GetName()
+            << "' has mismatch in number of components for type '"
+            << pTraits<Type>::typeName
+            << "' : target array has " << array->GetNumberOfComponents()
+            << " components instead of " << nComp
+            << endl;
     }
 
-    const label nComp = pTraits<Type>::nComponents;
+    const vtkIdType maxSize = array->GetNumberOfTuples();
+    const vtkIdType endPos = vtkIdType(start) + vtkIdType(input.size());
 
-    vtkFloatArray* fldData = vtkFloatArray::New();
-    fldData->SetNumberOfTuples(fld.size());
-    fldData->SetNumberOfComponents(nComp);
-    fldData->Allocate(nComp*fld.size());
-    fldData->SetName(name.c_str());
+    if (start < 0 || vtkIdType(start) >= maxSize)
+    {
+        WarningInFunction
+            << "vtk array '" << array->GetName()
+            << "' copy with out-of-range (0-" << long(maxSize-1) << ")"
+            << " starting location"
+            << endl;
 
-    float vec[nComp];
-    forAll(fld, i)
+        return 0;
+    }
+    else if (endPos > maxSize)
+    {
+        WarningInFunction
+            << "vtk array '" << array->GetName()
+            << "' copy ends out-of-range (" << long(maxSize) << ")"
+            << " using sizing (start,size) = ("
+            << start << "," << input.size() << ")"
+            << endl;
+
+        return 0;
+    }
+
+    float scratch[nComp];
+    forAll(input, idx)
     {
-        const Type& t = fld[i];
+        const Type& t = input[idx];
         for (direction d=0; d<nComp; ++d)
         {
-            vec[d] = component(t, d);
+            scratch[d] = component(t, d);
         }
-        foamPvFields::remapTuple<Type>(vec);
+        foamPvFields::remapTuple<Type>(scratch);
 
-        fldData->InsertTuple(i, vec);
+        array->SetTuple(start+idx, scratch);
     }
 
-    return fldData;
+    return input.size();
 }
 
 
 template<class Type>
-vtkFloatArray* Foam::vtkPVFoam::convertFaceFieldToVTK
+vtkSmartPointer<vtkFloatArray>
+Foam::vtkPVFoam::convertFieldToVTK
+(
+    const word& name,
+    const UList<Type>& fld
+) const
+{
+    const int nComp(pTraits<Type>::nComponents);
+
+    if (debug)
+    {
+        Info<< "convert UList<" << pTraits<Type>::typeName << "> "
+            << name
+            << " size="  << fld.size()
+            << " nComp=" << nComp << endl;
+    }
+
+    auto data = vtkSmartPointer<vtkFloatArray>::New();
+
+    data->SetName(name.c_str());
+    data->SetNumberOfComponents(nComp);
+    data->SetNumberOfTuples(fld.size());
+
+    transcribeFloatData(data, fld);
+
+    return data;
+}
+
+
+template<class Type>
+vtkSmartPointer<vtkFloatArray>
+Foam::vtkPVFoam::convertFaceFieldToVTK
 (
     const GeometricField<Type, fvPatchField, volMesh>& fld,
     const labelUList& faceLabels
-)
+) const
 {
     if (debug)
     {
         Info<< "convert face field: "
             << fld.name()
             << " size="  << faceLabels.size()
-            << " nComp=" << label(pTraits<Type>::nComponents) << endl;
+            << " nComp=" << int(pTraits<Type>::nComponents) << endl;
     }
 
     const fvMesh& mesh = fld.mesh();
 
-    const label nComp = pTraits<Type>::nComponents;
+    const int nComp(pTraits<Type>::nComponents);
     const label nInternalFaces = mesh.nInternalFaces();
     const labelList& faceOwner = mesh.faceOwner();
     const labelList& faceNeigh = mesh.faceNeighbour();
 
-    vtkFloatArray* fldData = vtkFloatArray::New();
-    fldData->SetNumberOfTuples(faceLabels.size());
-    fldData->SetNumberOfComponents(nComp);
-    fldData->Allocate(nComp*faceLabels.size());
-    fldData->SetName(fld.name().c_str());
+    auto data = vtkSmartPointer<vtkFloatArray>::New();
+    data->SetName(fld.name().c_str());
+    data->SetNumberOfComponents(nComp);
+    data->SetNumberOfTuples(faceLabels.size());
 
-    float vec[nComp];
+    float scratch[nComp];
 
-    // for interior faces: average owner/neighbour
-    // for boundary faces: owner
-    forAll(faceLabels, facei)
+    // Interior faces: average owner/neighbour
+    // Boundary faces: the owner value
+    forAll(faceLabels, idx)
     {
-        const label faceNo = faceLabels[facei];
+        const label faceNo = faceLabels[idx];
         if (faceNo < nInternalFaces)
         {
             Type t = 0.5*(fld[faceOwner[faceNo]] + fld[faceNeigh[faceNo]]);
 
             for (direction d=0; d<nComp; ++d)
             {
-                vec[d] = component(t, d);
+                scratch[d] = component(t, d);
             }
         }
         else
@@ -848,58 +852,58 @@ vtkFloatArray* Foam::vtkPVFoam::convertFaceFieldToVTK
             const Type& t = fld[faceOwner[faceNo]];
             for (direction d=0; d<nComp; ++d)
             {
-                vec[d] = component(t, d);
+                scratch[d] = component(t, d);
             }
         }
-        foamPvFields::remapTuple<Type>(vec);
+        foamPvFields::remapTuple<Type>(scratch);
 
-        fldData->InsertTuple(facei, vec);
+        data->SetTuple(idx, scratch);
     }
 
-    return fldData;
+    return data;
 }
 
 
 template<class Type>
-vtkFloatArray* Foam::vtkPVFoam::convertVolFieldToVTK
+vtkSmartPointer<vtkFloatArray>
+Foam::vtkPVFoam::convertVolFieldToVTK
 (
     const GeometricField<Type, fvPatchField, volMesh>& fld,
-    const polyDecomp& decompInfo
-)
+    const foamVtuData& vtuData
+) const
 {
-    const label nComp = pTraits<Type>::nComponents;
-    const labelList& superCells = decompInfo.superCells();
+    const int nComp(pTraits<Type>::nComponents);
+    const labelUList& cellMap = vtuData.cellMap();
 
-    vtkFloatArray* fldData = vtkFloatArray::New();
-    fldData->SetNumberOfTuples(superCells.size());
-    fldData->SetNumberOfComponents(nComp);
-    fldData->Allocate(nComp*superCells.size());
-    fldData->SetName(fld.name().c_str());
+    auto data = vtkSmartPointer<vtkFloatArray>::New();
+    data->SetName(fld.name().c_str());
+    data->SetNumberOfComponents(nComp);
+    data->SetNumberOfTuples(cellMap.size());
 
     if (debug)
     {
         Info<< "convert volField: "
             << fld.name()
-            << " size=" << superCells.size()
+            << " size=" << cellMap.size()
             << " (" << fld.size() << " + "
-            << (superCells.size() - fld.size())
+            << (cellMap.size() - fld.size())
             << ") nComp=" << nComp << endl;
     }
 
-    float vec[nComp];
-    forAll(superCells, i)
+    float scratch[nComp];
+    forAll(cellMap, idx)
     {
-        const Type& t = fld[superCells[i]];
+        const Type& t = fld[cellMap[idx]];
         for (direction d=0; d<nComp; ++d)
         {
-            vec[d] = component(t, d);
+            scratch[d] = component(t, d);
         }
-        foamPvFields::remapTuple<Type>(vec);
+        foamPvFields::remapTuple<Type>(scratch);
 
-        fldData->InsertTuple(i, vec);
+        data->SetTuple(idx, scratch);
     }
 
-    return fldData;
+    return data;
 }
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamFields.C b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamFields.C
index 880ca89a4fb310b08c879702b1d9c0ff47c298d5..9da212916f2e3ab1d1b0be919c5916f277155b16 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamFields.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamFields.C
@@ -40,32 +40,7 @@ License
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-void Foam::vtkPVFoam::pruneObjectList
-(
-    IOobjectList& objects,
-    const hashedWordList& retain
-)
-{
-    if (retain.empty())
-    {
-        objects.clear();
-    }
-
-    // only retain specified fields
-    forAllIter(IOobjectList, objects, iter)
-    {
-        if (!retain.found(iter()->name()))
-        {
-            objects.erase(iter);
-        }
-    }
-}
-
-
-void Foam::vtkPVFoam::convertVolFields
-(
-    vtkMultiBlockDataSet* output
-)
+void Foam::vtkPVFoam::convertVolFields()
 {
     const fvMesh& mesh = *meshPtr_;
 
@@ -83,7 +58,7 @@ void Foam::vtkPVFoam::convertVolFields
     // Get objects (fields) for this time - only keep selected fields
     // the region name is already in the mesh db
     IOobjectList objects(mesh, dbPtr_().timeName());
-    pruneObjectList(objects, selectedFields);
+    objects.filterKeys(selectedFields);
 
     if (objects.empty())
     {
@@ -92,8 +67,8 @@ void Foam::vtkPVFoam::convertVolFields
 
     if (debug)
     {
-        Info<< "<beg> convert volume fields" << endl;
-        forAllConstIter(IOobjectList, objects, iter)
+        Info<< "<beg> " << FUNCTION_NAME << endl;
+        forAllConstIters(objects, iter)
         {
             Info<< "  " << iter()->name()
                 << " == " << iter()->objectPath() << endl;
@@ -121,30 +96,27 @@ void Foam::vtkPVFoam::convertVolFields
         }
     }
 
-    convertVolFields<scalar>(mesh, interpLst, objects, output);
-    convertVolFields<vector>(mesh, interpLst, objects, output);
-    convertVolFields<sphericalTensor>(mesh, interpLst, objects, output);
-    convertVolFields<symmTensor>(mesh, interpLst, objects, output);
-    convertVolFields<tensor>(mesh, interpLst, objects, output);
+    convertVolFields<scalar>(mesh, interpLst, objects);
+    convertVolFields<vector>(mesh, interpLst, objects);
+    convertVolFields<sphericalTensor>(mesh, interpLst, objects);
+    convertVolFields<symmTensor>(mesh, interpLst, objects);
+    convertVolFields<tensor>(mesh, interpLst, objects);
 
-    convertDimFields<scalar>(mesh, interpLst, objects, output);
-    convertDimFields<vector>(mesh, interpLst, objects, output);
-    convertDimFields<sphericalTensor>(mesh, interpLst, objects, output);
-    convertDimFields<symmTensor>(mesh, interpLst, objects, output);
-    convertDimFields<tensor>(mesh, interpLst, objects, output);
+    convertDimFields<scalar>(mesh, interpLst, objects);
+    convertDimFields<vector>(mesh, interpLst, objects);
+    convertDimFields<sphericalTensor>(mesh, interpLst, objects);
+    convertDimFields<symmTensor>(mesh, interpLst, objects);
+    convertDimFields<tensor>(mesh, interpLst, objects);
 
     if (debug)
     {
-        Info<< "<end> convert volume fields" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
         printMemory();
     }
 }
 
 
-void Foam::vtkPVFoam::convertPointFields
-(
-    vtkMultiBlockDataSet* output
-)
+void Foam::vtkPVFoam::convertPointFields()
 {
     const fvMesh& mesh = *meshPtr_;
 
@@ -165,7 +137,7 @@ void Foam::vtkPVFoam::convertPointFields
     // Get objects (fields) for this time - only keep selected fields
     // the region name is already in the mesh db
     IOobjectList objects(mesh, dbPtr_().timeName());
-    pruneObjectList(objects, selectedFields);
+    objects.filterKeys(selectedFields);
 
     if (objects.empty())
     {
@@ -175,7 +147,7 @@ void Foam::vtkPVFoam::convertPointFields
     if (debug)
     {
         Info<< "<beg> convert volume -> point fields" << endl;
-        forAllConstIter(IOobjectList, objects, iter)
+        forAllConstIters(objects, iter)
         {
             Info<< "  " << iter()->name()
                 << " == " << iter()->objectPath() << endl;
@@ -186,11 +158,11 @@ void Foam::vtkPVFoam::convertPointFields
     // Construct interpolation on the raw mesh
     const pointMesh& pMesh = pointMesh::New(mesh);
 
-    convertPointFields<scalar>(pMesh, objects, output);
-    convertPointFields<vector>(pMesh, objects, output);
-    convertPointFields<sphericalTensor>(pMesh, objects, output);
-    convertPointFields<symmTensor>(pMesh, objects, output);
-    convertPointFields<tensor>(pMesh, objects, output);
+    convertPointFields<scalar>(pMesh, objects);
+    convertPointFields<vector>(pMesh, objects);
+    convertPointFields<sphericalTensor>(pMesh, objects);
+    convertPointFields<symmTensor>(pMesh, objects);
+    convertPointFields<tensor>(pMesh, objects);
 
     if (debug)
     {
@@ -200,12 +172,9 @@ void Foam::vtkPVFoam::convertPointFields
 }
 
 
-void Foam::vtkPVFoam::convertLagrangianFields
-(
-    vtkMultiBlockDataSet* output
-)
+void Foam::vtkPVFoam::convertLagrangianFields()
 {
-    arrayRange& range = arrayRangeLagrangian_;
+    const arrayRange& range = rangeLagrangian_;
     const fvMesh& mesh = *meshPtr_;
 
     hashedWordList selectedFields = getSelected
@@ -220,19 +189,27 @@ void Foam::vtkPVFoam::convertLagrangianFields
 
     if (debug)
     {
-        Info<< "<beg> convert Lagrangian fields" << endl;
+        Info<< "<beg> " << FUNCTION_NAME << endl;
         printMemory();
     }
 
-    for (int partId = range.start(); partId < range.end(); ++partId)
+    for (auto partId : range)
     {
-        const word  cloudName = getPartName(partId);
-        const label datasetNo = partDataset_[partId];
+        if (!selectedPartIds_.found(partId))
+        {
+            continue;
+        }
+
+        const auto& longName = selectedPartIds_[partId];
+        const word cloudName = getFoamName(longName);
 
-        if (!partStatus_[partId] || datasetNo < 0)
+        auto iter = cachedVtp_.find(longName);
+        if (!iter.found() || !iter.object().dataset)
         {
+            // Should not happen, but for safety require a vtk geometry
             continue;
         }
+        auto dataset = iter.object().dataset;
 
         // Get the Lagrangian fields for this time and this cloud
         // but only keep selected fields
@@ -243,7 +220,7 @@ void Foam::vtkPVFoam::convertLagrangianFields
             dbPtr_().timeName(),
             cloud::prefix/cloudName
         );
-        pruneObjectList(objects, selectedFields);
+        objects.filterKeys(selectedFields);
 
         if (objects.empty())
         {
@@ -253,24 +230,24 @@ void Foam::vtkPVFoam::convertLagrangianFields
         if (debug)
         {
             Info<< "converting OpenFOAM lagrangian fields" << endl;
-            forAllConstIter(IOobjectList, objects, iter)
+            forAllConstIters(objects, iter)
             {
                 Info<< "  " << iter()->name()
                     << " == " << iter()->objectPath() << endl;
             }
         }
 
-        convertLagrangianFields<label>(objects, output, datasetNo);
-        convertLagrangianFields<scalar>(objects, output, datasetNo);
-        convertLagrangianFields<vector>(objects, output, datasetNo);
-        convertLagrangianFields<sphericalTensor>(objects, output, datasetNo);
-        convertLagrangianFields<symmTensor>(objects, output, datasetNo);
-        convertLagrangianFields<tensor>(objects, output, datasetNo);
+        convertLagrangianFields<label>(objects, dataset);
+        convertLagrangianFields<scalar>(objects, dataset);
+        convertLagrangianFields<vector>(objects, dataset);
+        convertLagrangianFields<sphericalTensor>(objects, dataset);
+        convertLagrangianFields<symmTensor>(objects, dataset);
+        convertLagrangianFields<tensor>(objects, dataset);
     }
 
     if (debug)
     {
-        Info<< "<end> convert Lagrangian fields" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
         printMemory();
     }
 }
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamMesh.C b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamMesh.C
index 954866c540f4da18a5100a253d87dc73f97eb680..3ddd5d09569a9e533155a441273a2c48999b59b8 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamMesh.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamMesh.C
@@ -38,230 +38,255 @@ License
 #include "vtkMultiBlockDataSet.h"
 #include "vtkPolyData.h"
 #include "vtkUnstructuredGrid.h"
+#include "vtkSmartPointer.h"
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-void Foam::vtkPVFoam::convertMeshVolume
-(
-    vtkMultiBlockDataSet* output,
-    int& blockNo
-)
+void Foam::vtkPVFoam::convertMeshVolume()
 {
-    arrayRange& range = arrayRangeVolume_;
-    range.block(blockNo);      // set output block
-    label datasetNo = 0;       // restart at dataset 0
+    const arrayRange& range = rangeVolume_;
     const fvMesh& mesh = *meshPtr_;
 
-    // resize for decomposed polyhedra
-    regionPolyDecomp_.setSize(range.size());
-
     if (debug)
     {
-        Info<< "<beg> convertMeshVolume" << endl;
+        Info<< "<beg> " << FUNCTION_NAME << endl;
         printMemory();
     }
 
     // Convert the internalMesh
     // this looks like more than one part, but it isn't
-    for (int partId = range.start(); partId < range.end(); ++partId)
+    for (auto partId : range)
     {
-        const word partName = "internalMesh";
-
-        if (!partStatus_[partId])
+        if (selectedPartIds_.found(partId))
         {
-            continue;
-        }
+            const auto& longName = selectedPartIds_[partId];
+            foamVtuData& vtuData = cachedVtu_(longName);
 
-        vtkUnstructuredGrid* vtkmesh = volumeVTKMesh
-        (
-            mesh,
-            regionPolyDecomp_[datasetNo]
-        );
+            vtkSmartPointer<vtkUnstructuredGrid> vtkgeom;
+            if (vtuData.nPoints())
+            {
+                if (meshState_ == polyMesh::UNCHANGED)
+                {
+                    if (debug)
+                    {
+                        Info<< "reuse " << longName << nl;
+                    }
+                    vtuData.reuse(); // reuse
+                    continue;
+                }
+                else if (meshState_ == polyMesh::POINTS_MOVED)
+                {
+                    if (debug)
+                    {
+                        Info<< "move points " << longName << nl;
+                    }
+                    vtkgeom = vtuData.getCopy();
+                    vtkgeom->SetPoints(movePoints(mesh, vtuData));
+                }
+            }
 
-        if (vtkmesh)
-        {
-            addToBlock(output, vtkmesh, range, datasetNo, partName);
-            vtkmesh->Delete();
+            if (!vtkgeom)
+            {
+                // Nothing usable from cache - create new geometry
+                vtkgeom = volumeVTKMesh(mesh, vtuData);
+            }
 
-            partDataset_[partId] = datasetNo++;
+            vtuData.set(vtkgeom);
         }
     }
 
-    // anything added?
-    if (datasetNo)
-    {
-        ++blockNo;
-    }
-
     if (debug)
     {
-        Info<< "<end> convertMeshVolume" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
         printMemory();
     }
 }
 
 
-void Foam::vtkPVFoam::convertMeshLagrangian
-(
-    vtkMultiBlockDataSet* output,
-    int& blockNo
-)
+void Foam::vtkPVFoam::convertMeshLagrangian()
 {
-    arrayRange& range = arrayRangeLagrangian_;
-    range.block(blockNo);      // set output block
-    label datasetNo = 0;       // restart at dataset 0
+    const arrayRange& range = rangeLagrangian_;
     const fvMesh& mesh = *meshPtr_;
 
     if (debug)
     {
-        Info<< "<beg> convertMeshLagrangian" << endl;
+        Info<< "<beg> " << FUNCTION_NAME << endl;
         printMemory();
     }
 
-    for (int partId = range.start(); partId < range.end(); ++partId)
+    for (auto partId : range)
     {
-        const word cloudName = getPartName(partId);
-
-        if (!partStatus_[partId])
-        {
-            continue;
-        }
-
-        vtkPolyData* vtkmesh = lagrangianVTKMesh(mesh, cloudName);
-
-        if (vtkmesh)
+        if (selectedPartIds_.found(partId))
         {
-            addToBlock(output, vtkmesh, range, datasetNo, cloudName);
-            vtkmesh->Delete();
+            const auto& longName = selectedPartIds_[partId];
+            const word cloudName = getFoamName(longName);
 
-            partDataset_[partId] = datasetNo++;
+            // Direct conversion, no caching for Lagrangian
+            cachedVtp_(longName).set
+            (
+                lagrangianVTKMesh(mesh, cloudName)
+            );
         }
     }
 
-    // anything added?
-    if (datasetNo)
-    {
-        ++blockNo;
-    }
-
     if (debug)
     {
-        Info<< "<end> convertMeshLagrangian" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
         printMemory();
     }
 }
 
 
-void Foam::vtkPVFoam::convertMeshPatches
-(
-    vtkMultiBlockDataSet* output,
-    int& blockNo
-)
+void Foam::vtkPVFoam::convertMeshPatches()
 {
-    arrayRange& range = arrayRangePatches_;
-    range.block(blockNo);      // set output block
-    label datasetNo = 0;       // restart at dataset 0
+    const arrayRange& range = rangePatches_;
     const fvMesh& mesh = *meshPtr_;
     const polyBoundaryMesh& patches = mesh.boundaryMesh();
 
     if (debug)
     {
-        Info<< "<beg> convertMeshPatches" << endl;
+        Info<< "<beg> " << FUNCTION_NAME << endl;
         printMemory();
     }
 
-    for (int partId = range.start(); partId < range.end(); ++partId)
+    for (auto partId : range)
     {
-        if (!partStatus_[partId])
+        if (!selectedPartIds_.found(partId))
         {
             continue;
         }
+        const auto& longName = selectedPartIds_[partId];
+        const word partName = getFoamName(longName);
+        foamVtpData& vtpData = cachedVtp_(longName);
 
-        const word patchName = getPartName(partId);
-
-        labelHashSet
-            patchIds(patches.patchSet(List<wordRe>(1, wordRe(patchName))));
-
-        if (debug)
+        vtkSmartPointer<vtkPolyData> vtkgeom;
+        if (vtpData.nPoints())
         {
-            Info<< "Creating VTK mesh for patches [" << patchIds <<"] "
-                << patchName << endl;
-        }
+            if (meshState_ == polyMesh::UNCHANGED)
+            {
+                // Without movement is easy.
+                if (debug)
+                {
+                    Info<< "reuse " << longName << nl;
+                }
+                vtpData.reuse();
+                continue;
+            }
+            else if (meshState_ == polyMesh::POINTS_MOVED)
+            {
+                // Point movement on single patch is OK
 
-        vtkPolyData* vtkmesh = nullptr;
-        if (patchIds.size() == 1)
-        {
-            vtkmesh = patchVTKMesh(patchName, patches[patchIds.begin().key()]);
+                const labelList& patchIds = vtpData.additionalIds();
+                if (patchIds.size() == 1)
+                {
+                    vtkgeom = vtpData.getCopy();
+                    vtkgeom->SetPoints(movePatchPoints(patches[patchIds[0]]));
+                    continue;
+                }
+            }
         }
-        else
+
+        if (longName.startsWith("group/"))
         {
             // Patch group. Collect patch faces.
+
+            vtpData.clear(); // Remove any old mappings
+
+            const labelList& patchIds =
+                patches.groupPatchIDs().lookup(partName, labelList());
+
+            if (debug)
+            {
+                Info<< "Creating VTK mesh for patches [" << patchIds <<"] "
+                    << longName << endl;
+            }
+
+            // Store good patch ids as additionalIds
+            vtpData.additionalIds().reserve(patchIds.size());
+
             label sz = 0;
-            forAllConstIter(labelHashSet, patchIds, iter)
+            for (auto id : patchIds)
             {
-                sz += patches[iter.key()].size();
+                const label n = patches[id].size();
+
+                if (n)
+                {
+                    vtpData.additionalIds().append(id);
+                    sz += n;
+                }
             }
-            labelList faceLabels(sz);
-            sz = 0;
-            forAllConstIter(labelHashSet, patchIds, iter)
+            Foam::sort(vtpData.additionalIds());
+
+            // Temporarily (mis)use cellMap for face labels
+            DynamicList<label>& faceLabels = vtpData.cellMap();
+            faceLabels.reserve(sz);
+
+            for (auto id : vtpData.additionalIds())
             {
-                const polyPatch& pp = patches[iter.key()];
+                const auto& pp = patches[id];
                 forAll(pp, i)
                 {
-                    faceLabels[sz++] = pp.start()+i;
+                    faceLabels.append(pp.start()+i);
                 }
             }
 
-            uindirectPrimitivePatch pp
-            (
-                UIndirectList<face>
+            if (faceLabels.size())
+            {
+                uindirectPrimitivePatch pp
                 (
-                    mesh.faces(),
-                    faceLabels
-                ),
-                mesh.points()
-            );
+                    UIndirectList<face>(mesh.faces(), faceLabels),
+                    mesh.points()
+                );
 
-            vtkmesh = patchVTKMesh(patchName, pp);
-        }
+                vtkgeom = patchVTKMesh(pp);
+            }
 
-        if (vtkmesh)
+            faceLabels.clear();  // Unneeded
+        }
+        else
         {
-            addToBlock(output, vtkmesh, range, datasetNo, patchName);
-            vtkmesh->Delete();
+            vtpData.clear(); // Remove any old mappings
+
+            const label patchId = patches.findPatchID(partName);
 
-            partDataset_[partId] = datasetNo++;
+            if (debug)
+            {
+                Info<< "Creating VTK mesh for patch [" << patchId <<"] "
+                    << partName << endl;
+            }
+
+            if (patchId >= 0)
+            {
+                // Store good patch id as additionalIds
+                vtpData.additionalIds() = {patchId};
+
+                vtkgeom = patchVTKMesh(patches[patchId]);
+            }
         }
-    }
 
-    // anything added?
-    if (datasetNo)
-    {
-        ++blockNo;
+        if (vtkgeom)
+        {
+            vtpData.set(vtkgeom);
+        }
+        else
+        {
+            cachedVtp_.erase(longName);
+        }
     }
 
     if (debug)
     {
-        Info<< "<end> convertMeshPatches" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
         printMemory();
     }
 }
 
 
-void Foam::vtkPVFoam::convertMeshCellZones
-(
-    vtkMultiBlockDataSet* output,
-    int& blockNo
-)
+void Foam::vtkPVFoam::convertMeshCellZones()
 {
-    arrayRange& range = arrayRangeCellZones_;
-    range.block(blockNo);      // set output block
-    label datasetNo = 0;       // restart at dataset 0
+    const arrayRange& range = rangeCellZones_;
     const fvMesh& mesh = *meshPtr_;
 
-    // resize for decomposed polyhedra
-    zonePolyDecomp_.setSize(range.size());
-
     if (range.empty())
     {
         return;
@@ -269,17 +294,23 @@ void Foam::vtkPVFoam::convertMeshCellZones
 
     if (debug)
     {
-        Info<< "<beg> convertMeshCellZones" << endl;
+        Info<< "<beg> " << FUNCTION_NAME << endl;
         printMemory();
     }
 
     const cellZoneMesh& zMesh = mesh.cellZones();
-    for (int partId = range.start(); partId < range.end(); ++partId)
+    for (auto partId : range)
     {
-        const word zoneName = getPartName(partId);
+        if (!selectedPartIds_.found(partId))
+        {
+            continue;
+        }
+
+        const auto& longName = selectedPartIds_[partId];
+        const word zoneName = getFoamName(longName);
         const label  zoneId = zMesh.findZoneID(zoneName);
 
-        if (!partStatus_[partId] || zoneId < 0)
+        if (zoneId < 0)
         {
             continue;
         }
@@ -290,144 +321,129 @@ void Foam::vtkPVFoam::convertMeshCellZones
                 << zoneName << endl;
         }
 
-        fvMeshSubset subsetter(mesh);
-        subsetter.setLargeCellSubset(zMesh[zoneId]);
-
-        vtkUnstructuredGrid* vtkmesh = volumeVTKMesh
-        (
-            subsetter.subMesh(),
-            zonePolyDecomp_[datasetNo]
-        );
+        foamVtuData& vtuData = cachedVtu_(longName);
 
-        if (vtkmesh)
+        vtkSmartPointer<vtkUnstructuredGrid> vtkgeom;
+        if (vtuData.nPoints() && vtuData.pointMap().size())
         {
-            // superCells + addPointCellLabels must contain global cell ids
-            inplaceRenumber
-            (
-                subsetter.cellMap(),
-                zonePolyDecomp_[datasetNo].superCells()
-            );
-            inplaceRenumber
-            (
-                subsetter.cellMap(),
-                zonePolyDecomp_[datasetNo].addPointCellLabels()
-            );
-
-            // copy pointMap as well, otherwise pointFields fail
-            zonePolyDecomp_[datasetNo].pointMap() = subsetter.pointMap();
+            if (meshState_ == polyMesh::UNCHANGED)
+            {
+                if (debug)
+                {
+                    Info<< "reuse " << longName << nl;
+                }
+                vtuData.reuse();
+                continue;
+            }
+            else if (meshState_ == polyMesh::POINTS_MOVED)
+            {
+                if (debug)
+                {
+                    Info<< "move points " << longName << nl;
+                }
+                vtkgeom = vtuData.getCopy();
+                vtkgeom->SetPoints
+                (
+                    movePoints(mesh, vtuData, vtuData.pointMap())
+                );
+            }
+        }
 
-            addToBlock(output, vtkmesh, range, datasetNo, zoneName);
-            vtkmesh->Delete();
+        if (!vtkgeom)
+        {
+            fvMeshSubset subsetter(mesh);
+            subsetter.setLargeCellSubset(zMesh[zoneId]);
 
-            partDataset_[partId] = datasetNo++;
+            vtkgeom = volumeVTKSubsetMesh(subsetter, vtuData);
         }
-    }
 
-    // anything added?
-    if (datasetNo)
-    {
-        ++blockNo;
+        vtuData.set(vtkgeom);
     }
 
     if (debug)
     {
-        Info<< "<end> convertMeshCellZones" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
         printMemory();
     }
 }
 
 
-void Foam::vtkPVFoam::convertMeshCellSets
-(
-    vtkMultiBlockDataSet* output,
-    int& blockNo
-)
+void Foam::vtkPVFoam::convertMeshCellSets()
 {
-    arrayRange& range = arrayRangeCellSets_;
-    range.block(blockNo);      // set output block
-    label datasetNo = 0;       // restart at dataset 0
+    const arrayRange& range = rangeCellSets_;
     const fvMesh& mesh = *meshPtr_;
 
-    // resize for decomposed polyhedra
-    csetPolyDecomp_.setSize(range.size());
-
     if (debug)
     {
-        Info<< "<beg> convertMeshCellSets" << endl;
+        Info<< "<beg> " << FUNCTION_NAME << endl;
         printMemory();
     }
 
-    for (int partId = range.start(); partId < range.end(); ++partId)
+    for (auto partId : range)
     {
-        const word partName = getPartName(partId);
-
-        if (!partStatus_[partId])
+        if (!selectedPartIds_.found(partId))
         {
             continue;
         }
 
+        const auto& longName = selectedPartIds_[partId];
+        const word partName = getFoamName(longName);
+
         if (debug)
         {
             Info<< "Creating VTK mesh for cellSet=" << partName << endl;
         }
 
-        const cellSet cSet(mesh, partName);
-        fvMeshSubset subsetter(mesh);
-        subsetter.setLargeCellSubset(cSet);
+        foamVtuData& vtuData = cachedVtu_(longName);
 
-        vtkUnstructuredGrid* vtkmesh = volumeVTKMesh
-        (
-            subsetter.subMesh(),
-            csetPolyDecomp_[datasetNo]
-        );
-
-        if (vtkmesh)
+        vtkSmartPointer<vtkUnstructuredGrid> vtkgeom;
+        if (vtuData.nPoints() && vtuData.pointMap().size())
         {
-            // superCells + addPointCellLabels must contain global cell ids
-            inplaceRenumber
-            (
-                subsetter.cellMap(),
-                csetPolyDecomp_[datasetNo].superCells()
-            );
-            inplaceRenumber
-            (
-                subsetter.cellMap(),
-                csetPolyDecomp_[datasetNo].addPointCellLabels()
-            );
-
-            // copy pointMap as well, otherwise pointFields fail
-            csetPolyDecomp_[datasetNo].pointMap() = subsetter.pointMap();
+            if (meshState_ == polyMesh::UNCHANGED)
+            {
+                if (debug)
+                {
+                    Info<< "reuse " << longName << nl;
+                }
+                vtuData.reuse();
+                continue;
+            }
+            else if (meshState_ == polyMesh::POINTS_MOVED)
+            {
+                if (debug)
+                {
+                    Info<< "move points " << longName << nl;
+                }
+                vtkgeom = vtuData.getCopy();
+                vtkgeom->SetPoints
+                (
+                    movePoints(mesh, vtuData, vtuData.pointMap())
+                );
+            }
+        }
 
-            addToBlock(output, vtkmesh, range, datasetNo, partName);
-            vtkmesh->Delete();
+        if (!vtkgeom)
+        {
+            fvMeshSubset subsetter(mesh);
+            subsetter.setLargeCellSubset(cellSet(mesh, partName));
 
-            partDataset_[partId] = datasetNo++;
+            vtkgeom = volumeVTKSubsetMesh(subsetter, vtuData);
         }
-    }
 
-    // anything added?
-    if (datasetNo)
-    {
-        ++blockNo;
+        vtuData.set(vtkgeom);
     }
 
     if (debug)
     {
-        Info<< "<end> convertMeshCellSets" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
         printMemory();
     }
 }
 
 
-void Foam::vtkPVFoam::convertMeshFaceZones
-(
-    vtkMultiBlockDataSet* output,
-    int& blockNo
-)
+void Foam::vtkPVFoam::convertMeshFaceZones()
 {
-    arrayRange& range = arrayRangeFaceZones_;
-    range.block(blockNo);      // set output block
-    label datasetNo = 0;       // restart at dataset 0
+    const arrayRange& range = rangeFaceZones_;
     const fvMesh& mesh = *meshPtr_;
 
     if (range.empty())
@@ -437,257 +453,311 @@ void Foam::vtkPVFoam::convertMeshFaceZones
 
     if (debug)
     {
-        Info<< "<beg> convertMeshFaceZones" << endl;
+        Info<< "<beg> " << FUNCTION_NAME << endl;
         printMemory();
     }
 
     const faceZoneMesh& zMesh = mesh.faceZones();
-    for (int partId = range.start(); partId < range.end(); ++partId)
+    for (auto partId : range)
     {
-        const word zoneName = getPartName(partId);
+        if (!selectedPartIds_.found(partId))
+        {
+            continue;
+        }
+
+        const auto& longName = selectedPartIds_[partId];
+        const word zoneName = getFoamName(longName);
         const label  zoneId = zMesh.findZoneID(zoneName);
 
-        if (!partStatus_[partId] || zoneId < 0)
+        if (zoneId < 0)
         {
             continue;
         }
-
         if (debug)
         {
             Info<< "Creating VTKmesh for faceZone[" << zoneId << "] "
                 << zoneName << endl;
         }
 
-        vtkPolyData* vtkmesh = patchVTKMesh(zoneName, zMesh[zoneId]());
+        foamVtpData& vtpData = cachedVtp_(longName);
 
-        if (vtkmesh)
+        vtkSmartPointer<vtkPolyData> vtkgeom;
+        if (vtpData.nPoints())
         {
-            addToBlock(output, vtkmesh, range, datasetNo, zoneName);
-            vtkmesh->Delete();
+            if (meshState_ == polyMesh::UNCHANGED)
+            {
+                // Without movement is easy.
+                if (debug)
+                {
+                    Info<<"reuse " << longName << nl;
+                }
+                vtpData.reuse();
+                continue;
+            }
+            else if (meshState_ == polyMesh::POINTS_MOVED)
+            {
+                // Need point maps etc - not worth it at the moment
+            }
+        }
 
-            partDataset_[partId] = datasetNo++;
+        if (!vtkgeom)
+        {
+            vtpData.clear();  // No additional ids, maps
+
+            const primitiveFacePatch& pp = zMesh[zoneId]();
+            vtkgeom = patchVTKMesh(pp);
         }
-    }
 
-    // anything added?
-    if (datasetNo)
-    {
-        ++blockNo;
+        vtpData.set(vtkgeom);
     }
 
     if (debug)
     {
-        Info<< "<end> convertMeshFaceZones" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
         printMemory();
     }
 }
 
 
-void Foam::vtkPVFoam::convertMeshFaceSets
-(
-    vtkMultiBlockDataSet* output,
-    int& blockNo
-)
+void Foam::vtkPVFoam::convertMeshFaceSets()
 {
-    arrayRange& range = arrayRangeFaceSets_;
-    range.block(blockNo);      // set output block
-    label datasetNo = 0;       // restart at dataset 0
+    const arrayRange& range = rangeFaceSets_;
     const fvMesh& mesh = *meshPtr_;
 
     if (debug)
     {
-        Info<< "<beg> convertMeshFaceSets" << endl;
+        Info<< "<beg> " << FUNCTION_NAME << endl;
         printMemory();
     }
 
-    for (int partId = range.start(); partId < range.end(); ++partId)
+    for (auto partId : range)
     {
-        const word partName = getPartName(partId);
-
-        if (!partStatus_[partId])
+        if (!selectedPartIds_.found(partId))
         {
             continue;
         }
 
+        const auto& longName = selectedPartIds_[partId];
+        const word partName = getFoamName(longName);
+
         if (debug)
         {
             Info<< "Creating VTK mesh for faceSet=" << partName << endl;
         }
 
-        // faces in sorted order for more reliability
-        uindirectPrimitivePatch p
-        (
-            UIndirectList<face>
-            (
-                mesh.faces(),
-                faceSet(mesh, partName).sortedToc()
-            ),
-            mesh.points()
-        );
+        foamVtpData& vtpData = cachedVtp_(longName);
 
-        if (p.empty())
+        vtkSmartPointer<vtkPolyData> vtkgeom;
+        if (vtpData.nPoints())
         {
-            continue;
+            if (meshState_ == polyMesh::UNCHANGED)
+            {
+                // Without movement is easy.
+                if (debug)
+                {
+                    Info<<"reuse " << longName << nl;
+                }
+                vtpData.reuse();
+                continue;
+            }
+            else if (meshState_ == polyMesh::POINTS_MOVED)
+            {
+                // Need point maps etc - not worth it at the moment
+            }
         }
 
-        vtkPolyData* vtkmesh = patchVTKMesh("faceSet:" + partName, p);
-        if (vtkmesh)
+        if (!vtkgeom)
         {
-            addToBlock(output, vtkmesh, range, datasetNo, partName);
-            vtkmesh->Delete();
+            vtpData.clear();  // No other additional ids, maps
 
-            partDataset_[partId] = datasetNo++;
+            // Misuse cellMap for face labels - sorted order for reliability
+            vtpData.cellMap() = faceSet(mesh, partName).sortedToc();
+
+            if (vtpData.cellMap().size())
+            {
+                uindirectPrimitivePatch pp
+                (
+                    UIndirectList<face>(mesh.faces(), vtpData.cellMap()),
+                    mesh.points()
+                );
+
+                vtkgeom = patchVTKMesh(pp);
+            }
         }
-    }
 
-    // anything added?
-    if (datasetNo)
-    {
-        ++blockNo;
+        if (vtkgeom)
+        {
+            vtpData.set(vtkgeom);
+        }
+        else
+        {
+            cachedVtp_.erase(longName);
+        }
     }
 
     if (debug)
     {
-        Info<< "<end> convertMeshFaceSets" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
         printMemory();
     }
 }
 
 
-void Foam::vtkPVFoam::convertMeshPointZones
-(
-    vtkMultiBlockDataSet* output,
-    int& blockNo
-)
+void Foam::vtkPVFoam::convertMeshPointZones()
 {
-    arrayRange& range = arrayRangePointZones_;
-    range.block(blockNo);      // set output block
-    label datasetNo = 0;       // restart at dataset 0
+    const arrayRange& range = rangePointZones_;
     const fvMesh& mesh = *meshPtr_;
 
     if (debug)
     {
-        Info<< "<beg> convertMeshPointZones" << endl;
+        Info<< "<beg> " << FUNCTION_NAME << endl;
         printMemory();
     }
 
     if (range.size())
     {
         const pointZoneMesh& zMesh = mesh.pointZones();
-        for (int partId = range.start(); partId < range.end(); ++partId)
+        for (auto partId : range)
         {
-            word zoneName = getPartName(partId);
-            label zoneId = zMesh.findZoneID(zoneName);
+            if (!selectedPartIds_.found(partId))
+            {
+                continue;
+            }
+
+            const auto& longName = selectedPartIds_[partId];
+            const word zoneName = getFoamName(longName);
+            const label zoneId = zMesh.findZoneID(zoneName);
 
-            if (!partStatus_[partId] || zoneId < 0)
+            if (zoneId < 0)
             {
                 continue;
             }
 
-            const labelUList& pointLabels = zMesh[zoneId];
+            foamVtpData& vtpData = cachedVtp_(longName);
 
-            vtkPoints* vtkpoints = vtkPoints::New();
-            vtkpoints->Allocate(pointLabels.size());
+            vtkSmartPointer<vtkPolyData> vtkgeom;
+            if (vtpData.nPoints() && vtpData.pointMap().size())
+            {
+                if (meshState_ == polyMesh::UNCHANGED)
+                {
+                    if (debug)
+                    {
+                        Info<< "reusing " << longName << nl;
+                    }
+                    vtpData.reuse();
+                    continue;
+                }
+                else if (meshState_ == polyMesh::POINTS_MOVED)
+                {
+                    if (debug)
+                    {
+                        Info<< "move points " << longName << nl;
+                    }
+                    vtkgeom = vtpData.getCopy();
+                }
+            }
 
-            const pointField& meshPoints = mesh.points();
-            forAll(pointLabels, pointi)
+            if (!vtkgeom)
             {
-                vtkpoints->InsertNextPoint(meshPoints[pointLabels[pointi]].v_);
+                // First time, or topo change
+                vtkgeom = vtkSmartPointer<vtkPolyData>::New();
+                vtpData.pointMap() = zMesh[zoneId];
             }
 
-            vtkPolyData* vtkmesh = vtkPolyData::New();
-            vtkmesh->SetPoints(vtkpoints);
-            vtkpoints->Delete();
+            const pointField& points = mesh.points();
+            const labelUList& pointMap = vtpData.pointMap();
 
-            if (vtkmesh)
-            {
-                addToBlock(output, vtkmesh, range, datasetNo, zoneName);
-                vtkmesh->Delete();
+            auto vtkpoints = vtkSmartPointer<vtkPoints>::New();
 
-                partDataset_[partId] = datasetNo++;
+            vtkpoints->SetNumberOfPoints(pointMap.size());
+            forAll(pointMap, pointi)
+            {
+                vtkpoints->SetPoint(pointi, points[pointMap[pointi]].v_);
             }
-        }
-    }
 
-    // anything added?
-    if (datasetNo)
-    {
-        ++blockNo;
+            vtkgeom->SetPoints(vtkpoints);
+            vtpData.set(vtkgeom);
+        }
     }
 
     if (debug)
     {
-        Info<< "<end> convertMeshPointZones" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
         printMemory();
     }
 }
 
 
-
-void Foam::vtkPVFoam::convertMeshPointSets
-(
-    vtkMultiBlockDataSet* output,
-    int& blockNo
-)
+void Foam::vtkPVFoam::convertMeshPointSets()
 {
-    arrayRange& range = arrayRangePointSets_;
-    range.block(blockNo);      // set output block
-    label datasetNo = 0;       // restart at dataset 0
+    const arrayRange& range = rangePointSets_;
     const fvMesh& mesh = *meshPtr_;
 
     if (debug)
     {
-        Info<< "<beg> convertMeshPointSets" << endl;
+        Info<< "<beg> " << FUNCTION_NAME << endl;
         printMemory();
     }
 
-    for (int partId = range.start(); partId < range.end(); ++partId)
+    for (auto partId : range)
     {
-        word partName = getPartName(partId);
-
-        if (!partStatus_[partId])
+        if (!selectedPartIds_.found(partId))
         {
             continue;
         }
 
-        if (debug)
-        {
-            Info<< "Creating VTK mesh for pointSet=" << partName << endl;
-        }
+        const auto& longName = selectedPartIds_[partId];
+        const word partName = getFoamName(longName);
 
-        const pointSet pSet(mesh, partName);
+        foamVtpData& vtpData = cachedVtp_(longName);
 
-        vtkPoints* vtkpoints = vtkPoints::New();
-        vtkpoints->Allocate(pSet.size());
+        vtkSmartPointer<vtkPolyData> vtkgeom;
+        if (vtpData.nPoints() && vtpData.pointMap().size())
+        {
+            if (meshState_ == polyMesh::UNCHANGED)
+            {
+                if (debug)
+                {
+                    Info<< "reusing " << longName << nl;
+                }
+                vtpData.reuse();
+                continue;
+            }
+            else if (meshState_ == polyMesh::POINTS_MOVED)
+            {
+                if (debug)
+                {
+                    Info<< "move points " << longName << nl;
+                }
+                vtkgeom = vtpData.getCopy();
+            }
+        }
 
-        const pointField& meshPoints = mesh.points();
-        forAllConstIter(pointSet, pSet, iter)
+        if (!vtkgeom)
         {
-            vtkpoints->InsertNextPoint(meshPoints[iter.key()].v_);
+            // First time, or topo change
+            vtkgeom = vtkSmartPointer<vtkPolyData>::New();
+            vtpData.pointMap() = pointSet(mesh, partName).sortedToc();
         }
 
-        vtkPolyData* vtkmesh = vtkPolyData::New();
-        vtkmesh->SetPoints(vtkpoints);
-        vtkpoints->Delete();
+        const pointField& points = mesh.points();
+        const labelUList& pointMap = vtpData.pointMap();
 
-        if (vtkmesh)
-        {
-            addToBlock(output, vtkmesh, range, datasetNo, partName);
-            vtkmesh->Delete();
+        auto vtkpoints = vtkSmartPointer<vtkPoints>::New();
 
-            partDataset_[partId] = datasetNo++;
+        vtkpoints->SetNumberOfPoints(pointMap.size());
+        forAll(pointMap, pointi)
+        {
+            vtkpoints->SetPoint(pointi, points[pointMap[pointi]].v_);
         }
-    }
 
-    // anything added?
-    if (datasetNo)
-    {
-        ++blockNo;
+        vtkgeom->SetPoints(vtkpoints);
+        vtpData.set(vtkgeom);
     }
 
     if (debug)
     {
-        Info<< "<end> convertMeshPointSets" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
         printMemory();
     }
 }
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamMeshLagrangian.C b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamMeshLagrangian.C
index 4527d841c56dac7b91639698e968d4527478eeaf..c08e17559c5355fb432600bdbba21d04abdffc1c 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamMeshLagrangian.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamMeshLagrangian.C
@@ -35,16 +35,17 @@ License
 #include "vtkCellArray.h"
 #include "vtkPoints.h"
 #include "vtkPolyData.h"
+#include "vtkSmartPointer.h"
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-vtkPolyData* Foam::vtkPVFoam::lagrangianVTKMesh
+vtkSmartPointer<vtkPolyData> Foam::vtkPVFoam::lagrangianVTKMesh
 (
     const polyMesh& mesh,
     const word& cloudName
-)
+) const
 {
-    vtkPolyData* vtkmesh = nullptr;
+    vtkSmartPointer<vtkPolyData> vtkmesh;
 
     if (debug)
     {
@@ -72,27 +73,19 @@ vtkPolyData* Foam::vtkPVFoam::lagrangianVTKMesh
             Info<< "cloud with " << parcels.size() << " parcels" << endl;
         }
 
-        vtkmesh = vtkPolyData::New();
-        vtkPoints* vtkpoints = vtkPoints::New();
-        vtkCellArray* vtkcells = vtkCellArray::New();
-
-        vtkpoints->Allocate(parcels.size());
-        vtkcells->Allocate(parcels.size());
+        auto vtkpoints = vtkSmartPointer<vtkPoints>::New();
+        vtkpoints->SetNumberOfPoints(parcels.size());
 
         vtkIdType particleId = 0;
-        forAllConstIter(Cloud<passiveParticle>, parcels, iter)
+        forAllConstIters(parcels, iter)
         {
-            vtkpoints->InsertNextPoint(iter().position().v_);
-
-            vtkcells->InsertNextCell(1, &particleId);
-            particleId++;
+            vtkpoints->SetPoint(particleId, iter().position().v_);
+            ++particleId;
         }
 
+        vtkmesh = vtkSmartPointer<vtkPolyData>::New();
         vtkmesh->SetPoints(vtkpoints);
-        vtkpoints->Delete();
-
-        vtkmesh->SetVerts(vtkcells);
-        vtkcells->Delete();
+        vtkmesh->SetVerts(foamPvCore::identityVertices(parcels.size()));
     }
 
     if (debug)
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamMeshVolume.C b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamMeshVolume.C
index 6321e3cdfafa4355be5378d4d16bd423192f1a33..18beae4583e23308ffccc604ece0a8a66191f0d5 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamMeshVolume.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamMeshVolume.C
@@ -28,397 +28,188 @@ License
 
 // OpenFOAM includes
 #include "fvMesh.H"
-#include "cellModeller.H"
+#include "fvMeshSubset.H"
+#include "foamVtkAdaptors.H"
+#include "foamVtuSizing.H"
 
 // VTK includes
-#include "vtkCellArray.h"
-#include "vtkIdTypeArray.h"
 #include "vtkUnstructuredGrid.h"
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-vtkUnstructuredGrid* Foam::vtkPVFoam::volumeVTKMesh
+vtkSmartPointer<vtkPoints> Foam::vtkPVFoam::movePoints
 (
     const fvMesh& mesh,
-    polyDecomp& decompInfo
+    const foamVtuData& vtuData
 )
 {
-    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& tetWedge = *(cellModeller::lookup("tetWedge"));
-    const cellModel& hex = *(cellModeller::lookup("hex"));
+    // Convert OpenFOAM mesh vertices to VTK
+    auto vtkpoints = vtkSmartPointer<vtkPoints>::New();
 
-    vtkUnstructuredGrid* vtkmesh = vtkUnstructuredGrid::New();
+    // Normal points
+    const pointField& points = mesh.points();
 
-    if (debug)
+    // Additional cell centres
+    const labelList& addPoints = vtuData.additionalIds();
+
+    vtkpoints->SetNumberOfPoints(points.size() + addPoints.size());
+
+    // Normal points
+    label pointi = 0;
+    forAll(points, i)
     {
-        Info<< "<beg> volumeVTKMesh" << endl;
-        printMemory();
+        vtkpoints->SetPoint(pointi++, points[i].v_);
+    }
+
+    // Cell centres
+    forAll(addPoints, i)
+    {
+        vtkpoints->SetPoint(pointi++, mesh.C()[addPoints[i]].v_);
     }
 
-    const cellShapeList& cellShapes = mesh.cellShapes();
+    return vtkpoints;
+}
+
 
-    // Number of additional points needed by the decomposition of polyhedra
-    label nAddPoints = 0;
+vtkSmartPointer<vtkPoints> Foam::vtkPVFoam::movePoints
+(
+    const fvMesh& mesh,
+    const foamVtuData& vtuData,
+    const labelUList& pointMap
+)
+{
+    // Convert OpenFOAM mesh vertices to VTK
+    auto vtkpoints = vtkSmartPointer<vtkPoints>::New();
 
-    // Number of additional cells generated by the decomposition of polyhedra
-    label nAddCells = 0;
+    // Normal points
+    const pointField& points = mesh.points();
 
-    // face owner is needed to determine the face orientation
-    const labelList& owner = mesh.faceOwner();
+    // Additional cell centres
+    const labelList& addPoints = vtuData.additionalIds();
 
-    labelList& superCells = decompInfo.superCells();
-    labelList& addPointCellLabels = decompInfo.addPointCellLabels();
+    vtkpoints->SetNumberOfPoints(pointMap.size() + addPoints.size());
 
-    // Scan for cells which need to be decomposed and count additional points
-    // and cells
-    if (!reader_->GetUseVTKPolyhedron())
+    // Normal points
+    label pointi = 0;
+    forAll(pointMap, i)
     {
-        forAll(cellShapes, celli)
-        {
-            const cellModel& model = cellShapes[celli].model();
-
-            if
-            (
-                model != hex
-             && model != wedge
-             && model != prism
-             && model != pyr
-             && model != tet
-             && model != tetWedge
-            )
-            {
-                const cell& cFaces = mesh.cells()[celli];
-
-                forAll(cFaces, cFacei)
-                {
-                    const face& f = mesh.faces()[cFaces[cFacei]];
-
-                    label nQuads = 0;
-                    label nTris = 0;
-                    f.nTrianglesQuads(mesh.points(), nTris, nQuads);
-
-                    nAddCells += nQuads + nTris;
-                }
-
-                nAddCells--;
-                nAddPoints++;
-            }
-        }
+        vtkpoints->SetPoint(pointi++, points[pointMap[i]].v_);
     }
 
-    // Set size of additional point addressing array
-    // (from added point to original cell)
-    addPointCellLabels.setSize(nAddPoints);
-
-    // Set size of additional cells mapping array
-    // (from added cell to original cell)
-
-    superCells.setSize(mesh.nCells() + nAddCells);
+    // Cell centres
+    forAll(addPoints, i)
+    {
+        vtkpoints->SetPoint(pointi++, mesh.C()[addPoints[i]].v_);
+    }
 
-    // Convert OpenFOAM mesh vertices to VTK
-    vtkPoints* vtkpoints = vtkPoints::New();
-    vtkpoints->Allocate(mesh.nPoints() + nAddPoints);
+    return vtkpoints;
+}
 
-    const Foam::pointField& points = mesh.points();
 
-    forAll(points, i)
+vtkSmartPointer<vtkUnstructuredGrid> Foam::vtkPVFoam::volumeVTKMesh
+(
+    const fvMesh& mesh,
+    foamVtuData& vtuData,
+    const bool decompPoly
+)
+{
+    if (debug)
     {
-        vtkpoints->InsertNextPoint(points[i].v_);
+        Info<< "<beg> " << FUNCTION_NAME << endl;
+        printMemory();
     }
 
-    vtkmesh->Allocate(mesh.nCells() + nAddCells);
-
-    // Set counters for additional points and additional cells
-    label addPointi = 0, addCelli = 0;
+    vtk::vtuSizing sizing(mesh, decompPoly);
+
+    auto cellTypes = vtkSmartPointer<vtkUnsignedCharArray>::New();
+
+    auto cells = vtkSmartPointer<vtkCellArray>::New();
+    auto faces = vtkSmartPointer<vtkIdTypeArray>::New();
+
+    auto cellLocations = vtkSmartPointer<vtkIdTypeArray>::New();
+    auto faceLocations = vtkSmartPointer<vtkIdTypeArray>::New();
+
+    UList<uint8_t> cellTypesUL =
+        vtkUList
+        (
+            cellTypes,
+            sizing.nFieldCells()
+        );
+
+    UList<vtkIdType> cellsUL =
+        vtkUList
+        (
+            cells,
+            sizing.nFieldCells(),
+            sizing.sizeInternal(vtk::vtuSizing::slotType::CELLS)
+        );
+
+    UList<vtkIdType> cellLocationsUL =
+        vtkUList
+        (
+            cellLocations,
+            sizing.sizeInternal(vtk::vtuSizing::slotType::CELLS_OFFSETS)
+        );
+
+    UList<vtkIdType> facesUL =
+        vtkUList
+        (
+            faces,
+            sizing.sizeInternal(vtk::vtuSizing::slotType::FACES)
+        );
+
+    UList<vtkIdType> faceLocationsUL =
+        vtkUList
+        (
+            faceLocations,
+            sizing.sizeInternal(vtk::vtuSizing::slotType::FACES_OFFSETS)
+        );
+
+
+    sizing.populateInternal
+    (
+        mesh,
+        cellTypesUL,
+        cellsUL,
+        cellLocationsUL,
+        facesUL,
+        faceLocationsUL,
+        static_cast<foamVtkMeshMaps&>(vtuData)
+    );
+
+    auto vtkmesh = vtkSmartPointer<vtkUnstructuredGrid>::New();
 
-    // Create storage for points - needed for mapping from OpenFOAM to VTK
-    // data types - max 'order' = hex = 8 points
-    vtkIdType nodeIds[8];
-
-    // face-stream for a polyhedral cell
-    // [numFace0Pts, id1, id2, id3, numFace1Pts, id1, id2, id3, ...]
-    DynamicList<vtkIdType> faceStream(256);
+    // Convert OpenFOAM mesh vertices to VTK
+    // - can only do this *after* populating the decompInfo with cell-ids
+    //   for any additional points (ie, mesh cell-centres)
+    vtkmesh->SetPoints(movePoints(mesh, vtuData));
 
-    forAll(cellShapes, celli)
+    if (facesUL.size())
     {
-        const cellShape& cellShape = cellShapes[celli];
-        const cellModel& cellModel = cellShape.model();
-
-        superCells[addCelli++] = celli;
-
-        if (cellModel == tet)
-        {
-            for (int j = 0; j < 4; j++)
-            {
-                nodeIds[j] = cellShape[j];
-            }
-            vtkmesh->InsertNextCell
-            (
-                VTK_TETRA,
-                4,
-                nodeIds
-            );
-        }
-        else if (cellModel == pyr)
-        {
-            for (int j = 0; j < 5; j++)
-            {
-                nodeIds[j] = cellShape[j];
-            }
-            vtkmesh->InsertNextCell
-            (
-                VTK_PYRAMID,
-                5,
-                nodeIds
-            );
-        }
-        else if (cellModel == prism)
-        {
-            // VTK has a different node order for VTK_WEDGE
-            // their triangles point outwards!
-            nodeIds[0] = cellShape[0];
-            nodeIds[1] = cellShape[2];
-            nodeIds[2] = cellShape[1];
-            nodeIds[3] = cellShape[3];
-            nodeIds[4] = cellShape[5];
-            nodeIds[5] = cellShape[4];
-
-            vtkmesh->InsertNextCell
-            (
-                VTK_WEDGE,
-                6,
-                nodeIds
-            );
-        }
-        else if (cellModel == tetWedge && !reader_->GetUseVTKPolyhedron())
-        {
-            // Treat as squeezed prism (VTK_WEDGE)
-
-            nodeIds[0] = cellShape[0];
-            nodeIds[1] = cellShape[2];
-            nodeIds[2] = cellShape[1];
-            nodeIds[3] = cellShape[3];
-            nodeIds[4] = cellShape[4];
-            nodeIds[5] = cellShape[3];
-
-            vtkmesh->InsertNextCell
-            (
-                VTK_WEDGE,
-                6,
-                nodeIds
-            );
-        }
-        else if (cellModel == wedge)
-        {
-            // Treat as squeezed hex
-
-            nodeIds[0] = cellShape[0];
-            nodeIds[1] = cellShape[1];
-            nodeIds[2] = cellShape[2];
-            nodeIds[3] = cellShape[2];
-            nodeIds[4] = cellShape[3];
-            nodeIds[5] = cellShape[4];
-            nodeIds[6] = cellShape[5];
-            nodeIds[7] = cellShape[6];
-
-            vtkmesh->InsertNextCell
-            (
-                VTK_HEXAHEDRON,
-                8,
-                nodeIds
-            );
-        }
-        else if (cellModel == hex)
-        {
-            for (int j = 0; j < 8; j++)
-            {
-                nodeIds[j] = cellShape[j];
-            }
-            vtkmesh->InsertNextCell
-            (
-                VTK_HEXAHEDRON,
-                8,
-                nodeIds
-            );
-        }
-        else if (reader_->GetUseVTKPolyhedron())
-        {
-            // Polyhedral cell - use VTK_POLYHEDRON
-            const labelList& cFaces = mesh.cells()[celli];
-
-            vtkIdType nFaces = cFaces.size();
-            vtkIdType nLabels = nFaces;
-
-            // count size for face stream
-            forAll(cFaces, cFacei)
-            {
-                const face& f = mesh.faces()[cFaces[cFacei]];
-                nLabels += f.size();
-            }
-
-            // build face-stream
-            // [numFace0Pts, id1, id2, id3, numFace1Pts, id1, id2, id3, ...]
-            // point Ids are global
-            faceStream.clear();
-            faceStream.reserve(nLabels + nFaces);
-
-            forAll(cFaces, cFacei)
-            {
-                const face& f = mesh.faces()[cFaces[cFacei]];
-                const bool isOwner = (owner[cFaces[cFacei]] == celli);
-                const label nFacePoints = f.size();
-
-                // number of labels for this face
-                faceStream.append(nFacePoints);
-
-                if (isOwner)
-                {
-                    forAll(f, fp)
-                    {
-                        faceStream.append(f[fp]);
-                    }
-                }
-                else
-                {
-                    // fairly immaterial if we reverse the list
-                    // or use face::reverseFace()
-                    forAllReverse(f, fp)
-                    {
-                        faceStream.append(f[fp]);
-                    }
-                }
-            }
-
-            vtkmesh->InsertNextCell(VTK_POLYHEDRON, nFaces, faceStream.data());
-        }
-        else
-        {
-            // Polyhedral cell. Decompose into tets + prisms.
-
-            // Mapping from additional point to cell
-            addPointCellLabels[addPointi] = celli;
-
-            // The new vertex from the cell-centre
-            const label newVertexLabel = mesh.nPoints() + addPointi;
-            vtkpoints->InsertNextPoint(mesh.C()[celli].v_);
-
-            // Whether to insert cell in place of original or not.
-            bool substituteCell = true;
-
-            const labelList& cFaces = mesh.cells()[celli];
-            forAll(cFaces, cFacei)
-            {
-                const face& f = mesh.faces()[cFaces[cFacei]];
-                const bool isOwner = (owner[cFaces[cFacei]] == celli);
-
-                // Number of triangles and quads in decomposition
-                label nTris = 0;
-                label nQuads = 0;
-                f.nTrianglesQuads(mesh.points(), nTris, nQuads);
-
-                // Do actual decomposition into triFcs and quadFcs.
-                faceList triFcs(nTris);
-                faceList quadFcs(nQuads);
-                label trii = 0;
-                label quadi = 0;
-                f.trianglesQuads(mesh.points(), trii, quadi, triFcs, quadFcs);
-
-                forAll(quadFcs, quadI)
-                {
-                    if (substituteCell)
-                    {
-                        substituteCell = false;
-                    }
-                    else
-                    {
-                        superCells[addCelli++] = celli;
-                    }
-
-                    const face& quad = quadFcs[quadI];
-
-                    // Ensure we have the correct orientation for the
-                    // base of the primitive cell shape.
-                    // If the cell is face owner, the orientation needs to be
-                    // flipped.
-                    // At the moment, VTK doesn't actually seem to care if
-                    // negative cells are defined, but we'll do it anyhow
-                    // (for safety).
-                    if (isOwner)
-                    {
-                        nodeIds[0] = quad[3];
-                        nodeIds[1] = quad[2];
-                        nodeIds[2] = quad[1];
-                        nodeIds[3] = quad[0];
-                    }
-                    else
-                    {
-                        nodeIds[0] = quad[0];
-                        nodeIds[1] = quad[1];
-                        nodeIds[2] = quad[2];
-                        nodeIds[3] = quad[3];
-                    }
-                    nodeIds[4] = newVertexLabel;
-                    vtkmesh->InsertNextCell
-                    (
-                        VTK_PYRAMID,
-                        5,
-                        nodeIds
-                    );
-                }
-
-                forAll(triFcs, triI)
-                {
-                    if (substituteCell)
-                    {
-                        substituteCell = false;
-                    }
-                    else
-                    {
-                        superCells[addCelli++] = celli;
-                    }
-
-                    const face& tri = triFcs[triI];
-
-                    // See note above about the orientation.
-                    if (isOwner)
-                    {
-                        nodeIds[0] = tri[2];
-                        nodeIds[1] = tri[1];
-                        nodeIds[2] = tri[0];
-                    }
-                    else
-                    {
-                        nodeIds[0] = tri[0];
-                        nodeIds[1] = tri[1];
-                        nodeIds[2] = tri[2];
-                    }
-                    nodeIds[3] = newVertexLabel;
-
-                    vtkmesh->InsertNextCell
-                    (
-                        VTK_TETRA,
-                        4,
-                        nodeIds
-                    );
-                }
-            }
-
-            addPointi++;
-        }
+        vtkmesh->SetCells
+        (
+            cellTypes,
+            cellLocations,
+            cells,
+            faceLocations,
+            faces
+        );
+    }
+    else
+    {
+        vtkmesh->SetCells
+        (
+            cellTypes,
+            cellLocations,
+            cells,
+            nullptr,
+            nullptr
+        );
     }
-
-    vtkmesh->SetPoints(vtkpoints);
-    vtkpoints->Delete();
 
     if (debug)
     {
-        Info<<"nCells=" << mesh.nCells() <<" nPoints=" << mesh.nPoints()
-            <<" nAddCells=" << nAddCells <<" nAddPoints=" << nAddPoints
-            << nl
-            << "<end> volumeVTKMesh" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
         printMemory();
     }
 
@@ -426,4 +217,48 @@ vtkUnstructuredGrid* Foam::vtkPVFoam::volumeVTKMesh
 }
 
 
+vtkSmartPointer<vtkUnstructuredGrid> Foam::vtkPVFoam::volumeVTKSubsetMesh
+(
+    const fvMeshSubset& subsetter,
+    foamVtuData& vtuData,
+    const bool decompPoly
+)
+{
+    vtkSmartPointer<vtkUnstructuredGrid> vtkmesh = volumeVTKMesh
+    (
+        subsetter.subMesh(),
+        vtuData,
+        decompPoly
+    );
+
+    // Convert cellMap, addPointCellLabels to global cell ids
+    vtuData.renumberCells(subsetter.cellMap());
+
+    // Copy pointMap as well, otherwise pointFields fail
+    vtuData.pointMap() = subsetter.pointMap();
+
+    return vtkmesh;
+}
+
+
+vtkSmartPointer<vtkUnstructuredGrid> Foam::vtkPVFoam::volumeVTKMesh
+(
+    const fvMesh& mesh,
+    foamVtuData& vtuData
+) const
+{
+    return volumeVTKMesh(mesh, vtuData, this->decomposePoly_);
+}
+
+
+vtkSmartPointer<vtkUnstructuredGrid> Foam::vtkPVFoam::volumeVTKSubsetMesh
+(
+    const fvMeshSubset& subsetter,
+    foamVtuData& vtuData
+) const
+{
+    return volumeVTKSubsetMesh(subsetter, vtuData, this->decomposePoly_);
+}
+
+
 // ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamTemplates.C b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamTemplates.C
index 388f1bb79404b7dc0f3bd954c513115a6e886af4..ec64378d2f37b454211a0f009b086e4329a92741 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamTemplates.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamTemplates.C
@@ -28,67 +28,91 @@ License
 // OpenFOAM includes
 #include "polyPatch.H"
 #include "primitivePatch.H"
+#include "foamVtkAdaptors.H"
 
 // VTK includes
 #include "vtkCellArray.h"
 #include "vtkPoints.h"
 #include "vtkPolyData.h"
+#include "vtkSmartPointer.h"
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
 template<class PatchType>
-vtkPolyData* Foam::vtkPVFoam::patchVTKMesh
+vtkSmartPointer<vtkPoints> Foam::vtkPVFoam::movePatchPoints
 (
-    const word& name,
     const PatchType& p
 )
 {
-    vtkPolyData* vtkmesh = vtkPolyData::New();
+    // Convert OpenFOAM mesh vertices to VTK
+    const pointField& points = p.localPoints();
+
+    auto vtkpoints = vtkSmartPointer<vtkPoints>::New();
 
-    if (debug)
+    vtkpoints->SetNumberOfPoints(points.size());
+    forAll(points, i)
     {
-        Info<< "<beg> patchVTKMesh - " << name << endl;
-        printMemory();
+        vtkpoints->SetPoint(i, points[i].v_);
     }
 
-    // Convert OpenFOAM mesh vertices to VTK
-    const Foam::pointField& points = p.localPoints();
+    return vtkpoints;
+}
 
-    vtkPoints* vtkpoints = vtkPoints::New();
-    vtkpoints->Allocate(points.size());
-    forAll(points, i)
+
+template<class PatchType>
+vtkSmartPointer<vtkCellArray> Foam::vtkPVFoam::patchFacesVTKCells
+(
+    const PatchType& p
+)
+{
+    // Faces as polygons
+    const faceList& faces = p.localFaces();
+
+    label nAlloc = faces.size();
+    forAll(faces, facei)
     {
-        vtkpoints->InsertNextPoint(points[i].v_);
+        nAlloc += faces[facei].size();
     }
 
-    vtkmesh->SetPoints(vtkpoints);
-    vtkpoints->Delete();
+    auto cells = vtkSmartPointer<vtkCellArray>::New();
 
-    // Add faces as polygons
-    const faceList& faces = p.localFaces();
+    UList<vtkIdType> cellsUL =
+        vtkUList
+        (
+            cells,
+            faces.size(),
+            nAlloc
+        );
 
-    vtkCellArray* vtkcells = vtkCellArray::New();
-    vtkcells->Allocate(faces.size());
+    // Cell connectivity for polygons
+    // [size, verts..., size, verts... ]
+    label idx = 0;
     forAll(faces, facei)
     {
         const face& f = faces[facei];
-        vtkIdType nodeIds[f.size()];
+
+        cellsUL[idx++] = f.size();
 
         forAll(f, fp)
         {
-            nodeIds[fp] = f[fp];
+            cellsUL[idx++] = f[fp];
         }
-        vtkcells->InsertNextCell(f.size(), nodeIds);
     }
 
-    vtkmesh->SetPolys(vtkcells);
-    vtkcells->Delete();
+    return cells;
+}
 
-    if (debug)
-    {
-        Info<< "<end> patchVTKMesh - " << name << endl;
-        printMemory();
-    }
+
+template<class PatchType>
+vtkSmartPointer<vtkPolyData> Foam::vtkPVFoam::patchVTKMesh
+(
+    const PatchType& p
+)
+{
+    auto vtkmesh = vtkSmartPointer<vtkPolyData>::New();
+
+    vtkmesh->SetPoints(movePatchPoints(p));
+    vtkmesh->SetPolys(patchFacesVTKCells(p));
 
     return vtkmesh;
 }
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamUpdateInfo.C b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamUpdateInfo.C
index 52030e9c81028cc99803b5967695cb830f5094ab..f71354aaa1d390b33e64099f617712c32533e6a8 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamUpdateInfo.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamUpdateInfo.C
@@ -39,10 +39,6 @@ License
 // VTK includes
 #include "vtkDataArraySelection.h"
 
-// Templates (only needed here)
-#include "vtkPVFoamUpdateTemplates.C"
-
-
 // * * * * * * * * * * * * * * * Private Classes * * * * * * * * * * * * * * //
 
 namespace Foam
@@ -89,11 +85,11 @@ Foam::wordList Foam::vtkPVFoam::getZoneNames
     wordList names(zmesh.size());
     label nZone = 0;
 
-    forAll(zmesh, zoneI)
+    forAll(zmesh, zonei)
     {
-        if (!zmesh[zoneI].empty())
+        if (!zmesh[zonei].empty())
         {
-            names[nZone++] = zmesh[zoneI].name();
+            names[nZone++] = zmesh[zonei].name();
         }
     }
     names.setSize(nZone);
@@ -128,9 +124,9 @@ Foam::wordList Foam::vtkPVFoam::getZoneNames(const word& zoneType) const
         zonesEntries zones(ioObj);
 
         names.setSize(zones.size());
-        forAll(zones, zoneI)
+        forAll(zones, zonei)
         {
-            names[zoneI] = zones[zoneI].keyword();
+            names[zonei] = zones[zonei].keyword();
         }
     }
 
@@ -140,7 +136,7 @@ Foam::wordList Foam::vtkPVFoam::getZoneNames(const word& zoneType) const
 
 void Foam::vtkPVFoam::updateInfoInternalMesh
 (
-    vtkDataArraySelection* arraySelection
+    vtkDataArraySelection* select
 )
 {
     if (debug)
@@ -150,12 +146,8 @@ void Foam::vtkPVFoam::updateInfoInternalMesh
 
     // Determine mesh parts (internalMesh, patches...)
     //- Add internal mesh as first entry
-    arrayRangeVolume_.reset(arraySelection->GetNumberOfArrays());
-    arraySelection->AddArray
-    (
-        "internalMesh"
-    );
-    arrayRangeVolume_ += 1;
+    rangeVolume_.reset(select->GetNumberOfArrays(), 1);
+    select->AddArray("internalMesh");
 
     if (debug)
     {
@@ -166,16 +158,15 @@ void Foam::vtkPVFoam::updateInfoInternalMesh
 
 void Foam::vtkPVFoam::updateInfoLagrangian
 (
-    vtkDataArraySelection* arraySelection
+    vtkDataArraySelection* select
 )
 {
     if (debug)
     {
-        Info<< "<beg> updateInfoLagrangian" << nl
+        Info<< "<beg> " << FUNCTION_NAME << nl
             << "    " << dbPtr_->timePath()/cloud::prefix << endl;
     }
 
-
     // use the db directly since this might be called without a mesh,
     // but the region must get added back in
     fileName lagrangianPrefix(cloud::prefix);
@@ -190,96 +181,101 @@ void Foam::vtkPVFoam::updateInfoLagrangian
         readDir(dbPtr_->timePath()/lagrangianPrefix, fileName::DIRECTORY)
     );
 
-    arrayRangeLagrangian_.reset(arraySelection->GetNumberOfArrays());
-
-    int nClouds = 0;
-    forAll(cloudDirs, cloudI)
+    rangeLagrangian_.reset(select->GetNumberOfArrays());
+    forAll(cloudDirs, cloudi)
     {
         // Add cloud to GUI list
-        arraySelection->AddArray
+        select->AddArray
         (
-            (cloudDirs[cloudI] + " - lagrangian").c_str()
+            ("lagrangian/" + cloudDirs[cloudi]).c_str()
         );
-
-        ++nClouds;
+        ++rangeLagrangian_;
     }
-    arrayRangeLagrangian_ += nClouds;
 
     if (debug)
     {
-        Info<< "<end> updateInfoLagrangian" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
     }
 }
 
 
 void Foam::vtkPVFoam::updateInfoPatches
 (
-    vtkDataArraySelection* arraySelection,
-    stringList& enabledEntries
+    vtkDataArraySelection* select,
+    HashSet<string>& enabledEntries
 )
 {
     if (debug)
     {
-        Info<< "<beg> updateInfoPatches"
+        Info<< "<beg> " << FUNCTION_NAME
             << " [meshPtr=" << (meshPtr_ ? "set" : "null") << "]" << endl;
     }
 
+    rangePatches_.reset(select->GetNumberOfArrays());
 
-    HashSet<string> enabledEntriesSet(enabledEntries);
-
-    arrayRangePatches_.reset(arraySelection->GetNumberOfArrays());
-
-    int nPatches = 0;
     if (meshPtr_)
     {
         const polyBoundaryMesh& patches = meshPtr_->boundaryMesh();
         const HashTable<labelList>& groups = patches.groupPatchIDs();
-        const wordList allPatchNames = patches.names();
+        DynamicList<string> displayNames(groups.size());
 
-        // Add patch groups
-        // ~~~~~~~~~~~~~~~~
+        // Add (non-zero) patch groups to the list of mesh parts
+        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
         forAllConstIters(groups, iter)
         {
-            const word& groupName = iter.key();
-            const labelList& patchIDs = iter.object();
+            const auto& groupName = iter.key();
+            const auto& patchIDs  = iter.object();
 
             label nFaces = 0;
-            forAll(patchIDs, i)
+            for (auto patchId : patchIDs)
             {
-                nFaces += patches[patchIDs[i]].size();
+                nFaces += patches[patchId].size();
             }
 
-            // Valid patch if nFace > 0 - add patch to GUI list
-            if (nFaces)
+            if (!nFaces)
             {
-                string vtkGrpName = groupName + " - group";
-                arraySelection->AddArray(vtkGrpName.c_str());
+                // Skip if group has no faces
+                continue;
+            }
 
-                ++nPatches;
+            // Valid patch if nFace > 0 - add patch to GUI list
+            const string dpyName = "group/" + groupName;
+            displayNames.append(dpyName);
 
-                if (enabledEntriesSet.found(vtkGrpName))
+            // Optionally replace group with patch name selections
+            // - must remove the group from the select itself, otherwise
+            //   it can toggle on, but not toggle off very well
+            if
+            (
+                !reader_->GetShowGroupsOnly()
+             && enabledEntries.erase(dpyName)
+            )
+            {
+                for (auto patchId : patchIDs)
                 {
-                    if (!reader_->GetShowGroupsOnly())
+                    const polyPatch& pp = patches[patchId];
+                    if (pp.size())
                     {
-                        enabledEntriesSet.erase(vtkGrpName);
-                        forAll(patchIDs, i)
-                        {
-                            const polyPatch& pp = patches[patchIDs[i]];
-                            if (pp.size())
-                            {
-                                string vtkPatchName = pp.name() + " - patch";
-                                enabledEntriesSet.insert(vtkPatchName);
-                            }
-                        }
+                        enabledEntries.insert
+                        (
+                            "patch/" + pp.name()
+                        );
                     }
                 }
             }
         }
 
+        // Sort group names
+        Foam::sort(displayNames);
+        for (const auto& name : displayNames)
+        {
+            select->AddArray(name.c_str());
+            ++rangePatches_;
+        }
 
-        // Add patches
-        // ~~~~~~~~~~~
+        // Add (non-zero) patches to the list of mesh parts
+        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
         if (!reader_->GetShowGroupsOnly())
         {
@@ -290,12 +286,11 @@ void Foam::vtkPVFoam::updateInfoPatches
                 if (pp.size())
                 {
                     // Add patch to GUI list
-                    arraySelection->AddArray
+                    select->AddArray
                     (
-                        (pp.name() + " - patch").c_str()
+                        ("patch/" + pp.name()).c_str()
                     );
-
-                    ++nPatches;
+                    ++rangePatches_;
                 }
             }
         }
@@ -320,94 +315,76 @@ void Foam::vtkPVFoam::updateInfoPatches
             false
         );
 
-        // this should only ever fail if the mesh region doesn't exist
+        // This should only ever fail if the mesh region doesn't exist
         if (ioObj.typeHeaderOk<polyBoundaryMesh>(true, false))
         {
             polyBoundaryMeshEntries patchEntries(ioObj);
 
-
-            // Read patches and determine sizes
-            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
+            // Read patches, determine sizes and patch groups
             wordList names(patchEntries.size());
             labelList sizes(patchEntries.size());
+            HashTable<labelHashSet> groups(2*patchEntries.size());
 
             forAll(patchEntries, patchi)
             {
                 const dictionary& patchDict = patchEntries[patchi].dict();
+                wordList groupNames;
 
                 sizes[patchi] = readLabel(patchDict.lookup("nFaces"));
                 names[patchi] = patchEntries[patchi].keyword();
-            }
-
-
-            // Add (non-zero) patch groups to the list of mesh parts
-            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-            HashTable<labelList> groups(patchEntries.size());
 
-            forAll(patchEntries, patchi)
-            {
-                const dictionary& patchDict = patchEntries[patchi].dict();
-
-                wordList groupNames;
-                patchDict.readIfPresent("inGroups", groupNames);
-
-                forAll(groupNames, groupI)
+                if
+                (
+                    sizes[patchi]  // Valid patch if nFace > 0
+                 && patchDict.readIfPresent("inGroups", groupNames)
+                )
                 {
-                    HashTable<labelList>::iterator iter = groups.find
-                    (
-                        groupNames[groupI]
-                    );
-                    if (iter != groups.end())
+                    forAll(groupNames, groupI)
                     {
-                        iter().append(patchi);
-                    }
-                    else
-                    {
-                        groups.insert(groupNames[groupI], labelList{patchi});
+                        groups(groupNames[groupI]).insert(patchi);
                     }
                 }
             }
 
-            forAllConstIters(groups, iter)
-            {
-                const word& groupName = iter.key();
-                const labelList& patchIDs = iter.object();
 
-                label nFaces = 0;
-                forAll(patchIDs, i)
-                {
-                    nFaces += sizes[patchIDs[i]];
-                }
+            // Add (non-zero) patch groups to the list of mesh parts
+            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+            DynamicList<string> displayNames(groups.size());
 
-                // Valid patch if nFace > 0 - add patch to GUI list
-                if (nFaces)
+            forAllConstIters(groups, iter)
+            {
+                const auto& groupName = iter.key();
+                const auto& patchIDs  = iter.object();
+
+                const string dpyName = "group/" + groupName;
+                displayNames.append(dpyName);
+
+                // Optionally replace group with patch name selections
+                // - must remove the group from the select itself, otherwise
+                //   it can toggle on, but not toggle off very well
+                if
+                (
+                    !reader_->GetShowGroupsOnly()
+                 && enabledEntries.erase(dpyName)
+                )
                 {
-                    string vtkGrpName = groupName + " - group";
-                    arraySelection->AddArray(vtkGrpName.c_str());
-
-                    ++nPatches;
-
-                    if (enabledEntriesSet.found(vtkGrpName))
+                    for (auto patchId : patchIDs)
                     {
-                        if (!reader_->GetShowGroupsOnly())
-                        {
-                            enabledEntriesSet.erase(vtkGrpName);
-                            forAll(patchIDs, i)
-                            {
-                                if (sizes[patchIDs[i]])
-                                {
-                                    string vtkPatchName =
-                                        names[patchIDs[i]] + " - patch";
-                                    enabledEntriesSet.insert(vtkPatchName);
-                                }
-                            }
-                        }
+                        enabledEntries.insert
+                        (
+                            "patch/" + names[patchId]
+                        );
                     }
                 }
             }
 
+            // Sort group names
+            Foam::sort(displayNames);
+            for (const auto& name : displayNames)
+            {
+                select->AddArray(name.c_str());
+                ++rangePatches_;
+            }
 
             // Add (non-zero) patches to the list of mesh parts
             // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -419,32 +396,27 @@ void Foam::vtkPVFoam::updateInfoPatches
                     // Valid patch if nFace > 0 - add patch to GUI list
                     if (sizes[patchi])
                     {
-                        arraySelection->AddArray
+                        select->AddArray
                         (
-                            (names[patchi] + " - patch").c_str()
+                            ("patch/" + names[patchi]).c_str()
                         );
-
-                        ++nPatches;
+                        ++rangePatches_;
                     }
                 }
             }
         }
     }
-    arrayRangePatches_ += nPatches;
-
-    // Update enabled entries in case of group selection
-    enabledEntries = enabledEntriesSet.toc();
 
     if (debug)
     {
-        Info<< "<end> updateInfoPatches" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
     }
 }
 
 
 void Foam::vtkPVFoam::updateInfoZones
 (
-    vtkDataArraySelection* arraySelection
+    vtkDataArraySelection* select
 )
 {
     if (!reader_->GetIncludeZones())
@@ -472,15 +444,15 @@ void Foam::vtkPVFoam::updateInfoZones
         namesLst = getZoneNames("cellZones");
     }
 
-    arrayRangeCellZones_.reset(arraySelection->GetNumberOfArrays());
+    rangeCellZones_.reset(select->GetNumberOfArrays());
     forAll(namesLst, elemI)
     {
-        arraySelection->AddArray
+        select->AddArray
         (
-            (namesLst[elemI] + " - cellZone").c_str()
+            ("cellZone/" + namesLst[elemI]).c_str()
         );
+        ++rangeCellZones_;
     }
-    arrayRangeCellZones_ += namesLst.size();
 
 
     //
@@ -495,15 +467,15 @@ void Foam::vtkPVFoam::updateInfoZones
         namesLst = getZoneNames("faceZones");
     }
 
-    arrayRangeFaceZones_.reset(arraySelection->GetNumberOfArrays());
+    rangeFaceZones_.reset(select->GetNumberOfArrays());
     forAll(namesLst, elemI)
     {
-        arraySelection->AddArray
+        select->AddArray
         (
-            (namesLst[elemI] + " - faceZone").c_str()
+            ("faceZone/" + namesLst[elemI]).c_str()
         );
+        ++rangeFaceZones_;
     }
-    arrayRangeFaceZones_ += namesLst.size();
 
 
     //
@@ -518,15 +490,15 @@ void Foam::vtkPVFoam::updateInfoZones
         namesLst = getZoneNames("pointZones");
     }
 
-    arrayRangePointZones_.reset(arraySelection->GetNumberOfArrays());
+    rangePointZones_.reset(select->GetNumberOfArrays());
     forAll(namesLst, elemI)
     {
-        arraySelection->AddArray
+        select->AddArray
         (
-            (namesLst[elemI] + " - pointZone").c_str()
+            ("pointZone/" + namesLst[elemI]).c_str()
         );
+        ++rangePointZones_;
     }
-    arrayRangePointZones_ += namesLst.size();
 
     if (debug)
     {
@@ -537,7 +509,7 @@ void Foam::vtkPVFoam::updateInfoZones
 
 void Foam::vtkPVFoam::updateInfoSets
 (
-    vtkDataArraySelection* arraySelection
+    vtkDataArraySelection* select
 )
 {
     if (!reader_->GetIncludeSets())
@@ -577,28 +549,28 @@ void Foam::vtkPVFoam::updateInfoSets
     }
 
 
-    arrayRangeCellSets_.reset(arraySelection->GetNumberOfArrays());
-    arrayRangeCellSets_ += addToSelection<cellSet>
+    rangeCellSets_.reset(select->GetNumberOfArrays());
+    rangeCellSets_ += addToSelection<cellSet>
     (
-        arraySelection,
+        select,
         objects,
-        " - cellSet"
+        "cellSet/"
     );
 
-    arrayRangeFaceSets_.reset(arraySelection->GetNumberOfArrays());
-    arrayRangeFaceSets_ += addToSelection<faceSet>
+    rangeFaceSets_.reset(select->GetNumberOfArrays());
+    rangeFaceSets_ += addToSelection<faceSet>
     (
-        arraySelection,
+        select,
         objects,
-        " - faceSet"
+        "faceSet/"
     );
 
-    arrayRangePointSets_.reset(arraySelection->GetNumberOfArrays());
-    arrayRangePointSets_ += addToSelection<pointSet>
+    rangePointSets_.reset(select->GetNumberOfArrays());
+    rangePointSets_ += addToSelection<pointSet>
     (
-        arraySelection,
+        select,
         objects,
-        " - pointSet"
+        "pointSet/"
     );
 
     if (debug)
@@ -608,23 +580,6 @@ void Foam::vtkPVFoam::updateInfoSets
 }
 
 
-void Foam::vtkPVFoam::updateInfoFields()
-{
-    updateInfoFields<fvPatchField, volMesh>
-    (
-        reader_->GetVolFieldSelection()
-    );
-    updateInfoFields<pointPatchField, pointMesh>
-    (
-        reader_->GetPointFieldSelection()
-    );
-    updateInfoLagrangianFields
-    (
-        reader_->GetLagrangianFieldSelection()
-    );
-}
-
-
 void Foam::vtkPVFoam::updateInfoLagrangianFields
 (
     vtkDataArraySelection* select
@@ -635,22 +590,23 @@ void Foam::vtkPVFoam::updateInfoLagrangianFields
         Info<< "<beg> updateInfoLagrangianFields" << endl;
     }
 
-    // preserve the enabled selections
-    stringList enabledEntries = getSelectedArrayEntries(select);
+    // Preserve the enabled selections
+    HashSet<string> enabled = getSelectedArraySet(select);
     select->RemoveAllArrays();
 
     // TODO - currently only get fields from ONE cloud
     // have to decide if the second set of fields get mixed in
     // or dealt with separately
 
-    const arrayRange& range = arrayRangeLagrangian_;
+    const arrayRange& range = rangeLagrangian_;
     if (range.empty())
     {
         return;
     }
 
-    int partId = range.start();
-    word cloudName = getPartName(partId);
+    // Add Lagrangian fields even if particles are not enabled?
+    const int partId = range.start();
+    const word cloudName = getReaderPartName(partId);
 
     // use the db directly since this might be called without a mesh,
     // but the region must get added back in
@@ -674,26 +630,8 @@ void Foam::vtkPVFoam::updateInfoLagrangianFields
     addToSelection<IOField<symmTensor>>(select, objects);
     addToSelection<IOField<tensor>>(select, objects);
 
-    // restore the enabled selections
-    setSelectedArrayEntries(select, enabledEntries);
-
-    if (debug > 1)
-    {
-        boolList status;
-        const label nElem = getSelected(status, select);
-
-        forAll(status, i)
-        {
-            Info<< "  lagrangian[" << i << "] = "
-                << status[i]
-                << " : " << select->GetArrayName(i) << nl;
-        }
-
-        if (!nElem)
-        {
-            Info<< "  lagrangian[none]" << nl;
-        }
-    }
+    // Restore the enabled selections
+    setSelectedArrayEntries(select, enabled);
 
     if (debug)
     {
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamUpdateTemplates.C b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamUpdateTemplates.C
index 1d2b429467b24ad68675c71543ff0232a93e6f44..4f11fdb1d6fb5caa5d75554d7efdcc420626366a 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamUpdateTemplates.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/vtkPVFoam/vtkPVFoamUpdateTemplates.C
@@ -45,16 +45,16 @@ void Foam::vtkPVFoam::updateInfoFields
             << endl;
     }
 
-    stringList enabledEntries;
+    HashSet<string> enabled;
     if (!select->GetNumberOfArrays() && !meshPtr_)
     {
-        // enable 'p' and 'U' only on the first call
-        enabledEntries = { "p", "U" };
+        // Enable 'p' and 'U' only on the first call
+        enabled = { "p", "U" };
     }
     else
     {
-        // preserve the enabled selections
-        enabledEntries = getSelectedArrayEntries(select);
+        // Preserve the enabled selections
+        enabled = getSelectedArraySet(select);
     }
 
     select->RemoveAllArrays();
@@ -126,8 +126,8 @@ void Foam::vtkPVFoam::updateInfoFields
     );
 
 
-    // restore the enabled selections
-    setSelectedArrayEntries(select, enabledEntries);
+    // Restore the enabled selections
+    setSelectedArrayEntries(select, enabled);
 
     if (debug)
     {
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/pqFoamBlockMeshControls.cxx b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/pqFoamBlockMeshControls.cxx
index ab4a6517066433378fa09cf288e8f54d28b683df..ec60272d5a97d675cf81e4eed774b4834c3f8e21 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/pqFoamBlockMeshControls.cxx
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/pqFoamBlockMeshControls.cxx
@@ -40,13 +40,14 @@ License
 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
 // file-scope
-static QAbstractButton* setButtonProperties
+// Widget properties
+static QWidget* setWidgetProperties
 (
-    QAbstractButton* b,
+    QWidget* widget,
     vtkSMProperty* prop
 )
 {
-    QString tip;
+    widget->setFocusPolicy(Qt::NoFocus); // avoid dotted border
 
     vtkSMDocumentation* doc = prop->GetDocumentation();
     if (doc)
@@ -54,22 +55,33 @@ static QAbstractButton* setButtonProperties
         const char* txt = doc->GetDescription();
         if (txt)
         {
-            tip = QString(txt).simplified();
+            QString tip = QString(txt).simplified();
+            if (tip.size())
+            {
+               widget->setToolTip(tip);
+            }
         }
     }
 
-    b->setText(prop->GetXMLLabel());
-    if (tip.size())
-    {
-        b->setToolTip(tip);
-    }
-    b->setFocusPolicy(Qt::NoFocus); // avoid dotted border
+    return widget;
+}
 
 
+// file-scope
+// Button properties
+static QAbstractButton* setButtonProperties
+(
+    QAbstractButton* b,
+    vtkSMProperty* prop
+)
+{
+    setWidgetProperties(b, prop);
+    b->setText(prop->GetXMLLabel());
+
     vtkSMIntVectorProperty* intProp =
         vtkSMIntVectorProperty::SafeDownCast(prop);
 
-    // initial checked state for integer (bool) properties
+    // Initial checked state for integer (bool) properties
     if (intProp)
     {
         b->setChecked(intProp->GetElement(0));
@@ -111,12 +123,12 @@ void pqFoamBlockMeshControls::fireCommand(vtkSMProperty* prop)
 void pqFoamBlockMeshControls::fireCommand
 (
     vtkSMIntVectorProperty* prop,
-    bool checked
+    int val
 )
 {
     vtkSMProxy* pxy = this->proxy();
 
-    prop->SetElement(0, checked); // Toogle bool
+    prop->SetElement(0, val); // Set int value, toogle bool, etc
 
     // Fire off command
     prop->Modified();
@@ -200,7 +212,10 @@ pqFoamBlockMeshControls::pqFoamBlockMeshControls
         setButtonProperties(b, refresh_);
         form->addWidget(b, 0, 0, Qt::AlignLeft);
 
-        connect(b, SIGNAL(clicked()), this, SLOT(refreshPressed()));
+        connect
+        (
+            b, SIGNAL(clicked()), this, SLOT(refreshPressed())
+        );
     }
 
     if (showPatchNames_)
@@ -209,7 +224,10 @@ pqFoamBlockMeshControls::pqFoamBlockMeshControls
         setButtonProperties(b, showPatchNames_);
         form->addWidget(b, 0, 1, Qt::AlignLeft);
 
-        connect(b, SIGNAL(toggled(bool)), this, SLOT(showPatchNames(bool)));
+        connect
+        (
+            b, SIGNAL(toggled(bool)), this, SLOT(showPatchNames(bool))
+        );
     }
 
     if (showPointNumbers_)
@@ -218,7 +236,10 @@ pqFoamBlockMeshControls::pqFoamBlockMeshControls
         setButtonProperties(b, showPointNumbers_);
         form->addWidget(b, 0, 2, Qt::AlignLeft);
 
-        connect(b, SIGNAL(toggled(bool)), this, SLOT(showPointNumbers(bool)));
+        connect
+        (
+            b, SIGNAL(toggled(bool)), this, SLOT(showPointNumbers(bool))
+        );
     }
 }
 
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/pqFoamBlockMeshControls.h b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/pqFoamBlockMeshControls.h
index a46cdc30528cdfdfa4fd47b1453a065d31be4467..89d7e945db90579a201d85334cbc7e6df028ebba 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/pqFoamBlockMeshControls.h
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/pqFoamBlockMeshControls.h
@@ -71,8 +71,8 @@ class pqFoamBlockMeshControls
     //- Update property
     void fireCommand(vtkSMProperty* prop);
 
-    //- Toggle and update bool property
-    void fireCommand(vtkSMIntVectorProperty* prop, bool checked);
+    //- Update int property or toggle bool property
+    void fireCommand(vtkSMIntVectorProperty* prop, int val);
 
     //- Update "BlockArrayStatus", "CurvedEdgesArrayStatus" information
     void updateParts();
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/vtkPVblockMeshReader.cxx b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/vtkPVblockMeshReader.cxx
index 2c8c1ce453d2ca3c3a763cfcbe7af46d9904782f..ed0271d0a14558e543bb0d5a9f7a1026a8539b37 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/vtkPVblockMeshReader.cxx
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/vtkPVblockMeshReader.cxx
@@ -106,7 +106,7 @@ vtkPVblockMeshReader::~vtkPVblockMeshReader()
 
     if (FileName)
     {
-        delete [] FileName;
+        delete[] FileName;
     }
 
     BlockSelection->RemoveAllObservers();
@@ -165,20 +165,19 @@ int vtkPVblockMeshReader::RequestData
 
     if (!FileName)
     {
-        vtkErrorMacro("FileName has to be specified!");
+        vtkErrorMacro("FileName must be specified!");
         return 0;
     }
-
-    // Catch previous error
     if (!backend_)
     {
-        vtkErrorMacro("Reader failed - perhaps no mesh?");
+        // Catch some previous error
+        vtkErrorMacro("Reader failed - perhaps no blockMesh?");
         return 0;
     }
 
     if (Foam::vtkPVblockMesh::debug)
     {
-        cout<<"REQUEST_DATA:\n";
+        cout<<"RequestData:\n";
         outputVector->GetInformationObject(0)->Print(cout);
     }
 
@@ -190,19 +189,12 @@ int vtkPVblockMeshReader::RequestData
         )
     );
 
-    if (Foam::vtkPVblockMesh::debug)
-    {
-        cout<< "update output with "
-            << output->GetNumberOfBlocks() << " blocks\n";
-    }
-
     backend_->Update(output);
 
     updatePatchNamesView(ShowPatchNames);
     updatePointNumbersView(ShowPointNumbers);
 
-    // Do any cleanup on the OpenFOAM side
-    backend_->CleanUp();
+    backend_->UpdateFinalize();
 
     return 1;
 }
@@ -263,12 +255,11 @@ void vtkPVblockMeshReader::updatePatchNamesView(const bool show)
     }
 
     // Get all the pqRenderView instances
-    QList<pqRenderView*> renderViews = smModel->findItems<pqRenderView*>();
-    for (int viewI=0; viewI<renderViews.size(); ++viewI)
+    for (auto view : smModel->findItems<pqRenderView*>())
     {
         backend_->renderPatchNames
         (
-            renderViews[viewI]->getRenderViewProxy()->GetRenderer(),
+            view->getRenderViewProxy()->GetRenderer(),
             show
         );
     }
@@ -295,12 +286,11 @@ void vtkPVblockMeshReader::updatePointNumbersView(const bool show)
     }
 
     // Get all the pqRenderView instances
-    QList<pqRenderView*> renderViews = smModel->findItems<pqRenderView*>();
-    for (int viewI=0; viewI<renderViews.size(); ++viewI)
+    for (auto view : smModel->findItems<pqRenderView*>())
     {
         backend_->renderPointNumbers
         (
-            renderViews[viewI]->getRenderViewProxy()->GetRenderer(),
+            view->getRenderViewProxy()->GetRenderer(),
             show
         );
     }
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/vtkPVblockMesh/vtkPVblockMesh.C b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/vtkPVblockMesh/vtkPVblockMesh.C
index 39c60bb7380df4a11f67d1b48a7f2f7fd6dfadd3..70ccb1f42067c5a509ced280f7b6be1663a715b4 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/vtkPVblockMesh/vtkPVblockMesh.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/vtkPVblockMesh/vtkPVblockMesh.C
@@ -39,6 +39,7 @@ License
 #include "vtkRenderer.h"
 #include "vtkTextActor.h"
 #include "vtkTextProperty.h"
+#include "vtkSmartPointer.h"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -47,32 +48,37 @@ namespace Foam
     defineTypeNameAndDebug(vtkPVblockMesh, 0);
 }
 
-
 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
-vtkTextActor* Foam::vtkPVblockMesh::createTextActor
-(
-    const string& s,
-    const point& pt
-)
+namespace Foam
 {
-    vtkTextActor* txt = vtkTextActor::New();
-    txt->SetInput(s.c_str());
-
-    // Set text properties
-    vtkTextProperty* tprop = txt->GetTextProperty();
-    tprop->SetFontFamilyToArial();
-    tprop->BoldOn();
-    tprop->ShadowOff();
-    tprop->SetLineSpacing(1.0);
-    tprop->SetFontSize(14);
-    tprop->SetColor(1.0, 0.0, 1.0);
-    tprop->SetJustificationToCentered();
-
-    txt->GetPositionCoordinate()->SetCoordinateSystemToWorld();
-    txt->GetPositionCoordinate()->SetValue(pt.x(), pt.y(), pt.z());
-
-    return txt;
+    // file-scope
+    //- Create a text actor
+    static vtkSmartPointer<vtkTextActor> createTextActor
+    (
+        const std::string& s,
+        const Foam::point& pt
+    )
+    {
+        auto txt = vtkSmartPointer<vtkTextActor>::New();
+
+        txt->SetInput(s.c_str());
+
+        // Set text properties
+        vtkTextProperty* tprop = txt->GetTextProperty();
+        tprop->SetFontFamilyToArial();
+        tprop->BoldOn();
+        tprop->ShadowOff();
+        tprop->SetLineSpacing(1.0);
+        tprop->SetFontSize(14);
+        tprop->SetColor(1.0, 0.0, 1.0);
+        tprop->SetJustificationToCentered();
+
+        txt->GetPositionCoordinate()->SetCoordinateSystemToWorld();
+        txt->GetPositionCoordinate()->SetValue(pt.x(), pt.y(), pt.z());
+
+        return txt;
+    }
 }
 
 
@@ -81,9 +87,9 @@ vtkTextActor* Foam::vtkPVblockMesh::createTextActor
 void Foam::vtkPVblockMesh::resetCounters()
 {
     // Reset mesh part ids and sizes
-    arrayRangeBlocks_.reset();
-    arrayRangeEdges_.reset();
-    arrayRangeCorners_.reset();
+    rangeBlocks_.reset();
+    rangeEdges_.reset();
+    rangeCorners_.reset();
 }
 
 
@@ -92,15 +98,13 @@ void Foam::vtkPVblockMesh::updateInfoBlocks
     vtkDataArraySelection* select
 )
 {
-    arrayRange& range = arrayRangeBlocks_;
-
     if (debug)
     {
         Info<< "<beg> updateInfoBlocks"
             << " [meshPtr=" << (meshPtr_ ? "set" : "null") << "]" << endl;
     }
 
-    range.reset(select->GetNumberOfArrays());
+    rangeBlocks_.reset(select->GetNumberOfArrays());
 
     const blockMesh& blkMesh = *meshPtr_;
 
@@ -122,10 +126,9 @@ void Foam::vtkPVblockMesh::updateInfoBlocks
 
         // Add "blockId" or "blockId - zoneName" to GUI list
         select->AddArray(ostr.str().c_str());
+        ++rangeBlocks_;
     }
 
-    range += nBlocks;
-
     if (debug)
     {
         Info<< "<end> updateInfoBlocks" << endl;
@@ -138,15 +141,13 @@ void Foam::vtkPVblockMesh::updateInfoEdges
     vtkDataArraySelection* select
 )
 {
-    arrayRange& range = arrayRangeEdges_;
-
     if (debug)
     {
         Info<< "<beg> updateInfoEdges"
             << " [meshPtr=" << (meshPtr_ ? "set" : "null") << "]" << endl;
     }
 
-    range.reset(select->GetNumberOfArrays());
+    rangeEdges_.reset(select->GetNumberOfArrays());
 
     const blockMesh& blkMesh = *meshPtr_;
     const blockEdgeList& edges = blkMesh.edges();
@@ -161,10 +162,9 @@ void Foam::vtkPVblockMesh::updateInfoEdges
 
         // Add "beg:end - type" to GUI list
         select->AddArray(ostr.str().c_str());
+        ++rangeEdges_;
     }
 
-    range += edges.size();
-
     if (debug)
     {
         Info<< "<end> updateInfoEdges" << endl;
@@ -185,9 +185,9 @@ Foam::vtkPVblockMesh::vtkPVblockMesh
     meshPtr_(nullptr),
     meshRegion_(polyMesh::defaultRegion),
     meshDir_(polyMesh::meshSubDir),
-    arrayRangeBlocks_("block"),
-    arrayRangeEdges_("edges"),
-    arrayRangeCorners_("corners")
+    rangeBlocks_("block"),
+    rangeEdges_("edges"),
+    rangeCorners_("corners")
 {
     if (debug)
     {
@@ -302,14 +302,15 @@ void Foam::vtkPVblockMesh::updateInfo()
     vtkDataArraySelection* blockSelection = reader_->GetBlockSelection();
     vtkDataArraySelection* edgeSelection  = reader_->GetCurvedEdgesSelection();
 
-    // preserve the enabled selections if possible
-    stringList enabledParts;
-    stringList enabledEdges;
     const bool firstTime = (!blockSelection->GetNumberOfArrays() && !meshPtr_);
+
+    // Preserve the enabled selections if possible
+    HashSet<string> enabledParts;
+    HashSet<string> enabledEdges;
     if (!firstTime)
     {
-        enabledParts = getSelectedArrayEntries(blockSelection);
-        enabledEdges = getSelectedArrayEntries(edgeSelection);
+        enabledParts = getSelectedArraySet(blockSelection);
+        enabledEdges = getSelectedArraySet(edgeSelection);
     }
 
     // Clear current mesh parts list
@@ -325,7 +326,7 @@ void Foam::vtkPVblockMesh::updateInfo()
     // Update curved edges list
     updateInfoEdges(edgeSelection);
 
-    // restore the enabled selections
+    // Restore the enabled selections
     if (!firstTime)
     {
         setSelectedArrayEntries(blockSelection, enabledParts);
@@ -405,14 +406,6 @@ void Foam::vtkPVblockMesh::Update
 {
     reader_->UpdateProgress(0.1);
 
-    // Set up mesh parts selection(s)
-    getSelected(blockStatus_, reader_->GetBlockSelection());
-
-    // Set up curved edges selection(s)
-    getSelected(edgeStatus_,  reader_->GetCurvedEdgesSelection());
-
-    reader_->UpdateProgress(0.2);
-
     // Update the OpenFOAM mesh
     updateFoamMesh();
     reader_->UpdateProgress(0.5);
@@ -425,11 +418,10 @@ void Foam::vtkPVblockMesh::Update
     convertMeshEdges(output, blockNo);
 
     reader_->UpdateProgress(0.8);
-
 }
 
 
-void Foam::vtkPVblockMesh::CleanUp()
+void Foam::vtkPVblockMesh::UpdateFinalize()
 {
     reader_->UpdateProgress(1.0);
 }
@@ -442,12 +434,11 @@ void Foam::vtkPVblockMesh::renderPatchNames
 )
 {
     // always remove old actors first
-    forAll(patchTextActorsPtrs_, actori)
+    forAll(patchTextActors_, actori)
     {
-        renderer->RemoveViewProp(patchTextActorsPtrs_[actori]);
-        patchTextActorsPtrs_[actori]->Delete();
+        renderer->RemoveViewProp(patchTextActors_[actori]);
     }
-    patchTextActorsPtrs_.clear();
+    patchTextActors_.clear();
 
     // the number of text actors
     label nActors = 0;
@@ -465,7 +456,7 @@ void Foam::vtkPVblockMesh::renderPatchNames
         }
 
         // 8 sides per block is plenty
-        patchTextActorsPtrs_.setSize(8*blkMesh.size());
+        patchTextActors_.setSize(8*blkMesh.size());
 
         // Collect all variables
         dictionary varDict(meshDescription.subOrEmptyDict("namedVertices"));
@@ -501,33 +492,33 @@ void Foam::vtkPVblockMesh::renderPatchNames
                 const face& f = patchFaces[facei];
 
                 // Into a list for later removal
-                patchTextActorsPtrs_[nActors++] = createTextActor
+                patchTextActors_[nActors++] = createTextActor
                 (
                     patchName,
                     f.centre(cornerPts) * scaleFactor
                 );
 
-                if (nActors == patchTextActorsPtrs_.size())
+                if (nActors == patchTextActors_.size())
                 {
                     // hit max allocated space - bail out
                     break;
                 }
             }
 
-            if (nActors == patchTextActorsPtrs_.size())
+            if (nActors == patchTextActors_.size())
             {
                 // hit max allocated space - bail out
                 break;
             }
         }
 
-        patchTextActorsPtrs_.setSize(nActors);
+        patchTextActors_.setSize(nActors);
     }
 
     // Add text to each renderer
-    forAll(patchTextActorsPtrs_, actori)
+    forAll(patchTextActors_, actori)
     {
-        renderer->AddViewProp(patchTextActorsPtrs_[actori]);
+        renderer->AddViewProp(patchTextActors_[actori]);
     }
 }
 
@@ -540,12 +531,11 @@ void Foam::vtkPVblockMesh::renderPointNumbers
 {
     // always remove old actors first
 
-    forAll(pointTextActorsPtrs_, actori)
+    forAll(pointTextActors_, actori)
     {
-        renderer->RemoveViewProp(pointTextActorsPtrs_[actori]);
-        pointTextActorsPtrs_[actori]->Delete();
+        renderer->RemoveViewProp(pointTextActors_[actori]);
     }
-    pointTextActorsPtrs_.clear();
+    pointTextActors_.clear();
 
     if (show && meshPtr_)
     {
@@ -553,7 +543,7 @@ void Foam::vtkPVblockMesh::renderPointNumbers
         const pointField& cornerPts = blkMesh.vertices();
         const scalar scaleFactor = blkMesh.scaleFactor();
 
-        pointTextActorsPtrs_.setSize(cornerPts.size());
+        pointTextActors_.setSize(cornerPts.size());
         forAll(cornerPts, pointi)
         {
             // Display either pointi as a number or with its name
@@ -562,7 +552,7 @@ void Foam::vtkPVblockMesh::renderPointNumbers
             blockVertex::write(os, pointi, blkMesh.meshDict());
 
             // Into a list for later removal
-            pointTextActorsPtrs_[pointi] = createTextActor
+            pointTextActors_[pointi] = createTextActor
             (
                 os.str(),
                 cornerPts[pointi]*scaleFactor
@@ -571,9 +561,9 @@ void Foam::vtkPVblockMesh::renderPointNumbers
     }
 
     // Add text to each renderer
-    forAll(pointTextActorsPtrs_, actori)
+    forAll(pointTextActors_, actori)
     {
-        renderer->AddViewProp(pointTextActorsPtrs_[actori]);
+        renderer->AddViewProp(pointTextActors_[actori]);
     }
 }
 
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/vtkPVblockMesh/vtkPVblockMesh.H b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/vtkPVblockMesh/vtkPVblockMesh.H
index a22316c84afce69d88d71c5559185a980c524ae9..1a85c655298d1756ee480940e0116ee484bdbd24 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/vtkPVblockMesh/vtkPVblockMesh.H
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/vtkPVblockMesh/vtkPVblockMesh.H
@@ -25,13 +25,18 @@ Class
     Foam::vtkPVblockMesh
 
 Description
-    Provides a reader interface for OpenFOAM blockMesh to VTK interaction
+    The backend for the vtkPVblockMeshReader reader module -
+    providing a paraview reader interface for OpenFOAM blockMesh.
+
+    The block reader module can assist when creating a blockMeshDict
+    for use with the blockMesh utility. As well as blocks, it can be
+    used to visualize edges,corners and patch names.
+
+    There is no native VTK equivalent for this functionality.
 
 SourceFiles
     vtkPVblockMesh.C
     vtkPVblockMeshConvert.C
-    vtkPVblockMeshUpdate.C
-    vtkPVblockMeshUtils.C
 
     // Needed by VTK:
     vtkDataArrayTemplateImplicit.txx
@@ -56,6 +61,8 @@ class vtkPolyData;
 class vtkUnstructuredGrid;
 class vtkIndent;
 
+template<class T> class vtkSmartPointer;
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
@@ -93,34 +100,25 @@ class vtkPVblockMesh
         //- The mesh directory for the region
         fileName meshDir_;
 
-        //- Selected geometrical parts
-        boolList blockStatus_;
-
-        //- Selected curved edges
-        boolList edgeStatus_;
-
         //- First instance and size of bleckMesh blocks
         //  used to index into blockStatus_
-        arrayRange arrayRangeBlocks_;
+        arrayRange rangeBlocks_;
 
         //- First instance and size of CurvedEdges (only partially used)
-        arrayRange arrayRangeEdges_;
+        arrayRange rangeEdges_;
 
         //- First instance and size of block corners (only partially used)
-        arrayRange arrayRangeCorners_;
+        arrayRange rangeCorners_;
 
         //- List of patch names for rendering to window
-        List<vtkTextActor*> patchTextActorsPtrs_;
+        List<vtkSmartPointer<vtkTextActor>> patchTextActors_;
 
         //- List of point numbers for rendering to window
-        List<vtkTextActor*> pointTextActorsPtrs_;
+        List<vtkSmartPointer<vtkTextActor>> pointTextActors_;
 
 
     // Private Member Functions
 
-        //- Create a text actor
-        static vtkTextActor* createTextActor(const string& s, const point& pt);
-
         //- Reset data counters
         void resetCounters();
 
@@ -178,14 +176,15 @@ public:
 
         void Update(vtkMultiBlockDataSet* output);
 
-        //- Clean any storage
-        void CleanUp();
+        //- Final part of Update(), after any last minute rendering.
+        void UpdateFinalize();
 
         //- Add/remove patch names to/from the view
-        void renderPatchNames(vtkRenderer*, const bool show);
+        void renderPatchNames(vtkRenderer* renderer, const bool show);
 
         //- Add/remove point numbers to/from the view
-        void renderPointNumbers(vtkRenderer*, const bool show);
+        void renderPointNumbers(vtkRenderer* renderer, const bool show);
+
 
      // Access
 
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/vtkPVblockMesh/vtkPVblockMeshConvert.C b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/vtkPVblockMesh/vtkPVblockMeshConvert.C
index 51f8f4c90cac535258a505349f9858f331de50e4..032a5b011a957bfe6c243a61ae06a78e867fbd6a 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/vtkPVblockMesh/vtkPVblockMeshConvert.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/vtkPVblockMesh/vtkPVblockMeshConvert.C
@@ -37,28 +37,9 @@ License
 #include "vtkPoints.h"
 #include "vtkPolyData.h"
 #include "vtkUnstructuredGrid.h"
+#include "vtkSmartPointer.h"
 
 
-// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
-
-//! \cond fileScope
-inline static void insertNextPoint
-(
-    vtkPoints *points,
-    const Foam::point& p,
-    const Foam::scalar scaleFactor
-)
-{
-    points->InsertNextPoint
-    (
-        p.x()*scaleFactor,
-        p.y()*scaleFactor,
-        p.z()*scaleFactor
-    );
-}
-
-//! \endcond
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 void Foam::vtkPVblockMesh::convertMeshBlocks
@@ -67,56 +48,52 @@ void Foam::vtkPVblockMesh::convertMeshBlocks
     int& blockNo
 )
 {
-    vtkDataArraySelection* selection = reader_->GetBlockSelection();
-    arrayRange& range = arrayRangeBlocks_;
-    range.block(blockNo);   // set output block
-    label datasetNo = 0;    // restart at dataset 0
-
-    const blockMesh& blkMesh = *meshPtr_;
-    const Foam::pointField& blockPoints = blkMesh.vertices();
-
     if (debug)
     {
         Info<< "<beg> convertMeshBlocks" << endl;
     }
 
-    int blockI = 0;
-    const scalar scaleFactor = blkMesh.scaleFactor();
-
-    for
+    const Map<string> blockStatus = getSelectedArrayMap
     (
-        int partId = range.start();
-        partId < range.end();
-        ++partId, ++blockI
-    )
+        reader_->GetBlockSelection()
+    );
+
+    arrayRange& range = rangeBlocks_;
+    range.block(blockNo);   // set output block
+    label datasetNo = 0;    // restart at dataset 0
+
+    const blockMesh& blkMesh = *meshPtr_;
+    const pointField blkPoints(blkMesh.vertices() * blkMesh.scaleFactor());
+
+    vtkIdType nodeIds[8];  // Space for VTK_HEXAHEDRON vertices
+    int blockId = -1;
+    for (auto partId : range)
     {
-        if (!blockStatus_[partId])
+        ++blockId; // Increment first
+        if (!blockStatus.found(partId))
         {
             continue;
         }
+        const auto& longName = blockStatus[partId];
 
-        const blockDescriptor& blockDef = blkMesh[blockI];
-
-        // Convert OpenFOAM mesh vertices to VTK
-        vtkPoints *vtkpoints = vtkPoints::New();
-        vtkpoints->Allocate(blockDef.nPoints());
+        const blockDescriptor& blockDef = blkMesh[blockId];
         const labelList& blockLabels = blockDef.blockShape();
 
-        vtkIdType nodeIds[8];
+        auto vtkpoints = vtkSmartPointer<vtkPoints>::New();
+        vtkpoints->SetNumberOfPoints(blockLabels.size());
 
-        forAll(blockLabels, ptI)
+        forAll(blockLabels, pointi)
         {
-            insertNextPoint
+            vtkpoints->SetPoint
             (
-                vtkpoints,
-                blockPoints[blockLabels[ptI]],
-                scaleFactor
+                pointi,
+                blkPoints[blockLabels[pointi]].v_
             );
-
-            nodeIds[ptI] = ptI;
+            nodeIds[pointi] = pointi;
         }
 
-        vtkUnstructuredGrid* vtkmesh = vtkUnstructuredGrid::New();
+        auto vtkmesh = vtkSmartPointer<vtkUnstructuredGrid>::New();
+
         vtkmesh->Allocate(1);
         vtkmesh->InsertNextCell
         (
@@ -126,16 +103,9 @@ void Foam::vtkPVblockMesh::convertMeshBlocks
         );
 
         vtkmesh->SetPoints(vtkpoints);
-        vtkpoints->Delete();
-
-        addToBlock
-        (
-            output, vtkmesh, range, datasetNo,
-            selection->GetArrayName(partId)
-        );
 
-        vtkmesh->Delete();
-        datasetNo++;
+        addToBlock(output, vtkmesh, range, datasetNo, longName);
+        ++datasetNo;
     }
 
 
@@ -158,34 +128,34 @@ void Foam::vtkPVblockMesh::convertMeshEdges
     int& blockNo
 )
 {
-    vtkDataArraySelection* selection = reader_->GetCurvedEdgesSelection();
-    arrayRange& range = arrayRangeEdges_;
+    const Map<string> edgeStatus = getSelectedArrayMap
+    (
+        reader_->GetCurvedEdgesSelection()
+    );
+
+    arrayRange& range = rangeEdges_;
 
     range.block(blockNo);      // set output block
     label datasetNo = 0;       // restart at dataset 0
 
     const blockMesh& blkMesh = *meshPtr_;
     const blockEdgeList& edges = blkMesh.edges();
-
-    int edgeI = 0;
     const scalar scaleFactor = blkMesh.scaleFactor();
 
-    for
-    (
-        int partId = range.start();
-        partId < range.end();
-        ++partId, ++edgeI
-    )
+    int edgeId = -1;
+    for (auto partId : range)
     {
-        if (!edgeStatus_[partId])
+        ++edgeId; // Increment first
+        if (!edgeStatus.found(partId))
         {
             continue;
         }
+        const auto& longName = edgeStatus[partId];
 
-        // search each block
-        forAll(blkMesh, blockI)
+        // Search each block
+        forAll(blkMesh, blockId)
         {
-            const blockDescriptor& blockDef = blkMesh[blockI];
+            const blockDescriptor& blockDef = blkMesh[blockId];
 
             edgeList blkEdges = blockDef.blockShape().edges();
 
@@ -198,7 +168,7 @@ void Foam::vtkPVblockMesh::convertMeshEdges
             label foundEdgeI = -1;
             forAll(blkEdges, blkEdgeI)
             {
-                if (edges[edgeI].compare(blkEdges[blkEdgeI]))
+                if (edges[edgeId].compare(blkEdges[blkEdgeI]))
                 {
                     foundEdgeI = blkEdgeI;
                     break;
@@ -209,24 +179,21 @@ void Foam::vtkPVblockMesh::convertMeshEdges
             {
                 const List<point>& edgePoints = edgesPoints[foundEdgeI];
 
-                vtkPolyData* vtkmesh = vtkPolyData::New();
-                vtkPoints* vtkpoints = vtkPoints::New();
-
-                vtkpoints->Allocate( edgePoints.size() );
-                vtkmesh->Allocate(1);
+                auto vtkpoints = vtkSmartPointer<vtkPoints>::New();
+                vtkpoints->SetNumberOfPoints(edgePoints.size());
 
                 vtkIdType pointIds[edgePoints.size()];
-                forAll(edgePoints, ptI)
+                forAll(edgePoints, pointi)
                 {
-                    insertNextPoint
-                    (
-                        vtkpoints,
-                        edgePoints[ptI],
-                        scaleFactor
-                    );
-                    pointIds[ptI] = ptI;
+                    const point p = edgePoints[pointi] * scaleFactor;
+
+                    vtkpoints->SetPoint(pointi, p.v_);
+                    pointIds[pointi] = pointi;
                 }
 
+                auto vtkmesh = vtkSmartPointer<vtkPolyData>::New();
+
+                vtkmesh->Allocate(1);
                 vtkmesh->InsertNextCell
                 (
                     VTK_POLY_LINE,
@@ -235,16 +202,9 @@ void Foam::vtkPVblockMesh::convertMeshEdges
                 );
 
                 vtkmesh->SetPoints(vtkpoints);
-                vtkpoints->Delete();
-
-                addToBlock
-                (
-                    output, vtkmesh, range, datasetNo,
-                    selection->GetArrayName(partId)
-                );
 
-                vtkmesh->Delete();
-                datasetNo++;
+                addToBlock(output, vtkmesh, range, datasetNo, longName);
+                ++datasetNo;
 
                 break;
             }
@@ -271,51 +231,34 @@ void Foam::vtkPVblockMesh::convertMeshCorners
     int& blockNo
 )
 {
-    arrayRange& range = arrayRangeCorners_;
+    arrayRange& range = rangeCorners_;
     range.block(blockNo);      // set output block
     label datasetNo = 0;       // restart at dataset 0
 
-    const pointField& blockPoints = meshPtr_->vertices();
-    const scalar& scaleFactor = meshPtr_->scaleFactor();
+    const pointField blkPoints(meshPtr_->vertices() * meshPtr_->scaleFactor());
 
     if (debug)
     {
-        Info<< "<beg> convertMeshCorners" << endl;
+        Info<< "<beg> " << FUNCTION_NAME << endl;
     }
 
-    if (true)  // or some flag or other condition
+    if (true)  // Or some flag or other condition
     {
-        vtkPolyData* vtkmesh = vtkPolyData::New();
-        vtkPoints* vtkpoints = vtkPoints::New();
-        vtkCellArray* vtkcells = vtkCellArray::New();
-
-        vtkpoints->Allocate( blockPoints.size() );
-        vtkcells->Allocate( blockPoints.size() );
+        auto vtkpoints = vtkSmartPointer<vtkPoints>::New();
+        vtkpoints->SetNumberOfPoints(blkPoints.size());
 
-        vtkIdType pointId = 0;
-        forAll(blockPoints, ptI)
+        forAll(blkPoints, pointi)
         {
-            insertNextPoint
-            (
-                vtkpoints,
-                blockPoints[ptI],
-                scaleFactor
-            );
-
-            vtkcells->InsertNextCell(1, &pointId); // VTK_VERTEX
-            pointId++;
+            vtkpoints->SetPoint(pointi, blkPoints[pointi].v_);
         }
 
-        vtkmesh->SetPoints(vtkpoints);
-        vtkpoints->Delete();
+        auto vtkmesh = vtkSmartPointer<vtkPolyData>::New();
 
-        vtkmesh->SetVerts(vtkcells);
-        vtkcells->Delete();
+        vtkmesh->SetPoints(vtkpoints);
+        vtkmesh->SetVerts(foamPvCore::identityVertices(blkPoints.size()));
 
         addToBlock(output, vtkmesh, range, datasetNo, range.name());
-        vtkmesh->Delete();
-
-        datasetNo++;
+        ++datasetNo;
     }
 
     // anything added?
@@ -326,7 +269,7 @@ void Foam::vtkPVblockMesh::convertMeshCorners
 
     if (debug)
     {
-        Info<< "<end> convertMeshCorners" << endl;
+        Info<< "<end> " << FUNCTION_NAME << endl;
     }
 }
 
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamPvCore.C b/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamPvCore.C
index 478cff22a4dc7d99b7cefd666f18964cade030c6..57e52af03dbed1396cf74dc95d89fa9a85c2e041 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamPvCore.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamPvCore.C
@@ -32,6 +32,9 @@ License
 #include "vtkDataSet.h"
 #include "vtkMultiBlockDataSet.h"
 #include "vtkInformation.h"
+#include "vtkSmartPointer.h"
+
+#include "foamVtkAdaptors.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -54,7 +57,8 @@ void Foam::foamPvCore::addToBlock
     const int blockNo = selector.block();
 
     vtkDataObject* dataObj = output->GetBlock(blockNo);
-    vtkMultiBlockDataSet* block = vtkMultiBlockDataSet::SafeDownCast(dataObj);
+    vtkSmartPointer<vtkMultiBlockDataSet> block =
+        vtkMultiBlockDataSet::SafeDownCast(dataObj);
 
     if (!block)
     {
@@ -66,9 +70,8 @@ void Foam::foamPvCore::addToBlock
             return;
         }
 
-        block = vtkMultiBlockDataSet::New();
+        block = vtkSmartPointer<vtkMultiBlockDataSet>::New();
         output->SetBlock(blockNo, block);
-        block->Delete();
     }
 
     if (debug)
@@ -81,7 +84,7 @@ void Foam::foamPvCore::addToBlock
 
     block->SetBlock(datasetNo, dataset);
 
-    // name the output block when assigning dataset 0
+    // Name the output block when assigning dataset 0
     if (datasetNo == 0)
     {
         output->GetMetaData(blockNo)->Set
@@ -102,56 +105,6 @@ void Foam::foamPvCore::addToBlock
 }
 
 
-int Foam::foamPvCore::getNumberOfDataSets
-(
-    vtkMultiBlockDataSet* output,
-    const arrayRange& selector
-)
-{
-    const int blockNo = selector.block();
-
-    vtkMultiBlockDataSet* block = vtkMultiBlockDataSet::SafeDownCast
-    (
-        output->GetBlock(blockNo)
-    );
-
-    if (block)
-    {
-        return block->GetNumberOfBlocks();
-    }
-
-    return 0;
-}
-
-
-int Foam::foamPvCore::getSelected
-(
-    boolList& status,
-    vtkDataArraySelection* selection
-)
-{
-    const int n = selection->GetNumberOfArrays();
-    if (status.size() != n)
-    {
-        status.setSize(n);
-        status = false;
-    }
-
-    int count = 0;
-    forAll(status, i)
-    {
-        const bool setting = selection->GetArraySetting(i);
-        if (setting)
-        {
-            ++count;
-        }
-        status[i] = setting;
-    }
-
-    return count;
-}
-
-
 Foam::hashedWordList Foam::foamPvCore::getSelected
 (
     vtkDataArraySelection* select
@@ -164,7 +117,7 @@ Foam::hashedWordList Foam::foamPvCore::getSelected
     {
         if (select->GetArraySetting(i))
         {
-            selected.append(getFirstWord(select->GetArrayName(i)));
+            selected.append(getFoamName(select->GetArrayName(i)));
         }
     }
 
@@ -181,11 +134,11 @@ Foam::hashedWordList Foam::foamPvCore::getSelected
     const int n = select->GetNumberOfArrays();
     DynamicList<word> selected(n);
 
-    for (int i = selector.start(); i < selector.end(); ++i)
+    for (auto i : selector)
     {
         if (select->GetArraySetting(i))
         {
-            selected.append(getFirstWord(select->GetArrayName(i)));
+            selected.append(getFoamName(select->GetArrayName(i)));
         }
     }
 
@@ -193,22 +146,22 @@ Foam::hashedWordList Foam::foamPvCore::getSelected
 }
 
 
-Foam::stringList Foam::foamPvCore::getSelectedArrayEntries
+Foam::HashSet<Foam::string>
+Foam::foamPvCore::getSelectedArraySet
 (
     vtkDataArraySelection* select
 )
 {
-    stringList selections(select->GetNumberOfArrays());
-    label nElem = 0;
+    const int n = select->GetNumberOfArrays();
+    HashSet<string> enabled(2*n);
 
-    forAll(selections, elemI)
+    for (int i=0; i < n; ++i)
     {
-        if (select->GetArraySetting(elemI))
+        if (select->GetArraySetting(i))
         {
-            selections[nElem++] = select->GetArrayName(elemI);
+            enabled.insert(select->GetArrayName(i));
         }
     }
-    selections.setSize(nElem);
 
     if (debug > 1)
     {
@@ -220,92 +173,61 @@ Foam::stringList Foam::foamPvCore::getSelectedArrayEntries
         }
         Info<< " )\nselected(";
 
-        forAll(selections, elemI)
+        for (auto k : enabled)
         {
-            Info<< " " << selections[elemI];
+            Info<< " " << k;
         }
         Info<< " )\n";
     }
 
-    return selections;
+    return enabled;
 }
 
 
-Foam::stringList Foam::foamPvCore::getSelectedArrayEntries
+Foam::Map<Foam::string>
+Foam::foamPvCore::getSelectedArrayMap
 (
-    vtkDataArraySelection* select,
-    const arrayRange& selector
+    vtkDataArraySelection* select
 )
 {
-    stringList selections(selector.size());
-    label nElem = 0;
+    const int n = select->GetNumberOfArrays();
+    Map<string> enabled(2*n);
 
-    for (int i = selector.start(); i < selector.end(); ++i)
+    for (int i=0; i < n; ++i)
     {
         if (select->GetArraySetting(i))
         {
-            selections[nElem++] = select->GetArrayName(i);
-        }
-    }
-    selections.setSize(nElem);
-
-    if (debug > 1)
-    {
-        Info<< "available(";
-        for (int i = selector.start(); i < selector.end(); ++i)
-        {
-            Info<< " \"" << select->GetArrayName(i) << "\"";
+            enabled.insert(i, select->GetArrayName(i));
         }
-        Info<< " )\nselected(";
-
-        forAll(selections, elemI)
-        {
-            Info<< " " << selections[elemI];
-        }
-        Info<< " )\n";
     }
 
-    return selections;
+    return enabled;
 }
 
 
-void Foam::foamPvCore::setSelectedArrayEntries
-(
-    vtkDataArraySelection* select,
-    const stringList& selections
-)
+Foam::word Foam::foamPvCore::getFoamName(const std::string& str)
 {
-    const int n = select->GetNumberOfArrays();
-    select->DisableAllArrays();
-
-    // Loop through entries, setting values from selectedEntries
-    for (int i=0; i < n; ++i)
+    if (str.size())
     {
-        const string arrayName(select->GetArrayName(i));
-
-        forAll(selections, elemI)
+        std::string::size_type beg = str.rfind('/');
+        if (beg == std::string::npos)
         {
-            if (selections[elemI] == arrayName)
-            {
-                select->EnableArray(arrayName.c_str());
-                break;
-            }
+            beg = 0;
+        }
+        else
+        {
+            ++beg;
         }
-    }
-}
 
+        std::string::size_type end = beg;
 
-Foam::word Foam::foamPvCore::getFirstWord(const char* str)
-{
-    if (str)
-    {
-        label n = 0;
-        while (str[n] && word::valid(str[n]))
+        while (str[end] && word::valid(str[end]))
         {
-            ++n;
+            ++end;
         }
-        // don't need to re-check for invalid chars
-        return word(str, n, false);
+
+        // Already checked for valid/invalid chars
+        return word(str.substr(beg, beg+end), false);
     }
     else
     {
@@ -324,4 +246,30 @@ void Foam::foamPvCore::printMemory()
     }
 }
 
+
+vtkSmartPointer<vtkCellArray> Foam::foamPvCore::identityVertices
+(
+    const label size
+)
+{
+    // VTK_VERTEX
+    auto cells = vtkSmartPointer<vtkCellArray>::New();
+
+    UList<vtkIdType> cellsUL = vtkUList(cells, size, 2*size);
+
+    // Cell connectivity for vertex
+    // [size, ids.., size, ids...]
+    // which means
+    // [1, id, 1, id, ...]
+    label idx = 0;
+    for (label id=0; id < size; ++id)
+    {
+        cellsUL[idx++] = 1;
+        cellsUL[idx++] = id;
+    }
+
+    return cells;
+}
+
+
 // ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamPvCore.H b/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamPvCore.H
index f6203690fd54f7eeb730faea212b19c9ef51c937..3bbc92855e52f4c6c21b7be82807c7553582b44a 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamPvCore.H
+++ b/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamPvCore.H
@@ -39,16 +39,20 @@ SourceFiles
 #include "pointList.H"
 #include "wordList.H"
 #include "Hash.H"
+#include "HashSet.H"
+#include "Map.H"
 #include "hashedWordList.H"
-
-#include "vtkPoints.h"
+#include "labelRange.H"
 
 // * * * * * * * * * * * * * Forward Declarations  * * * * * * * * * * * * * //
 
+class vtkCellArray;
 class vtkDataArraySelection;
 class vtkDataSet;
-class vtkMultiBlockDataSet;
 class vtkIndent;
+class vtkMultiBlockDataSet;
+class vtkPoints;
+template<class T> class vtkSmartPointer;
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -69,21 +73,20 @@ public:
     //- Bookkeeping for GUI checklists and multi-block organization
     //  Works like a SubList selection.
     class arrayRange
+    :
+        public labelRange
     {
         const char *name_;
         int block_;
-        int start_;
-        int size_;
 
     public:
 
         //- Construct with given name for the specified block
-        arrayRange(const char *name, const int blockNo=0)
+        arrayRange(const char *name, int blockNo=0)
         :
+            labelRange(),
             name_(name),
-            block_(blockNo),
-            start_(0),
-            size_(0)
+            block_(blockNo)
         {}
 
         //- Return the block holding these datasets
@@ -106,47 +109,21 @@ public:
             return name_;
         }
 
-        //- The array start index
-        int start() const
-        {
-            return start_;
-        }
-
-        //- The array end index
-        int end() const
-        {
-            return start_ + size_;
-        }
-
-        //- The sub-list size
-        int size() const
-        {
-            return size_;
-        }
-
-        //- True if the sub-list is empty
-        bool empty() const
-        {
-            return !size_;
-        }
+        //- Reset the start/size directly
+        using labelRange::reset;
 
         //- Reset the size to zero and optionally assign a new start
-        void reset(const int startAt = 0)
+        void reset(label startAt = 0)
         {
-            start_ = startAt;
-            size_  = 0;
+            clear();
+            setStart(startAt);
         }
 
-        //- Assign new start and reset the size
-        void operator=(const int i)
-        {
-            reset(i);
-        }
 
         //- Increment the size
-        void operator+=(const int n)
+        void operator+=(label n)
         {
-            size_ += n;
+            setSize(size() + n);
         }
 
     }; // End class arrayRange
@@ -183,48 +160,26 @@ public:
         const std::string& datasetName
     );
 
-    //- Convenience method for the VTK multiblock API
-    //  Always returns a nullptr if datasetNo is negative
-    template<class Type=vtkDataSet>
-    static Type* getDataFromBlock
-    (
-        vtkMultiBlockDataSet* output,
-        const arrayRange& selector,
-        const label datasetNo
-    );
-
-    //- Convenience method for the VTK multiblock API
-    static int getNumberOfDataSets
-    (
-        vtkMultiBlockDataSet* output,
-        const arrayRange& selector
-    );
-
     //- Add objects of Type to array selection
     template<class Type>
     static label addToSelection
     (
         vtkDataArraySelection* select,
         const IOobjectList& objects,
-        const string& suffix = string::null
+        const std::string& prefix = string::null
     );
 
 
-    //- Retrieve the current selections into a boolList
-    static int getSelected
-    (
-        boolList& lst,
-        vtkDataArraySelection* select
-    );
-
-    //- Retrieve the current selections as a wordHashSet
+    //- Retrieve the current selections as a hashedWordList,
+    //  while stripping off any prefix or suffix
     static hashedWordList getSelected
     (
         vtkDataArraySelection* select
     );
 
 
-    //- Retrieve a sub-list of the current selections
+    //- Retrieve a sub-list of the current selections as a hashedWordList,
+    //  while stripping off any prefix or suffix
     static hashedWordList getSelected
     (
         vtkDataArraySelection* select,
@@ -232,35 +187,42 @@ public:
     );
 
 
-    //- Retrieve the current selections
-    static stringList getSelectedArrayEntries
+    //- Retrieve the currently enabled selections as hashset
+    static HashSet<string> getSelectedArraySet
     (
         vtkDataArraySelection* select
     );
 
-    //- Retrieve a sub-list of the current selections
-    static stringList getSelectedArrayEntries
+    //- Retrieve the currently enabled selections as id/name map
+    static Map<string> getSelectedArrayMap
     (
-        vtkDataArraySelection* select,
-        const arrayRange& selector
+        vtkDataArraySelection* select
     );
 
-
-    //- Set selection(s)
+    //- Enable the selection(s)
+    template<class AnyValue, class AnyHasher>
     static void setSelectedArrayEntries
     (
         vtkDataArraySelection* select,
-        const stringList& selections
+        const HashTable<AnyValue, string, AnyHasher>& enabled
     );
 
 
-    //- Extract up to the first non-word characters
-    static word getFirstWord(const char* str);
+    //- Extract the first word characters after a slash
+    static word getFoamName(const std::string& str);
+
 
     //- Simple memory used debugging information
     static void printMemory();
 
 
+    //- Return an identity list of VTK_VERTEX
+    static vtkSmartPointer<vtkCellArray> identityVertices
+    (
+        const label size
+    );
+
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 }; // End class foamPvCore
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamPvCoreTemplates.C b/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamPvCoreTemplates.C
index e5d1353699ea5fa62a738e42b2f069b60449082f..54eeee88c09bb8d06756afcade39996a2c85f461 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamPvCoreTemplates.C
+++ b/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamPvCoreTemplates.C
@@ -25,55 +25,28 @@ License
 
 #include "IOobjectList.H"
 #include "vtkDataArraySelection.h"
-#include "vtkMultiBlockDataSet.h"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-template<class Type>
-Type* Foam::foamPvCore::getDataFromBlock
-(
-    vtkMultiBlockDataSet* output,
-    const arrayRange& selector,
-    const label datasetNo
-)
-{
-    const int blockNo = selector.block();
-
-    vtkMultiBlockDataSet* block =
-    (
-        datasetNo < 0
-      ? nullptr
-      : vtkMultiBlockDataSet::SafeDownCast(output->GetBlock(blockNo))
-    );
-
-    if (block)
-    {
-        return Type::SafeDownCast(block->GetBlock(datasetNo));
-    }
-
-    return nullptr;
-}
-
-
 template<class Type>
 Foam::label Foam::foamPvCore::addToSelection
 (
     vtkDataArraySelection *select,
     const IOobjectList& objects,
-    const string& suffix
+    const std::string& prefix
 )
 {
     const wordList names = objects.sortedNames(Type::typeName);
 
     forAll(names, i)
     {
-        if (suffix.empty())
+        if (prefix.empty())
         {
             select->AddArray(names[i].c_str());
         }
         else
         {
-            select->AddArray((names[i] + suffix).c_str());
+            select->AddArray((prefix + names[i]).c_str());
         }
     }
 
@@ -81,4 +54,27 @@ Foam::label Foam::foamPvCore::addToSelection
 }
 
 
+template<class AnyValue, class AnyHasher>
+void Foam::foamPvCore::setSelectedArrayEntries
+(
+    vtkDataArraySelection* select,
+    const HashTable<AnyValue, string, AnyHasher>& enabled
+)
+{
+    const int n = select->GetNumberOfArrays();
+    // disable everything not explicitly enabled
+    select->DisableAllArrays();
+
+    // Loop through entries, enabling as required
+    for (int i=0; i < n; ++i)
+    {
+        const char* arrayName = select->GetArrayName(i);
+        if (enabled.found(arrayName))
+        {
+            select->EnableArray(arrayName);
+        }
+    }
+}
+
+
 // ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamVtkAdaptors.H b/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamVtkAdaptors.H
new file mode 100644
index 0000000000000000000000000000000000000000..89146bc8895389068b65d41b64bce9e4d295b5d5
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PVReaders/foamPv/foamVtkAdaptors.H
@@ -0,0 +1,115 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 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/>.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef foamVtkAdaptors_H
+#define foamVtkAdaptors_H
+
+// OpenFOAM includes
+#include "labelList.H"
+
+// VTK includes
+#include "vtkCellArray.h"
+#include "vtkIdTypeArray.h"
+#include "vtkSmartPointer.h"
+#include "vtkUnsignedCharArray.h"
+#include "vtkAOSDataArrayTemplate.h"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    //- Attach a smart pointer, or generate a non-null one.
+    template<class T>
+    inline vtkSmartPointer<T> nonNullSmartPointer(T* ptr)
+    {
+        return vtkSmartPointer<T>(ptr ? ptr : T::New());
+    }
+
+
+    //- Helper to wrap vtkUnsignedCharArray as a UList
+    inline UList<uint8_t> vtkUList
+    (
+        vtkUnsignedCharArray* array,
+        const label size
+    )
+    {
+        array->SetNumberOfComponents(1);
+        array->SetNumberOfTuples(size);
+
+        UList<uint8_t> list
+        (
+            array->WritePointer(0, size),
+            size
+        );
+
+        return list;
+    }
+
+
+    //- Helper to wrap vtkIdTypeArray as a UList
+    inline UList<vtkIdType> vtkUList
+    (
+        vtkIdTypeArray* array,
+        const label size
+    )
+    {
+        array->SetNumberOfComponents(1);
+        array->SetNumberOfTuples(size);
+
+        UList<vtkIdType> list
+        (
+            array->WritePointer(0, size),
+            size
+        );
+
+        return list;
+    }
+
+
+    //- Special helper to wrap vtkCellArray as a UList
+    inline UList<vtkIdType> vtkUList
+    (
+        vtkCellArray* cells,
+        const label nCells,
+        const label size
+    )
+    {
+        cells->GetData()->SetNumberOfTuples(size);
+
+        UList<vtkIdType> list
+        (
+            cells->WritePointer(nCells, size),
+            size
+        );
+
+        return list;
+    }
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/Make/options b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/Make/options
index 004f0474b8f682bfba1ee2725cacf8198cafef9e..6898c7800d9047ca992caa070b69b84a8c02f243 100644
--- a/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/Make/options
+++ b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/Make/options
@@ -1,5 +1,6 @@
 EXE_INC = \
     -I$(LIB_SRC)/lagrangian/basic/lnInclude \
+    -I$(LIB_SRC)/fileFormats/lnInclude \
     -I$(LIB_SRC)/meshTools/lnInclude \
     -I$(LIB_SRC)/finiteVolume/lnInclude
 
diff --git a/applications/utilities/surface/surfaceMeshConvertTesting/surfaceMeshConvertTesting.C b/applications/utilities/surface/surfaceMeshConvertTesting/surfaceMeshConvertTesting.C
index 5f1c5e9a33dbc2e94e984b654889927c1cbd41a3..abdeec1c89fa66a0cc7a2bf492c60da9686dee07 100644
--- a/applications/utilities/surface/surfaceMeshConvertTesting/surfaceMeshConvertTesting.C
+++ b/applications/utilities/surface/surfaceMeshConvertTesting/surfaceMeshConvertTesting.C
@@ -159,12 +159,16 @@ int main(int argc, char *argv[])
 
     if
     (
-        !MeshedSurface<face>::canRead(importName, true)
-     ||
-        (
-            !optStdout
-         && !MeshedSurface<face>::canWriteType(exportName.ext(), true)
-        )
+        !args.optionFound("triSurface")
+    &&
+         (
+            !MeshedSurface<face>::canRead(importName, true)
+         ||
+            (
+                !optStdout
+             && !MeshedSurface<face>::canWriteType(exportName.ext(), true)
+            )
+         )
     )
     {
         return 1;
diff --git a/bin/paraFoam b/bin/paraFoam
index dcfe4cf1d9cf6c0e23243acd10e68097cfebf1e4..0015e73952bca7d06a7cbdb3a8fe0ec4ef9f4a5c 100755
--- a/bin/paraFoam
+++ b/bin/paraFoam
@@ -26,10 +26,10 @@
 #     paraFoam
 #
 # Description
-#     start paraview with the OpenFOAM libraries
+#     Start paraview with the OpenFOAM libraries and reader modules.
 #
 # Note
-#     combining -block or -builtin options with the -region option yields
+#     Combining -block or -builtin options with -region option yields
 #     undefined behaviour
 #------------------------------------------------------------------------------
 usage() {
@@ -37,7 +37,7 @@ usage() {
     while [ "$#" -ge 1 ]; do echo "$1"; shift; done
     cat<<USAGE
 
-Usage: ${0##*/} [OPTION] [PARAVIEW_OPTION]
+Usage: ${0##*/} [OPTION] [--] [PARAVIEW_OPTION]
 options:
   -block            use blockMesh reader  (uses .blockMesh extension)
   -case <dir>       specify alternative case directory, default is the cwd
@@ -46,10 +46,10 @@ options:
   -touchAll         create .blockMesh, .OpenFOAM files (and for all regions)
   -vtk | -builtin   use VTK builtin OpenFOAM reader  (uses .foam extension)
   -help             print the usage
+  --help            paraview help
 
-Paraview options start with a double dashes.
-
-* start paraview with the OpenFOAM libraries
+Start paraview with the OpenFOAM libraries and reader modules.
+Note that paraview options begin with double dashes.
 
   paraview=$(command -v paraview)
 
@@ -57,12 +57,9 @@ USAGE
     exit 1
 }
 
-# We want to do nice exit when running paraview to give paraview opportunity
-# to clean up
+# Do a nice exit to give paraview an opportunity to clean up
 unset FOAM_ABORT
 
-unset regionName optTouch
-
 # Hack: change all locale to 'C' i.e. using '.' for decimal point. This is
 # only needed temporarily until paraview is locale aware. (git version is
 # already 2010-07)
@@ -73,18 +70,19 @@ extension=OpenFOAM
 plugin=PVFoamReader
 
 # Parse options
+unset regionName optTouch
 while [ "$#" -gt 0 ]
 do
     case "$1" in
     -h | -help)
         usage
         ;;
-    -block | -blockMesh)
+    -block*)
         extension=blockMesh
         plugin=PVblockMeshReader
         shift
         ;;
-    -builtin | -vtk)
+    -vtk | -built*)
         extension=foam
         unset plugin
         shift
@@ -113,6 +111,11 @@ do
         shift
         break    # Stop here, treat balance as paraview options
         ;;
+    --help)      # Emit paraview help directly
+        exec paraview "$@"
+        echo "Error: could not exec paraview" 1>&2
+        exit 1   # This should not have happened
+        ;;
     --*)
         break    # Stop here, treat this and balance as paraview options
         ;;
@@ -253,6 +256,8 @@ then
 
     # Has --data=.., send directly to paraview
     exec paraview "$@"
+    echo "Error: could not exec paraview" 1>&2
+    exit 1   # This should not have happened
 
 else
 
diff --git a/etc/caseDicts/surface/surfaceFeatureExtractDict.cfg b/etc/caseDicts/surface/surfaceFeatureExtractDict.cfg
index 683d8acd59648b913a43b305f5269d1d60df9384..14af1b9e48472ade3f43611e78cbd320a9489455 100644
--- a/etc/caseDicts/surface/surfaceFeatureExtractDict.cfg
+++ b/etc/caseDicts/surface/surfaceFeatureExtractDict.cfg
@@ -1,7 +1,7 @@
 /*--------------------------------*- C++ -*----------------------------------*\
 | =========                 |                                                 |
 | \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
-|  \\    /   O peration     | Version:  plus                                  |  
+|  \\    /   O peration     | Version:  plus                                  |
 |   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
 |    \\/     M anipulation  |                                                 |
 \*---------------------------------------------------------------------------*/
diff --git a/etc/config.csh/paraview b/etc/config.csh/paraview
index cbc37767026f08f60796b704faa1eba8f7af9279..fa0cea0f4953c0384fb0e42af91407e241ac0df4 100644
--- a/etc/config.csh/paraview
+++ b/etc/config.csh/paraview
@@ -52,7 +52,7 @@
 #------------------------------------------------------------------------------
 # USER EDITABLE PART: Changes made here may be lost with the next upgrade
 
-setenv ParaView_VERSION 5.3.0
+setenv ParaView_VERSION 5.4.0
 setenv ParaView_MAJOR detect            # Automatically determine major version
 set cmake_version=cmake-system
 
diff --git a/etc/config.sh/bashcompletion b/etc/config.sh/bashcompletion
index b7b919e15d5f7f4d3be431880c5bd3594b2e12c7..464fb2f1ef7c5ea5028874b67e1b5a9b593865cc 100644
--- a/etc/config.sh/bashcompletion
+++ b/etc/config.sh/bashcompletion
@@ -2563,8 +2563,8 @@ _of_foamToVTK()
     local cur="${COMP_WORDS[COMP_CWORD]}"
     local prev="${COMP_WORDS[COMP_CWORD-1]}"
 
-    local opts="-allPatches -ascii -constant -latestTime -nearCellValue -newTimes -noFaceZones -noFunctionObjects -noInternal -noLagrangian -noLinks -noPointValues -noZero -parallel -poly -surfaceFields -useTimeName -srcDoc -doc -help "
-    local optsWithArgs="-case -cellSet -decomposeParDict -excludePatches -faceSet -fields -pointSet -region -roots -time "
+    local opts="-allPatches -ascii -constant -latestTime -nearCellValue -newTimes -noFaceZones -noFunctionObjects -noInternal -noLagrangian -noLinks -noPointValues -noZero -parallel -poly -surfaceFields -useTimeName -xml -srcDoc -doc -help "
+    local optsWithArgs="-case -cellSet -decomposeParDict -excludePatches -faceSet -fields -name -pointSet -region -roots -time "
 
     case ${prev} in
         -case)
diff --git a/etc/config.sh/paraview b/etc/config.sh/paraview
index 6c66ddcc3e34405d0b013dfabec3eb4a1d475129..b2a1cc161aa7e23abba8c5d16f15a786acf373b4 100644
--- a/etc/config.sh/paraview
+++ b/etc/config.sh/paraview
@@ -55,7 +55,7 @@
 #------------------------------------------------------------------------------
 # USER EDITABLE PART: Changes made here may be lost with the next upgrade
 
-ParaView_VERSION=5.3.0
+ParaView_VERSION=5.4.0
 ParaView_MAJOR=detect                   # Automatically determine major version
 cmake_version=cmake-system
 
diff --git a/src/conversion/Make/files b/src/conversion/Make/files
index 3f2c0a0c98c7e6ccb2679829519124f5f4fadf6b..a5b3ffea227982dfd421d5a8be97c62626c2d953 100644
--- a/src/conversion/Make/files
+++ b/src/conversion/Make/files
@@ -24,7 +24,13 @@ starcd/STARCDMeshWriter.C
 
 polyDualMesh/polyDualMesh.C
 
-vtk/part/foamVtkCells.C
-vtk/output/foamVtkOutput.C
+vtk/output/foamVtkInternalWriter.H
+vtk/output/foamVtkPatchWriter.H
+vtk/output/foamVtkSurfaceMeshWriter.C
+vtk/output/foamVtkWriteSurfFields.C
+
+vtk/part/foamVtkMeshMaps.C
+vtk/part/foamVtuCells.C
+vtk/part/foamVtuSizing.C
 
 LIB = $(FOAM_LIBBIN)/libconversion
diff --git a/src/conversion/vtk/output/foamVtkInternalWriter.C b/src/conversion/vtk/output/foamVtkInternalWriter.C
new file mode 100644
index 0000000000000000000000000000000000000000..49bf062e8273aea0e407a27d7df3b77ccf93590f
--- /dev/null
+++ b/src/conversion/vtk/output/foamVtkInternalWriter.C
@@ -0,0 +1,380 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "foamVtkInternalWriter.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::vtk::internalWriter::beginPiece()
+{
+    if (!legacy_)
+    {
+        format()
+            .openTag(vtk::fileTag::PIECE)
+            .xmlAttr(vtk::fileAttr::NUMBER_OF_POINTS, vtuCells_.nFieldPoints())
+            .xmlAttr(vtk::fileAttr::NUMBER_OF_CELLS,  vtuCells_.nFieldCells())
+            .closeTag();
+    }
+}
+
+
+void Foam::vtk::internalWriter::writePoints()
+{
+    // payload size
+    const uint64_t payLoad = (vtuCells_.nFieldPoints() * 3 * sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::beginPoints(os_, vtuCells_.nFieldPoints());
+    }
+    else
+    {
+        format()
+            .tag(vtk::fileTag::POINTS)
+            .openDataArray<float,3>(vtk::dataArrayAttr::POINTS)
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+
+    vtk::writeList(format(), mesh_.points());
+    vtk::writeList
+    (
+        format(),
+        mesh_.cellCentres(),
+        vtuCells_.addPointCellLabels()
+    );
+
+    format().flush();
+
+    if (!legacy_)
+    {
+        format()
+            .endDataArray()
+            .endTag(vtk::fileTag::POINTS);
+    }
+}
+
+
+void Foam::vtk::internalWriter::writeCellsLegacy()
+{
+    const List<uint8_t>& cellTypes = vtuCells_.cellTypes();
+    const labelList& vertLabels = vtuCells_.vertLabels();
+
+    os_ << "CELLS " << vtuCells_.nFieldCells() << ' '
+        << vertLabels.size() << nl;
+
+    vtk::writeList(format(), vertLabels);
+    format().flush();
+
+    os_ << "CELL_TYPES " << cellTypes.size() << nl;
+
+    // No nComponents for char, so cannot use vtk::writeList
+    forAll(cellTypes, i)
+    {
+        format().write(cellTypes[i]);
+    }
+    format().flush();
+}
+
+
+void Foam::vtk::internalWriter::writeCells()
+{
+    format().tag(vtk::fileTag::CELLS);
+
+    //
+    // 'connectivity'
+    //
+    {
+        const labelList& vertLabels = vtuCells_.vertLabels();
+        const uint64_t payLoad = vertLabels.size() * sizeof(label);
+
+        format().openDataArray<label>(vtk::dataArrayAttr::CONNECTIVITY)
+            .closeTag();
+
+        format().writeSize(payLoad);
+        vtk::writeList(format(), vertLabels);
+        format().flush();
+
+        format().endDataArray();
+    }
+
+
+    //
+    // 'offsets'  (connectivity offsets)
+    //
+    {
+        const labelList& vertOffsets = vtuCells_.vertOffsets();
+        const uint64_t payLoad = vertOffsets.size() * sizeof(label);
+
+        format().openDataArray<label>(vtk::dataArrayAttr::OFFSETS)
+            .closeTag();
+
+        format().writeSize(payLoad);
+        vtk::writeList(format(), vertOffsets);
+        format().flush();
+
+        format().endDataArray();
+    }
+
+
+    //
+    // 'types' (cell types)
+    //
+    {
+        const List<uint8_t>& cellTypes = vtuCells_.cellTypes();
+        const uint64_t payLoad = cellTypes.size() * sizeof(uint8_t);
+
+        format().openDataArray<uint8_t>(vtk::dataArrayAttr::TYPES)
+            .closeTag();
+
+        format().writeSize(payLoad);
+        forAll(cellTypes, i)
+        {
+            // No nComponents for char, cannot use vtk::writeList here
+            format().write(cellTypes[i]);
+        }
+        format().flush();
+
+        format().endDataArray();
+    }
+
+
+    //
+    // can quit here if there are NO face streams
+    //
+    if (vtuCells_.faceLabels().empty())
+    {
+        format().endTag(vtk::fileTag::CELLS);
+
+        return;
+    }
+
+
+    // --------------------------------------------------
+
+    //
+    // 'faces' (face streams)
+    //
+    {
+        const labelList& faceLabels = vtuCells_.faceLabels();
+        const uint64_t payLoad = faceLabels.size() * sizeof(label);
+
+        format().openDataArray<label>(vtk::dataArrayAttr::FACES)
+            .closeTag();
+
+        format().writeSize(payLoad);
+        vtk::writeList(format(), faceLabels);
+        format().flush();
+
+        format().endDataArray();
+    }
+
+
+    // 'faceoffsets' (face stream offsets)
+    // -1 to indicate that the cell is a primitive type that does not
+    // have a face stream
+    {
+        const labelList& faceOffsets = vtuCells_.faceOffsets();
+        const uint64_t payLoad = faceOffsets.size() * sizeof(label);
+
+        format().openDataArray<label>(vtk::dataArrayAttr::FACEOFFSETS)
+            .closeTag();
+
+        format().writeSize(payLoad);
+        vtk::writeList(format(), faceOffsets);
+        format().flush();
+
+        format().endDataArray();
+    }
+
+    format().endTag(vtk::fileTag::CELLS);
+}
+
+
+void Foam::vtk::internalWriter::writeMesh()
+{
+    writePoints();
+    if (legacy_)
+    {
+        writeCellsLegacy();
+    }
+    else
+    {
+        writeCells();
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::vtk::internalWriter::internalWriter
+(
+    const fvMesh& mesh,
+    const vtk::vtuCells& cells,
+    const fileName& baseName,
+    const vtk::outputOptions outOpts
+)
+:
+    mesh_(mesh),
+    legacy_(outOpts.legacy()),
+    format_(),
+    vtuCells_(cells),
+    os_()
+{
+    outputOptions opts(outOpts);
+    opts.append(false);  // No append supported
+
+    os_.open((baseName + (legacy_ ? ".vtk" : ".vtu")).c_str());
+    format_ = opts.newFormatter(os_);
+
+    const auto& title = mesh_.time().caseName();
+
+    if (legacy_)
+    {
+        legacy::fileHeader(format(), title, vtk::fileTag::UNSTRUCTURED_GRID);
+    }
+    else
+    {
+        // XML (inline)
+
+        format()
+            .xmlHeader()
+            .xmlComment(title)
+            .beginVTKFile(vtk::fileTag::UNSTRUCTURED_GRID, "0.1");
+    }
+
+    beginPiece();
+    writeMesh();
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::vtk::internalWriter::~internalWriter()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+
+void Foam::vtk::internalWriter::beginCellData(label nFields)
+{
+    if (legacy_)
+    {
+        legacy::dataHeader
+        (
+            os(),
+            vtk::fileTag::CELL_DATA,
+            vtuCells_.nFieldCells(),
+            nFields
+        );
+    }
+    else
+    {
+        format().tag(vtk::fileTag::CELL_DATA);
+    }
+}
+
+
+void Foam::vtk::internalWriter::endCellData()
+{
+    if (!legacy_)
+    {
+        format().endTag(vtk::fileTag::CELL_DATA);
+    }
+}
+
+
+void Foam::vtk::internalWriter::beginPointData(label nFields)
+{
+    if (legacy_)
+    {
+        legacy::dataHeader
+        (
+            os(),
+            vtk::fileTag::POINT_DATA,
+            vtuCells_.nFieldPoints(),
+            nFields
+        );
+    }
+    else
+    {
+        format().tag(vtk::fileTag::POINT_DATA);
+    }
+}
+
+
+void Foam::vtk::internalWriter::endPointData()
+{
+    if (!legacy_)
+    {
+        format().endTag(vtk::fileTag::POINT_DATA);
+    }
+}
+
+
+void Foam::vtk::internalWriter::writeFooter()
+{
+    if (!legacy_)
+    {
+        // slight cheat. </Piece> too
+        format().endTag(vtk::fileTag::PIECE);
+
+        format().endTag(vtk::fileTag::UNSTRUCTURED_GRID)
+            .endVTKFile();
+    }
+}
+
+
+void Foam::vtk::internalWriter::writeCellIDs()
+{
+    // Cell ids first
+    const labelList& cellMap = vtuCells_.cellMap();
+    const uint64_t payLoad = vtuCells_.nFieldCells() * sizeof(label);
+
+    if (legacy_)
+    {
+        os_ << "cellID 1 " << vtuCells_.nFieldCells() << " int" << nl;
+    }
+    else
+    {
+        format().openDataArray<label>("cellID")
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+
+    vtk::writeList(format(), cellMap);
+    format().flush();
+
+    if (!legacy_)
+    {
+        format().endDataArray();
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/output/foamVtkInternalWriter.H b/src/conversion/vtk/output/foamVtkInternalWriter.H
new file mode 100644
index 0000000000000000000000000000000000000000..7fd4aa4f5dafbcc2625254d4b253157474830940
--- /dev/null
+++ b/src/conversion/vtk/output/foamVtkInternalWriter.H
@@ -0,0 +1,255 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::vtk::internalWriter
+
+Description
+    Write fields (internal).
+
+SourceFiles
+    foamVtkInternalWriter.C
+    foamVtkInternalWriterTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef foamVtkInternalWriter_H
+#define foamVtkInternalWriter_H
+
+#include "OFstream.H"
+#include "volFields.H"
+#include "pointFields.H"
+
+#include "foamVtkOutputFields.H"
+#include "foamVtkOutputOptions.H"
+#include "foamVtuCells.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+class volPointInterpolation;
+
+namespace vtk
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class internalWriter Declaration
+\*---------------------------------------------------------------------------*/
+
+class internalWriter
+{
+    // Private Member Data
+
+        //- Reference to the OpenFOAM mesh (or subset)
+        const fvMesh& mesh_;
+
+        //- Commonly used query
+        const bool legacy_;
+
+        autoPtr<vtk::formatter> format_;
+
+        //- The volume cells (internalMesh)
+        const vtuCells& vtuCells_;
+
+        std::ofstream os_;
+
+
+    // Private Member Functions
+
+        //- Begin piece
+        void beginPiece();
+
+        //- Write mesh points
+        void writePoints();
+
+        //- Write mesh cells
+        void writeCellsLegacy();
+
+        //- Write mesh cells
+        void writeCells();
+
+        //- Write mesh topology
+        void writeMesh();
+
+
+        //- Disallow default bitwise copy construct
+        internalWriter(const internalWriter&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const internalWriter&) = delete;
+
+
+public:
+
+    // Constructors
+
+        //- Construct from components
+        internalWriter
+        (
+            const fvMesh& mesh,
+            const vtk::vtuCells& cells,
+            const fileName& baseName,
+            const vtk::outputOptions outOpts
+        );
+
+
+    //- Destructor
+    ~internalWriter();
+
+
+    // Member Functions
+
+        inline std::ofstream& os()
+        {
+            return os_;
+        }
+
+        inline vtk::formatter& format()
+        {
+            return format_();
+        }
+
+
+        //- Open write for CellData of count fields.
+        //  The parameters are only used for the legacy format.
+        void beginCellData(label nFields);
+
+        //- Close write for CellData
+        void endCellData();
+
+        //- Open write for PointData of count fields
+        //  The parameters are only used for the legacy format.
+        void beginPointData(label nFields);
+
+        //- Close write for PointData
+        void endPointData();
+
+
+        //- Write cellIDs
+        void writeCellIDs();
+
+        //- Write file footer
+        void writeFooter();
+
+
+      // Write fields (individually)
+
+        //- Write the internal field
+        template<class Type>
+        void write(const DimensionedField<Type, volMesh>& field);
+
+        //- Write the volume field (internal part)
+        template<class Type, template<class> class PatchField>
+        void write(const GeometricField<Type, PatchField, volMesh>& field);
+
+        //- Write the point field
+        //  Interpolate to originating cell centre for decomposed cells.
+        template<class Type, template<class> class PatchField>
+        void write
+        (
+            const GeometricField<Type, PatchField, pointMesh>& field
+        );
+
+        //- Write point-interpolated internal field
+        template<class Type>
+        void write
+        (
+            const volPointInterpolation& pInterp,
+            const DimensionedField<Type, volMesh>& vfield
+        );
+
+        //- Write point-interpolated volume field
+        template<class Type>
+        void write
+        (
+            const volPointInterpolation& pInterp,
+            const GeometricField<Type, fvPatchField, volMesh>& vfield
+        );
+
+
+      // Write fields (collectively)
+
+        //- Write multiple internal fields
+        template<class Type>
+        void write
+        (
+            const UPtrList
+            <
+                const DimensionedField<Type, volMesh>
+            >& flds
+        );
+
+        //- Write multiple volume/point fields
+        template<class Type, template<class> class PatchField, class GeoMesh>
+        void write
+        (
+            const UPtrList
+            <
+                const GeometricField<Type, PatchField, GeoMesh>
+            >& flds
+        );
+
+
+        //- Write multiple point-interpolated internal fields
+        template<class Type>
+        void write
+        (
+            const volPointInterpolation& pInterp,
+            const UPtrList
+            <
+                const DimensionedField<Type, volMesh>
+            >& flds
+        );
+
+        //- Write multiple point-interpolated volume fields
+        template<class Type>
+        void write
+        (
+            const volPointInterpolation& pInterp,
+            const UPtrList
+            <
+                const GeometricField<Type, fvPatchField, volMesh>
+            >& flds
+        );
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace vtk
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "foamVtkInternalWriterTemplates.C"
+#endif
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/output/foamVtkInternalWriterTemplates.C b/src/conversion/vtk/output/foamVtkInternalWriterTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..77689e5ec7b8d37391168db0ae145d2e91955e88
--- /dev/null
+++ b/src/conversion/vtk/output/foamVtkInternalWriterTemplates.C
@@ -0,0 +1,256 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "foamVtkInternalWriter.H"
+#include "foamVtkOutput.H"
+#include "volPointInterpolation.H"
+#include "interpolatePointToCell.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+void Foam::vtk::internalWriter::write
+(
+    const DimensionedField<Type, volMesh>& field
+)
+{
+    const labelList& cellMap = vtuCells_.cellMap();
+
+    const int nCmpt(pTraits<Type>::nComponents);
+    // const uint64_t payLoad(cellMap.size() * nCmpt * sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::floatField(os(), field.name(), nCmpt, cellMap.size());
+    }
+    else
+    {
+        format().openDataArray<float, nCmpt>(field.name())
+            .closeTag();
+    }
+
+    // writeField includes payload size, and flush
+    vtk::writeField(format(), field, cellMap);
+
+    if (!legacy_)
+    {
+        format().endDataArray();
+    }
+}
+
+
+template<class Type, template<class> class PatchField>
+void Foam::vtk::internalWriter::write
+(
+    const GeometricField<Type, PatchField, volMesh>& field
+)
+{
+    write(field.internalField());
+}
+
+
+template<class Type, template<class> class PatchField>
+void Foam::vtk::internalWriter::write
+(
+    const GeometricField<Type, PatchField, pointMesh>& field
+)
+{
+    const labelList& addPointCellLabels = vtuCells_.addPointCellLabels();
+
+    const int nCmpt(pTraits<Type>::nComponents);
+    const label nVals(vtuCells_.nFieldPoints());
+
+    // Only needed for non-legacy
+    const uint64_t payLoad(nVals * nCmpt * sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::floatField(os(), field.name(), nCmpt, nVals);
+    }
+    else
+    {
+        format().openDataArray<float, nCmpt>(field.name())
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+    vtk::writeList(format(), field);
+
+    for (const label cellId : addPointCellLabels)
+    {
+        const Type val = interpolatePointToCell(field, cellId);
+        vtk::write(format(), val);
+    }
+
+    format().flush();
+
+    if (!legacy_)
+    {
+        format().endDataArray();
+    }
+}
+
+
+template<class Type>
+void Foam::vtk::internalWriter::write
+(
+    const volPointInterpolation& pInterp,
+    const DimensionedField<Type, volMesh>& vfield
+)
+{
+    typedef DimensionedField<Type, pointMesh> PointFieldType;
+
+    // Use tmp intermediate. Compiler sometimes weird otherwise.
+    tmp<PointFieldType> tfield = pInterp.interpolate(vfield);
+    const PointFieldType& pfield = tfield();
+
+    const labelList& addPointCellLabels = vtuCells_.addPointCellLabels();
+
+    const int nCmpt(pTraits<Type>::nComponents);
+    const label nVals(vtuCells_.nFieldPoints());
+
+    // Only needed for non-legacy
+    const uint64_t payLoad(nVals * nCmpt * sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::floatField(os(), vfield.name(), nCmpt, nVals);
+    }
+    else
+    {
+        format().openDataArray<float, nCmpt>(vfield.name())
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+    vtk::writeList(format(), pfield);
+    vtk::writeList(format(), vfield, addPointCellLabels);
+    format().flush();
+
+    if (!legacy_)
+    {
+        format().endDataArray();
+    }
+}
+
+
+template<class Type>
+void Foam::vtk::internalWriter::write
+(
+    const volPointInterpolation& pInterp,
+    const GeometricField<Type, fvPatchField, volMesh>& vfield
+)
+{
+    typedef GeometricField<Type, pointPatchField, pointMesh> PointFieldType;
+
+    // Use tmp intermediate. Compiler sometimes weird otherwise.
+    tmp<PointFieldType> tfield = pInterp.interpolate(vfield);
+    const PointFieldType& pfield = tfield();
+
+    const labelList& addPointCellLabels = vtuCells_.addPointCellLabels();
+
+    const int nCmpt(pTraits<Type>::nComponents);
+    const label nVals(vtuCells_.nFieldPoints());
+
+    // Only needed for non-legacy
+    const uint64_t payLoad(nVals * nCmpt * sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::floatField(os(), vfield.name(), nCmpt, nVals);
+    }
+    else
+    {
+        format().openDataArray<float, nCmpt>(vfield.name())
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+    vtk::writeList(format(), pfield);
+    vtk::writeList(format(), vfield, addPointCellLabels);
+    format().flush();
+
+    if (!legacy_)
+    {
+        format().endDataArray();
+    }
+}
+
+
+template<class Type>
+void Foam::vtk::internalWriter::write
+(
+    const UPtrList<const DimensionedField<Type, volMesh>>& flds
+)
+{
+    for (const auto& field : flds)
+    {
+        write(field);
+    }
+}
+
+
+template<class Type, template<class> class PatchField, class GeoMesh>
+void Foam::vtk::internalWriter::write
+(
+    const UPtrList<const GeometricField<Type, PatchField, GeoMesh>>& flds
+)
+{
+    for (const auto& field : flds)
+    {
+        write(field);
+    }
+}
+
+
+template<class Type>
+void Foam::vtk::internalWriter::write
+(
+    const volPointInterpolation& pInterp,
+    const UPtrList<const DimensionedField<Type, volMesh>>& flds
+)
+{
+    for (const auto& field : flds)
+    {
+        write(pInterp, field);
+    }
+}
+
+
+template<class Type>
+void Foam::vtk::internalWriter::write
+(
+    const volPointInterpolation& pInterp,
+    const UPtrList<const GeometricField<Type, fvPatchField, volMesh>>& flds
+)
+{
+    for (const auto& field : flds)
+    {
+        write(pInterp, field);
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/output/foamVtkOutput.C b/src/conversion/vtk/output/foamVtkOutput.C
deleted file mode 100644
index fc2d29884189feb9a38640cb1c92a0ee61e950b2..0000000000000000000000000000000000000000
--- a/src/conversion/vtk/output/foamVtkOutput.C
+++ /dev/null
@@ -1,119 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016-2017 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 "foamVtkOutput.H"
-#include "foamVtkAsciiFormatter.H"
-
-// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
-
-const Foam::word Foam::foamVtkOutput::legacy::EXT = "vtk";
-
-
-//! \cond fileScope
-static inline std::ostream& legacyDataHeader
-(
-    std::ostream& os,
-    const char* tag,
-    const Foam::label nItems,
-    const Foam::label nFields
-)
-{
-    os  << tag << ' ' << nItems << '\n'
-        << "FIELD attributes " << nFields << '\n';
-
-    return os;
-}
-//! \endcond
-
-
-// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
-
-Foam::label Foam::foamVtkOutput::writeVtmFile
-(
-    std::ostream& os,
-    const UList<fileName>& files
-)
-{
-    const word& content = "vtkMultiBlockDataSet";
-
-    foamVtkAsciiFormatter vtmFile(os);
-
-    vtmFile
-        .xmlHeader()
-        .beginVTKFile(content, "1.0");
-
-    forAll(files, i)
-    {
-        vtmFile
-            .openTag("DataSet")
-            ( "index", i )
-            ( "file", files[i] )
-            .closeTag(true);
-    }
-
-    vtmFile.endTag(content).endVTKFile();
-
-    return files.size();
-}
-
-
-std::ostream& Foam::foamVtkOutput::legacy::writeHeader
-(
-    std::ostream& os,
-    const std::string& title,
-    const bool binary
-)
-{
-    os  << "# vtk DataFile Version 2.0" << nl
-        << title << nl
-        << (binary ? "BINARY" : "ASCII") << nl;
-
-    return os;
-}
-
-
-std::ostream& Foam::foamVtkOutput::legacy::writeCellDataHeader
-(
-    std::ostream& os,
-    const label nCells,
-    const label nFields
-)
-{
-    return legacyDataHeader(os, "CELL_DATA", nCells, nFields);
-}
-
-
-std::ostream& Foam::foamVtkOutput::legacy::writePointDataHeader
-(
-    std::ostream& os,
-    const label nPoints,
-    const label nFields
-)
-{
-    return legacyDataHeader(os, "POINT_DATA", nPoints, nFields);
-}
-
-
-// ************************************************************************* //
diff --git a/src/conversion/vtk/output/foamVtkOutput.H b/src/conversion/vtk/output/foamVtkOutput.H
deleted file mode 100644
index f0897d6675ca1658d6287ac3f1a98f7b260d14aa..0000000000000000000000000000000000000000
--- a/src/conversion/vtk/output/foamVtkOutput.H
+++ /dev/null
@@ -1,222 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  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
-    foamVtkOutput
-
-Description
-    A collection of functions for writing vtk file content.
-
-SourceFiles
-    foamVtkOutput.C
-    foamVtkOutputTemplates.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef foamVtkOutput_H
-#define foamVtkOutput_H
-
-#include "floatScalar.H"
-#include "volFields.H"
-#include "foamVtkFormatter.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-/*---------------------------------------------------------------------------*\
-                        Class foamVtkOutput Declaration
-\*---------------------------------------------------------------------------*/
-
-class foamVtkOutput
-{
-    // Private Member Functions
-
-        //- Disallow construction
-        foamVtkOutput() = delete;
-
-public:
-
-    // Public typedefs
-
-        //- Use UInt64 for header data
-        typedef foamVtkFormatter::headerType headerType;
-
-
-    // Forward declarations
-    class legacy;
-
-
-    // Static Members
-
-        //- Write vtm datasets for specified files
-        static Foam::label writeVtmFile
-        (
-            std::ostream& os,
-            const UList<fileName>& files
-        );
-
-
-        //- Write a value component-wise.
-        template<class Type>
-        inline static void write(foamVtkFormatter&, const Type&);
-
-
-        //- Write a list of values.
-        //  The output does not include the payload size.
-        template<class Type>
-        static void writeList
-        (
-            foamVtkFormatter&,
-            const UList<Type>&
-        );
-
-
-        //- Write a list of values via indirect addressing.
-        //  The output does not include the payload size.
-        template<class Type>
-        static void writeList
-        (
-            foamVtkFormatter&,
-            const UList<Type>&,
-            const UList<label>& addressing
-        );
-
-
-        //- Write volField with cell values (including decomposed cells).
-        //  The output includes the payload size and flush.
-        template<class Type>
-        static void writeField
-        (
-            foamVtkFormatter&,
-            const GeometricField<Type, fvPatchField, volMesh>&,
-            const UList<label>& superCells
-        );
-
-};
-
-
-/*---------------------------------------------------------------------------*\
-                    Class foamVtkOutput::legacy Declaration
-\*---------------------------------------------------------------------------*/
-
-//- Basic support for legacy files
-class foamVtkOutput::legacy
-{
-    // Private Member Functions
-
-        //- Disallow construction
-        legacy() = delete;
-
-public:
-
-    // Static data members
-
-        //- file extension for legacy files (vtk)
-        static const Foam::word EXT;
-
-
-    // Static Members
-
-        //- Emit header for legacy file
-        static std::ostream& writeHeader
-        (
-            std::ostream&,
-            const std::string& title,
-            const bool binary = false
-        );
-
-
-        //- Emit header for legacy CELL_DATA
-        static std::ostream& writeCellDataHeader
-        (
-            std::ostream& os,
-            const label nCells,
-            const label nFields
-        );
-
-
-        //- Emit header for legacy POINT_DATA
-        static std::ostream& writePointDataHeader
-        (
-            std::ostream& os,
-            const label nPoints,
-            const label nFields
-        );
-
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-
-//- Template specialization for label
-template<>
-inline void Foam::foamVtkOutput::write<label>
-(
-    foamVtkFormatter& fmt,
-    const label& val
-)
-{
-    fmt.write(val);
-}
-
-
-//- Template specialization for float
-template<>
-inline void Foam::foamVtkOutput::write<float>
-(
-    foamVtkFormatter& fmt,
-    const float& val
-)
-{
-    fmt.write(val);
-}
-
-
-//- Template specialization for double
-template<>
-inline void Foam::foamVtkOutput::write<double>
-(
-    foamVtkFormatter& fmt,
-    const double& val
-)
-{
-    fmt.write(val);
-}
-
-} // End namespace Foam
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#ifdef NoRepository
-    #include "foamVtkOutputTemplates.C"
-#endif
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/src/conversion/vtk/output/foamVtkOutputFields.H b/src/conversion/vtk/output/foamVtkOutputFields.H
new file mode 100644
index 0000000000000000000000000000000000000000..116aadbfeb18d24b860d67b8ff3dcff96cc6bcd6
--- /dev/null
+++ b/src/conversion/vtk/output/foamVtkOutputFields.H
@@ -0,0 +1,105 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016-2107 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/>.
+
+InNamespace
+    Foam::vtk
+
+Description
+    Additional functions for writing fields in VTK format.
+
+SourceFiles
+    foamVtkOutputFieldsTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef foamVtkOutputFields_H
+#define foamVtkOutputFields_H
+
+#include "foamVtkOutput.H"
+#include "volFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace vtk
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+    //- Write DimensionedField for mesh
+    //  The output includes the payload size and flush.
+    template<class Type>
+    void writeField
+    (
+        vtk::formatter& fmt,
+        const DimensionedField<Type, volMesh>& fld
+    );
+
+    //- Write DimensionedField based on the cellMap
+    //  The output includes the payload size and flush.
+    template<class Type>
+    void writeField
+    (
+        vtk::formatter& fmt,
+        const DimensionedField<Type, volMesh>& fld,
+        const UList<label>& cellMap
+    );
+
+    //- Write internalField for mesh
+    //  The output includes the payload size and flush.
+    template<class Type>
+    void writeField
+    (
+        vtk::formatter& fmt,
+        const GeometricField<Type, fvPatchField, volMesh>& fld
+    );
+
+    //- Write internalField based on the cellMap
+    //  The output includes the payload size and flush.
+    template<class Type>
+    void writeField
+    (
+        vtk::formatter& fmt,
+        const GeometricField<Type, fvPatchField, volMesh>& fld,
+        const UList<label>& cellMap
+    );
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace vtk
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "foamVtkOutputFieldsTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/output/foamVtkOutputFieldsTemplates.C b/src/conversion/vtk/output/foamVtkOutputFieldsTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..b462922416f9e86b88cf2b5fdd3de074b3b05b41
--- /dev/null
+++ b/src/conversion/vtk/output/foamVtkOutputFieldsTemplates.C
@@ -0,0 +1,107 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016-2107 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/>.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+
+template<class Type>
+void Foam::vtk::writeField
+(
+    vtk::formatter& fmt,
+    const DimensionedField<Type, volMesh>& fld
+)
+{
+    const uint64_t payLoad =
+    (
+        fld.size() * pTraits<Type>::nComponents * sizeof(float)
+    );
+
+    fmt.writeSize(payLoad);
+    writeList(fmt, fld);
+
+    fmt.flush();
+}
+
+
+template<class Type>
+void Foam::vtk::writeField
+(
+    vtk::formatter& fmt,
+    const DimensionedField<Type, volMesh>& fld,
+    const UList<label>& cellMap
+)
+{
+    const uint64_t payLoad =
+    (
+        cellMap.size() * pTraits<Type>::nComponents * sizeof(float)
+    );
+
+    fmt.writeSize(payLoad);
+    writeList(fmt, fld, cellMap);
+
+    fmt.flush();
+}
+
+
+template<class Type>
+void Foam::vtk::writeField
+(
+    vtk::formatter& fmt,
+    const GeometricField<Type, fvPatchField, volMesh>& fld
+)
+{
+    const uint64_t payLoad =
+    (
+        fld.size() * pTraits<Type>::nComponents * sizeof(float)
+    );
+
+    fmt.writeSize(payLoad);
+    writeList(fmt, fld.internalField());
+
+    fmt.flush();
+}
+
+
+template<class Type>
+void Foam::vtk::writeField
+(
+    vtk::formatter& fmt,
+    const GeometricField<Type, fvPatchField, volMesh>& fld,
+    const UList<label>& cellMap
+)
+{
+    const uint64_t payLoad =
+    (
+        cellMap.size() * pTraits<Type>::nComponents * sizeof(float)
+    );
+
+    fmt.writeSize(payLoad);
+    writeList(fmt, fld.internalField(), cellMap);
+
+    fmt.flush();
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/output/foamVtkPatchWriter.C b/src/conversion/vtk/output/foamVtkPatchWriter.C
new file mode 100644
index 0000000000000000000000000000000000000000..fcbe032cfd25baef27eacd90e8145d1d4230614b
--- /dev/null
+++ b/src/conversion/vtk/output/foamVtkPatchWriter.C
@@ -0,0 +1,404 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "foamVtkPatchWriter.H"
+#include "foamVtkOutput.H"
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::vtk::patchWriter::beginPiece()
+{
+    if (!legacy_)
+    {
+        format()
+            .openTag(vtk::fileTag::PIECE)
+            .xmlAttr(vtk::fileAttr::NUMBER_OF_POINTS, nPoints_)
+            .xmlAttr(vtk::fileAttr::NUMBER_OF_POLYS,  nFaces_)
+            .closeTag();
+    }
+}
+
+
+void Foam::vtk::patchWriter::writePoints()
+{
+    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
+
+    const uint64_t payLoad = (nPoints_*3*sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::beginPoints(os_, nPoints_);
+    }
+    else
+    {
+        format().tag(vtk::fileTag::POINTS)
+            .openDataArray<float, 3>(vtk::dataArrayAttr::POINTS)
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+
+    for (const label patchId : patchIDs_)
+    {
+        const polyPatch& pp = patches[patchId];
+
+        vtk::writeList(format(), pp.localPoints());
+    }
+    format().flush();
+
+    if (!legacy_)
+    {
+        format()
+            .endDataArray()
+            .endTag(vtk::fileTag::POINTS);
+    }
+}
+
+
+void Foam::vtk::patchWriter::writePolysLegacy()
+{
+    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
+
+    // connectivity count without additional storage (done internally)
+    uint64_t nConnectivity = 0;
+    for (const label patchId : patchIDs_)
+    {
+        const polyPatch& pp = patches[patchId];
+
+        forAll(pp, facei)
+        {
+            nConnectivity += pp[facei].size();
+        }
+    }
+
+    legacy::beginPolys(os_, nFaces_, nConnectivity);
+
+
+    // legacy: size + connectivity together
+    // [nPts, id1, id2, ..., nPts, id1, id2, ...]
+
+    label off = 0;
+    for (const label patchId : patchIDs_)
+    {
+        const polyPatch& pp = patches[patchId];
+
+        forAll(pp, facei)
+        {
+            const face& f = pp.localFaces()[facei];
+
+            format().write(f.size());  // The size prefix
+            forAll(f, fi)
+            {
+                format().write(off + f[fi]);
+            }
+        }
+        off += pp.nPoints();
+    }
+
+    format().flush();
+}
+
+
+void Foam::vtk::patchWriter::writePolys()
+{
+    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
+
+    //
+    // 'connectivity'
+    //
+
+    format().tag(vtk::fileTag::POLYS);
+
+    //
+    // 'connectivity'
+    //
+    {
+        // payload count
+        uint64_t payLoad = 0;
+        for (const label patchId : patchIDs_)
+        {
+            const polyPatch& pp = patches[patchId];
+
+            forAll(pp, facei)
+            {
+                payLoad += pp[facei].size();
+            }
+        }
+
+        format().openDataArray<label>(vtk::dataArrayAttr::CONNECTIVITY)
+            .closeTag();
+
+        // payload size
+        format().writeSize(payLoad * sizeof(label));
+
+        label off = 0;
+        for (const label patchId : patchIDs_)
+        {
+            const polyPatch& pp = patches[patchId];
+
+            forAll(pp, facei)
+            {
+                const face& f = pp.localFaces()[facei];
+                forAll(f, fi)
+                {
+                    format().write(off + f[fi]);
+                }
+            }
+
+            off += pp.nPoints();
+        }
+
+        format().flush();
+
+        format()
+            .endDataArray();
+    }
+
+
+    //
+    // 'offsets'  (connectivity offsets)
+    //
+    {
+        format()
+            .openDataArray<label>(vtk::dataArrayAttr::OFFSETS)
+            .closeTag();
+
+        // payload size
+        format().writeSize(nFaces_ * sizeof(label));
+
+        label off = 0;
+        for (const label patchId : patchIDs_)
+        {
+            const polyPatch& pp = patches[patchId];
+
+            forAll(pp, facei)
+            {
+                off += pp[facei].size();
+
+                format().write(off);
+            }
+        }
+
+        format().flush();
+        format().endDataArray();
+    }
+
+    format().endTag(vtk::fileTag::POLYS);
+}
+
+
+void Foam::vtk::patchWriter::writeMesh()
+{
+    writePoints();
+    if (legacy_)
+    {
+        writePolysLegacy();
+    }
+    else
+    {
+        writePolys();
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::vtk::patchWriter::patchWriter
+(
+    const fvMesh& mesh,
+    const fileName& baseName,
+    const vtk::outputOptions outOpts,
+    const bool nearCellValue,
+    const labelList& patchIDs
+)
+:
+    mesh_(mesh),
+    legacy_(outOpts.legacy()),
+    format_(),
+    nearCellValue_(nearCellValue),
+    patchIDs_(patchIDs),
+    os_(),
+    nPoints_(0),
+    nFaces_(0)
+{
+    outputOptions opts(outOpts);
+    opts.append(false);  // No append
+
+    os_.open((baseName + (legacy_ ? ".vtk" : ".vtp")).c_str());
+    format_ = opts.newFormatter(os_);
+
+    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
+
+    const word& title =
+    (
+        patchIDs_.size() == 1
+      ? patches[patchIDs_.first()].name()
+      : "patches"
+    );
+
+    // Basic sizes
+    nPoints_ = nFaces_ = 0;
+    for (const label patchId : patchIDs_)
+    {
+        const polyPatch& pp = patches[patchId];
+
+        nPoints_ += pp.nPoints();
+        nFaces_  += pp.size();
+    }
+
+
+    if (legacy_)
+    {
+        legacy::fileHeader(format(), title, vtk::fileTag::POLY_DATA);
+    }
+    else
+    {
+        // XML (inline)
+
+        format()
+            .xmlHeader()
+            .xmlComment(title)
+            .beginVTKFile(vtk::fileTag::POLY_DATA, "0.1");
+    }
+
+    beginPiece();
+    writeMesh();
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::vtk::patchWriter::~patchWriter()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::vtk::patchWriter::beginCellData(label nFields)
+{
+    if (legacy_)
+    {
+        legacy::dataHeader
+        (
+            os(),
+            vtk::fileTag::CELL_DATA,
+            nFaces_,
+            nFields
+        );
+    }
+    else
+    {
+        format().tag(vtk::fileTag::CELL_DATA);
+    }
+}
+
+
+void Foam::vtk::patchWriter::endCellData()
+{
+    if (!legacy_)
+    {
+        format().endTag(vtk::fileTag::CELL_DATA);
+    }
+}
+
+
+void Foam::vtk::patchWriter::beginPointData(label nFields)
+{
+    if (legacy_)
+    {
+        legacy::dataHeader
+        (
+            os(),
+            vtk::fileTag::POINT_DATA,
+            nPoints_,
+            nFields
+        );
+    }
+    else
+    {
+        format().tag(vtk::fileTag::POINT_DATA);
+    }
+}
+
+
+void Foam::vtk::patchWriter::endPointData()
+{
+    if (!legacy_)
+    {
+        format().endTag(vtk::fileTag::POINT_DATA);
+    }
+}
+
+
+void Foam::vtk::patchWriter::writeFooter()
+{
+    if (!legacy_)
+    {
+        // slight cheat. </Piece> too
+        format().endTag(vtk::fileTag::PIECE);
+
+        format().endTag(vtk::fileTag::POLY_DATA)
+            .endVTKFile();
+    }
+}
+
+
+void Foam::vtk::patchWriter::writePatchIDs()
+{
+    // Patch ids first
+    const uint64_t payLoad = nFaces_ * sizeof(label);
+
+    if (legacy_)
+    {
+        legacy::intField(os_, "patchID", 1, nFaces_);
+    }
+    else
+    {
+        format().openDataArray<label>("patchID")
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+
+    for (const label patchId : patchIDs_)
+    {
+        const label sz = mesh_.boundaryMesh()[patchId].size();
+
+        for (label facei = 0; facei < sz; ++facei)
+        {
+            format().write(patchId);
+        }
+    }
+    format().flush();
+
+    if (!legacy_)
+    {
+        format().endDataArray();
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/output/foamVtkPatchWriter.H b/src/conversion/vtk/output/foamVtkPatchWriter.H
new file mode 100644
index 0000000000000000000000000000000000000000..627b84788210de52f8f06eca2580a9332bf52349
--- /dev/null
+++ b/src/conversion/vtk/output/foamVtkPatchWriter.H
@@ -0,0 +1,230 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::vtk::patchWriter
+
+Description
+    Write patch fields
+
+SourceFiles
+    foamVtkPatchWriter.C
+    foamVtkPatchWriterTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef foamVtkPatchWriter_H
+#define foamVtkPatchWriter_H
+
+#include "pointMesh.H"
+#include "OFstream.H"
+#include "volFields.H"
+#include "pointFields.H"
+#include "indirectPrimitivePatch.H"
+#include "PrimitivePatchInterpolation.H"
+#include "foamVtkOutputOptions.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+class volPointInterpolation;
+
+namespace vtk
+{
+
+/*---------------------------------------------------------------------------*\
+                           Class patchWriter Declaration
+\*---------------------------------------------------------------------------*/
+
+class patchWriter
+{
+    // Private Member Data
+
+        //- Reference to the OpenFOAM mesh (or subset)
+        const fvMesh& mesh_;
+
+        //- Commonly used query
+        const bool legacy_;
+
+        autoPtr<vtk::formatter> format_;
+
+        const bool nearCellValue_;
+
+        const labelList patchIDs_;
+
+        std::ofstream os_;
+
+        label nPoints_;
+
+        label nFaces_;
+
+
+    // Private Member Functions
+
+        //- Begin piece
+        void beginPiece();
+
+        //- Write patch points
+        void writePoints();
+
+        //- Write patch faces
+        void writePolysLegacy();
+
+        //- Write patch faces
+        void writePolys();
+
+        //- Write mesh topology
+        void writeMesh();
+
+
+        //- Disallow default bitwise copy construct
+        patchWriter(const patchWriter&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const patchWriter&) = delete;
+
+
+public:
+
+    // Constructors
+
+        //- Construct from components
+        patchWriter
+        (
+            const fvMesh& mesh,
+            const fileName& baseName,
+            const vtk::outputOptions outOpts,
+            const bool nearCellValue,
+            const labelList& patchIDs
+        );
+
+
+    //- Destructor
+    ~patchWriter();
+
+
+    // Member Functions
+
+        inline std::ofstream& os()
+        {
+            return os_;
+        }
+
+        inline vtk::formatter& format()
+        {
+            return format_();
+        }
+
+        inline label nPoints() const
+        {
+            return nPoints_;
+        }
+
+        inline label nFaces() const
+        {
+            return nFaces_;
+        }
+
+        //- Open write for CellData of count fields.
+        //  The parameters are only used for the legacy format.
+        void beginCellData(label nFields);
+
+        //- Close write for CellData
+        void endCellData();
+
+        //- Open write for PointData of count fields
+        //  The parameters are only used for the legacy format.
+        void beginPointData(label nFields);
+
+        //- Close write for PointData
+        void endPointData();
+
+        //- Write cellIDs
+        void writePatchIDs();
+
+        //- Write file footer
+        void writeFooter();
+
+
+      // Write fields (individually)
+
+        //- Write volume field
+        template<class Type, template<class> class PatchField>
+        void write(const GeometricField<Type, PatchField, volMesh>& field);
+
+        //- Write point fields
+        template<class Type, template<class> class PatchField>
+        void write(const GeometricField<Type, PatchField, pointMesh>& field);
+
+        //- Write point-interpolated volume field
+        template<class Type>
+        void write
+        (
+            const PrimitivePatchInterpolation<primitivePatch>& pInterp,
+            const GeometricField<Type, fvPatchField, volMesh>& field
+        );
+
+
+      // Write fields (collectively)
+
+        //- Write multiple volume/point fields
+        template<class Type, template<class> class PatchField, class GeoMesh>
+        void write
+        (
+            const UPtrList
+            <
+                const GeometricField<Type, PatchField, GeoMesh>
+            >& flds
+        );
+
+        //- Write multiple point-interpolated volume fields
+        template<class Type>
+        void write
+        (
+            const PrimitivePatchInterpolation<primitivePatch>& pInterp,
+            const UPtrList
+            <
+                const GeometricField<Type, fvPatchField, volMesh>
+            >& flds
+        );
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace vtk
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "foamVtkPatchWriterTemplates.C"
+#endif
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/output/foamVtkPatchWriterTemplates.C b/src/conversion/vtk/output/foamVtkPatchWriterTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..9c77912499fce907fe916f401ee10ae7b1fe4ab7
--- /dev/null
+++ b/src/conversion/vtk/output/foamVtkPatchWriterTemplates.C
@@ -0,0 +1,189 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "foamVtkPatchWriter.H"
+#include "foamVtkOutput.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type, template<class> class PatchField>
+void Foam::vtk::patchWriter::write
+(
+    const GeometricField<Type, PatchField, volMesh>& field
+)
+{
+    const int nCmpt(pTraits<Type>::nComponents);
+    const uint64_t payLoad(nFaces_ * nCmpt * sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::floatField(os_, field.name(), nCmpt, nFaces_);
+    }
+    else
+    {
+        format().openDataArray<float, nCmpt>(field.name())
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+
+    for (const label patchId : patchIDs_)
+    {
+        const auto& pfld = field.boundaryField()[patchId];
+
+        if (nearCellValue_)
+        {
+            vtk::writeList(format(), pfld.patchInternalField()());
+        }
+        else
+        {
+            vtk::writeList(format(), pfld);
+        }
+    }
+
+    format().flush();
+
+    if (!legacy_)
+    {
+        format().endDataArray();
+    }
+}
+
+
+template<class Type, template<class> class PatchField>
+void Foam::vtk::patchWriter::write
+(
+    const GeometricField<Type, PatchField, pointMesh>& field
+)
+{
+    const int nCmpt(pTraits<Type>::nComponents);
+    const uint64_t payLoad(nPoints_ * nCmpt * sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::floatField(os_, field.name(), nCmpt, nPoints_);
+    }
+    else
+    {
+        format().openDataArray<float, nCmpt>(field.name())
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+
+    for (const label patchId : patchIDs_)
+    {
+        const auto& pfld = field.boundaryField()[patchId];
+
+        vtk::writeList(format(), pfld.patchInternalField()());
+    }
+
+    format().flush();
+
+    if (!legacy_)
+    {
+        format().endDataArray();
+    }
+}
+
+
+template<class Type>
+void Foam::vtk::patchWriter::write
+(
+    const PrimitivePatchInterpolation<primitivePatch>& pInter,
+    const GeometricField<Type, fvPatchField, volMesh>& field
+)
+{
+    const int nCmpt(pTraits<Type>::nComponents);
+    const uint64_t payLoad(nPoints_ * nCmpt * sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::floatField(os_, field.name(), nCmpt, nPoints_);
+    }
+    else
+    {
+        format().openDataArray<float, nCmpt>(field.name())
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+
+    for (const label patchId : patchIDs_)
+    {
+        const auto& pfld = field.boundaryField()[patchId];
+
+        if (nearCellValue_)
+        {
+            auto tfield =
+                pInter.faceToPointInterpolate(pfld.patchInternalField()());
+
+            vtk::writeList(format(), tfield());
+        }
+        else
+        {
+            auto tfield = pInter.faceToPointInterpolate(pfld);
+
+            vtk::writeList(format(), tfield());
+        }
+    }
+
+    format().flush();
+
+    if (!legacy_)
+    {
+        format().endDataArray();
+    }
+}
+
+
+template<class Type, template<class> class PatchField, class GeoMesh>
+void Foam::vtk::patchWriter::write
+(
+    const UPtrList<const GeometricField<Type, PatchField, GeoMesh>>& flds
+)
+{
+    for (const auto& field : flds)
+    {
+        write(field);
+    }
+}
+
+
+template<class Type>
+void Foam::vtk::patchWriter::write
+(
+    const PrimitivePatchInterpolation<primitivePatch>& pInter,
+    const UPtrList<const GeometricField<Type, fvPatchField, volMesh>>& flds
+)
+{
+    for (const auto& field : flds)
+    {
+        write(pInter, field);
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/output/foamVtkSurfaceMeshWriter.C b/src/conversion/vtk/output/foamVtkSurfaceMeshWriter.C
new file mode 100644
index 0000000000000000000000000000000000000000..df54f039cda22b571fb51747c7222a90f4520993
--- /dev/null
+++ b/src/conversion/vtk/output/foamVtkSurfaceMeshWriter.C
@@ -0,0 +1,264 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "foamVtkSurfaceMeshWriter.H"
+#include "foamVtkOutput.H"
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::vtk::surfaceMeshWriter::beginPiece()
+{
+    if (!legacy_)
+    {
+        format()
+            .openTag(vtk::fileTag::PIECE)
+            .xmlAttr(vtk::fileAttr::NUMBER_OF_POINTS, pp_.nPoints())
+            .xmlAttr(vtk::fileAttr::NUMBER_OF_POLYS,  pp_.size())
+            .closeTag();
+    }
+}
+
+
+void Foam::vtk::surfaceMeshWriter::writePoints()
+{
+    const uint64_t payLoad = (pp_.nPoints()*3*sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::beginPoints(os_, pp_.nPoints());
+    }
+    else
+    {
+        format().tag(vtk::fileTag::POINTS)
+            .openDataArray<float, 3>(vtk::dataArrayAttr::POINTS)
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+
+    vtk::writeList(format(), pp_.localPoints());
+    format().flush();
+
+    if (!legacy_)
+    {
+        format()
+            .endDataArray()
+            .endTag(vtk::fileTag::POINTS);
+    }
+}
+
+
+void Foam::vtk::surfaceMeshWriter::writePolysLegacy()
+{
+    // connectivity count without additional storage (done internally)
+    uint64_t nConnectivity = 0;
+    forAll(pp_, facei)
+    {
+        nConnectivity += pp_[facei].size();
+    }
+
+    legacy::beginPolys(os_, pp_.size(), nConnectivity);
+
+
+    // legacy: size + connectivity together
+    // [nPts, id1, id2, ..., nPts, id1, id2, ...]
+
+    forAll(pp_, facei)
+    {
+        const face& f = pp_.localFaces()[facei];
+
+        format().write(f.size());  // The size prefix
+        vtk::writeList(format(), f);
+    }
+
+    format().flush();
+}
+
+
+void Foam::vtk::surfaceMeshWriter::writePolys()
+{
+    //
+    // 'connectivity'
+    //
+
+    format().tag(vtk::fileTag::POLYS);
+
+    //
+    // 'connectivity'
+    //
+    {
+        // payload count
+        uint64_t payLoad = 0;
+        forAll(pp_, facei)
+        {
+            payLoad += pp_[facei].size();
+        }
+
+        format().openDataArray<label>(vtk::dataArrayAttr::CONNECTIVITY)
+            .closeTag();
+
+        // payload size
+        format().writeSize(payLoad * sizeof(label));
+
+        forAll(pp_, facei)
+        {
+            const face& f = pp_.localFaces()[facei];
+            vtk::writeList(format(), f);
+        }
+
+        format().flush();
+
+        format()
+            .endDataArray();
+    }
+
+
+    //
+    // 'offsets'  (connectivity offsets)
+    //
+    {
+        format()
+            .openDataArray<label>(vtk::dataArrayAttr::OFFSETS)
+            .closeTag();
+
+        // payload size
+        format().writeSize(pp_.size() * sizeof(label));
+
+        label off = 0;
+        forAll(pp_, facei)
+        {
+            off += pp_[facei].size();
+
+            format().write(off);
+        }
+
+        format().flush();
+        format().endDataArray();
+    }
+
+    format().endTag(vtk::fileTag::POLYS);
+}
+
+
+void Foam::vtk::surfaceMeshWriter::writeMesh()
+{
+    writePoints();
+    if (legacy_)
+    {
+        writePolysLegacy();
+    }
+    else
+    {
+        writePolys();
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::vtk::surfaceMeshWriter::surfaceMeshWriter
+(
+    const indirectPrimitivePatch& pp,
+    const word& name,
+    const fileName& baseName,
+    const vtk::outputOptions outOpts
+)
+:
+    pp_(pp),
+    legacy_(outOpts.legacy()),
+    format_(),
+    os_()
+{
+    outputOptions opts(outOpts);
+    opts.legacy(true);  // No append supported
+
+    os_.open((baseName + (legacy_ ? ".vtk" : ".vtp")).c_str());
+    format_ = opts.newFormatter(os_);
+
+    if (legacy_)
+    {
+        legacy::fileHeader(format(), name, vtk::fileTag::POLY_DATA);
+    }
+    else
+    {
+        // XML (inline)
+
+        format()
+            .xmlHeader()
+            .xmlComment(name)
+            .beginVTKFile(vtk::fileTag::POLY_DATA, "0.1");
+
+    }
+
+    beginPiece();
+    writeMesh();
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::vtk::surfaceMeshWriter::~surfaceMeshWriter()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::vtk::surfaceMeshWriter::beginCellData(label nFields)
+{
+    if (legacy_)
+    {
+        legacy::dataHeader(os(), vtk::fileTag::CELL_DATA, pp_.size(), nFields);
+    }
+    else
+    {
+        format().tag(vtk::fileTag::CELL_DATA);
+    }
+}
+
+
+void Foam::vtk::surfaceMeshWriter::endCellData()
+{
+    if (!legacy_)
+    {
+        format().endTag(vtk::fileTag::CELL_DATA);
+    }
+}
+
+
+void Foam::vtk::surfaceMeshWriter::writeFooter()
+{
+    if (!legacy_)
+    {
+        // slight cheat. </Piece> too
+        format().endTag(vtk::fileTag::PIECE);
+
+        format().endTag(vtk::fileTag::POLY_DATA)
+            .endVTKFile();
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/surfaceMeshWriter.H b/src/conversion/vtk/output/foamVtkSurfaceMeshWriter.H
similarity index 57%
rename from applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/surfaceMeshWriter.H
rename to src/conversion/vtk/output/foamVtkSurfaceMeshWriter.H
index 0a5589c26e7edbe6866388d9bb55936b45d02d37..bf5de51327b169a3c16847ba095683a739482bb0 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/surfaceMeshWriter.H
+++ b/src/conversion/vtk/output/foamVtkSurfaceMeshWriter.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) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -22,47 +22,77 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    Foam::surfaceMeshWriter
+    Foam::vtk::surfaceMeshWriter
 
 Description
     Write faces with fields
 
 SourceFiles
-    surfaceMeshWriter.C
-    surfaceMeshWriterTemplates.C
+    foamVtkSurfaceMeshWriter.C
+    foamVtkSurfaceMeshWriterTemplates.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef surfaceMeshWriter_H
-#define surfaceMeshWriter_H
+#ifndef foamVtkSurfaceMeshWriter_H
+#define foamVtkSurfaceMeshWriter_H
 
 #include "pointMesh.H"
 #include "OFstream.H"
 #include "volFields.H"
 #include "surfaceFields.H"
 #include "indirectPrimitivePatch.H"
+#include "foamVtkOutputOptions.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
-
 class volPointInterpolation;
 
+namespace vtk
+{
+
 /*---------------------------------------------------------------------------*\
                       Class surfaceMeshWriter Declaration
 \*---------------------------------------------------------------------------*/
 
 class surfaceMeshWriter
 {
-    const bool binary_;
+    // Private Member Data
+
+        const indirectPrimitivePatch& pp_;
+
+        //- Commonly used query
+        const bool legacy_;
+
+        autoPtr<vtk::formatter> format_;
+
+        std::ofstream os_;
+
 
-    const indirectPrimitivePatch& pp_;
+    // Private Member Functions
 
-    const fileName fName_;
+        //- Begin piece
+        void beginPiece();
 
-    std::ofstream os_;
+        //- Write patch points
+        void writePoints();
 
+        //- Write patch faces
+        void writePolysLegacy();
+
+        //- Write patch faces
+        void writePolys();
+
+        //- Write mesh topology
+        void writeMesh();
+
+
+        //- Disallow default bitwise copy construct
+        surfaceMeshWriter(const surfaceMeshWriter&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const surfaceMeshWriter&) = delete;
 
 public:
 
@@ -71,47 +101,81 @@ public:
         //- Construct from components
         surfaceMeshWriter
         (
-            const bool binary,
             const indirectPrimitivePatch& pp,
             const word& name,
-            const fileName&
+            const fileName& baseName,
+            const vtk::outputOptions outOpts
         );
 
 
+    //- Destructor
+    ~surfaceMeshWriter();
+
+
     // Member Functions
 
-        std::ofstream& os()
+        inline std::ofstream& os()
         {
             return os_;
         }
 
-        //- Extract face data
+        inline vtk::formatter& format()
+        {
+            return format_();
+        }
+
+        //- Open write for CellData of count fields.
+        //  The parameters are only used for the legacy format.
+        void beginCellData(label nFields);
+
+        //- Close write for CellData
+        void endCellData();
+
+        //- Write file footer
+        void writeFooter();
+
+
+        //- Get face field (internal face or boundary face)
         template<class Type>
         tmp<Field<Type>> getFaceField
         (
-            const GeometricField<Type, fvsPatchField, surfaceMesh>&
+            const GeometricField<Type, fvsPatchField, surfaceMesh>& sfld
         ) const;
 
-        //- Write surfaceFields
+
+      // Write fields (individually)
+
+        //- Write surface field
+        template<class Type>
+        void write
+        (
+            const GeometricField<Type, fvsPatchField, surfaceMesh>& field
+        );
+
+
+      // Write fields (collectively)
+
+        //- Write surface fields
         template<class Type>
         void write
         (
             const UPtrList
             <
                 const GeometricField<Type, fvsPatchField, surfaceMesh>
-            >&
+            >& sflds
         );
 };
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace vtk
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 #ifdef NoRepository
-    #include "surfaceMeshWriterTemplates.C"
+    #include "foamVtkSurfaceMeshWriterTemplates.C"
 #endif
 
 
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/surfaceMeshWriterTemplates.C b/src/conversion/vtk/output/foamVtkSurfaceMeshWriterTemplates.C
similarity index 65%
rename from applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/surfaceMeshWriterTemplates.C
rename to src/conversion/vtk/output/foamVtkSurfaceMeshWriterTemplates.C
index 92d878f2292b534fe915f2c5e8bae4ed2056fff2..1b459b3bd9626b616669276d1843d7670da733f4 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/surfaceMeshWriterTemplates.C
+++ b/src/conversion/vtk/output/foamVtkSurfaceMeshWriterTemplates.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  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -23,14 +23,13 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "surfaceMeshWriter.H"
-#include "writeFuns.H"
+#include "foamVtkSurfaceMeshWriter.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 template<class Type>
 Foam::tmp<Foam::Field<Type>>
-Foam::surfaceMeshWriter::getFaceField
+Foam::vtk::surfaceMeshWriter::getFaceField
 (
     const GeometricField<Type, fvsPatchField, surfaceMesh>& sfld
 ) const
@@ -42,9 +41,8 @@ Foam::surfaceMeshWriter::getFaceField
 
     forAll(pp_.addressing(), i)
     {
-        label facei = pp_.addressing()[i];
-
-        label patchi = patches.whichPatch(facei);
+        const label facei = pp_.addressing()[i];
+        const label patchi = patches.whichPatch(facei);
 
         if (patchi == -1)
         {
@@ -52,7 +50,7 @@ Foam::surfaceMeshWriter::getFaceField
         }
         else
         {
-            label localFacei = facei - patches[patchi].start();
+            const label localFacei = facei - patches[patchi].start();
             fld[i] = sfld.boundaryField()[patchi][localFacei];
         }
     }
@@ -62,7 +60,38 @@ Foam::surfaceMeshWriter::getFaceField
 
 
 template<class Type>
-void Foam::surfaceMeshWriter::write
+void Foam::vtk::surfaceMeshWriter::write
+(
+    const GeometricField<Type, fvsPatchField, surfaceMesh>& field
+)
+{
+    const int nCmpt(pTraits<Type>::nComponents);
+    const uint64_t payLoad(pp_.size() * nCmpt * sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::floatField(os(), field.name(), nCmpt, pp_.size());
+    }
+    else
+    {
+        format().openDataArray<float, nCmpt>(field.name())
+            .closeTag();
+    }
+
+    format().writeSize(payLoad);
+    vtk::writeList(format(), getFaceField(field)());
+
+    format().flush();
+
+    if (!legacy_)
+    {
+        format().endDataArray();
+    }
+}
+
+
+template<class Type>
+void Foam::vtk::surfaceMeshWriter::write
 (
     const UPtrList
     <
@@ -70,18 +99,9 @@ void Foam::surfaceMeshWriter::write
     >& sflds
 )
 {
-    forAll(sflds, fieldi)
+    for (const auto& field : sflds)
     {
-        const GeometricField<Type, fvsPatchField, surfaceMesh>& fld =
-            sflds[fieldi];
-
-        os_ << fld.name() << ' '
-            << int(pTraits<Type>::nComponents) << ' '
-            << pp_.size() << " float" << std::endl;
-
-        DynamicList<floatScalar> fField(pTraits<Type>::nComponents*pp_.size());
-        writeFuns::insert(getFaceField(fld)(), fField);
-        writeFuns::write(os_, binary_, fField);
+        write(field);
     }
 }
 
diff --git a/src/conversion/vtk/output/foamVtkWriteSurfFields.C b/src/conversion/vtk/output/foamVtkWriteSurfFields.C
new file mode 100644
index 0000000000000000000000000000000000000000..40c99456a1c6bd0bf4df0184966afb643f5a4f1e
--- /dev/null
+++ b/src/conversion/vtk/output/foamVtkWriteSurfFields.C
@@ -0,0 +1,172 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "foamVtkWriteSurfFields.H"
+#include "OFstream.H"
+#include "emptyFvsPatchFields.H"
+#include "fvsPatchFields.H"
+#include "surfaceFields.H"
+#include "foamVtkOutput.H"
+
+// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
+
+void Foam::vtk::writeSurfFields
+(
+    const fvMesh& mesh,
+    const fileName& baseName,
+    const vtk::outputOptions outOpts,
+    const UPtrList<const surfaceVectorField>& surfVectorFields
+)
+{
+    outputOptions opts(outOpts);
+    opts.append(false);  // No append supported
+
+    const bool legacy_(opts.legacy());
+
+    std::ofstream os((baseName + (legacy_ ? ".vtk" : ".vtp")).c_str());
+    autoPtr<vtk::formatter> format = opts.newFormatter(os);
+
+    // Same payload size for points and vector fields!
+    const int nCmpt(3);  // vector
+    const uint64_t payLoad(mesh.nFaces() * 3 * sizeof(float));
+
+    if (legacy_)
+    {
+        legacy::fileHeader(format(), "surfaceFields", vtk::fileTag::POLY_DATA);
+        legacy::beginPoints(os, mesh.nFaces());
+    }
+    else
+    {
+        // XML (inline)
+
+        format()
+            .xmlHeader()
+            .xmlComment("surfaceFields")
+            .beginVTKFile(vtk::fileTag::POLY_DATA, "0.1");
+
+        // Tricky - hide in beginPiece()
+        format()
+            .openTag(vtk::fileTag::PIECE)
+            .xmlAttr(vtk::fileAttr::NUMBER_OF_POINTS, mesh.nFaces())
+            .closeTag();
+
+        format().tag(vtk::fileTag::POINTS)
+            .openDataArray<float,3>(vtk::dataArrayAttr::POINTS)
+            .closeTag();
+    }
+
+    const pointField& fc = mesh.faceCentres();
+
+    format().writeSize(payLoad);
+    vtk::writeList(format(), fc);
+    format().flush();
+
+    if (!legacy_)
+    {
+        format()
+            .endDataArray()
+            .endTag(vtk::fileTag::POINTS);
+    }
+
+
+    // Fields
+    if (legacy_)
+    {
+        legacy::dataHeader
+        (
+            os,
+            vtk::fileTag::POINT_DATA,
+            mesh.nFaces(),
+            surfVectorFields.size()
+        );
+    }
+    else
+    {
+        format().tag(vtk::fileTag::POINT_DATA);
+    }
+
+    // surfVectorFields
+    forAll(surfVectorFields, fieldi)
+    {
+        const auto& fld = surfVectorFields[fieldi];
+
+        if (legacy_)
+        {
+            legacy::floatField(os, fld.name(), nCmpt, mesh.nFaces());
+        }
+        else
+        {
+            format().openDataArray<float, nCmpt>(fld.name())
+                .closeTag();
+        }
+
+        format().writeSize(payLoad);
+
+        for (label facei=0; facei < mesh.nInternalFaces(); ++facei)
+        {
+            vtk::write(format(), fld[facei]);
+        }
+
+        forAll(fld.boundaryField(), patchi)
+        {
+            const fvPatch& pp = mesh.boundary()[patchi];
+            const auto& pf = fld.boundaryField()[patchi];
+
+            if (isA<emptyFvsPatchVectorField>(pf))
+            {
+                // Note: loop over polypatch size, not fvpatch size.
+                forAll(pp.patch(), i)
+                {
+                    vtk::write(format(), vector::zero);
+                }
+            }
+            else
+            {
+                vtk::writeList(format(), pf);
+            }
+        }
+
+        format().flush();
+
+        if (!legacy_)
+        {
+            format().endDataArray();
+        }
+    }
+
+    if (!legacy_)
+    {
+        format().endTag(vtk::fileTag::POINT_DATA);
+
+        // slight cheat. </Piece> too
+        format().endTag(vtk::fileTag::PIECE);
+
+        format().endTag(vtk::fileTag::POLY_DATA)
+            .endVTKFile();
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeSurfFields.H b/src/conversion/vtk/output/foamVtkWriteSurfFields.H
similarity index 82%
rename from applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeSurfFields.H
rename to src/conversion/vtk/output/foamVtkWriteSurfFields.H
index 7740e15f78f48c3817ebfca37e8ab65b17eb3f44..ff7e77b00fd3886fe5f60a2e12b44c24ae523743 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeSurfFields.H
+++ b/src/conversion/vtk/output/foamVtkWriteSurfFields.H
@@ -21,38 +21,42 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
-InClass
-    Foam::writeSurfFields
+InNamespace
+    Foam::vtk
 
 Description
-    Write a patch with its data.
+    Write surface fields as vectors
 
 SourceFiles
-    writeSurfFields.C
+    foamVtkWriteSurfFields.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef writeSurfFields_H
-#define writeSurfFields_H
+#ifndef foamVtkWriteSurfFields_H
+#define foamVtkWriteSurfFields_H
 
 #include "fvMesh.H"
 #include "surfaceMesh.H"
 #include "surfaceFieldsFwd.H"
+#include "foamVtkOutputOptions.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
+namespace vtk
+{
 
-// Write surface vector fields
+//- Write surface vector fields
 void writeSurfFields
 (
-    const bool binary,
-    const fvMesh&,
-    const fileName& fileName,
+    const fvMesh& mesh,
+    const fileName& baseName,
+    const vtk::outputOptions outOpts,
     const UPtrList<const surfaceVectorField>& surfVectorFields
 );
 
+} // End namespace vtk
 } // End namespace Foam
 
 
diff --git a/src/conversion/vtk/part/foamVtkCells.C b/src/conversion/vtk/part/foamVtkCells.C
deleted file mode 100644
index 5846c8442d705359cd54460ce2668b80ca091588..0000000000000000000000000000000000000000
--- a/src/conversion/vtk/part/foamVtkCells.C
+++ /dev/null
@@ -1,649 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-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 "foamVtkCells.H"
-#include "polyMesh.H"
-#include "cellShape.H"
-#include "cellModeller.H"
-
-// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
-
-void Foam::foamVtkCells::correct()
-{
-    // Clear derived data
-    // clearGeom();
-
-    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& tetWedge = *(cellModeller::lookup("tetWedge"));
-    const cellModel& hex      = *(cellModeller::lookup("hex"));
-
-    const cellShapeList& cellShapes = mesh_.cellShapes();
-
-    // face owner is needed to determine the face orientation
-    const labelList& owner = mesh_.faceOwner();
-
-    // Unique vertex labels per polyhedral
-    HashSet<label> hashUniqId(2*256);
-
-    // =======================
-    // PASS 1: Determine sizes
-
-    label nVertLabels = 0;
-    label nFaceLabels = 0;
-    label nAddPoints  = 0;
-    label nAddCells   = 0;
-    label nAddVerts   = 0;
-
-    forAll(cellShapes, cellI)
-    {
-        const cellShape& shape = cellShapes[cellI];
-        const cellModel& model = shape.model();
-
-        if
-        (
-            model == tet
-         || model == pyr
-         || model == prism
-         || model == hex
-        )
-        {
-            // normal primitives
-            nVertLabels += shape.size();
-        }
-        else if (model == tetWedge && decompose_.requested())
-        {
-            // Treat as squeezed prism (VTK_WEDGE)
-            nVertLabels += 6;
-        }
-        else if (model == wedge && decompose_.requested())
-        {
-            // Treat as squeezed hex
-            nVertLabels += 8;
-        }
-        else if (decompose_.requested())
-        {
-            // Polyhedral: Decompose into tets + pyramids.
-
-            // Count vertices in first decomposed cell
-            bool first = true;
-
-            const cell& cFaces = mesh_.cells()[cellI];
-            forAll(cFaces, cFaceI)
-            {
-                const face& f = mesh_.faces()[cFaces[cFaceI]];
-
-                // Face decomposed into triangles and quads
-                // Tri -> Tet, Quad -> Pyr
-                label nTria = 0, nQuad = 0;
-                f.nTrianglesQuads(mesh_.points(), nTria, nQuad);
-
-                nAddCells  += nTria + nQuad;
-                nAddVerts  += (nTria * 4) + (nQuad * 5);
-
-                if (first)
-                {
-                    const label nvrt = (nQuad ? 5 : 4);
-                    nAddCells--;
-                    nAddVerts   -= nvrt;
-                    nVertLabels += nvrt;
-
-                    first = false;
-                }
-            }
-
-            ++nAddPoints;
-        }
-        else
-        {
-            // Polyhedral: Not decomposed.
-
-            const labelList& cFaces = mesh_.cells()[cellI];
-
-            // establish unique node ids used (only needed for XML)
-            hashUniqId.clear();
-
-            // determing sizing for face stream
-            // number of faces, size of each face, vertices per face
-            // [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
-
-            forAll(cFaces, cFaceI)
-            {
-                const face& f = mesh_.faces()[cFaces[cFaceI]];
-                nFaceLabels += f.size();
-
-                forAll(f, fp)
-                {
-                    hashUniqId.insert(f[fp]);
-                }
-            }
-
-            nVertLabels += hashUniqId.size();
-            nFaceLabels += 1 + cFaces.size();
-        }
-    }
-
-
-    //
-    // adjust/reserve sizes
-    //
-
-    // Cell types (including added cells) in vtk numbering
-    cellTypes_.setSize(cellShapes.size() + nAddCells);
-
-    // List of vertex labels in VTK ordering
-    vertLabels_.setSize(nVertLabels + nAddVerts);
-
-    vertOffset_.setSize(cellShapes.size() + nAddCells);
-
-    faceLabels_.clear();
-    faceOffset_.clear();
-    if (nFaceLabels)
-    {
-        faceLabels_.setSize(nFaceLabels);
-
-        // only need nCells (without nAddCells)
-        // set to -1 (primitive)
-        faceOffset_.setSize(cellShapes.size(), -1);
-    }
-
-    if (decompose_.requested())
-    {
-        decompose_.addPointCellLabels_.setSize(nAddPoints);
-        decompose_.superCells_.setSize(nAddCells);
-    }
-
-
-    // ======================
-    // PASS 2: Fill in arrays
-
-    // Need this offset later, but only for decomposed polys
-    const label offsetAddVerts = nVertLabels;
-
-    // Reset counters
-    nVertLabels = 0;
-    nFaceLabels = 0;
-    nAddPoints  = 0;
-    nAddCells   = 0;
-    nAddVerts   = 0;
-
-    forAll(cellShapes, cellI)
-    {
-        const cellShape& shape = cellShapes[cellI];
-        const cellModel& model = shape.model();
-
-        if (model == tet)
-        {
-            cellTypes_[cellI] = foamVtkCore::VTK_TETRA;
-            forAll(shape, i)
-            {
-                vertLabels_[nVertLabels++] = shape[i];
-            }
-            vertOffset_[cellI] = nVertLabels;
-        }
-        else if (model == pyr)
-        {
-            cellTypes_[cellI] = foamVtkCore::VTK_PYRAMID;
-            forAll(shape, i)
-            {
-                vertLabels_[nVertLabels++] = shape[i];
-            }
-            vertOffset_[cellI] = nVertLabels;
-        }
-        else if (model == hex)
-        {
-            cellTypes_[cellI] = foamVtkCore::VTK_HEXAHEDRON;
-            forAll(shape, i)
-            {
-                vertLabels_[nVertLabels++] = shape[i];
-            }
-            vertOffset_[cellI] = nVertLabels;
-        }
-        else if (model == prism)
-        {
-            cellTypes_[cellI] = foamVtkCore::VTK_WEDGE;
-
-            // VTK_WEDGE triangles point outwards (swap 1<->2, 4<->5)
-            vertLabels_[nVertLabels++] = shape[0];
-            vertLabels_[nVertLabels++] = shape[2];
-            vertLabels_[nVertLabels++] = shape[1];
-            vertLabels_[nVertLabels++] = shape[3];
-            vertLabels_[nVertLabels++] = shape[5];
-            vertLabels_[nVertLabels++] = shape[4];
-
-            vertOffset_[cellI] = nVertLabels;
-        }
-        else if (model == tetWedge && decompose_.requested())
-        {
-            // Treat as squeezed prism (VTK_WEDGE)
-            cellTypes_[cellI] = foamVtkCore::VTK_WEDGE;
-
-            vertLabels_[nVertLabels++] = shape[0];
-            vertLabels_[nVertLabels++] = shape[2];
-            vertLabels_[nVertLabels++] = shape[1];
-            vertLabels_[nVertLabels++] = shape[3];
-            vertLabels_[nVertLabels++] = shape[4];
-            vertLabels_[nVertLabels++] = shape[3];
-
-            vertOffset_[cellI] = nVertLabels;
-        }
-        else if (model == wedge && decompose_.requested())
-        {
-            // Treat as squeezed hex
-            cellTypes_[cellI] = foamVtkCore::VTK_HEXAHEDRON;
-
-            vertLabels_[nVertLabels++] = shape[0];
-            vertLabels_[nVertLabels++] = shape[1];
-            vertLabels_[nVertLabels++] = shape[2];
-            vertLabels_[nVertLabels++] = shape[2];
-            vertLabels_[nVertLabels++] = shape[3];
-            vertLabels_[nVertLabels++] = shape[4];
-            vertLabels_[nVertLabels++] = shape[5];
-            vertLabels_[nVertLabels++] = shape[6];
-
-            vertOffset_[cellI] = nVertLabels;
-        }
-        else if (decompose_.requested())
-        {
-            // Polyhedral cell - decompose into tet/pyr.
-
-            // Ensure we have the correct orientation for the base of the
-            // primitive cell shape.
-            // If the cell is face owner, the orientation needs to be flipped
-            // to avoid defining negative cells.
-            // VTK doesn't seem to care, but we'll do it anyhow for safety.
-
-            // The new vertex from the cell-centre
-            const label newVertexLabel = mesh_.nPoints() + nAddPoints;
-
-            // Mapping from additional point to cell
-            decompose_.addPointCellLabels_[nAddPoints++] = cellI;
-
-            // Whether to insert cell in place of original or not.
-            bool first = true;
-
-            const labelList& cFaces = mesh_.cells()[cellI];
-            forAll(cFaces, cFaceI)
-            {
-                const face& f = mesh_.faces()[cFaces[cFaceI]];
-                const bool isOwner = (owner[cFaces[cFaceI]] == cellI);
-
-                // Count triangles/quads in decomposition
-                label nTria = 0;
-                label nQuad = 0;
-                f.nTrianglesQuads(mesh_.points(), nTria, nQuad);
-
-                // Do actual decomposition
-                faceList faces3(nTria);
-                faceList faces4(nQuad);
-                nTria = 0, nQuad = 0;
-                f.trianglesQuads(mesh_.points(), nTria, nQuad, faces3, faces4);
-
-                forAll(faces4, fci)
-                {
-                    const face& quad = faces4[fci];
-
-                    label celLoc;
-                    label vrtLoc;
-
-                    if (first)
-                    {
-                        celLoc = cellI;
-                        vrtLoc = nVertLabels;
-                        nVertLabels += 5;
-
-                        vertOffset_[celLoc] = nVertLabels;
-                        first = false;
-                    }
-                    else
-                    {
-                        celLoc = mesh_.nCells() + nAddCells;
-                        vrtLoc = offsetAddVerts  + nAddVerts;
-                        nAddVerts += 5;
-
-                        vertOffset_[celLoc] = nAddVerts;
-                        decompose_.superCells_[nAddCells++] = cellI;
-                    }
-
-                    cellTypes_[celLoc] = foamVtkCore::VTK_PYRAMID;
-
-                    // See note above about the orientation.
-                    if (isOwner)
-                    {
-                        vertLabels_[vrtLoc++] = quad[3];
-                        vertLabels_[vrtLoc++] = quad[2];
-                        vertLabels_[vrtLoc++] = quad[1];
-                        vertLabels_[vrtLoc++] = quad[0];
-                    }
-                    else
-                    {
-                        vertLabels_[vrtLoc++] = quad[0];
-                        vertLabels_[vrtLoc++] = quad[1];
-                        vertLabels_[vrtLoc++] = quad[2];
-                        vertLabels_[vrtLoc++] = quad[3];
-                    }
-
-                    vertLabels_[vrtLoc++] = newVertexLabel;
-                }
-
-                forAll(faces3, fci)
-                {
-                    const face& tria = faces3[fci];
-
-                    label celLoc;
-                    label vrtLoc;
-
-                    if (first)
-                    {
-                        celLoc = cellI;
-                        vrtLoc = nVertLabels;
-                        nVertLabels += 4;
-
-                        vertOffset_[celLoc] = nVertLabels;
-                        first = false;
-                    }
-                    else
-                    {
-                        celLoc = mesh_.nCells() + nAddCells;
-                        vrtLoc = offsetAddVerts + nAddVerts;
-                        nAddVerts += 4;
-
-                        vertOffset_[celLoc] = nAddVerts;
-                        decompose_.superCells_[nAddCells++] = cellI;
-                    }
-
-                    cellTypes_[celLoc] = foamVtkCore::VTK_TETRA;
-
-                    // See note above about the orientation.
-                    if (isOwner)
-                    {
-                        vertLabels_[vrtLoc++] = tria[2];
-                        vertLabels_[vrtLoc++] = tria[1];
-                        vertLabels_[vrtLoc++] = tria[0];
-                    }
-                    else
-                    {
-                        vertLabels_[vrtLoc++] = tria[0];
-                        vertLabels_[vrtLoc++] = tria[1];
-                        vertLabels_[vrtLoc++] = tria[2];
-                    }
-                    vertLabels_[vrtLoc++] = newVertexLabel;
-                }
-            }
-        }
-        else
-        {
-            // Polyhedral cell - not decomposed
-
-            hashUniqId.clear();  // unique node ids used (only needed for XML)
-
-            // face-stream
-            //   [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
-
-            cellTypes_[cellI] = foamVtkCore::VTK_POLYHEDRON;
-            const labelList& cFaces = mesh_.cells()[cellI];
-
-            faceLabels_[nFaceLabels++] = cFaces.size();
-
-            forAll(cFaces, cFaceI)
-            {
-                const face& f = mesh_.faces()[cFaces[cFaceI]];
-                const bool isOwner = (owner[cFaces[cFaceI]] == cellI);
-
-                forAll(f, fp)
-                {
-                    hashUniqId.insert(f[fp]);
-                }
-
-                // number of labels for this face
-                faceLabels_[nFaceLabels++] = f.size();
-
-                if (isOwner)
-                {
-                    forAll(f, fp)
-                    {
-                        faceLabels_[nFaceLabels++] = f[fp];
-                    }
-                }
-                else
-                {
-                    // fairly immaterial if we reverse the list
-                    // or use face::reverseFace()
-                    forAllReverse(f, fp)
-                    {
-                        faceLabels_[nFaceLabels++] = f[fp];
-                    }
-                }
-            }
-
-            faceOffset_[cellI] = nFaceLabels;
-
-            const labelList uniq = hashUniqId.sortedToc();
-            forAll(uniq, i)
-            {
-                vertLabels_[nVertLabels++] = uniq[i];
-            }
-
-            vertOffset_[cellI] = nVertLabels;
-        }
-    }
-
-    // ===========================================
-    // PASS 3: Repair offsets for additional cells
-
-//     Info<<"vertOffset: " << vertOffset_.size() << " VS. " << (mesh_.nCells()) << endl;
-//     Info<<"nAddCells: "  << nAddCells << " VS. " << (mesh_.nCells()) << endl;
-
-    if (nAddCells)
-    {
-        const label beg = mesh_.nCells();
-        const label add = vertOffset_[beg-1];
-
-        for (label i = beg; i < vertOffset_.size(); ++i)
-        {
-            vertOffset_[i] += add;
-        }
-    }
-
-    // Some basic programming/sanity checks
-
-    if ((nVertLabels + nAddVerts) != vertOffset_[mesh_.nCells()-1 + nAddCells])
-    {
-        WarningInFunction
-            << "predicted offsets (" << nVertLabels << " + " << nAddVerts << ") != "
-            << vertOffset_[mesh_.nCells()-1 + nAddCells]
-            << endl;
-    }
-
-    if (offsetAddVerts != vertOffset_[mesh_.nCells()-1])
-    {
-        WarningInFunction
-            << "predicted regular offset " << offsetAddVerts
-            << " != " << vertOffset_[mesh_.nCells()]
-            << endl;
-    }
-
-    // nFaceLabels = 0;
-    // nAddPoints  = 0;
-    // nAddCells   = 0;
-
-    // Pout<<"vertLabels: " << vertLabels_.size() << " vs. " << (nVertLabels + nAddVerts) << endl;
-    // Pout<<"faceLabels: " << faceLabels_.size() << " vs. " << nFaceLabels << endl;
-#if 0
-    if (decompose_.requested())
-    {
-        Pout<< "    Original cells:" << mesh_.nCells()
-            << " points:" << mesh_.nPoints()
-            << " Additional cells:" << decompose_.superCells_.size()
-            << " additional points:" << decompose_.addPointCellLabels_.size()
-            << nl << endl;
-    }
-#endif
-}
-
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::foamVtkCells::decomp::decomp(const bool decomposePoly)
-:
-    addPointCellLabels_(),
-    superCells_(),
-    pointMap_(),
-    requested_(decomposePoly)
-{}
-
-
-Foam::foamVtkCells::foamVtkCells
-(
-    const polyMesh& mesh,
-    const bool decomposePoly,
-    const bool lazy
-)
-:
-    mesh_(mesh),
-    cellTypes_(),
-    vertLabels_(),
-    vertOffset_(),
-    faceLabels_(),
-    faceOffset_(),
-    decompose_(decomposePoly),
-    needsUpdate_(true)
-{
-    if (!lazy)
-    {
-        correct();
-    }
-}
-
-
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::foamVtkCells::decomp::~decomp()
-{}
-
-
-Foam::foamVtkCells::~foamVtkCells()
-{}
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-
-void Foam::foamVtkCells::decomp::clear()
-{
-    superCells_.clear();
-    addPointCellLabels_.clear();
-    pointMap_.clear();
-}
-
-
-Foam::label Foam::foamVtkCells::nFieldPoints() const
-{
-    return mesh_.nPoints() + decompose_.addPointCellLabels_.size();
-}
-
-
-Foam::label Foam::foamVtkCells::legacyCellPayLoad() const
-{
-    label payLoad = cellTypes_.size();
-
-    if (faceOffset_.size())
-    {
-        // also has polys with face streams
-
-        label begVert = 0;
-        label begFace = 0;
-
-        forAll(faceOffset_, i)
-        {
-            label endFace = faceOffset_[i];
-            label endVert = vertOffset_[i];
-
-            if (endFace > 0)
-            {
-                // poly with face stream
-                payLoad += endFace - begFace;
-
-                begFace = endFace;
-            }
-            else
-            {
-                // primitive without face stream
-                payLoad += endVert - begVert;
-            }
-            begVert = endVert;
-        }
-    }
-    else if (vertOffset_.size())
-    {
-        // primitives only, trivial
-        payLoad += vertOffset_[vertOffset_.size()-1];
-    }
-
-    return payLoad;
-}
-
-
-bool Foam::foamVtkCells::needsUpdate() const
-{
-    return needsUpdate_;
-}
-
-
-bool Foam::foamVtkCells::expire()
-{
-    // Clear any stored topologies
-
-    // Clear derived data
-    // clearGeom();
-
-    // already marked as expired
-    if (needsUpdate_)
-    {
-        return false;
-    }
-
-    needsUpdate_ = true;
-    return true;
-}
-
-
-bool Foam::foamVtkCells::update()
-{
-    if (!needsUpdate_)
-    {
-        return false;
-    }
-
-    correct();
-
-    needsUpdate_ = false;
-    return true;
-}
-
-
-// ************************************************************************* //
diff --git a/src/conversion/vtk/part/foamVtkCells.H b/src/conversion/vtk/part/foamVtkCells.H
deleted file mode 100644
index 692614a4b9b98e272062fb199751cde0c37980be..0000000000000000000000000000000000000000
--- a/src/conversion/vtk/part/foamVtkCells.H
+++ /dev/null
@@ -1,350 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-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::foamVtkCells
-
-Description
-    The deep-copy description of an OpenFOAM volume mesh in data structures
-    corresponding to an VTK UnstructuredGrid, including the possiblity of
-    decomposing polyhedral cells into primitive cell types.
-
-    Knowledge of the vtkUnstructuredGrid and the corresponding \c .vtu
-    xml file-format aids in understanding this class.
-    For flexibilty, support for the legacy vtk file-format is also provided.
-
-    Primitive cell types are straighforward, polyhedral cells are represented
-    by a face stream:
-    \verbatim
-        [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
-    \endverbatim
-
-    For the legacy format, the face stream is simply passed as vertex labels
-    (connectivity).
-
-    For the xml format, the face stream is saved separately:
-    \verbatim
-        "connectivity"
-        == the unique vertex labels used by the cell (optionally sorted).
-
-        "offsets":
-        == offset + sizeof(connectivity)
-
-        "faces":
-        [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
-
-        "faceoffsets":
-        == faceoffsets + sizeof(faces)
-    \endverbatim
-
-    The storage of "connectivity" and "offsets" strongly resembles a
-    CompactListList, but the "offsets" point to the end of the respective
-    sub-lists.
-
-SourceFiles
-    foamVtkCells.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef foamVtkCells_H
-#define foamVtkCells_H
-
-#include "foamVtkCore.H"
-#include "DynamicList.H"
-#include "SubList.H"
-#include "labelList.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-// Forward declaration of classes
-class polyMesh;
-
-/*---------------------------------------------------------------------------*\
-                      Class foamVtkCells Declaration
-\*---------------------------------------------------------------------------*/
-
-class foamVtkCells
-:
-    public fileFormats::foamVtkCore
-{
-public:
-
-    //- Bookkeeping for polyhedral cell decomposition
-    class decomp
-    {
-    private:
-        friend foamVtkCells;
-
-        // Private data
-
-            //- Cell-centre labels for additional points of decomposed cells
-            DynamicList<label> addPointCellLabels_;
-
-            //- Label of original cell for decomposed cells
-            DynamicList<label> superCells_;
-
-            //- Point labels for subsetted meshes
-            DynamicList<label> pointMap_;
-
-            //- Track if decomposition was requested
-            const bool requested_;
-
-
-        // Private Member Functions
-
-            //- Disallow default bitwise copy construct
-            decomp(const decomp&) = delete;
-
-            //- Disallow default bitwise assignment
-            void operator=(const decomp&) = delete;
-
-    public:
-
-        // Constructors
-
-            //- Construct null
-            decomp(const bool decomposePoly = false);
-
-
-        //- Destructor
-        ~decomp();
-
-
-        // Member Functions
-
-        // Access
-
-            //- Polyhedral decomposition requested
-            inline bool requested() const;
-
-            //- Polyhedral decomposition used
-            inline bool used() const;
-
-            //- Label of original cell for decomposed cells
-            inline const labelList& superCells() const;
-
-            //- Cell-centre labels for additional points of decomposed cells
-            inline const labelList& addPointCellLabels() const;
-
-            //- Point labels for subsetted meshes
-            inline const labelList& pointMap() const;
-
-
-        // Edit
-
-            //- Clear
-            void clear();
-    };
-
-
-private:
-
-    // Private data
-
-        //- Reference to underlying mesh or mesh sub-set
-        const polyMesh& mesh_;
-
-        //- Cell types (including added cells) in vtk numbering
-        //  Range is 1-255
-        List<uint8_t> cellTypes_;
-
-        //- Vertices per cell (including added cells) in vtk ordering
-        DynamicList<label> vertLabels_;
-
-        //- Vertices per cell (including added cells) in vtk ordering
-        DynamicList<label> vertOffset_;
-
-        //- Face lists per polyhedral cell
-        DynamicList<label> faceLabels_;
-
-        //- Face label offsets
-        DynamicList<label> faceOffset_;
-
-        //- Bookkeeping for polyhedral cell decomposition
-        decomp decompose_;
-
-        //- Needs update
-        bool needsUpdate_;
-
-
-
-    // Private Member Functions
-
-        //- Create the geometry
-        void correct();
-
-        //- Disallow default bitwise copy construct
-        foamVtkCells(const foamVtkCells&) = delete;
-
-        //- Disallow default bitwise assignment
-        void operator=(const foamVtkCells&) = delete;
-
-
-public:
-
-    // Constructors
-
-        //- Construct from components.
-        //  Optionally with polyhedral decomposition and/or lazy evaluation.
-        //  A 'lazy' evaluation avoids fully creation within the constructor.
-        foamVtkCells
-        (
-            const polyMesh&,
-            const bool decomposePoly = false,
-            const bool lazy = false
-        );
-
-
-    //- Destructor
-    ~foamVtkCells();
-
-
-    // Member Functions
-
-        // Access
-
-            //- Query the poly decompose flag.
-            inline bool decomposeRequested() const;
-
-            //- Values for "connectivity" (XML) or basis for "CELLS" (legacy)
-            //  In the legacy format, the size (offset) must be prefixed.
-            inline const labelList& vertLabels() const;
-
-            //- Values for "offsets" (XML)
-            //  or sizes to prefix for for "CELLS" (legacy)
-            inline const labelList& vertOffsets() const;
-
-            //- Values for "types" (XML) and "CELL_TYPES" (legacy)
-            inline const List<uint8_t>& cellTypes() const;
-
-            //- Values for "faces" (XML)
-            inline const labelList& faceLabels() const;
-
-            //- Values for "faceoffsets" (XML)
-            inline const labelList& faceOffsets() const;
-
-            //- Additional point addressing (from added point to original cell)
-            inline const labelList& addPointCellLabels() const;
-
-            //- Additional cells mapping (from added cell to original cell)
-            inline const labelList& superCells() const;
-
-
-            //- Number of field cells
-            inline label nFieldCells() const;
-
-            //- Number of field points
-            label nFieldPoints() const;
-
-            //- The field size for legacy "CELLS".
-            //  In the legacy format, the size (offset) must be prefixed.
-            label legacyCellPayLoad() const;
-
-
-        //- Does the mapping need an update?
-        bool needsUpdate() const;
-
-        //- Mark as needing an update.
-        //  May also free up unneeded data.
-        //  Return false if it was already marked as expired.
-        bool expire();
-
-        //- Update the description (and decomposition) as required.
-        //  Do nothing (and return false) if no update was required
-        bool update();
-
-
-        //- The const_iterator for foamVtkCells
-        class const_iterator
-        {
-            friend class foamVtkCells;
-
-        protected:
-
-            // Protected Data
-
-                //- Reference to parent list
-                const foamVtkCells& parent_;
-
-                //- Element index
-                label index_;
-
-                //- Begin of connectivity sub-list
-                mutable label begVert_;
-
-                //- Begin of faces sub-list
-                mutable label begFace_;
-
-                //- On-demand legacy pointer
-                mutable autoPtr<SubList<label>> legacy_;
-
-
-            // Constructors
-
-                //- Construct begin/end iterator
-                inline const_iterator
-                (
-                    const foamVtkCells&,
-                    bool isEnd = false
-                );
-
-        public:
-
-            // Member operators
-
-                //- On-demand legacy cell labels (primitive or faces)
-                inline const labelUList& legacyCell() const;
-
-                //- Compare position
-                inline bool operator!=(const const_iterator&) const;
-
-                //- Pre-increment iterator
-                inline const_iterator& operator++();
-        };
-
-
-        //- const_iterator set to the beginning
-        inline const_iterator begin() const;
-
-        //- const_iterator set to beyond the end
-        inline const_iterator end() const;
-
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#include "foamVtkCellsI.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/src/conversion/vtk/part/foamVtkCellsI.H b/src/conversion/vtk/part/foamVtkCellsI.H
deleted file mode 100644
index 5973f5113e8de89c3630fa095c201fed966401ca..0000000000000000000000000000000000000000
--- a/src/conversion/vtk/part/foamVtkCellsI.H
+++ /dev/null
@@ -1,239 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  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 "foamVtkCells.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-inline bool Foam::foamVtkCells::decomp::requested() const
-{
-    return requested_;
-}
-
-
-inline bool Foam::foamVtkCells::decomp::used() const
-{
-    return !superCells_.empty();
-}
-
-
-inline const Foam::labelList&
-Foam::foamVtkCells::decomp::superCells() const
-{
-    return superCells_;
-}
-
-
-inline const Foam::labelList&
-Foam::foamVtkCells::decomp::addPointCellLabels() const
-{
-    return addPointCellLabels_;
-}
-
-
-inline const Foam::labelList&
-Foam::foamVtkCells::decomp::pointMap() const
-{
-    return pointMap_;
-}
-
-
-inline bool Foam::foamVtkCells::decomposeRequested() const
-{
-    return decompose_.requested();
-}
-
-
-inline const Foam::labelList&
-Foam::foamVtkCells::vertLabels() const
-{
-    return vertLabels_;
-}
-
-
-inline const Foam::labelList&
-Foam::foamVtkCells::vertOffsets() const
-{
-    return vertOffset_;
-}
-
-
-inline const Foam::List<uint8_t>&
-Foam::foamVtkCells::cellTypes() const
-{
-    return cellTypes_;
-}
-
-
-inline const Foam::labelList&
-Foam::foamVtkCells::faceLabels() const
-{
-    return faceLabels_;
-}
-
-
-inline const Foam::labelList&
-Foam::foamVtkCells::faceOffsets() const
-{
-    return faceOffset_;
-}
-
-
-inline const Foam::labelList&
-Foam::foamVtkCells::addPointCellLabels() const
-{
-    return decompose_.addPointCellLabels();
-}
-
-
-inline const Foam::labelList&
-Foam::foamVtkCells::superCells() const
-{
-    return decompose_.superCells();
-}
-
-
-inline Foam::label
-Foam::foamVtkCells::nFieldCells() const
-{
-    return cellTypes_.size();
-}
-
-
-inline Foam::foamVtkCells::const_iterator
-Foam::foamVtkCells::begin() const
-{
-    return const_iterator(*this);
-}
-
-
-inline Foam::foamVtkCells::const_iterator
-Foam::foamVtkCells::end() const
-{
-    return const_iterator(*this, true);
-}
-
-
-// * * * * * * * * * * * * * * * * Iterators * * * * * * * * * * * * * * * * //
-
-inline Foam::foamVtkCells::const_iterator::const_iterator
-(
-    const foamVtkCells& cells,
-    bool isEnd
-)
-:
-    parent_(cells),
-    index_(0),
-    begVert_(0),
-    begFace_(0),
-    legacy_()
-{
-    if (isEnd)
-    {
-        index_ = parent_.vertOffsets().size();
-    }
-}
-
-
-inline
-Foam::foamVtkCells::const_iterator&
-Foam::foamVtkCells::const_iterator::operator++()
-{
-    ++index_;
-    legacy_.clear();
-
-    return *this;
-}
-
-
-inline
-const Foam::UList<Foam::label>&
-Foam::foamVtkCells::const_iterator::legacyCell() const
-{
-    if
-    (
-        legacy_.valid()
-     || index_ >= parent_.vertOffsets().size()
-    )
-    {
-        return legacy_();
-    }
-
-    const label endVert = parent_.vertOffsets()[index_];
-
-    const label endFace =
-    (
-        parent_.faceOffsets().size()
-      ? parent_.faceOffsets()[index_]
-      : -1
-    );
-
-    if (endFace > 0)
-    {
-        // poly with face stream
-
-        legacy_.reset
-        (
-            new SubList<label>
-            (
-                parent_.faceLabels(),
-                endFace - begFace_,
-                begFace_
-            )
-        );
-
-        begFace_ = endFace;
-    }
-    else
-    {
-        // primitive without face stream
-        legacy_.reset
-        (
-            new SubList<label>
-            (
-                parent_.vertLabels(),
-                endVert - begVert_,
-                begVert_
-            )
-        );
-    }
-
-    begVert_ = endVert;
-
-    return legacy_();
-}
-
-
-inline bool
-Foam::foamVtkCells::const_iterator::operator!=
-(
-    const const_iterator& rhs
-) const
-{
-    return (index_ != rhs.index_);
-}
-
-
-// ************************************************************************* //
diff --git a/src/fileFormats/vtk/format/foamVtkOutputOptionsI.H b/src/conversion/vtk/part/foamVtkMeshMaps.C
similarity index 70%
rename from src/fileFormats/vtk/format/foamVtkOutputOptionsI.H
rename to src/conversion/vtk/part/foamVtkMeshMaps.C
index 0205f2f98ec87c5dba88223afb604310eb13407b..badc422df5065e3e0082cd3cf3442b181b6e22a3 100644
--- a/src/fileFormats/vtk/format/foamVtkOutputOptionsI.H
+++ b/src/conversion/vtk/part/foamVtkMeshMaps.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -23,33 +23,21 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-inline bool Foam::foamVtkOutputOptions::legacy() const
-{
-    return (type_ & LEGACY);
-}
-
-
-inline bool Foam::foamVtkOutputOptions::xml() const
-{
-    return !legacy();
-}
-
-
-inline bool Foam::foamVtkOutputOptions::append() const
-{
-    return (type_ & APPEND);
-}
+#include "foamVtkMeshMaps.H"
+#include "ListOps.H"
 
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-inline bool Foam::foamVtkOutputOptions::insitu() const
+void Foam::foamVtkMeshMaps::renumberCells(const UList<label>& mapping)
 {
-    return !(type_ & APPEND);
+    inplaceRenumber(mapping, cellMap_);
+    inplaceRenumber(mapping, additionalIds_);
 }
 
 
-inline bool Foam::foamVtkOutputOptions::ascii() const
+void Foam::foamVtkMeshMaps::renumberPoints(const UList<label>& mapping)
 {
-    return !(type_ & (BINARY | BASE64));
+    inplaceRenumber(mapping, pointMap_);
 }
 
 
diff --git a/src/conversion/vtk/part/foamVtkMeshMaps.H b/src/conversion/vtk/part/foamVtkMeshMaps.H
new file mode 100644
index 0000000000000000000000000000000000000000..737f02a2edfbf4f202eca1c291ea0af6cb4755ea
--- /dev/null
+++ b/src/conversion/vtk/part/foamVtkMeshMaps.H
@@ -0,0 +1,143 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 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::foamVtkMeshMaps
+
+Description
+    Bookkeeping for mesh subsetting and/or polyhedral cell decomposition.
+    Although the main use case is for handling vtk meshes, it is not specific
+    to VTK alone.
+
+    The cellMap is a local-to-global lookup for normal and decomposed cells.
+    The pointMap is an optional local-to-global lookup for point ids.
+    The additional ids is typically used to store the cell-centre labels
+    for additional points of decomposed cells
+
+SourceFiles
+    foamVtkMeshMapsI.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef foamVtkMeshMaps_H
+#define foamVtkMeshMaps_H
+
+#include "DynamicList.H"
+#include "labelList.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class foamVtkMeshMaps Declaration
+\*---------------------------------------------------------------------------*/
+
+class foamVtkMeshMaps
+{
+    // Private data
+
+        //- Original cell ids for all cells (regular and decomposed)
+        DynamicList<label> cellMap_;
+
+        //- Point labels for subsetted meshes
+        DynamicList<label> pointMap_;
+
+        //- Any additional (user) labels.
+        //  Eg, cell-centre labels for additional points of decomposed cells
+        DynamicList<label> additionalIds_;
+
+public:
+
+    // Constructors
+
+        //- Construct null
+        inline foamVtkMeshMaps(const label size = 0);
+
+
+    //- Destructor
+    inline ~foamVtkMeshMaps();
+
+
+    // Member Functions
+
+      // Access
+
+        //- Original cell ids for all cells (regular and decomposed).
+        //  A regular mesh comprising only primitive cell types, this will just
+        //  be an identity list. However, for subsetted meshes and decomposed
+        //  cells this becomes a useful means of mapping from the original mesh.
+        inline const labelList& cellMap() const;
+
+        //- Point labels for subsetted meshes
+        inline const labelList& pointMap() const;
+
+        //- Any additional (user) labels.
+        //  Eg, cell-centre labels for additional points of decomposed cells
+        inline const labelList& additionalIds() const;
+
+
+      // Edit
+
+        //- Clear
+        inline void clear();
+
+        //- Renumber cell ids (cellMap and additionalIds) to account for
+        //  subset meshes
+        void renumberCells(const UList<label>& mapping);
+
+        //- Renumber point ids (pointMap) to account for subset meshes
+        void renumberPoints(const UList<label>& mapping);
+
+
+        //- Original cell ids for all cells (regular and decomposed).
+        //  For a regular mesh comprising only primitive cell types, this
+        //  will simply be an identity list. However, for subsetted meshes
+        //  and decomposed cells this becomes a useful means of mapping from
+        //  the original mesh.
+        inline DynamicList<label>& cellMap();
+
+        //- Point labels for subsetted meshes
+        inline DynamicList<label>& pointMap();
+
+        //- Any additional (user) labels.
+        //  Eg, cell-centre labels for additional points of decomposed cells
+        inline DynamicList<label>& additionalIds();
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "foamVtkMeshMapsI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/surfaceMeshWriter.C b/src/conversion/vtk/part/foamVtkMeshMapsI.H
similarity index 52%
rename from applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/surfaceMeshWriter.C
rename to src/conversion/vtk/part/foamVtkMeshMapsI.H
index 367dd92e7a57c376031e8af2e5e61e5191832dcb..5f53fb25b2edf9e442920f0e441e8cd65853f946 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/surfaceMeshWriter.C
+++ b/src/conversion/vtk/part/foamVtkMeshMapsI.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -23,56 +23,73 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "surfaceMeshWriter.H"
-#include "writeFuns.H"
+#include "foamVtkMeshMaps.H"
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::surfaceMeshWriter::surfaceMeshWriter
-(
-    const bool binary,
-    const indirectPrimitivePatch& pp,
-    const word& name,
-    const fileName& fName
-)
+inline Foam::foamVtkMeshMaps::foamVtkMeshMaps(const label size)
 :
-    binary_(binary),
-    pp_(pp),
-    fName_(fName),
-    os_(fName.c_str())
+    cellMap_(size),
+    pointMap_(size),
+    additionalIds_(size)
+{}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+inline Foam::foamVtkMeshMaps::~foamVtkMeshMaps()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+inline void Foam::foamVtkMeshMaps::clear()
+{
+    cellMap_.clear();
+    pointMap_.clear();
+    additionalIds_.clear();
+}
+
+
+inline const Foam::labelList&
+Foam::foamVtkMeshMaps::cellMap() const
 {
-    // Write header
-    writeFuns::writeHeader(os_, binary_, name);
+    return cellMap_;
+}
 
-    os_ << "DATASET POLYDATA" << std::endl;
 
-    // Write topology
-    label nFaceVerts = 0;
+inline Foam::DynamicList<Foam::label>&
+Foam::foamVtkMeshMaps::cellMap()
+{
+    return cellMap_;
+}
 
-    forAll(pp, facei)
-    {
-        nFaceVerts += pp[facei].size() + 1;
-    }
 
-    os_ << "POINTS " << pp.nPoints() << " float" << std::endl;
+inline const Foam::labelList&
+Foam::foamVtkMeshMaps::pointMap() const
+{
+    return pointMap_;
+}
 
-    DynamicList<floatScalar> ptField(3*pp.nPoints());
-    writeFuns::insert(pp.localPoints(), ptField);
-    writeFuns::write(os_, binary, ptField);
 
+inline Foam::DynamicList<Foam::label>&
+Foam::foamVtkMeshMaps::pointMap()
+{
+    return pointMap_;
+}
 
-    os_ << "POLYGONS " << pp.size() << ' ' << nFaceVerts << std::endl;
 
-    DynamicList<label> vertLabels(nFaceVerts);
+inline const Foam::labelList&
+Foam::foamVtkMeshMaps::additionalIds() const
+{
+    return additionalIds_;
+}
 
-    forAll(pp, facei)
-    {
-        const face& f = pp.localFaces()[facei];
 
-        vertLabels.append(f.size());
-        writeFuns::insert(f, vertLabels);
-    }
-    writeFuns::write(os_, binary_, vertLabels);
+inline Foam::DynamicList<Foam::label>&
+Foam::foamVtkMeshMaps::additionalIds()
+{
+    return additionalIds_;
 }
 
 
diff --git a/src/conversion/vtk/part/foamVtuCells.C b/src/conversion/vtk/part/foamVtuCells.C
new file mode 100644
index 0000000000000000000000000000000000000000..962fa9b0ee8d49b99e03181741cf2cc8dce9fcac
--- /dev/null
+++ b/src/conversion/vtk/part/foamVtuCells.C
@@ -0,0 +1,186 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016-2017 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 "polyMesh.H"
+#include "foamVtuCells.H"
+#include "foamVtkOutputOptions.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::vtk::vtuCells::vtuCells
+(
+    const contentType output,
+    const bool decompose
+)
+:
+    vtk::vtuSizing(),
+    output_(output),
+    decomposeRequest_(decompose),
+    cellTypes_(),
+    vertLabels_(),
+    vertOffset_(),
+    faceLabels_(),
+    faceOffset_(),
+    maps_()
+{}
+
+
+Foam::vtk::vtuCells::vtuCells
+(
+    const polyMesh& mesh,
+    const contentType output,
+    const bool decompose
+)
+:
+    vtuCells(output, decompose)
+{
+    reset(mesh);
+}
+
+
+Foam::vtk::vtuCells::vtuCells
+(
+    const vtk::outputOptions outOpts,
+    const bool decompose
+)
+:
+    vtuCells
+    (
+        (outOpts.legacy() ? contentType::LEGACY : contentType::XML),
+        decompose
+    )
+{}
+
+
+Foam::vtk::vtuCells::vtuCells
+(
+    const polyMesh& mesh,
+    const vtk::outputOptions outOpts,
+    const bool decompose
+)
+:
+    vtuCells(outOpts, decompose)
+{
+    reset(mesh);
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::vtk::vtuCells::~vtuCells()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::vtk::vtuCells::clear()
+{
+    vtuSizing::clear();
+    cellTypes_.clear();
+    vertLabels_.clear();
+    vertOffset_.clear();
+    faceLabels_.clear();
+    faceOffset_.clear();
+
+    maps_.clear();
+}
+
+
+void Foam::vtk::vtuCells::reset(const polyMesh& mesh)
+{
+    vtuSizing::reset(mesh, decomposeRequest_);
+
+    cellTypes_.setSize(nFieldCells());
+    vertLabels_.setSize(sizeOf(output_, slotType::CELLS));
+    vertOffset_.setSize(sizeOf(output_, slotType::CELLS_OFFSETS));
+    faceLabels_.setSize(sizeOf(output_, slotType::FACES));
+    faceOffset_.setSize(sizeOf(output_, slotType::FACES_OFFSETS));
+
+    switch (output_)
+    {
+        case contentType::LEGACY:
+            populateLegacy
+            (
+                mesh,
+                cellTypes_,
+                vertLabels_,
+                maps_
+            );
+            break;
+        case contentType::XML:
+            populateXml
+            (
+                mesh,
+                cellTypes_,
+                vertLabels_,
+                vertOffset_,
+                faceLabels_,
+                faceOffset_,
+                maps_
+            );
+            break;
+        case contentType::INTERNAL:
+            populateInternal
+            (
+                mesh,
+                cellTypes_,
+                vertLabels_,
+                vertOffset_,
+                faceLabels_,
+                faceOffset_,
+                maps_
+            );
+            break;
+    }
+}
+
+
+void Foam::vtk::vtuCells::reset
+(
+    const polyMesh& mesh,
+    const enum contentType output,
+    const bool decompose
+)
+{
+    output_ = output;
+    decomposeRequest_ = decompose;
+
+    reset(mesh);
+}
+
+
+void Foam::vtk::vtuCells::renumberCells(const UList<label>& mapping)
+{
+    maps_.renumberCells(mapping);
+}
+
+
+void Foam::vtk::vtuCells::renumberPoints(const UList<label>& mapping)
+{
+    maps_.renumberPoints(mapping);
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/part/foamVtuCells.H b/src/conversion/vtk/part/foamVtuCells.H
new file mode 100644
index 0000000000000000000000000000000000000000..6c4c71c52424a52264ba58364eb8aff8652c4087
--- /dev/null
+++ b/src/conversion/vtk/part/foamVtuCells.H
@@ -0,0 +1,242 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2017 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::vtk::vtuCells
+
+Description
+    A deep-copy description of an OpenFOAM volume mesh in data structures
+    suitable for VTK UnstructuredGrid, including the possibility of
+    decomposing polyhedral cells into primitive cell types.
+
+    Knowledge of the vtkUnstructuredGrid and the corresponding \c .vtu
+    xml file-format aids in understanding this class.
+    The class can be used for the VTK xml format, legacy format, as well as a
+    VTK internal representation. The internal representation is somewhat
+    related to the xml format, but not entirely.
+
+SeeAlso
+    Foam::vtk::vtuSizing
+
+SourceFiles
+    foamVtuCells.C
+    foamVtuCellsI.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef foamVtuCells_H
+#define foamVtuCells_H
+
+#include "foamVtkCore.H"
+#include "foamVtkMeshMaps.H"
+#include "foamVtuSizing.H"
+#include "DynamicList.H"
+#include "labelList.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+class polyMesh;
+
+namespace vtk
+{
+// Forward declaration of classes
+    class outputOptions;
+
+/*---------------------------------------------------------------------------*\
+                     Class Foam::vtk::vtuCells Declaration
+\*---------------------------------------------------------------------------*/
+
+class vtuCells
+:
+    public vtuSizing
+{
+    // Private Member Data
+
+      // Requested output types
+
+        //- Output content type
+        contentType output_;
+
+        //- Bookkeeping for polyhedral cell decomposition
+        bool decomposeRequest_;
+
+      // Storage of output
+
+        //- Cell types (including added cells) in vtk numbering
+        //  Range is 1-255
+        List<uint8_t> cellTypes_;
+
+        //- Vertices per cell (including added cells) in vtk ordering
+        List<label> vertLabels_;
+
+        //- Connectivity (vertices) offset for the end of each cell
+        List<label> vertOffset_;
+
+        //- Face lists per polyhedral cell
+        List<label> faceLabels_;
+
+        //- Face label offsets
+        List<label> faceOffset_;
+
+        //- Bookkeeping for polyhedral cell decomposition
+        foamVtkMeshMaps maps_;
+
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        vtuCells(const vtuCells&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const vtuCells&) = delete;
+
+
+public:
+
+    // Constructors
+
+        //- Construct from components.
+        //  Optionally with polyhedral decomposition.
+        vtuCells
+        (
+            const enum contentType output = contentType::XML,
+            const bool decompose = false
+        );
+
+        //- Construct from components and create the output information
+        //  immediately
+        vtuCells
+        (
+            const polyMesh& mesh,
+            const enum contentType output = contentType::XML,
+            const bool decompose = false
+        );
+
+        //- Construct from components.
+        //  Optionally with polyhedral decomposition.
+        vtuCells
+        (
+            const vtk::outputOptions outOpts,
+            const bool decompose = false
+        );
+
+        //- Construct from components and create the output information
+        //  immediately
+        vtuCells
+        (
+            const polyMesh& mesh,
+            const vtk::outputOptions outOpts,
+            const bool decompose = false
+        );
+
+
+    //- Destructor
+    ~vtuCells();
+
+
+    // Member Functions
+
+      // Access
+
+        //- The output content type
+        inline enum contentType content() const;
+
+        //- Query the polyhedral decompose requested flag.
+        inline bool decomposeRequested() const;
+
+        //- True if no cellTypes are populated.
+        inline bool empty() const;
+
+        //- The size of populated cellTypes.
+        inline label size() const;
+
+
+      // Edit
+
+        //- Reset all sizes to zero.
+        void clear();
+
+        //- Create the geometry using the previously requested output and
+        //  decomposition types.
+        void reset(const polyMesh& mesh);
+
+        //- Respecify requested output and decomposition type prior to
+        //  creating the geometry
+        void reset
+        (
+            const polyMesh& mesh,
+            const enum contentType output,
+            const bool decompose
+        );
+
+        //- Renumber cell ids to account for subset meshes
+        void renumberCells(const UList<label>& mapping);
+
+        //- Renumber point ids to account for subset meshes
+        void renumberPoints(const UList<label>& mapping);
+
+
+      // Storage Access
+
+        //- Values for "types" (XML) and "CELL_TYPES" (legacy)
+        inline const List<uint8_t>& cellTypes() const;
+
+        //- Values for "connectivity" (XML) or "CELLS" (legacy)
+        inline const labelList& vertLabels() const;
+
+        //- Values for "offsets" (XML only)
+        inline const labelList& vertOffsets() const;
+
+        //- Values for "faces" (XML only)
+        inline const labelList& faceLabels() const;
+
+        //- Values for "faceoffset" (XML only)
+        inline const labelList& faceOffsets() const;
+
+        //- Additional point addressing (from added point to original cell)
+        inline const labelList& addPointCellLabels() const;
+
+        //- Original cell ids for all cells (regular and decomposed).
+        inline const labelList& cellMap() const;
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace vtk
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "foamVtuCellsI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/part/foamVtuCellsI.H b/src/conversion/vtk/part/foamVtuCellsI.H
new file mode 100644
index 0000000000000000000000000000000000000000..49cbe1871750f729b28c92c8abdc193747401e29
--- /dev/null
+++ b/src/conversion/vtk/part/foamVtuCellsI.H
@@ -0,0 +1,105 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016-2017 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 "foamVtuCells.H"
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+
+inline enum Foam::vtk::vtuCells::contentType
+Foam::vtk::vtuCells::content() const
+{
+    return output_;
+}
+
+
+inline bool Foam::vtk::vtuCells::decomposeRequested() const
+{
+    return decomposeRequest_;
+}
+
+
+inline bool Foam::vtk::vtuCells::empty() const
+{
+    return cellTypes_.empty();
+}
+
+
+inline Foam::label Foam::vtk::vtuCells::size() const
+{
+    return cellTypes_.size();
+}
+
+
+inline const Foam::List<uint8_t>&
+Foam::vtk::vtuCells::cellTypes() const
+{
+    return cellTypes_;
+}
+
+
+inline const Foam::labelList&
+Foam::vtk::vtuCells::vertLabels() const
+{
+    return vertLabels_;
+}
+
+
+inline const Foam::labelList&
+Foam::vtk::vtuCells::vertOffsets() const
+{
+    return vertOffset_;
+}
+
+
+inline const Foam::labelList&
+Foam::vtk::vtuCells::faceLabels() const
+{
+    return faceLabels_;
+}
+
+
+inline const Foam::labelList&
+Foam::vtk::vtuCells::faceOffsets() const
+{
+    return faceOffset_;
+}
+
+
+inline const Foam::labelList&
+Foam::vtk::vtuCells::addPointCellLabels() const
+{
+    return maps_.additionalIds();
+}
+
+
+inline const Foam::labelList&
+Foam::vtk::vtuCells::cellMap() const
+{
+    return maps_.cellMap();
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/part/foamVtuSizing.C b/src/conversion/vtk/part/foamVtuSizing.C
new file mode 100644
index 0000000000000000000000000000000000000000..15c4429380e88b494ef97dac0814d6c67b933384
--- /dev/null
+++ b/src/conversion/vtk/part/foamVtuSizing.C
@@ -0,0 +1,578 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016-2017 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 "foamVtuSizing.H"
+#include "foamVtkCore.H"
+#include "polyMesh.H"
+#include "cellShape.H"
+#include "cellModeller.H"
+
+// Only used in this file
+#include "foamVtuSizingTemplates.C"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::vtk::vtuSizing::presizeMaps(foamVtkMeshMaps& maps) const
+{
+    maps.cellMap().setSize(this->nFieldCells());
+    maps.additionalIds().setSize(this->nAddPoints());
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::vtk::vtuSizing::vtuSizing
+(
+    const polyMesh& mesh,
+    const bool decompose
+)
+{
+    clear();
+    reset(mesh, decompose);
+}
+
+
+Foam::vtk::vtuSizing::vtuSizing()
+{
+    clear();
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::vtk::vtuSizing::~vtuSizing()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::vtk::vtuSizing::reset
+(
+    const polyMesh& mesh,
+    const bool decompose
+)
+{
+    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& tetWedge = *(cellModeller::lookup("tetWedge"));
+    const cellModel& hex      = *(cellModeller::lookup("hex"));
+
+    const cellShapeList& shapes = mesh.cellShapes();
+
+    // Unique vertex labels per polyhedral
+    HashSet<label> hashUniqId(2*256);
+
+    decompose_ = decompose;
+    nCells_    = mesh.nCells();
+    nPoints_   = mesh.nPoints();
+    nAddCells_ = 0;
+    nAddVerts_ = 0;
+
+    nCellsPoly_  = nCells_;
+    nVertLabels_ = 0;
+    nFaceLabels_ = 0;
+    nVertPoly_   = 0;
+
+    forAll(shapes, celli)
+    {
+        const cellShape& shape = shapes[celli];
+        const cellModel& model = shape.model();
+
+        if
+        (
+            model == tet
+         || model == pyr
+         || model == prism
+         || model == hex
+        )
+        {
+            // Normal primitive - not a poly
+            --nCellsPoly_;
+            nVertLabels_ += shape.size();
+        }
+        else if (model == tetWedge && decompose)
+        {
+            nVertLabels_ += 6;  // Treat as squeezed prism (VTK_WEDGE)
+        }
+        else if (model == wedge && decompose)
+        {
+            nVertLabels_ += 8;  // Treat as squeezed hex
+        }
+        else if (decompose)
+        {
+            // Polyhedral: Decompose into tets + pyramids.
+            ++nAddPoints_;
+
+            // Count vertices into first decomposed cell
+            bool first = true;
+
+            const cell& cFaces = mesh.cells()[celli];
+            forAll(cFaces, cFaceI)
+            {
+                const face& f = mesh.faces()[cFaces[cFaceI]];
+
+                // Face decomposed into triangles and quads
+                // Tri -> Tet, Quad -> Pyr
+                label nTria = 0, nQuad = 0;
+                f.nTrianglesQuads(mesh.points(), nTria, nQuad);
+
+                nAddCells_ += nTria + nQuad;
+                nAddVerts_ += (nTria * 4) + (nQuad * 5);
+
+                if (first)
+                {
+                    first = false;
+                    --nAddCells_;
+
+                    const label nvrt = (nQuad ? 5 : 4);
+                    nAddVerts_   -= nvrt;
+                    nVertLabels_ += nvrt;
+                }
+            }
+        }
+        else
+        {
+            // Polyhedral: Not decomposed
+
+            const labelList& cFaces = mesh.cells()[celli];
+
+            // Unique node ids used (XML/INTERNAL, not needed for LEGACY)
+            hashUniqId.clear();
+
+            // Face stream sizing:
+            // number of faces, size of each face, vertices per face
+            // [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
+
+            forAll(cFaces, cFaceI)
+            {
+                const face& f = mesh.faces()[cFaces[cFaceI]];
+                nFaceLabels_ += f.size();
+
+                hashUniqId.insert(f);
+            }
+
+            // Legacy format only uses the face-stream.
+            // - track what *NOT* to use for legacy
+            nVertLabels_ += hashUniqId.size();
+            nVertPoly_   += hashUniqId.size();
+
+            nFaceLabels_ += 1 + cFaces.size();
+        }
+    }
+
+    // decompose requested and needed
+    decompose_ = (decompose && nCellsPoly_);
+}
+
+
+Foam::label Foam::vtk::vtuSizing::sizeOf
+(
+    const enum contentType output,
+    const enum slotType slot
+) const
+{
+    switch (output)
+    {
+        case contentType::LEGACY:
+        {
+            switch (slot)
+            {
+                case slotType::CELLS:
+                    // legacy uses connectivity for primitives, but directly
+                    // stores face streams into connectivity as well.
+                    // size-prefix per cell
+                    return
+                    (
+                        nVertLabels() + nAddVerts() - nVertPoly() // primitives
+                      + nFaceLabels()     // face-stream (poly)
+                      + nFieldCells()     // nFieldCells (size prefix)
+                    );
+                    break;
+
+                default:
+                    break;
+            }
+            break;
+        }
+        case contentType::XML:
+        {
+            switch (slot)
+            {
+                case slotType::CELLS:
+                    return (nVertLabels() + nAddVerts());
+                    break;
+
+                case slotType::CELLS_OFFSETS:
+                    return nFieldCells();
+                    break;
+
+                case slotType::FACES:
+                    return nFaceLabels();
+                    break;
+
+                case slotType::FACES_OFFSETS:
+                    return nFaceLabels() ? nFieldCells() : 0;
+                    break;
+            }
+            break;
+        }
+        case contentType::INTERNAL:
+        {
+            switch (slot)
+            {
+                case slotType::CELLS:
+                    // size-prefix per cell
+                    return (nVertLabels() + nAddVerts() + nFieldCells());
+                    break;
+
+                case slotType::CELLS_OFFSETS:
+                    return nFieldCells();
+                    break;
+
+                case slotType::FACES:
+                    return nFaceLabels();
+                    break;
+
+                case slotType::FACES_OFFSETS:
+                    return nFaceLabels() ? nFieldCells() : 0;
+                    break;
+            }
+            break;
+        }
+    }
+
+    return 0;
+}
+
+
+void Foam::vtk::vtuSizing::populateLegacy
+(
+    const polyMesh& mesh,
+    UList<uint8_t>& cellTypes,
+    UList<label>& vertLabels,
+    foamVtkMeshMaps& maps
+) const
+{
+    // Leave as zero-sized so that populateArrays doesn't fill it.
+    List<label> unused;
+
+    presizeMaps(maps);
+
+    populateArrays
+    (
+        mesh,
+        *this,
+        cellTypes,
+        vertLabels,
+        unused, // offsets
+        unused, // faces
+        unused, // facesOffsets
+        contentType::LEGACY,
+        maps.cellMap(),
+        maps.additionalIds()
+    );
+}
+
+
+void Foam::vtk::vtuSizing::populateXml
+(
+    const polyMesh& mesh,
+    UList<uint8_t>& cellTypes,
+    UList<label>& connectivity,
+    UList<label>& offsets,
+    UList<label>& faces,
+    UList<label>& facesOffsets,
+    foamVtkMeshMaps& maps
+) const
+{
+    presizeMaps(maps);
+
+    populateArrays
+    (
+        mesh,
+        *this,
+        cellTypes,
+        connectivity,
+        offsets,
+        faces,
+        facesOffsets,
+        contentType::XML,
+        maps.cellMap(),
+        maps.additionalIds()
+    );
+}
+
+
+void Foam::vtk::vtuSizing::populateInternal
+(
+    const polyMesh& mesh,
+    UList<uint8_t>& cellTypes,
+    UList<int>& connectivity,
+    UList<int>& offsets,
+    UList<int>& faces,
+    UList<int>& facesOffsets,
+    foamVtkMeshMaps& maps
+) const
+{
+    presizeMaps(maps);
+
+    populateArrays
+    (
+        mesh,
+        *this,
+        cellTypes,
+        connectivity,
+        offsets,
+        faces,
+        facesOffsets,
+        contentType::INTERNAL,
+        maps.cellMap(),
+        maps.additionalIds()
+    );
+}
+
+
+void Foam::vtk::vtuSizing::populateInternal
+(
+    const polyMesh& mesh,
+    UList<uint8_t>& cellTypes,
+    UList<long>& connectivity,
+    UList<long>& offsets,
+    UList<long>& faces,
+    UList<long>& facesOffsets,
+    foamVtkMeshMaps& maps
+) const
+{
+    presizeMaps(maps);
+
+    populateArrays
+    (
+        mesh,
+        *this,
+        cellTypes,
+        connectivity,
+        offsets,
+        faces,
+        facesOffsets,
+        contentType::INTERNAL,
+        maps.cellMap(),
+        maps.additionalIds()
+    );
+}
+
+
+void Foam::vtk::vtuSizing::populateInternal
+(
+    const polyMesh& mesh,
+    UList<uint8_t>& cellTypes,
+    UList<long long>& connectivity,
+    UList<long long>& offsets,
+    UList<long long>& faces,
+    UList<long long>& facesOffsets,
+    foamVtkMeshMaps& maps
+) const
+{
+    presizeMaps(maps);
+
+    populateArrays
+    (
+        mesh,
+        *this,
+        cellTypes,
+        connectivity,
+        offsets,
+        faces,
+        facesOffsets,
+        contentType::INTERNAL,
+        maps.cellMap(),
+        maps.additionalIds()
+    );
+}
+
+
+void Foam::vtk::vtuSizing::populateInternal
+(
+    const polyMesh& mesh,
+    UList<uint8_t>& cellTypes,
+    UList<int>& connectivity,
+    UList<int>& offsets,
+    UList<int>& faces,
+    UList<int>& facesOffsets,
+    UList<label>& cellMap,
+    UList<label>& addPointsIds
+) const
+{
+    populateArrays
+    (
+        mesh,
+        *this,
+        cellTypes,
+        connectivity,
+        offsets,
+        faces,
+        facesOffsets,
+        contentType::INTERNAL,
+        cellMap,
+        addPointsIds
+    );
+}
+
+
+void Foam::vtk::vtuSizing::populateInternal
+(
+    const polyMesh& mesh,
+    UList<uint8_t>& cellTypes,
+    UList<long>& connectivity,
+    UList<long>& offsets,
+    UList<long>& faces,
+    UList<long>& facesOffsets,
+    UList<label>& cellMap,
+    UList<label>& addPointsIds
+) const
+{
+    populateArrays
+    (
+        mesh,
+        *this,
+        cellTypes,
+        connectivity,
+        offsets,
+        faces,
+        facesOffsets,
+        contentType::INTERNAL,
+        cellMap,
+        addPointsIds
+    );
+}
+
+
+void Foam::vtk::vtuSizing::populateInternal
+(
+    const polyMesh& mesh,
+    UList<uint8_t>& cellTypes,
+    UList<long long>& connectivity,
+    UList<long long>& offsets,
+    UList<long long>& faces,
+    UList<long long>& facesOffsets,
+    UList<label>& cellMap,
+    UList<label>& addPointsIds
+) const
+{
+    populateArrays
+    (
+        mesh,
+        *this,
+        cellTypes,
+        connectivity,
+        offsets,
+        faces,
+        facesOffsets,
+        contentType::INTERNAL,
+        cellMap,
+        addPointsIds
+    );
+}
+
+
+void Foam::vtk::vtuSizing::clear()
+{
+    decompose_   = false;
+    nCells_      = 0;
+    nPoints_     = 0;
+    nVertLabels_ = 0;
+
+    nFaceLabels_ = 0;
+    nCellsPoly_  = 0;
+    nVertPoly_   = 0;
+
+    nAddCells_   = 0;
+    nAddPoints_  = 0;
+    nAddVerts_   = 0;
+}
+
+
+void Foam::vtk::vtuSizing::info(Ostream& os) const
+{
+    os  << "nFieldCells:" << nFieldCells();
+    if (nAddCells_)
+    {
+        os  << " (" << nCells_
+            << "+" << nAddCells_ << ")";
+    }
+    else
+    {
+        os  << " (poly:" << nCellsPoly_ << ")";
+    }
+
+    os  << " nFieldPoints:" << nFieldPoints();
+    if (nAddPoints_)
+    {
+        os  << " (" << nPoints_ << "+" << nAddPoints_ << ")";
+    }
+
+    os  << " nVertLabels:" << (nVertLabels_ + nAddVerts_);
+    if (nAddVerts_)
+    {
+        os  << " (" << nVertLabels_ << "+" << nAddVerts_ << ")";
+    }
+    else if (nVertPoly_)
+    {
+        os  << " (poly:" << nVertPoly_ << ")";
+    }
+
+    os << " nFaceLabels:" << nFaceLabels_;
+    os << " legacy-count:" << sizeLegacy();
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+bool Foam::vtk::vtuSizing::operator==(const vtuSizing& rhs) const
+{
+    return
+    (
+        decompose()   == rhs.decompose()
+     && nCells()      == rhs.nCells()
+     && nPoints()     == rhs.nPoints()
+     && nVertLabels() == rhs.nVertLabels()
+     && nFaceLabels() == rhs.nFaceLabels()
+     && nCellsPoly()  == rhs.nCellsPoly()
+     && nVertPoly()   == rhs.nVertPoly()
+     && nAddCells()   == rhs.nAddCells()
+     && nAddPoints()  == rhs.nAddPoints()
+     && nAddVerts()   == rhs.nAddVerts()
+    );
+}
+
+
+bool Foam::vtk::vtuSizing::operator!=(const vtuSizing& rhs) const
+{
+    return !operator==(rhs);
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/part/foamVtuSizing.H b/src/conversion/vtk/part/foamVtuSizing.H
new file mode 100644
index 0000000000000000000000000000000000000000..a14209807a9a1945fb20fae37e5f7d620a021c8b
--- /dev/null
+++ b/src/conversion/vtk/part/foamVtuSizing.H
@@ -0,0 +1,413 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016-2017 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::vtk::vtuSizing
+
+Description
+    Sizing descriptions and routines for transcribing an OpenFOAM volume mesh
+    into a VTK unstructured grid, with possible decomposition of polyhedral
+    cells into primitive cell types.
+
+    This class is intended to populate externally allocated arrays with content
+    that is compatible with what VTK expects. This approach allows an improved
+    separation of the OpenFOAM mesh description and the storage, and allows
+    support of alternative storage containers (eg, std::vector, vtkDataArray).
+    The ideal goal would be a zero-copy mechanism, but this does not work for
+    several reasons:
+    \par
+    - OpenFOAM and VTK have different point ordering for prism
+    - polyhedral decomposition
+    - face-stream are required for VTK
+    - VTK internal storage includes list size as part of the data
+    - VTK includes storage may be a different base size (eg, long long)
+      compared to the OpenFOAM label.
+
+    \par Data Entries (slots)
+
+    These are the storage entries normally associate with each output-type:
+    \table
+        legacy output
+        \c types    | vtk cell type (1-255)
+        \c cells    | nLabels and unique vertex labels used by the cell, or
+                    | [nLabels nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
+    \endtable
+
+    \table
+        xml output
+        \c types        | vtk cell type (1-255)
+        \c connectivity | unique vertex labels used by the cell
+        \c offsets      | end offset for each of \c connectivity
+        \c faces        | face stream for polyhedral cells
+                        | [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
+        \c faceoffsets  | end offset for each of \c faces, with -1 for primitive cells
+    \endtable
+
+    \table
+        internal storage
+        \c types        | vtk cell type (1-255)
+        \c connectivity | nLabels and unique vertex labels used by the cell
+        \c location     | begin location for each of \c connectivity
+        \c faces        | face stream for polyhedral cells
+                        | [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
+        \c facelocation | begin location for each of \c faces, with -1 for primitive cells
+    \endtable
+
+    The VTK storage concept for "connectivity" and "faces" somewhat resemble
+    a CompactListList.
+
+SourceFiles
+    foamVtuSizing.C
+    foamVtuSizingI.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef foamVtuSizing_H
+#define foamVtuSizing_H
+
+#include "label.H"
+#include "labelList.H"
+#include "foamVtkMeshMaps.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declaration of classes
+class polyMesh;
+
+namespace vtk
+{
+
+/*---------------------------------------------------------------------------*\
+                    Class Foam::vtk::vtuSizing Declaration
+\*---------------------------------------------------------------------------*/
+
+class vtuSizing
+{
+public:
+
+    // Public data
+
+    //- Types of content that the storage may represent
+    enum contentType
+    {
+        LEGACY,     //!< Legacy VTK content
+        XML,        //!< XML (VTU) content
+        INTERNAL    //!< Internal vtkUnstructuredGrid content
+    };
+
+    //- The possible storage 'slots' that can be used
+    enum slotType
+    {
+        CELLS,         //!< Cell connectivity (ALL)
+        CELLS_OFFSETS, //!< End-offsets (XML) or locations (INTERNAL) for cells
+        FACES,         //!< Face-stream (XML, INTERNAL)
+        FACES_OFFSETS  //!< End-offsets (XML) or locations (INTERNAL) for faces
+    };
+
+
+private:
+
+    // Private Member Data
+
+        //- Polyhedral decomposition requested
+        bool decompose_;
+
+        //- Number of cells in the mesh
+        label nCells_;
+
+        //- Number of points in the mesh
+        label nPoints_;
+
+        //- Number of vertex labels to represent the mesh
+        label nVertLabels_;
+
+      // Polyhedrals
+
+        //- Number of polyhedral face labels for the mesh
+        label nFaceLabels_;
+
+        //- Number of polyhedral cells (informational)
+        label nCellsPoly_;
+
+        //- Number of vertex labels used by polyhedrals
+        label nVertPoly_;
+
+      // Decomposed polyhedrals
+
+        //- Number of additional (decomposed) cells for the mesh
+        label nAddCells_;
+
+        //- Number of additional (decomposed) points for the mesh
+        label nAddPoints_;
+
+        //- Number of additional (decomposed) vertices for the mesh
+        label nAddVerts_;
+
+
+    // Private Member Functions
+
+        //- set-size for cellMap and additionalIds
+        void presizeMaps(foamVtkMeshMaps& maps) const;
+
+        //- Populate lists for internal VTK representation
+        template<class LabelType, class LabelType2>
+        static void populateArrays
+        (
+            const polyMesh& mesh,
+            const vtk::vtuSizing& sizing,
+            UList<uint8_t>& cellTypes,
+            UList<LabelType>& vertLabels,
+            UList<LabelType>& vertOffset,
+            UList<LabelType>& faceLabels,
+            UList<LabelType>& faceOffset,
+            const enum contentType output,
+            UList<LabelType2>& cellMap,
+            UList<LabelType2>& addPointsIds
+        );
+
+        // Allow default bitwise copy/assignment
+
+public:
+
+    // Constructors
+
+        //- Construct null.
+        vtuSizing();
+
+        //- Construct sizes by analyzing the mesh,
+        //  optionally with polyhedral decomposition.
+        vtuSizing(const polyMesh& mesh, const bool decompose=false);
+
+
+    //- Destructor
+    ~vtuSizing();
+
+
+    // Member Functions
+
+      // Edit
+
+        //- Construct sizes by analyzing the mesh,
+        //  optionally with polyhedral decomposition.
+        void reset(const polyMesh& mesh, const bool decompose=false);
+
+        //- Reset all sizes to zero.
+        void clear();
+
+
+      // Access
+
+        //- Query the decompose flag
+        inline bool decompose() const;
+
+        //- Number of cells for the mesh
+        inline label nCells() const;
+
+        //- Number of points for the mesh
+        inline label nPoints() const;
+
+        //- Number of vertex labels for the mesh
+        inline label nVertLabels() const;
+
+        //- Number of polyhedral face labels for the mesh
+        inline label nFaceLabels() const;
+
+        //- Number of polyhedral cells for the mesh
+        inline label nCellsPoly() const;
+
+        //- Number of vertex labels for polyhedral cells of the mesh
+        inline label nVertPoly() const;
+
+        //- Number of additional (decomposed) cells for the mesh
+        inline label nAddCells() const;
+
+        //- Number of additional (decomposed) points for the mesh
+        inline label nAddPoints() const;
+
+        //- Number of additional (decomposed) vertices for the mesh
+        inline label nAddVerts() const;
+
+
+        //- Number of field cells = nCells + nAddCells
+        inline label nFieldCells() const;
+
+        //- Number of field points = nPoints + nAddPoints
+        inline label nFieldPoints() const;
+
+
+      // Derived sizes
+
+        //- Return the required size for the storage slot
+        label sizeOf
+        (
+            const enum contentType output,
+            const enum slotType slot
+        ) const;
+
+
+        //- The calculated size for legacy storage
+        inline label sizeLegacy() const;
+
+        //- The calculated size for legacy storage of the specified slot
+        inline label sizeLegacy(const enum slotType slot) const;
+
+        //- The calculated size for xml storage of the specified slot
+        inline label sizeXml(const enum slotType slot) const;
+
+        //- The calculated size for vtk-internal storage of the specified slot
+        inline label sizeInternal(const enum slotType slot) const;
+
+
+      // Utilty routines
+
+        //- Populate lists for Legacy output
+        void populateLegacy
+        (
+            const polyMesh& mesh,
+            UList<uint8_t>& cellTypes,
+            UList<label>& connectivity,
+            foamVtkMeshMaps& maps
+        ) const;
+
+        //- Populate lists for XML output
+        void populateXml
+        (
+            const polyMesh& mesh,
+            UList<uint8_t>& cellTypes,
+            UList<label>& connectivity,
+            UList<label>& offsets,
+            UList<label>& faces,
+            UList<label>& facesOffsets,
+            foamVtkMeshMaps& maps
+        ) const;
+
+        //- Populate lists for Internal VTK format
+        void populateInternal
+        (
+            const polyMesh& mesh,
+            UList<uint8_t>& cellTypes,
+            UList<int>& connectivity,
+            UList<int>& offsets,
+            UList<int>& faces,
+            UList<int>& facesOffsets,
+            foamVtkMeshMaps& maps
+        ) const;
+
+        //- Populate lists for Internal VTK format
+        void populateInternal
+        (
+            const polyMesh& mesh,
+            UList<uint8_t>& cellTypes,
+            UList<long>& connectivity,
+            UList<long>& offsets,
+            UList<long>& faces,
+            UList<long>& facesOffsets,
+            foamVtkMeshMaps& maps
+        ) const;
+
+        //- Populate lists for Internal VTK format
+        void populateInternal
+        (
+            const polyMesh& mesh,
+            UList<uint8_t>& cellTypes,
+            UList<long long>& connectivity,
+            UList<long long>& offsets,
+            UList<long long>& faces,
+            UList<long long>& facesOffsets,
+            foamVtkMeshMaps& maps
+        ) const;
+
+        //- Populate lists for Internal VTK format
+        void populateInternal
+        (
+            const polyMesh& mesh,
+            UList<uint8_t>& cellTypes,
+            UList<int>& connectivity,
+            UList<int>& offsets,
+            UList<int>& faces,
+            UList<int>& facesOffsets,
+            UList<label>& cellMap,
+            UList<label>& addPointsIds
+        ) const;
+
+        //- Populate lists for Internal VTK format
+        void populateInternal
+        (
+            const polyMesh& mesh,
+            UList<uint8_t>& cellTypes,
+            UList<long>& connectivity,
+            UList<long>& offsets,
+            UList<long>& faces,
+            UList<long>& facesOffsets,
+            UList<label>& cellMap,
+            UList<label>& addPointsIds
+        ) const;
+
+        //- Populate lists for Internal VTK format
+        void populateInternal
+        (
+            const polyMesh& mesh,
+            UList<uint8_t>& cellTypes,
+            UList<long long>& connectivity,
+            UList<long long>& offsets,
+            UList<long long>& faces,
+            UList<long long>& facesOffsets,
+            UList<label>& cellMap,
+            UList<label>& addPointsIds
+        ) const;
+
+
+      // Write
+
+        //- Report some information
+        void info(Ostream& os) const;
+
+
+      // Member Operators
+
+        //- Test equality
+        bool operator==(const vtuSizing& rhs) const;
+
+        //- Test inequality
+        bool operator!=(const vtuSizing& rhs) const;
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace vtk
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "foamVtuSizingI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/part/foamVtuSizingI.H b/src/conversion/vtk/part/foamVtuSizingI.H
new file mode 100644
index 0000000000000000000000000000000000000000..6777ce7e7a91fac943560487ffe0169d9023ebc2
--- /dev/null
+++ b/src/conversion/vtk/part/foamVtuSizingI.H
@@ -0,0 +1,135 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 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 "foamVtuSizing.H"
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+inline bool Foam::vtk::vtuSizing::decompose() const
+{
+    return decompose_;
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::nCells() const
+{
+    return nCells_;
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::nPoints() const
+{
+    return nPoints_;
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::nVertLabels() const
+{
+    return nVertLabels_;
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::nFaceLabels() const
+{
+    return nFaceLabels_;
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::nCellsPoly() const
+{
+    return nCellsPoly_;
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::nVertPoly() const
+{
+    return nVertPoly_;
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::nAddCells() const
+{
+    return nAddCells_;
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::nAddPoints() const
+{
+    return nAddPoints_;
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::nAddVerts() const
+{
+    return nAddVerts_;
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::nFieldCells() const
+{
+    return nCells_ + nAddCells_;
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::nFieldPoints() const
+{
+    return nPoints_ + nAddPoints_;
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::sizeLegacy() const
+{
+    return sizeOf(contentType::LEGACY, slotType::CELLS);
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::sizeLegacy
+(
+    const enum slotType slot
+) const
+{
+    return sizeOf(contentType::LEGACY, slot);
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::sizeXml
+(
+    const enum slotType slot
+) const
+{
+    return sizeOf(contentType::XML, slot);
+}
+
+
+inline Foam::label Foam::vtk::vtuSizing::sizeInternal
+(
+    const enum slotType slot
+) const
+{
+    return sizeOf(contentType::INTERNAL, slot);
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/part/foamVtuSizingTemplates.C b/src/conversion/vtk/part/foamVtuSizingTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..0c4ffe44ac81b1cb19a244f13d6495d2bc395b06
--- /dev/null
+++ b/src/conversion/vtk/part/foamVtuSizingTemplates.C
@@ -0,0 +1,668 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016-2017 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 "foamVtuSizing.H"
+#include "foamVtkCore.H"
+#include "polyMesh.H"
+#include "cellShape.H"
+#include "cellModeller.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+template<class LabelType, class LabelType2>
+void Foam::vtk::vtuSizing::populateArrays
+(
+    const polyMesh& mesh,
+    const vtk::vtuSizing& sizing,
+    UList<uint8_t>& cellTypes,
+    UList<LabelType>& vertLabels,
+    UList<LabelType>& vertOffset,
+    UList<LabelType>& faceLabels,
+    UList<LabelType>& faceOffset,
+    const enum contentType output,
+    UList<LabelType2>& cellMap,
+    UList<LabelType2>& addPointsIds
+)
+{
+    // STAGE 1: Verify storage sizes
+
+    if (cellTypes.size() != sizing.nFieldCells())
+    {
+        FatalErrorInFunction
+            << " cellTypes size=" << cellTypes.size()
+            << " expected " << sizing.nFieldCells()
+            << exit(FatalError);
+    }
+
+    if (cellMap.size() != sizing.nFieldCells())
+    {
+        FatalErrorInFunction
+            << " cellMap size=" << cellMap.size()
+            << " expected " << sizing.nFieldCells()
+            << exit(FatalError);
+    }
+
+    if (addPointsIds.size() != sizing.nAddPoints())
+    {
+        FatalErrorInFunction
+            << " addPointsIds size=" << addPointsIds.size()
+            << " expected " << sizing.nAddPoints()
+            << exit(FatalError);
+    }
+
+    // Prefix vertLabels with the size too?
+    // Also use as the size of the prefixed information
+    const int prefix = (output != contentType::XML) ? 1 : 0;
+
+    switch (output)
+    {
+        case contentType::LEGACY:
+        {
+            if (vertLabels.size() != sizing.sizeLegacy())
+            {
+                FatalErrorInFunction
+                    << " legacy size=" << vertLabels.size()
+                    << " expected " << sizing.sizeLegacy()
+                    << exit(FatalError);
+            }
+            break;
+        }
+        case contentType::XML:
+        {
+            // XML uses connectivity/offset pair.
+            if
+            (
+                vertLabels.size()
+             != sizing.sizeXml(slotType::CELLS)
+            )
+            {
+                FatalErrorInFunction
+                    << " connectivity size=" << vertLabels.size()
+                    << " expected "
+                    << sizing.sizeXml(slotType::CELLS)
+                    << exit(FatalError);
+            }
+
+            if
+            (
+                vertOffset.size()
+             != sizing.sizeXml(slotType::CELLS_OFFSETS)
+            )
+            {
+                FatalErrorInFunction
+                    << " offsets size=" << vertOffset.size()
+                    << " expected "
+                    << sizing.sizeXml(slotType::CELLS_OFFSETS)
+                    << exit(FatalError);
+            }
+
+            if (sizing.nFaceLabels())
+            {
+                if
+                (
+                    faceLabels.size()
+                 != sizing.sizeXml(slotType::FACES)
+                )
+                {
+                    FatalErrorInFunction
+                        << " faces size=" << faceLabels.size()
+                        << " expected "
+                        << sizing.sizeXml(slotType::FACES)
+                        << exit(FatalError);
+                }
+
+                if
+                (
+                    faceOffset.size()
+                 != sizing.sizeXml(slotType::FACES_OFFSETS)
+                )
+                {
+                    FatalErrorInFunction
+                        << " facesOffsets size=" << faceOffset.size()
+                        << " expected "
+                        << sizing.sizeXml(slotType::FACES_OFFSETS)
+                        << exit(FatalError);
+                }
+            }
+            break;
+        }
+        case contentType::INTERNAL:
+        {
+            // VTK-internal connectivity/offset pair.
+            if
+            (
+                vertLabels.size()
+             != sizing.sizeInternal(slotType::CELLS)
+            )
+            {
+                FatalErrorInFunction
+                    << " connectivity size=" << vertLabels.size()
+                    << " expected "
+                    << sizing.sizeInternal(slotType::CELLS)
+                    << exit(FatalError);
+            }
+
+            if
+            (
+                vertOffset.size()
+             != sizing.sizeInternal(slotType::CELLS_OFFSETS)
+            )
+            {
+                FatalErrorInFunction
+                    << " offsets size=" << vertOffset.size()
+                    << " expected "
+                    << sizing.sizeInternal(slotType::CELLS_OFFSETS)
+                    << exit(FatalError);
+            }
+
+            if (sizing.nFaceLabels())
+            {
+                if
+                (
+                    faceLabels.size()
+                 != sizing.sizeInternal(slotType::FACES)
+                )
+                {
+                    FatalErrorInFunction
+                        << " faces size=" << faceLabels.size()
+                        << " expected "
+                        << sizing.sizeInternal(slotType::FACES)
+                        << exit(FatalError);
+                }
+
+                if
+                (
+                    faceOffset.size()
+                 != sizing.sizeInternal(slotType::FACES_OFFSETS)
+                )
+                {
+                    FatalErrorInFunction
+                        << " facesOffsets size=" << faceOffset.size()
+                        << " expected "
+                        << sizing.sizeInternal(slotType::FACES_OFFSETS)
+                        << exit(FatalError);
+                }
+            }
+            break;
+        }
+    }
+
+
+    faceOffset = -1;
+
+    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& tetWedge = *(cellModeller::lookup("tetWedge"));
+    const cellModel& hex      = *(cellModeller::lookup("hex"));
+
+    const cellShapeList& shapes = mesh.cellShapes();
+
+    // face owner is needed to determine the face orientation
+    const labelList& owner = mesh.faceOwner();
+
+    // Unique vertex labels per polyhedral
+    HashSet<label> hashUniqId(2*256);
+
+    // Index into vertLabels, faceLabels for normal cells
+    label nVertLabels = 0;
+    label nFaceLabels = 0;
+
+    // Index into vertLabels for decomposed polys
+    label nVertDecomp = sizing.nVertLabels() + prefix*sizing.nCells();
+
+    // Placement of decomposed cells
+    label nCellDecomp = mesh.nCells();
+
+    // Placement of additional point labels
+    label nPointDecomp = 0;
+
+    // Non-decomposed polyhedral are represented as a face-stream.
+    // For legacy format, this stream replaces the normal connectivity
+    // information. Use references to alias where the face output should land.
+
+    UList<LabelType>& faceOutput =
+    (
+        output == contentType::LEGACY
+      ? vertLabels
+      : faceLabels
+    );
+
+    label& faceIndexer =
+    (
+        output == contentType::LEGACY
+      ? nVertLabels
+      : nFaceLabels
+    );
+
+    // ===========================================
+    // STAGE 2: Rewrite in VTK form
+    // During this stage, the vertOffset contains the *size* associated with
+    // the per-cell vertLabels entries, and the faceOffset contains the *size*
+    // associated with the per-cell faceLabels.
+
+    forAll(shapes, celli)
+    {
+        const cellShape& shape = shapes[celli];
+        const cellModel& model = shape.model();
+
+        cellMap[celli] = celli;
+
+        if (model == tet)
+        {
+            cellTypes[celli] = vtk::cellType::VTK_TETRA;
+            if (vertOffset.size())
+            {
+                vertOffset[celli] = shape.size();
+            }
+            if (prefix)
+            {
+                vertLabels[nVertLabels++] = shape.size();
+            }
+
+            forAll(shape, i)
+            {
+                vertLabels[nVertLabels++] = shape[i];
+            }
+        }
+        else if (model == pyr)
+        {
+            cellTypes[celli] = vtk::cellType::VTK_PYRAMID;
+            if (vertOffset.size())
+            {
+                vertOffset[celli] = shape.size();
+            }
+            if (prefix)
+            {
+                vertLabels[nVertLabels++] = shape.size();
+            }
+
+            forAll(shape, i)
+            {
+                vertLabels[nVertLabels++] = shape[i];
+            }
+        }
+        else if (model == hex)
+        {
+            cellTypes[celli] = vtk::cellType::VTK_HEXAHEDRON;
+            if (vertOffset.size())
+            {
+                vertOffset[celli] = shape.size();
+            }
+            if (prefix)
+            {
+                vertLabels[nVertLabels++] = shape.size();
+            }
+
+            forAll(shape, i)
+            {
+                vertLabels[nVertLabels++] = shape[i];
+            }
+        }
+        else if (model == prism)
+        {
+            cellTypes[celli] = vtk::cellType::VTK_WEDGE;
+            if (vertOffset.size())
+            {
+                vertOffset[celli] = shape.size();
+            }
+            if (prefix)
+            {
+                vertLabels[nVertLabels++] = shape.size();
+            }
+
+            // VTK_WEDGE triangles point outwards (swap 1<->2, 4<->5)
+            vertLabels[nVertLabels++] = shape[0];
+            vertLabels[nVertLabels++] = shape[2];
+            vertLabels[nVertLabels++] = shape[1];
+            vertLabels[nVertLabels++] = shape[3];
+            vertLabels[nVertLabels++] = shape[5];
+            vertLabels[nVertLabels++] = shape[4];
+        }
+        else if (model == tetWedge && sizing.decompose())
+        {
+            // Treat as squeezed prism
+            cellTypes[celli] = vtk::cellType::VTK_WEDGE;
+            if (vertOffset.size())
+            {
+                vertOffset[celli] = 6;
+            }
+            if (prefix)
+            {
+                vertLabels[nVertLabels++] = 6;
+            }
+
+            vertLabels[nVertLabels++] = shape[0];
+            vertLabels[nVertLabels++] = shape[2];
+            vertLabels[nVertLabels++] = shape[1];
+            vertLabels[nVertLabels++] = shape[3];
+            vertLabels[nVertLabels++] = shape[4];
+            vertLabels[nVertLabels++] = shape[3];
+        }
+        else if (model == wedge && sizing.decompose())
+        {
+            // Treat as squeezed hex
+            cellTypes[celli] = vtk::cellType::VTK_HEXAHEDRON;
+            if (vertOffset.size())
+            {
+                vertOffset[celli] = 8;
+            }
+            if (prefix)
+            {
+                vertLabels[nVertLabels++] = 8;
+            }
+
+            vertLabels[nVertLabels++] = shape[0];
+            vertLabels[nVertLabels++] = shape[1];
+            vertLabels[nVertLabels++] = shape[2];
+            vertLabels[nVertLabels++] = shape[2];
+            vertLabels[nVertLabels++] = shape[3];
+            vertLabels[nVertLabels++] = shape[4];
+            vertLabels[nVertLabels++] = shape[5];
+            vertLabels[nVertLabels++] = shape[6];
+        }
+        else if (sizing.decompose())
+        {
+            // Polyhedral cell - decompose into tet/pyr.
+
+            // Ensure we have the correct orientation for the base of the
+            // primitive cell shape.
+            // If the cell is face owner, the orientation needs to be flipped
+            // to avoid defining negative cells.
+            // VTK may not care, but we'll do it anyhow for safety.
+
+            // Mapping from additional point to cell, and the new vertex from
+            // the cell-centre
+            const label newVertexLabel = mesh.nPoints() + nPointDecomp;
+
+            addPointsIds[nPointDecomp++] = celli;
+
+            // Whether to insert cell in place of original or not.
+            bool first = true;
+
+            const labelList& cFaces = mesh.cells()[celli];
+            forAll(cFaces, cFaceI)
+            {
+                const face& f = mesh.faces()[cFaces[cFaceI]];
+                const bool isOwner = (owner[cFaces[cFaceI]] == celli);
+
+                // Count triangles/quads in decomposition
+                label nTria = 0, nQuad = 0;
+                f.nTrianglesQuads(mesh.points(), nTria, nQuad);
+
+                // Do actual decomposition
+                faceList faces3(nTria);
+                faceList faces4(nQuad);
+                nTria = 0, nQuad = 0;
+                f.trianglesQuads(mesh.points(), nTria, nQuad, faces3, faces4);
+
+                forAll(faces4, fci)
+                {
+                    // Quad becomes a pyramid
+                    const face& quad = faces4[fci];
+                    const label nShapePoints = 5;  // pyr (5 vertices)
+
+                    label celLoc, vrtLoc;
+                    if (first)
+                    {
+                        first = false;
+                        celLoc = celli;
+                        vrtLoc = nVertLabels;
+                        nVertLabels += prefix + nShapePoints;
+                    }
+                    else
+                    {
+                        celLoc = nCellDecomp++;
+                        vrtLoc = nVertDecomp;
+                        nVertDecomp += prefix + nShapePoints;
+                    }
+                    cellMap[celLoc] = celli;
+
+                    cellTypes[celLoc] = vtk::cellType::VTK_PYRAMID;
+                    if (vertOffset.size())
+                    {
+                        vertOffset[celLoc] = nShapePoints;
+                    }
+                    if (prefix)
+                    {
+                        vertLabels[vrtLoc++] = nShapePoints;
+                    }
+
+                    // See note above about the orientation.
+                    if (isOwner)
+                    {
+                        vertLabels[vrtLoc++] = quad[3];
+                        vertLabels[vrtLoc++] = quad[2];
+                        vertLabels[vrtLoc++] = quad[1];
+                        vertLabels[vrtLoc++] = quad[0];
+                    }
+                    else
+                    {
+                        vertLabels[vrtLoc++] = quad[0];
+                        vertLabels[vrtLoc++] = quad[1];
+                        vertLabels[vrtLoc++] = quad[2];
+                        vertLabels[vrtLoc++] = quad[3];
+                    }
+
+                    vertLabels[vrtLoc++] = newVertexLabel; // apex
+                }
+
+                forAll(faces3, fci)
+                {
+                    // Triangle becomes a tetrahedral
+                    const face& tria = faces3[fci];
+                    const label nShapePoints = 4;  // tet (4 vertices)
+
+                    label celLoc, vrtLoc;
+                    if (first)
+                    {
+                        first = false;
+                        celLoc = celli;
+                        vrtLoc = nVertLabels;
+                        nVertLabels += prefix + nShapePoints;
+                    }
+                    else
+                    {
+                        celLoc = nCellDecomp++;
+                        vrtLoc = nVertDecomp;
+                        nVertDecomp += prefix + nShapePoints;
+                    }
+                    cellMap[celLoc] = celli;
+
+                    cellTypes[celLoc] = vtk::cellType::VTK_TETRA;
+                    if (vertOffset.size())
+                    {
+                        vertOffset[celLoc] = nShapePoints;
+                    }
+                    if (prefix)
+                    {
+                        vertLabels[vrtLoc++] = nShapePoints;
+                    }
+
+                    cellTypes[celLoc] = vtk::cellType::VTK_TETRA;
+
+                    // See note above about the orientation.
+                    if (isOwner)
+                    {
+                        vertLabels[vrtLoc++] = tria[2];
+                        vertLabels[vrtLoc++] = tria[1];
+                        vertLabels[vrtLoc++] = tria[0];
+                    }
+                    else
+                    {
+                        vertLabels[vrtLoc++] = tria[0];
+                        vertLabels[vrtLoc++] = tria[1];
+                        vertLabels[vrtLoc++] = tria[2];
+                    }
+                    vertLabels[vrtLoc++] = newVertexLabel; // apex
+                }
+            }
+        }
+        else
+        {
+            // Polyhedral cell - not decomposed
+            hashUniqId.clear();  // unique node ids used (XML, INTERNAL)
+
+            // face-stream
+            //   [nFaces, nFace0Pts, id1, id2, ..., nFace1Pts, id1, id2, ...]
+            cellTypes[celli] = vtk::cellType::VTK_POLYHEDRON;
+            const labelList& cFaces = mesh.cells()[celli];
+
+            const label startLabel = faceIndexer;
+
+            if (output == contentType::LEGACY)
+            {
+                faceOutput[startLabel] = 0; // placeholder for size
+                ++faceIndexer;
+            }
+
+            faceOutput[faceIndexer++] = cFaces.size();
+
+            forAll(cFaces, cFaceI)
+            {
+                const face& f = mesh.faces()[cFaces[cFaceI]];
+                const bool isOwner = (owner[cFaces[cFaceI]] == celli);
+
+                forAll(f, fp)
+                {
+                    hashUniqId.insert(f[fp]);
+                }
+
+                // number of labels for this face
+                faceOutput[faceIndexer++] = f.size();
+
+                if (isOwner)
+                {
+                    forAll(f, fp)
+                    {
+                        faceOutput[faceIndexer++] = f[fp];
+                    }
+                }
+                else
+                {
+                    // fairly immaterial if we reverse the list
+                    // or use face::reverseFace()
+                    forAllReverse(f, fp)
+                    {
+                        faceOutput[faceIndexer++] = f[fp];
+                    }
+                }
+            }
+
+            if (output == contentType::LEGACY)
+            {
+                // Update size for legacy face stream
+                faceOutput[startLabel] = (faceIndexer - startLabel);
+            }
+            else
+            {
+                // Size for face stream
+                faceOffset[celli] = (faceIndexer - startLabel);
+
+                vertOffset[celli] = hashUniqId.size();
+                if (prefix)
+                {
+                    vertLabels[nVertLabels++] = hashUniqId.size();
+                }
+
+                const labelList uniq = hashUniqId.sortedToc();
+                forAll(uniq, i)
+                {
+                    vertLabels[nVertLabels++] = uniq[i];
+                }
+            }
+        }
+    }
+
+    // ===========================================
+    // STAGE 3: Adjust vertOffset for all cells
+    // A second pass is needed for several reasons.
+    // - Additional (decomposed) cells are placed out of sequence
+    // - Internal format has the size prefixed, XML format does not.
+    // - XML format expects end-offsets, Internal expects begin-offsets
+
+    switch (output)
+    {
+        case contentType::LEGACY: // nothing to do
+            break;
+
+        case contentType::XML:
+        {
+            // No prefix, determine end offsets
+            // vertOffset[0] already contains its size
+            for (label i = 1; i < vertOffset.size(); ++i)
+            {
+                vertOffset[i] += vertOffset[i-1];
+            }
+
+            if (sizing.nFaceLabels())
+            {
+                // End face offsets, leaving -1 untouched
+                label prev = 0;
+                forAll(faceOffset, i)
+                {
+                    const label sz = faceOffset[i];
+                    if (sz > 0)
+                    {
+                        prev += sz;
+                        faceOffset[i] = prev;
+                    }
+                }
+            }
+            break;
+        }
+        case contentType::INTERNAL:
+        {
+            // Has prefix, determine begin offsets
+            label beg = 0;
+            forAll(vertOffset, i)
+            {
+                const label sz = vertOffset[i];
+                vertOffset[i] = beg;
+                beg += 1 + sz;
+            }
+
+            // Begin face offsets, leaving -1 untouched
+            if (sizing.nFaceLabels())
+            {
+                beg = 0;
+                forAll(faceOffset, i)
+                {
+                    const label sz = faceOffset[i];
+                    if (sz > 0)
+                    {
+                        faceOffset[i] = beg;
+                        beg += sz;
+                    }
+                }
+            }
+            break;
+        }
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/Make/files b/src/fileFormats/Make/files
index ab7fe26dc28d14e0a433dd49fb4a3dc37aab39ab..1dd9b3469a2679b3844693cd628dfeba20f7ef7d 100644
--- a/src/fileFormats/Make/files
+++ b/src/fileFormats/Make/files
@@ -14,17 +14,19 @@ stl/STLCore.C
 stl/STLReader.C
 stl/STLReaderASCII.L
 
-vtk/foamVtkCore.C
-vtk/format/foamVtkAppendBase64Formatter.C
-vtk/format/foamVtkAppendRawFormatter.C
+vtk/core/foamVtkCore.C
+vtk/core/foamVtkPTraits.C
+vtk/format/foamVtkFormatter.C
 vtk/format/foamVtkAsciiFormatter.C
 vtk/format/foamVtkBase64Formatter.C
+vtk/format/foamVtkAppendBase64Formatter.C
+vtk/format/foamVtkAppendRawFormatter.C
 vtk/format/foamVtkBase64Layer.C
-vtk/format/foamVtkLegacyFormatter.C
-vtk/format/foamVtkFormatter.C
-vtk/format/foamVtkOutputOptions.C
+vtk/format/foamVtkLegacyAsciiFormatter.C
+vtk/format/foamVtkLegacyRawFormatter.C
+vtk/output/foamVtkOutput.C
+vtk/output/foamVtkOutputOptions.C
 vtk/read/vtkUnstructuredReader.C
-vtk/type/foamVtkPTraits.C
 
 coordSet/coordSet.C
 
diff --git a/src/fileFormats/sampledSetWriters/vtk/vtkSetWriter.C b/src/fileFormats/sampledSetWriters/vtk/vtkSetWriter.C
index 87996eeff58910db32a716548cb5572c5920979d..f48080f69dbfd9f8e103e3dfd0611151edfca089 100644
--- a/src/fileFormats/sampledSetWriters/vtk/vtkSetWriter.C
+++ b/src/fileFormats/sampledSetWriters/vtk/vtkSetWriter.C
@@ -79,7 +79,6 @@ void Foam::vtkSetWriter<Type>::write
         os  << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
     }
 
-
     os  << "POINT_DATA " << points.size() << nl
         << " FIELD attributes " << valueSetNames.size() << nl;
 
diff --git a/src/fileFormats/vtk/core/foamVtkCore.C b/src/fileFormats/vtk/core/foamVtkCore.C
new file mode 100644
index 0000000000000000000000000000000000000000..be0cffa033ed79ea971d761a6457c5f2b8e25ea1
--- /dev/null
+++ b/src/fileFormats/vtk/core/foamVtkCore.C
@@ -0,0 +1,71 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 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 "foamVtkCore.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+const Foam::Enum<Foam::vtk::fileTag> Foam::vtk::fileTagNames
+{
+    { fileTag::VTK_FILE, "VTKFile" },
+    { fileTag::DATA_ARRAY, "DataArray" },
+    { fileTag::PIECE, "Piece" },
+    { fileTag::DATA_SET, "DataSet" },
+    { fileTag::POINTS, "Points" },
+    { fileTag::CELLS, "Cells" },
+    { fileTag::POLYS, "Polys" },
+    { fileTag::VERTS, "Verts" },
+    { fileTag::LINES, "Lines" },
+    { fileTag::CELL_DATA, "CellData" },
+    { fileTag::POINT_DATA, "PointData" },
+    { fileTag::POLY_DATA, "PolyData" },
+    { fileTag::UNSTRUCTURED_GRID, "UnstructuredGrid" },
+};
+
+
+const Foam::Enum<Foam::vtk::fileAttr> Foam::vtk::fileAttrNames
+{
+    { fileAttr::OFFSET, "offset" },
+    { fileAttr::NUMBER_OF_COMPONENTS, "NumberOfComponents" },
+    { fileAttr::NUMBER_OF_POINTS, "NumberOfPoints" },
+    { fileAttr::NUMBER_OF_CELLS, "NumberOfCells" },
+    { fileAttr::NUMBER_OF_POLYS, "NumberOfPolys" },
+    { fileAttr::NUMBER_OF_VERTS, "NumberOfVerts" },
+    { fileAttr::NUMBER_OF_LINES, "NumberOfLines" },
+};
+
+
+const Foam::Enum<Foam::vtk::dataArrayAttr> Foam::vtk::dataArrayAttrNames
+{
+    { dataArrayAttr::POINTS, "Points" },
+    { dataArrayAttr::OFFSETS, "offsets" },
+    { dataArrayAttr::CONNECTIVITY, "connectivity" },
+    { dataArrayAttr::TYPES, "types" },
+    { dataArrayAttr::FACES, "faces" },
+    { dataArrayAttr::FACEOFFSETS, "faceoffsets" },
+};
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/vtk/core/foamVtkCore.H b/src/fileFormats/vtk/core/foamVtkCore.H
new file mode 100644
index 0000000000000000000000000000000000000000..d209d60c9315ac608c86e34d839dd7f495b23697
--- /dev/null
+++ b/src/fileFormats/vtk/core/foamVtkCore.H
@@ -0,0 +1,163 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016-2017 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/>.
+
+Namespace
+    Foam::vtk
+
+Description
+    Namespace for handling VTK input/output.
+
+SourceFiles
+    foamVtkCore.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef foamVtkCore_H
+#define foamVtkCore_H
+
+#include "Enum.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace vtk
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+  // Enumerations
+
+    //- The context when outputting a VTK file (XML or legacy).
+    enum OutputContext
+    {
+        INLINE,     //<! Generate header and inline data
+        HEADER,     //<! Generate header only
+        APPEND      //<! Generate append-data
+    };
+
+
+    //- The output format type for file contents.
+    //  Upper bits for output type, lower bits for the format itself.
+    enum class formatType
+    {
+        /** XML inline ASCII, using the asciiFormatter */
+        INLINE_ASCII  = 0,
+        /** XML inline base64, using the base64Formatter */
+        INLINE_BASE64 = 0x01,
+        /** XML append base64, using the appendBase64Formatter */
+        APPEND_BASE64 = 0x11,
+        /** XML append raw binary, using the appendRawFormatter */
+        APPEND_BINARY = 0x12,
+        /** Legacy ASCII, using the legacyAsciiFormatter */
+        LEGACY_ASCII  = 0x20,
+        /** Legacy raw binary, using the legacyRawFormatter */
+        LEGACY_BINARY = 0x22,
+    };
+
+    //- Equivalent to enumeration in "vtkCellType.h"
+    enum cellType
+    {
+        VTK_EMPTY_CELL       = 0,
+        VTK_VERTEX           = 1,
+        VTK_POLY_VERTEX      = 2,
+        VTK_LINE             = 3,
+        VTK_POLY_LINE        = 4,
+        VTK_TRIANGLE         = 5,
+        VTK_TRIANGLE_STRIP   = 6,
+        VTK_POLYGON          = 7,
+        VTK_PIXEL            = 8,
+        VTK_QUAD             = 9,
+        VTK_TETRA            = 10,
+        VTK_VOXEL            = 11,
+        VTK_HEXAHEDRON       = 12,
+        VTK_WEDGE            = 13,
+        VTK_PYRAMID          = 14,
+        VTK_PENTAGONAL_PRISM = 15,
+        VTK_HEXAGONAL_PRISM  = 16,
+        VTK_POLYHEDRON       = 42
+    };
+
+
+    //- Some common XML tags for vtk files
+    enum class fileTag
+    {
+        VTK_FILE,               //!< "VTKFile"
+        DATA_ARRAY,             //!< "DataArray"
+        PIECE,                  //!< "Piece"
+        DATA_SET,               //!< "DataSet"
+        POINTS,                 //!< "Points"
+        CELLS,                  //!< "Cells"
+        POLYS,                  //!< "Polys"
+        VERTS,                  //!< "Verts"
+        LINES,                  //!< "Lines"
+        CELL_DATA,              //!< "CellData"
+        POINT_DATA,             //!< "PointData"
+        POLY_DATA,              //!< "PolyData"
+        UNSTRUCTURED_GRID,      //!< "UnstructuredGrid"
+    };
+
+    //- Strings corresponding to the vtk xml tags
+    extern const Foam::Enum<fileTag> fileTagNames;
+
+    //- Some common XML attributes for vtk files
+    enum class fileAttr
+    {
+        OFFSET,                 //!< "offset"
+        NUMBER_OF_COMPONENTS,   //!< "NumberOfComponents"
+        NUMBER_OF_POINTS,       //!< "NumberOfPoints"
+        NUMBER_OF_CELLS,        //!< "NumberOfCells"
+        NUMBER_OF_POLYS,        //!< "NumberOfPolys"
+        NUMBER_OF_VERTS,        //!< "NumberOfVerts"
+        NUMBER_OF_LINES,        //!< "NumberOfLines"
+    };
+
+    //- Strings corresponding to the vtk xml attributes
+    extern const Foam::Enum<fileAttr> fileAttrNames;
+
+    //- Some common names for XML data arrays
+    enum class dataArrayAttr
+    {
+        POINTS,                 //!< "Points"
+        OFFSETS,                //!< "offsets"
+        CONNECTIVITY,           //!< "connectivity"
+        TYPES,                  //!< "types"
+        FACES,                  //!< "faces"
+        FACEOFFSETS,            //!< "faceoffsets"
+    };
+
+    //- Strings corresponding to the vtk xml attributes
+    extern const Foam::Enum<dataArrayAttr> dataArrayAttrNames;
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace vtk
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/fileFormats/vtk/type/foamVtkPTraits.C b/src/fileFormats/vtk/core/foamVtkPTraits.C
similarity index 77%
rename from src/fileFormats/vtk/type/foamVtkPTraits.C
rename to src/fileFormats/vtk/core/foamVtkPTraits.C
index feb5e909c25c5b20d239452ce851f3ea431b18f9..0cc5ca04e49720ba33bc279637be951e5801f9ba 100644
--- a/src/fileFormats/vtk/type/foamVtkPTraits.C
+++ b/src/fileFormats/vtk/core/foamVtkPTraits.C
@@ -30,40 +30,40 @@ License
 
 template<>
 const char* const
-Foam::foamVtkPTraits<uint8_t>::typeName = "UInt8";
+Foam::vtkPTraits<uint8_t>::typeName = "UInt8";
 
 template<>
 const char * const
-Foam::foamVtkPTraits<int32_t>::typeName = "Int32";
+Foam::vtkPTraits<int32_t>::typeName = "Int32";
 
 template<>
 const char * const
-Foam::foamVtkPTraits<uint32_t>::typeName = "UInt32";
+Foam::vtkPTraits<uint32_t>::typeName = "UInt32";
 
 template<>
 const char * const
-Foam::foamVtkPTraits<int64_t>::typeName = "Int64";
+Foam::vtkPTraits<int64_t>::typeName = "Int64";
 
 template<>
 const char * const
-Foam::foamVtkPTraits<uint64_t>::typeName = "UInt64";
+Foam::vtkPTraits<uint64_t>::typeName = "UInt64";
 
 template<>
 const char * const
-Foam::foamVtkPTraits<float>::typeName = "Float32";
+Foam::vtkPTraits<float>::typeName = "Float32";
 
 template<>
 const char * const
-Foam::foamVtkPTraits<double>::typeName = "Float64";
+Foam::vtkPTraits<double>::typeName = "Float64";
 
 #ifdef WM_LITTLE_ENDIAN
 template<>
 const char* const
-Foam::foamVtkPTraits<Foam::endian>::typeName = "LittleEndian";
+Foam::vtkPTraits<Foam::endian>::typeName = "LittleEndian";
 #else
 template<>
 const char* const
-Foam::foamVtkPTraits<Foam::endian>::typeName = "BigEndian";
+Foam::vtkPTraits<Foam::endian>::typeName = "BigEndian";
 #endif
 
 
diff --git a/src/fileFormats/vtk/type/foamVtkPTraits.H b/src/fileFormats/vtk/core/foamVtkPTraits.H
similarity index 76%
rename from src/fileFormats/vtk/type/foamVtkPTraits.H
rename to src/fileFormats/vtk/core/foamVtkPTraits.H
index ff77c03b8d9498f97737a2435e5235c9f6bba537..ac8df0664659fe746c0c1b32e286aca89f2975e1 100644
--- a/src/fileFormats/vtk/type/foamVtkPTraits.H
+++ b/src/fileFormats/vtk/core/foamVtkPTraits.H
@@ -22,7 +22,7 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    Foam::foamVtkPTraits
+    Foam::vtkPTraits
 
 Description
     Names for VTK primitive types.
@@ -43,11 +43,11 @@ namespace Foam
 class endian;
 
 /*---------------------------------------------------------------------------*\
-                         Class foamVtkPTraits Declaration
+                         Class vtkPTraits Declaration
 \*---------------------------------------------------------------------------*/
 
 template<class PrimitiveType>
-class foamVtkPTraits
+class vtkPTraits
 {
 public:
 
@@ -58,28 +58,28 @@ public:
 
 
 template<>
-const char* const foamVtkPTraits<uint8_t>::typeName;  // UInt8
+const char* const vtkPTraits<uint8_t>::typeName;  // UInt8
 
 template<>
-const char* const foamVtkPTraits<int32_t>::typeName;  // Int32
+const char* const vtkPTraits<int32_t>::typeName;  // Int32
 
 template<>
-const char* const foamVtkPTraits<uint32_t>::typeName; // UInt32
+const char* const vtkPTraits<uint32_t>::typeName; // UInt32
 
 template<>
-const char* const foamVtkPTraits<int64_t>::typeName;  // Int64
+const char* const vtkPTraits<int64_t>::typeName;  // Int64
 
 template<>
-const char* const foamVtkPTraits<uint64_t>::typeName; // UInt64
+const char* const vtkPTraits<uint64_t>::typeName; // UInt64
 
 template<>
-const char* const foamVtkPTraits<float>::typeName;    // Float32
+const char* const vtkPTraits<float>::typeName;    // Float32
 
 template<>
-const char* const foamVtkPTraits<double>::typeName;   // Float64
+const char* const vtkPTraits<double>::typeName;   // Float64
 
 template<>
-const char* const foamVtkPTraits<Foam::endian>::typeName; // (Big|Little)Endian
+const char* const vtkPTraits<Foam::endian>::typeName; // (Big|Little)Endian
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/fileFormats/vtk/format/foamVtkAppendBase64Formatter.C b/src/fileFormats/vtk/format/foamVtkAppendBase64Formatter.C
index 3805b61812e783c4bddd29582c2cc442a45e815f..5527e5c35aefc28cc4ce9d9bbc34fae72e434002 100644
--- a/src/fileFormats/vtk/format/foamVtkAppendBase64Formatter.C
+++ b/src/fileFormats/vtk/format/foamVtkAppendBase64Formatter.C
@@ -24,15 +24,19 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "foamVtkAppendBase64Formatter.H"
+#include "foamVtkOutputOptions.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
-const char* Foam::foamVtkAppendBase64Formatter::name_ = "append";
+const char* Foam::vtk::appendBase64Formatter::name_ = "append";
+
+const Foam::vtk::outputOptions
+Foam::vtk::appendBase64Formatter::opts_(formatType::APPEND_BASE64);
 
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::foamVtkAppendBase64Formatter::foamVtkAppendBase64Formatter
+Foam::vtk::appendBase64Formatter::appendBase64Formatter
 (
     std::ostream& os
 )
@@ -43,7 +47,7 @@ Foam::foamVtkAppendBase64Formatter::foamVtkAppendBase64Formatter
 
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
-Foam::foamVtkAppendBase64Formatter::~foamVtkAppendBase64Formatter()
+Foam::vtk::appendBase64Formatter::~appendBase64Formatter()
 {
     base64Layer::close();
 }
@@ -51,7 +55,14 @@ Foam::foamVtkAppendBase64Formatter::~foamVtkAppendBase64Formatter()
 
 // * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-const char* Foam::foamVtkAppendBase64Formatter::name() const
+const Foam::vtk::outputOptions&
+Foam::vtk::appendBase64Formatter::opts() const
+{
+    return opts_;
+}
+
+
+const char* Foam::vtk::appendBase64Formatter::name() const
 {
     return name_;
 }
diff --git a/src/fileFormats/vtk/format/foamVtkAppendBase64Formatter.H b/src/fileFormats/vtk/format/foamVtkAppendBase64Formatter.H
index db3e1d6694fffda7c0869e1ae43916bce97dc2fb..2df2e8ce508822ffe804bcabb6be3c69480ef591 100644
--- a/src/fileFormats/vtk/format/foamVtkAppendBase64Formatter.H
+++ b/src/fileFormats/vtk/format/foamVtkAppendBase64Formatter.H
@@ -22,7 +22,7 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    foamVtkAppendBase64Formatter
+    Foam::vtk::appendBase64Formatter
 
 Description
     Appended base-64 encoded binary output.
@@ -42,27 +42,30 @@ SourceFiles
 
 namespace Foam
 {
+namespace vtk
+{
 
 /*---------------------------------------------------------------------------*\
-                Class foamVtkAppendBase64Formatter Declaration
+                    Class appendBase64Formatter Declaration
 \*---------------------------------------------------------------------------*/
 
-class foamVtkAppendBase64Formatter
+class appendBase64Formatter
 :
     public foamVtkBase64Layer
 {
     // Private Data Members
 
         static const char* name_;
+        static const outputOptions opts_;
 
 
     // Private Member Functions
 
-    //- Disallow default bitwise copy construct
-    foamVtkAppendBase64Formatter(const foamVtkAppendBase64Formatter&) = delete;
+        //- Disallow default bitwise copy construct
+        appendBase64Formatter(const appendBase64Formatter&) = delete;
 
-    //- Disallow default bitwise assignment
-    void operator=(const foamVtkAppendBase64Formatter&) = delete;
+        //- Disallow default bitwise assignment
+        void operator=(const appendBase64Formatter&) = delete;
 
 
 public:
@@ -70,15 +73,18 @@ public:
     // Constructors
 
         //- Construct and attach to an output stream
-        foamVtkAppendBase64Formatter(std::ostream& os);
+        appendBase64Formatter(std::ostream& os);
 
 
     //- Destructor
-    virtual ~foamVtkAppendBase64Formatter();
+    virtual ~appendBase64Formatter();
 
 
     // Member Functions
 
+        //- The output is APPEND_BASE64.
+        virtual const outputOptions& opts() const;
+
         //- Output name for XML type ("append")
         virtual const char* name() const;
 
@@ -86,6 +92,7 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace vtk
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/fileFormats/vtk/format/foamVtkAppendRawFormatter.C b/src/fileFormats/vtk/format/foamVtkAppendRawFormatter.C
index ae565323b8546a93739d9eca782a519a039f8b52..0ff9e5c4cd74b228be7193f07e200588ec1739df 100644
--- a/src/fileFormats/vtk/format/foamVtkAppendRawFormatter.C
+++ b/src/fileFormats/vtk/format/foamVtkAppendRawFormatter.C
@@ -24,16 +24,20 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "foamVtkAppendRawFormatter.H"
+#include "foamVtkOutputOptions.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
-const char* Foam::foamVtkAppendRawFormatter::name_     = "append";
-const char* Foam::foamVtkAppendRawFormatter::encoding_ = "raw";
+const char* Foam::vtk::appendRawFormatter::name_     = "append";
+const char* Foam::vtk::appendRawFormatter::encoding_ = "raw";
+
+const Foam::vtk::outputOptions
+Foam::vtk::appendRawFormatter::opts_(formatType::APPEND_BINARY);
 
 
 // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
 
-void Foam::foamVtkAppendRawFormatter::write
+void Foam::vtk::appendRawFormatter::write
 (
     const char* s,
     std::streamsize n
@@ -45,59 +49,66 @@ void Foam::foamVtkAppendRawFormatter::write
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::foamVtkAppendRawFormatter::foamVtkAppendRawFormatter(std::ostream& os)
+Foam::vtk::appendRawFormatter::appendRawFormatter(std::ostream& os)
 :
-    foamVtkFormatter(os)
+    formatter(os)
 {}
 
 
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
-Foam::foamVtkAppendRawFormatter::~foamVtkAppendRawFormatter()
+Foam::vtk::appendRawFormatter::~appendRawFormatter()
 {}
 
 
 // * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-const char* Foam::foamVtkAppendRawFormatter::name() const
+const Foam::vtk::outputOptions&
+Foam::vtk::appendRawFormatter::opts() const
+{
+    return opts_;
+}
+
+
+const char* Foam::vtk::appendRawFormatter::name() const
 {
     return name_;
 }
 
 
-const char* Foam::foamVtkAppendRawFormatter::encoding() const
+const char* Foam::vtk::appendRawFormatter::encoding() const
 {
     return encoding_;
 }
 
 
-void Foam::foamVtkAppendRawFormatter::writeSize(const uint64_t nBytes)
+void Foam::vtk::appendRawFormatter::writeSize(const uint64_t nBytes)
 {
     write(reinterpret_cast<const char*>(&nBytes), sizeof(uint64_t));
 }
 
 
-void Foam::foamVtkAppendRawFormatter::write(const uint8_t val)
+void Foam::vtk::appendRawFormatter::write(const uint8_t val)
 {
     write(reinterpret_cast<const char*>(&val), sizeof(uint8_t));
 }
 
 
-void Foam::foamVtkAppendRawFormatter::write(const label val)
+void Foam::vtk::appendRawFormatter::write(const label val)
 {
     // std::cerr<<"label:" << sizeof(val) << "=" << val << '\n';
     write(reinterpret_cast<const char*>(&val), sizeof(label));
 }
 
 
-void Foam::foamVtkAppendRawFormatter::write(const float val)
+void Foam::vtk::appendRawFormatter::write(const float val)
 {
     // std::cerr<<"float:" << sizeof(val) << "=" << val << '\n';
     write(reinterpret_cast<const char*>(&val), sizeof(float));
 }
 
 
-void Foam::foamVtkAppendRawFormatter::write(const double val)
+void Foam::vtk::appendRawFormatter::write(const double val)
 {
     // std::cerr<<"double as float=" << val << '\n';
     float copy(val);
@@ -105,7 +116,7 @@ void Foam::foamVtkAppendRawFormatter::write(const double val)
 }
 
 
-void Foam::foamVtkAppendRawFormatter::flush()
+void Foam::vtk::appendRawFormatter::flush()
 {/*nop*/}
 
 
diff --git a/src/fileFormats/vtk/format/foamVtkAppendRawFormatter.H b/src/fileFormats/vtk/format/foamVtkAppendRawFormatter.H
index 1dcb9b8d55c39a2fd3845947c0e2b8915effddbe..758fa8d93d964396e92f0f06759f519336c7f3e7 100644
--- a/src/fileFormats/vtk/format/foamVtkAppendRawFormatter.H
+++ b/src/fileFormats/vtk/format/foamVtkAppendRawFormatter.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2016-2017 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -22,7 +22,7 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    foamVtkAppendRawFormatter
+    Foam::vtk::appendRawFormatter
 
 Description
     Appended raw binary output.
@@ -41,27 +41,31 @@ SourceFiles
 
 namespace Foam
 {
+namespace vtk
+{
 
 /*---------------------------------------------------------------------------*\
-                  Class foamVtkAppendRawFormatter Declaration
+                     Class appendRawFormatter Declaration
 \*---------------------------------------------------------------------------*/
 
-class foamVtkAppendRawFormatter
+class appendRawFormatter
 :
-    public foamVtkFormatter
+    public formatter
 {
     // Private Data Members
 
         static const char* name_;
         static const char* encoding_;
+        static const outputOptions opts_;
+
 
     // Private Member Functions
 
         //- Disallow default bitwise copy construct
-        foamVtkAppendRawFormatter(const foamVtkAppendRawFormatter&) = delete;
+        appendRawFormatter(const appendRawFormatter&) = delete;
 
         //- Disallow default bitwise assignment
-        void operator=(const foamVtkAppendRawFormatter&) = delete;
+        void operator=(const appendRawFormatter&) = delete;
 
 
 protected:
@@ -77,15 +81,18 @@ public:
     // Constructors
 
         //- Construct and attach to an output stream
-        foamVtkAppendRawFormatter(std::ostream& os);
+        appendRawFormatter(std::ostream& os);
 
 
     //- Destructor
-    virtual ~foamVtkAppendRawFormatter();
+    virtual ~appendRawFormatter();
 
 
     // Member Functions
 
+        //- The output is APPEND_BINARY.
+        virtual const outputOptions& opts() const;
+
         //- Output name for XML type ("append")
         virtual const char* name() const;
 
@@ -108,6 +115,7 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace vtk
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/fileFormats/vtk/format/foamVtkAsciiFormatter.C b/src/fileFormats/vtk/format/foamVtkAsciiFormatter.C
index 9ed22db23303d3239a446e6328f435a7f8268c6f..1bcbc3b84cf40c8f7e8b1752bbcadb8fef62e516 100644
--- a/src/fileFormats/vtk/format/foamVtkAsciiFormatter.C
+++ b/src/fileFormats/vtk/format/foamVtkAsciiFormatter.C
@@ -24,15 +24,19 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "foamVtkAsciiFormatter.H"
+#include "foamVtkOutputOptions.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
-const char* Foam::foamVtkAsciiFormatter::name_ = "ascii";
+const char* Foam::vtk::asciiFormatter::name_ = "ascii";
+
+const Foam::vtk::outputOptions
+Foam::vtk::asciiFormatter::opts_(formatType::INLINE_ASCII);
 
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-inline void Foam::foamVtkAsciiFormatter::next()
+inline void Foam::vtk::asciiFormatter::next()
 {
     if (pos_ == 6)
     {
@@ -47,7 +51,7 @@ inline void Foam::foamVtkAsciiFormatter::next()
 }
 
 
-inline void Foam::foamVtkAsciiFormatter::done()
+inline void Foam::vtk::asciiFormatter::done()
 {
     if (pos_)
     {
@@ -59,20 +63,20 @@ inline void Foam::foamVtkAsciiFormatter::done()
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::foamVtkAsciiFormatter::foamVtkAsciiFormatter(std::ostream& os)
+Foam::vtk::asciiFormatter::asciiFormatter(std::ostream& os)
 :
-    foamVtkFormatter(os),
+    formatter(os),
     pos_(0)
 {}
 
 
-Foam::foamVtkAsciiFormatter::foamVtkAsciiFormatter
+Foam::vtk::asciiFormatter::asciiFormatter
 (
     std::ostream& os,
     unsigned precision
 )
 :
-    foamVtkFormatter(os),
+    formatter(os),
     pos_(0)
 {
     os.precision(precision);
@@ -81,7 +85,7 @@ Foam::foamVtkAsciiFormatter::foamVtkAsciiFormatter
 
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
-Foam::foamVtkAsciiFormatter::~foamVtkAsciiFormatter()
+Foam::vtk::asciiFormatter::~asciiFormatter()
 {
     done();
 }
@@ -89,58 +93,65 @@ Foam::foamVtkAsciiFormatter::~foamVtkAsciiFormatter()
 
 // * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-const char* Foam::foamVtkAsciiFormatter::name() const
+const Foam::vtk::outputOptions&
+Foam::vtk::asciiFormatter::opts() const
+{
+    return opts_;
+}
+
+
+const char* Foam::vtk::asciiFormatter::name() const
 {
     return name_;
 }
 
 
-const char* Foam::foamVtkAsciiFormatter::encoding() const
+const char* Foam::vtk::asciiFormatter::encoding() const
 {
     return name_;
 }
 
 
-void Foam::foamVtkAsciiFormatter::writeSize(const uint64_t ignored)
+void Foam::vtk::asciiFormatter::writeSize(const uint64_t ignored)
 {/*nop*/}
 
 
-void Foam::foamVtkAsciiFormatter::write(const uint8_t val)
+void Foam::vtk::asciiFormatter::write(const uint8_t val)
 {
     next();
     os()<< int(val);
 }
 
 
-void Foam::foamVtkAsciiFormatter::write(const label val)
+void Foam::vtk::asciiFormatter::write(const label val)
 {
     next();
     os()<< val;
 }
 
 
-void Foam::foamVtkAsciiFormatter::write(const float val)
+void Foam::vtk::asciiFormatter::write(const float val)
 {
     next();
     os()<< val;
 }
 
 
-void Foam::foamVtkAsciiFormatter::write(const double val)
+void Foam::vtk::asciiFormatter::write(const double val)
 {
     next();
     os()<< float(val);
 }
 
 
-void Foam::foamVtkAsciiFormatter::flush()
+void Foam::vtk::asciiFormatter::flush()
 {
     done();
 }
 
 
 std::size_t
-Foam::foamVtkAsciiFormatter::encodedLength(std::size_t ignored) const
+Foam::vtk::asciiFormatter::encodedLength(std::size_t ignored) const
 {
     return 0;
 }
diff --git a/src/fileFormats/vtk/format/foamVtkAsciiFormatter.H b/src/fileFormats/vtk/format/foamVtkAsciiFormatter.H
index 8b8e06b2a226c855c2243f89f4675aeb4bc2251c..bbedc55e91e138b78d834f7594cd2b4e4ef217fc 100644
--- a/src/fileFormats/vtk/format/foamVtkAsciiFormatter.H
+++ b/src/fileFormats/vtk/format/foamVtkAsciiFormatter.H
@@ -22,10 +22,10 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    foamVtkAsciiFormatter
+    Foam::vtk::asciiFormatter
 
 Description
-    Inline ASCII binary output.
+    Inline ASCII output.
     Adds spaces between entries and a newline every 6 items
     (for consistency with what VTK itself outputs).
 
@@ -43,18 +43,21 @@ SourceFiles
 
 namespace Foam
 {
+namespace vtk
+{
 
 /*---------------------------------------------------------------------------*\
-                    Class foamVtkAsciiFormatter Declaration
+                       Class asciiFormatter Declaration
 \*---------------------------------------------------------------------------*/
 
-class foamVtkAsciiFormatter
+class asciiFormatter
 :
-    public foamVtkFormatter
+    public formatter
 {
     // Private Data Members
 
         static const char* name_;
+        static const outputOptions opts_;
 
         //- Track the current output position
         unsigned short pos_;
@@ -70,10 +73,10 @@ class foamVtkAsciiFormatter
 
 
         //- Disallow default bitwise copy construct
-        foamVtkAsciiFormatter(const foamVtkAsciiFormatter&) = delete;
+        asciiFormatter(const asciiFormatter&) = delete;
 
         //- Disallow default bitwise assignment
-        void operator=(const foamVtkAsciiFormatter&) = delete;
+        void operator=(const asciiFormatter&) = delete;
 
 
 public:
@@ -81,20 +84,22 @@ public:
     // Constructors
 
         //- Construct and attach to an output stream, use default precision
-        foamVtkAsciiFormatter(std::ostream& os);
+        asciiFormatter(std::ostream& os);
 
         //- Construct and attach to an output stream, use specified precision
-        foamVtkAsciiFormatter(std::ostream& os, unsigned precision);
+        asciiFormatter(std::ostream& os, unsigned precision);
 
 
     //- Destructor
-    virtual ~foamVtkAsciiFormatter();
+    virtual ~asciiFormatter();
 
 
     // Member Functions
 
+        //- The output is INLINE_ASCII.
+        virtual const outputOptions& opts() const;
+
         //- Name for the XML output type ("ascii")
-        //  The legacy output type is an uppercase version of this.
         virtual const char* name() const;
 
         //- Name for the XML append encoding - unused.
@@ -120,6 +125,7 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace vtk
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/fileFormats/vtk/format/foamVtkBase64Formatter.C b/src/fileFormats/vtk/format/foamVtkBase64Formatter.C
index f87efbb19f4972a65dd02f9c40eb56800696e0bb..3e8d86be9545193e911a6850a6106342c76f4c16 100644
--- a/src/fileFormats/vtk/format/foamVtkBase64Formatter.C
+++ b/src/fileFormats/vtk/format/foamVtkBase64Formatter.C
@@ -24,15 +24,19 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "foamVtkBase64Formatter.H"
+#include "foamVtkOutputOptions.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
-const char* Foam::foamVtkBase64Formatter::name_ = "binary";
+const char* Foam::vtk::base64Formatter::name_ = "binary";
+
+const Foam::vtk::outputOptions
+Foam::vtk::base64Formatter::opts_(formatType::INLINE_BASE64);
 
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::foamVtkBase64Formatter::foamVtkBase64Formatter(std::ostream& os)
+Foam::vtk::base64Formatter::base64Formatter(std::ostream& os)
 :
     foamVtkBase64Layer(os)
 {}
@@ -40,7 +44,7 @@ Foam::foamVtkBase64Formatter::foamVtkBase64Formatter(std::ostream& os)
 
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
-Foam::foamVtkBase64Formatter::~foamVtkBase64Formatter()
+Foam::vtk::base64Formatter::~base64Formatter()
 {
     if (base64Layer::close())
     {
@@ -51,13 +55,20 @@ Foam::foamVtkBase64Formatter::~foamVtkBase64Formatter()
 
 // * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-const char* Foam::foamVtkBase64Formatter::name() const
+const Foam::vtk::outputOptions&
+Foam::vtk::base64Formatter::opts() const
+{
+    return opts_;
+}
+
+
+const char* Foam::vtk::base64Formatter::name() const
 {
     return name_;
 }
 
 
-void Foam::foamVtkBase64Formatter::flush()
+void Foam::vtk::base64Formatter::flush()
 {
     if (base64Layer::close())
     {
diff --git a/src/fileFormats/vtk/format/foamVtkBase64Formatter.H b/src/fileFormats/vtk/format/foamVtkBase64Formatter.H
index e92fa4f9e374c21c8ead9795234d6c777b8ab381..df27f23087be308cf51947694fe86c384ac265e4 100644
--- a/src/fileFormats/vtk/format/foamVtkBase64Formatter.H
+++ b/src/fileFormats/vtk/format/foamVtkBase64Formatter.H
@@ -22,7 +22,7 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    foamVtkBase64Formatter
+    Foam::vtk::base64Formatter
 
 Description
     Inline base-64 encoded binary output.
@@ -33,51 +33,57 @@ Description
 #ifndef foamVtkBase64Formatter_H
 #define foamVtkBase64Formatter_H
 
+#include "foamVtkFormatter.H"
 #include "foamVtkBase64Layer.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
+namespace vtk
+{
 
 /*---------------------------------------------------------------------------*\
-                   Class foamVtkBase64Formatter Declaration
+                       Class base64Formatter Declaration
 \*---------------------------------------------------------------------------*/
 
-class foamVtkBase64Formatter
+class base64Formatter
 :
     public foamVtkBase64Layer
 {
     // Private Data Members
 
         static const char* name_;
-        static const char* encoding_;
+        static const outputOptions opts_;
 
 
     // Private Member Functions
 
         //- Disallow default bitwise copy construct
-        foamVtkBase64Formatter(const foamVtkBase64Formatter&) = delete;
+        base64Formatter(const base64Formatter&) = delete;
 
         //- Disallow default bitwise assignment
-        void operator=(const foamVtkBase64Formatter&) = delete;
+        void operator=(const base64Formatter&) = delete;
+
 
 public:
 
     // Constructors
 
         //- Construct and attach to an output stream
-        foamVtkBase64Formatter(std::ostream& os);
+        base64Formatter(std::ostream& os);
 
 
     //- Destructor
-    virtual ~foamVtkBase64Formatter();
+    virtual ~base64Formatter();
 
 
     // Member Functions
 
+        //- The output is INLINE_BASE64.
+        virtual const outputOptions& opts() const;
+
         //- Name for the XML output type ("binary")
-        //  The lowercase version of the Legacy output type.
         virtual const char* name() const;
 
 
@@ -89,6 +95,7 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace vtk
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/fileFormats/vtk/format/foamVtkBase64Layer.C b/src/fileFormats/vtk/format/foamVtkBase64Layer.C
index d66970d522b7e356eb03e711557b66985939bcd2..500a8dce9c041f9d0f8a95d6b46ed095fbfa5c32 100644
--- a/src/fileFormats/vtk/format/foamVtkBase64Layer.C
+++ b/src/fileFormats/vtk/format/foamVtkBase64Layer.C
@@ -27,12 +27,12 @@ License
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
-const char* Foam::foamVtkBase64Layer::encoding_ = "base64";
+const char* Foam::vtk::foamVtkBase64Layer::encoding_ = "base64";
 
 
 // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
 
-void Foam::foamVtkBase64Layer::write
+void Foam::vtk::foamVtkBase64Layer::write
 (
     const char* s,
     std::streamsize n
@@ -44,16 +44,16 @@ void Foam::foamVtkBase64Layer::write
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::foamVtkBase64Layer::foamVtkBase64Layer(std::ostream& os)
+Foam::vtk::foamVtkBase64Layer::foamVtkBase64Layer(std::ostream& os)
 :
-    foamVtkFormatter(os),
+    formatter(os),
     base64Layer(os)
 {}
 
 
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
-Foam::foamVtkBase64Layer::~foamVtkBase64Layer()
+Foam::vtk::foamVtkBase64Layer::~foamVtkBase64Layer()
 {
     base64Layer::close();
 }
@@ -61,39 +61,39 @@ Foam::foamVtkBase64Layer::~foamVtkBase64Layer()
 
 // * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-const char* Foam::foamVtkBase64Layer::encoding() const
+const char* Foam::vtk::foamVtkBase64Layer::encoding() const
 {
     return encoding_;
 }
 
 
-void Foam::foamVtkBase64Layer::writeSize(const uint64_t nBytes)
+void Foam::vtk::foamVtkBase64Layer::writeSize(const uint64_t nBytes)
 {
     write(reinterpret_cast<const char*>(&nBytes), sizeof(uint64_t));
 }
 
 
-void Foam::foamVtkBase64Layer::write(const uint8_t val)
+void Foam::vtk::foamVtkBase64Layer::write(const uint8_t val)
 {
     base64Layer::add(val);
 }
 
 
-void Foam::foamVtkBase64Layer::write(const label val)
+void Foam::vtk::foamVtkBase64Layer::write(const label val)
 {
     // std::cerr<<"label:" << sizeof(val) << "=" << val << '\n';
     write(reinterpret_cast<const char*>(&val), sizeof(label));
 }
 
 
-void Foam::foamVtkBase64Layer::write(const float val)
+void Foam::vtk::foamVtkBase64Layer::write(const float val)
 {
     // std::cerr<<"float:" << sizeof(val) << "=" << val << '\n';
     write(reinterpret_cast<const char*>(&val), sizeof(float));
 }
 
 
-void Foam::foamVtkBase64Layer::write(const double val)
+void Foam::vtk::foamVtkBase64Layer::write(const double val)
 {
     // std::cerr<<"double as float=" << val << '\n';
     float copy(val);
@@ -101,13 +101,16 @@ void Foam::foamVtkBase64Layer::write(const double val)
 }
 
 
-void Foam::foamVtkBase64Layer::flush()
+void Foam::vtk::foamVtkBase64Layer::flush()
 {
     base64Layer::close();
 }
 
 
-std::size_t Foam::foamVtkBase64Layer::encodedLength(std::size_t n) const
+std::size_t Foam::vtk::foamVtkBase64Layer::encodedLength
+(
+    std::size_t n
+) const
 {
     return base64Layer::encodedLength(n);
 }
diff --git a/src/fileFormats/vtk/format/foamVtkBase64Layer.H b/src/fileFormats/vtk/format/foamVtkBase64Layer.H
index 61527a11bc02d6047ef6ee8b28bca8e61f978584..6bfa3652d4da34d125067278e4a3f7f6ed7a6045 100644
--- a/src/fileFormats/vtk/format/foamVtkBase64Layer.H
+++ b/src/fileFormats/vtk/format/foamVtkBase64Layer.H
@@ -22,10 +22,10 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    foamVtkBase64Layer
+    Foam::vtk::foamVtkBase64Layer
 
 Description
-    Base-64 encoded output.
+    Base-64 encoded output layer - normally only used indirectly by formatters.
 
 \*---------------------------------------------------------------------------*/
 
@@ -39,14 +39,16 @@ Description
 
 namespace Foam
 {
+namespace vtk
+{
 
 /*---------------------------------------------------------------------------*\
-                   Class foamVtkBase64Layer Declaration
+                     Class foamVtkBase64Layer Declaration
 \*---------------------------------------------------------------------------*/
 
 class foamVtkBase64Layer
 :
-    public foamVtkFormatter,
+    public formatter,
     protected base64Layer
 {
     // Private Data Members
@@ -62,6 +64,7 @@ class foamVtkBase64Layer
         //- Disallow default bitwise assignment
         void operator=(const foamVtkBase64Layer&) = delete;
 
+
 protected:
 
     // Protected Member Functions
@@ -105,6 +108,7 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace vtk
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/fileFormats/vtk/format/foamVtkFormatter.C b/src/fileFormats/vtk/format/foamVtkFormatter.C
index 5b9fded769abb084d5ed0f4e9e13fb16928919a1..2bb49322d38927976bc34eea1afbfbcdc61954ff 100644
--- a/src/fileFormats/vtk/format/foamVtkFormatter.C
+++ b/src/fileFormats/vtk/format/foamVtkFormatter.C
@@ -24,31 +24,21 @@ License
 
 #include "foamVtkFormatter.H"
 
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::foamVtkFormatter::foamVtkFormatter(std::ostream& os)
-:
-    os_(os),
-    xmlTags_(),
-    inTag_(false)
-{}
-
-
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
-Foam::foamVtkFormatter::~foamVtkFormatter()
+Foam::vtk::formatter::~formatter()
 {}
 
 
 // * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-std::size_t Foam::foamVtkFormatter::encodedLength(std::size_t n) const
+std::size_t Foam::vtk::formatter::encodedLength(std::size_t n) const
 {
     return n;
 }
 
 
-void Foam::foamVtkFormatter::indent()
+void Foam::vtk::formatter::indent()
 {
     label n = xmlTags_.size() * 2;
     while (n--)
@@ -58,8 +48,8 @@ void Foam::foamVtkFormatter::indent()
 }
 
 
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::xmlHeader()
+Foam::vtk::formatter&
+Foam::vtk::formatter::xmlHeader()
 {
     if (inTag_)
     {
@@ -74,8 +64,8 @@ Foam::foamVtkFormatter::xmlHeader()
 }
 
 
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::comment(const std::string& text)
+Foam::vtk::formatter&
+Foam::vtk::formatter::xmlComment(const std::string& comment)
 {
     if (inTag_)
     {
@@ -85,34 +75,35 @@ Foam::foamVtkFormatter::comment(const std::string& text)
     }
 
     indent();
-    os_ << "<!-- " << text << " -->" << nl;
+    os_ << "<!-- " << comment << " -->" << nl;
 
     return *this;
 }
 
 
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::openTag(const word& tag)
+Foam::vtk::formatter&
+Foam::vtk::formatter::openTag(const word& tagName)
 {
     if (inTag_)
     {
         WarningInFunction
-            << "open XML tag '" << tag << "', but already within a tag!"
+            << "open XML tag '" << tagName
+            << "', but already within a tag!"
             << endl;
     }
 
     indent();
-    os_ << '<' << tag;
+    os_ << '<' << tagName;
 
-    xmlTags_.push(tag);
+    xmlTags_.push(tagName);
     inTag_ = true;
 
     return *this;
 }
 
 
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::closeTag(const bool isEmpty)
+Foam::vtk::formatter&
+Foam::vtk::formatter::closeTag(const bool isEmpty)
 {
     if (!inTag_)
     {
@@ -135,8 +126,8 @@ Foam::foamVtkFormatter::closeTag(const bool isEmpty)
 }
 
 
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::endTag(const word& tag)
+Foam::vtk::formatter&
+Foam::vtk::formatter::endTag(const word& tagName)
 {
     const word curr = xmlTags_.pop();
     indent();
@@ -149,11 +140,11 @@ Foam::foamVtkFormatter::endTag(const word& tag)
             << endl;
     }
 
-    // verify inTag_
-    if (!tag.empty() && tag != curr)
+    // verify expected end tag
+    if (!tagName.empty() && tagName != curr)
     {
         WarningInFunction
-            << "expected to end xml-tag '" << tag
+            << "expecting to end xml-tag '" << tagName
             << "' but found '" << curr << "' instead"
             << endl;
     }
@@ -166,29 +157,19 @@ Foam::foamVtkFormatter::endTag(const word& tag)
 }
 
 
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::tag(const word& tag)
-{
-    openTag(tag);
-    closeTag();
-
-    return *this;
-}
-
-
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::beginVTKFile
+Foam::vtk::formatter&
+Foam::vtk::formatter::beginVTKFile
 (
     const word& contentType,
     const word& contentVersion,
     const bool leaveOpen
 )
 {
-    openTag("VTKFile");
+    openTag(vtk::fileTag::VTK_FILE);
     xmlAttr("type",        contentType);
     xmlAttr("version",     contentVersion);
-    xmlAttr("byte_order",  foamVtkPTraits<Foam::endian>::typeName);
-    xmlAttr("header_type", foamVtkPTraits<headerType>::typeName);
+    xmlAttr("byte_order",  vtkPTraits<Foam::endian>::typeName);
+    xmlAttr("header_type", vtkPTraits<headerType>::typeName);
     closeTag();
 
     openTag(contentType);
@@ -201,8 +182,15 @@ Foam::foamVtkFormatter::beginVTKFile
 }
 
 
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::beginAppendedData()
+Foam::vtk::formatter&
+Foam::vtk::formatter::endVTKFile()
+{
+    return endTag(vtk::fileTag::VTK_FILE);
+}
+
+
+Foam::vtk::formatter&
+Foam::vtk::formatter::beginAppendedData()
 {
     openTag("AppendedData");
     xmlAttr("encoding", encoding());
@@ -213,8 +201,17 @@ Foam::foamVtkFormatter::beginAppendedData()
 }
 
 
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::xmlAttr
+Foam::vtk::formatter&
+Foam::vtk::formatter::endAppendedData()
+{
+    flush();     // flush any pending encoded content
+    os_ << nl;   // ensure clear separation from content.
+    return endTag("AppendedData");
+}
+
+
+Foam::vtk::formatter&
+Foam::vtk::formatter::xmlAttr
 (
     const word& k,
     const std::string& v,
@@ -234,89 +231,4 @@ Foam::foamVtkFormatter::xmlAttr
 }
 
 
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::xmlAttr
-(
-    const word& k,
-    const int32_t v,
-    const char quote
-)
-{
-    return xmlAttribute(k, v, quote);
-}
-
-
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::xmlAttr
-(
-    const word& k,
-    const int64_t v,
-    const char quote
-)
-{
-    return xmlAttribute(k, v, quote);
-}
-
-
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::xmlAttr
-(
-    const word& k,
-    const uint64_t v,
-    const char quote
-)
-{
-    return xmlAttribute(k, v, quote);
-}
-
-
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::xmlAttr
-(
-    const word& k,
-    const scalar v,
-    const char quote
-)
-{
-    return xmlAttribute(k, v, quote);
-}
-
-
-// * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * //
-
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::operator()(const word& k, const std::string& v)
-{
-    return xmlAttr(k, v);
-}
-
-
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::operator()(const word& k, const int32_t v)
-{
-    return xmlAttr(k, v);
-}
-
-
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::operator()(const word& k, const int64_t v)
-{
-    return xmlAttr(k, v);
-}
-
-
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::operator()(const word& k, const uint64_t v)
-{
-    return xmlAttr(k, v);
-}
-
-
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::operator()(const word& k, const scalar v)
-{
-    return xmlAttr(k, v);
-}
-
-
 // ************************************************************************* //
diff --git a/src/fileFormats/vtk/format/foamVtkFormatter.H b/src/fileFormats/vtk/format/foamVtkFormatter.H
index 9e37f2c6253ff5a70dc48becccbcf93b2287ee93..abe6e2972d51c0b7cf451e52e60af52b61ad41a9 100644
--- a/src/fileFormats/vtk/format/foamVtkFormatter.H
+++ b/src/fileFormats/vtk/format/foamVtkFormatter.H
@@ -22,15 +22,16 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    foamVtkFormatter
+    Foam::vtk::formatter
 
 Description
     Abstract class for a VTK output stream formatter.
 
-    Includes very simple support for writing XML tags.
+    Includes very simple support for writing XML elements.
 
 SourceFiles
     foamVtkFormatter.C
+    foamVtkFormatterTemplates.C
 
 \*---------------------------------------------------------------------------*/
 
@@ -43,6 +44,7 @@ SourceFiles
 #include "word.H"
 #include "UList.H"
 #include "LIFOStack.H"
+#include "foamVtkCore.H"
 #include "foamVtkPTraits.H"
 
 #include <iostream>
@@ -51,12 +53,16 @@ SourceFiles
 
 namespace Foam
 {
+namespace vtk
+{
+
+class outputOptions;
 
 /*---------------------------------------------------------------------------*\
-                      Class foamVtkFormatter Declaration
+                          Class formatter Declaration
 \*---------------------------------------------------------------------------*/
 
-class foamVtkFormatter
+class formatter
 {
     // Private Data
 
@@ -70,13 +76,15 @@ class foamVtkFormatter
         mutable bool inTag_;
 
 
-        //- Write XML attribute
+    // Private Member Functions
+
+        //- Write XML attribute key/value pair
         template<class Type>
-        foamVtkFormatter& xmlAttribute
+        formatter& writeAttribute
         (
             const word& k,
             const Type& v,
-            const char quote
+            const char quote = '\''
         );
 
 
@@ -85,7 +93,7 @@ protected:
     // Protected Member Functions
 
         //- Construct and attach to an output stream
-        foamVtkFormatter(std::ostream& os);
+        inline formatter(std::ostream& os);
 
 public:
 
@@ -96,20 +104,20 @@ public:
 
 
     //- Destructor
-    virtual ~foamVtkFormatter();
+    virtual ~formatter();
 
 
     // Member Functions
 
+      // Access
+
         //- Access to the underlying output stream
-        inline std::ostream& os()
-        {
-            return os_;
-        }
+        inline std::ostream& os();
 
+        //- The format-type / output options.
+        virtual const outputOptions& opts() const = 0;
 
-        //- Name for the XML output type.
-        //  Possibly the lowercase version of the Legacy output type
+        //- Name for the XML output type or the legacy output type.
         virtual const char* name() const = 0;
 
         //- Name for the XML append encoding
@@ -134,79 +142,113 @@ public:
 
     // Member Functions
 
+      // Output
+
         //- Indent according to the currently nested XML tags
         void indent();
 
         //- Write XML header
-        foamVtkFormatter& xmlHeader();
+        //  \return formatter for chaining
+        formatter& xmlHeader();
 
         //- Write XML comment (at the current indentation level)
-        foamVtkFormatter& comment(const std::string& text);
+        //  \return formatter for chaining
+        formatter& xmlComment(const std::string& comment);
+
 
+        //- Open XML tag
+        //  \return formatter for chaining
+        formatter& openTag(const word& tagName);
 
         //- Open XML tag
-        foamVtkFormatter& openTag(const word& tag);
+        //  \return formatter for chaining
+        inline formatter& openTag(const vtk::fileTag& tagEnum);
 
         //- Close XML tag, optional as an empty container.
         //  Always adds a trailing newline.
-        foamVtkFormatter& closeTag(const bool isEmpty = false);
+        //  \return formatter for chaining
+        formatter& closeTag(const bool isEmpty = false);
 
         //- End XML tag, optional with sanity check
         //  Always adds a trailing newline.
-        foamVtkFormatter& endTag(const word& tag = word::null);
+        //  \return formatter for chaining
+        formatter& endTag(const word& tagName = word::null);
+
+        //- End XML tag with sanity check
+        //  Always adds a trailing newline.
+        //  \return formatter for chaining
+        inline formatter& endTag(const vtk::fileTag& tagEnum);
 
         //- Write XML tag without any attributes. Combines openTag/closeTag.
-        foamVtkFormatter& tag(const word& tag);
+        //  \return formatter for chaining
+        inline formatter& tag(const word& tagName);
+
+        //- Write XML tag without any attributes. Combines openTag/closeTag.
+        //  \return formatter for chaining
+        inline formatter& tag(const vtk::fileTag& tagEnum);
 
         //- Add a "VTKFile" XML tag for contentType, followed by a tag for
         //  the contentType itself. Optionally leave the contentType tag
         //  open for adding additional attributes.
-        foamVtkFormatter& beginVTKFile
+        //  \return formatter for chaining
+        formatter& beginVTKFile
         (
             const word& contentType,
             const word& contentVersion,
             const bool leaveOpen = false
         );
 
-        //- Add a "AppendedData" XML tag with the current encoding and  output
+        //- Add a "VTKFile" XML tag for contentType, followed by a tag for
+        //  the contentType itself. Optionally leave the contentType tag
+        //  open for adding additional attributes.
+        //  \return formatter for chaining
+        inline formatter& beginVTKFile
+        (
+            const vtk::fileTag& contentType,
+            const word& contentVersion,
+            const bool leaveOpen = false
+        );
+
+        //- Add a "AppendedData" XML tag with the current encoding and output
         //  the requisite '_' prefix.
-        foamVtkFormatter& beginAppendedData();
+        //  \return formatter for chaining
+        formatter& beginAppendedData();
+
 
+        //- Open "DataArray" XML tag
+        //  \return formatter for chaining
+        template<class Type, int nComp=0>
+        formatter& openDataArray(const word& dataName);
 
         //- Open "DataArray" XML tag
+        //  \return formatter for chaining
         template<class Type, int nComp=0>
-        foamVtkFormatter& openDataArray(const word& dataName);
+        formatter& openDataArray(const vtk::dataArrayAttr& attrEnum);
 
 
         //- Insert a single "PDataArray" XML entry tag.
         //  For some entries, the name is optional.
+        //  \return formatter for chaining
         template<class Type, int nComp=0>
-        foamVtkFormatter& PDataArray(const word& dataName);
+        formatter& PDataArray(const word& dataName);
 
 
         //- End "DataArray" XML tag
-        inline foamVtkFormatter& endDataArray()
-        {
-            return endTag("DataArray");
-        }
+        //  \return formatter for chaining
+        inline formatter& endDataArray();
 
         //- End "AppendedData" XML tag
-        inline foamVtkFormatter& endAppendedData()
-        {
-            flush();     // flush any pending encoded content
-            os_ << '\n'; // clear separation from content.
-            return endTag("AppendedData");
-        }
+        //  \return formatter for chaining
+        formatter& endAppendedData();
 
         //- End "VTKFile" XML tag
-        inline foamVtkFormatter& endVTKFile()
-        {
-            return endTag("VTKFile");
-        }
+        //  \return formatter for chaining
+        formatter& endVTKFile();
 
 
         //- Write XML attribute
-        foamVtkFormatter& xmlAttr
+        //  \return formatter for chaining
+        formatter& xmlAttr
         (
             const word& k,
             const std::string& v,
@@ -214,7 +256,8 @@ public:
         );
 
         //- Write XML attribute
-        foamVtkFormatter& xmlAttr
+        //  \return formatter for chaining
+        inline formatter& xmlAttr
         (
             const word& k,
             const int32_t v,
@@ -222,7 +265,8 @@ public:
         );
 
         //- Write XML attribute
-        foamVtkFormatter& xmlAttr
+        //  \return formatter for chaining
+        inline formatter& xmlAttr
         (
             const word& k,
             const int64_t v,
@@ -230,7 +274,8 @@ public:
         );
 
         //- Write XML attribute
-        foamVtkFormatter& xmlAttr
+        //  \return formatter for chaining
+        inline formatter& xmlAttr
         (
             const word& k,
             const uint64_t v,
@@ -238,41 +283,53 @@ public:
         );
 
         //- Write XML attribute
-        foamVtkFormatter& xmlAttr
+        //  \return formatter for chaining
+        inline formatter& xmlAttr
         (
             const word& k,
             const scalar v,
             const char quote = '\''
         );
 
-
-
-    // Member Operators
-
         //- Write XML attribute
-        foamVtkFormatter& operator()(const word& k, const std::string& v);
-
-        //- Write XML attribute
-        foamVtkFormatter& operator()(const word& k, const int32_t v);
-
-        //- Write XML attribute
-        foamVtkFormatter& operator()(const word& k, const int64_t v);
+        //  \return formatter for chaining
+        inline formatter& xmlAttr
+        (
+            const vtk::fileAttr& attrEnum,
+            const int32_t v,
+            const char quote = '\''
+        );
 
         //- Write XML attribute
-        foamVtkFormatter& operator()(const word& k, const uint64_t v);
+        //  \return formatter for chaining
+        inline formatter& xmlAttr
+        (
+            const vtk::fileAttr& attrEnum,
+            const int64_t v,
+            const char quote = '\''
+        );
 
         //- Write XML attribute
-        foamVtkFormatter& operator()(const word& k, const scalar v);
+        //  \return formatter for chaining
+        inline formatter& xmlAttr
+        (
+            const vtk::fileAttr& attrEnum,
+            const uint64_t v,
+            const char quote = '\''
+        );
 
 };
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace vtk
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+#include "foamVtkFormatterI.H"
+
 #ifdef NoRepository
     #include "foamVtkFormatterTemplates.C"
 #endif
diff --git a/src/fileFormats/vtk/format/foamVtkFormatterI.H b/src/fileFormats/vtk/format/foamVtkFormatterI.H
new file mode 100644
index 0000000000000000000000000000000000000000..58e050bf54223b03609bab01eff9afe9f385e85a
--- /dev/null
+++ b/src/fileFormats/vtk/format/foamVtkFormatterI.H
@@ -0,0 +1,183 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 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/>.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+inline Foam::vtk::formatter::formatter(std::ostream& os)
+:
+    os_(os),
+    xmlTags_(),
+    inTag_(false)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+inline std::ostream& Foam::vtk::formatter::os()
+{
+    return os_;
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::openTag(const vtk::fileTag& tagEnum)
+{
+    return openTag(vtk::fileTagNames[tagEnum]);
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::endTag(const vtk::fileTag& tagEnum)
+{
+    return endTag(vtk::fileTagNames[tagEnum]);
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::tag(const word& tagName)
+{
+    openTag(tagName);
+    closeTag();
+
+    return *this;
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::tag(const vtk::fileTag& tagEnum)
+{
+    return tag(vtk::fileTagNames[tagEnum]);
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::beginVTKFile
+(
+    const vtk::fileTag& contentType,
+    const word& contentVersion,
+    const bool leaveOpen
+)
+{
+    return beginVTKFile
+    (
+        vtk::fileTagNames[contentType],
+        contentVersion,
+        leaveOpen
+    );
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::endDataArray()
+{
+    return endTag("DataArray");
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::xmlAttr
+(
+    const word& k,
+    const int32_t v,
+    const char quote
+)
+{
+    return writeAttribute(k, v, quote);
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::xmlAttr
+(
+    const word& k,
+    const int64_t v,
+    const char quote
+)
+{
+    return writeAttribute(k, v, quote);
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::xmlAttr
+(
+    const word& k,
+    const uint64_t v,
+    const char quote
+)
+{
+    return writeAttribute(k, v, quote);
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::xmlAttr
+(
+    const word& k,
+    const scalar v,
+    const char quote
+)
+{
+    return writeAttribute(k, v, quote);
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::xmlAttr
+(
+    const vtk::fileAttr& attrEnum,
+    const int32_t v,
+    const char quote
+)
+{
+    return xmlAttr(vtk::fileAttrNames[attrEnum], v, quote);
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::xmlAttr
+(
+    const vtk::fileAttr& attrEnum,
+    const int64_t v,
+    const char quote
+)
+{
+    return xmlAttr(vtk::fileAttrNames[attrEnum], v, quote);
+}
+
+
+inline Foam::vtk::formatter&
+Foam::vtk::formatter::xmlAttr
+(
+    const vtk::fileAttr& attrEnum,
+    const uint64_t v,
+    const char quote
+)
+{
+    return xmlAttr(vtk::fileAttrNames[attrEnum], v, quote);
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/vtk/format/foamVtkFormatterTemplates.C b/src/fileFormats/vtk/format/foamVtkFormatterTemplates.C
index 1cde34a61e278147dca32ef073238687476c8672..87f4f9131b50ccfdc3fb37088d95c240e57a147e 100644
--- a/src/fileFormats/vtk/format/foamVtkFormatterTemplates.C
+++ b/src/fileFormats/vtk/format/foamVtkFormatterTemplates.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2016-2017 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -27,8 +27,8 @@ License
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 template<class Type>
-Foam::foamVtkFormatter&
-Foam::foamVtkFormatter::xmlAttribute
+Foam::vtk::formatter&
+Foam::vtk::formatter::writeAttribute
 (
     const word& k,
     const Type& v,
@@ -49,17 +49,18 @@ Foam::foamVtkFormatter::xmlAttribute
 
 
 template<class Type, int nComp>
-Foam::foamVtkFormatter& Foam::foamVtkFormatter::openDataArray
+Foam::vtk::formatter&
+Foam::vtk::formatter::openDataArray
 (
     const word& dataName
 )
 {
     openTag("DataArray");
-    xmlAttr("type", foamVtkPTraits<Type>::typeName);
+    xmlAttr("type", vtkPTraits<Type>::typeName);
     xmlAttr("Name", dataName);
     if (nComp > 1)
     {
-        xmlAttr("NumberOfComponents", nComp);
+        xmlAttr(fileAttr::NUMBER_OF_COMPONENTS, nComp);
     }
     xmlAttr("format", name());
 
@@ -68,20 +69,32 @@ Foam::foamVtkFormatter& Foam::foamVtkFormatter::openDataArray
 
 
 template<class Type, int nComp>
-Foam::foamVtkFormatter& Foam::foamVtkFormatter::PDataArray
+Foam::vtk::formatter&
+Foam::vtk::formatter::openDataArray
+(
+    const vtk::dataArrayAttr& attrEnum
+)
+{
+    return openDataArray<Type, nComp>(vtk::dataArrayAttrNames[attrEnum]);
+}
+
+
+template<class Type, int nComp>
+Foam::vtk::formatter&
+Foam::vtk::formatter::PDataArray
 (
     const word& dataName
 )
 {
     openTag("PDataArray");
-    xmlAttr("type", foamVtkPTraits<Type>::typeName);
+    xmlAttr("type", vtkPTraits<Type>::typeName);
     if (dataName.size())
     {
         xmlAttr("Name", dataName);
     }
     if (nComp > 1)
     {
-        xmlAttr("NumberOfComponents", nComp);
+        xmlAttr(fileAttr::NUMBER_OF_COMPONENTS, nComp);
     }
 
     closeTag(true);
@@ -89,4 +102,5 @@ Foam::foamVtkFormatter& Foam::foamVtkFormatter::PDataArray
     return *this;
 }
 
+
 // ************************************************************************* //
diff --git a/src/fileFormats/vtk/foamVtkCore.C b/src/fileFormats/vtk/format/foamVtkLegacyAsciiFormatter.C
similarity index 57%
rename from src/fileFormats/vtk/foamVtkCore.C
rename to src/fileFormats/vtk/format/foamVtkLegacyAsciiFormatter.C
index 2450c02b7b2d0c1c7acc86c9a1c7f6395410bbc0..fe8728854cfdf726ed709a9db4215dbe418073cd 100644
--- a/src/fileFormats/vtk/foamVtkCore.C
+++ b/src/fileFormats/vtk/format/foamVtkLegacyAsciiFormatter.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -23,32 +23,63 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "foamVtkCore.H"
+#include "foamVtkLegacyAsciiFormatter.H"
+#include "foamVtkOutputOptions.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
+const char* Foam::vtk::legacyAsciiFormatter::legacyName_ = "ASCII";
+
+const Foam::vtk::outputOptions
+Foam::vtk::legacyAsciiFormatter::opts_(formatType::LEGACY_ASCII);
+
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::fileFormats::foamVtkCore::foamVtkCore()
+Foam::vtk::legacyAsciiFormatter::legacyAsciiFormatter
+(
+    std::ostream& os
+)
+:
+    asciiFormatter(os)
 {}
 
 
-// * * * * * * * * * * *  Protected Member Functions * * * * * * * * * * * * //
+Foam::vtk::legacyAsciiFormatter::legacyAsciiFormatter
+(
+    std::ostream& os,
+    unsigned precision
+)
+:
+    asciiFormatter(os, precision)
+{}
 
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
-/*
-Foam::fileName Foam::fileFormats::foamVtkCore::vtkFileName
-(
-    const fileName& base,
-    const enum fileExt ext
-)
+Foam::vtk::legacyAsciiFormatter::~legacyAsciiFormatter()
+{}
+
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+const Foam::vtk::outputOptions&
+Foam::vtk::legacyAsciiFormatter::opts() const
+{
+    return opts_;
+}
+
+
+const char* Foam::vtk::legacyAsciiFormatter::name() const
+{
+    return legacyName_;
+}
+
+
+const char* Foam::vtk::legacyAsciiFormatter::encoding() const
 {
-    return base + '.' + fileExtensions_[ext];
+    return legacyName_;
 }
-*/
 
 
 // ************************************************************************* //
diff --git a/src/fileFormats/vtk/format/foamVtkLegacyAsciiFormatter.H b/src/fileFormats/vtk/format/foamVtkLegacyAsciiFormatter.H
new file mode 100644
index 0000000000000000000000000000000000000000..7301ef98540366f2d639cfad965aaab809a5d38a
--- /dev/null
+++ b/src/fileFormats/vtk/format/foamVtkLegacyAsciiFormatter.H
@@ -0,0 +1,109 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 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::vtk::legacyAsciiFormatter
+
+Description
+    Formatting as per Foam::vtk::asciiFormatter, but with
+    naming for legacy output.
+
+SourceFiles
+    foamVtkLegacyAsciiFormatter.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef foamVtkLegacyAsciiFormatter_H
+#define foamVtkLegacyAsciiFormatter_H
+
+#include "foamVtkAsciiFormatter.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace vtk
+{
+
+/*---------------------------------------------------------------------------*\
+                    Class legacyAsciiFormatter Declaration
+\*---------------------------------------------------------------------------*/
+
+class legacyAsciiFormatter
+:
+    public asciiFormatter
+{
+    // Private Data Members
+
+        static const char* legacyName_;
+        static const outputOptions opts_;
+
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        legacyAsciiFormatter(const legacyAsciiFormatter&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const legacyAsciiFormatter&) = delete;
+
+
+public:
+
+    // Constructors
+
+        //- Construct and attach to an output stream, use default precision
+        legacyAsciiFormatter(std::ostream& os);
+
+        //- Construct and attach to an output stream, use specified precision
+        legacyAsciiFormatter(std::ostream& os, unsigned precision);
+
+
+    //- Destructor
+    virtual ~legacyAsciiFormatter();
+
+
+    // Member Functions
+
+        //- The output is LEGACY_ASCII.
+        virtual const outputOptions& opts() const;
+
+        //- Name for the legacy ascii output type ("ASCII")
+        virtual const char* name() const;
+
+        //- Name for the XML append encoding (unused).
+        //  Currently identical to name(), but do not rely on this.
+        virtual const char* encoding() const;
+
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace vtk
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/fileFormats/vtk/format/foamVtkLegacyFormatter.C b/src/fileFormats/vtk/format/foamVtkLegacyRawFormatter.C
similarity index 74%
rename from src/fileFormats/vtk/format/foamVtkLegacyFormatter.C
rename to src/fileFormats/vtk/format/foamVtkLegacyRawFormatter.C
index a3e87264f82fc1bc30977fa0f7dd4ed02f3a86e0..28b042c1959732dc78893606ffbac2c58fdc2762 100644
--- a/src/fileFormats/vtk/format/foamVtkLegacyFormatter.C
+++ b/src/fileFormats/vtk/format/foamVtkLegacyRawFormatter.C
@@ -23,17 +23,21 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "foamVtkLegacyFormatter.H"
+#include "foamVtkLegacyRawFormatter.H"
+#include "foamVtkOutputOptions.H"
 #include "endian.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
-const char* Foam::foamVtkLegacyFormatter::name_ = "BINARY";
+const char* Foam::vtk::legacyRawFormatter::legacyName_ = "BINARY";
+
+const Foam::vtk::outputOptions
+Foam::vtk::legacyRawFormatter::opts_(formatType::LEGACY_BINARY);
 
 
 // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
 
-void Foam::foamVtkLegacyFormatter::write
+void Foam::vtk::legacyRawFormatter::write
 (
     const char* s,
     std::streamsize n
@@ -45,37 +49,53 @@ void Foam::foamVtkLegacyFormatter::write
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::foamVtkLegacyFormatter::foamVtkLegacyFormatter(std::ostream& os)
+Foam::vtk::legacyRawFormatter::legacyRawFormatter
+(
+    std::ostream& os
+)
 :
-    foamVtkFormatter(os)
+    formatter(os)
 {}
 
 
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
-Foam::foamVtkLegacyFormatter::~foamVtkLegacyFormatter()
+Foam::vtk::legacyRawFormatter::~legacyRawFormatter()
 {}
 
 
 // * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-const char* Foam::foamVtkLegacyFormatter::name() const
+const Foam::vtk::outputOptions&
+Foam::vtk::legacyRawFormatter::opts() const
 {
-    return name_;
+    return opts_;
 }
 
 
-const char* Foam::foamVtkLegacyFormatter::encoding() const
+const char* Foam::vtk::legacyRawFormatter::name() const
 {
-    return name_;
+    return legacyName_;
 }
 
 
-void Foam::foamVtkLegacyFormatter::writeSize(const uint64_t ignored)
+const char* Foam::vtk::legacyRawFormatter::encoding() const
+{
+    return legacyName_;
+}
+
+
+void Foam::vtk::legacyRawFormatter::writeSize
+(
+    const uint64_t ignored
+)
 {/*nop*/}
 
 
-void Foam::foamVtkLegacyFormatter::write(const uint8_t val)
+void Foam::vtk::legacyRawFormatter::write
+(
+    const uint8_t val
+)
 {
     // Legacy can only handle 32-bit integers.
     // Nonetheless promote to 'label' (32 or 64 bit) and deal with it later
@@ -84,7 +104,10 @@ void Foam::foamVtkLegacyFormatter::write(const uint8_t val)
 }
 
 
-void Foam::foamVtkLegacyFormatter::write(const label val)
+void Foam::vtk::legacyRawFormatter::write
+(
+    const label val
+)
 {
     // std::cerr<<"label is:" << sizeof(val) << '\n';
 
@@ -104,7 +127,10 @@ void Foam::foamVtkLegacyFormatter::write(const label val)
 }
 
 
-void Foam::foamVtkLegacyFormatter::write(const float val)
+void Foam::vtk::legacyRawFormatter::write
+(
+    const float val
+)
 {
     // std::cerr<<"float is:" << sizeof(val) << '\n';
 
@@ -122,7 +148,10 @@ void Foam::foamVtkLegacyFormatter::write(const float val)
 }
 
 
-void Foam::foamVtkLegacyFormatter::write(const double val)
+void Foam::vtk::legacyRawFormatter::write
+(
+    const double val
+)
 {
     // Legacy cannot support Float64 anyhow.
     // std::cerr<<"write double as float:" << val << '\n';
@@ -131,7 +160,7 @@ void Foam::foamVtkLegacyFormatter::write(const double val)
 }
 
 
-void Foam::foamVtkLegacyFormatter::flush()
+void Foam::vtk::legacyRawFormatter::flush()
 {
     os()<< '\n';
 }
diff --git a/src/fileFormats/vtk/format/foamVtkLegacyFormatter.H b/src/fileFormats/vtk/format/foamVtkLegacyRawFormatter.H
similarity index 80%
rename from src/fileFormats/vtk/format/foamVtkLegacyFormatter.H
rename to src/fileFormats/vtk/format/foamVtkLegacyRawFormatter.H
index 6ec5ba7e8dd37209a9bc92c6b91fa2e479e75eac..3f24f05cb07555a57921887108f7f06f160f9403 100644
--- a/src/fileFormats/vtk/format/foamVtkLegacyFormatter.H
+++ b/src/fileFormats/vtk/format/foamVtkLegacyRawFormatter.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016-2017 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -22,7 +22,7 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    foamVtkLegacyFormatter
+    Foam::vtk::legacyRawFormatter
 
 Description
     Binary output for the VTK legacy format, always written as big-endian
@@ -31,12 +31,12 @@ Description
     This format should never be used for OpenFOAM with 64-bit label sizes.
 
 SourceFiles
-    foamVtkLegacyFormatter.C
+    foamVtkLegacyRawFormatter.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef foamVtkLegacyFormatter_H
-#define foamVtkLegacyFormatter_H
+#ifndef foamVtkLegacyRawFormatter_H
+#define foamVtkLegacyRawFormatter_H
 
 #include "foamVtkFormatter.H"
 
@@ -44,27 +44,30 @@ SourceFiles
 
 namespace Foam
 {
+namespace vtk
+{
 
 /*---------------------------------------------------------------------------*\
-                   Class foamVtkLegacyFormatter Declaration
+                       Class legacyRawFormatter Declaration
 \*---------------------------------------------------------------------------*/
 
-class foamVtkLegacyFormatter
+class legacyRawFormatter
 :
-    public foamVtkFormatter
+    public formatter
 {
     // Private Data Members
 
-        static const char* name_;
+        static const char* legacyName_;
+        static const outputOptions opts_;
 
 
     // Private Member Functions
 
         //- Disallow default bitwise copy construct
-        foamVtkLegacyFormatter(const foamVtkLegacyFormatter&) = delete;
+        legacyRawFormatter(const legacyRawFormatter&) = delete;
 
         //- Disallow default bitwise assignment
-        void operator=(const foamVtkLegacyFormatter&) = delete;
+        void operator=(const legacyRawFormatter&) = delete;
 
 
 protected:
@@ -80,15 +83,18 @@ public:
     // Constructors
 
         //- Construct and attach to an output stream
-        foamVtkLegacyFormatter(std::ostream& os);
+        legacyRawFormatter(std::ostream& os);
 
 
     //- Destructor
-    virtual ~foamVtkLegacyFormatter();
+    virtual ~legacyRawFormatter();
 
 
     // Member Functions
 
+        //- The output is LEGACY_BINARY.
+        virtual const outputOptions& opts() const;
+
         //- Name for the legacy binary output type ("BINARY")
         virtual const char* name() const;
 
@@ -112,6 +118,7 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace vtk
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/fileFormats/vtk/format/foamVtkOutputOptions.C b/src/fileFormats/vtk/format/foamVtkOutputOptions.C
deleted file mode 100644
index c88d334594d14289c27237b66c66839fb89f5def..0000000000000000000000000000000000000000
--- a/src/fileFormats/vtk/format/foamVtkOutputOptions.C
+++ /dev/null
@@ -1,235 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016-2017 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 "foamVtkOutputOptions.H"
-
-#include "foamVtkAppendBase64Formatter.H"
-#include "foamVtkAppendRawFormatter.H"
-#include "foamVtkAsciiFormatter.H"
-#include "foamVtkBase64Formatter.H"
-#include "foamVtkLegacyFormatter.H"
-
-#include "IOstream.H"
-
-
-// * * * * * * * * * * * * * * Constructor * * * * * * * * * * * * * //
-
-Foam::foamVtkOutputOptions::foamVtkOutputOptions()
-:
-    type_(ASCII),
-    precision_(IOstream::defaultPrecision())
-{}
-
-
-// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
-
-Foam::autoPtr<Foam::foamVtkFormatter>
-Foam::foamVtkOutputOptions::newFormatter(std::ostream& os) const
-{
-    switch (type_)
-    {
-        case (LEGACY | BINARY):
-            return autoPtr<foamVtkFormatter>
-            (
-                new foamVtkLegacyFormatter(os)
-            );
-
-        case BASE64:  // xml insitu
-            return autoPtr<foamVtkFormatter>
-            (
-                new foamVtkBase64Formatter(os)
-            );
-
-        case (APPEND | BASE64):
-            return autoPtr<foamVtkFormatter>
-            (
-                new foamVtkAppendBase64Formatter(os)
-            );
-
-        case (APPEND | BINARY):
-            return autoPtr<foamVtkFormatter>
-            (
-                new foamVtkAppendRawFormatter(os)
-            );
-
-        default:   // ASCII (legacy or xml) must always work
-            return autoPtr<foamVtkFormatter>
-            (
-                new foamVtkAsciiFormatter(os, precision_)
-            );
-    }
-}
-
-
-// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
-
-void Foam::foamVtkOutputOptions::ascii(bool on)
-{
-    if (on)
-    {
-        // Force ASCII:
-
-        if (type_ & APPEND)
-        {
-            // Append: ascii = base64 (vs raw binary)
-            type_ = (APPEND | BASE64);
-        }
-        else if (type_ & LEGACY)
-        {
-            // Legacy: ascii = ascii
-            type_ = (LEGACY | ASCII);
-        }
-        else
-        {
-            // XML: ascii = ascii
-            type_ = ASCII;
-        }
-    }
-    else
-    {
-        // Non-ASCII:
-
-        if (type_ & APPEND)
-        {
-            // Append: binary == (raw) binary
-            type_ = APPEND | BINARY;
-        }
-        else if (type_ & LEGACY)
-        {
-            // Legacy: binary = binary
-            type_ = LEGACY | BINARY;
-        }
-        else
-        {
-            // XML: binary == (inline) binary == base64
-            type_ = BASE64;
-        }
-    }
-}
-
-
-void Foam::foamVtkOutputOptions::append(bool on)
-{
-    if (on)
-    {
-        if (!(type_ & APPEND))
-        {
-            // XML:    base64 -> raw binary, ascii -> base64
-            // Legacy: binary -> raw binary, ascii -> base64
-            type_ = APPEND | ((type_ & (BASE64 | BINARY)) ? BINARY : BASE64);
-        }
-    }
-    else if (type_ & APPEND)
-    {
-        // Only revert back to inline XML base64 versions
-        // ASCII needs another step.
-
-        type_ = BASE64;
-    }
-}
-
-
-void Foam::foamVtkOutputOptions::legacy(bool on)
-{
-    if (on)
-    {
-        if (type_ & APPEND)
-        {
-            // Append: base64 -> ascii, binary -> binary
-            type_ = (LEGACY | ((type_ & BINARY) ? BINARY : ASCII));
-        }
-        else if (type_ & LEGACY)
-        {
-            // no-op
-        }
-        else
-        {
-            // XML: ascii -> ascii, base64 -> binary
-            type_ = (LEGACY | ((type_ & BASE64) ? BINARY : ASCII));
-        }
-    }
-    else if (type_ & LEGACY)
-    {
-        // Legacy: ascii -> xml ascii, binary -> xml base64
-        type_ = (type_ & BINARY) ? BASE64 : ASCII;
-    }
-}
-
-
-void Foam::foamVtkOutputOptions::precision(unsigned prec) const
-{
-    precision_ = prec;
-}
-
-
-Foam::Ostream& Foam::foamVtkOutputOptions::info(Ostream& os) const
-{
-    os << "type: " << type_;
-
-    switch (type_)
-    {
-        case (LEGACY | ASCII):
-            os << " legacy ascii";
-            break;
-
-        case (LEGACY | BINARY):
-            os << " legacy binary";
-            break;
-
-        case BASE64:
-            os << " xml insitu base64";
-            break;
-
-        case (APPEND | BASE64):
-            os << " xml-append base64";
-            break;
-
-        case (APPEND | BINARY):
-            os << " xml-append binary";
-            break;
-
-        case ASCII:
-            os << " xml insitu ascii";
-            break;
-
-        case BINARY:
-            os << " xml insitu binary - WRONG";
-            break;
-
-        default:
-            os << " unknown";
-            break;
-    }
-
-    if (legacy()) os << " legacy";
-    if (xml())    os << " xml";
-    if (append()) os << " append";
-    if (ascii())  os << " ascii";
-
-    return os;
-}
-
-
-// ************************************************************************* //
diff --git a/src/fileFormats/vtk/output/foamVtkOutput.C b/src/fileFormats/vtk/output/foamVtkOutput.C
new file mode 100644
index 0000000000000000000000000000000000000000..7e18f7231438a71916e30bbe4ed8335030e1022e
--- /dev/null
+++ b/src/fileFormats/vtk/output/foamVtkOutput.C
@@ -0,0 +1,146 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016-2017 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 "foamVtkOutput.H"
+
+#include "foamVtkFormatter.H"
+#include "foamVtkAsciiFormatter.H"
+#include "foamVtkBase64Formatter.H"
+#include "foamVtkAppendBase64Formatter.H"
+#include "foamVtkAppendRawFormatter.H"
+#include "foamVtkLegacyAsciiFormatter.H"
+#include "foamVtkLegacyRawFormatter.H"
+#include "typeInfo.H"
+
+// * * * * * * * * * * * * * * * Static Data * * * * * * * * * * * * * * * * //
+
+const Foam::Enum<Foam::vtk::fileTag>
+Foam::vtk::legacy::contentNames
+{
+    { vtk::fileTag::POLY_DATA,         "POLYDATA" },
+    { vtk::fileTag::UNSTRUCTURED_GRID, "UNSTRUCTURED_GRID" },
+};
+
+
+const Foam::Enum<Foam::vtk::fileTag>
+Foam::vtk::legacy::dataTypeNames
+{
+    { vtk::fileTag::CELL_DATA,  "CELL_DATA" },
+    { vtk::fileTag::POINT_DATA, "POINT_DATA" }
+};
+
+
+// * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * * //
+
+Foam::autoPtr<Foam::vtk::formatter>
+Foam::vtk::newFormatter
+(
+    std::ostream& os,
+    const enum formatType fmtType,
+    unsigned prec
+)
+{
+    autoPtr<vtk::formatter> fmt;
+
+    switch (fmtType)
+    {
+        case formatType::INLINE_ASCII:
+            fmt.set(new vtk::asciiFormatter(os, prec));
+            break;
+
+        case formatType::INLINE_BASE64:
+            fmt.set(new vtk::base64Formatter(os));
+            break;
+
+        case formatType::APPEND_BASE64:
+            fmt.set(new vtk::appendBase64Formatter(os));
+            break;
+
+        case formatType::APPEND_BINARY:
+            fmt.set(new vtk::appendRawFormatter(os));
+            break;
+
+        case formatType::LEGACY_ASCII:
+            fmt.set(new vtk::legacyAsciiFormatter(os, prec));
+            break;
+
+        case formatType::LEGACY_BINARY:
+            fmt.set(new vtk::legacyRawFormatter(os));
+            break;
+    }
+
+    return fmt;
+}
+
+
+Foam::label Foam::vtk::writeVtmFile
+(
+    std::ostream& os,
+    const UList<fileName>& files
+)
+{
+    const word& content = "vtkMultiBlockDataSet";
+
+    asciiFormatter vtmFile(os);
+
+    vtmFile
+        .xmlHeader()
+        .beginVTKFile(content, "1.0");
+
+    forAll(files, i)
+    {
+        vtmFile
+            .openTag(vtk::fileTag::DATA_SET)
+            .xmlAttr("index", i)
+            .xmlAttr("file", files[i])
+            .closeTag(true);
+    }
+
+    vtmFile.endTag(content).endVTKFile();
+
+    return files.size();
+}
+
+
+std::ostream& Foam::vtk::legacy::fileHeader
+(
+    vtk::formatter& fmt,
+    const std::string& title,
+    const std::string& contentType
+)
+{
+    std::ostream& os = fmt.os();
+
+    fileHeader(os, title, isType<legacyRawFormatter>(fmt));
+    if (!contentType.empty())
+    {
+        os << "DATASET " << contentType.c_str() << nl;
+    }
+
+    return os;
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/vtk/output/foamVtkOutput.H b/src/fileFormats/vtk/output/foamVtkOutput.H
new file mode 100644
index 0000000000000000000000000000000000000000..c3632a11913c324ef48890691f1848ae41cc565c
--- /dev/null
+++ b/src/fileFormats/vtk/output/foamVtkOutput.H
@@ -0,0 +1,236 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016-2017 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/>.
+
+Namespace
+    Foam::vtk
+
+Description
+    Namespace for handling VTK output.
+    Contains classes and functions for writing VTK file content.
+
+Namespace
+    Foam::vtk::legacy
+
+Description
+    Namespace for legacy VTK output constants and functions.
+
+SourceFiles
+    foamVtkOutput.C
+    foamVtkOutputTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef foamVtkOutput_H
+#define foamVtkOutput_H
+
+#include "autoPtr.H"
+#include "Enum.H"
+#include "foamVtkCore.H"
+#include "foamVtkFormatter.H"
+#include "floatScalar.H"
+#include "IOstream.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace vtk
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+  // Constants
+
+  // General Functions
+
+    //- Return a default asciiFormatter
+    autoPtr<vtk::formatter> newFormatter(std::ostream& os);
+
+    //- Return a new formatter based on the specified format type
+    autoPtr<vtk::formatter> newFormatter
+    (
+        std::ostream& os,
+        const enum formatType fmtType,
+        unsigned prec = IOstream::defaultPrecision()
+    );
+
+
+    //- Write vtm datasets for specified files
+    label writeVtmFile(std::ostream& os, const UList<fileName>& files);
+
+
+    //- Write a value component-wise.
+    template<class Type>
+    inline void write
+    (
+        vtk::formatter& fmt,
+        const Type& val
+    );
+
+
+    //- Write a list of values.
+    //  The output does not include the payload size.
+    template<class Type>
+    void writeList
+    (
+        vtk::formatter& fmt,
+        const UList<Type>& lst
+    );
+
+    //- Write a list of values.
+    //  The output does not include the payload size.
+    template<class Type, unsigned Size>
+    void writeList
+    (
+        vtk::formatter& fmt,
+        const FixedList<Type, Size>& lst
+    );
+
+
+    //- Write a list of values via indirect addressing.
+    //  The output does not include the payload size.
+    template<class Type>
+    void writeList
+    (
+        vtk::formatter& fmt,
+        const UList<Type>& lst,
+        const UList<label>& addressing
+    );
+
+
+/*---------------------------------------------------------------------------*\
+                               Namespace legacy
+\*---------------------------------------------------------------------------*/
+
+//- Some minimal additional support for writing legacy files
+namespace legacy
+{
+
+  // Constants
+
+    //- Strings corresponding to the (POLYDATA, UNSTRUCTURED_GRID) elements
+    extern const Foam::Enum<vtk::fileTag> contentNames;
+
+    //- Strings corresponding to the (CELL_DATA, POINT_DATA) elements
+    extern const Foam::Enum<vtk::fileTag> dataTypeNames;
+
+
+  // Functions
+
+    //- Emit header for legacy file.
+    //  Writes "ASCII" or "BINARY" depending on specified type.
+    inline std::ostream& fileHeader
+    (
+        std::ostream& os,
+        const std::string& title,
+        const bool binary
+    );
+
+    //- Emit header for legacy file, with "ASCII" or "BINARY" depending on
+    //  the formatter type.
+    //  Includes "DATASET" with the specified dataset type.
+    inline void fileHeader
+    (
+        vtk::formatter& fmt,
+        const std::string& title,
+        const vtk::fileTag& contentTypeTag
+    );
+
+    //- Emit header for legacy file, with "ASCII" or "BINARY" depending on
+    //  the formatter type.
+    //  If the contentType is non-empty, it is used for "DATASET" line.
+    std::ostream& fileHeader
+    (
+        vtk::formatter& fmt,
+        const std::string& title,
+        const std::string& contentType
+    );
+
+
+    //- Emit header for POINTS (with trailing newline).
+    inline void beginPoints(std::ostream& os, const label nPoints);
+
+    //- Emit header for POLYGONS (with trailing newline).
+    //  The nConnectivity is the sum of all connectivity points used,
+    //  but \b without additional space for the size prefixes.
+    //  The additional prefix sizes are added internally.
+    inline void beginPolys
+    (
+        std::ostream& os,
+        const label nPolys,
+        const label nConnectivity
+    );
+
+
+    //- Use the enumerations vtk::fileTag::CELL_DATA, vtk::fileTag::POINT_DATA,
+    //  to emit a legacy CELL_DATA, POINT_DATA element.
+    //  The nEntries corresponds similarly to the number of cells or points,
+    //  respectively.
+    inline void dataHeader
+    (
+        std::ostream& os,
+        const vtk::fileTag& dataTypeTag,
+        const label nEntries,
+        const label nFields
+    );
+
+    //- Start output of float field with the specified name.
+    inline void floatField
+    (
+        std::ostream& os,
+        const word& name,
+        const int nCmpt,
+        const label nEntries
+    );
+
+    //- Start output of int field with the specified name.
+    inline void intField
+    (
+        std::ostream& os,
+        const word& name,
+        const int nCmpt,
+        const label nEntries
+    );
+
+} // End namespace legacy
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace vtk
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "foamVtkOutputI.H"
+
+#ifdef NoRepository
+    #include "foamVtkOutputTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/fileFormats/vtk/output/foamVtkOutputI.H b/src/fileFormats/vtk/output/foamVtkOutputI.H
new file mode 100644
index 0000000000000000000000000000000000000000..b7717ea66d34faaa88930bde4fb797b724d16a68
--- /dev/null
+++ b/src/fileFormats/vtk/output/foamVtkOutputI.H
@@ -0,0 +1,146 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 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/>.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * Specializations * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace vtk
+{
+
+//- Template specialization for label
+template<>
+inline void write<label>(vtk::formatter& fmt, const label& val)
+{
+    fmt.write(val);
+}
+
+
+//- Template specialization for float
+template<>
+inline void write<float>(vtk::formatter& fmt, const float& val)
+{
+    fmt.write(val);
+}
+
+
+//- Template specialization for double
+template<>
+inline void write<double>(vtk::formatter& fmt, const double& val)
+{
+    fmt.write(val);
+}
+
+} // End namespace vtk
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * * //
+
+inline std::ostream& Foam::vtk::legacy::fileHeader
+(
+    std::ostream& os,
+    const std::string& title,
+    const bool binary
+)
+{
+    os  << "# vtk DataFile Version 2.0" << nl
+        << title << nl
+        << (binary ? "BINARY" : "ASCII") << nl;
+
+    return os;
+}
+
+
+inline void Foam::vtk::legacy::fileHeader
+(
+    vtk::formatter& fmt,
+    const std::string& title,
+    const vtk::fileTag& contentTypeTag
+)
+{
+    fileHeader(fmt, title, contentNames[contentTypeTag]);
+}
+
+
+inline void Foam::vtk::legacy::beginPoints
+(
+    std::ostream& os,
+    const label nPoints
+)
+{
+    os  << "POINTS " << nPoints << " float" << nl;
+}
+
+
+inline void Foam::vtk::legacy::beginPolys
+(
+    std::ostream& os,
+    const label nPolys,
+    const label nConnectivity
+)
+{
+    os  << "POLYGONS " << nPolys << ' ' << (nPolys + nConnectivity) << nl;
+}
+
+
+inline void Foam::vtk::legacy::dataHeader
+(
+    std::ostream& os,
+    const vtk::fileTag& dataTypeTag,
+    const label nEntries,
+    const label nFields
+)
+{
+    os  << dataTypeNames[dataTypeTag] << ' ' << nEntries << nl
+        << "FIELD attributes " << nFields << nl;
+}
+
+
+inline void Foam::vtk::legacy::floatField
+(
+    std::ostream& os,
+    const word& fieldName,
+    const int nCmpt,
+    const label nEntries
+)
+{
+    os  << fieldName << ' ' << nCmpt << ' ' << nEntries << " float" << nl;
+}
+
+
+inline void Foam::vtk::legacy::intField
+(
+    std::ostream& os,
+    const word& fieldName,
+    const int nCmpt,
+    const label nEntries
+)
+{
+    os  << fieldName << ' ' << nCmpt << ' ' << nEntries << " int" << nl;
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/vtk/output/foamVtkOutputOptions.C b/src/fileFormats/vtk/output/foamVtkOutputOptions.C
new file mode 100644
index 0000000000000000000000000000000000000000..8a8c30a060ad6345ae51172eb80edfa1a871d024
--- /dev/null
+++ b/src/fileFormats/vtk/output/foamVtkOutputOptions.C
@@ -0,0 +1,187 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016-2017 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 "foamVtkOutputOptions.H"
+
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+Foam::vtk::outputOptions&
+Foam::vtk::outputOptions::ascii(bool on)
+{
+    if (on)
+    {
+        switch (fmtType_)
+        {
+            case formatType::INLINE_BASE64:
+                fmtType_ = formatType::INLINE_ASCII;
+                break;
+
+            case formatType::APPEND_BINARY:
+                fmtType_ = formatType::APPEND_BASE64;
+                break;
+
+            case formatType::LEGACY_BINARY:
+                fmtType_ = formatType::LEGACY_ASCII;
+                break;
+
+            default:  // No change
+                break;
+        }
+    }
+    else
+    {
+        switch (fmtType_)
+        {
+            case formatType::INLINE_ASCII:
+                fmtType_ = formatType::INLINE_BASE64;
+                break;
+
+            case formatType::APPEND_BASE64:
+                fmtType_ = formatType::APPEND_BINARY;
+                break;
+
+            case formatType::LEGACY_ASCII:
+                fmtType_ = formatType::LEGACY_BINARY;
+                break;
+
+            default:  // No change
+                break;
+        }
+    }
+
+    return *this;
+}
+
+
+Foam::vtk::outputOptions&
+Foam::vtk::outputOptions::append(bool on)
+{
+    if (on)
+    {
+        switch (fmtType_)
+        {
+            case formatType::INLINE_ASCII:
+            case formatType::LEGACY_ASCII:
+                fmtType_ = formatType::APPEND_BASE64;
+                break;
+
+            case formatType::INLINE_BASE64:
+            case formatType::LEGACY_BINARY:
+                fmtType_ = formatType::APPEND_BINARY;
+                break;
+
+            default:  // No change
+                break;
+        }
+    }
+    else
+    {
+        switch (fmtType_)
+        {
+            case formatType::APPEND_BASE64:
+                fmtType_ = formatType::INLINE_ASCII;
+                break;
+
+            case formatType::APPEND_BINARY:
+                fmtType_ = formatType::INLINE_BASE64;
+                break;
+
+            default:  // No change
+                break;
+        }
+    }
+
+    return *this;
+}
+
+
+Foam::vtk::outputOptions&
+Foam::vtk::outputOptions::legacy(bool on)
+{
+    if (on)
+    {
+        switch (fmtType_)
+        {
+            case formatType::INLINE_ASCII:
+            case formatType::APPEND_BASE64:
+                fmtType_ = formatType::LEGACY_ASCII;
+                break;
+
+            case formatType::INLINE_BASE64:
+            case formatType::APPEND_BINARY:
+                fmtType_ = formatType::LEGACY_BINARY;
+                break;
+
+            default:  // no change
+                break;
+        }
+    }
+    else
+    {
+        switch (fmtType_)
+        {
+            case formatType::LEGACY_ASCII:
+                fmtType_ = formatType::INLINE_ASCII;
+                break;
+
+            case formatType::LEGACY_BINARY:
+                fmtType_ = formatType::INLINE_BASE64;
+                break;
+
+            default:  // no change
+                break;
+        }
+    }
+
+    return *this;
+}
+
+
+Foam::vtk::outputOptions&
+Foam::vtk::outputOptions::precision(unsigned prec)
+{
+    precision_ = prec;
+    return *this;
+}
+
+
+Foam::string Foam::vtk::outputOptions::description() const
+{
+    switch (fmtType_)
+    {
+        case formatType::INLINE_ASCII:  return "xml ascii";
+        case formatType::INLINE_BASE64: return "xml base64";
+        case formatType::APPEND_BASE64: return "xml-append base64";
+        case formatType::APPEND_BINARY: return "xml-append binary";
+        case formatType::LEGACY_ASCII:  return "legacy ascii";
+        case formatType::LEGACY_BINARY: return "legacy binary";
+    }
+
+    return "";
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/vtk/format/foamVtkOutputOptions.H b/src/fileFormats/vtk/output/foamVtkOutputOptions.H
similarity index 62%
rename from src/fileFormats/vtk/format/foamVtkOutputOptions.H
rename to src/fileFormats/vtk/output/foamVtkOutputOptions.H
index 7e0e89b24be155f760fb45f3d16e97b71b8f57de..00e715b15cb6c7a1394f78f2e37974c7c9bf950f 100644
--- a/src/fileFormats/vtk/format/foamVtkOutputOptions.H
+++ b/src/fileFormats/vtk/output/foamVtkOutputOptions.H
@@ -22,10 +22,15 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    foamVtkOutputOptions
+    Foam::vtk::outputOptions
 
 Description
-    Encapsulate combinations of output format options.
+    Encapsulated combinations of output format options.
+    This is primarily useful when defining the output type based on some
+    command-line arguments or dictionary contents.
+    However, it can also be a useful alternative to using the underlying
+    enumeration directly, since this class provides additional methods
+    not possible with an enum.
 
 SourceFiles
     foamVtkOutputOptions.C
@@ -35,43 +40,33 @@ SourceFiles
 #ifndef foamVtkOutputOptions_H
 #define foamVtkOutputOptions_H
 
-#include "autoPtr.H"
-#include "foamVtkFormatter.H"
+#include "foamVtkOutput.H"
+#include "string.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
-class Ostream;
+namespace vtk
+{
 
 /*---------------------------------------------------------------------------*\
-                    Class foamVtkOutputOptions Declaration
+                        Class outputOptions Declaration
 \*---------------------------------------------------------------------------*/
 
-class foamVtkOutputOptions
+class outputOptions
 {
-    // Private data
-
-        //- The supported output/format types
-        enum foamVtkOptionTypes
-        {
-            ASCII  = 0x0000,    //!< ASCII formatting for data
-            BINARY = 0x0001,    //!< Raw binary formatting for data
-            BASE64 = 0x0002,    //!< Base64 encoding for data
-            LEGACY = 0x0100,    //!< Legacy vtk file format
-            APPEND = 0x0200     //!< XML append format
-        };
+    // Private Member Data
 
         //- The output style tuning
-        enum foamVtkStyleOptions
+        enum styleType
         {
-            NONE   = 0x0000,    //!< Normal
-            HEADER = 0x0001     //!< Emit xml header
+            NONE   = 0x00,  //!< Normal
+            HEADER = 0x01   //!< Emit xml header
         };
 
-
         //- The output format type
-        unsigned short type_;
+        formatType fmtType_;
 
         //- ASCII write precision
         mutable unsigned precision_;
@@ -82,18 +77,25 @@ public:
     // Constructors
 
         //- Construct null - XML insitu ASCII format with default precision
-        foamVtkOutputOptions();
+        inline outputOptions();
+
+        //- Construct with specified format.
+        //  This constructor should remain non-explicit.
+        inline outputOptions(enum formatType fmtType);
 
 
     // Selectors
 
-        //- Return new data formatter based on the writer options
-        autoPtr<foamVtkFormatter> newFormatter(std::ostream& os) const;
+        //- Return new formatter based on the selected output options
+        inline autoPtr<formatter> newFormatter(std::ostream& os) const;
 
 
     // Member Functions
 
-    // Access
+      // Access
+
+        //- The output format type
+        inline formatType fmt() const;
 
         //- True if writer uses legacy file format
         inline bool legacy() const;
@@ -110,35 +112,43 @@ public:
         //- True if output format is ASCII
         inline bool ascii() const;
 
+        //- Return the ASCII write precision
+        inline unsigned precision() const;
+
 
-    // Edit
+      // Edit
 
         //- Toggle ASCII mode on/off.
-        //  In append mode, this switches between base64 and raw binary.
-        //  In XML mode, this switches between ASCII and base64.
+        //  In XML append mode, this switches between base64 and raw binary.
+        //  In XML inline mode, this switches between ASCII and base64.
         //  In legacy mode, this switches between ASCII and binary.
-        void ascii(bool on);
+        //  \return outputOptions for chaining
+        outputOptions& ascii(bool on);
 
         //- Toggle append mode on/off.
-        void append(bool on);
+        //  \return outputOptions for chaining
+        outputOptions& append(bool on);
 
         //- Toggle legacy mode on/off.
-        void legacy(bool on);
+        //  \return outputOptions for chaining
+        outputOptions& legacy(bool on);
 
         //- Set the write precision to be used for new ASCII formatters
-        void precision(unsigned prec) const;
+        //  \return outputOptions for chaining
+        outputOptions& precision(unsigned prec);
 
 
     // Other
 
-        //- Report information about the options
-        Ostream& info(Ostream&) const;
+        //- A text description about the output option selected
+        string description() const;
 
 };
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace vtk
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/fileFormats/vtk/output/foamVtkOutputOptionsI.H b/src/fileFormats/vtk/output/foamVtkOutputOptionsI.H
new file mode 100644
index 0000000000000000000000000000000000000000..c8802c3da8b5744fac2e80190ad9185b6656ce57
--- /dev/null
+++ b/src/fileFormats/vtk/output/foamVtkOutputOptionsI.H
@@ -0,0 +1,110 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016-2017 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 "foamVtkOutput.H"
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+inline Foam::vtk::outputOptions::outputOptions()
+:
+    fmtType_(formatType::INLINE_ASCII),
+    precision_(IOstream::defaultPrecision())
+{}
+
+
+inline Foam::vtk::outputOptions::outputOptions
+(
+    enum formatType fmtType
+)
+:
+    fmtType_(fmtType),
+    precision_(IOstream::defaultPrecision())
+{}
+
+
+// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
+
+inline Foam::autoPtr<Foam::vtk::formatter>
+Foam::vtk::outputOptions::newFormatter(std::ostream& os) const
+{
+    return vtk::newFormatter(os, fmtType_, precision_);
+}
+
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+inline Foam::vtk::formatType
+Foam::vtk::outputOptions::fmt() const
+{
+    return fmtType_;
+}
+
+
+inline bool Foam::vtk::outputOptions::legacy() const
+{
+    return
+    (
+        fmtType_ == formatType::LEGACY_ASCII
+     || fmtType_ == formatType::LEGACY_BINARY
+    );
+}
+
+
+inline bool Foam::vtk::outputOptions::xml() const
+{
+    return !legacy();
+}
+
+
+inline bool Foam::vtk::outputOptions::append() const
+{
+    return
+    (
+        fmtType_ == formatType::APPEND_BASE64
+     || fmtType_ == formatType::APPEND_BINARY
+    );
+}
+
+
+inline bool Foam::vtk::outputOptions::insitu() const
+{
+    return !append();
+}
+
+
+inline bool Foam::vtk::outputOptions::ascii() const
+{
+    return !(unsigned(fmtType_) & 0x0F);
+}
+
+
+inline unsigned Foam::vtk::outputOptions::precision() const
+{
+    return precision_;
+}
+
+
+// ************************************************************************* //
diff --git a/src/conversion/vtk/output/foamVtkOutputTemplates.C b/src/fileFormats/vtk/output/foamVtkOutputTemplates.C
similarity index 68%
rename from src/conversion/vtk/output/foamVtkOutputTemplates.C
rename to src/fileFormats/vtk/output/foamVtkOutputTemplates.C
index 03c2d56bd9d941d97e427b049914698fd179147a..f28d458378e1fc64d6f7beddd1388f61b0a4b64b 100644
--- a/src/conversion/vtk/output/foamVtkOutputTemplates.C
+++ b/src/fileFormats/vtk/output/foamVtkOutputTemplates.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2016-2107 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -25,15 +25,15 @@ License
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-
 template<class Type>
-inline void Foam::foamVtkOutput::write
+inline void Foam::vtk::write
 (
-    foamVtkFormatter& fmt,
+    vtk::formatter& fmt,
     const Type& val
 )
 {
-    for (direction cmpt=0; cmpt < pTraits<Type>::nComponents; ++cmpt)
+    const direction nCmpt = pTraits<Type>::nComponents;
+    for (direction cmpt=0; cmpt < nCmpt; ++cmpt)
     {
         fmt.write(component(val, cmpt));
     }
@@ -41,9 +41,9 @@ inline void Foam::foamVtkOutput::write
 
 
 template<class Type>
-void Foam::foamVtkOutput::writeList
+void Foam::vtk::writeList
 (
-    foamVtkFormatter& fmt,
+    vtk::formatter& fmt,
     const UList<Type>& lst
 )
 {
@@ -54,40 +54,32 @@ void Foam::foamVtkOutput::writeList
 }
 
 
-template<class Type>
-void Foam::foamVtkOutput::writeList
+template<class Type, unsigned Size>
+void Foam::vtk::writeList
 (
-    foamVtkFormatter& fmt,
-    const UList<Type>& lst,
-    const UList<label>& addressing
+    vtk::formatter& fmt,
+    const FixedList<Type, Size>& lst
 )
 {
-    forAll(addressing, i)
+    for (unsigned i=0; i<Size; ++i)
     {
-        write(fmt, lst[addressing[i]]);
+        write(fmt, lst[i]);
     }
 }
 
 
 template<class Type>
-void Foam::foamVtkOutput::writeField
+void Foam::vtk::writeList
 (
-    foamVtkFormatter& fmt,
-    const GeometricField<Type, fvPatchField, volMesh>& vf,
-    const UList<label>& superCells
+    vtk::formatter& fmt,
+    const UList<Type>& lst,
+    const UList<label>& addressing
 )
 {
-    const uint64_t payLoad =
-    (
-        (vf.size() + superCells.size())
-      * pTraits<Type>::nComponents * sizeof(float)
-    );
-
-    fmt.writeSize(payLoad);
-    writeList(fmt, vf.internalField());
-    writeList(fmt, vf, superCells);
-
-    fmt.flush();
+    forAll(addressing, i)
+    {
+        write(fmt, lst[addressing[i]]);
+    }
 }
 
 
diff --git a/src/fileFormats/vtk/read/vtkUnstructuredReader.C b/src/fileFormats/vtk/read/vtkUnstructuredReader.C
index 153c16578263edc40d1cbd951d702a73fd26202e..f29d57995ce3fc4909e69bc203995d75791591fb 100644
--- a/src/fileFormats/vtk/read/vtkUnstructuredReader.C
+++ b/src/fileFormats/vtk/read/vtkUnstructuredReader.C
@@ -125,7 +125,7 @@ void Foam::vtkUnstructuredReader::extractCells
     {
         switch (cellTypes[i])
         {
-            case foamVtkCore::VTK_VERTEX:
+            case vtk::cellType::VTK_VERTEX:
             {
                 warnUnhandledType(inFile, cellTypes[i], warningGiven);
                 label nRead = cellVertData[dataIndex++];
@@ -141,7 +141,7 @@ void Foam::vtkUnstructuredReader::extractCells
             }
             break;
 
-            case foamVtkCore::VTK_POLY_VERTEX:
+            case vtk::cellType::VTK_POLY_VERTEX:
             {
                 warnUnhandledType(inFile, cellTypes[i], warningGiven);
                 label nRead = cellVertData[dataIndex++];
@@ -149,7 +149,7 @@ void Foam::vtkUnstructuredReader::extractCells
             }
             break;
 
-            case foamVtkCore::VTK_LINE:
+            case vtk::cellType::VTK_LINE:
             {
                 //warnUnhandledType(inFile, cellTypes[i], warningGiven);
                 label nRead = cellVertData[dataIndex++];
@@ -169,7 +169,7 @@ void Foam::vtkUnstructuredReader::extractCells
             }
             break;
 
-            case foamVtkCore::VTK_POLY_LINE:
+            case vtk::cellType::VTK_POLY_LINE:
             {
                 //warnUnhandledType(inFile, cellTypes[i], warningGiven);
                 label nRead = cellVertData[dataIndex++];
@@ -183,7 +183,7 @@ void Foam::vtkUnstructuredReader::extractCells
             }
             break;
 
-            case foamVtkCore::VTK_TRIANGLE:
+            case vtk::cellType::VTK_TRIANGLE:
             {
                 faceMap_[facei] = i;
                 face& f = faces_[facei++];
@@ -203,7 +203,7 @@ void Foam::vtkUnstructuredReader::extractCells
             }
             break;
 
-            case foamVtkCore::VTK_QUAD:
+            case vtk::cellType::VTK_QUAD:
             {
                 faceMap_[facei] = i;
                 face& f = faces_[facei++];
@@ -224,7 +224,7 @@ void Foam::vtkUnstructuredReader::extractCells
             }
             break;
 
-            case foamVtkCore::VTK_POLYGON:
+            case vtk::cellType::VTK_POLYGON:
             {
                 faceMap_[facei] = i;
                 face& f = faces_[facei++];
@@ -237,7 +237,7 @@ void Foam::vtkUnstructuredReader::extractCells
             }
             break;
 
-            case foamVtkCore::VTK_TETRA:
+            case vtk::cellType::VTK_TETRA:
             {
                 label nRead = cellVertData[dataIndex++];
                 if (nRead != 4)
@@ -257,7 +257,7 @@ void Foam::vtkUnstructuredReader::extractCells
             }
             break;
 
-            case foamVtkCore::VTK_PYRAMID:
+            case vtk::cellType::VTK_PYRAMID:
             {
                 label nRead = cellVertData[dataIndex++];
                 if (nRead != 5)
@@ -278,7 +278,7 @@ void Foam::vtkUnstructuredReader::extractCells
             }
             break;
 
-            case foamVtkCore::VTK_WEDGE:
+            case vtk::cellType::VTK_WEDGE:
             {
                 label nRead = cellVertData[dataIndex++];
                 if (nRead != 6)
@@ -300,7 +300,7 @@ void Foam::vtkUnstructuredReader::extractCells
             }
             break;
 
-            case foamVtkCore::VTK_HEXAHEDRON:
+            case vtk::cellType::VTK_HEXAHEDRON:
             {
                 label nRead = cellVertData[dataIndex++];
                 if (nRead != 8)
diff --git a/src/fileFormats/vtk/read/vtkUnstructuredReader.H b/src/fileFormats/vtk/read/vtkUnstructuredReader.H
index 48dc38890a843b60b6dd1bf2d3823afeb032999c..bee79496c65377dc40c5f219d2d3db62b29da5de 100644
--- a/src/fileFormats/vtk/read/vtkUnstructuredReader.H
+++ b/src/fileFormats/vtk/read/vtkUnstructuredReader.H
@@ -63,8 +63,6 @@ namespace Foam
 \*---------------------------------------------------------------------------*/
 
 class vtkUnstructuredReader
-:
-    public fileFormats::foamVtkCore
 {
 public:
 
@@ -206,7 +204,7 @@ private:
 
         void read(ISstream& inFile);
 
-        //- Dissallow assignment
+        //- Disallow assignment
         void operator=(const vtkUnstructuredReader&);
 
 
@@ -220,6 +218,7 @@ public:
         //- Construct from Istream, read all
         vtkUnstructuredReader(const objectRegistry& obr, ISstream&);
 
+
     // Member Functions
 
         //- Header
diff --git a/src/functionObjects/utilities/Make/files b/src/functionObjects/utilities/Make/files
index e2f72c06cfe35edc354c239f6006bd35fb00082c..5cd7055b4693edf0427e31d1e210770218dc3728 100644
--- a/src/functionObjects/utilities/Make/files
+++ b/src/functionObjects/utilities/Make/files
@@ -2,6 +2,7 @@ abort/abort.C
 
 codedFunctionObject/codedFunctionObject.C
 ensightWrite/ensightWrite.C
+vtkWrite/vtkWrite.C
 
 removeRegisteredObject/removeRegisteredObject.C
 
diff --git a/src/functionObjects/utilities/ensightWrite/ensightWrite.H b/src/functionObjects/utilities/ensightWrite/ensightWrite.H
index 79c4110800b0f102a7157385fa89f2a7cc5c3ec7..ce9592f99c4112e565a4071aee8a212c9d5c738e 100644
--- a/src/functionObjects/utilities/ensightWrite/ensightWrite.H
+++ b/src/functionObjects/utilities/ensightWrite/ensightWrite.H
@@ -76,7 +76,6 @@ SourceFiles
     ensightWrite.C
     ensightWriteTemplates.C
 
-
 \*---------------------------------------------------------------------------*/
 
 #ifndef functionObjects_ensightWrite_H
diff --git a/src/functionObjects/utilities/vtkWrite/vtkWrite.C b/src/functionObjects/utilities/vtkWrite/vtkWrite.C
new file mode 100644
index 0000000000000000000000000000000000000000..af55e3f82ea9a1b704d153a6ad4c56715ea59abf
--- /dev/null
+++ b/src/functionObjects/utilities/vtkWrite/vtkWrite.C
@@ -0,0 +1,221 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "vtkWrite.H"
+#include "dictionary.H"
+#include "Time.H"
+#include "foamVtkInternalWriter.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace functionObjects
+{
+    defineTypeNameAndDebug(vtkWrite, 0);
+    addToRunTimeSelectionTable(functionObject, vtkWrite, dictionary);
+}
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::functionObjects::vtkWrite::vtkWrite
+(
+    const word& name,
+    const Time& runTime,
+    const dictionary& dict
+)
+:
+    fvMeshFunctionObject(name, runTime, dict),
+    writeOpts_(vtk::formatType::INLINE_BASE64),
+    selectFields_(),
+    dirName_("VTK")
+{
+    read(dict);
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::functionObjects::vtkWrite::~vtkWrite()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::functionObjects::vtkWrite::read(const dictionary& dict)
+{
+    fvMeshFunctionObject::read(dict);
+
+    //
+    // writer options - default is xml base64
+    //
+    writeOpts_ = vtk::formatType::INLINE_BASE64;
+    if (dict.lookupOrDefault<bool>("legacy", false))
+    {
+        writeOpts_.legacy(true);
+    }
+
+    writeOpts_.ascii
+    (
+        dict.found("format")
+     && (IOstream::formatEnum(dict.lookup("format")) == IOstream::ASCII)
+    );
+
+    // FUTURE?
+    // writeOpts_.precision
+    // (
+    //     dict.lookupOrDefault
+    //     (
+    //         "writePrecision",
+    //         IOstream::defaultPrecision()
+    //     )
+    // );
+
+    // Info<< type() << " " << name() << " output-format: "
+    //     << writeOpts_.description() << nl;
+
+    //
+    // other options
+    //
+    dict.readIfPresent("directory", dirName_);
+
+    writeIds_ = dict.lookupOrDefault<bool>("writeIds", false);
+
+
+    //
+    // output fields
+    //
+    dict.lookup("fields") >> selectFields_;
+    wordRes::inplaceUniq(selectFields_);
+
+    return true;
+}
+
+
+bool Foam::functionObjects::vtkWrite::execute()
+{
+    return true;
+}
+
+
+bool Foam::functionObjects::vtkWrite::write()
+{
+    // Count number of fields to be written: only needed for legacy vtk format
+    label nFields = 0;
+    if (writeOpts_.legacy())
+    {
+        nFields =
+        (
+            (writeIds_ ? 1 : 0)
+          + countFields<volScalarField>()
+          + countFields<volVectorField>()
+          + countFields<volSphericalTensorField>()
+          + countFields<volSymmTensorField>()
+          + countFields<volTensorField>()
+        );
+    }
+
+    // const word timeDesc =
+    //     useTimeName ? time_.timeName() : Foam::name(time_.timeIndex());
+
+    const word timeDesc = time_.timeName();
+
+    fileName vtkDir = dirName_;
+    if (!vtkDir.isAbsolute())
+    {
+        vtkDir = time_.path()/vtkDir;
+    }
+    mkDir(vtkDir);
+
+    string vtkName = time_.caseName();
+
+    if (Pstream::parRun())
+    {
+        // Strip off leading casename, leaving just processor_DDD ending.
+        string::size_type i = vtkName.rfind("processor");
+
+        if (i != string::npos)
+        {
+            vtkName = vtkName.substr(i);
+        }
+    }
+
+    // Create file and write header
+    const fileName outputName
+    (
+        vtkDir/vtkName
+      + "_"
+      + timeDesc
+    );
+
+    Info<< name() << " output Time: " << time_.timeName() << nl
+        << "    Internal  : " << outputName << endl;
+
+    vtk::vtuCells vtuMeshCells
+    (
+        mesh_,
+        writeOpts_,
+        true  // decompose
+    );
+
+    // Write mesh
+    vtk::internalWriter writer
+    (
+        mesh_,
+        vtuMeshCells,
+        outputName,
+        writeOpts_
+    );
+
+    // CellData
+    {
+        writer.beginCellData(nFields);
+
+        // Write cellID field
+        if (writeIds_)
+        {
+            writer.writeCellIDs();
+        }
+
+        // Write volFields
+        writeFields<volScalarField>(writer);
+        writeFields<volVectorField>(writer);
+        writeFields<volSphericalTensorField>(writer);
+        writeFields<volSymmTensorField>(writer);
+        writeFields<volTensorField>(writer);
+
+        writer.endCellData();
+    }
+
+    writer.writeFooter();
+
+    return true;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeVTK/writeVTK.H b/src/functionObjects/utilities/vtkWrite/vtkWrite.H
similarity index 58%
rename from applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeVTK/writeVTK.H
rename to src/functionObjects/utilities/vtkWrite/vtkWrite.H
index c15dd17f48580e76ef40512a6a613ac52d893fe2..025e92bdab21e505d14c7abad6924b92d271a468 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeVTK/writeVTK.H
+++ b/src/functionObjects/utilities/vtkWrite/vtkWrite.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -22,71 +22,61 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    Foam::functionObjects::writeVTK
+    Foam::functionObjects::vtkWrite
 
 Group
     grpUtilitiesFunctionObjects
 
 Description
-    This functionObject writes objects registered to the database in VTK format
-    using the foamToVTK library.
+    This functionObject writes objects registered to the database in VTK format.
 
-    Currently only the writing of the cell-values of volFields is supported but
+    Currently only supports writing of the cell-values of volFields but
     support for other field types, patch fields, Lagrangian data etc. will be
     added.
 
     Example of function object specification:
     \verbatim
-        writeVTK1
-        {
-            type        writeVTK;
-            libs ("libutilityFunctionObjects.so");
-            ...
-            objectNames (obj1 obj2);
-        }
+    vtkWrite1
+    {
+        type            vtkWrite;
+        libs            ("libutilityFunctionObjects.so");
+        writeControl    writeTime;
+        writeInterval   1;
+        format          binary;
+        legacy          false;
+        ...
+        fields          (U p);
+    }
     \endverbatim
 
 Usage
     \table
         Property     | Description             | Required    | Default value
-        type         | type name: writeVTK     | yes         |
-        objectNames  | objects to write        | yes         |
+        type         | Type name: vtkWrite     | yes         |
+        fields       | Fields to output        | yes         |
+        writeControl | Output control          | recommended | timeStep
+        directory    | The output directory name | no        | "VTK"
+        format       | ASCII or binary format  | no          | binary
+        legacy       | Legacy VTK output       | no          | false
+        writeIds     | Write cell ids as field | no          | true
     \endtable
 
 See also
     Foam::functionObjects::fvMeshFunctionObject
     Foam::functionObjects::timeControl
 
-    Example of function object specification to calculate Lambda2:
-    \verbatim
-    Lambda2_1
-    {
-        type        Lambda2;
-        functionObjectLibs ("libutilityFunctionObjects.so");
-        ...
-    }
-    \endverbatim
-
-    \heading Function object usage
-    \table
-        Property     | Description             | Required    | Default value
-        type         | Type name: Lambda2      | yes         |
-        UName        | Name of velocity field  | no          | U
-        resultName   | Name of Lambda2 field   | no          | <function name>
-        log          | Log to standard output  | no          | yes
-    \endtable
-
 SourceFiles
-    writeVTK.C
-    IOwriteVTK.H
+    vtkWrite.C
+    vtkWriteTemplates.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef functionObjects_writeVTK_H
-#define functionObjects_writeVTK_H
+#ifndef functionObjects_vtkWrite_H
+#define functionObjects_vtkWrite_H
 
 #include "fvMeshFunctionObject.H"
-#include "wordReList.H"
+#include "foamVtkInternalWriter.H"
+#include "wordRes.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -96,67 +86,77 @@ namespace functionObjects
 {
 
 /*---------------------------------------------------------------------------*\
-                   Class writeVTK Declaration
+                          Class vtkWrite Declaration
 \*---------------------------------------------------------------------------*/
 
-class writeVTK
+class vtkWrite
 :
     public fvMeshFunctionObject
 {
     // Private data
 
-        //- Names of objects
-        wordReList objectNames_;
+        //- VTK output options
+        vtk::outputOptions writeOpts_;
 
+        //- Name of fields to process
+        wordReList selectFields_;
 
-        //- Result name
-        word resultName_;
+        //- Output directory name
+        fileName dirName_;
+
+        //- Write cell ids field
+        bool writeIds_;
 
-        //- Switch to send output to Info as well as to file
-        Switch log_;
 
     // Private Member Functions
 
+        //- Count number of selected fields for GeoField type.
+        //  Only needed for legacy vtk format.
+        template<class GeoField>
+        label countFields() const;
+
+        //- Write selected fields for GeoField type.
         template<class GeoField>
-        UPtrList<const GeoField> lookupFields() const;
+        label writeFields(vtk::internalWriter& writer, bool verbose=true) const;
+
 
         //- Disallow default bitwise copy construct
-        writeVTK(const writeVTK&);
+        vtkWrite(const vtkWrite&) = delete;
 
         //- Disallow default bitwise assignment
-        void operator=(const writeVTK&);
+        void operator=(const vtkWrite&) = delete;
 
 
 public:
 
     //- Runtime type information
-    TypeName("writeVTK");
+    TypeName("vtkWrite");
 
 
     // Constructors
 
         //- Construct from Time and dictionary
-        writeVTK
+        vtkWrite
         (
             const word& name,
             const Time& t,
-            const dictionary&
+            const dictionary& dict
         );
 
 
     //- Destructor
-    virtual ~writeVTK();
+    virtual ~vtkWrite();
 
 
     // Member Functions
 
-        //- Read the writeVTK data
-        virtual bool read(const dictionary&);
+        //- Read the vtkWrite specification
+        virtual bool read(const dictionary& dict);
 
         //- Execute, currently does nothing
         virtual bool execute();
 
-        //- Write the writeVTK
+        //- Write fields
         virtual bool write();
 };
 
@@ -169,7 +169,7 @@ public:
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 #ifdef NoRepository
-    #include "writeVTKTemplates.C"
+    #include "vtkWriteTemplates.C"
 #endif
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeVTK/writeVTKTemplates.C b/src/functionObjects/utilities/vtkWrite/vtkWriteTemplates.C
similarity index 63%
rename from applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeVTK/writeVTKTemplates.C
rename to src/functionObjects/utilities/vtkWrite/vtkWriteTemplates.C
index e46f0333d4d02905fa08d4f11f0986c5d80bae78..1cdce49cd15a595d955244999a91238375282338 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeVTK/writeVTKTemplates.C
+++ b/src/functionObjects/utilities/vtkWrite/vtkWriteTemplates.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016 OpenFOAM Foundation
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -23,38 +23,38 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "writeVTK.H"
-#include "objectRegistry.H"
-#include "DynamicList.H"
-
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 template<class GeoField>
-Foam::UPtrList<const GeoField>
-Foam::functionObjects::writeVTK::lookupFields() const
+Foam::label
+Foam::functionObjects::vtkWrite::countFields() const
 {
-    DynamicList<word> allNames(obr_.toc().size());
-    forAll(objectNames_, i)
-    {
-        wordList names(obr_.names<GeoField>(objectNames_[i]));
+    return obr_.names<GeoField>(selectFields_).size();
+}
 
-        if (names.size())
-        {
-            allNames.append(names);
-        }
-    }
 
-    UPtrList<const GeoField> fields(allNames.size());
+template<class GeoField>
+Foam::label
+Foam::functionObjects::vtkWrite::writeFields
+(
+    vtk::internalWriter& writer,
+    bool verbose
+) const
+{
+    const wordList names = obr_.sortedNames<GeoField>(selectFields_);
+
+    if (verbose && names.size())
+    {
+        Info<< "    " << GeoField::typeName
+            << " " << flatOutput(names) << endl;
+    }
 
-    forAll(allNames, i)
+    for (const word& fieldName : names)
     {
-        const GeoField& field = obr_.lookupObject<GeoField>(allNames[i]);
-        Info<< "    Writing " << GeoField::typeName
-            << " field " << field.name() << endl;
-        fields.set(i, &field);
+        writer.write(obr_.lookupObject<GeoField>(fieldName));
     }
 
-    return fields;
+    return names.size();
 }
 
 
diff --git a/src/meshTools/Make/files b/src/meshTools/Make/files
index f9af11d9bef117e32cc43b44f7da06f863f18e40..1beec64e855e55a88d463127b5a86295d3601551 100644
--- a/src/meshTools/Make/files
+++ b/src/meshTools/Make/files
@@ -266,6 +266,10 @@ meshStructure/meshStructure.C
 meshStructure/topoDistanceData.C
 meshStructure/pointTopoDistanceData.C
 
+output/foamVtkWriteFaceSet.C
+output/foamVtkWritePointSet.C
+output/foamVtkWriteCellSetFaces.C
+
 regionCoupled/patches/regionCoupledPolyPatch/regionCoupledBase.C
 regionCoupled/patches/regionCoupledPolyPatch/regionCoupledPolyPatch.C
 regionCoupled/patches/regionCoupledPolyPatch/regionCoupledWallPolyPatch.C
diff --git a/src/meshTools/output/foamVtkWriteCellSetFaces.C b/src/meshTools/output/foamVtkWriteCellSetFaces.C
new file mode 100644
index 0000000000000000000000000000000000000000..a84b5d5b7068d508da4c3433364cbef5b60fb9d9
--- /dev/null
+++ b/src/meshTools/output/foamVtkWriteCellSetFaces.C
@@ -0,0 +1,147 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "foamVtkWriteCellSetFaces.H"
+#include "foamVtkOutputOptions.H"
+#include "OFstream.H"
+#include "primitiveMesh.H"
+#include "cellSet.H"
+#include "uindirectPrimitivePatch.H"
+
+// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
+
+void Foam::vtk::writeCellSetFaces
+(
+    const primitiveMesh& mesh,
+    const cellSet& set,
+    const fileName& baseName,
+    const vtk::outputOptions outOpts
+)
+{
+    outputOptions opts(outOpts);
+    opts.legacy(true);  // Legacy only, no append
+
+    const bool legacy_(opts.legacy());
+
+    std::ofstream os((baseName + (legacy_ ? ".vtk" : ".vtp")).c_str());
+
+    autoPtr<vtk::formatter> format = opts.newFormatter(os);
+
+    if (legacy_)
+    {
+        legacy::fileHeader(format(), set.name(), vtk::fileTag::POLY_DATA);
+    }
+
+    //-------------------------------------------------------------------------
+
+    // External faces of cellset with OpenFOAM cellID as value
+
+    Map<label> cellFaces(2*set.size());
+
+    forAllConstIters(set, iter)
+    {
+        label celli = iter.key();
+        const cell& cFaces = mesh.cells()[celli];
+
+        forAll(cFaces, i)
+        {
+            label facei = cFaces[i];
+
+            if (mesh.isInternalFace(facei))
+            {
+                label otherCelli = mesh.faceOwner()[facei];
+
+                if (otherCelli == celli)
+                {
+                    otherCelli = mesh.faceNeighbour()[facei];
+                }
+
+                if (!set.found(otherCelli))
+                {
+                    cellFaces.insert(facei, celli);
+                }
+            }
+            else
+            {
+                cellFaces.insert(facei, celli);
+            }
+        }
+    }
+
+    const labelList faceLabels = cellFaces.sortedToc();
+    labelList faceValues(cellFaces.size());
+
+    forAll(faceLabels, facei)
+    {
+        faceValues[facei] = cellFaces[faceLabels[facei]];  // Cell ID
+    }
+
+    uindirectPrimitivePatch pp
+    (
+        UIndirectList<face>(mesh.faces(), faceLabels),
+        mesh.points()
+    );
+
+    //-------------------------------------------------------------------------
+
+    // Write points and faces as polygons
+    legacy::beginPoints(os, pp.nPoints());
+
+    vtk::writeList(format(), pp.localPoints());
+    format().flush();
+
+    // connectivity count without additional storage (done internally)
+    uint64_t nConnectivity = 0;
+    forAll(pp, facei)
+    {
+        nConnectivity += pp[facei].size();
+    }
+
+    legacy::beginPolys(os, pp.size(), nConnectivity);
+
+
+    // legacy: size + connectivity together
+    // [nPts, id1, id2, ..., nPts, id1, id2, ...]
+    forAll(pp, facei)
+    {
+        const face& f = pp.localFaces()[facei];
+
+        format().write(f.size());  // The size prefix
+        vtk::writeList(format(), f);
+    }
+    format().flush();
+
+
+    // Write data - faceId/cellId
+    legacy::dataHeader(os, vtk::fileTag::CELL_DATA, pp.size(), 1);
+
+    os << "cellID 1 " << pp.size() << " int" << nl;
+
+    vtk::writeList(format(), faceValues);
+    format().flush();
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFaceSet.H b/src/meshTools/output/foamVtkWriteCellSetFaces.H
similarity index 65%
rename from applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFaceSet.H
rename to src/meshTools/output/foamVtkWriteCellSetFaces.H
index 73ca4f07416e6fc9fdfff79350a6ddefdd876160..765ff60807fd28dd7c127940d5b2ed2699076913 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/writeFaceSet.H
+++ b/src/meshTools/output/foamVtkWriteCellSetFaces.H
@@ -2,8 +2,8 @@
   =========                 |
   \\      /  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.
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
+     \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -21,38 +21,48 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
-InClass
-    Foam::writeFaceSet
+InNamespace
+    Foam::vtk
 
 Description
-    Write faceSet to vtk polydata file. Only one data which is original
-    faceID.
+    Write faces of cellSet to vtk polydata file.
+
+    The data are the original cell ids
 
 SourceFiles
-    writeFaceSet.C
+    foamVtkWriteCellSetFaces.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef writeFaceSet_H
-#define writeFaceSet_H
+#ifndef foamVtkWriteCellSetFaces_H
+#define foamVtkWriteCellSetFaces_H
 
-#include "fvMesh.H"
-#include "faceSet.H"
+#include "primitiveMesh.H"
+#include "uindirectPrimitivePatch.H"
+#include "foamVtkOutputOptions.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
+class primitiveMesh;
+class cellSet;
+class fileName;
+
+namespace vtk
+{
 
-// Write lagrangian fields.
-void writeFaceSet
+//- Write perimeter faces of cellset to vtk polydata file.
+//  The data are the original cell ids
+void writeCellSetFaces
 (
-    const bool binary,
-    const fvMesh&,
-    const faceSet& set,
-    const fileName& fileName
+    const primitiveMesh& mesh,
+    const cellSet& set,
+    const fileName& baseName,
+    const vtk::outputOptions outOpts
 );
 
+} // End namespace vtk
 } // End namespace Foam
 
 
diff --git a/src/meshTools/output/foamVtkWriteFaceSet.C b/src/meshTools/output/foamVtkWriteFaceSet.C
new file mode 100644
index 0000000000000000000000000000000000000000..59c11329d4122d220a8915ed2cc825e63474a946
--- /dev/null
+++ b/src/meshTools/output/foamVtkWriteFaceSet.C
@@ -0,0 +1,108 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "foamVtkWriteFaceSet.H"
+#include "foamVtkOutputOptions.H"
+#include "OFstream.H"
+#include "primitiveMesh.H"
+#include "faceSet.H"
+#include "uindirectPrimitivePatch.H"
+
+// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
+
+void Foam::vtk::writeFaceSet
+(
+    const primitiveMesh& mesh,
+    const faceSet& set,
+    const fileName& baseName,
+    const vtk::outputOptions outOpts
+)
+{
+    outputOptions opts(outOpts);
+    opts.legacy(true);  // Legacy only, no append
+
+    const bool legacy_(opts.legacy());
+
+    std::ofstream os((baseName + (legacy_ ? ".vtk" : ".vtp")).c_str());
+
+    autoPtr<vtk::formatter> format = opts.newFormatter(os);
+
+    if (legacy_)
+    {
+        legacy::fileHeader(format(), set.name(), vtk::fileTag::POLY_DATA);
+    }
+
+    //-------------------------------------------------------------------------
+
+    // Faces of set with OpenFOAM faceID as value
+    const labelList faceLabels = set.sortedToc();
+
+    uindirectPrimitivePatch pp
+    (
+        UIndirectList<face>(mesh.faces(), faceLabels),
+        mesh.points()
+    );
+
+    //-------------------------------------------------------------------------
+
+    // Write points and faces as polygons
+    legacy::beginPoints(os, pp.nPoints());
+
+    vtk::writeList(format(), pp.localPoints());
+    format().flush();
+
+    // connectivity count without additional storage (done internally)
+    uint64_t nConnectivity = 0;
+    forAll(pp, facei)
+    {
+        nConnectivity += pp[facei].size();
+    }
+    legacy::beginPolys(os, pp.size(), nConnectivity);
+
+
+    // legacy: size + connectivity together
+    // [nPts, id1, id2, ..., nPts, id1, id2, ...]
+    forAll(pp, facei)
+    {
+        const face& f = pp.localFaces()[facei];
+
+        format().write(f.size());  // The size prefix
+        vtk::writeList(format(), f);
+    }
+    format().flush();
+
+
+    // Write data - faceId/cellId
+
+    legacy::dataHeader(os, vtk::fileTag::CELL_DATA, pp.size(), 1);
+
+    os << "faceID 1 " << pp.size() << " int" << nl;
+
+    vtk::writeList(format(), faceLabels);
+    format().flush();
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/mesh/manipulation/setSet/writePointSet.H b/src/meshTools/output/foamVtkWriteFaceSet.H
similarity index 76%
rename from applications/utilities/mesh/manipulation/setSet/writePointSet.H
rename to src/meshTools/output/foamVtkWriteFaceSet.H
index 983eb32aed029fff7f491aca2a7aa6348c4d848d..24ba0c3932b58e093d629d1daa46ba2433ec6584 100644
--- a/applications/utilities/mesh/manipulation/setSet/writePointSet.H
+++ b/src/meshTools/output/foamVtkWriteFaceSet.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -22,38 +22,45 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 InNamespace
-    Foam
+    Foam::vtk
 
 Description
-    Write pointSet to vtk polydata file. Only one data which is original
-    pointID.
+    Write faceSet to vtk polydata file.
+    The data are the original point ids.
 
 SourceFiles
-    writePointSet.C
+    foamVtkWritePointSet.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef writePointSet_H
-#define writePointSet_H
+#ifndef foamVtkWriteFaceSet_H
+#define foamVtkWriteFaceSet_H
 
-#include "primitiveMesh.H"
-#include "pointSet.H"
+#include "foamVtkOutputOptions.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
+class primitiveMesh;
+class faceSet;
+class fileName;
+
+namespace vtk
+{
 
 //- Write pointSet to vtk polydata file.
 //  Only one data which is original pointID.
-void writePointSet
+void writeFaceSet
 (
-    const bool binary,
     const primitiveMesh& mesh,
-    const topoSet& set,
-    const fileName& fileName
+    const faceSet& set,
+    const fileName& baseName,
+    const vtk::outputOptions outOpts
 );
 
+
+} // End namespace vtk
 } // End namespace Foam
 
 
diff --git a/src/meshTools/output/foamVtkWritePointSet.C b/src/meshTools/output/foamVtkWritePointSet.C
new file mode 100644
index 0000000000000000000000000000000000000000..66cbfc8c4439d2902ce9131f1afce68a23878a99
--- /dev/null
+++ b/src/meshTools/output/foamVtkWritePointSet.C
@@ -0,0 +1,76 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "foamVtkWritePointSet.H"
+#include "foamVtkOutputOptions.H"
+#include "OFstream.H"
+#include "primitiveMesh.H"
+#include "pointSet.H"
+
+// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
+
+void Foam::vtk::writePointSet
+(
+    const primitiveMesh& mesh,
+    const pointSet& set,
+    const fileName& baseName,
+    const vtk::outputOptions outOpts
+)
+{
+    outputOptions opts(outOpts);
+    opts.legacy(true);  // Legacy only, no append
+
+    const bool legacy_(opts.legacy());
+
+    std::ofstream os((baseName + (legacy_ ? ".vtk" : ".vtp")).c_str());
+
+    autoPtr<vtk::formatter> format = opts.newFormatter(os);
+
+    if (legacy_)
+    {
+        legacy::fileHeader(format(), set.name(), vtk::fileTag::POLY_DATA);
+    }
+
+    //-------------------------------------------------------------------------
+
+    const labelList pointLabels(set.sortedToc());
+
+    // Write points
+    legacy::beginPoints(os, pointLabels.size());
+
+    vtk::writeList(format(), mesh.points(), pointLabels);
+    format().flush();
+
+    // Write data - pointID
+    legacy::dataHeader(os, vtk::fileTag::POINT_DATA, pointLabels.size(), 1);
+
+    os << "pointID 1 " << pointLabels.size() << " int" << nl;
+
+    vtk::writeList(format(), pointLabels);
+    format().flush();
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/mesh/manipulation/setSet/writePatch.H b/src/meshTools/output/foamVtkWritePointSet.H
similarity index 70%
rename from applications/utilities/mesh/manipulation/setSet/writePatch.H
rename to src/meshTools/output/foamVtkWritePointSet.H
index ccc82e835deda81369945bebcaf7053d5c3f7c8b..830dfd304a1363dab4e7fe815f9ab6c606f5dae2 100644
--- a/applications/utilities/mesh/manipulation/setSet/writePatch.H
+++ b/src/meshTools/output/foamVtkWritePointSet.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -21,40 +21,46 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
-InClass
-    Foam::writePatch
+InNamespace
+    Foam::vtk
 
 Description
-    Write faceSet to vtk polydata file. Only one data which is original
-    faceID.
+    Write pointSet to vtk polydata file.
+    The data are the original point ids.
 
 SourceFiles
-    writePatch.C
+    foamVtkWritePointSet.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef writePatch_H
-#define writePatch_H
+#ifndef foamVtkWritePointSet_H
+#define foamVtkWritePointSet_H
 
-#include "primitiveMesh.H"
-#include "primitiveFacePatch.H"
+#include "foamVtkOutputOptions.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
+class primitiveMesh;
+class pointSet;
+class fileName;
 
-// Write faceSet
-void writePatch
+namespace vtk
+{
+
+//- Write pointSet to vtk polydata file.
+//  The data are the original point ids.
+void writePointSet
 (
-    const bool binary,
-    const word& setName,
-    const primitiveFacePatch& fp,
-    const word& fieldName,
-    labelList& fieldValues,
-    const fileName& fileName
+    const primitiveMesh& mesh,
+    const pointSet& set,
+    const fileName& baseName,
+    const vtk::outputOptions outOpts
 );
 
+
+} // End namespace vtk
 } // End namespace Foam
 
 
diff --git a/src/surfMesh/Make/files b/src/surfMesh/Make/files
index 10d6171c207a6a1f0ef8349bb1d6e12fe19ad359..2bf796be62828de399df11d6bdf636011bf6fca9 100644
--- a/src/surfMesh/Make/files
+++ b/src/surfMesh/Make/files
@@ -37,6 +37,8 @@ $(surfaceFormats)/tri/TRIsurfaceFormatCore.C
 $(surfaceFormats)/tri/TRIsurfaceFormatRunTime.C
 $(surfaceFormats)/vtk/VTKsurfaceFormatCore.C
 $(surfaceFormats)/vtk/VTKsurfaceFormatRunTime.C
+$(surfaceFormats)/vtp/VTPsurfaceFormatCore.C
+$(surfaceFormats)/vtp/VTPsurfaceFormatRunTime.C
 $(surfaceFormats)/x3d/X3DsurfaceFormatCore.C
 $(surfaceFormats)/x3d/X3DsurfaceFormatRunTime.C
 
diff --git a/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.C b/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.C
index b0a5d2711498e694299a1d41c2504fdd83eb5fd6..b7141105d6d5a0e974bd409778164c4b73cf9e22 100644
--- a/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.C
@@ -28,26 +28,54 @@ License
 #include "scalarIOField.H"
 #include "faceTraits.H"
 #include "OFstream.H"
+#include "foamVtkOutput.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+// File-scope constant.
+//
+// TODO: make this run-time selectable (ASCII | BINARY)
+// - Legacy mode only
+
+static const Foam::vtk::formatType fmtType =
+    Foam::vtk::formatType::LEGACY_ASCII;
+    // Foam::vtk::formatType::LEGACY_BINARY;
+
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 template<class Face>
-void Foam::fileFormats::VTKsurfaceFormat<Face>::writeHeaderPolygons
+void Foam::fileFormats::VTKsurfaceFormat<Face>::writePolys
 (
-    Ostream& os,
-    const UList<Face>& faceLst
+    vtk::formatter& format,
+    const UList<Face>& faces
 )
 {
-    label nNodes = 0;
+    // connectivity count without additional storage (done internally)
+    label nConnectivity = 0;
+    for (const auto& f : faces)
+    {
+        nConnectivity += f.size();
+    }
 
-    forAll(faceLst, facei)
+    vtk::legacy::beginPolys
+    (
+        format.os(),
+        faces.size(),
+        nConnectivity
+    );
+
+
+    // legacy: size + connectivity together
+    // [nPts, id1, id2, ..., nPts, id1, id2, ...]
+
+    for (const Face& f : faces)
     {
-        nNodes += faceLst[facei].size();
+        format.write(f.size());  // The size prefix
+        vtk::writeList(format, f);
     }
 
-    os  << nl
-        << "POLYGONS " << faceLst.size() << ' '
-        << faceLst.size() + nNodes << nl;
+    format.flush();
 }
 
 
@@ -115,31 +143,37 @@ bool Foam::fileFormats::VTKsurfaceFormat<Face>::read
 
     // Assume all faces in zone0 unless a region field is present
     labelList zones(faces.size(), 0);
-    if (reader.cellData().foundObject<scalarIOField>("region"))
+
+    for (auto fieldName : { "region", "STLSolidLabeling" })
     {
-        const scalarIOField& region =
-            reader.cellData().lookupObject<scalarIOField>
-            (
-                "region"
-            );
-        forAll(region, i)
+        const labelIOField* lptr =
+            reader.cellData().lookupObjectPtr<labelIOField>(fieldName);
+
+        if (lptr)
         {
-            zones[i] = label(region[i]);
+            label i = 0;
+            for (const auto& region : *lptr)
+            {
+                zones[i++] = label(region);
+            }
+            break;
         }
-    }
-    else if (reader.cellData().foundObject<scalarIOField>("STLSolidLabeling"))
-    {
-        const scalarIOField& region =
-            reader.cellData().lookupObject<scalarIOField>
-            (
-                "STLSolidLabeling"
-            );
-        forAll(region, i)
+
+        const scalarIOField* sptr =
+            reader.cellData().lookupObjectPtr<scalarIOField>(fieldName);
+
+        if (sptr)
         {
-            zones[i] = label(region[i]);
+            label i = 0;
+            for (const auto& region : *sptr)
+            {
+                zones[i++] = label(region);
+            }
+            break;
         }
     }
 
+
     // Create zone names
     const label nZones = max(zones)+1;
     wordList zoneNames(nZones);
@@ -240,54 +274,54 @@ void Foam::fileFormats::VTKsurfaceFormat<Face>::write
 
     const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
 
-    OFstream os(filename);
-    if (!os.good())
-    {
-        FatalErrorInFunction
-            << "Cannot open file for writing " << filename
-            << exit(FatalError);
-    }
+    std::ofstream os(filename.c_str());
 
+    autoPtr<vtk::formatter> format =
+        vtk::newFormatter(os, fmtType);
 
-    writeHeader(os, pointLst);
-    writeHeaderPolygons(os, faceLst);
+    writeHeader(format(), pointLst);
 
-    label faceIndex = 0;
-    forAll(zones, zoneI)
+    if (useFaceMap)
     {
-        const surfZone& zone = zones[zoneI];
+        // connectivity count without additional storage (done internally)
+        label nConnectivity = 0;
+        for (const auto& f : faceLst)
+        {
+            nConnectivity += f.size();
+        }
 
-        if (useFaceMap)
+        vtk::legacy::beginPolys
+        (
+            format().os(),
+            faceLst.size(),
+            nConnectivity
+        );
+
+        label faceIndex = 0;
+        for (const surfZone& zone : zones)
         {
-            forAll(zone, localFacei)
+            forAll(zone, i)
             {
                 const Face& f = faceLst[faceMap[faceIndex++]];
 
-                os << f.size();
-                forAll(f, fp)
-                {
-                    os << ' ' << f[fp];
-                }
-                os << ' ' << nl;
-            }
-        }
-        else
-        {
-            forAll(zone, localFacei)
-            {
-                const Face& f = faceLst[faceIndex++];
-
-                os << f.size();
-                forAll(f, fp)
-                {
-                    os << ' ' << f[fp];
-                }
-                os << ' ' << nl;
+                format().write(f.size());  // The size prefix
+                vtk::writeList(format(), f);
             }
         }
+
+        format().flush();
+    }
+    else
+    {
+        // Easy to write polys without a faceMap
+        writePolys(format(), faceLst);
     }
 
-    writeTail(os, zones);
+    // Write regions (zones) as CellData
+    if (zones.size() > 1)
+    {
+        writeCellData(format(), zones);
+    }
 }
 
 
@@ -298,33 +332,18 @@ void Foam::fileFormats::VTKsurfaceFormat<Face>::write
     const UnsortedMeshedSurface<Face>& surf
 )
 {
-    OFstream os(filename);
-    if (!os.good())
-    {
-        FatalErrorInFunction
-            << "Cannot open file for writing " << filename
-            << exit(FatalError);
-    }
+    std::ofstream os(filename.c_str());
 
+    autoPtr<vtk::formatter> format =
+        vtk::newFormatter(os, fmtType);
 
-    const List<Face>& faceLst = surf.surfFaces();
+    writeHeader(format(), surf.points());
 
-    writeHeader(os, surf.points());
-    writeHeaderPolygons(os, faceLst);
-
-    forAll(faceLst, facei)
-    {
-        const Face& f = faceLst[facei];
-
-        os << f.size();
-        forAll(f, fp)
-        {
-            os << ' ' << f[fp];
-        }
-        os << ' ' << nl;
-    }
+    // Easy to write polys without a faceMap
+    writePolys(format(), surf.surfFaces());
 
-    writeTail(os, surf.zoneIds());
+    // Write regions (zones) as CellData
+    writeCellData(format(), surf.zoneIds());
 }
 
 
diff --git a/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.H b/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.H
index 437eb249212441ffc2c574e3259ad8bca6836652..9a73aceeb5adae70feb2e8e98a6f59e3a1c353a0 100644
--- a/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.H
+++ b/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormat.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  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -60,8 +60,13 @@ class VTKsurfaceFormat
 {
     // Private Member Functions
 
-        //- Write header information about number of polygon points
-        static void writeHeaderPolygons(Ostream&, const UList<Face>&);
+        //- Write polygons
+        static void writePolys
+        (
+            vtk::formatter& format,
+            const UList<Face>& faces
+        );
+
 
         //- Disallow default bitwise copy construct
         VTKsurfaceFormat(const VTKsurfaceFormat<Face>&) = delete;
@@ -75,7 +80,7 @@ public:
     // Constructors
 
         //- Construct from file name
-        VTKsurfaceFormat(const fileName&);
+        VTKsurfaceFormat(const fileName& filename);
 
 
     // Selectors
@@ -97,24 +102,24 @@ public:
 
     // Member Functions
 
-        // Write
+      // Write
 
         //- Write surface mesh components by proxy
         static void write
         (
-            const fileName&,
-            const MeshedSurfaceProxy<Face>&
+            const fileName& filename,
+            const MeshedSurfaceProxy<Face>& surf
         );
 
         //- Write UnsortedMeshedSurface, the output remains unsorted
         static void write
         (
-            const fileName&,
-            const UnsortedMeshedSurface<Face>&
+            const fileName& fileName,
+            const UnsortedMeshedSurface<Face>& surf
         );
 
         //- Read from file
-        virtual bool read(const fileName&);
+        virtual bool read(const fileName& filename);
 
         //- Write object file
         virtual void write(const fileName& name) const
diff --git a/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormatCore.C b/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormatCore.C
index 9a28648d0c22c0310f6834c99fecfa893ed4552d..fe58168e5b23ffeb2eebb7e5c8e551fb9c905249 100644
--- a/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormatCore.C
+++ b/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormatCore.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) 2017 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -25,102 +25,103 @@ License
 
 #include "VTKsurfaceFormatCore.H"
 #include "clock.H"
+#include "foamVtkOutput.H"
 
 // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
 
 void Foam::fileFormats::VTKsurfaceFormatCore::writeHeader
 (
-    Ostream& os,
-    const pointField& pointLst
+    vtk::formatter& format,
+    const pointField& pts
 )
 {
-    // Write header
-    os  << "# vtk DataFile Version 2.0" << nl
-        << "surface written " << clock::dateTime().c_str() << nl
-        << "ASCII" << nl
-        << nl
-        << "DATASET POLYDATA" << nl;
-
-    // Write vertex coords
-    os  << "POINTS " << pointLst.size() << " float" << nl;
-    forAll(pointLst, ptI)
-    {
-        const point& pt = pointLst[ptI];
+    vtk::legacy::fileHeader
+    (
+        format,
+        ("surface written " + clock::dateTime()),
+        vtk::fileTag::POLY_DATA
+    );
 
-        os  << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
-    }
+    vtk::legacy::beginPoints(format.os(), pts.size());
+
+    vtk::writeList(format, pts);
+    format.flush();
 }
 
 
-void Foam::fileFormats::VTKsurfaceFormatCore::writeTail
+void Foam::fileFormats::VTKsurfaceFormatCore::writeCellData
 (
-    Ostream& os,
-    const UList<surfZone>& zoneLst
+    vtk::formatter& format,
+    const UList<surfZone>& zones
 )
 {
+    // Zone ids as CellData
+
+    // Number of faces covered by the zones
     label nFaces = 0;
-    forAll(zoneLst, zoneI)
+    for (const auto& z : zones)
     {
-        nFaces += zoneLst[zoneI].size();
+        nFaces += z.size();
     }
 
-    // Print zone numbers
-    os  << nl
-        << "CELL_DATA " << nFaces << nl
-        << "FIELD attributes 1" << nl
-        << "region 1 " << nFaces << " float" << nl;
-
-
-    forAll(zoneLst, zoneI)
+    vtk::legacy::dataHeader
+    (
+        format.os(),
+        vtk::fileTag::CELL_DATA,
+        nFaces,
+        1  // Only one field
+    );
+
+    vtk::legacy::intField
+    (
+        format.os(),
+        "region",
+        1, // nComponent
+        nFaces
+    );
+
+    label zoneId = 0;
+    for (const surfZone& zone : zones)
     {
-        forAll(zoneLst[zoneI], localFacei)
+        forAll(zone, i)
         {
-            if (localFacei)
-            {
-                if (localFacei % 20)
-                {
-                    os << ' ';
-                }
-                else
-                {
-                    os << nl;
-                }
-            }
-            os  << zoneI + 1;
+            format.write(zoneId);
         }
-        os  << nl;
+        ++zoneId;
     }
+    format.flush();
 }
 
 
-void Foam::fileFormats::VTKsurfaceFormatCore::writeTail
+void Foam::fileFormats::VTKsurfaceFormatCore::writeCellData
 (
-    Ostream& os,
+    vtk::formatter& format,
     const labelUList& zoneIds
 )
 {
-    // Print zone numbers
-    os  << nl
-        << "CELL_DATA " << zoneIds.size() << nl
-        << "FIELD attributes 1" << nl
-        << "region 1 " << zoneIds.size() << " float" << nl;
-
-    forAll(zoneIds, facei)
-    {
-        if (facei)
-        {
-            if (facei % 20)
-            {
-                os << ' ';
-            }
-            else
-            {
-                os << nl;
-            }
-        }
-        os  << zoneIds[facei] + 1;
-    }
-    os  << nl;
+    // Zone ids as CellData
+
+    // Number of faces
+    const label nFaces = zoneIds.size();
+
+    vtk::legacy::dataHeader
+    (
+        format.os(),
+        vtk::fileTag::CELL_DATA,
+        nFaces,
+        1  // Only one field
+    );
+
+    vtk::legacy::intField
+    (
+        format.os(),
+        "region",
+        1, // nComponent
+        nFaces
+    );
+
+    vtk::writeList(format, zoneIds);
+    format.flush();
 }
 
 
diff --git a/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormatCore.H b/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormatCore.H
index 946440ddb0cf3734cc1a2bf6e99d81d2b207c2ea..8b09942f87777ac28a80b2ed31d53df8c9bffd11 100644
--- a/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormatCore.H
+++ b/src/surfMesh/surfaceFormats/vtk/VTKsurfaceFormatCore.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -36,7 +36,7 @@ SourceFiles
 #define VTKsurfaceFormatCore_H
 
 #include "MeshedSurface.H"
-#include "Ostream.H"
+#include "foamVtkFormatter.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -58,15 +58,24 @@ protected:
         //- Write header information with points
         static void writeHeader
         (
-            Ostream&,
-            const pointField&
+            vtk::formatter& format,
+            const pointField& pts
         );
 
-        //- Write trailing information with zone information
-        static void writeTail(Ostream&, const UList<surfZone>&);
+        //- Write regions (zones) information as CellData
+        static void writeCellData
+        (
+            vtk::formatter& format,
+            const UList<surfZone>& zones
+        );
+
+        //- Write regions (zones) information as CellData
+        static void writeCellData
+        (
+            vtk::formatter& format,
+            const labelUList& zoneIds
+        );
 
-        //- Write trailing information with zone Ids
-        static void writeTail(Ostream&, const labelUList& zoneIds);
 };
 
 
diff --git a/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormat.C b/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormat.C
new file mode 100644
index 0000000000000000000000000000000000000000..edab56477518baca80b204c839c003f3513bc2f3
--- /dev/null
+++ b/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormat.C
@@ -0,0 +1,251 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 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 "VTPsurfaceFormat.H"
+#include "OFstream.H"
+#include "foamVtkOutput.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+// File-scope constant.
+//
+// TODO: make this run-time selectable
+// - No append mode supported
+// - Legacy mode is dispatched via 'VTKsurfaceFormat' instead
+
+static const Foam::vtk::formatType fmtType =
+    Foam::vtk::formatType::INLINE_ASCII;
+    // Foam::vtk::formatType::INLINE_BASE64;
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+template<class Face>
+void Foam::fileFormats::VTPsurfaceFormat<Face>::writePolys
+(
+    vtk::formatter& format,
+    const UList<Face>& faces
+)
+{
+    format.tag(vtk::fileTag::POLYS);
+
+    //
+    // 'connectivity'
+    //
+    {
+        uint64_t payLoad = 0;
+        for (const auto& f : faces)
+        {
+            payLoad += f.size();
+        }
+
+        format.openDataArray<label>(vtk::dataArrayAttr::CONNECTIVITY)
+            .closeTag();
+
+        format.writeSize(payLoad * sizeof(label));
+
+        for (const Face& f : faces)
+        {
+            vtk::writeList(format, f);
+        }
+
+        format.flush();
+        format.endDataArray();
+    }
+
+
+    //
+    // 'offsets'  (connectivity offsets)
+    //
+    {
+        const uint64_t payLoad(faces.size() * sizeof(label));
+
+        format
+            .openDataArray<label>(vtk::dataArrayAttr::OFFSETS)
+            .closeTag();
+
+        format.writeSize(payLoad);
+
+        label off = 0;
+        for (const auto& f : faces)
+        {
+            off += f.size();
+
+            format.write(off);
+        }
+
+        format.flush();
+        format.endDataArray();
+    }
+
+    format.endTag(vtk::fileTag::POLYS);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+template<class Face>
+Foam::fileFormats::VTPsurfaceFormat<Face>::VTPsurfaceFormat()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class Face>
+void Foam::fileFormats::VTPsurfaceFormat<Face>::write
+(
+    const fileName& filename,
+    const MeshedSurfaceProxy<Face>& surf
+)
+{
+    const pointField& pointLst = surf.points();
+    const List<Face>&  faceLst = surf.surfFaces();
+    const List<label>& faceMap = surf.faceMap();
+
+    const List<surfZone>& zones =
+    (
+        surf.surfZones().empty()
+      ? surfaceFormatsCore::oneZone(faceLst)
+      : surf.surfZones()
+    );
+
+    const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
+
+    std::ofstream os(filename.c_str(), std::ios::binary);
+
+    autoPtr<vtk::formatter> format =
+        vtk::newFormatter(os, fmtType);
+
+    writeHeader(format(), pointLst, faceLst.size());
+
+    if (useFaceMap)
+    {
+        format().tag(vtk::fileTag::POLYS);
+
+        //
+        // 'connectivity'
+        //
+        {
+            uint64_t payLoad = 0;
+            for (const auto& f : faceLst)
+            {
+                payLoad += f.size();
+            }
+
+            format().openDataArray<label>(vtk::dataArrayAttr::CONNECTIVITY)
+                .closeTag();
+
+            format().writeSize(payLoad * sizeof(label));
+
+            label faceIndex = 0;
+            for (const surfZone& zone : zones)
+            {
+                forAll(zone, i)
+                {
+                    const Face& f = faceLst[faceMap[faceIndex++]];
+
+                    vtk::writeList(format(), f);
+                }
+            }
+
+            format().flush();
+            format().endDataArray();
+        }
+
+
+        //
+        // 'offsets'  (connectivity offsets)
+        //
+        {
+            const uint64_t payLoad(faceLst.size() * sizeof(label));
+
+            format()
+                .openDataArray<label>(vtk::dataArrayAttr::OFFSETS)
+                    .closeTag();
+
+            format().writeSize(payLoad);
+
+            label off = 0, faceIndex = 0;
+            for (const surfZone& zone : zones)
+            {
+                forAll(zone, i)
+                {
+                    const Face& f = faceLst[faceMap[faceIndex++]];
+
+                    off += f.size();
+
+                    format().write(off);
+                }
+            }
+
+            format().flush();
+            format().endDataArray();
+        }
+
+        format().endTag(vtk::fileTag::POLYS);
+    }
+    else
+    {
+        // Easy to write polys without a faceMap
+        writePolys(format(), faceLst);
+    }
+
+    // Write regions (zones) as CellData
+    if (zones.size() > 1)
+    {
+        writeCellData(format(), zones);
+    }
+
+    writeFooter(format());
+}
+
+
+template<class Face>
+void Foam::fileFormats::VTPsurfaceFormat<Face>::write
+(
+    const fileName& filename,
+    const UnsortedMeshedSurface<Face>& surf
+)
+{
+    std::ofstream os(filename.c_str(), std::ios::binary);
+
+    autoPtr<vtk::formatter> format =
+        vtk::newFormatter(os, fmtType);
+
+    const List<Face>& faceLst = surf.surfFaces();
+
+    writeHeader(format(), surf.points(), faceLst.size());
+
+    // Easy to write polys without a faceMap
+    writePolys(format(), faceLst);
+
+    // Write regions (zones) as CellData
+    writeCellData(format(), surf.zoneIds());
+
+    writeFooter(format());
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/internalWriter.H b/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormat.H
similarity index 51%
rename from applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/internalWriter.H
rename to src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormat.H
index b1836afb60e16c05542594272367a3ea69fdea25..ebc35eca0843a45c3592aa3e8451c1eed791f1b3 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK/internalWriter.H
+++ b/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormat.H
@@ -2,8 +2,8 @@
   =========                 |
   \\      /  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.
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
+     \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -22,112 +22,109 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    Foam::internalWriter
+    Foam::fileFormats::VTPsurfaceFormat
 
 Description
-    Write fields (internal).
+    Provide a means of writing VTP (xml) format.
+    The output is never sorted by zone.
 
 SourceFiles
-    internalWriter.C
-    internalWriterTemplates.C
+    VTPsurfaceFormat.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef internalWriter_H
-#define internalWriter_H
+#ifndef VTPsurfaceFormat_H
+#define VTPsurfaceFormat_H
 
-#include "OFstream.H"
-#include "volFields.H"
-#include "pointFields.H"
-#include "vtkMesh.H"
+#include "MeshedSurface.H"
+#include "MeshedSurfaceProxy.H"
+#include "UnsortedMeshedSurface.H"
+#include "VTPsurfaceFormatCore.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
-
-class volPointInterpolation;
+namespace fileFormats
+{
 
 /*---------------------------------------------------------------------------*\
-                           Class internalWriter Declaration
+                      Class VTPsurfaceFormat Declaration
 \*---------------------------------------------------------------------------*/
 
-class internalWriter
+template<class Face>
+class VTPsurfaceFormat
+:
+    public MeshedSurface<Face>,
+    public VTPsurfaceFormatCore
 {
-    const vtkMesh& vMesh_;
+    // Private Member Functions
+
+        //- Write polygons
+        static void writePolys
+        (
+            vtk::formatter& format,
+            const UList<Face>& faces
+        );
 
-    const bool binary_;
 
-    const fileName fName_;
+        //- Disallow default bitwise copy construct
+        VTPsurfaceFormat(const VTPsurfaceFormat<Face>&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const VTPsurfaceFormat<Face>&) = delete;
 
-    std::ofstream os_;
 
 public:
 
     // Constructors
 
-        //- Construct from components
-        internalWriter
-        (
-            const vtkMesh&,
-            const bool binary,
-            const fileName&
-        );
+        //- Construct null
+        VTPsurfaceFormat();
 
 
-    // Member Functions
+    //- Destructor
+    virtual ~VTPsurfaceFormat()
+    {}
 
-        std::ofstream& os()
-        {
-            return os_;
-        }
 
-        //- Write cellIDs
-        void writeCellIDs();
+    // Member Functions
 
-        //- Write generic GeometricFields
-        template<class Type, template<class> class PatchField, class GeoMesh>
-        void write
-        (
-            const UPtrList<const GeometricField<Type, PatchField, GeoMesh>>&
-        );
+      // Write
 
-        //- Write generic internal fields
-        template<class Type, class GeoMesh>
-        void write
+        //- Write surface mesh components by proxy
+        static void write
         (
-            const PtrList<const DimensionedField<Type, volMesh>>& flds
+            const fileName& filename,
+            const MeshedSurfaceProxy<Face>& surf
         );
 
-        //- Interpolate and write volFields
-        template<class Type>
-        void write
+        //- Write UnsortedMeshedSurface, the output remains unsorted
+        static void write
         (
-            const volPointInterpolation&,
-            const UPtrList<const GeometricField<Type, fvPatchField, volMesh>>&
+            const fileName& filename,
+            const UnsortedMeshedSurface<Face>& surf
         );
 
-        //- Interpolate and internal fields
-        template<class Type, class GeoMesh>
-        void write
-        (
-            const volPointInterpolation&,
-            const PtrList<const DimensionedField<Type, volMesh>>&
-        );
+        //- Write object file
+        virtual void write(const fileName& name) const
+        {
+            write(name, MeshedSurfaceProxy<Face>(*this));
+        }
 };
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace fileFormats
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 #ifdef NoRepository
-    #include "internalWriterTemplates.C"
+    #include "VTPsurfaceFormat.C"
 #endif
 
-
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 #endif
diff --git a/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormatCore.C b/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormatCore.C
new file mode 100644
index 0000000000000000000000000000000000000000..947b77d32fee41426770527263b7af7e13cfc91d
--- /dev/null
+++ b/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormatCore.C
@@ -0,0 +1,149 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 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 "VTPsurfaceFormatCore.H"
+#include "clock.H"
+#include "foamVtkOutput.H"
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+void Foam::fileFormats::VTPsurfaceFormatCore::writeHeader
+(
+    vtk::formatter& format,
+    const pointField& pts,
+    const label nFaces
+)
+{
+    // XML (inline)
+
+    format
+        .xmlHeader()
+        .xmlComment("surface written " + clock::dateTime())
+        .beginVTKFile(vtk::fileTag::POLY_DATA, "0.1");
+
+    // <Piece>
+    format
+        .openTag(vtk::fileTag::PIECE)
+        .xmlAttr(vtk::fileAttr::NUMBER_OF_POINTS, pts.size())
+        .xmlAttr(vtk::fileAttr::NUMBER_OF_POLYS,  nFaces)
+        .closeTag();
+
+
+    // Points
+
+    const uint64_t payLoad = (pts.size()*3* sizeof(float));
+
+    format.tag(vtk::fileTag::POINTS)
+        .openDataArray<float, 3>(vtk::dataArrayAttr::POINTS)
+        .closeTag();
+
+    format.writeSize(payLoad);
+    vtk::writeList(format, pts);
+    format.flush();
+
+    format
+        .endDataArray()
+        .endTag(vtk::fileTag::POINTS);
+}
+
+
+void Foam::fileFormats::VTPsurfaceFormatCore::writeFooter
+(
+    vtk::formatter& format
+)
+{
+    // Slight cheat. </Piece> too
+    format.endTag(Foam::vtk::fileTag::PIECE);
+
+    format.endTag(vtk::fileTag::POLY_DATA)
+        .endVTKFile();
+}
+
+
+
+void Foam::fileFormats::VTPsurfaceFormatCore::writeCellData
+(
+    vtk::formatter& format,
+    const UList<surfZone>& zones
+)
+{
+    // Zone ids as CellData
+
+    // Number of faces covered by the zones
+    uint64_t payLoad = 0;
+    for (const auto& z : zones)
+    {
+        payLoad += z.size();
+    }
+
+    format.tag(vtk::fileTag::CELL_DATA);
+    format.openDataArray<label>("region")
+        .closeTag();
+
+    format.writeSize(payLoad * sizeof(label));
+
+    label zoneId = 0;
+    for (const surfZone& zone : zones)
+    {
+        forAll(zone, i)
+        {
+            format.write(zoneId);
+        }
+        ++zoneId;
+    }
+
+    format.flush();
+    format.endDataArray();
+
+    format.endTag(vtk::fileTag::CELL_DATA);
+}
+
+
+void Foam::fileFormats::VTPsurfaceFormatCore::writeCellData
+(
+    vtk::formatter& format,
+    const labelUList& zoneIds
+)
+{
+    // Zone ids as CellData
+
+    format.tag(vtk::fileTag::CELL_DATA);
+    format.openDataArray<label>("region")
+        .closeTag();
+
+    const uint64_t payLoad(zoneIds.size() * sizeof(label));
+
+    format.writeSize(payLoad);
+    vtk::writeList(format, zoneIds);
+
+    format.flush();
+    format.endDataArray();
+
+    format.endTag(vtk::fileTag::CELL_DATA);
+
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/vtk/foamVtkCore.H b/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormatCore.H
similarity index 54%
rename from src/fileFormats/vtk/foamVtkCore.H
rename to src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormatCore.H
index adcdc00871a5300fb0e5ddb4e12345473d40b1f8..4b4a3ad85de4446b97d4a442ffaf63d5f9d48e0c 100644
--- a/src/fileFormats/vtk/foamVtkCore.H
+++ b/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormatCore.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -22,84 +22,70 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    Foam::foamVtkCore
+    Foam::fileFormats::VTPsurfaceFormatCore
 
 Description
-    Core routines for dealing with VTK files.
+    Internal class used by the VTPsurfaceFormat
 
 SourceFiles
-    foamVtkCore.C
+    VTPsurfaceFormatCore.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef foamVtkCore_H
-#define foamVtkCore_H
+#ifndef VTPsurfaceFormatCore_H
+#define VTPsurfaceFormatCore_H
+
+#include "MeshedSurface.H"
+#include "foamVtkFormatter.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
-
 namespace fileFormats
 {
 
 /*---------------------------------------------------------------------------*\
-                  Class fileFormats::foamVtkCore Declaration
+                    Class VTPsurfaceFormatCore Declaration
 \*---------------------------------------------------------------------------*/
 
-class foamVtkCore
+class VTPsurfaceFormatCore
 {
-public:
-
-    // Public Data, Declarations
-
-        //- The context when outputting a VTK file (XML or legacy).
-        enum OutputContext
-        {
-            INLINE,     //<! Generate header and inline data
-            HEADER,     //<! Generate header only
-            APPEND      //<! Generate append-data
-        };
-
-
-        //- Equivalent to enumeration in "vtkCellType.h"
-        enum vtkTypes
-        {
-            VTK_EMPTY_CELL       = 0,
-            VTK_VERTEX           = 1,
-            VTK_POLY_VERTEX      = 2,
-            VTK_LINE             = 3,
-            VTK_POLY_LINE        = 4,
-            VTK_TRIANGLE         = 5,
-            VTK_TRIANGLE_STRIP   = 6,
-            VTK_POLYGON          = 7,
-            VTK_PIXEL            = 8,
-            VTK_QUAD             = 9,
-            VTK_TETRA            = 10,
-            VTK_VOXEL            = 11,
-            VTK_HEXAHEDRON       = 12,
-            VTK_WEDGE            = 13,
-            VTK_PYRAMID          = 14,
-            VTK_PENTAGONAL_PRISM = 15,
-            VTK_HEXAGONAL_PRISM  = 16,
-            VTK_POLYHEDRON       = 42
-        };
-
-
 protected:
 
-    // Constructors
-
-        //- Construct null
-        foamVtkCore();
-
+    // Protected Member Functions
+
+        //- Write file header information with points
+        static void writeHeader
+        (
+            vtk::formatter& format,
+            const pointField& pts,
+            const label nFaces
+        );
+
+        //- Write file footer
+        static void writeFooter(vtk::formatter& format);
+
+
+        //- Write regions (zones) information as CellData
+        static void writeCellData
+        (
+            vtk::formatter& format,
+            const UList<surfZone>& zones
+        );
+
+        //- Write regions (zones) information as CellData
+        static void writeCellData
+        (
+            vtk::formatter& format,
+            const labelUList& zoneIds
+        );
 };
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 } // End namespace fileFormats
-
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormatRunTime.C b/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormatRunTime.C
new file mode 100644
index 0000000000000000000000000000000000000000..ab9ca19e13028e38dd903f78ec4e105bb1a18ba0
--- /dev/null
+++ b/src/surfMesh/surfaceFormats/vtp/VTPsurfaceFormatRunTime.C
@@ -0,0 +1,98 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 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 "VTPsurfaceFormat.H"
+
+#include "addToRunTimeSelectionTable.H"
+#include "addToMemberFunctionSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace fileFormats
+{
+// write MeshedSurfaceProxy
+addNamedTemplatedToMemberFunctionSelectionTable
+(
+    MeshedSurfaceProxy,
+    VTPsurfaceFormat,
+    face,
+    write,
+    fileExtension,
+    vtp
+);
+addNamedTemplatedToMemberFunctionSelectionTable
+(
+    MeshedSurfaceProxy,
+    VTPsurfaceFormat,
+    triFace,
+    write,
+    fileExtension,
+    vtp
+);
+addNamedTemplatedToMemberFunctionSelectionTable
+(
+    MeshedSurfaceProxy,
+    VTPsurfaceFormat,
+    labelledTri,
+    write,
+    fileExtension,
+    vtp
+);
+
+// write UnsortedMeshedSurface
+addNamedTemplatedToMemberFunctionSelectionTable
+(
+    UnsortedMeshedSurface,
+    VTPsurfaceFormat,
+    face,
+    write,
+    fileExtension,
+    vtp
+);
+addNamedTemplatedToMemberFunctionSelectionTable
+(
+    UnsortedMeshedSurface,
+    VTPsurfaceFormat,
+    triFace,
+    write,
+    fileExtension,
+    vtp
+);
+addNamedTemplatedToMemberFunctionSelectionTable
+(
+    UnsortedMeshedSurface,
+    VTPsurfaceFormat,
+    labelledTri,
+    write,
+    fileExtension,
+    vtp
+);
+
+}
+}
+
+// ************************************************************************* //
diff --git a/src/surfMesh/triSurface/interfaces/VTK/writeVTK.C b/src/surfMesh/triSurface/interfaces/VTK/writeVTK.C
index 41e33ea0c5db5f4a733f830e2bcd7e0a2adc30ef..047a5c53a755599a93bed86607c17610bb7daefd 100644
--- a/src/surfMesh/triSurface/interfaces/VTK/writeVTK.C
+++ b/src/surfMesh/triSurface/interfaces/VTK/writeVTK.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) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -24,159 +24,144 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "triSurface.H"
+#include "foamVtkOutput.H"
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+// File-scope constant.
+//
+// TODO: make this run-time selectable (ASCII | BINARY)
+// - Legacy mode only
+
+static const Foam::vtk::formatType fmtType =
+    Foam::vtk::formatType::LEGACY_ASCII;
+    // Foam::vtk::formatType::LEGACY_BINARY;
 
-namespace Foam
-{
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-void triSurface::writeVTK(const bool writeSorted, Ostream& os) const
+void Foam::triSurface::writeVTK
+(
+    const bool writeSorted,
+    std::ostream& os
+) const
 {
-    // Write header
-    os  << "# vtk DataFile Version 2.0" << nl
-        << "triSurface" << nl
-        << "ASCII" << nl
-        << "DATASET POLYDATA"
-        << nl;
+    autoPtr<vtk::formatter> format =
+        vtk::newFormatter(os, fmtType);
 
-    const pointField& ps = points();
+    // Header
+    vtk::legacy::fileHeader
+    (
+        format(),
+        "triSurface",
+        vtk::fileTag::POLY_DATA
+    );
 
-    os  << "POINTS " << ps.size() << " float" << nl;
+    const pointField& pts = this->points();
+    const auto& faceLst = this->surfFaces();
 
-    // Write vertex coords
-    forAll(ps, pointi)
-    {
-        if (pointi > 0 && (pointi % 10) == 0)
-        {
-            os  << nl;
-        }
-        else
-        {
-            os  << ' ';
-        }
-        os  << ps[pointi].x() << ' '
-            << ps[pointi].y() << ' '
-            << ps[pointi].z();
-    }
-    os  << nl;
+    const label nFaces = faceLst.size();
+
+    // Points
+    vtk::legacy::beginPoints(os, pts.size());
+
+    vtk::writeList(format(), pts);
+    format().flush();
 
-    os  << "POLYGONS " << size() << ' ' << 4*size() << nl;
+    // connectivity count (without additional storage)
+    // is simply 3 * nFaces
+
+    vtk::legacy::beginPolys(os, nFaces, 3*nFaces);
 
     labelList faceMap;
     surfacePatchList patches(calcPatches(faceMap));
 
-    if (writeSorted)
+    const bool useFaceMap = (writeSorted && patches.size() > 1);
+
+    if (useFaceMap)
     {
         label faceIndex = 0;
-
-        forAll(patches, patchi)
+        for (const surfacePatch& patch : patches)
         {
-            // Print all faces belonging to this patch
-
-            for
-            (
-                label patchFacei = 0;
-                patchFacei < patches[patchi].size();
-                patchFacei++
-            )
+            forAll(patch, i)
             {
-                if (faceIndex > 0 && (faceIndex % 10) == 0)
-                {
-                    os  << nl;
-                }
-                else
-                {
-                    os  << ' ';
-                }
+                const Face& f = faceLst[faceMap[faceIndex++]];
 
-                const label facei = faceMap[faceIndex++];
-
-                os  << "3 "
-                    << operator[](facei)[0] << ' '
-                    << operator[](facei)[1] << ' '
-                    << operator[](facei)[2];
+                format().write(3);  // The size prefix
+                vtk::writeList(format(), f);
             }
         }
-        os  << nl;
-
+        format().flush();
 
-        // Print region numbers
 
-        os  << "CELL_DATA " << size() << nl;
-        os  << "FIELD attributes 1" << nl;
-        os  << "region 1 " << size() << " float" << nl;
-
-        faceIndex = 0;
-
-        forAll(patches, patchi)
+        // Write regions (zones) as CellData
+        if (patches.size() > 1)
         {
-            for
+            vtk::legacy::dataHeader
+            (
+                os,
+                vtk::fileTag::CELL_DATA,
+                nFaces,
+                1  // Only one field
+            );
+
+            vtk::legacy::intField
             (
-                label patchFacei = 0;
-                patchFacei < patches[patchi].size();
-                patchFacei++
-            )
+                os,
+                "region",
+                1, // nComponent
+                nFaces
+            );
+
+            faceIndex = 0;
+            for (const surfacePatch& patch : patches)
             {
-                if (faceIndex > 0 && (faceIndex % 10) == 0)
-                {
-                    os  << nl;
-                }
-                else
+                forAll(patch, i)
                 {
-                    os  << ' ';
+                    const Face& f = faceLst[faceMap[faceIndex++]];
+                    format().write(f.region());
                 }
-
-                const label facei = faceMap[faceIndex++];
-
-                os  << operator[](facei).region();
             }
+            format().flush();
         }
-        os  << nl;
     }
     else
     {
-        forAll(*this, facei)
+        // No faceMap (unsorted)
+
+        for (const Face& f : faceLst)
         {
-            if (facei > 0 && (facei % 10) == 0)
-            {
-                os  << nl;
-            }
-            else
-            {
-                os  << ' ';
-            }
-            os  << "3 "
-                << operator[](facei)[0] << ' '
-                << operator[](facei)[1] << ' '
-                << operator[](facei)[2];
+            format().write(3);  // The size prefix
+            vtk::writeList(format(), f);
         }
-        os  << nl;
+        format().flush();
+
 
-        os  << "CELL_DATA " << size() << nl;
-        os  << "FIELD attributes 1" << nl;
-        os  << "region 1 " << size() << " float" << nl;
+        // Write regions (zones) as CellData
 
-        forAll(*this, facei)
+        vtk::legacy::dataHeader
+        (
+            os,
+            vtk::fileTag::CELL_DATA,
+            faceLst.size(),
+            1  // Only one field
+        );
+
+        vtk::legacy::intField
+        (
+            os,
+            "region",
+            1, // nComponent
+            faceLst.size()
+        );
+
+        for (const Face& f : faceLst)
         {
-            if (facei > 0 && (facei % 10) == 0)
-            {
-                os  << nl;
-            }
-            else
-            {
-                os  << ' ';
-            }
-            os  << operator[](facei).region();
+            format().write(f.region());
         }
-        os  << nl;
+        format().flush();
     }
 }
 
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
 // ************************************************************************* //
diff --git a/src/surfMesh/triSurface/triSurface.C b/src/surfMesh/triSurface/triSurface.C
index fa8c7ba874c733346007586db38076584317fb92..324c7913de7e80ce93780fdf15feed40c557f742 100644
--- a/src/surfMesh/triSurface/triSurface.C
+++ b/src/surfMesh/triSurface/triSurface.C
@@ -33,6 +33,7 @@ License
 #include "PackedBoolList.H"
 #include "surfZoneList.H"
 #include "surfaceFormatsCore.H"
+#include "MeshedSurfaceProxy.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -52,7 +53,9 @@ const Foam::wordHashSet Foam::triSurface::readTypes_
 
 const Foam::wordHashSet Foam::triSurface::writeTypes_
 {
-    "ftr", "stl", "stlb", "gts", "obj", "off", "tri", "ac", "smesh", "vtk"
+    "ftr", "stl", "stlb", "gts", "obj", "off", "tri", "ac", "smesh", "vtk",
+    // via proxy:
+    "inp", "vtp"
 };
 
 
@@ -477,8 +480,9 @@ bool Foam::triSurface::read
     {
         FatalErrorInFunction
             << "unknown file extension " << ext
-            << ". Supported extensions are '.ftr', '.stl', '.stlb', '.gts'"
-            << ", '.obj', '.ac', '.off', '.nas', '.tri' and '.vtk'"
+            << " for reading file " << name
+            << ". Supported extensions:" << nl
+            << "    " << flatOutput(readTypes_.sortedToc()) << nl
             << exit(FatalError);
 
         return false;
@@ -504,7 +508,7 @@ void Foam::triSurface::write
     }
     else if (ext == "stlb")
     {
-        ofstream outFile(name.c_str(), std::ios::binary);
+        std::ofstream outFile(name.c_str(), std::ios::binary);
 
         writeSTLBINARY(outFile);
     }
@@ -522,7 +526,27 @@ void Foam::triSurface::write
     }
     else if (ext == "vtk")
     {
-        writeVTK(sort, OFstream(name)());
+        std::ofstream outFile(name.c_str(), std::ios::binary);
+        writeVTK(sort, outFile);
+    }
+    else if
+    (
+        ext == "inp"  // STARCD
+     || ext == "vtp"  // VTK
+    )
+    {
+        labelList faceMap;
+        List<surfZone> zoneLst = this->sortedZones(faceMap);
+
+        MeshedSurfaceProxy<labelledTri> proxy
+        (
+            this->points(),
+            this->surfFaces(),
+            zoneLst,
+            faceMap
+        );
+
+        proxy.write(name, ext);
     }
     else if (ext == "tri")
     {
@@ -540,10 +564,9 @@ void Foam::triSurface::write
     {
         FatalErrorInFunction
             << "unknown file extension " << ext
-            << " for file " << name
-            << ". Supported extensions are '.ftr', '.stl', '.stlb', "
-            << "'.gts', '.obj', '.vtk'"
-            << ", '.off', '.smesh', '.ac' and '.tri'"
+            << " for writing file " << name
+            << ". Supported extensions:" << nl
+            << "    " << flatOutput(writeTypes_.sortedToc()) << nl
             << exit(FatalError);
     }
 }
diff --git a/src/surfMesh/triSurface/triSurface.H b/src/surfMesh/triSurface/triSurface.H
index fa10f875578efc18023617b69c2278845ee8c10d..24f8b5183787adbfe13ccea8a4f23a415bd22f29 100644
--- a/src/surfMesh/triSurface/triSurface.H
+++ b/src/surfMesh/triSurface/triSurface.H
@@ -167,7 +167,7 @@ class triSurface
         void writeOFF(const bool writeSorted, Ostream&) const;
 
         //- Write to VTK legacy format.
-        void writeVTK(const bool writeSorted, Ostream&) const;
+        void writeVTK(const bool writeSorted, std::ostream& os) const;
 
         //- Write to Ostream in TRI (AC3D) format
         //  Ac3d .tri format (unmerged triangle format)
@@ -318,143 +318,145 @@ public:
 
     // Member Functions
 
-        // Access
-
-            const geometricSurfacePatchList& patches() const
-            {
-                return patches_;
-            }
-
-            geometricSurfacePatchList& patches()
-            {
-                return patches_;
-            }
-
-            //- Return edge-face addressing sorted (for edges with more than
-            //  2 faces) according to the angle around the edge.
-            //  Orientation is anticlockwise looking from
-            //  edge.vec(localPoints())
-            const labelListList& sortedEdgeFaces() const;
-
-            //- If 2 face neighbours: label of face where ordering of edge
-            //  is consistent with righthand walk.
-            //  If 1 neighbour: label of only face.
-            //  If >2 neighbours: undetermined.
-            const labelList& edgeOwner() const;
-
+      // Access
 
-            //- Face area vectors (normals)
-            inline const vectorField& Sf() const
-            {
-                return ParentType::faceAreas();
-            }
+        const geometricSurfacePatchList& patches() const
+        {
+            return patches_;
+        }
 
-            //- Face area magnitudes
-            inline const scalarField& magSf() const
-            {
-                return ParentType::magFaceAreas();
-            }
+        geometricSurfacePatchList& patches()
+        {
+            return patches_;
+        }
 
-            //- Face centres
-            inline const vectorField& Cf() const
-            {
-                return ParentType::faceCentres();
-            }
+        //- Return const access to the faces
+        inline const List<labelledTri>& surfFaces() const
+        {
+            return static_cast<const List<labelledTri>&>(*this);
+        }
 
+        //- Return edge-face addressing sorted (for edges with more than
+        //  2 faces) according to the angle around the edge.
+        //  Orientation is anticlockwise looking from
+        //  edge.vec(localPoints())
+        const labelListList& sortedEdgeFaces() const;
 
-        // Interoperability with other surface mesh classes
+        //- If 2 face neighbours: label of face where ordering of edge
+        //  is consistent with righthand walk.
+        //  If 1 neighbour: label of only face.
+        //  If >2 neighbours: undetermined.
+        const labelList& edgeOwner() const;
 
-            //- Sort faces according to zoneIds
-            //  Returns a surfZoneList and sets faceMap to index within faces()
-            //  (i.e. map from original,unsorted to sorted)
-            List<surfZone> sortedZones(labelList& faceMap) const;
 
-            //- Create a list of faces from the triFaces
-            void triFaceFaces(List<face>& plainFaceList) const;
+        //- Face area vectors (normals)
+        inline const vectorField& Sf() const
+        {
+            return ParentType::faceAreas();
+        }
 
+        //- Face area magnitudes
+        inline const scalarField& magSf() const
+        {
+            return ParentType::magFaceAreas();
+        }
 
-        // Edit
+        //- Face centres
+        inline const vectorField& Cf() const
+        {
+            return ParentType::faceCentres();
+        }
+
+
+      // Interoperability with other surface mesh classes
+
+        //- Sort faces according to zoneIds
+        //  Returns a surfZoneList and sets faceMap to index within faces()
+        //  (i.e. map from original,unsorted to sorted)
+        List<surfZone> sortedZones(labelList& faceMap) const;
+
+        //- Create a list of faces from the triFaces
+        void triFaceFaces(List<face>& plainFaceList) const;
 
-            //- Move points
-            virtual void movePoints(const pointField&);
 
-            //- Scale points. A non-positive factor is ignored
-            virtual void scalePoints(const scalar);
+      // Edit
 
-            //- Check/remove duplicate/degenerate triangles
-            void checkTriangles(const bool verbose);
+        //- Move points
+        virtual void movePoints(const pointField&);
 
-            //- Check triply (or more) connected edges.
-            void checkEdges(const bool verbose);
+        //- Scale points. A non-positive factor is ignored
+        virtual void scalePoints(const scalar);
 
-            //- Remove non-valid triangles
-            void cleanup(const bool verbose);
+        //- Check/remove duplicate/degenerate triangles
+        void checkTriangles(const bool verbose);
 
-            //- Fill faceZone with currentZone for every face reachable
-            //  from facei without crossing edge marked in borderEdge.
-            //  Note: faceZone has to be sized nFaces before calling this fun.
-            void markZone
-            (
-                const boolList& borderEdge,
-                const label facei,
-                const label currentZone,
-                labelList& faceZone
-            ) const;
+        //- Check triply (or more) connected edges.
+        void checkEdges(const bool verbose);
 
-            //- (size and) fills faceZone with zone of face. Zone is area
-            //  reachable by edge crossing without crossing borderEdge
-            //  (bool for every edge in surface). Returns number of zones.
-            label markZones
-            (
-                const boolList& borderEdge,
-                labelList& faceZone
-            ) const;
+        //- Remove non-valid triangles
+        void cleanup(const bool verbose);
 
-            //- 'Create' sub mesh, including only faces for which
-            //  boolList entry is true
-            //  Sets: pointMap: from new to old localPoints
-            //        faceMap: new to old faces
-            void subsetMeshMap
-            (
-                const boolList& include,
-                labelList& pointMap,
-                labelList& faceMap
-            ) const;
-
-            //- Return new surface. Returns pointMap, faceMap from
-            //  subsetMeshMap
-            triSurface subsetMesh
-            (
-                const boolList& include,
-                labelList& pointMap,
-                labelList& faceMap
-            ) const;
+        //- Fill faceZone with currentZone for every face reachable
+        //  from facei without crossing edge marked in borderEdge.
+        //  Note: faceZone has to be sized nFaces before calling this fun.
+        void markZone
+        (
+            const boolList& borderEdge,
+            const label facei,
+            const label currentZone,
+            labelList& faceZone
+        ) const;
+
+        //- (size and) fills faceZone with zone of face. Zone is area
+        //  reachable by edge crossing without crossing borderEdge
+        //  (bool for every edge in surface). Returns number of zones.
+        label markZones
+        (
+            const boolList& borderEdge,
+            labelList& faceZone
+        ) const;
+
+        //- 'Create' sub mesh, including only faces for which
+        //  boolList entry is true
+        //  Sets: pointMap: from new to old localPoints
+        //        faceMap: new to old faces
+        void subsetMeshMap
+        (
+            const boolList& include,
+            labelList& pointMap,
+            labelList& faceMap
+        ) const;
+
+        //- Return new surface. Returns pointMap, faceMap from
+        //  subsetMeshMap
+        triSurface subsetMesh
+        (
+            const boolList& include,
+            labelList& pointMap,
+            labelList& faceMap
+        ) const;
 
 
-            //- Transfer stored faces to an Xfer container
-            Xfer<List<labelledTri>> xferFaces();
-
-            //- Transfer stored points to an Xfer container
-            Xfer<List<point>> xferPoints();
+        //- Transfer stored faces to an Xfer container
+        Xfer<List<labelledTri>> xferFaces();
 
+        //- Transfer stored points to an Xfer container
+        Xfer<List<point>> xferPoints();
 
-        // Write
 
-            //- Write to Ostream in simple FOAM format
-            void write(Ostream&) const;
+      // Write
 
-            //- Generic write routine. Chooses writer based on extension.
-            void write(const fileName&, const bool sortByRegion = false) const;
+        //- Write to Ostream in simple FOAM format
+        void write(Ostream&) const;
 
-            //- Write to database
-            void write(const Time&) const;
+        //- Generic write routine. Chooses writer based on extension.
+        void write(const fileName&, const bool sortByRegion = false) const;
 
-            //- Write to Ostream in OpenDX format
-            void writeDX(const scalarField&, Ostream&) const;
-            void writeDX(const vectorField&, Ostream&) const;
+        //- Write to database
+        void write(const Time&) const;
 
-            //- Write some statistics
-            void writeStats(Ostream&) const;
+        //- Write some statistics
+        void writeStats(Ostream& os) const;
 
 
     // Member operators
diff --git a/tutorials/incompressible/simpleFoam/motorBike/system/ensightWrite b/tutorials/incompressible/simpleFoam/motorBike/system/ensightWrite
index 34e7b14d71b4f1e12eea04845ba07454a9f3264b..2630bdc3b63debd09671c9747ef073584682e9b7 100644
--- a/tutorials/incompressible/simpleFoam/motorBike/system/ensightWrite
+++ b/tutorials/incompressible/simpleFoam/motorBike/system/ensightWrite
@@ -10,8 +10,8 @@ ensightWrite
     // Fields to output (words or regex)
     fields  (U p "(k|epsilon|omega)");
 
-    writeControl writeTime;
-    writeIterval 1;
+    writeControl  writeTime;
+    writeInterval 1;
 }
 
 // ************************************************************************* //
diff --git a/tutorials/incompressible/simpleFoam/windAroundBuildings/system/controlDict b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/controlDict
index 7ceca861c1be4f50552b4ba7b4588ed3bbced585..2f6bf243811bd5adbf5df6cc4a73fbb69a42eafe 100644
--- a/tutorials/incompressible/simpleFoam/windAroundBuildings/system/controlDict
+++ b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/controlDict
@@ -50,6 +50,8 @@ runTimeModifiable true;
 
 functions
 {
+    #include "vtkWrite"
 }
 
+
 // ************************************************************************* //
diff --git a/tutorials/incompressible/simpleFoam/windAroundBuildings/system/vtkWrite b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/vtkWrite
new file mode 100644
index 0000000000000000000000000000000000000000..9f729db0cba4f5feeb3aad2341dd483c75941b0c
--- /dev/null
+++ b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/vtkWrite
@@ -0,0 +1,31 @@
+// -*- C++ -*-
+// Minimal example of using the vtkWrite function object.
+vtkWrite
+{
+    type    vtkWrite;
+    libs    ("libutilityFunctionObjects.so");
+    log     true;
+
+    // Fields to output (words or regex)
+    fields  (U p "(k|epsilon|omega)");
+
+    //- Output format (ascii | binary) - Default=binary
+    // format  binary;
+
+    //- Use legacy output format - Default=false
+    // legacy  false;
+
+    //- Output directory name - Default="VTK"
+    // directory       "VTK";
+
+    //- Write cell ids as field - Default=true
+    writeIds        false;
+
+    writeControl    writeTime;
+    writeInterval   1;
+
+    writeControl    timeStep;
+    writeInterval   25;
+}
+
+// ************************************************************************* //