ENH: parallel output for vtk::patchWriter (issue #926)

This commit is contained in:
Mark Olesen
2018-09-10 18:28:55 +02:00
parent e7b77c0af6
commit 1adac97150
3 changed files with 965 additions and 423 deletions

View File

@ -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-2017 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -25,19 +25,53 @@ License
#include "foamVtkPatchWriter.H"
#include "foamVtkOutput.H"
#include "globalIndex.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::vtk::patchWriter::beginPiece()
{
if (!legacy_)
// Basic sizes
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
nLocalPoints_ = nLocalFaces_ = nLocalVerts_ = 0;
for (const label patchId : patchIDs_)
{
const polyPatch& pp = patches[patchId];
nLocalPoints_ += pp.nPoints();
nLocalFaces_ += pp.size();
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()
.openTag(vtk::fileTag::PIECE)
.xmlAttr(vtk::fileAttr::NUMBER_OF_POINTS, nPoints_)
.xmlAttr(vtk::fileAttr::NUMBER_OF_POLYS, nFaces_)
.closeTag();
.tag
(
vtk::fileTag::PIECE,
vtk::fileAttr::NUMBER_OF_POINTS, numberOfPoints_,
vtk::fileAttr::NUMBER_OF_POLYS, numberOfCells_
);
}
}
@ -46,135 +80,244 @@ void Foam::vtk::patchWriter::writePoints()
{
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
const uint64_t payLoad = (nPoints_*3*sizeof(float));
if (legacy_)
if (format_)
{
legacy::beginPoints(os_, nPoints_);
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)
{
for (const label patchId : patchIDs_)
{
const polyPatch& pp = patches[patchId];
vtk::writeList(format(), pp.localPoints());
}
}
if (parallel_)
{
// Patch Ids are identical across all processes
const label nPatches = patchIDs_.size();
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);
for (label i=0; i < nPatches; ++i)
{
fromSlave >> recv;
vtk::writeList(format(), recv);
}
}
}
else
{
// Send each point field to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
for (const label patchId : patchIDs_)
{
const polyPatch& pp = patches[patchId];
toMaster << pp.localPoints();
}
}
}
if (format_)
{
format().flush();
format().endDataArray();
if (!legacy())
{
format()
.endTag(vtk::fileTag::POINTS);
}
}
}
void Foam::vtk::patchWriter::writePolysLegacy
(
const globalIndex& pointOffsets
)
{
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
// 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 label patchId : patchIDs_)
{
const polyPatch& pp = patches[patchId];
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
{
format().tag(vtk::fileTag::POINTS)
.openDataArray<float, 3>(vtk::dataArrayAttr::POINTS)
.closeTag();
vtk::writeList(format(), vertLabels);
}
format().writeSize(payLoad);
for (const label patchId : patchIDs_)
if (format_)
{
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();
void Foam::vtk::patchWriter::writePolys
(
const globalIndex& pointOffsets
)
{
if (format_)
{
format().tag(vtk::fileTag::POLYS);
}
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
//
// '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);
}
{
// XML: connectivity only
// [id1, id2, ..., id1, id2, ...]
auto iter = vertLabels.begin();
label off = pointOffsets.localStart();
for (const label patchId : patchIDs_)
{
const polyPatch& pp = patches[patchId];
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();
}
}
@ -182,44 +325,64 @@ void Foam::vtk::patchWriter::writePolys()
// 'offsets' (connectivity offsets)
//
{
format()
.openDataArray<label>(vtk::dataArrayAttr::OFFSETS)
.closeTag();
labelList vertOffsets(nLocalFaces_);
label nOffs = vertOffsets.size();
// payload size
format().writeSize(nFaces_ * sizeof(label));
// 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();
label off = 0;
for (const label patchId : patchIDs_)
{
const polyPatch& pp = patches[patchId];
forAll(pp, facei)
for (const face& f : pp)
{
off += pp[facei].size();
format().write(off);
off += f.size(); // End offset
*iter = off;
++iter;
}
}
format().flush();
format().endDataArray();
if (parallel_)
{
vtk::writeListParallel(format_.ref(), vertOffsets);
}
else
{
vtk::writeList(format_.ref(), vertOffsets);
}
if (format_)
{
format().flush();
format().endDataArray();
}
}
format().endTag(vtk::fileTag::POLYS);
}
void Foam::vtk::patchWriter::writeMesh()
{
writePoints();
if (legacy_)
if (format_)
{
writePolysLegacy();
}
else
{
writePolys();
format().endTag(vtk::fileTag::POLYS);
}
}
@ -229,161 +392,273 @@ void Foam::vtk::patchWriter::writeMesh()
Foam::vtk::patchWriter::patchWriter
(
const fvMesh& mesh,
const fileName& baseName,
const vtk::outputOptions outOpts,
const bool nearCellValue,
const labelList& patchIDs
const labelList& patchIDs,
const vtk::outputOptions opts,
const bool useNearCellValue
)
:
vtk::fileWriter(vtk::fileTag::POLY_DATA, opts),
mesh_(mesh),
legacy_(outOpts.legacy()),
format_(),
nearCellValue_(nearCellValue),
patchIDs_(patchIDs),
os_(),
nPoints_(0),
nFaces_(0)
useNearCellValue_(useNearCellValue),
numberOfPoints_(0),
numberOfCells_(0),
nLocalPoints_(0),
nLocalFaces_(0),
nLocalVerts_(0)
{
outputOptions opts(outOpts);
opts.append(false); // No append supported
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();
// We do not currently support append mode
opts_.append(false);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::vtk::patchWriter::patchWriter
(
const fvMesh& mesh,
const labelList& patchIDs,
const fileName& file,
bool parallel
)
:
patchWriter(mesh, patchIDs)
{
open(file, parallel);
}
Foam::vtk::patchWriter::~patchWriter()
{}
Foam::vtk::patchWriter::patchWriter
(
const fvMesh& mesh,
const labelList& patchIDs,
const vtk::outputOptions opts,
const fileName& file,
bool parallel
)
:
patchWriter(mesh, patchIDs, opts)
{
open(file, parallel);
}
Foam::vtk::patchWriter::patchWriter
(
const fvMesh& mesh,
const labelList& patchIDs,
const vtk::outputOptions opts,
const bool useNearCellValue,
const fileName& file,
bool parallel
)
:
patchWriter(mesh, patchIDs, opts, useNearCellValue)
{
open(file, parallel);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::vtk::patchWriter::beginCellData(label nFields)
bool Foam::vtk::patchWriter::beginFile(std::string title)
{
if (legacy_)
if (title.size())
{
legacy::beginCellData(format(), nFaces_, nFields);
return vtk::fileWriter::beginFile(title);
}
// Provide default title
if (legacy())
{
title =
(
patchIDs_.size() == 1
? mesh_.boundaryMesh()[patchIDs_.first()].name()
: "patches"
);
return vtk::fileWriter::beginFile(title);
}
// XML (inline)
if (patchIDs_.size() == 1)
{
title =
(
"patch='" + mesh_.boundaryMesh()[patchIDs_.first()].name() + "'"
);
}
else
{
format().beginCellData();
title =
(
"npatches='" + Foam::name(patchIDs_.size()) + "'"
);
}
title +=
(
" time='" + mesh_.time().timeName()
+ "' index='" + Foam::name(mesh_.time().timeIndex())
+ "'"
);
return vtk::fileWriter::beginFile(title);
}
void Foam::vtk::patchWriter::endCellData()
bool Foam::vtk::patchWriter::writeGeometry()
{
if (!legacy_)
{
format().endCellData();
}
}
enter_Piece();
beginPiece();
void Foam::vtk::patchWriter::beginPointData(label nFields)
{
if (legacy_)
writePoints();
const globalIndex globalPointOffset(nLocalPoints_);
if (legacy())
{
legacy::beginPointData(format(), nPoints_, nFields);
writePolysLegacy(globalPointOffset);
}
else
{
format().beginPointData();
writePolys(globalPointOffset);
}
return true;
}
void Foam::vtk::patchWriter::endPointData()
bool Foam::vtk::patchWriter::beginCellData(label nFields)
{
if (!legacy_)
{
format().endPointData();
}
return enter_CellData(numberOfCells_, nFields);
}
void Foam::vtk::patchWriter::writeFooter()
bool Foam::vtk::patchWriter::beginPointData(label nFields)
{
if (!legacy_)
{
// slight cheat. </Piece> too
format().endTag(vtk::fileTag::PIECE);
format().endTag(vtk::fileTag::POLY_DATA)
.endVTKFile();
}
return enter_PointData(numberOfPoints_, nFields);
}
void Foam::vtk::patchWriter::writePatchIDs()
{
// Patch ids first
const uint64_t payLoad = nFaces_ * sizeof(label);
if (legacy_)
if (isState(outputState::CELL_DATA))
{
legacy::intField<1>(format(), "patchID", nFaces_); // 1 component
++nCellData_;
}
else
{
format().openDataArray<label>("patchID")
.closeTag();
FatalErrorInFunction
<< "Bad writer state (" << stateNames[state_]
<< ") - should be (" << stateNames[outputState::CELL_DATA]
<< ") for patchID field" << nl << endl
<< exit(FatalError);
}
format().writeSize(payLoad);
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
for (const label patchId : patchIDs_)
label nFaces = nLocalFaces_;
if (parallel_)
{
const label sz = mesh_.boundaryMesh()[patchId].size();
reduce(nFaces, sumOp<label>());
}
for (label facei = 0; facei < sz; ++facei)
if (format_)
{
if (legacy())
{
format().write(patchId);
legacy::intField<1>(format(), "patchID", nFaces); // 1 component
}
else
{
const uint64_t payLoad =
vtk::sizeofData<label>(nFaces);
format().beginDataArray<label>("patchID");
format().writeSize(payLoad);
}
}
format().flush();
if (!legacy_)
if (parallel_ ? Pstream::master() : true)
{
for (const label patchId : patchIDs_)
{
label count = patches[patchId].size();
const label val = patchId;
while (count--)
{
format().write(val);
}
}
}
if (parallel_)
{
if (Pstream::master())
{
labelList recv;
// Receive each pair
for
(
int slave=Pstream::firstSlave();
slave<=Pstream::lastSlave();
++slave
)
{
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
fromSlave >> recv;
for (label i=0; i < recv.size(); ++i)
{
label count = recv[i];
++i;
const label val = recv[i];
while (count--)
{
format().write(val);
}
}
}
}
else
{
// Send to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
labelList send(2*patchIDs_.size());
// Encode as [size, id] pairs
label i = 0;
for (const label patchId : patchIDs_)
{
send[i] = patches[patchId].size();
send[i+1] = patchId;
i += 2;
}
toMaster << send;
}
}
if (format_)
{
format().flush();
format().endDataArray();
}
}

View File

@ -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-2017 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -25,7 +25,17 @@ Class
Foam::vtk::patchWriter
Description
Write patch fields
Write OpenFOAM patches and patch fields in VTP or legacy vtk format.
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
foamVtkPatchWriter.C
@ -36,66 +46,71 @@ SourceFiles
#ifndef foamVtkPatchWriter_H
#define foamVtkPatchWriter_H
#include "pointMesh.H"
#include "OFstream.H"
#include "foamVtkFileWriter.H"
#include "volFields.H"
#include "pointFields.H"
#include "indirectPrimitivePatch.H"
#include "PrimitivePatchInterpolation.H"
#include "foamVtkOutputOptions.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
class volPointInterpolation;
// Forward declarations
class globalIndex;
namespace vtk
{
/*---------------------------------------------------------------------------*\
Class patchWriter Declaration
Class vtk::patchWriter Declaration
\*---------------------------------------------------------------------------*/
class patchWriter
:
public vtk::fileWriter
{
// Private Member Data
//- Reference to the OpenFOAM mesh (or subset)
const fvMesh& mesh_;
//- Commonly used query
const bool legacy_;
//- The selected patch ids
labelList patchIDs_;
autoPtr<vtk::formatter> format_;
//- Use internal field value instead of patch value
bool useNearCellValue_;
const bool nearCellValue_;
//- The numer of field points for the current Piece
label numberOfPoints_;
const labelList patchIDs_;
//- The numer of field cells (faces) for the current Piece
label numberOfCells_;
std::ofstream os_;
//- Local number of points
label nLocalPoints_;
label nPoints_;
//- Local number of faces
label nLocalFaces_;
label nFaces_;
//- Local face vertices (connectivity) count. Sum of face sizes.
label nLocalVerts_;
// Private Member Functions
//- Begin piece
//- Determing sizes (nLocalPoints_, nLocalFaces_, nLocalVerts_),
//- and begin piece.
void beginPiece();
//- Write patch points
void writePoints();
//- Write patch faces
void writePolysLegacy();
//- Write patch faces, legacy format
void writePolysLegacy(const globalIndex& pointOffsets);
//- Write patch faces
void writePolys();
//- Write mesh topology
void writeMesh();
void writePolys(const globalIndex& pointOffsets);
//- No copy construct
@ -109,104 +124,137 @@ public:
// Constructors
//- Construct from components
//- Construct from components (default format INLINE_BASE64)
// \param useNearCellValue to use cell instead of patch values
patchWriter
(
const fvMesh& mesh,
const fileName& baseName,
const vtk::outputOptions outOpts,
const bool nearCellValue,
const labelList& patchIDs
const labelList& patchIDs,
const vtk::outputOptions opts = vtk::formatType::INLINE_BASE64,
const bool useNearCellValue = false
);
//- Construct from components (default format INLINE_BASE64),
//- and open the file for writing.
// The file name is with/without an extension.
patchWriter
(
const fvMesh& mesh,
const labelList& patchIDs,
const fileName& file,
bool parallel = Pstream::parRun()
);
//- Construct from components (default format INLINE_BASE64),
//- Construct from components and open the file for writing.
// The file name is with/without an extension.
patchWriter
(
const fvMesh& mesh,
const labelList& patchIDs,
const vtk::outputOptions opts,
const fileName& file,
bool parallel = Pstream::parRun()
);
//- Construct from components and open the file for writing.
// The file name is with/without an extension.
// \param useNearCellValue to use cell instead of patch values
patchWriter
(
const fvMesh& mesh,
const labelList& patchIDs,
const vtk::outputOptions opts,
const bool useNearCellValue,
const fileName& file,
bool parallel = Pstream::parRun()
);
//- Destructor
~patchWriter();
virtual ~patchWriter() = default;
// Member Functions
inline std::ofstream& os()
//- File extension for current format type.
using vtk::fileWriter::ext;
//- File extension for given output type
inline static word ext(vtk::outputOptions opts)
{
return os_;
return opts.ext(vtk::fileTag::POLY_DATA);
}
inline vtk::formatter& format()
//- The patch IDs
inline const labelList& patchIDs() const
{
return *format_;
return patchIDs_;
}
inline label nPoints() const
{
return nPoints_;
}
//- Write file header (non-collective)
// \note Expected calling states: (OPENED).
virtual bool beginFile(std::string title = "");
inline label nFaces() const
{
return nFaces_;
}
//- 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();
//- Open write for CellData of count fields.
// The parameters are only used for the legacy format.
void beginCellData(label nFields);
//- 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);
//- Close write for CellData
void endCellData();
//- 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);
//- 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
//- Write patch ids as CellData.
// Must be called within the CELL_DATA state.
void writePatchIDs();
//- Write file footer
void writeFooter();
// Write
// Write fields (individually)
//- Write point field
template<class Type, template<class> class PatchField>
void write
(
const GeometricField<Type, PatchField, pointMesh>& field
);
//- Write volume field
template<class Type, template<class> class PatchField>
void write(const GeometricField<Type, PatchField, volMesh>& field);
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
//- Write volume field with point interpolation
template<class Type>
void write
(
const PrimitivePatchInterpolation<primitivePatch>& pInterp,
const GeometricField<Type, fvPatchField, volMesh>& field
const GeometricField<Type, fvPatchField, volMesh>& field,
const PrimitivePatchInterpolation<primitivePatch>& pInterp
);
// 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
//- Write volume field with point interpolation
template<class Type>
void write
(
const PrimitivePatchInterpolation<primitivePatch>& pInterp,
const UPtrList
<
const GeometricField<Type, fvPatchField, volMesh>
>& flds
const GeometricField<Type, fvPatchField, volMesh>& field,
const PrimitivePatchInterpolation<primitivePatch>* pInterp
);
};

View File

@ -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-2017 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -31,42 +31,109 @@ License
template<class Type, template<class> class PatchField>
void Foam::vtk::patchWriter::write
(
const GeometricField<Type, PatchField, volMesh>& field
const GeometricField<Type, PatchField, pointMesh>& field
)
{
const int nCmpt(pTraits<Type>::nComponents);
const uint64_t payLoad(nFaces_ * nCmpt * sizeof(float));
if (legacy_)
if (isState(outputState::POINT_DATA))
{
legacy::floatField<nCmpt>(format(), field.name(), nFaces_);
++nPointData_;
}
else
{
format().openDataArray<float, nCmpt>(field.name())
.closeTag();
FatalErrorInFunction
<< "Bad writer state (" << stateNames[state_]
<< ") - should be (" << stateNames[outputState::POINT_DATA]
<< ") for field " << field.name() << nl << endl
<< exit(FatalError);
}
format().writeSize(payLoad);
const direction nCmpt(pTraits<Type>::nComponents);
for (const label patchId : patchIDs_)
label nPoints = nLocalPoints_;
if (parallel_)
{
const auto& pfld = field.boundaryField()[patchId];
reduce(nPoints, sumOp<label>());
}
if (nearCellValue_)
if (format_)
{
if (legacy())
{
vtk::writeList(format(), pfld.patchInternalField()());
legacy::floatField<nCmpt>(format(), field.name(), nPoints);
}
else
{
vtk::writeList(format(), pfld);
const uint64_t payLoad =
vtk::sizeofData<float, nCmpt>(nPoints);
format().beginDataArray<float, nCmpt>(field.name());
format().writeSize(payLoad);
}
}
format().flush();
if (!legacy_)
if (parallel_ ? Pstream::master() : true)
{
for (const label patchId : patchIDs_)
{
const auto& pfld = field.boundaryField()[patchId];
vtk::writeList(format(), pfld.patchInternalField()());
}
}
if (parallel_)
{
// Patch Ids are identical across all processes
const label nPatches = patchIDs_.size();
if (Pstream::master())
{
Field<Type> recv;
// Receive each patch field and write
for
(
int slave=Pstream::firstSlave();
slave<=Pstream::lastSlave();
++slave
)
{
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
for (label i=0; i < nPatches; ++i)
{
fromSlave >> recv;
vtk::writeList(format(), recv);
}
}
}
else
{
// Send each patch field to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
for (const label patchId : patchIDs_)
{
const auto& pfld = field.boundaryField()[patchId];
toMaster << pfld.patchInternalField()();
}
}
}
if (format_)
{
format().flush();
format().endDataArray();
}
}
@ -75,99 +142,123 @@ void Foam::vtk::patchWriter::write
template<class Type, template<class> class PatchField>
void Foam::vtk::patchWriter::write
(
const GeometricField<Type, PatchField, pointMesh>& field
const GeometricField<Type, PatchField, volMesh>& field
)
{
const int nCmpt(pTraits<Type>::nComponents);
const uint64_t payLoad(nPoints_ * nCmpt * sizeof(float));
if (legacy_)
if (isState(outputState::CELL_DATA))
{
legacy::floatField<nCmpt>(format(), field.name(), nPoints_);
++nCellData_;
}
else
{
format().openDataArray<float, nCmpt>(field.name())
.closeTag();
FatalErrorInFunction
<< "Bad writer state (" << stateNames[state_]
<< ") - should be (" << stateNames[outputState::CELL_DATA]
<< ") for field " << field.name() << nl << endl
<< exit(FatalError);
}
format().writeSize(payLoad);
const direction nCmpt(pTraits<Type>::nComponents);
for (const label patchId : patchIDs_)
label nFaces = nLocalFaces_;
if (parallel_)
{
const auto& pfld = field.boundaryField()[patchId];
vtk::writeList(format(), pfld.patchInternalField()());
reduce(nFaces, sumOp<label>());
}
format().flush();
if (!legacy_)
if (format_)
{
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<nCmpt>(format(), field.name(), 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_)
if (legacy())
{
auto tfield =
pInter.faceToPointInterpolate(pfld.patchInternalField()());
vtk::writeList(format(), tfield());
legacy::floatField<nCmpt>(format(), field.name(), nFaces);
}
else
{
auto tfield = pInter.faceToPointInterpolate(pfld);
const uint64_t payLoad =
vtk::sizeofData<float, nCmpt>(nFaces);
vtk::writeList(format(), tfield());
format().beginDataArray<float, nCmpt>(field.name());
format().writeSize(payLoad);
}
}
format().flush();
if (!legacy_)
if (parallel_ ? Pstream::master() : true)
{
format().endDataArray();
for (const label patchId : patchIDs_)
{
const auto& pfld = field.boundaryField()[patchId];
if (useNearCellValue_)
{
vtk::writeList(format(), pfld.patchInternalField()());
}
else
{
vtk::writeList(format(), pfld);
}
}
}
}
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)
if (parallel_)
{
write(field);
// Patch Ids are identical across all processes
const label nPatches = patchIDs_.size();
if (Pstream::master())
{
Field<Type> recv;
// Receive each patch field and write
for
(
int slave=Pstream::firstSlave();
slave<=Pstream::lastSlave();
++slave
)
{
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
for (label i=0; i < nPatches; ++i)
{
fromSlave >> recv;
vtk::writeList(format(), recv);
}
}
}
else
{
// Send each patch field to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
for (const label patchId : patchIDs_)
{
const auto& pfld = field.boundaryField()[patchId];
if (useNearCellValue_)
{
toMaster << pfld.patchInternalField()();
}
else
{
toMaster << static_cast<const Field<Type>&>(pfld);
}
}
}
}
if (format_)
{
format().flush();
format().endDataArray();
}
}
@ -175,13 +266,141 @@ void Foam::vtk::patchWriter::write
template<class Type>
void Foam::vtk::patchWriter::write
(
const PrimitivePatchInterpolation<primitivePatch>& pInter,
const UPtrList<const GeometricField<Type, fvPatchField, volMesh>>& flds
const GeometricField<Type, fvPatchField, volMesh>& field,
const PrimitivePatchInterpolation<primitivePatch>& pInter
)
{
for (const auto& field : flds)
if (isState(outputState::POINT_DATA))
{
write(pInter, field);
++nPointData_;
}
else
{
FatalErrorInFunction
<< "Bad writer state (" << stateNames[state_]
<< ") - should be (" << stateNames[outputState::POINT_DATA]
<< ") for field " << field.name() << nl << endl
<< exit(FatalError);
}
const direction nCmpt(pTraits<Type>::nComponents);
label nPoints = nLocalPoints_;
if (parallel_)
{
reduce(nPoints, sumOp<label>());
}
if (format_)
{
if (legacy())
{
legacy::floatField<nCmpt>(format(), field.name(), nPoints);
}
else
{
const uint64_t payLoad =
vtk::sizeofData<float, nCmpt>(nPoints);
format().beginDataArray<float, nCmpt>(field.name());
format().writeSize(payLoad);
}
}
if (parallel_ ? Pstream::master() : true)
{
for (const label patchId : patchIDs_)
{
const auto& pfld = field.boundaryField()[patchId];
if (useNearCellValue_)
{
auto tfield =
pInter.faceToPointInterpolate
(
pfld.patchInternalField()()
);
vtk::writeList(format(), tfield());
}
else
{
auto tfield = pInter.faceToPointInterpolate(pfld);
vtk::writeList(format(), tfield());
}
}
}
if (parallel_)
{
// Patch Ids are identical across all processes
const label nPatches = patchIDs_.size();
if (Pstream::master())
{
Field<Type> recv;
// Receive each patch field and write
for
(
int slave=Pstream::firstSlave();
slave<=Pstream::lastSlave();
++slave
)
{
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
for (label i=0; i < nPatches; ++i)
{
fromSlave >> recv;
vtk::writeList(format(), recv);
}
}
}
else
{
// Send each patch field to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
for (const label patchId : patchIDs_)
{
const auto& pfld = field.boundaryField()[patchId];
if (useNearCellValue_)
{
auto tfield =
pInter.faceToPointInterpolate
(
pfld.patchInternalField()()
);
toMaster << tfield();
}
else
{
auto tfield = pInter.faceToPointInterpolate(pfld);
toMaster << tfield();
}
}
}
}
if (format_)
{
format().flush();
format().endDataArray();
}
}