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:
parent
4f2ec88d24
commit
8cff734abc
@ -1,7 +1,10 @@
|
||||
abort/abort.C
|
||||
|
||||
codedFunctionObject/codedFunctionObject.C
|
||||
|
||||
ensightWrite/ensightWrite.C
|
||||
ensightWrite/ensightWriteUpdate.C
|
||||
|
||||
vtkWrite/vtkWrite.C
|
||||
vtkWrite/vtkWriteUpdate.C
|
||||
|
||||
|
@ -47,50 +47,21 @@ namespace functionObjects
|
||||
|
||||
// * * * * * * * * * * * * * 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 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;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
@ -115,19 +86,24 @@ Foam::functionObjects::ensightWrite::ensightWrite
|
||||
)
|
||||
),
|
||||
caseOpts_(writeOpts_.format()),
|
||||
selectFields_(),
|
||||
dirName_("ensightWrite"),
|
||||
outputDir_(),
|
||||
consecutive_(false),
|
||||
bounds_()
|
||||
meshState_(polyMesh::TOPO_CHANGE),
|
||||
selectFields_(),
|
||||
selection_(),
|
||||
meshSubset_(mesh_),
|
||||
ensCase_(nullptr),
|
||||
ensMesh_(nullptr)
|
||||
{
|
||||
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);
|
||||
}
|
||||
@ -139,16 +115,29 @@ bool Foam::functionObjects::ensightWrite::read(const dictionary& dict)
|
||||
{
|
||||
fvMeshFunctionObject::read(dict);
|
||||
|
||||
// Ensure consistency
|
||||
|
||||
meshSubset_.clear();
|
||||
ensMesh_.clear();
|
||||
readSelection(dict);
|
||||
|
||||
|
||||
//
|
||||
// writer options
|
||||
//
|
||||
writeOpts_.noPatches(dict.lookupOrDefault("noPatches", false));
|
||||
// Writer options
|
||||
|
||||
consecutive_ = dict.lookupOrDefault("consecutive", 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;
|
||||
if (dict.readIfPresent("patches", list))
|
||||
@ -164,33 +153,35 @@ bool Foam::functionObjects::ensightWrite::read(const dictionary& dict)
|
||||
}
|
||||
|
||||
|
||||
bounds_.clear();
|
||||
dict.readIfPresent("bounds", bounds_);
|
||||
|
||||
|
||||
//
|
||||
// case options
|
||||
//
|
||||
// Case options
|
||||
|
||||
caseOpts_.nodeValues(dict.lookupOrDefault("nodeValues", false));
|
||||
|
||||
caseOpts_.width(dict.lookupOrDefault<label>("width", 8));
|
||||
|
||||
// remove existing output directory
|
||||
caseOpts_.overwrite(dict.lookupOrDefault("overwrite", false));
|
||||
|
||||
//
|
||||
// other options
|
||||
//
|
||||
dict.readIfPresent("directory", dirName_);
|
||||
consecutive_ = dict.lookupOrDefault("consecutive", false);
|
||||
|
||||
// Output directory
|
||||
|
||||
//
|
||||
// output fields
|
||||
//
|
||||
dict.readEntry("fields", selectFields_);
|
||||
selectFields_.uniq();
|
||||
outputDir_.clear();
|
||||
dict.readIfPresent("directory", outputDir_);
|
||||
|
||||
const Time& time_ = obr_.time();
|
||||
|
||||
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;
|
||||
}
|
||||
@ -208,24 +199,9 @@ bool Foam::functionObjects::ensightWrite::write()
|
||||
|
||||
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
|
||||
(
|
||||
new ensightCase
|
||||
(
|
||||
ensightDir,
|
||||
t.globalCaseName(),
|
||||
caseOpts_
|
||||
)
|
||||
new ensightCase(outputDir_, t.globalCaseName(), caseOpts_)
|
||||
);
|
||||
}
|
||||
|
||||
@ -238,37 +214,8 @@ bool Foam::functionObjects::ensightWrite::write()
|
||||
ensCase().setTime(t.value(), t.timeIndex());
|
||||
}
|
||||
|
||||
bool writeGeom = false;
|
||||
if (!ensMesh_.valid())
|
||||
{
|
||||
writeGeom = true;
|
||||
|
||||
bitSet selection = this->cellSelection();
|
||||
|
||||
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)
|
||||
if (update())
|
||||
{
|
||||
// Treat all geometry as moving, since we do not know a priori
|
||||
// if the simulation has mesh motion later on.
|
||||
@ -276,47 +223,19 @@ bool Foam::functionObjects::ensightWrite::write()
|
||||
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: (";
|
||||
writeAllVolFields(meshSubset_, acceptField);
|
||||
|
||||
wordHashSet candidates(subsetStrings(selectFields_, mesh_.names()));
|
||||
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;
|
||||
}
|
||||
Log << " )" << nl;
|
||||
|
||||
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;
|
||||
width 12;
|
||||
directory "EnSight";
|
||||
|
||||
fields
|
||||
(
|
||||
U
|
||||
p
|
||||
);
|
||||
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
|
||||
|
||||
\heading Function object usage
|
||||
\heading Basic Usage
|
||||
\table
|
||||
Property | Description | Required | Default value
|
||||
type | Type name: ensightWrite | yes |
|
||||
fields | Fields to output | yes |
|
||||
writeControl | Output control | recommended | timeStep
|
||||
directory | The output directory name | no | "ensightWrite"
|
||||
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
|
||||
bounds | Limit with a bounding box | no |
|
||||
Property | Description | Required | Default
|
||||
type | Type name: ensightWrite | yes |
|
||||
fields | Fields to output | yes |
|
||||
boundary | Convert boundary fields | no | true
|
||||
internal | Convert internal fields | no | true
|
||||
nodeValues | Write values at nodes | no | false
|
||||
\endtable
|
||||
|
||||
Note that if the \c patches entry is an empty list, this will select all
|
||||
patches and suppress writing the internalMesh.
|
||||
\heading Ensight Output Options
|
||||
\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.
|
||||
|
||||
See also
|
||||
@ -94,8 +138,9 @@ SourceFiles
|
||||
|
||||
#include "interpolation.H"
|
||||
#include "volFields.H"
|
||||
#include "fvMeshSubset.H"
|
||||
#include "surfaceFields.H"
|
||||
#include "fvMeshSubsetProxy.H"
|
||||
#include "searchableSurfaces.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -118,24 +163,29 @@ class ensightWrite
|
||||
{
|
||||
// Private data
|
||||
|
||||
//- Writer options
|
||||
//- Ensight writer options
|
||||
ensightMesh::options writeOpts_;
|
||||
|
||||
//- Ensight case options
|
||||
ensightCase::options caseOpts_;
|
||||
|
||||
//- Name of fields to process
|
||||
wordRes selectFields_;
|
||||
|
||||
//- Output directory name
|
||||
fileName dirName_;
|
||||
//- The output directory
|
||||
fileName outputDir_;
|
||||
|
||||
//- Consecutive output numbering
|
||||
bool consecutive_;
|
||||
|
||||
//- Restrict to bounding box
|
||||
boundBox bounds_;
|
||||
//- Track changes in mesh geometry
|
||||
enum polyMesh::readUpdateState meshState_;
|
||||
|
||||
//- Requested names of fields to process
|
||||
wordRes selectFields_;
|
||||
|
||||
//- Dictionary of volume selections
|
||||
dictionary selection_;
|
||||
|
||||
//- Mesh subset handler
|
||||
autoPtr<fvMeshSubset> meshSubset_;
|
||||
fvMeshSubset meshSubset_;
|
||||
|
||||
//- Ensight case handler
|
||||
autoPtr<ensightCase> ensCase_;
|
||||
@ -158,16 +208,34 @@ class ensightWrite
|
||||
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>
|
||||
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
|
||||
ensightWrite(const ensightWrite&) = delete;
|
||||
|
@ -23,65 +23,51 @@ License
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "Time.H"
|
||||
#include "ensightOutput.H"
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class Type>
|
||||
int Foam::functionObjects::ensightWrite::writeVolField
|
||||
Foam::label Foam::functionObjects::ensightWrite::writeVolFields
|
||||
(
|
||||
const word& inputName,
|
||||
int& state
|
||||
const fvMeshSubset& proxy,
|
||||
const wordHashSet& acceptField
|
||||
)
|
||||
{
|
||||
// State: return 0 (not-processed), -1 (skip), +1 ok
|
||||
typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
|
||||
typedef GeometricField<Type, fvPatchField, volMesh> GeoField;
|
||||
|
||||
// Already done
|
||||
if (state)
|
||||
const fvMesh& baseMesh = proxy.baseMesh();
|
||||
|
||||
label count = 0;
|
||||
|
||||
for (const word& fieldName : baseMesh.sortedNames<GeoField>(acceptField))
|
||||
{
|
||||
return state;
|
||||
}
|
||||
const auto* fieldptr = baseMesh.findObject<GeoField>(fieldName);
|
||||
|
||||
const VolFieldType* fldPtr = findObject<VolFieldType>(inputName);
|
||||
if (!fieldptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Not available
|
||||
if (!fldPtr)
|
||||
{
|
||||
return state;
|
||||
}
|
||||
auto tfield = fvMeshSubsetProxy::interpolate(proxy, *fieldptr);
|
||||
const auto& field = tfield();
|
||||
|
||||
autoPtr<ensightFile> os = ensCase().newData<Type>(inputName);
|
||||
|
||||
|
||||
if (meshSubset_.valid())
|
||||
{
|
||||
tmp<VolFieldType> tfield = meshSubset_->interpolate(*fldPtr);
|
||||
autoPtr<ensightFile> os = ensCase().newData<Type>(fieldName);
|
||||
|
||||
ensightOutput::writeField<Type>
|
||||
(
|
||||
tfield(),
|
||||
ensMesh(),
|
||||
os,
|
||||
caseOpts_.nodeValues()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ensightOutput::writeField<Type>
|
||||
(
|
||||
*fldPtr,
|
||||
field,
|
||||
ensMesh(),
|
||||
os,
|
||||
caseOpts_.nodeValues()
|
||||
);
|
||||
|
||||
Log << ' ' << fieldName;
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
Log << " " << inputName;
|
||||
|
||||
state = +1;
|
||||
return state;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
Loading…
Reference in New Issue
Block a user