From 0d2dbaf61b23673f7f085ef5eb35003ea35a7ca9 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Mon, 17 Sep 2018 15:41:58 +0200
Subject: [PATCH] ENH: parallel and xml output for vtk topoSet writers (issue
 #926)

- introduce lower-level vtk::indirectPatchWriter class
---
 .../mesh/manipulation/setSet/setSet.C         |  93 ++--
 .../dataConversion/foamToVTK/foamToVTK.C      |  50 +-
 src/meshTools/Make/files                      |   2 +
 src/meshTools/output/foamVtkIndPatchWriter.C  | 449 ++++++++++++++++++
 src/meshTools/output/foamVtkIndPatchWriter.H  | 222 +++++++++
 .../output/foamVtkIndPatchWriterTemplates.C   | 130 +++++
 .../output/foamVtkWriteCellSetFaces.C         | 103 ++--
 src/meshTools/output/foamVtkWriteFaceSet.C    |  87 ++--
 src/meshTools/output/foamVtkWritePointSet.C   | 210 ++++++--
 src/meshTools/output/foamVtkWritePointSet.H   |  73 ---
 ...tkWriteFaceSet.H => foamVtkWriteTopoSet.C} |  98 ++--
 ...teCellSetFaces.H => foamVtkWriteTopoSet.H} |  74 ++-
 12 files changed, 1246 insertions(+), 345 deletions(-)
 create mode 100644 src/meshTools/output/foamVtkIndPatchWriter.C
 create mode 100644 src/meshTools/output/foamVtkIndPatchWriter.H
 create mode 100644 src/meshTools/output/foamVtkIndPatchWriterTemplates.C
 delete mode 100644 src/meshTools/output/foamVtkWritePointSet.H
 rename src/meshTools/output/{foamVtkWriteFaceSet.H => foamVtkWriteTopoSet.C} (51%)
 rename src/meshTools/output/{foamVtkWriteCellSetFaces.H => foamVtkWriteTopoSet.H} (52%)

diff --git a/applications/utilities/mesh/manipulation/setSet/setSet.C b/applications/utilities/mesh/manipulation/setSet/setSet.C
index fa48186c90c..e37212d1605 100644
--- a/applications/utilities/mesh/manipulation/setSet/setSet.C
+++ b/applications/utilities/mesh/manipulation/setSet/setSet.C
@@ -43,9 +43,7 @@ Description
 #include "topoSetSource.H"
 #include "Fstream.H"
 #include "demandDrivenData.H"
-#include "foamVtkWriteCellSetFaces.H"
-#include "foamVtkWriteFaceSet.H"
-#include "foamVtkWritePointSet.H"
+#include "foamVtkWriteTopoSet.H"
 #include "IOobjectList.H"
 #include "cellZoneSet.H"
 #include "faceZoneSet.H"
@@ -70,47 +68,26 @@ using namespace Foam;
 void writeVTK
 (
     const polyMesh& mesh,
-    const topoSet& currentSet,
-    const fileName& vtkBaseName
+    const topoSet& currSet,
+    const fileName& outputName
 )
 {
-    if (isA<faceSet>(currentSet))
-    {
-        // Faces of set with OpenFOAM faceID as value
-        vtk::writeFaceSet
-        (
-            mesh,
-            dynamicCast<const faceSet&>(currentSet),
-            mesh.time().path()/vtkBaseName,
-            vtk::formatType::LEGACY_BINARY
-        );
-    }
-    else if (isA<cellSet>(currentSet))
-    {
-        // External faces of cellset with OpenFOAM cellID as value
-        vtk::writeCellSetFaces
-        (
-            mesh,
-            dynamicCast<const cellSet&>(currentSet),
-            mesh.time().path()/vtkBaseName,
-            vtk::formatType::LEGACY_BINARY
-        );
-    }
-    else if (isA<pointSet>(currentSet))
-    {
-        vtk::writePointSet
+    if
+    (
+        !vtk::writeTopoSet
         (
             mesh,
-            dynamicCast<const pointSet&>(currentSet),
-            mesh.time().path()/vtkBaseName,
-            vtk::formatType::LEGACY_BINARY
-        );
-    }
-    else
+            currSet,
+            vtk::formatType::INLINE_BASE64,     // XML-binary
+            // vtk::formatType::LEGACY_BINARY,
+            outputName,
+            false // Not parallel
+        )
+    )
     {
         WarningInFunction
-            << "Don't know how to handle set of type " << currentSet.type()
-            << endl;
+            << "Don't know how to handle set of type "
+            << currSet.type() << nl;
     }
 }
 
@@ -502,35 +479,35 @@ bool doCommand
                 if (!noSync) currentSet.sync(mesh);
 
                 // Write
+                Info<< "    Writing " << currentSet.name()
+                    << " (size "
+                    << returnReduce(currentSet.size(), sumOp<label>())
+                    << ") to "
+                    << (
+                          currentSet.instance()/currentSet.local()
+                        / currentSet.name()
+                       );
+
+
                 if (writeVTKFile)
                 {
-                    mkDir(mesh.time().path()/"VTK"/currentSet.name());
-
-                    fileName vtkName
+                    fileName outputName
                     (
-                        "VTK"/currentSet.name()/currentSet.name()
-                      + "_"
-                      + name(mesh.time().timeIndex())
+                        mesh.time().path()/"VTK"/currentSet.name()
+                      / currentSet.name() + "_"
+                      + Foam::name(mesh.time().timeIndex())
                     );
+                    mkDir(outputName.path());
 
-                    Info<< "    Writing " << currentSet.name()
-                        << " (size "
-                        << returnReduce(currentSet.size(), sumOp<label>())
-                        << ") to "
-                        << currentSet.instance()/currentSet.local()
-                           /currentSet.name()
-                        << " and to vtk file " << vtkName << endl << endl;
+                    Info<< " and to vtk file "
+                        << outputName.relative(mesh.time().path())
+                        << nl << nl;
 
-                    writeVTK(mesh, currentSet, vtkName);
+                    writeVTK(mesh, currentSet, outputName);
                 }
                 else
                 {
-                    Info<< "    Writing " << currentSet.name()
-                        << " (size "
-                        << returnReduce(currentSet.size(), sumOp<label>())
-                        << ") to "
-                        << currentSet.instance()/currentSet.local()
-                           /currentSet.name() << endl << endl;
+                    Info<< nl << nl;
                 }
 
                 if (writeCurrentTime)
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C
index e253be1f19e..3fdb93d05c1 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C
@@ -168,8 +168,7 @@ Note
 #include "foamVtkPatchWriter.H"
 #include "foamVtkSurfaceMeshWriter.H"
 #include "foamVtkLagrangianWriter.H"
-#include "foamVtkWriteFaceSet.H"
-#include "foamVtkWritePointSet.H"
+#include "foamVtkWriteTopoSet.H"
 #include "foamVtkWriteSurfFields.H"
 
 #include "memInfo.H"
@@ -629,21 +628,25 @@ int main(int argc, char *argv[])
             vtuMeshCells.clear();
         }
 
+
+        // Attempt topoSets first
+        bool shortCircuit = false;
+
         // If faceSet: write faceSet only (as polydata)
         if (faceSetName.size())
         {
-            // Load the faceSet
+            // Load
             faceSet set(mesh, faceSetName);
 
             // Filename as if patch with same name.
-            mkDir(fvPath/set.name());
-
-            fileName outputName
+            const fileName outputName
             (
-                fvPath/set.name()/set.name()
-              + "_"
-              + timeDesc
+                fvPath/set.name()
+              / set.name() + "_" + timeDesc
             );
+
+            mkDir(outputName.path());
+
             Info<< "    faceSet   : "
                 << outputName.relative(runTime.path()) << nl;
 
@@ -651,27 +654,29 @@ int main(int argc, char *argv[])
             (
                 meshProxy.mesh(),
                 set,
+                fmtType,
                 outputName,
-                fmtType
+                false // In parallel (later)
             );
-            continue;
+
+            shortCircuit = true;
         }
 
         // If pointSet: write pointSet only (as polydata)
         if (pointSetName.size())
         {
-            // Load the pointSet
+            // Load
             pointSet set(mesh, pointSetName);
 
             // Filename as if patch with same name.
-            mkDir(fvPath/set.name());
-
-            fileName outputName
+            const fileName outputName
             (
-                fvPath/set.name()/set.name()
-              + "_"
-              + timeDesc
+                fvPath/set.name()
+              / set.name() + "_" + timeDesc
             );
+
+            mkDir(outputName.path());
+
             Info<< "    pointSet  : "
                 << outputName.relative(runTime.path()) << nl;
 
@@ -679,9 +684,16 @@ int main(int argc, char *argv[])
             (
                 meshProxy.mesh(),
                 set,
+                fmtType,
                 outputName,
-                fmtType
+                false // In parallel (later)
             );
+
+            shortCircuit = true;
+        }
+
+        if (shortCircuit)
+        {
             continue;
         }
 
diff --git a/src/meshTools/Make/files b/src/meshTools/Make/files
index cf53f0e9268..e89cf987fcd 100644
--- a/src/meshTools/Make/files
+++ b/src/meshTools/Make/files
@@ -297,6 +297,8 @@ meshStructure/meshStructure.C
 meshStructure/topoDistanceData.C
 meshStructure/pointTopoDistanceData.C
 
+output/foamVtkIndPatchWriter.C
+output/foamVtkWriteTopoSet.C
 output/foamVtkWriteFaceSet.C
 output/foamVtkWritePointSet.C
 output/foamVtkWriteCellSetFaces.C
diff --git a/src/meshTools/output/foamVtkIndPatchWriter.C b/src/meshTools/output/foamVtkIndPatchWriter.C
new file mode 100644
index 00000000000..bf8adcf9fcc
--- /dev/null
+++ b/src/meshTools/output/foamVtkIndPatchWriter.C
@@ -0,0 +1,449 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 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 "foamVtkIndPatchWriter.H"
+#include "foamVtkOutput.H"
+#include "globalIndex.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::vtk::indirectPatchWriter::beginPiece()
+{
+    // Basic sizes
+    nLocalPoints_ = pp_.nPoints();
+    nLocalFaces_  = pp_.size();
+    nLocalVerts_  = 0;
+
+    for (const face& f : pp_)
+    {
+        nLocalVerts_ += f.size();
+    }
+
+    numberOfPoints_ = nLocalPoints_;
+    numberOfCells_  = nLocalFaces_;
+
+    if (parallel_)
+    {
+        reduce(numberOfPoints_, sumOp<label>());
+        reduce(numberOfCells_,  sumOp<label>());
+    }
+
+
+    // Nothing else to do for legacy
+    if (legacy()) return;
+
+    if (format_)
+    {
+        format().tag
+        (
+            vtk::fileTag::PIECE,
+            vtk::fileAttr::NUMBER_OF_POINTS, numberOfPoints_,
+            vtk::fileAttr::NUMBER_OF_POLYS,  numberOfCells_
+        );
+    }
+}
+
+
+void Foam::vtk::indirectPatchWriter::writePoints()
+{
+    if (format_)
+    {
+        if (legacy())
+        {
+            legacy::beginPoints(os_, numberOfPoints_);
+        }
+        else
+        {
+            const uint64_t payLoad = vtk::sizeofData<float, 3>(numberOfPoints_);
+
+            format()
+                .tag(vtk::fileTag::POINTS)
+                .beginDataArray<float,3>(vtk::dataArrayAttr::POINTS);
+
+            format().writeSize(payLoad);
+        }
+    }
+
+
+    if (parallel_ ? Pstream::master() : true)
+    {
+        {
+            vtk::writeList(format(), pp_.localPoints());
+        }
+    }
+
+
+    if (parallel_)
+    {
+        if (Pstream::master())
+        {
+            pointField recv;
+
+            // Receive each point field and write
+            for
+            (
+                int slave=Pstream::firstSlave();
+                slave<=Pstream::lastSlave();
+                ++slave
+            )
+            {
+                IPstream fromSlave(Pstream::commsTypes::blocking, slave);
+
+                {
+                    fromSlave >> recv;
+
+                    vtk::writeList(format(), recv);
+                }
+            }
+        }
+        else
+        {
+            // Send to master
+            OPstream toMaster
+            (
+                Pstream::commsTypes::blocking,
+                Pstream::masterNo()
+            );
+
+            {
+                toMaster << pp_.localPoints();
+            }
+        }
+    }
+
+
+    if (format_)
+    {
+        format().flush();
+        format().endDataArray();
+
+        if (!legacy())
+        {
+            format()
+                .endTag(vtk::fileTag::POINTS);
+        }
+    }
+}
+
+
+void Foam::vtk::indirectPatchWriter::writePolysLegacy
+(
+    const globalIndex& pointOffsets
+)
+{
+    // Connectivity count without additional storage (done internally)
+
+    label nFaces = nLocalFaces_;
+    label nVerts = nLocalVerts_;
+
+    if (parallel_)
+    {
+        reduce(nFaces, sumOp<label>());
+        reduce(nVerts, sumOp<label>());
+    }
+
+    if (nFaces != numberOfCells_)
+    {
+        FatalErrorInFunction
+            << "Expecting " << numberOfCells_
+            << " faces, but found " << nFaces
+            << exit(FatalError);
+    }
+
+    legacy::beginPolys(os_, nFaces, nVerts);
+
+    labelList vertLabels(nLocalFaces_ + nLocalVerts_);
+
+    {
+        // Legacy: size + connectivity together
+        // [nPts, id1, id2, ..., nPts, id1, id2, ...]
+
+        auto iter = vertLabels.begin();
+
+        label off = pointOffsets.localStart();
+
+        {
+            for (const face& f : pp_.localFaces())
+            {
+                *iter = f.size();       // The size prefix
+                ++iter;
+
+                for (const label pfi : f)
+                {
+                    *iter = pfi + off;  // Face vertex label
+                    ++iter;
+                }
+            }
+            off += pp_.nPoints();
+        }
+    }
+
+
+    if (parallel_)
+    {
+        vtk::writeListParallel(format_.ref(), vertLabels);
+    }
+    else
+    {
+        vtk::writeList(format(), vertLabels);
+    }
+
+    if (format_)
+    {
+        format().flush();
+    }
+}
+
+
+void Foam::vtk::indirectPatchWriter::writePolys
+(
+    const globalIndex& pointOffsets
+)
+{
+    if (format_)
+    {
+        format().tag(vtk::fileTag::POLYS);
+    }
+
+    //
+    // 'connectivity'
+    //
+    {
+        labelList vertLabels(nLocalVerts_);
+
+        label nVerts = nLocalVerts_;
+
+        if (parallel_)
+        {
+            reduce(nVerts, sumOp<label>());
+        }
+
+        if (format_)
+        {
+            const uint64_t payLoad = vtk::sizeofData<label>(nVerts);
+
+            format().beginDataArray<label>(vtk::dataArrayAttr::CONNECTIVITY);
+            format().writeSize(payLoad * sizeof(label));
+        }
+
+        {
+            // XML: connectivity only
+            // [id1, id2, ..., id1, id2, ...]
+
+            auto iter = vertLabels.begin();
+
+            label off = pointOffsets.localStart();
+
+            {
+                for (const face& f : pp_.localFaces())
+                {
+                    for (const label pfi : f)
+                    {
+                        *iter = pfi + off;  // Face vertex label
+                        ++iter;
+                    }
+                }
+                off += pp_.nPoints();
+            }
+        }
+
+
+        if (parallel_)
+        {
+            vtk::writeListParallel(format_.ref(), vertLabels);
+        }
+        else
+        {
+            vtk::writeList(format(), vertLabels);
+        }
+
+        if (format_)
+        {
+            format().flush();
+            format().endDataArray();
+        }
+    }
+
+
+    //
+    // 'offsets'  (connectivity offsets)
+    //
+    {
+        labelList vertOffsets(nLocalFaces_);
+        label nOffs = vertOffsets.size();
+
+        // global connectivity offsets
+        const globalIndex procOffset(nLocalVerts_);
+
+        if (parallel_)
+        {
+            reduce(nOffs, sumOp<label>());
+        }
+
+        if (format_)
+        {
+            const uint64_t payLoad = vtk::sizeofData<label>(nOffs);
+
+            format().beginDataArray<label>(vtk::dataArrayAttr::OFFSETS);
+            format().writeSize(payLoad);
+        }
+
+
+        label off = procOffset.localStart();
+
+        auto iter = vertOffsets.begin();
+
+        {
+            for (const face& f : pp_)
+            {
+                off += f.size();   // End offset
+                *iter = off;
+                ++iter;
+            }
+        }
+
+
+        if (parallel_)
+        {
+            vtk::writeListParallel(format_.ref(), vertOffsets);
+        }
+        else
+        {
+            vtk::writeList(format_.ref(), vertOffsets);
+        }
+
+
+        if (format_)
+        {
+            format().flush();
+            format().endDataArray();
+        }
+    }
+
+    if (format_)
+    {
+        format().endTag(vtk::fileTag::POLYS);
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::vtk::indirectPatchWriter::indirectPatchWriter
+(
+    const indirectPrimitivePatch& pp,
+    const vtk::outputOptions opts
+)
+:
+    vtk::fileWriter(vtk::fileTag::POLY_DATA, opts),
+    pp_(pp),
+    numberOfPoints_(0),
+    numberOfCells_(0),
+    nLocalPoints_(0),
+    nLocalFaces_(0),
+    nLocalVerts_(0)
+{
+    // We do not currently support append mode
+    opts_.append(false);
+}
+
+
+Foam::vtk::indirectPatchWriter::indirectPatchWriter
+(
+    const indirectPrimitivePatch& pp,
+    const fileName& file,
+    bool parallel
+)
+:
+    indirectPatchWriter(pp)
+{
+    open(file, parallel);
+}
+
+
+Foam::vtk::indirectPatchWriter::indirectPatchWriter
+(
+    const indirectPrimitivePatch& pp,
+    const vtk::outputOptions opts,
+    const fileName& file,
+    bool parallel
+)
+:
+    indirectPatchWriter(pp, opts)
+{
+    open(file, parallel);
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::vtk::indirectPatchWriter::beginFile(std::string title)
+{
+    if (title.size())
+    {
+        return vtk::fileWriter::beginFile(title);
+    }
+
+    // Provide default title
+    return vtk::fileWriter::beginFile("surfaces");
+}
+
+
+bool Foam::vtk::indirectPatchWriter::writeGeometry()
+{
+    enter_Piece();
+
+    beginPiece();
+
+    writePoints();
+
+    const globalIndex globalPointOffset(nLocalPoints_);
+
+    if (legacy())
+    {
+        writePolysLegacy(globalPointOffset);
+    }
+    else
+    {
+        writePolys(globalPointOffset);
+    }
+
+    return true;
+}
+
+
+bool Foam::vtk::indirectPatchWriter::beginCellData(label nFields)
+{
+    return enter_CellData(numberOfCells_, nFields);
+}
+
+
+bool Foam::vtk::indirectPatchWriter::beginPointData(label nFields)
+{
+    return enter_PointData(numberOfPoints_, nFields);
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/output/foamVtkIndPatchWriter.H b/src/meshTools/output/foamVtkIndPatchWriter.H
new file mode 100644
index 00000000000..c0e989dbf08
--- /dev/null
+++ b/src/meshTools/output/foamVtkIndPatchWriter.H
@@ -0,0 +1,222 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 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::indirectPatchWriter
+
+Description
+    Write indirectPrimitivePatch faces/points (optionally with fields)
+    as a vtp file or a legacy vtk file.
+
+    The file output states are managed by the Foam::vtk::fileWriter class.
+    FieldData (eg, TimeValue) must appear before any geometry pieces.
+
+Note
+    Parallel output is combined into a single Piece without point merging,
+    which is similar to using multi-piece data sets, but allows more
+    convenient creation as a streaming process.
+    In the future, the duplicate points at processor connections
+    may be addressed using ghost points.
+
+SourceFiles
+    foamVtkIndPatchWriter.C
+    foamVtkIndPatchWriterTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef foamVtkIndPatchWriter_H
+#define foamVtkIndPatchWriter_H
+
+#include "foamVtkFileWriter.H"
+#include "indirectPrimitivePatch.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declarations
+class globalIndex;
+
+namespace vtk
+{
+
+/*---------------------------------------------------------------------------*\
+                  Class vtk::indirectPatchWriter Declaration
+\*---------------------------------------------------------------------------*/
+
+class indirectPatchWriter
+:
+    public vtk::fileWriter
+{
+    // Private Member Data
+
+        //- Reference to the faces as an indirect patch
+        const indirectPrimitivePatch& pp_;
+
+        //- The numer of field points for the current Piece
+        label numberOfPoints_;
+
+        //- The numer of field cells (faces) for the current Piece
+        label numberOfCells_;
+
+        //- Local number of points
+        label nLocalPoints_;
+
+        //- Local number of faces
+        label nLocalFaces_;
+
+        //- Local face vertices (connectivity) count. Sum of face sizes.
+        label nLocalVerts_;
+
+
+    // Private Member Functions
+
+        //- Determing sizes (nLocalPoints_, nLocalFaces_, nLocalVerts_),
+        //- and begin piece
+        void beginPiece();
+
+        //- Write patch points
+        void writePoints();
+
+        //- Write patch faces, legacy format
+        void writePolysLegacy(const globalIndex& pointOffsets);
+
+        //- Write patch faces
+        void writePolys(const globalIndex& pointOffsets);
+
+
+        //- No copy construct
+        indirectPatchWriter(const indirectPatchWriter&) = delete;
+
+        //- No copy assignment
+        void operator=(const indirectPatchWriter&) = delete;
+
+
+public:
+
+    // Constructors
+
+        //- Construct from patch (default output INLINE_BASE64)
+        indirectPatchWriter
+        (
+            const indirectPrimitivePatch& pp,
+            const vtk::outputOptions opts = vtk::formatType::INLINE_BASE64
+        );
+
+        //- Construct from components (default output INLINE_BASE64),
+        //  and open the file for writing.
+        //  The file name is with/without an extension.
+        indirectPatchWriter
+        (
+            const indirectPrimitivePatch& pp,
+            const fileName& file,
+            bool parallel = Pstream::parRun()
+        );
+
+        //- Construct from components and open the file for writing.
+        //  The file name is with/without an extension.
+        indirectPatchWriter
+        (
+            const indirectPrimitivePatch& pp,
+            const vtk::outputOptions opts,
+            const fileName& file,
+            bool parallel = Pstream::parRun()
+        );
+
+
+    //- Destructor
+    virtual ~indirectPatchWriter() = default;
+
+
+    // Member Functions
+
+        //- File extension for current format type.
+        using vtk::fileWriter::ext;
+
+        //- File extension for given output type
+        inline static word ext(vtk::outputOptions opts)
+        {
+            return opts.ext(vtk::fileTag::POLY_DATA);
+        }
+
+        //- Reference to the indirect patch
+        inline const indirectPrimitivePatch& patch() const
+        {
+            return pp_;
+        }
+
+
+        //- Write file header (non-collective)
+        //  \note Expected calling states: (OPENED).
+        virtual bool beginFile(std::string title = "");
+
+        //- Write patch topology
+        //  Also writes the file header if not previously written.
+        //  \note Must be called prior to writing CellData or PointData
+        virtual bool writeGeometry();
+
+        //- Begin CellData output section for specified number of fields.
+        //  Must be called prior to writing any cell data fields.
+        //  \param nFields is for legacy format only.
+        //      When nFields=0, this a no-op for legacy format.
+        //  \note Expected calling states: (PIECE | POINT_DATA).
+        //
+        //  \return True if the state changed
+        virtual bool beginCellData(label nFields = 0);
+
+        //- Begin PointData for specified number of fields.
+        //  Must be called prior to writing any point data fields.
+        //  \param nFields is for legacy format only.
+        //      When nFields=0, this a no-op for legacy format.
+        //  \note Expected calling states: (PIECE | CELL_DATA).
+        //
+        //  \return True if the state changed
+        virtual bool beginPointData(label nFields = 0);
+
+
+    // Write
+
+        //- Write a list of Cell (Face) or Point values
+        template<class Type>
+        void write(const word& fieldName, const UList<Type>& field);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace vtk
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "foamVtkIndPatchWriterTemplates.C"
+#endif
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/output/foamVtkIndPatchWriterTemplates.C b/src/meshTools/output/foamVtkIndPatchWriterTemplates.C
new file mode 100644
index 00000000000..b0819afc183
--- /dev/null
+++ b/src/meshTools/output/foamVtkIndPatchWriterTemplates.C
@@ -0,0 +1,130 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 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/>.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class Type>
+void Foam::vtk::indirectPatchWriter::write
+(
+    const word& fieldName,
+    const UList<Type>& field
+)
+{
+    if (isState(outputState::CELL_DATA))
+    {
+        ++nCellData_;
+    }
+    else if (isState(outputState::POINT_DATA))
+    {
+        ++nPointData_;
+    }
+    else
+    {
+        FatalErrorInFunction
+            << "Bad writer state (" << stateNames[state_]
+            << ") - should be (" << stateNames[outputState::CELL_DATA]
+            << ") or (" << stateNames[outputState::POINT_DATA]
+            << ") for field " << fieldName << nl << endl
+            << exit(FatalError);
+    }
+
+    static_assert
+    (
+        (
+            std::is_same<typename pTraits<Type>::cmptType,label>::value
+         || std::is_floating_point<typename pTraits<Type>::cmptType>::value
+        ),
+        "Label and Floating-point vector space only"
+    );
+
+    const bool isLabel =
+        std::is_same<typename pTraits<Type>::cmptType(), label>::value;
+
+
+    const direction nCmpt(pTraits<Type>::nComponents);
+
+    label nValues = field.size();
+
+    // Could check sizes:
+    //     nValues == nLocalFaces (CELL_DATA)
+    //     nValues == nLocalPoints (POINT_DATA)
+
+    if (parallel_)
+    {
+        reduce(nValues, sumOp<label>());
+    }
+
+    if (format_)
+    {
+        if (isLabel)
+        {
+            if (legacy())
+            {
+                legacy::intField<nCmpt>(format(), fieldName, nValues);
+            }
+            else
+            {
+                const uint64_t payLoad = vtk::sizeofData<label, nCmpt>(nValues);
+
+                format().beginDataArray<label, nCmpt>(fieldName);
+                format().writeSize(payLoad);
+            }
+        }
+        else
+        {
+            if (legacy())
+            {
+                legacy::floatField<nCmpt>(format(), fieldName, nValues);
+            }
+            else
+            {
+                const uint64_t payLoad = vtk::sizeofData<float, nCmpt>(nValues);
+
+                format().beginDataArray<float, nCmpt>(fieldName);
+                format().writeSize(payLoad);
+            }
+        }
+    }
+
+
+    if (parallel_)
+    {
+        vtk::writeListParallel(format_.ref(), field);
+    }
+    else
+    {
+        vtk::writeList(format(), field);
+    }
+
+
+    if (format_)
+    {
+        format().flush();
+        format().endDataArray();
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/output/foamVtkWriteCellSetFaces.C b/src/meshTools/output/foamVtkWriteCellSetFaces.C
index 38bc7d107d0..09227deb246 100644
--- a/src/meshTools/output/foamVtkWriteCellSetFaces.C
+++ b/src/meshTools/output/foamVtkWriteCellSetFaces.C
@@ -2,8 +2,8 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2017-2018 OpenCFD Ltd.
+     \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -23,36 +23,34 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "foamVtkWriteCellSetFaces.H"
-#include "foamVtkOutputOptions.H"
-#include "OFstream.H"
-#include "primitiveMesh.H"
+#include "foamVtkWriteTopoSet.H"
+#include "foamVtkIndPatchWriter.H"
+#include "polyMesh.H"
 #include "cellSet.H"
-#include "uindirectPrimitivePatch.H"
+#include "globalIndex.H"
 
 // * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
 
-void Foam::vtk::writeCellSetFaces
+bool Foam::vtk::writeCellSetFaces
 (
-    const primitiveMesh& mesh,
+    const polyMesh& mesh,
     const cellSet& set,
-    const fileName& baseName,
-    const vtk::outputOptions outOpts
+    const vtk::outputOptions opts,
+    const fileName& file,
+    bool parallel
 )
 {
-    outputOptions opts(outOpts);
-    opts.legacy(true);  // Legacy only, no xml, no append
+    typedef IndirectList<face> FaceListType;
 
-    const bool legacy_(opts.legacy());
+    const globalIndex cellIdOffset(mesh.nCells());
 
-    std::ofstream os(baseName + (legacy_ ? ".vtk" : ".vtp"));
-
-    autoPtr<vtk::formatter> format = opts.newFormatter(os);
+    indirectPrimitivePatch pp
+    (
+        FaceListType(mesh.faces(), labelList()),
+        mesh.points()
+    );
+    FaceListType& faces = pp;
 
-    if (legacy_)
-    {
-        legacy::fileHeader(format(), set.name(), vtk::fileTag::POLY_DATA);
-    }
 
     //-------------------------------------------------------------------------
 
@@ -87,57 +85,48 @@ void Foam::vtk::writeCellSetFaces
         }
     }
 
-    const labelList faceLabels(cellFaces.sortedToc());
-    labelList faceValues(cellFaces.size());
+    // Use these faces
+    faces.resetAddressing(cellFaces.sortedToc());
 
-    forAll(faceLabels, facei)
+    // For each face, the corresponding cellID
+
+    labelList faceValues(faces.size());
+
+    // Cell ID
     {
-        faceValues[facei] = cellFaces[faceLabels[facei]];  // Cell ID
-    }
+        const labelList& faceIds = faces.addressing();
 
-    uindirectPrimitivePatch pp
-    (
-        UIndirectList<face>(mesh.faces(), faceLabels),
-        mesh.points()
-    );
+        const label off = cellIdOffset.localStart();
+
+        forAll(faceValues, facei)
+        {
+            faceValues[facei] = cellFaces[faceIds[facei]] + off;
+        }
+    }
 
     //-------------------------------------------------------------------------
 
-    // Write points and faces as polygons
-    legacy::beginPoints(os, pp.nPoints());
+    indirectPatchWriter writer(pp, opts);
 
-    vtk::writeList(format(), pp.localPoints());
-    format().flush();
+    writer.open(file, parallel);
 
-    // connectivity count without additional storage (done internally)
-    uint64_t nConnectivity = 0;
-    forAll(pp, facei)
-    {
-        nConnectivity += pp[facei].size();
-    }
-
-    legacy::beginPolys(os, pp.size(), nConnectivity);
+    writer.beginFile(set.name());
+    writer.writeGeometry();
 
+    //-------------------------------------------------------------------------
 
-    // legacy: size + connectivity together
-    // [nPts, id1, id2, ..., nPts, id1, id2, ...]
-    forAll(pp, facei)
+    // CellData - cellID only
     {
-        const face& f = pp.localFaces()[facei];
+        writer.beginCellData(1);
 
-        format().write(f.size());  // The size prefix
-        vtk::writeList(format(), f);
-    }
-    format().flush();
+        writer.write("faceID", faceValues);
 
+        // End CellData/PointData is implicit
+    }
 
-    // Write data - faceId/cellId
-    legacy::beginCellData(format(), pp.size(), 1);
-
-    os << "cellID 1 " << pp.size() << " int" << nl;
+    writer.close();
 
-    vtk::writeList(format(), faceValues);
-    format().flush();
+    return true;
 }
 
 
diff --git a/src/meshTools/output/foamVtkWriteFaceSet.C b/src/meshTools/output/foamVtkWriteFaceSet.C
index cfe8a5e895d..28003c9be23 100644
--- a/src/meshTools/output/foamVtkWriteFaceSet.C
+++ b/src/meshTools/output/foamVtkWriteFaceSet.C
@@ -2,8 +2,8 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2017-2018 OpenCFD Ltd.
+     \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -23,85 +23,62 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "foamVtkWriteFaceSet.H"
-#include "foamVtkOutputOptions.H"
-#include "OFstream.H"
-#include "primitiveMesh.H"
+#include "foamVtkWriteTopoSet.H"
+#include "foamVtkIndPatchWriter.H"
+#include "polyMesh.H"
 #include "faceSet.H"
-#include "uindirectPrimitivePatch.H"
+#include "globalIndex.H"
 
 // * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
 
-void Foam::vtk::writeFaceSet
+bool Foam::vtk::writeFaceSet
 (
-    const primitiveMesh& mesh,
+    const polyMesh& mesh,
     const faceSet& set,
-    const fileName& baseName,
-    const vtk::outputOptions outOpts
+    const vtk::outputOptions opts,
+    const fileName& file,
+    bool parallel
 )
 {
-    outputOptions opts(outOpts);
-    opts.legacy(true);  // Legacy only, no xml, no append
+    typedef IndirectList<face> FaceListType;
 
-    const bool legacy_(opts.legacy());
+    const globalIndex faceIdOffset(mesh.nFaces());
 
-    std::ofstream os(baseName + (legacy_ ? ".vtk" : ".vtp"));
-
-    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
+    indirectPrimitivePatch pp
     (
-        UIndirectList<face>(mesh.faces(), faceLabels),
+        FaceListType(mesh.faces(), labelList()),
         mesh.points()
     );
+    FaceListType& faces = pp;
+
+    // Use the faces from faceSet
+    faces.resetAddressing(set.sortedToc());
 
     //-------------------------------------------------------------------------
 
-    // Write points and faces as polygons
-    legacy::beginPoints(os, pp.nPoints());
+    indirectPatchWriter writer(pp, opts);
 
-    vtk::writeList(format(), pp.localPoints());
-    format().flush();
+    writer.open(file, parallel);
 
-    // connectivity count without additional storage (done internally)
-    uint64_t nConnectivity = 0;
-    forAll(pp, facei)
-    {
-        nConnectivity += pp[facei].size();
-    }
-    legacy::beginPolys(os, pp.size(), nConnectivity);
+    writer.beginFile(set.name());
+    writer.writeGeometry();
 
 
-    // legacy: size + connectivity together
-    // [nPts, id1, id2, ..., nPts, id1, id2, ...]
-    forAll(pp, facei)
+    // CellData - faceID only
     {
-        const face& f = pp.localFaces()[facei];
-
-        format().write(f.size());  // The size prefix
-        vtk::writeList(format(), f);
-    }
-    format().flush();
+        writer.beginCellData(1);
 
+        labelField faceValues(faces.addressing());
+        faceValues += faceIdOffset.localStart();
 
-    // Write data - faceId/cellId
+        writer.write("faceID", faceValues);
 
-    legacy::beginCellData(format(), pp.size(), 1);
+        // End CellData/PointData is implicit
+    }
 
-    os << "faceID 1 " << pp.size() << " int" << nl;
+    writer.close();
 
-    vtk::writeList(format(), faceLabels);
-    format().flush();
+    return true;
 }
 
 
diff --git a/src/meshTools/output/foamVtkWritePointSet.C b/src/meshTools/output/foamVtkWritePointSet.C
index e2283599462..1952c3a2fc4 100644
--- a/src/meshTools/output/foamVtkWritePointSet.C
+++ b/src/meshTools/output/foamVtkWritePointSet.C
@@ -2,8 +2,8 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2017-2018 OpenCFD Ltd.
+     \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -23,53 +23,209 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "foamVtkWritePointSet.H"
-#include "foamVtkOutputOptions.H"
-#include "OFstream.H"
-#include "primitiveMesh.H"
+#include <fstream>
+#include "foamVtkWriteTopoSet.H"
+#include "polyMesh.H"
 #include "pointSet.H"
+#include "globalIndex.H"
+#include "OSspecific.H"
 
 // * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
 
-void Foam::vtk::writePointSet
+bool Foam::vtk::writePointSet
 (
-    const primitiveMesh& mesh,
+    const polyMesh& mesh,
     const pointSet& set,
-    const fileName& baseName,
-    const vtk::outputOptions outOpts
+    const vtk::outputOptions opts,
+    const fileName& file,
+    bool parallel
 )
 {
-    outputOptions opts(outOpts);
-    opts.legacy(true);  // Legacy only, no xml, no append
+    vtk::outputOptions opts_(opts);
+    opts_.append(false);  // Do not support append
 
-    const bool legacy_(opts.legacy());
+    const bool legacy = opts_.legacy();
 
-    std::ofstream os(baseName + (legacy_ ? ".vtk" : ".vtp"));
+    // Only allow parallel if really is a parallel run.
+    parallel = parallel && Pstream::parRun();
 
-    autoPtr<vtk::formatter> format = opts.newFormatter(os);
 
-    if (legacy_)
+    std::ofstream os_;
+    autoPtr<vtk::formatter> format;
+
+    // Open a file and attach a formatter
+    // - on master (always)
+    // - on slave if not parallel
+    //
+    // This means we can always check if format_ is defined to know if output
+    // is desired on any particular process.
+
+    if (Pstream::master() || !parallel)
+    {
+        mkDir(file.path());
+
+        // Extension is inappropriate. Legacy instead of xml, or vice versa.
+        const word ext = vtk::fileExtension[vtk::fileTag::POLY_DATA];
+
+        if (file.hasExt(ext))
+        {
+            // Extension is correct
+            os_.open(file);
+        }
+        else if
+        (
+            legacy
+          ? file.hasExt(ext)
+          : file.hasExt(vtk::legacy::fileExtension)
+        )
+        {
+            // Extension is inappropriate. Legacy instead of xml, or vice versa.
+            os_.open(file.lessExt() + "." + ext);
+        }
+        else
+        {
+            // Extension added automatically
+            os_.open(file + "." + ext);
+        }
+
+        format = opts_.newFormatter(os_);
+    }
+
+
+    //-------------------------------------------------------------------------
+
+    const globalIndex pointIdOffset(mesh.nPoints());
+
+    labelField pointLabels(set.sortedToc());
+
+    label numberOfPoints = pointLabels.size();
+
+    if (parallel)
     {
-        legacy::fileHeader(format(), set.name(), vtk::fileTag::POLY_DATA);
+        reduce(numberOfPoints, sumOp<label>());
+    }
+
+    if (format)
+    {
+        const auto& title = set.name();
+
+        if (legacy)
+        {
+            // beginFile:
+
+            legacy::fileHeader<vtk::fileTag::POLY_DATA>(format(), title);
+
+            // beginPoints:
+
+            legacy::beginPoints(os_, numberOfPoints);
+        }
+        else
+        {
+            // XML (inline)
+
+            // beginFile:
+
+            format()
+                .xmlHeader()
+                .xmlComment(title)
+                .beginVTKFile<vtk::fileTag::POLY_DATA>();
+
+            // beginPiece:
+            format()
+                .tag
+                (
+                    vtk::fileTag::PIECE,
+                    vtk::fileAttr::NUMBER_OF_POINTS, numberOfPoints
+                );
+
+            // beginPoints:
+            const uint64_t payLoad = vtk::sizeofData<float,3>(numberOfPoints);
+
+            format()
+                .tag(vtk::fileTag::POINTS)
+                .beginDataArray<float,3>(vtk::dataArrayAttr::POINTS);
+            format().writeSize(payLoad);
+        }
     }
 
+
     //-------------------------------------------------------------------------
 
-    const labelList pointLabels(set.sortedToc());
+    // pointLabels are the addressing for an indirect list
 
-    // Write points
-    legacy::beginPoints(os, pointLabels.size());
+    if (parallel)
+    {
+        vtk::writeListParallel(format(), mesh.points(), pointLabels);
+    }
+    else
+    {
+        vtk::writeList(format(), mesh.points(), pointLabels);
+    }
 
-    vtk::writeList(format(), mesh.points(), pointLabels);
-    format().flush();
+    if (format)
+    {
+        format().flush();
+        format().endDataArray();
+
+        if (!legacy)
+        {
+            format()
+                .endTag(vtk::fileTag::POINTS);
+        }
+
+
+        // beginPointData:
+        if (legacy)
+        {
+            legacy::beginPointData(format(), numberOfPoints, 1); // 1 field
+        }
+        else
+        {
+            format().beginPointData();
+        }
+    }
 
-    // Write data - pointID
-    legacy::beginPointData(format(), pointLabels.size(), 1);
+    if (format)
+    {
+        // pointID
+
+        if (legacy)
+        {
+            // 1 component
+            legacy::intField<1>(format(), "pointID", numberOfPoints);
+        }
+        else
+        {
+            const uint64_t payLoad = vtk::sizeofData<label>(numberOfPoints);
+
+            format().beginDataArray<label>("pointID");
+            format().writeSize(payLoad);
+        }
+    }
 
-    os << "pointID 1 " << pointLabels.size() << " int" << nl;
 
-    vtk::writeList(format(), pointLabels);
-    format().flush();
+    if (parallel)
+    {
+        vtk::writeListParallel(format.ref(), pointLabels, pointIdOffset);
+    }
+    else
+    {
+        vtk::writeList(format(), pointLabels);
+    }
+
+
+    if (format)
+    {
+        format().flush();
+        format().endDataArray();
+        format().endPointData();
+        format().endPiece();
+
+        format().endTag(vtk::fileTag::POLY_DATA)
+            .endVTKFile();
+    }
+
+    return true;
 }
 
 
diff --git a/src/meshTools/output/foamVtkWritePointSet.H b/src/meshTools/output/foamVtkWritePointSet.H
deleted file mode 100644
index 576f2ccb4d1..00000000000
--- a/src/meshTools/output/foamVtkWritePointSet.H
+++ /dev/null
@@ -1,73 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  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/>.
-
-InNamespace
-    Foam::vtk
-
-Description
-    Write pointSet to vtk polydata file.
-    The data are the original point ids.
-
-SourceFiles
-    foamVtkWritePointSet.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef foamVtkWritePointSet_H
-#define foamVtkWritePointSet_H
-
-#include "foamVtkOutputOptions.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-// Forward declarations
-class primitiveMesh;
-class pointSet;
-class fileName;
-
-namespace vtk
-{
-
-//- Write pointSet to vtk polydata file.
-//  The data are the original point ids.
-void writePointSet
-(
-    const primitiveMesh& mesh,
-    const pointSet& set,
-    const fileName& baseName,
-    const vtk::outputOptions outOpts
-);
-
-
-} // End namespace vtk
-} // End namespace Foam
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/src/meshTools/output/foamVtkWriteFaceSet.H b/src/meshTools/output/foamVtkWriteTopoSet.C
similarity index 51%
rename from src/meshTools/output/foamVtkWriteFaceSet.H
rename to src/meshTools/output/foamVtkWriteTopoSet.C
index d556c91bdb7..b4f433d148f 100644
--- a/src/meshTools/output/foamVtkWriteFaceSet.H
+++ b/src/meshTools/output/foamVtkWriteTopoSet.C
@@ -2,8 +2,8 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2018 OpenCFD Ltd.
+     \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -21,53 +21,65 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
-InNamespace
-    Foam::vtk
-
-Description
-    Write faceSet to vtk polydata file.
-    The data are the mesh face ids.
-
-SourceFiles
-    foamVtkWritePointSet.C
-
 \*---------------------------------------------------------------------------*/
 
-#ifndef foamVtkWriteFaceSet_H
-#define foamVtkWriteFaceSet_H
-
-#include "foamVtkOutputOptions.H"
+#include "foamVtkWriteTopoSet.H"
+#include "polyMesh.H"
+#include "topoSet.H"
+#include "faceSet.H"
+#include "cellSet.H"
+#include "pointSet.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-namespace Foam
-{
-
-// Forward declarations
-class primitiveMesh;
-class faceSet;
-class fileName;
-
-namespace vtk
-{
-
-//- Write faceSet to vtk polydata file.
-//  Only one data which is original pointID.
-void writeFaceSet
+bool Foam::vtk::writeTopoSet
 (
-    const primitiveMesh& mesh,
-    const faceSet& set,
-    const fileName& baseName,
-    const vtk::outputOptions outOpts
-);
-
-
-} // End namespace vtk
-} // End namespace Foam
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+    const polyMesh& mesh,
+    const topoSet& set,
+    const vtk::outputOptions opts,
+    const fileName& file,
+    bool parallel
+)
+{
+    if (isA<pointSet>(set))
+    {
+        return vtk::writePointSet
+        (
+            mesh,
+            dynamicCast<const pointSet&>(set),
+            opts,
+            file,
+            parallel
+        );
+    }
+    else if (isA<faceSet>(set))
+    {
+        return vtk::writeFaceSet
+        (
+            mesh,
+            dynamicCast<const faceSet&>(set),
+            opts,
+            file,
+            parallel
+        );
+    }
+    else if (isA<cellSet>(set))
+    {
+        return vtk::writeCellSetFaces
+        (
+            mesh,
+            dynamicCast<const cellSet&>(set),
+            opts,
+            file,
+            parallel
+        );
+    }
+
+    WarningInFunction
+        << "No VTK writer for '" << set.type() << "' topoSet" << nl << endl;
+
+    return false;
+}
 
-#endif
 
 // ************************************************************************* //
diff --git a/src/meshTools/output/foamVtkWriteCellSetFaces.H b/src/meshTools/output/foamVtkWriteTopoSet.H
similarity index 52%
rename from src/meshTools/output/foamVtkWriteCellSetFaces.H
rename to src/meshTools/output/foamVtkWriteTopoSet.H
index e4d15efc9e2..0e4c07a09ae 100644
--- a/src/meshTools/output/foamVtkWriteCellSetFaces.H
+++ b/src/meshTools/output/foamVtkWriteTopoSet.H
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2017-2018 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -25,20 +25,21 @@ InNamespace
     Foam::vtk
 
 Description
-    Write faces of cellSet to vtk polydata file.
-
-    The data are the original cell ids
+    Write topoSet in VTK format
 
 SourceFiles
+    foamVtkWriteTopoSet.C
     foamVtkWriteCellSetFaces.C
+    foamVtkWriteFaceSet.C
+    foamVtkWritePointSet.C
 
 \*---------------------------------------------------------------------------*/
 
 #ifndef foamVtkWriteCellSetFaces_H
 #define foamVtkWriteCellSetFaces_H
 
-#include "primitiveMesh.H"
-#include "uindirectPrimitivePatch.H"
+#include "fileName.H"
+#include "UPstream.H"
 #include "foamVtkOutputOptions.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -47,27 +48,74 @@ namespace Foam
 {
 
 // Forward declarations
-class primitiveMesh;
+class polyMesh;
+class topoSet;
+class faceSet;
 class cellSet;
-class fileName;
+class pointSet;
 
 namespace vtk
 {
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+//- Dispatch to vtk::writeCellSetFaces, vtk::writeFaceSet, vtk::writePointSet
+//  The file name is with/without an extension.
+//  \return True on successful dispatch
+bool writeTopoSet
+(
+    const polyMesh& mesh,
+    const topoSet& set,
+    const vtk::outputOptions opts,
+    const fileName& file,
+    bool parallel = Pstream::parRun()
+);
+
+
+//- Write faceSet as VTK polydata file.
+//  Only one CELL_DATA, which is the original faceID
+//  The file name is with/without an extension.
+bool writeFaceSet
+(
+    const polyMesh& mesh,
+    const faceSet& set,
+    const vtk::outputOptions opts,
+    const fileName& file,
+    bool parallel = Pstream::parRun()
+);
+
+
 //- Write perimeter faces of cellset to vtk polydata file.
 //  The data are the original cell ids
-void writeCellSetFaces
+//  The file name is with/without an extension.
+bool writeCellSetFaces
 (
-    const primitiveMesh& mesh,
+    const polyMesh& mesh,
     const cellSet& set,
-    const fileName& baseName,
-    const vtk::outputOptions outOpts
+    const vtk::outputOptions opts,
+    const fileName& file,
+    bool parallel = Pstream::parRun()
+);
+
+
+//- Write pointSet to VTK polydata file.
+//  Only one CELL_DATA, which is the original pointID
+//  The file name is with/without an extension.
+bool writePointSet
+(
+    const polyMesh& mesh,
+    const pointSet& set,
+    const vtk::outputOptions opts,
+    const fileName& file,
+    bool parallel = Pstream::parRun()
 );
 
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 } // End namespace vtk
 } // End namespace Foam
 
-
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 #endif
-- 
GitLab