Commit 0d2dbaf6 authored by Mark Olesen's avatar Mark Olesen
Browse files

ENH: parallel and xml output for vtk topoSet writers (issue #926)

- introduce lower-level vtk::indirectPatchWriter class
parent 0e47b071
......@@ -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)
......
......@@ -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;
}
......
......@@ -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
......
/*---------------------------------------------------------------------------*\
========= |
\\ / 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,