ENH: parallel and xml output for surface vector fields (issue #926)

-  implemented as vtk::surfaceFieldWriter, which replaces
   the vtk::writeSurfFields function.
This commit is contained in:
Mark Olesen
2018-09-27 13:38:31 +02:00
parent 6f06ce6e02
commit ed62ed1b19
5 changed files with 487 additions and 239 deletions

View File

@ -26,6 +26,6 @@ polyDualMesh/polyDualMesh.C
vtk/output/foamVtkInternalWriter.H
vtk/output/foamVtkPatchWriter.H
vtk/output/foamVtkWriteSurfFields.C
vtk/output/foamVtkSurfaceFieldWriter.C
LIB = $(FOAM_LIBBIN)/libconversion

View File

@ -0,0 +1,300 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016-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 "foamVtkSurfaceFieldWriter.H"
#include "emptyFvsPatchFields.H"
#include "fvsPatchFields.H"
#include "surfaceFields.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::List<Foam::vector> Foam::vtk::surfaceFieldWriter::flattenBoundary
(
const surfaceVectorField& field
) const
{
// Boundary field - flatten
List<vector> flat(mesh_.nBoundaryFaces(), Zero);
forAll(field.boundaryField(), patchi)
{
const polyPatch& pp = mesh_.boundaryMesh()[patchi];
const auto& pfld = field.boundaryField()[patchi];
if (!isA<emptyFvsPatchVectorField>(pfld))
{
SubList<vector>(flat, pp.size(), pp.offset()) = pfld;
}
}
return flat;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::vtk::surfaceFieldWriter::surfaceFieldWriter
(
const fvMesh& mesh,
const vtk::outputOptions opts
)
:
vtk::fileWriter(vtk::fileTag::POLY_DATA, opts),
mesh_(mesh),
numberOfPoints_(0)
{
opts_.append(false); // No append mode (horrible for streaming)
opts_.legacy(false); // Disallow legacy (inconvenient)
}
Foam::vtk::surfaceFieldWriter::surfaceFieldWriter
(
const fvMesh& mesh,
const fileName& file,
bool parallel
)
:
surfaceFieldWriter(mesh)
{
open(file, parallel);
}
Foam::vtk::surfaceFieldWriter::surfaceFieldWriter
(
const fvMesh& mesh,
const vtk::outputOptions opts,
const fileName& file,
bool parallel
)
:
surfaceFieldWriter(mesh, opts)
{
open(file, parallel);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::vtk::surfaceFieldWriter::beginFile(std::string title)
{
if (title.size())
{
return vtk::fileWriter::beginFile(title);
}
// Provide Default title
if (legacy())
{
return vtk::fileWriter::beginFile("surfaceFields");
}
// XML (inline)
return vtk::fileWriter::beginFile
(
"surfaceFields "
"case='" + mesh_.time().globalCaseName()
+ "' region='" + mesh_.name()
+ "' time='" + mesh_.time().timeName()
+ "' index='" + Foam::name(mesh_.time().timeIndex())
+ "'"
);
}
bool Foam::vtk::surfaceFieldWriter::writeGeometry()
{
enter_Piece();
// Output
const pointField& centres = mesh_.faceCentres();
// PointData for each face.
numberOfPoints_ = centres.size();
if (parallel_)
{
reduce(numberOfPoints_, sumOp<label>());
}
// <Piece>
if (format_)
{
format()
.tag
(
vtk::fileTag::PIECE,
fileAttr::NUMBER_OF_POINTS, numberOfPoints_
);
}
// <Point>
if (format_)
{
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_)
{
// Internal faces
vtk::writeListParallel
(
format_.ref(),
SubList<point>(centres, mesh_.nInternalFaces())
);
// Boundary faces
vtk::writeListParallel
(
format_.ref(),
SubList<point>(centres, mesh_.boundaryMesh().range())
);
}
else
{
// Non-parallel: use a normal write
vtk::writeList(format(), centres);
}
if (format_)
{
format().flush();
// Non-legacy
format()
.endDataArray()
.endTag(vtk::fileTag::POINTS);
}
return true;
}
bool Foam::vtk::surfaceFieldWriter::beginCellData(label nFields)
{
// No legacy, no CellData
return enter_CellData(0, 0);
}
bool Foam::vtk::surfaceFieldWriter::beginPointData(label nFields)
{
// No legacy
return enter_PointData(numberOfPoints_, 0);
}
void Foam::vtk::surfaceFieldWriter::write(const surfaceVectorField& field)
{
if (isState(outputState::POINT_DATA))
{
++nPointData_;
}
else
{
FatalErrorInFunction
<< "Bad writer state (" << stateNames[state_]
<< ") - should be (" << stateNames[outputState::POINT_DATA]
<< ") for field " << field.name() << nl << endl
<< exit(FatalError);
}
label nFaces = field.mesh().nFaces();
if (parallel_)
{
reduce(nFaces, sumOp<label>());
}
if (nFaces != numberOfPoints_)
{
FatalErrorInFunction
<< "Expecting " << numberOfPoints_
<< " faces, but found " << nFaces
<< exit(FatalError);
}
if (format_)
{
// Non-legacy
const uint64_t payLoad =
vtk::sizeofData<float, 3>(nFaces);
format().beginDataArray<float, 3>(field.name());
format().writeSize(payLoad);
}
// Internal field
const SubList<vector> internal(field, mesh_.nInternalFaces());
// Boundary field (flattened)
auto boundary(flattenBoundary(field));
if (parallel_)
{
// Internal field
vtk::writeListParallel(format_.ref(), internal);
// Boundary field
vtk::writeListParallel(format_.ref(), boundary);
}
else
{
// Non-parallel
// Internal field
vtk::writeList(format_.ref(), internal);
// Boundary field
vtk::writeList(format_.ref(), boundary);
}
if (format_)
{
format().flush();
format().endDataArray();
}
}
// ************************************************************************* //

View File

@ -0,0 +1,186 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016-2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::vtk::surfaceFieldWriter
Description
Write surfaces fields (as PointData) in VTP format.
Legacy VTK format is intentionally not supported.
The file output is structured as HEAD, FIELD_DATA, PIECE followed by any
CELL_DATA or POINT_DATA. These states are tracked internally to help
detect logic errors.
The FieldData element is to be placed prior to writing any geometry
Piece. This moves the information to the front of the output file
for visibility and simplifies the logic.
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
surfaceFieldWriter.C
\*---------------------------------------------------------------------------*/
#ifndef foamVtkSurfaceFieldWriter_H
#define foamVtkSurfaceFieldWriter_H
#include "foamVtkFileWriter.H"
#include "fvMesh.H"
#include "pointField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace vtk
{
/*---------------------------------------------------------------------------*\
Class vtk::surfaceFieldWriter Declaration
\*---------------------------------------------------------------------------*/
class surfaceFieldWriter
:
public vtk::fileWriter
{
// Private Member Data
//- Reference to the OpenFOAM mesh (or subset)
const fvMesh& mesh_;
//- The numer of field points for the current Piece
label numberOfPoints_;
// Private Member Functions
//- Flatten boundary field values into a contiguous list
List<vector> flattenBoundary(const surfaceVectorField& field) const;
//- No copy construct
surfaceFieldWriter(const surfaceFieldWriter&) = delete;
//- No copy assignment
void operator=(const surfaceFieldWriter&) = delete;
public:
// Constructors
//- Construct from mesh (default format INLINE_BASE64)
surfaceFieldWriter
(
const fvMesh& mesh,
const vtk::outputOptions opts = vtk::formatType::INLINE_BASE64
);
//- Construct from mesh (default format INLINE_BASE64),
//- and open the file for writing.
// The file name is with/without an extension.
surfaceFieldWriter
(
const fvMesh& mesh,
const fileName& file,
bool parallel = Pstream::parRun()
);
//- Construct from mesh and open the file for writing.
// The file name is with/without an extension.
surfaceFieldWriter
(
const fvMesh& mesh,
const vtk::outputOptions opts,
const fileName& file,
bool parallel = Pstream::parRun()
);
//- Destructor
virtual ~surfaceFieldWriter() = 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)
{
// No legacy
return vtk::fileExtension[vtk::fileTag::POLY_DATA];
}
//- Write file header (non-collective)
// \note Expected calling states: (OPENED).
virtual bool beginFile(std::string title = "");
//- Write cloud positions
// 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 the number of fields, which is required for
// legacy format.
// \note Expected calling states: (PIECE | POINT_DATA).
//
// \return True if the state changed
virtual bool beginCellData(label nFields=0);
//- Begin PointData output section
// Must be called prior to writing data fields.
// \note Expected calling states: (PIECE).
//
// \return True if the state changed
virtual bool beginPointData(label nFields=0);
// Write
//- Write field
void write(const surfaceVectorField& field);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace vtk
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,171 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "foamVtkWriteSurfFields.H"
#include "OFstream.H"
#include "emptyFvsPatchFields.H"
#include "fvsPatchFields.H"
#include "surfaceFields.H"
#include "foamVtkOutput.H"
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
void Foam::vtk::writeSurfFields
(
const fvMesh& mesh,
const fileName& baseName,
const vtk::outputOptions outOpts,
const UPtrList<const surfaceVectorField>& surfVectorFields
)
{
outputOptions opts(outOpts);
opts.append(false); // No append supported
const bool legacy_(opts.legacy());
std::ofstream os(baseName + (legacy_ ? ".vtk" : ".vtp"));
autoPtr<vtk::formatter> format = opts.newFormatter(os);
// Same payload size for points and vector fields!
const int nCmpt(3); // vector
const uint64_t payLoad(mesh.nFaces() * 3 * sizeof(float));
if (legacy_)
{
legacy::fileHeader(format(), "surfaceFields", vtk::fileTag::POLY_DATA);
legacy::beginPoints(os, mesh.nFaces());
}
else
{
// XML (inline)
format()
.xmlHeader()
.xmlComment("surfaceFields")
.beginVTKFile(vtk::fileTag::POLY_DATA, "0.1");
// Tricky - hide in beginPiece()
format()
.openTag(vtk::fileTag::PIECE)
.xmlAttr(vtk::fileAttr::NUMBER_OF_POINTS, mesh.nFaces())
.closeTag();
format().tag(vtk::fileTag::POINTS)
.openDataArray<float,3>(vtk::dataArrayAttr::POINTS)
.closeTag();
}
const pointField& fc = mesh.faceCentres();
format().writeSize(payLoad);
vtk::writeList(format(), fc);
format().flush();
if (!legacy_)
{
format()
.endDataArray()
.endTag(vtk::fileTag::POINTS);
}
// Fields
if (legacy_)
{
legacy::beginPointData
(
format(),
mesh.nFaces(),
surfVectorFields.size()
);
}
else
{
format().tag(vtk::fileTag::POINT_DATA);
}
// surfVectorFields
forAll(surfVectorFields, fieldi)
{
const auto& fld = surfVectorFields[fieldi];
if (legacy_)
{
legacy::floatField<nCmpt>(format(), fld.name(), mesh.nFaces());
}
else
{
format().openDataArray<float, nCmpt>(fld.name())
.closeTag();
}
format().writeSize(payLoad);
for (label facei=0; facei < mesh.nInternalFaces(); ++facei)
{
vtk::write(format(), fld[facei]);
}
forAll(fld.boundaryField(), patchi)
{
const fvPatch& pp = mesh.boundary()[patchi];
const auto& pf = fld.boundaryField()[patchi];
if (isA<emptyFvsPatchVectorField>(pf))
{
// Note: loop over polypatch size, not fvpatch size.
forAll(pp.patch(), i)
{
vtk::write(format(), vector::zero);
}
}
else
{
vtk::writeList(format(), pf);
}
}
format().flush();
if (!legacy_)
{
format().endDataArray();
}
}
if (!legacy_)
{
format().endTag(vtk::fileTag::POINT_DATA);
// slight cheat. </Piece> too
format().endTag(vtk::fileTag::PIECE);
format().endTag(vtk::fileTag::POLY_DATA)
.endVTKFile();
}
}
// ************************************************************************* //

View File

@ -1,67 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
InNamespace
Foam::vtk
Description
Write surface fields as vectors
SourceFiles
foamVtkWriteSurfFields.C
\*---------------------------------------------------------------------------*/
#ifndef foamVtkWriteSurfFields_H
#define foamVtkWriteSurfFields_H
#include "fvMesh.H"
#include "surfaceMesh.H"
#include "surfaceFieldsFwd.H"
#include "foamVtkOutputOptions.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace vtk
{
//- Write surface vector fields
void writeSurfFields
(
const fvMesh& mesh,
const fileName& baseName,
const vtk::outputOptions outOpts,
const UPtrList<const surfaceVectorField>& surfVectorFields
);
} // End namespace vtk
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //