ENH: bounding box clipping for ensightWrite function object (issue #973)

- for larger problems with a smaller region of interest, can apply a
  bounding to limit the size of the ensight geometry and fields created.

  Since the implementation uses a fvMeshSubset, there is an additional
  per-process memory overhead.

  A high output frequency should be avoided with moving meshes, since
  this indirectly forces a frequent update of the submesh.
This commit is contained in:
Mark Olesen
2018-08-14 11:50:53 +02:00
parent 62b83a76a4
commit 45f4a8b9c5
7 changed files with 164 additions and 14 deletions

View File

@ -4,6 +4,7 @@ EXE_INC = \
-I$(LIB_SRC)/fileFormats/lnInclude \
-I$(LIB_SRC)/conversion/lnInclude \
-I$(LIB_SRC)/sampling/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/ODE/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
-I$(LIB_SRC)/transportModels/compressible/lnInclude
@ -13,6 +14,7 @@ LIB_LIBS = \
-lfiniteArea \
-lconversion \
-lsampling \
-ldynamicMesh \
-lfluidThermophysicalModels \
-lcompressibleTransportModels \
-lODE

View File

@ -47,6 +47,39 @@ namespace functionObjects
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::bitSet Foam::functionObjects::ensightWrite::cellSelection() const
{
bitSet cellsToSelect;
// Could also deal with cellZones here, as required
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;
@ -83,7 +116,8 @@ Foam::functionObjects::ensightWrite::ensightWrite
caseOpts_(writeOpts_.format()),
selectFields_(),
dirName_("ensightWrite"),
consecutive_(false)
consecutive_(false),
bounds_()
{
if (postProcess)
{
@ -104,6 +138,12 @@ bool Foam::functionObjects::ensightWrite::read(const dictionary& dict)
{
fvMeshFunctionObject::read(dict);
// Ensure consistency
meshSubset_.clear();
ensMesh_.clear();
//
// writer options
//
@ -123,6 +163,10 @@ bool Foam::functionObjects::ensightWrite::read(const dictionary& dict)
}
bounds_.clear();
dict.readIfPresent("bounds", bounds_);
//
// case options
//
@ -197,7 +241,25 @@ bool Foam::functionObjects::ensightWrite::write()
if (!ensMesh_.valid())
{
writeGeom = true;
ensMesh_.reset(new ensightMesh(mesh_, writeOpts_));
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())
{
@ -219,12 +281,12 @@ bool Foam::functionObjects::ensightWrite::write()
DynamicList<word> missing(selectFields_.size());
DynamicList<word> ignored(selectFields_.size());
// check exact matches first
// Check exact matches first
for (const wordRe& select : selectFields_)
{
if (!select.isPattern())
{
const word& fieldName = static_cast<const word&>(select);
const word& fieldName = select;
if (!candidates.erase(fieldName))
{
@ -271,7 +333,14 @@ void Foam::functionObjects::ensightWrite::updateMesh(const mapPolyMesh& mpm)
{
// fvMeshFunctionObject::updateMesh(mpm);
if (ensMesh_.valid())
// 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();
}
@ -282,7 +351,14 @@ void Foam::functionObjects::ensightWrite::movePoints(const polyMesh& mpm)
{
// fvMeshFunctionObject::updateMesh(mpm);
if (ensMesh_.valid())
// 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();
}

View File

@ -67,6 +67,7 @@ Description
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 |
\endtable
Note that if the \c patches entry is an empty list, this will select all
@ -93,6 +94,7 @@ SourceFiles
#include "interpolation.H"
#include "volFields.H"
#include "fvMeshSubset.H"
#include "surfaceFields.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -129,6 +131,12 @@ class ensightWrite
//- Consecutive output numbering
bool consecutive_;
//- Restrict to bounding box
boundBox bounds_;
//- Mesh subset handler
autoPtr<fvMeshSubset> meshSubset_;
//- Ensight case handler
autoPtr<ensightCase> ensCase_;
@ -150,6 +158,9 @@ 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
template<class Type>

View File

@ -38,20 +38,39 @@ int Foam::functionObjects::ensightWrite::writeVolField
// State: return 0 (not-processed), -1 (skip), +1 ok
typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
const VolFieldType* fldPtr;
// Already done, or not available
if (state || !foundObject<VolFieldType>(inputName))
if (state || !(fldPtr = lookupObjectPtr<VolFieldType>(inputName)))
{
return state;
}
autoPtr<ensightFile> os = ensCase().newData<Type>(inputName);
ensightOutput::writeField<Type>
(
lookupObject<VolFieldType>(inputName),
ensMesh(),
os,
caseOpts_.nodeValues()
);
if (meshSubset_.valid())
{
tmp<VolFieldType> tfield = meshSubset_->interpolate(*fldPtr);
ensightOutput::writeField<Type>
(
tfield(),
ensMesh(),
os,
caseOpts_.nodeValues()
);
}
else
{
ensightOutput::writeField<Type>
(
*fldPtr,
ensMesh(),
os,
caseOpts_.nodeValues()
);
}
Log << " " << inputName;

View File

@ -0,0 +1,16 @@
#!/bin/sh
cd ${0%/*} || exit 1 # Run from this directory
. $WM_PROJECT_DIR/bin/tools/RunFunctions # Tutorial run functions
runApplication surfaceFeatureExtract
runApplication blockMesh
runApplication snappyHexMesh -overwrite
runApplication decomposePar
runParallel $(getApplication)
runApplication reconstructPar
#------------------------------------------------------------------------------

View File

@ -0,0 +1,23 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1806 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object decomposeParDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
numberOfSubdomains 6;
// method kahip;
method scotch;
// ************************************************************************* //

View File

@ -12,6 +12,9 @@ ensightWrite
// Fields to output (words or regex)
fields (U p "(k|epsilon|omega)");
// Limit output region
bounds (0 0 0) (245 180 80);
//- Write more frequent than fields
writeControl timeStep;
writeInterval 5;