mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: improvements for ensightWrite function object (issue #926)
- align input parameters and some of the behaviour with vtkWrite The output is now postProcessing/<name> for similar reasoning as mentioned in #866 - better alignment with other function objects, no data collision with foamToEnsight output. - separate controls for internal and boundary meshes - can restrict conversion based on zone names, enclosing volumes, bounding box.
This commit is contained in:
@ -1,7 +1,10 @@
|
|||||||
abort/abort.C
|
abort/abort.C
|
||||||
|
|
||||||
codedFunctionObject/codedFunctionObject.C
|
codedFunctionObject/codedFunctionObject.C
|
||||||
|
|
||||||
ensightWrite/ensightWrite.C
|
ensightWrite/ensightWrite.C
|
||||||
|
ensightWrite/ensightWriteUpdate.C
|
||||||
|
|
||||||
vtkWrite/vtkWrite.C
|
vtkWrite/vtkWrite.C
|
||||||
vtkWrite/vtkWriteUpdate.C
|
vtkWrite/vtkWriteUpdate.C
|
||||||
|
|
||||||
|
|||||||
@ -47,50 +47,21 @@ namespace functionObjects
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
Foam::bitSet Foam::functionObjects::ensightWrite::cellSelection() const
|
Foam::label Foam::functionObjects::ensightWrite::writeAllVolFields
|
||||||
|
(
|
||||||
|
const fvMeshSubset& proxy,
|
||||||
|
const wordHashSet& acceptField
|
||||||
|
)
|
||||||
{
|
{
|
||||||
bitSet cellsToSelect;
|
label count = 0;
|
||||||
|
|
||||||
// Could also deal with cellZones here, as required
|
count += writeVolFields<scalar>(proxy, acceptField);
|
||||||
|
count += writeVolFields<vector>(proxy, acceptField);
|
||||||
|
count += writeVolFields<sphericalTensor>(proxy, acceptField);
|
||||||
|
count += writeVolFields<symmTensor>(proxy, acceptField);
|
||||||
|
count += writeVolFields<tensor>(proxy, acceptField);
|
||||||
|
|
||||||
if (bounds_.empty())
|
return count;
|
||||||
{
|
|
||||||
return cellsToSelect;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const auto& cellCentres = static_cast<const fvMesh&>(mesh_).C();
|
|
||||||
|
|
||||||
const label len = mesh_.nCells();
|
|
||||||
|
|
||||||
cellsToSelect.resize(len);
|
|
||||||
|
|
||||||
for (label celli=0; celli < len; ++celli)
|
|
||||||
{
|
|
||||||
const point& cc = cellCentres[celli];
|
|
||||||
|
|
||||||
if (bounds_.contains(cc))
|
|
||||||
{
|
|
||||||
cellsToSelect.set(celli);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cellsToSelect;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int Foam::functionObjects::ensightWrite::process(const word& fieldName)
|
|
||||||
{
|
|
||||||
int state = 0;
|
|
||||||
|
|
||||||
writeVolField<scalar>(fieldName, state);
|
|
||||||
writeVolField<vector>(fieldName, state);
|
|
||||||
writeVolField<sphericalTensor>(fieldName, state);
|
|
||||||
writeVolField<symmTensor>(fieldName, state);
|
|
||||||
writeVolField<tensor>(fieldName, state);
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -115,19 +86,24 @@ Foam::functionObjects::ensightWrite::ensightWrite
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
caseOpts_(writeOpts_.format()),
|
caseOpts_(writeOpts_.format()),
|
||||||
selectFields_(),
|
outputDir_(),
|
||||||
dirName_("ensightWrite"),
|
|
||||||
consecutive_(false),
|
consecutive_(false),
|
||||||
bounds_()
|
meshState_(polyMesh::TOPO_CHANGE),
|
||||||
|
selectFields_(),
|
||||||
|
selection_(),
|
||||||
|
meshSubset_(mesh_),
|
||||||
|
ensCase_(nullptr),
|
||||||
|
ensMesh_(nullptr)
|
||||||
{
|
{
|
||||||
if (postProcess)
|
// May still want this? (OCT-2018)
|
||||||
{
|
// if (postProcess)
|
||||||
// Disable for post-process mode.
|
// {
|
||||||
// Emit as FatalError for the try/catch in the caller.
|
// // Disable for post-process mode.
|
||||||
FatalError
|
// // Emit as FatalError for the try/catch in the caller.
|
||||||
<< type() << " disabled in post-process mode"
|
// FatalError
|
||||||
<< exit(FatalError);
|
// << type() << " disabled in post-process mode"
|
||||||
}
|
// << exit(FatalError);
|
||||||
|
// }
|
||||||
|
|
||||||
read(dict);
|
read(dict);
|
||||||
}
|
}
|
||||||
@ -139,16 +115,29 @@ bool Foam::functionObjects::ensightWrite::read(const dictionary& dict)
|
|||||||
{
|
{
|
||||||
fvMeshFunctionObject::read(dict);
|
fvMeshFunctionObject::read(dict);
|
||||||
|
|
||||||
// Ensure consistency
|
readSelection(dict);
|
||||||
|
|
||||||
meshSubset_.clear();
|
|
||||||
ensMesh_.clear();
|
|
||||||
|
|
||||||
|
|
||||||
//
|
// Writer options
|
||||||
// writer options
|
|
||||||
//
|
consecutive_ = dict.lookupOrDefault("consecutive", false);
|
||||||
writeOpts_.noPatches(dict.lookupOrDefault("noPatches", false));
|
|
||||||
|
writeOpts_.useBoundaryMesh(dict.lookupOrDefault("boundary", true));
|
||||||
|
writeOpts_.useInternalMesh(dict.lookupOrDefault("internal", true));
|
||||||
|
|
||||||
|
|
||||||
|
// Warn if noPatches keyword (1806) exists and contradicts our settings
|
||||||
|
// Cannot readily use Compat since the boolean has the opposite value.
|
||||||
|
if
|
||||||
|
(
|
||||||
|
dict.lookupOrDefault("noPatches", false)
|
||||||
|
&& writeOpts_.useBoundaryMesh()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
WarningInFunction
|
||||||
|
<< "Use 'boundary' instead of 'noPatches' to enable/disable "
|
||||||
|
<< "conversion of the boundaries" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
wordRes list;
|
wordRes list;
|
||||||
if (dict.readIfPresent("patches", list))
|
if (dict.readIfPresent("patches", list))
|
||||||
@ -164,33 +153,35 @@ bool Foam::functionObjects::ensightWrite::read(const dictionary& dict)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bounds_.clear();
|
// Case options
|
||||||
dict.readIfPresent("bounds", bounds_);
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// case options
|
|
||||||
//
|
|
||||||
|
|
||||||
caseOpts_.nodeValues(dict.lookupOrDefault("nodeValues", false));
|
caseOpts_.nodeValues(dict.lookupOrDefault("nodeValues", false));
|
||||||
|
|
||||||
caseOpts_.width(dict.lookupOrDefault<label>("width", 8));
|
caseOpts_.width(dict.lookupOrDefault<label>("width", 8));
|
||||||
|
|
||||||
// remove existing output directory
|
|
||||||
caseOpts_.overwrite(dict.lookupOrDefault("overwrite", false));
|
caseOpts_.overwrite(dict.lookupOrDefault("overwrite", false));
|
||||||
|
|
||||||
//
|
|
||||||
// other options
|
|
||||||
//
|
|
||||||
dict.readIfPresent("directory", dirName_);
|
|
||||||
consecutive_ = dict.lookupOrDefault("consecutive", false);
|
|
||||||
|
|
||||||
|
// Output directory
|
||||||
|
|
||||||
//
|
outputDir_.clear();
|
||||||
// output fields
|
dict.readIfPresent("directory", outputDir_);
|
||||||
//
|
|
||||||
dict.readEntry("fields", selectFields_);
|
const Time& time_ = obr_.time();
|
||||||
selectFields_.uniq();
|
|
||||||
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@ -208,24 +199,9 @@ bool Foam::functionObjects::ensightWrite::write()
|
|||||||
|
|
||||||
if (!ensCase_.valid())
|
if (!ensCase_.valid())
|
||||||
{
|
{
|
||||||
// Define sub-directory name to use for EnSight data.
|
|
||||||
// The path to the ensight directory is at case level only
|
|
||||||
// - For parallel cases, data only written from master
|
|
||||||
|
|
||||||
fileName ensightDir = dirName_;
|
|
||||||
if (!ensightDir.isAbsolute())
|
|
||||||
{
|
|
||||||
ensightDir = t.globalPath()/ensightDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
ensCase_.reset
|
ensCase_.reset
|
||||||
(
|
(
|
||||||
new ensightCase
|
new ensightCase(outputDir_, t.globalCaseName(), caseOpts_)
|
||||||
(
|
|
||||||
ensightDir,
|
|
||||||
t.globalCaseName(),
|
|
||||||
caseOpts_
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,37 +214,8 @@ bool Foam::functionObjects::ensightWrite::write()
|
|||||||
ensCase().setTime(t.value(), t.timeIndex());
|
ensCase().setTime(t.value(), t.timeIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeGeom = false;
|
|
||||||
if (!ensMesh_.valid())
|
|
||||||
{
|
|
||||||
writeGeom = true;
|
|
||||||
|
|
||||||
bitSet selection = this->cellSelection();
|
if (update())
|
||||||
|
|
||||||
if (returnReduce(!selection.empty(), orOp<bool>()))
|
|
||||||
{
|
|
||||||
meshSubset_.clear();
|
|
||||||
meshSubset_.reset(new fvMeshSubset(mesh_, selection));
|
|
||||||
ensMesh_.reset
|
|
||||||
(
|
|
||||||
new ensightMesh(meshSubset_->subMesh(), writeOpts_)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ensMesh_.reset
|
|
||||||
(
|
|
||||||
new ensightMesh(mesh_, writeOpts_)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ensMesh_().needsUpdate())
|
|
||||||
{
|
|
||||||
writeGeom = true;
|
|
||||||
ensMesh_().correct();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writeGeom)
|
|
||||||
{
|
{
|
||||||
// Treat all geometry as moving, since we do not know a priori
|
// Treat all geometry as moving, since we do not know a priori
|
||||||
// if the simulation has mesh motion later on.
|
// if the simulation has mesh motion later on.
|
||||||
@ -276,47 +223,19 @@ bool Foam::functionObjects::ensightWrite::write()
|
|||||||
ensMesh_().write(os);
|
ensMesh_().write(os);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wordHashSet acceptField(mesh_.names<void>(selectFields_));
|
||||||
|
|
||||||
|
// Prune restart fields
|
||||||
|
acceptField.filterKeys
|
||||||
|
(
|
||||||
|
[](const word& k){ return k.endsWith("_0"); },
|
||||||
|
true // prune
|
||||||
|
);
|
||||||
|
|
||||||
Log << type() << " " << name() << " write: (";
|
Log << type() << " " << name() << " write: (";
|
||||||
|
writeAllVolFields(meshSubset_, acceptField);
|
||||||
|
|
||||||
wordHashSet candidates(subsetStrings(selectFields_, mesh_.names()));
|
Log << " )" << nl;
|
||||||
DynamicList<word> missing(selectFields_.size());
|
|
||||||
DynamicList<word> ignored(selectFields_.size());
|
|
||||||
|
|
||||||
// Check exact matches first
|
|
||||||
for (const wordRe& select : selectFields_)
|
|
||||||
{
|
|
||||||
if (select.isLiteral())
|
|
||||||
{
|
|
||||||
const word& fieldName = select;
|
|
||||||
|
|
||||||
if (!candidates.erase(fieldName))
|
|
||||||
{
|
|
||||||
missing.append(fieldName);
|
|
||||||
}
|
|
||||||
else if (process(fieldName) < 1)
|
|
||||||
{
|
|
||||||
ignored.append(fieldName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const word& cand : candidates)
|
|
||||||
{
|
|
||||||
process(cand);
|
|
||||||
}
|
|
||||||
|
|
||||||
Log << " )" << endl;
|
|
||||||
|
|
||||||
if (missing.size())
|
|
||||||
{
|
|
||||||
WarningInFunction
|
|
||||||
<< "Missing field " << missing << endl;
|
|
||||||
}
|
|
||||||
if (ignored.size())
|
|
||||||
{
|
|
||||||
WarningInFunction
|
|
||||||
<< "Unprocessed field " << ignored << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
ensCase().write(); // Flush case information
|
ensCase().write(); // Flush case information
|
||||||
|
|
||||||
@ -330,40 +249,4 @@ bool Foam::functionObjects::ensightWrite::end()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Foam::functionObjects::ensightWrite::updateMesh(const mapPolyMesh& mpm)
|
|
||||||
{
|
|
||||||
// fvMeshFunctionObject::updateMesh(mpm);
|
|
||||||
|
|
||||||
// This is heavy-handed, but with a bounding-box limited sub-mesh,
|
|
||||||
// we don't readily know if the updates affect the subsetted mesh.
|
|
||||||
if (!bounds_.empty())
|
|
||||||
{
|
|
||||||
ensMesh_.clear();
|
|
||||||
meshSubset_.clear();
|
|
||||||
}
|
|
||||||
else if (ensMesh_.valid())
|
|
||||||
{
|
|
||||||
ensMesh_->expire();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::functionObjects::ensightWrite::movePoints(const polyMesh& mpm)
|
|
||||||
{
|
|
||||||
// fvMeshFunctionObject::updateMesh(mpm);
|
|
||||||
|
|
||||||
// This is heavy-handed, but with a bounding-box limited sub-mesh,
|
|
||||||
// we don't readily know if the updates affect the subsetted mesh.
|
|
||||||
if (!bounds_.empty())
|
|
||||||
{
|
|
||||||
ensMesh_.clear();
|
|
||||||
meshSubset_.clear();
|
|
||||||
}
|
|
||||||
else if (ensMesh_.valid())
|
|
||||||
{
|
|
||||||
ensMesh_->expire();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
// ************************************************************************* //
|
||||||
|
|||||||
@ -42,36 +42,80 @@ Description
|
|||||||
|
|
||||||
overwrite true;
|
overwrite true;
|
||||||
width 12;
|
width 12;
|
||||||
directory "EnSight";
|
|
||||||
|
|
||||||
fields
|
fields (U p);
|
||||||
(
|
|
||||||
U
|
selection
|
||||||
p
|
{
|
||||||
);
|
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
|
\endverbatim
|
||||||
|
|
||||||
\heading Function object usage
|
\heading Basic Usage
|
||||||
\table
|
\table
|
||||||
Property | Description | Required | Default value
|
Property | Description | Required | Default
|
||||||
type | Type name: ensightWrite | yes |
|
type | Type name: ensightWrite | yes |
|
||||||
fields | Fields to output | yes |
|
fields | Fields to output | yes |
|
||||||
writeControl | Output control | recommended | timeStep
|
boundary | Convert boundary fields | no | true
|
||||||
directory | The output directory name | no | "ensightWrite"
|
internal | Convert internal fields | no | true
|
||||||
overwrite | Remove existing directory | no | false
|
|
||||||
format | Either ascii or binary | no | same as simulation
|
|
||||||
width | Mask width for \c data/XXXX | no | 8
|
|
||||||
noPatches | Suppress writing patches | no | false
|
|
||||||
patches | Select patches to write | no |
|
|
||||||
faceZones | Select faceZones to write | no |
|
|
||||||
consecutive | Consecutive output numbering | no | false
|
|
||||||
nodeValues | Write values at nodes | no | false
|
nodeValues | Write values at nodes | no | false
|
||||||
bounds | Limit with a bounding box | no |
|
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
Note that if the \c patches entry is an empty list, this will select all
|
\heading Ensight Output Options
|
||||||
patches and suppress writing the internalMesh.
|
\table
|
||||||
|
Property | Description | Required | Default
|
||||||
|
format | ascii or binary format | no | same as simulation
|
||||||
|
width | Mask width for \c data/XXXX | no | 8
|
||||||
|
directory | The output directory name | no | postProcessing/NAME
|
||||||
|
overwrite | Remove existing directory | no | false
|
||||||
|
consecutive | Consecutive output numbering | no | false
|
||||||
|
nodeValues | Write values at nodes | no | false
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
\heading Output Selection
|
||||||
|
\table
|
||||||
|
Property | Description | Required | Default
|
||||||
|
region | Name for a single region | no | region0
|
||||||
|
faceZones | Select faceZones to write | 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.
|
||||||
|
|
||||||
Consecutive output numbering can be used in conjunction with \c overwrite.
|
Consecutive output numbering can be used in conjunction with \c overwrite.
|
||||||
|
|
||||||
See also
|
See also
|
||||||
@ -94,8 +138,9 @@ SourceFiles
|
|||||||
|
|
||||||
#include "interpolation.H"
|
#include "interpolation.H"
|
||||||
#include "volFields.H"
|
#include "volFields.H"
|
||||||
#include "fvMeshSubset.H"
|
|
||||||
#include "surfaceFields.H"
|
#include "surfaceFields.H"
|
||||||
|
#include "fvMeshSubsetProxy.H"
|
||||||
|
#include "searchableSurfaces.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -118,24 +163,29 @@ class ensightWrite
|
|||||||
{
|
{
|
||||||
// Private data
|
// Private data
|
||||||
|
|
||||||
//- Writer options
|
//- Ensight writer options
|
||||||
ensightMesh::options writeOpts_;
|
ensightMesh::options writeOpts_;
|
||||||
|
|
||||||
|
//- Ensight case options
|
||||||
ensightCase::options caseOpts_;
|
ensightCase::options caseOpts_;
|
||||||
|
|
||||||
//- Name of fields to process
|
//- The output directory
|
||||||
wordRes selectFields_;
|
fileName outputDir_;
|
||||||
|
|
||||||
//- Output directory name
|
|
||||||
fileName dirName_;
|
|
||||||
|
|
||||||
//- Consecutive output numbering
|
//- Consecutive output numbering
|
||||||
bool consecutive_;
|
bool consecutive_;
|
||||||
|
|
||||||
//- Restrict to bounding box
|
//- Track changes in mesh geometry
|
||||||
boundBox bounds_;
|
enum polyMesh::readUpdateState meshState_;
|
||||||
|
|
||||||
|
//- Requested names of fields to process
|
||||||
|
wordRes selectFields_;
|
||||||
|
|
||||||
|
//- Dictionary of volume selections
|
||||||
|
dictionary selection_;
|
||||||
|
|
||||||
//- Mesh subset handler
|
//- Mesh subset handler
|
||||||
autoPtr<fvMeshSubset> meshSubset_;
|
fvMeshSubset meshSubset_;
|
||||||
|
|
||||||
//- Ensight case handler
|
//- Ensight case handler
|
||||||
autoPtr<ensightCase> ensCase_;
|
autoPtr<ensightCase> ensCase_;
|
||||||
@ -158,16 +208,34 @@ class ensightWrite
|
|||||||
return *ensMesh_;
|
return *ensMesh_;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Define cell selection from bounding box.
|
|
||||||
// An empty set if no bounding box is specified.
|
|
||||||
bitSet cellSelection() const;
|
|
||||||
|
|
||||||
//- Apply for the volume field type
|
//- Update mesh subset according to zones, geometry, bounds
|
||||||
|
bool updateSubset(fvMeshSubset& subsetter) const;
|
||||||
|
|
||||||
|
//- Read information for selections
|
||||||
|
bool readSelection(const dictionary& dict);
|
||||||
|
|
||||||
|
//- Update meshes, subMeshes etc.
|
||||||
|
bool update();
|
||||||
|
|
||||||
|
|
||||||
|
// Write
|
||||||
|
|
||||||
|
//- Write all volume fields
|
||||||
|
label writeAllVolFields
|
||||||
|
(
|
||||||
|
const fvMeshSubset& proxy,
|
||||||
|
const wordHashSet& acceptField
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Write selected volume fields.
|
||||||
template<class Type>
|
template<class Type>
|
||||||
int writeVolField(const word& inputName, int& state);
|
label writeVolFields
|
||||||
|
(
|
||||||
|
const fvMeshSubset& proxy,
|
||||||
|
const wordHashSet& acceptField
|
||||||
|
);
|
||||||
|
|
||||||
//- Process by trying to apply for various volume field types.
|
|
||||||
int process(const word& inputName);
|
|
||||||
|
|
||||||
//- No copy construct
|
//- No copy construct
|
||||||
ensightWrite(const ensightWrite&) = delete;
|
ensightWrite(const ensightWrite&) = delete;
|
||||||
|
|||||||
@ -23,65 +23,51 @@ License
|
|||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "Time.H"
|
|
||||||
#include "ensightOutput.H"
|
#include "ensightOutput.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
int Foam::functionObjects::ensightWrite::writeVolField
|
Foam::label Foam::functionObjects::ensightWrite::writeVolFields
|
||||||
(
|
(
|
||||||
const word& inputName,
|
const fvMeshSubset& proxy,
|
||||||
int& state
|
const wordHashSet& acceptField
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// State: return 0 (not-processed), -1 (skip), +1 ok
|
typedef GeometricField<Type, fvPatchField, volMesh> GeoField;
|
||||||
typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
|
|
||||||
|
|
||||||
// Already done
|
const fvMesh& baseMesh = proxy.baseMesh();
|
||||||
if (state)
|
|
||||||
|
label count = 0;
|
||||||
|
|
||||||
|
for (const word& fieldName : baseMesh.sortedNames<GeoField>(acceptField))
|
||||||
{
|
{
|
||||||
return state;
|
const auto* fieldptr = baseMesh.findObject<GeoField>(fieldName);
|
||||||
|
|
||||||
|
if (!fieldptr)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VolFieldType* fldPtr = findObject<VolFieldType>(inputName);
|
auto tfield = fvMeshSubsetProxy::interpolate(proxy, *fieldptr);
|
||||||
|
const auto& field = tfield();
|
||||||
|
|
||||||
// Not available
|
autoPtr<ensightFile> os = ensCase().newData<Type>(fieldName);
|
||||||
if (!fldPtr)
|
|
||||||
{
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
autoPtr<ensightFile> os = ensCase().newData<Type>(inputName);
|
|
||||||
|
|
||||||
|
|
||||||
if (meshSubset_.valid())
|
|
||||||
{
|
|
||||||
tmp<VolFieldType> tfield = meshSubset_->interpolate(*fldPtr);
|
|
||||||
|
|
||||||
ensightOutput::writeField<Type>
|
ensightOutput::writeField<Type>
|
||||||
(
|
(
|
||||||
tfield(),
|
field,
|
||||||
ensMesh(),
|
|
||||||
os,
|
|
||||||
caseOpts_.nodeValues()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ensightOutput::writeField<Type>
|
|
||||||
(
|
|
||||||
*fldPtr,
|
|
||||||
ensMesh(),
|
ensMesh(),
|
||||||
os,
|
os,
|
||||||
caseOpts_.nodeValues()
|
caseOpts_.nodeValues()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Log << ' ' << fieldName;
|
||||||
|
|
||||||
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log << " " << inputName;
|
return count;
|
||||||
|
|
||||||
state = +1;
|
|
||||||
return state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
235
src/functionObjects/utilities/ensightWrite/ensightWriteUpdate.C
Normal file
235
src/functionObjects/utilities/ensightWrite/ensightWriteUpdate.C
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / 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 "ensightWrite.H"
|
||||||
|
#include "dictionary.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::ensightWrite::updateSubset
|
||||||
|
(
|
||||||
|
fvMeshSubset& subsetter
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
if (selection_.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fvMesh& mesh = subsetter.baseMesh();
|
||||||
|
|
||||||
|
// Start with all cells unselected
|
||||||
|
cellBitSet cellsToSelect(mesh, false);
|
||||||
|
|
||||||
|
// Execute all actions
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
Foam::labelList Foam::functionObjects::ensightWrite::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();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::functionObjects::ensightWrite::update()
|
||||||
|
{
|
||||||
|
if (meshState_ == polyMesh::UNCHANGED)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is heavy-handed, but with a bounding-box limited sub-mesh,
|
||||||
|
// we don't readily know if the updates affect the subsetted mesh.
|
||||||
|
|
||||||
|
// if (meshSubset_.hasSubMesh())
|
||||||
|
// {
|
||||||
|
// ensMesh_.clear();
|
||||||
|
// meshSubset_.clear();
|
||||||
|
// }
|
||||||
|
// else if (ensMesh_.valid())
|
||||||
|
// {
|
||||||
|
// ensMesh_->expire();
|
||||||
|
// }
|
||||||
|
|
||||||
|
meshSubset_.clear();
|
||||||
|
|
||||||
|
updateSubset(meshSubset_);
|
||||||
|
|
||||||
|
meshState_ = polyMesh::UNCHANGED;
|
||||||
|
|
||||||
|
if (!ensMesh_.valid())
|
||||||
|
{
|
||||||
|
ensMesh_.reset(new ensightMesh(meshSubset_.mesh(), writeOpts_));
|
||||||
|
}
|
||||||
|
else if (ensMesh_().needsUpdate())
|
||||||
|
{
|
||||||
|
ensMesh_().correct();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
bool Foam::functionObjects::ensightWrite::readSelection(const dictionary& dict)
|
||||||
|
{
|
||||||
|
// Ensure consistency
|
||||||
|
ensMesh_.clear();
|
||||||
|
|
||||||
|
meshSubset_.clear();
|
||||||
|
meshState_ = polyMesh::TOPO_CHANGE;
|
||||||
|
|
||||||
|
selectFields_.clear();
|
||||||
|
dict.readEntry("fields", selectFields_);
|
||||||
|
selectFields_.uniq();
|
||||||
|
|
||||||
|
// Actions to define selection
|
||||||
|
selection_ = dict.subOrEmptyDict("selection");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::functionObjects::ensightWrite::updateMesh(const mapPolyMesh&)
|
||||||
|
{
|
||||||
|
meshState_ = polyMesh::TOPO_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::functionObjects::ensightWrite::movePoints(const polyMesh&)
|
||||||
|
{
|
||||||
|
// Only move to worse states
|
||||||
|
if (meshState_ == polyMesh::UNCHANGED)
|
||||||
|
{
|
||||||
|
meshState_ = polyMesh::POINTS_MOVED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
Reference in New Issue
Block a user