mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: improvements for vtkWrite function object (issue #926)
- parallel output. The output is now postProcessing/<name> for similar reasoning as mentioned in #866 - better alignment with other function objects, no collision with foamToVTK output. - align the input parameters with those of vtkCloud so that we can specify the ASCII precision and the padding width for the output file names as well. - emit TimeValue field, support file series generation - support internal or boundary meshes, combining the result into a vtm file. - can restrict conversion based on zone names, enclosing volumes, bounding box
This commit is contained in:
@ -27,7 +27,11 @@ License
|
||||
#include "dictionary.H"
|
||||
#include "Time.H"
|
||||
#include "areaFields.H"
|
||||
#include "stringListOps.H"
|
||||
#include "foamVtkInternalWriter.H"
|
||||
#include "foamVtkPatchWriter.H"
|
||||
#include "foamVtkSeriesWriter.H"
|
||||
#include "foamVtmWriter.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
@ -42,6 +46,73 @@ namespace functionObjects
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
Foam::label Foam::functionObjects::vtkWrite::writeAllVolFields
|
||||
(
|
||||
autoPtr<vtk::internalWriter>& internalWriter,
|
||||
UPtrList<vtk::patchWriter>& patchWriters,
|
||||
const fvMeshSubset& proxy,
|
||||
const wordHashSet& acceptField
|
||||
) const
|
||||
{
|
||||
#undef vtkWrite_WRITE_FIELD
|
||||
#define vtkWrite_WRITE_FIELD(FieldType) \
|
||||
writeVolFields<FieldType> \
|
||||
( \
|
||||
internalWriter, \
|
||||
patchWriters, \
|
||||
proxy, \
|
||||
acceptField \
|
||||
)
|
||||
|
||||
|
||||
label count = 0;
|
||||
count += vtkWrite_WRITE_FIELD(volScalarField);
|
||||
count += vtkWrite_WRITE_FIELD(volVectorField);
|
||||
count += vtkWrite_WRITE_FIELD(volSphericalTensorField);
|
||||
count += vtkWrite_WRITE_FIELD(volSymmTensorField);
|
||||
count += vtkWrite_WRITE_FIELD(volTensorField);
|
||||
|
||||
#undef vtkWrite_WRITE_FIELD
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::functionObjects::vtkWrite::writeAllVolFields
|
||||
(
|
||||
autoPtr<vtk::internalWriter>& internalWriter,
|
||||
const autoPtr<volPointInterpolation>& pInterp,
|
||||
|
||||
UPtrList<vtk::patchWriter>& patchWriters,
|
||||
const UPtrList<PrimitivePatchInterpolation<primitivePatch>>& patchInterps,
|
||||
const fvMeshSubset& proxy,
|
||||
const wordHashSet& acceptField
|
||||
) const
|
||||
{
|
||||
#undef vtkWrite_WRITE_FIELD
|
||||
#define vtkWrite_WRITE_FIELD(FieldType) \
|
||||
writeVolFields<FieldType> \
|
||||
( \
|
||||
internalWriter, pInterp, \
|
||||
patchWriters, patchInterps, \
|
||||
proxy, \
|
||||
acceptField \
|
||||
)
|
||||
|
||||
|
||||
label count = 0;
|
||||
count += vtkWrite_WRITE_FIELD(volScalarField);
|
||||
count += vtkWrite_WRITE_FIELD(volVectorField);
|
||||
count += vtkWrite_WRITE_FIELD(volSphericalTensorField);
|
||||
count += vtkWrite_WRITE_FIELD(volSymmTensorField);
|
||||
count += vtkWrite_WRITE_FIELD(volTensorField);
|
||||
|
||||
#undef vtkWrite_WRITE_FIELD
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::functionObjects::vtkWrite::vtkWrite
|
||||
@ -51,19 +122,37 @@ Foam::functionObjects::vtkWrite::vtkWrite
|
||||
const dictionary& dict
|
||||
)
|
||||
:
|
||||
fvMeshFunctionObject(name, runTime, dict),
|
||||
functionObject(name),
|
||||
time_(runTime),
|
||||
outputDir_(),
|
||||
printf_(),
|
||||
writeOpts_(vtk::formatType::INLINE_BASE64),
|
||||
verbose_(true),
|
||||
doInternal_(true),
|
||||
doBoundary_(true),
|
||||
oneBoundary_(false),
|
||||
interpolate_(false),
|
||||
decompose_(false),
|
||||
writeIds_(false),
|
||||
meshState_(polyMesh::TOPO_CHANGE),
|
||||
selectRegions_(),
|
||||
selectPatches_(),
|
||||
selectFields_(),
|
||||
dirName_("VTK")
|
||||
selection_(),
|
||||
meshes_(),
|
||||
meshSubsets_(),
|
||||
vtuMappings_(),
|
||||
series_()
|
||||
{
|
||||
if (postProcess)
|
||||
{
|
||||
// Disable for post-process mode.
|
||||
// Emit as FatalError for the try/catch in the caller.
|
||||
FatalError
|
||||
<< type() << " disabled in post-process mode"
|
||||
<< exit(FatalError);
|
||||
}
|
||||
// May still want this? (OCT-2018)
|
||||
// if (postProcess)
|
||||
// {
|
||||
// // Disable for post-process mode.
|
||||
// // Emit as FatalError for the try/catch in the caller.
|
||||
// FatalError
|
||||
// << type() << " disabled in post-process mode"
|
||||
// << exit(FatalError);
|
||||
// }
|
||||
|
||||
read(dict);
|
||||
}
|
||||
@ -73,16 +162,23 @@ Foam::functionObjects::vtkWrite::vtkWrite
|
||||
|
||||
bool Foam::functionObjects::vtkWrite::read(const dictionary& dict)
|
||||
{
|
||||
fvMeshFunctionObject::read(dict);
|
||||
functionObject::read(dict);
|
||||
|
||||
readSelection(dict);
|
||||
|
||||
// We probably cannot trust old information after a reread
|
||||
series_.clear();
|
||||
|
||||
// verbose_ = dict.lookupOrDefault<bool>("verbose", true);
|
||||
doInternal_ = dict.lookupOrDefault<bool>("internal", true);
|
||||
doBoundary_ = dict.lookupOrDefault<bool>("boundary", true);
|
||||
oneBoundary_ = dict.lookupOrDefault<bool>("single", false);
|
||||
interpolate_ = dict.lookupOrDefault<bool>("interpolate", false);
|
||||
|
||||
//
|
||||
// writer options - default is xml base64
|
||||
// Writer options - default is xml base64
|
||||
//
|
||||
writeOpts_ = vtk::formatType::INLINE_BASE64;
|
||||
if (dict.lookupOrDefault("legacy", false))
|
||||
{
|
||||
writeOpts_.legacy(true);
|
||||
}
|
||||
|
||||
writeOpts_.ascii
|
||||
(
|
||||
@ -90,33 +186,63 @@ bool Foam::functionObjects::vtkWrite::read(const dictionary& dict)
|
||||
&& (IOstream::formatEnum(dict.get<word>("format")) == IOstream::ASCII)
|
||||
);
|
||||
|
||||
// FUTURE?
|
||||
// writeOpts_.precision
|
||||
// (
|
||||
// dict.lookupOrDefault
|
||||
// (
|
||||
// "writePrecision",
|
||||
// IOstream::defaultPrecision()
|
||||
// )
|
||||
// );
|
||||
if (dict.lookupOrDefault("legacy", false))
|
||||
{
|
||||
writeOpts_.legacy(true);
|
||||
}
|
||||
|
||||
writeOpts_.precision
|
||||
(
|
||||
dict.lookupOrDefault
|
||||
(
|
||||
"precision",
|
||||
IOstream::defaultPrecision()
|
||||
)
|
||||
);
|
||||
|
||||
// Info<< type() << " " << name() << " output-format: "
|
||||
// << writeOpts_.description() << nl;
|
||||
|
||||
const int padWidth = dict.lookupOrDefault<int>("width", 8);
|
||||
|
||||
// Appropriate printf format - Enforce min/max sanity limits
|
||||
if (padWidth < 1 || padWidth > 31)
|
||||
{
|
||||
printf_.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf_ = "%0" + std::to_string(padWidth) + "d";
|
||||
}
|
||||
|
||||
//
|
||||
// other options
|
||||
// Other options
|
||||
//
|
||||
dict.readIfPresent("directory", dirName_);
|
||||
|
||||
decompose_ = dict.lookupOrDefault("decompose", false);
|
||||
writeIds_ = dict.lookupOrDefault("writeIds", false);
|
||||
|
||||
|
||||
//
|
||||
// output fields
|
||||
//
|
||||
dict.readEntry("fields", selectFields_);
|
||||
selectFields_.uniq();
|
||||
// Output directory
|
||||
|
||||
outputDir_.clear();
|
||||
dict.readIfPresent("directory", outputDir_);
|
||||
|
||||
if (outputDir_.size())
|
||||
{
|
||||
// User-defined output directory
|
||||
outputDir_.expand();
|
||||
if (!outputDir_.isAbsolute())
|
||||
{
|
||||
outputDir_ = time_.globalPath()/outputDir_;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Standard postProcessing/ naming
|
||||
outputDir_ = time_.globalPath()/functionObject::outputPrefix/name();
|
||||
}
|
||||
outputDir_.clean();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -133,96 +259,515 @@ bool Foam::functionObjects::vtkWrite::write()
|
||||
// const word timeDesc =
|
||||
// useTimeName ? time_.timeName() : Foam::name(time_.timeIndex());
|
||||
|
||||
const word timeDesc = time_.timeName();
|
||||
const word timeDesc = "_" +
|
||||
(
|
||||
printf_.empty()
|
||||
? Foam::name(time_.timeIndex())
|
||||
: word::printf(printf_, time_.timeIndex())
|
||||
);
|
||||
|
||||
fileName vtkDir = dirName_;
|
||||
if (!vtkDir.isAbsolute())
|
||||
const scalar timeValue = time_.value();
|
||||
|
||||
update();
|
||||
|
||||
if (meshes_.empty() || (!doInternal_ && !doBoundary_))
|
||||
{
|
||||
vtkDir = time_.path()/vtkDir;
|
||||
// Skip
|
||||
return true;
|
||||
}
|
||||
mkDir(vtkDir);
|
||||
|
||||
string vtkName = time_.caseName();
|
||||
|
||||
if (Pstream::parRun())
|
||||
fileName vtkName = time_.globalCaseName();
|
||||
|
||||
vtk::vtmWriter vtmMultiRegion;
|
||||
|
||||
Info<< name() << " output Time: " << time_.timeName() << nl;
|
||||
|
||||
label regioni = 0;
|
||||
for (const word& regionName : meshes_.sortedToc())
|
||||
{
|
||||
// Strip off leading casename, leaving just processor_DDD ending.
|
||||
const auto i = vtkName.rfind("processor");
|
||||
|
||||
if (i != string::npos)
|
||||
fileName regionPrefix;
|
||||
if (regionName != polyMesh::defaultRegion)
|
||||
{
|
||||
vtkName = vtkName.substr(i);
|
||||
regionPrefix = regionName;
|
||||
}
|
||||
}
|
||||
|
||||
// internal mesh
|
||||
{
|
||||
const fileName outputName
|
||||
auto& meshProxy = meshSubsets_[regioni];
|
||||
auto& vtuMeshCells = vtuMappings_[regioni];
|
||||
++regioni;
|
||||
|
||||
const fvMesh& baseMesh = meshProxy.baseMesh();
|
||||
|
||||
wordHashSet acceptField(baseMesh.names<void>(selectFields_));
|
||||
|
||||
// Prune restart fields
|
||||
acceptField.filterKeys
|
||||
(
|
||||
vtkDir/vtkName
|
||||
+ "_"
|
||||
+ timeDesc
|
||||
[](const word& k){ return k.endsWith("_0"); },
|
||||
true // prune
|
||||
);
|
||||
|
||||
Info<< name() << " output Time: " << time_.timeName() << nl
|
||||
<< " Internal : " << outputName << endl;
|
||||
|
||||
// Number of fields to be written: only needed for legacy vtk format
|
||||
label nVolFields = 0;
|
||||
if (writeOpts_.legacy())
|
||||
{
|
||||
nVolFields =
|
||||
const label nVolFields =
|
||||
(
|
||||
(doInternal_ || doBoundary_)
|
||||
? baseMesh.count
|
||||
(
|
||||
(writeIds_ ? 1 : 0)
|
||||
+ countFields<volScalarField>()
|
||||
+ countFields<volVectorField>()
|
||||
+ countFields<volSphericalTensorField>()
|
||||
+ countFields<volSymmTensorField>()
|
||||
+ countFields<volTensorField>()
|
||||
stringListOps::foundOp<word>(fieldTypes::volume),
|
||||
acceptField
|
||||
)
|
||||
: 0
|
||||
);
|
||||
|
||||
// Undecided if we want to automatically support DimensionedFields
|
||||
// or only on demand:
|
||||
const label nDimFields = 0;
|
||||
// (
|
||||
// (doInternal_ || doBoundary_)
|
||||
// ? baseMesh.count
|
||||
// (
|
||||
// stringListOps::foundOp<word>(fieldTypes::internal),
|
||||
// acceptField
|
||||
// )
|
||||
// : 0
|
||||
// );
|
||||
|
||||
|
||||
// Setup for the vtm writer.
|
||||
// For legacy format, the information added is simply ignored.
|
||||
|
||||
fileName vtmOutputBase
|
||||
(
|
||||
outputDir_/regionPrefix/vtkName + timeDesc
|
||||
);
|
||||
|
||||
// Combined internal + boundary in a vtm file
|
||||
vtk::vtmWriter vtmWriter;
|
||||
|
||||
// Collect individual boundaries into a vtm file
|
||||
vtk::vtmWriter vtmBoundaries;
|
||||
|
||||
// Setup the internal writer
|
||||
autoPtr<vtk::internalWriter> internalWriter;
|
||||
|
||||
// Interpolator for volume and dimensioned fields
|
||||
autoPtr<volPointInterpolation> pInterp;
|
||||
|
||||
if (doInternal_)
|
||||
{
|
||||
if (interpolate_)
|
||||
{
|
||||
pInterp.reset(new volPointInterpolation(meshProxy.mesh()));
|
||||
}
|
||||
|
||||
if (vtuMeshCells.empty())
|
||||
{
|
||||
// Use the appropriate mesh (baseMesh or subMesh)
|
||||
vtuMeshCells.reset(meshProxy.mesh());
|
||||
}
|
||||
|
||||
internalWriter = autoPtr<vtk::internalWriter>::New
|
||||
(
|
||||
meshProxy.mesh(),
|
||||
vtuMeshCells,
|
||||
writeOpts_,
|
||||
// Output name for internal
|
||||
(
|
||||
writeOpts_.legacy()
|
||||
? vtmOutputBase
|
||||
: (vtmOutputBase / "internal")
|
||||
),
|
||||
Pstream::parRun()
|
||||
);
|
||||
|
||||
Info<< " Internal : "
|
||||
<< internalWriter->output().relative(time_.globalPath())
|
||||
<< endl;
|
||||
|
||||
// No sub-block for internal
|
||||
vtmWriter.append_vtu
|
||||
(
|
||||
"internal",
|
||||
vtmOutputBase.name()/"internal"
|
||||
);
|
||||
|
||||
internalWriter->writeTimeValue(timeValue);
|
||||
internalWriter->writeGeometry();
|
||||
}
|
||||
|
||||
vtk::vtuCells vtuMeshCells
|
||||
(
|
||||
mesh_,
|
||||
writeOpts_,
|
||||
decompose_
|
||||
);
|
||||
|
||||
// Write mesh
|
||||
vtk::internalWriter writer
|
||||
(
|
||||
mesh_,
|
||||
vtuMeshCells,
|
||||
outputName,
|
||||
writeOpts_
|
||||
);
|
||||
// Setup the patch writers
|
||||
|
||||
const polyBoundaryMesh& patches = meshProxy.mesh().boundaryMesh();
|
||||
|
||||
PtrList<vtk::patchWriter> patchWriters;
|
||||
PtrList<PrimitivePatchInterpolation<primitivePatch>> patchInterps;
|
||||
|
||||
labelList patchIds;
|
||||
if (doBoundary_)
|
||||
{
|
||||
patchIds = getSelectedPatches(patches);
|
||||
}
|
||||
|
||||
if (oneBoundary_ && patchIds.size())
|
||||
{
|
||||
auto writer = autoPtr<vtk::patchWriter>::New
|
||||
(
|
||||
meshProxy.mesh(),
|
||||
patchIds,
|
||||
writeOpts_,
|
||||
// Output name for one patch: "boundary"
|
||||
(
|
||||
writeOpts_.legacy()
|
||||
? (outputDir_/regionPrefix/"boundary"/"boundary" + timeDesc)
|
||||
: (vtmOutputBase / "boundary")
|
||||
),
|
||||
Pstream::parRun()
|
||||
);
|
||||
|
||||
// No sub-block for one-patch
|
||||
vtmWriter.append_vtp
|
||||
(
|
||||
"boundary",
|
||||
vtmOutputBase.name()/"boundary"
|
||||
);
|
||||
|
||||
Info<< " Boundaries: "
|
||||
<< writer->output().relative(time_.globalPath()) << nl;
|
||||
|
||||
|
||||
writer->writeTimeValue(timeValue);
|
||||
writer->writeGeometry();
|
||||
|
||||
// Transfer writer to list for later use
|
||||
patchWriters.resize(1);
|
||||
patchWriters.set(0, writer);
|
||||
|
||||
// Avoid patchInterpolation for each sub-patch
|
||||
patchInterps.resize(1); // == nullptr
|
||||
}
|
||||
else if (patchIds.size())
|
||||
{
|
||||
patchWriters.resize(patchIds.size());
|
||||
if (interpolate_)
|
||||
{
|
||||
patchInterps.resize(patchIds.size());
|
||||
}
|
||||
|
||||
label nPatchWriters = 0;
|
||||
label nPatchInterps = 0;
|
||||
|
||||
for (const label patchId : patchIds)
|
||||
{
|
||||
const polyPatch& pp = patches[patchId];
|
||||
|
||||
auto writer = autoPtr<vtk::patchWriter>::New
|
||||
(
|
||||
meshProxy.mesh(),
|
||||
labelList(one(), pp.index()),
|
||||
writeOpts_,
|
||||
// Output name for patch: "boundary"/name
|
||||
(
|
||||
writeOpts_.legacy()
|
||||
?
|
||||
(
|
||||
outputDir_/regionPrefix/pp.name()
|
||||
/ (pp.name()) + timeDesc
|
||||
)
|
||||
: (vtmOutputBase / "boundary" / pp.name())
|
||||
),
|
||||
Pstream::parRun()
|
||||
);
|
||||
|
||||
if (!nPatchWriters)
|
||||
{
|
||||
vtmWriter.beginBlock("boundary");
|
||||
vtmBoundaries.beginBlock("boundary");
|
||||
}
|
||||
|
||||
vtmWriter.append_vtp
|
||||
(
|
||||
pp.name(),
|
||||
vtmOutputBase.name()/"boundary"/pp.name()
|
||||
);
|
||||
|
||||
vtmBoundaries.append_vtp
|
||||
(
|
||||
pp.name(),
|
||||
"boundary"/pp.name()
|
||||
);
|
||||
|
||||
Info<< " Boundary : "
|
||||
<< writer->output().relative(time_.globalPath()) << nl;
|
||||
|
||||
writer->writeTimeValue(timeValue);
|
||||
writer->writeGeometry();
|
||||
|
||||
// Transfer writer to list for later use
|
||||
patchWriters.set(nPatchWriters++, writer);
|
||||
|
||||
if (patchInterps.size())
|
||||
{
|
||||
patchInterps.set
|
||||
(
|
||||
nPatchInterps++,
|
||||
new PrimitivePatchInterpolation<primitivePatch>(pp)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (nPatchWriters)
|
||||
{
|
||||
vtmWriter.endBlock("boundary");
|
||||
vtmBoundaries.endBlock("boundary");
|
||||
}
|
||||
|
||||
patchWriters.resize(nPatchWriters);
|
||||
patchInterps.resize(nPatchInterps);
|
||||
}
|
||||
|
||||
// CellData
|
||||
{
|
||||
writer.beginCellData(nVolFields);
|
||||
|
||||
// Write cellID field
|
||||
if (writeIds_)
|
||||
if (internalWriter.valid())
|
||||
{
|
||||
writer.writeCellIDs();
|
||||
// cellIds + procIds (parallel)
|
||||
internalWriter->beginCellData
|
||||
(
|
||||
(writeIds_ ? 1 + (internalWriter->parallel() ? 1 : 0) : 0)
|
||||
+ (internalWriter->parallel() ? 1 : 0)
|
||||
+ nVolFields + nDimFields
|
||||
);
|
||||
|
||||
// Write cellID field + procID (parallel only)
|
||||
if (writeIds_)
|
||||
{
|
||||
internalWriter->writeCellIDs();
|
||||
internalWriter->writeProcIDs(); // parallel only
|
||||
}
|
||||
}
|
||||
|
||||
// Write volFields
|
||||
writeFields<volScalarField>(writer);
|
||||
writeFields<volVectorField>(writer);
|
||||
writeFields<volSphericalTensorField>(writer);
|
||||
writeFields<volSymmTensorField>(writer);
|
||||
writeFields<volTensorField>(writer);
|
||||
if (nVolFields)
|
||||
{
|
||||
for (vtk::patchWriter& writer : patchWriters)
|
||||
{
|
||||
writer.beginCellData
|
||||
(
|
||||
(writeIds_ ? 1 : 0)
|
||||
+ nVolFields
|
||||
);
|
||||
if (writeIds_)
|
||||
{
|
||||
writer.writePatchIDs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.endCellData();
|
||||
writeAllVolFields
|
||||
(
|
||||
internalWriter,
|
||||
patchWriters,
|
||||
meshProxy,
|
||||
acceptField
|
||||
);
|
||||
|
||||
// writeAllDimFields
|
||||
// (
|
||||
// internalWriter,
|
||||
// meshProxy,
|
||||
// acceptField
|
||||
// );
|
||||
|
||||
// End CellData is implicit
|
||||
}
|
||||
|
||||
writer.writeFooter();
|
||||
|
||||
// PointData
|
||||
// - only construct pointMesh on request since it constructs
|
||||
// edge addressing
|
||||
if (interpolate_)
|
||||
{
|
||||
// Begin PointData
|
||||
if (internalWriter.valid())
|
||||
{
|
||||
internalWriter->beginPointData
|
||||
(
|
||||
nVolFields + nDimFields
|
||||
);
|
||||
}
|
||||
|
||||
forAll(patchWriters, writeri)
|
||||
{
|
||||
const label nPatchFields =
|
||||
(
|
||||
writeri < patchInterps.size() && patchInterps.set(writeri)
|
||||
? nVolFields
|
||||
: 0
|
||||
);
|
||||
|
||||
if (nPatchFields)
|
||||
{
|
||||
patchWriters[writeri].beginPointData(nPatchFields);
|
||||
}
|
||||
}
|
||||
|
||||
writeAllVolFields
|
||||
(
|
||||
internalWriter, pInterp,
|
||||
patchWriters, patchInterps,
|
||||
meshProxy,
|
||||
acceptField
|
||||
);
|
||||
|
||||
// writeAllDimFields
|
||||
// (
|
||||
// internalWriter, pInterp,
|
||||
// meshProxy,
|
||||
// acceptField
|
||||
// );
|
||||
|
||||
// writeAllPointFields
|
||||
// (
|
||||
// internalWriter,
|
||||
// patchWriters,
|
||||
// meshProxy,
|
||||
// acceptField
|
||||
// );
|
||||
|
||||
// End PointData is implicit
|
||||
}
|
||||
|
||||
|
||||
// Finish writers
|
||||
if (internalWriter.valid())
|
||||
{
|
||||
internalWriter->close();
|
||||
}
|
||||
|
||||
for (vtk::patchWriter& writer : patchWriters)
|
||||
{
|
||||
writer.close();
|
||||
}
|
||||
|
||||
pInterp.clear();
|
||||
patchWriters.clear();
|
||||
patchInterps.clear();
|
||||
|
||||
|
||||
// Collective output
|
||||
|
||||
if (Pstream::master())
|
||||
{
|
||||
// Naming for vtm, file series etc.
|
||||
fileName outputName(vtmOutputBase);
|
||||
|
||||
if (writeOpts_.legacy())
|
||||
{
|
||||
if (doInternal_)
|
||||
{
|
||||
// Add to file-series and emit as JSON
|
||||
|
||||
outputName.ext(vtk::legacy::fileExtension);
|
||||
|
||||
fileName seriesName(vtk::seriesWriter::base(outputName));
|
||||
|
||||
vtk::seriesWriter& series = series_(seriesName);
|
||||
|
||||
// First time?
|
||||
// Load from file, verify against filesystem,
|
||||
// prune time >= currentTime
|
||||
if (series.empty())
|
||||
{
|
||||
series.load(seriesName, true, timeValue);
|
||||
}
|
||||
|
||||
series.append(timeValue, timeDesc);
|
||||
series.write(seriesName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vtmWriter.size())
|
||||
{
|
||||
// Emit ".vtm"
|
||||
|
||||
outputName.ext(vtmWriter.ext());
|
||||
|
||||
vtmWriter.setTime(timeValue);
|
||||
vtmWriter.write(outputName);
|
||||
|
||||
fileName seriesName(vtk::seriesWriter::base(outputName));
|
||||
|
||||
vtk::seriesWriter& series = series_(seriesName);
|
||||
|
||||
// First time?
|
||||
// Load from file, verify against filesystem,
|
||||
// prune time >= currentTime
|
||||
if (series.empty())
|
||||
{
|
||||
series.load(seriesName, true, timeValue);
|
||||
}
|
||||
|
||||
series.append(timeValue, outputName);
|
||||
series.write(seriesName);
|
||||
|
||||
// Add to multi-region vtm
|
||||
vtmMultiRegion.add(regionName, regionPrefix, vtmWriter);
|
||||
}
|
||||
|
||||
if (vtmBoundaries.size())
|
||||
{
|
||||
// Emit "boundary.vtm" with collection of boundaries
|
||||
|
||||
// Naming for vtm
|
||||
fileName outputName(vtmOutputBase / "boundary");
|
||||
outputName.ext(vtmBoundaries.ext());
|
||||
|
||||
vtmBoundaries.setTime(timeValue);
|
||||
vtmBoundaries.write(outputName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Emit multi-region vtm
|
||||
if (Pstream::master() && meshes_.size() > 1)
|
||||
{
|
||||
fileName outputName
|
||||
(
|
||||
outputDir_/vtkName + "-regions" + timeDesc + ".vtm"
|
||||
);
|
||||
|
||||
vtmMultiRegion.setTime(timeValue);
|
||||
vtmMultiRegion.write(outputName);
|
||||
|
||||
fileName seriesName(vtk::seriesWriter::base(outputName));
|
||||
|
||||
vtk::seriesWriter& series = series_(seriesName);
|
||||
|
||||
// First time?
|
||||
// Load from file, verify against filesystem,
|
||||
// prune time >= currentTime
|
||||
if (series.empty())
|
||||
{
|
||||
series.load(seriesName, true, timeValue);
|
||||
}
|
||||
|
||||
series.append(timeValue, outputName);
|
||||
series.write(seriesName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::functionObjects::vtkWrite::end()
|
||||
{
|
||||
meshSubsets_.clear();
|
||||
vtuMappings_.clear();
|
||||
meshes_.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
Reference in New Issue
Block a user