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:
@ -3,6 +3,7 @@ abort/abort.C
|
||||
codedFunctionObject/codedFunctionObject.C
|
||||
ensightWrite/ensightWrite.C
|
||||
vtkWrite/vtkWrite.C
|
||||
vtkWrite/vtkWriteUpdate.C
|
||||
|
||||
removeRegisteredObject/removeRegisteredObject.C
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
|
||||
\\/ M anipulation | Copyright (C) 2017-2018 OpenCFD Ltd.
|
||||
\\ / A nd | Copyright (C) 2017-2018 OpenCFD Ltd.
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -28,11 +28,8 @@ Group
|
||||
grpUtilitiesFunctionObjects
|
||||
|
||||
Description
|
||||
This functionObject writes objects registered to the database in VTK format.
|
||||
|
||||
Currently only supports writing of the cell-values of volFields but
|
||||
support for other field types, patch fields, Lagrangian data etc. will be
|
||||
added.
|
||||
Writes fields in VTK (xml or legacy) format.
|
||||
Writes cell-values or point-interpolated values for volFields.
|
||||
|
||||
Example of function object specification:
|
||||
\verbatim
|
||||
@ -47,22 +44,80 @@ Description
|
||||
decompose false;
|
||||
...
|
||||
fields (U p);
|
||||
|
||||
selection
|
||||
{
|
||||
box
|
||||
{
|
||||
action add;
|
||||
source box;
|
||||
box (-0.1 -0.01 -0.1) (0.1 0.30 0.1);
|
||||
}
|
||||
dome
|
||||
{
|
||||
action add;
|
||||
shape sphere;
|
||||
origin (-0.1 -0.01 -0.1);
|
||||
radius 0.25;
|
||||
}
|
||||
centre
|
||||
{
|
||||
action subtract;
|
||||
source sphere;
|
||||
origin (-0.1 -0.01 -0.1);
|
||||
radius 0.1;
|
||||
}
|
||||
blob
|
||||
{
|
||||
action add;
|
||||
source surface;
|
||||
surface triSurfaceMesh;
|
||||
name blob.stl;
|
||||
}
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
|
||||
Usage
|
||||
\heading Basic Usage
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
type | Type name: vtkWrite | yes |
|
||||
fields | Fields to output | yes |
|
||||
writeControl | Output control | recommended | timeStep
|
||||
directory | The output directory name | no | "VTK"
|
||||
format | ASCII or binary format | no | binary
|
||||
legacy | Legacy VTK output | no | false
|
||||
decompose | decompose polyhedra | no | false
|
||||
writeIds | Write cell ids as field | no | true
|
||||
Property | Description | Required | Default
|
||||
type | Type name: vtkWrite | yes |
|
||||
fields | Fields to output (wordRe list) | yes |
|
||||
boundary | Convert boundary fields | no | true
|
||||
internal | Convert internal fields | no | true
|
||||
single | Combine patches into a single boundary | no | false
|
||||
interpolate | Interpolate for point values | no | false
|
||||
\endtable
|
||||
|
||||
\heading Output Options
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
format | ascii or binary format | no | binary
|
||||
legacy | Legacy VTK output | no | false
|
||||
precision | Write precision in ascii | no | same as IOstream
|
||||
directory | The output directory name | no | postProcessing/NAME
|
||||
width | Padding width for file name | no | 8
|
||||
decompose | Decompose polyhedral cells | no | false
|
||||
writeIds | Write cell/patch ids as field | no | true
|
||||
\endtable
|
||||
|
||||
\heading Output Selection
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
region | Name for a single region | no | region0
|
||||
regions | List of regions (wordRe list) | no |
|
||||
patches | Limit to listed patches (wordRe list) | no |
|
||||
selection | Cell selection (topoSet actions) | no | empty dict
|
||||
\endtable
|
||||
|
||||
Note
|
||||
The region of interest is defined by the selection dictionary
|
||||
as a set of actions (add,subtract,subset,invert).
|
||||
Omitting the selection dictionary is the same as specifying the
|
||||
conversion of all cells (in the selected regions).
|
||||
Omitting the patches entry is the same as specifying the conversion of all
|
||||
patches.
|
||||
|
||||
See also
|
||||
Foam::functionObjects::ensightWrite
|
||||
Foam::functionObjects::fvMeshFunctionObject
|
||||
@ -77,10 +132,12 @@ SourceFiles
|
||||
#ifndef functionObjects_vtkWrite_H
|
||||
#define functionObjects_vtkWrite_H
|
||||
|
||||
#include "fvMeshFunctionObject.H"
|
||||
#include "functionObject.H"
|
||||
#include "foamVtkInternalWriter.H"
|
||||
#include "foamVtkSurfaceMeshWriter.H"
|
||||
#include "wordRes.H"
|
||||
#include "foamVtkPatchWriter.H"
|
||||
#include "foamVtkSeriesWriter.H"
|
||||
#include "fvMeshSubsetProxy.H"
|
||||
#include "searchableSurfaces.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -95,18 +152,36 @@ namespace functionObjects
|
||||
|
||||
class vtkWrite
|
||||
:
|
||||
public fvMeshFunctionObject
|
||||
public functionObject
|
||||
{
|
||||
// Private data
|
||||
// Private Data
|
||||
|
||||
//- Reference to the time database
|
||||
const Time& time_;
|
||||
|
||||
//- The output directory
|
||||
fileName outputDir_;
|
||||
|
||||
//- The printf format for zero-padding names
|
||||
string printf_;
|
||||
|
||||
//- VTK output options
|
||||
vtk::outputOptions writeOpts_;
|
||||
|
||||
//- Name of fields to process
|
||||
wordRes selectFields_;
|
||||
//- Verbose output
|
||||
bool verbose_;
|
||||
|
||||
//- Output directory name
|
||||
fileName dirName_;
|
||||
//- Convert internal mesh
|
||||
bool doInternal_;
|
||||
|
||||
//- Convert boundary mesh
|
||||
bool doBoundary_;
|
||||
|
||||
//- Combine patches into a single file
|
||||
bool oneBoundary_;
|
||||
|
||||
//- Interpolate cell to point values
|
||||
bool interpolate_;
|
||||
|
||||
//- Decompose polyhedra
|
||||
bool decompose_;
|
||||
@ -114,29 +189,99 @@ class vtkWrite
|
||||
//- Write cell ids field
|
||||
bool writeIds_;
|
||||
|
||||
//- Track changes in mesh geometry
|
||||
enum polyMesh::readUpdateState meshState_;
|
||||
|
||||
//- Requested names of regions to process
|
||||
wordRes selectRegions_;
|
||||
|
||||
//- Requested names of patches to process
|
||||
wordRes selectPatches_;
|
||||
|
||||
//- Requested names of fields to process
|
||||
wordRes selectFields_;
|
||||
|
||||
//- Dictionary of volume selections
|
||||
dictionary selection_;
|
||||
|
||||
//- Pointers to the requested mesh regions
|
||||
HashTable<const fvMesh*> meshes_;
|
||||
|
||||
//- Subsetting for meshes.
|
||||
// Access index according to sorted mesh names.
|
||||
PtrList<fvMeshSubset> meshSubsets_;
|
||||
|
||||
//- Storage for VTU cells, sizing.
|
||||
// Access index according to sorted mesh names.
|
||||
PtrList<vtk::vtuCells> vtuMappings_;
|
||||
|
||||
//- VTK file series
|
||||
HashTable<vtk::seriesWriter, fileName> series_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Count number of selected fields for GeoField type.
|
||||
// Only needed for legacy vtk format.
|
||||
template<class GeoField>
|
||||
label countFields() const;
|
||||
//- Update mesh subset according to zones, geometry, bounds
|
||||
bool updateSubset(fvMeshSubset& subsetter) const;
|
||||
|
||||
//- Write selected fields for GeoField type.
|
||||
template<class GeoField>
|
||||
label writeFields
|
||||
//- Get patchIds selected in list
|
||||
labelList getSelectedPatches(const polyBoundaryMesh& patches) const;
|
||||
|
||||
//- Read information for selections
|
||||
bool readSelection(const dictionary& dict);
|
||||
|
||||
//- Update meshes, subMeshes etc.
|
||||
bool update();
|
||||
|
||||
|
||||
// Write
|
||||
|
||||
//- Write all volume fields
|
||||
label writeAllVolFields
|
||||
(
|
||||
vtk::internalWriter& writer,
|
||||
bool verbose=true
|
||||
autoPtr<vtk::internalWriter>& internalWriter,
|
||||
UPtrList<vtk::patchWriter>& patchWriters,
|
||||
const fvMeshSubset& proxy,
|
||||
const wordHashSet& acceptField
|
||||
) const;
|
||||
|
||||
|
||||
//- Write selected fields for GeoField type.
|
||||
template<class GeoField>
|
||||
label writeFields
|
||||
//- Write all volume fields with point interpolation
|
||||
label writeAllVolFields
|
||||
(
|
||||
vtk::surfaceMeshWriter& writer,
|
||||
bool verbose=true
|
||||
autoPtr<vtk::internalWriter>& internalWriter,
|
||||
const autoPtr<volPointInterpolation>& pInterp,
|
||||
UPtrList<vtk::patchWriter>& patchWriters,
|
||||
const UPtrList
|
||||
<
|
||||
PrimitivePatchInterpolation<primitivePatch>
|
||||
>& patchInterps,
|
||||
const fvMeshSubset& proxy,
|
||||
const wordHashSet& acceptField
|
||||
) const;
|
||||
|
||||
//- Write selected GeoField fields.
|
||||
template<class GeoField>
|
||||
label writeVolFields
|
||||
(
|
||||
autoPtr<vtk::internalWriter>& internalWriter,
|
||||
UPtrList<vtk::patchWriter>& patchWriters,
|
||||
const fvMeshSubset& proxy,
|
||||
const wordHashSet& acceptField
|
||||
) const;
|
||||
|
||||
//- Write selected GeoField fields with point interpolation
|
||||
template<class GeoField>
|
||||
label writeVolFields
|
||||
(
|
||||
autoPtr<vtk::internalWriter>& internalWriter,
|
||||
const autoPtr<volPointInterpolation>& pInterp,
|
||||
UPtrList<vtk::patchWriter>& patchWriters,
|
||||
const UPtrList
|
||||
<
|
||||
PrimitivePatchInterpolation<primitivePatch>
|
||||
>& patchInterps,
|
||||
const fvMeshSubset& proxy,
|
||||
const wordHashSet& acceptField
|
||||
) const;
|
||||
|
||||
|
||||
@ -173,11 +318,20 @@ public:
|
||||
//- Read the vtkWrite specification
|
||||
virtual bool read(const dictionary& dict);
|
||||
|
||||
//- Execute, currently does nothing
|
||||
//- Execute - does nothing
|
||||
virtual bool execute();
|
||||
|
||||
//- Write fields
|
||||
virtual bool write();
|
||||
|
||||
//- On end - provide feedback about disconnecting from catatyst.
|
||||
virtual bool end();
|
||||
|
||||
//- Update for changes of mesh
|
||||
virtual void updateMesh(const mapPolyMesh& mpm);
|
||||
|
||||
//- Update for mesh point-motion
|
||||
virtual void movePoints(const polyMesh& mesh);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -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) 2018 OpenCFD Ltd.
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -26,60 +26,147 @@ License
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class GeoField>
|
||||
Foam::label
|
||||
Foam::functionObjects::vtkWrite::countFields() const
|
||||
Foam::label Foam::functionObjects::vtkWrite::writeVolFields
|
||||
(
|
||||
autoPtr<vtk::internalWriter>& internalWriter,
|
||||
UPtrList<vtk::patchWriter>& patchWriters,
|
||||
const fvMeshSubset& proxy,
|
||||
const wordHashSet& acceptField
|
||||
) const
|
||||
{
|
||||
return obr_.names<GeoField>(selectFields_).size();
|
||||
const fvMesh& baseMesh = proxy.baseMesh();
|
||||
|
||||
label count = 0;
|
||||
|
||||
for (const word& fieldName : baseMesh.sortedNames<GeoField>(acceptField))
|
||||
{
|
||||
bool ok = false;
|
||||
const auto* fieldptr = baseMesh.findObject<GeoField>(fieldName);
|
||||
|
||||
if (!fieldptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto tfield = fvMeshSubsetProxy::interpolate(proxy, *fieldptr);
|
||||
const auto& field = tfield();
|
||||
|
||||
// Internal
|
||||
if (internalWriter.valid())
|
||||
{
|
||||
ok = true;
|
||||
internalWriter->write(field);
|
||||
}
|
||||
|
||||
// Boundary
|
||||
label writeri = 0;
|
||||
for (vtk::patchWriter& writer : patchWriters)
|
||||
{
|
||||
ok = true;
|
||||
writer.write(field);
|
||||
++writeri;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
++count;
|
||||
|
||||
if (verbose_)
|
||||
{
|
||||
if (count == 1)
|
||||
{
|
||||
Log << " " << GeoField::typeName << '(';
|
||||
}
|
||||
else
|
||||
{
|
||||
Log << ' ';
|
||||
}
|
||||
Log << fieldName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose_ && count)
|
||||
{
|
||||
Log << ')' << endl;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
template<class GeoField>
|
||||
Foam::label
|
||||
Foam::functionObjects::vtkWrite::writeFields
|
||||
Foam::label Foam::functionObjects::vtkWrite::writeVolFields
|
||||
(
|
||||
vtk::internalWriter& writer,
|
||||
bool verbose
|
||||
autoPtr<vtk::internalWriter>& internalWriter,
|
||||
const autoPtr<volPointInterpolation>& pInterp,
|
||||
UPtrList<vtk::patchWriter>& patchWriters,
|
||||
const UPtrList<PrimitivePatchInterpolation<primitivePatch>>& patchInterps,
|
||||
const fvMeshSubset& proxy,
|
||||
const wordHashSet& acceptField
|
||||
) const
|
||||
{
|
||||
const wordList names = obr_.sortedNames<GeoField>(selectFields_);
|
||||
const fvMesh& baseMesh = proxy.baseMesh();
|
||||
|
||||
if (verbose && names.size())
|
||||
label count = 0;
|
||||
|
||||
for (const word& fieldName : baseMesh.sortedNames<GeoField>(acceptField))
|
||||
{
|
||||
Info<< " " << GeoField::typeName
|
||||
<< " " << flatOutput(names) << endl;
|
||||
bool ok = false;
|
||||
const auto* fieldptr = baseMesh.findObject<GeoField>(fieldName);
|
||||
|
||||
if (!fieldptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto tfield = fvMeshSubsetProxy::interpolate(proxy, *fieldptr);
|
||||
const auto& field = tfield();
|
||||
|
||||
// Internal
|
||||
if (internalWriter.valid() && pInterp.valid())
|
||||
{
|
||||
ok = true;
|
||||
internalWriter->write(field, *pInterp);
|
||||
}
|
||||
|
||||
// Boundary
|
||||
label writeri = 0;
|
||||
for (vtk::patchWriter& writer : patchWriters)
|
||||
{
|
||||
if (writeri < patchInterps.size() && patchInterps.set(writeri))
|
||||
{
|
||||
ok = true;
|
||||
writer.write(field, patchInterps[writeri]);
|
||||
}
|
||||
++writeri;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
++count;
|
||||
|
||||
if (verbose_)
|
||||
{
|
||||
if (count == 1)
|
||||
{
|
||||
Log << " " << GeoField::typeName << "->point(";
|
||||
}
|
||||
else
|
||||
{
|
||||
Log << ' ';
|
||||
}
|
||||
Log << fieldName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const word& fieldName : names)
|
||||
if (verbose_ && count)
|
||||
{
|
||||
writer.write(obr_.lookupObject<GeoField>(fieldName));
|
||||
Log << ')' << endl;
|
||||
}
|
||||
|
||||
return names.size();
|
||||
}
|
||||
|
||||
|
||||
template<class GeoField>
|
||||
Foam::label
|
||||
Foam::functionObjects::vtkWrite::writeFields
|
||||
(
|
||||
vtk::surfaceMeshWriter& writer,
|
||||
bool verbose
|
||||
) const
|
||||
{
|
||||
const wordList names = obr_.sortedNames<GeoField>(selectFields_);
|
||||
|
||||
if (verbose && names.size())
|
||||
{
|
||||
Info<< " " << GeoField::typeName
|
||||
<< " " << flatOutput(names) << endl;
|
||||
}
|
||||
|
||||
for (const word& fieldName : names)
|
||||
{
|
||||
writer.write(obr_.lookupObject<GeoField>(fieldName));
|
||||
}
|
||||
|
||||
return names.size();
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
274
src/functionObjects/utilities/vtkWrite/vtkWriteUpdate.C
Normal file
274
src/functionObjects/utilities/vtkWrite/vtkWriteUpdate.C
Normal file
@ -0,0 +1,274 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / 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 "vtkWrite.H"
|
||||
#include "cellBitSet.H"
|
||||
#include "topoSetCellSource.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Local Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
// A limited selection of actions
|
||||
const Enum<topoSetSource::setAction> actionNames
|
||||
({
|
||||
{ topoSetSource::ADD, "add" },
|
||||
{ topoSetSource::SUBTRACT, "subtract" },
|
||||
{ topoSetSource::SUBSET, "subset" },
|
||||
{ topoSetSource::INVERT, "invert" },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
bool Foam::functionObjects::vtkWrite::updateSubset
|
||||
(
|
||||
fvMeshSubset& subsetter
|
||||
) const
|
||||
{
|
||||
if (selection_.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const fvMesh& mesh = subsetter.baseMesh();
|
||||
|
||||
// Start with all cells unselected
|
||||
cellBitSet cellsToSelect(mesh, false);
|
||||
|
||||
for (const entry& dEntry : selection_)
|
||||
{
|
||||
if (!dEntry.isDict())
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Ignoring non-dictionary entry "
|
||||
<< dEntry << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
const dictionary& dict = dEntry.dict();
|
||||
|
||||
const auto action = actionNames.get("action", dict);
|
||||
|
||||
// Handle manually
|
||||
if (action == topoSetSource::INVERT)
|
||||
{
|
||||
cellsToSelect.invert(mesh.nCells());
|
||||
continue;
|
||||
}
|
||||
|
||||
auto source = topoSetCellSource::New
|
||||
(
|
||||
dict.get<word>("source"),
|
||||
mesh,
|
||||
dict.optionalSubDict("sourceInfo")
|
||||
);
|
||||
source->verbose(false);
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case topoSetSource::ADD:
|
||||
case topoSetSource::SUBTRACT:
|
||||
source->applyToSet(action, cellsToSelect);
|
||||
break;
|
||||
|
||||
case topoSetSource::SUBSET:
|
||||
{
|
||||
cellBitSet other(mesh, false);
|
||||
source->applyToSet(topoSetSource::NEW, other);
|
||||
|
||||
cellsToSelect.subset(other);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Should already have been caught
|
||||
WarningInFunction
|
||||
<< "Ignoring unhandled action '"
|
||||
<< actionNames[action] << "'" << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
subsetter.setCellSubset(cellsToSelect.addressing());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Foam::labelList Foam::functionObjects::vtkWrite::getSelectedPatches
|
||||
(
|
||||
const polyBoundaryMesh& patches
|
||||
) const
|
||||
{
|
||||
DynamicList<label> patchIDs(patches.size());
|
||||
|
||||
for (const polyPatch& pp : patches)
|
||||
{
|
||||
if (isType<emptyPolyPatch>(pp))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (isType<processorPolyPatch>(pp))
|
||||
{
|
||||
break; // No processor patches
|
||||
}
|
||||
|
||||
if
|
||||
(
|
||||
selectPatches_.size()
|
||||
? selectPatches_.match(pp.name())
|
||||
: true
|
||||
)
|
||||
{
|
||||
patchIDs.append(pp.index());
|
||||
}
|
||||
}
|
||||
|
||||
return patchIDs.shrink();
|
||||
}
|
||||
|
||||
|
||||
bool Foam::functionObjects::vtkWrite::update()
|
||||
{
|
||||
if
|
||||
(
|
||||
meshState_ == polyMesh::UNCHANGED
|
||||
&& !meshSubsets_.empty()
|
||||
&& !vtuMappings_.empty()
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
meshSubsets_.resize(meshes_.size());
|
||||
vtuMappings_.resize(meshes_.size());
|
||||
|
||||
label regioni = 0;
|
||||
for (const word& regionName : meshes_.sortedToc())
|
||||
{
|
||||
const fvMesh& mesh = *(meshes_[regionName]);
|
||||
|
||||
if (meshSubsets_.set(regioni))
|
||||
{
|
||||
meshSubsets_.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mesh subsetting, or pass through
|
||||
meshSubsets_.set(regioni, new fvMeshSubset(mesh));
|
||||
}
|
||||
|
||||
if (vtuMappings_.set(regioni))
|
||||
{
|
||||
// Trigger change for vtk cells too
|
||||
vtuMappings_[regioni].clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// VTU sizing and decomposition information
|
||||
vtuMappings_.set
|
||||
(
|
||||
regioni,
|
||||
new vtk::vtuCells(writeOpts_, decompose_)
|
||||
);
|
||||
}
|
||||
|
||||
++regioni;
|
||||
}
|
||||
|
||||
for (auto& subsetter : meshSubsets_)
|
||||
{
|
||||
updateSubset(subsetter);
|
||||
}
|
||||
|
||||
meshState_ = polyMesh::UNCHANGED;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::functionObjects::vtkWrite::readSelection(const dictionary& dict)
|
||||
{
|
||||
meshSubsets_.clear();
|
||||
vtuMappings_.clear();
|
||||
meshState_ = polyMesh::TOPO_CHANGE;
|
||||
|
||||
// All possible meshes
|
||||
meshes_ = time_.lookupClass<fvMesh>();
|
||||
|
||||
selectRegions_.clear();
|
||||
dict.readIfPresent("regions", selectRegions_);
|
||||
|
||||
if (selectRegions_.empty())
|
||||
{
|
||||
selectRegions_.resize(1);
|
||||
selectRegions_.first() =
|
||||
dict.lookupOrDefault<word>("region", polyMesh::defaultRegion);
|
||||
}
|
||||
|
||||
// Restrict to specified meshes
|
||||
meshes_.filterKeys(selectRegions_);
|
||||
|
||||
if (meshes_.empty())
|
||||
{
|
||||
WarningInFunction
|
||||
<< "No mesh regions selected for function object " << name()
|
||||
<< nl;
|
||||
}
|
||||
|
||||
selectPatches_.clear();
|
||||
dict.readIfPresent("patches", selectPatches_);
|
||||
|
||||
selectFields_.clear();
|
||||
dict.readEntry("fields", selectFields_);
|
||||
selectFields_.uniq();
|
||||
|
||||
// Actions to define selection
|
||||
selection_ = dict.subOrEmptyDict("selection");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Foam::functionObjects::vtkWrite::updateMesh(const mapPolyMesh&)
|
||||
{
|
||||
meshState_ = polyMesh::TOPO_CHANGE;
|
||||
}
|
||||
|
||||
|
||||
void Foam::functionObjects::vtkWrite::movePoints(const polyMesh&)
|
||||
{
|
||||
// Only move to worse states
|
||||
if (meshState_ == polyMesh::UNCHANGED)
|
||||
{
|
||||
meshState_ = polyMesh::POINTS_MOVED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -52,4 +52,9 @@ maxDi 10.0;
|
||||
|
||||
adjustTimeStep yes;
|
||||
|
||||
functions
|
||||
{
|
||||
#include "vtkWrite"
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
// -*- C++ -*-
|
||||
// Use the vtkWrite function object
|
||||
|
||||
vtkWrite
|
||||
{
|
||||
type vtkWrite;
|
||||
libs ("libutilityFunctionObjects.so");
|
||||
log true;
|
||||
|
||||
writeControl writeTime;
|
||||
writeInterval 1;
|
||||
|
||||
// Fields to output (words or regex)
|
||||
regions (".*");
|
||||
|
||||
internal true;
|
||||
|
||||
boundary true;
|
||||
|
||||
single false;
|
||||
|
||||
interpolate true;
|
||||
|
||||
// Fields to output (words or regex)
|
||||
fields (".*");
|
||||
|
||||
//- Output format (ascii | binary) - Default=binary
|
||||
// format binary;
|
||||
|
||||
//- Use legacy output format - Default=false
|
||||
// legacy false;
|
||||
|
||||
//- Output directory name - Default="postProcessing/<name>"
|
||||
// directory "VTK";
|
||||
|
||||
//- Write cell ids as field - Default=true
|
||||
writeIds false;
|
||||
}
|
||||
|
||||
|
||||
// Solid walls only
|
||||
walls
|
||||
{
|
||||
type vtkWrite;
|
||||
libs ("libutilityFunctionObjects.so");
|
||||
log true;
|
||||
|
||||
writeControl writeTime;
|
||||
writeInterval 1;
|
||||
|
||||
internal false;
|
||||
|
||||
// single true;
|
||||
|
||||
regions ( heater "(?i).*solid" );
|
||||
patches ( "(?i).*solid_to.*" "heater.*(Air|Water)" );
|
||||
|
||||
fields (T);
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -15,15 +15,69 @@ vtkWrite
|
||||
//- Use legacy output format - Default=false
|
||||
// legacy false;
|
||||
|
||||
//- Output directory name - Default="VTK"
|
||||
//- Output directory name - Default="postProcessing/<name>"
|
||||
// directory "VTK";
|
||||
|
||||
//- Write cell ids as field - Default=true
|
||||
writeIds false;
|
||||
writeIds false;
|
||||
|
||||
//- Write more frequent than fields
|
||||
writeControl timeStep;
|
||||
writeInterval 25;
|
||||
}
|
||||
|
||||
subset
|
||||
{
|
||||
type vtkWrite;
|
||||
libs ("libutilityFunctionObjects.so");
|
||||
log true;
|
||||
|
||||
// boundary false;
|
||||
|
||||
interpolate true;
|
||||
|
||||
// Fields to output (words or regex)
|
||||
fields (U p);
|
||||
|
||||
//- Write cell ids as field - Default=true
|
||||
writeIds false;
|
||||
|
||||
//- Write more frequent than fields
|
||||
writeControl timeStep;
|
||||
writeInterval 25;
|
||||
|
||||
// Region of interest
|
||||
selection
|
||||
{
|
||||
dome
|
||||
{
|
||||
action add;
|
||||
source sphere;
|
||||
origin (125 100 0);
|
||||
radius 100;
|
||||
}
|
||||
cylinder
|
||||
{
|
||||
action subtract;
|
||||
source cylinder;
|
||||
p1 (125 100 0);
|
||||
p2 (125 100 100);
|
||||
radius 20;
|
||||
}
|
||||
outlet
|
||||
{
|
||||
action add;
|
||||
source box;
|
||||
box (300 -100 -100) (330 250 100);
|
||||
}
|
||||
clipping
|
||||
{
|
||||
action subset;
|
||||
source box;
|
||||
box (-1000 -1000 -1000) (1000 1000 50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
Reference in New Issue
Block a user