objectRegistry: Added support for optionally caching temporary objects
which provides a very convenient mechanism to process and write any temporary
fields created during a time-step, either within models the construction of
equations and matrices or any other intermediate processing step within an
OpenFOAM application. The cached fields can relate to physical properties in
models, e.g. the generation term or other terms in the turbulence models, or
numerical, e.g. the limiters used on convection schemes. This mechanism
provides a new very powerful non-intrusive way of analysing the internals of an
OpenFOAM application for diagnosis and general post-processing which cannot be
easily achieved by any other means without adding specific diagnostics code to
the models or interest and recompiling.
For example to cache the kEpsilon:G field in
tutorials/incompressible/simpleFoam/pitzDaily add the dictionary entry
cacheTemporaryObjects
(
grad(k)
kEpsilon:G
);
to system/controlDict and to write the field add a writeObjects entry to the
functions list:
functions
{
writeCachedObjects
{
type writeObjects;
libs ("libutilityFunctionObjects.so");
writeControl writeTime;
writeOption anyWrite;
objects
(
grad(k)
kEpsilon:G
);
}
#includeFunc streamlines
}
If a name of a field which in never constructed is added to the
cacheTemporaryObjects list a waning message is generated which includes a useful
list of ALL the temporary fields constructed during the time step, e.g. for the
tutorials/incompressible/simpleFoam/pitzDaily case:
--> FOAM Warning : Could not find temporary object dummy in registry region0
Available temporary objects
81
(
(((0.666667*C1)-C3)*div(phi))
div(phi)
(interpolate(nuEff)*magSf)
surfaceIntegrate(phi)
(interpolate(DepsilonEff)*magSf)
((interpolate(((1|((1|(1|A(U)))-H(1)))-(1|A(U))))*snGrad(p))*magSf)
grad(p)
((interpolate(nuEff)*magSf)*snGradCorr(U))
(interpolate((1|((1|(1|A(U)))-H(1))))*magSf)
((1|((1|(1|A(U)))-H(1)))-(1|A(U)))
((Cmu*sqr(k))|epsilon)
interpolate(HbyA)
interpolate(DkEff)
interpolate(U)
phiHbyA
weights
div(((interpolate((1|((1|(1|A(U)))-H(1))))*magSf)*snGradCorr(p)))
(phiHbyA-flux(p))
MRFZoneList:acceleration
average(interpolate(max(epsilon,epsilonMin)))
div(((interpolate(DepsilonEff)*magSf)*snGradCorr(epsilon)))
nuEff
kEpsilon:G
grad(k)
interpolate((1|((1|(1|A(U)))-H(1))))
(nuEff*dev2(T(grad(U))))
grad(U)
interpolate(epsilon)
(phi*linearUpwind::correction(U))
((interpolate(DepsilonEff)*magSf)*snGradCorr(epsilon))
grad(k)Cached
(HbyA-((1|((1|(1|A(U)))-H(1)))*grad(p)))
pos0(phi)
-div((nuEff*dev2(T(grad(U)))))
H(1)
interpolate(k)
((nut|sigmak)+nu)
snGrad(p)
(0.666667*div(phi))
surfaceIntegrate(((interpolate((1|((1|(1|A(U)))-H(1))))*magSf)*snGradCorr(p)))
DepsilonEff
(1|A(U))
surfaceIntegrate(((interpolate(DepsilonEff)*magSf)*snGradCorr(epsilon)))
limitedLinearLimiter(epsilon)
surfaceIntegrate(((interpolate(DkEff)*magSf)*snGradCorr(k)))
grad(epsilon)
(interpolate(DkEff)*magSf)
div(((interpolate(DkEff)*magSf)*snGradCorr(k)))
surfaceSum(magSf)
((1|A(U))-(1|((1|(1|A(U)))-H(1))))
(1|((1|(1|A(U)))-H(1)))
((interpolate((1|((1|(1|A(U)))-H(1))))*magSf)*snGradCorr(p))
mag(div(phi))
surfaceSum((magSf*interpolate(max(epsilon,epsilonMin))))
interpolate(DepsilonEff)
-grad(p)
snGradCorr(p)
interpolate(p)
interpolate(max(epsilon,epsilonMin))
dev(twoSymm(grad(U)))
surfaceIntegrate((phi*linearUpwind::correction(U)))
(magSf*interpolate(max(epsilon,epsilonMin)))
limitedLinearLimiter(k)
(nut+nu)
HbyA
max(epsilon,epsilonMin)
surfaceIntegrate(((interpolate(nuEff)*magSf)*snGradCorr(U)))
surfaceIntegrate(phiHbyA)
DkEff
(((C1*kEpsilon:G)*epsilon)|k)
(mag(S)+2.22507e-308)
(((1|A(U))-(1|((1|(1|A(U)))-H(1))))*grad(p))
((nut|sigmaEps)+nu)
((interpolate(DkEff)*magSf)*snGradCorr(k))
(nut*(dev(twoSymm(grad(U)))&&grad(U)))
interpolate(nuEff)
((C2*epsilon)|k)
interpolate((nuEff*dev2(T(grad(U)))))
(epsilon|k)
div(phiHbyA)
div(((interpolate(nuEff)*magSf)*snGradCorr(U)))
)
Multiple regions are also supported by specifying individual region names in a
cacheTemporaryObjects dictionary, e.g. in the
tutorials/heatTransfer/chtMultiRegionFoam/heatExchanger case
cacheTemporaryObjects
{
air
(
kEpsilon:G
);
porous
(
porosityBlockage:UNbr
);
}
functions
{
writeAirObjects
{
type writeObjects;
libs ("libutilityFunctionObjects.so");
region air;
writeControl writeTime;
writeOption anyWrite;
objects (kEpsilon:G);
}
writePorousObjects
{
type writeObjects;
libs ("libutilityFunctionObjects.so");
region porous;
writeControl writeTime;
writeOption anyWrite;
objects (porosityBlockage:UNbr);
}
}
This commit is contained in:
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -364,6 +364,7 @@ Foam::Time::Time
|
||||
writeCompression_(IOstream::UNCOMPRESSED),
|
||||
graphFormat_("raw"),
|
||||
runTimeModifiable_(false),
|
||||
cacheTemporaryObjects_(true),
|
||||
|
||||
functionObjects_(*this, enableFunctionObjects)
|
||||
{
|
||||
@ -440,6 +441,7 @@ Foam::Time::Time
|
||||
writeCompression_(IOstream::UNCOMPRESSED),
|
||||
graphFormat_("raw"),
|
||||
runTimeModifiable_(false),
|
||||
cacheTemporaryObjects_(true),
|
||||
|
||||
functionObjects_
|
||||
(
|
||||
@ -523,6 +525,7 @@ Foam::Time::Time
|
||||
writeCompression_(IOstream::UNCOMPRESSED),
|
||||
graphFormat_("raw"),
|
||||
runTimeModifiable_(false),
|
||||
cacheTemporaryObjects_(true),
|
||||
|
||||
functionObjects_(*this, enableFunctionObjects)
|
||||
{
|
||||
@ -600,6 +603,7 @@ Foam::Time::Time
|
||||
writeCompression_(IOstream::UNCOMPRESSED),
|
||||
graphFormat_("raw"),
|
||||
runTimeModifiable_(false),
|
||||
cacheTemporaryObjects_(true),
|
||||
|
||||
functionObjects_(*this, enableFunctionObjects)
|
||||
{
|
||||
@ -804,6 +808,11 @@ bool Foam::Time::run() const
|
||||
{
|
||||
if (!running && timeIndex_ != startTimeIndex_)
|
||||
{
|
||||
if (cacheTemporaryObjects_)
|
||||
{
|
||||
cacheTemporaryObjects_ = checkCacheTemporaryObjects();
|
||||
}
|
||||
|
||||
functionObjects_.execute();
|
||||
functionObjects_.end();
|
||||
}
|
||||
@ -821,6 +830,11 @@ bool Foam::Time::run() const
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cacheTemporaryObjects_)
|
||||
{
|
||||
cacheTemporaryObjects_ = checkCacheTemporaryObjects();
|
||||
}
|
||||
|
||||
functionObjects_.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,6 +187,9 @@ private:
|
||||
//- Is runtime modification of dictionaries allowed?
|
||||
Switch runTimeModifiable_;
|
||||
|
||||
//- Is temporary object cache enabled
|
||||
mutable bool cacheTemporaryObjects_;
|
||||
|
||||
//- Function objects executed at start and on ++, +=
|
||||
mutable functionObjectList functionObjects_;
|
||||
|
||||
|
||||
@ -42,6 +42,46 @@ bool Foam::objectRegistry::parentNotTime() const
|
||||
}
|
||||
|
||||
|
||||
void Foam::objectRegistry::readCacheTemporaryObjects() const
|
||||
{
|
||||
if
|
||||
(
|
||||
!cacheTemporaryObjectsSet_
|
||||
&& time_.controlDict().found("cacheTemporaryObjects")
|
||||
)
|
||||
{
|
||||
cacheTemporaryObjectsSet_ = true;
|
||||
|
||||
const dictionary& controlDict = time_.controlDict();
|
||||
|
||||
wordList cacheTemporaryObjects;
|
||||
|
||||
if (controlDict.isDict("cacheTemporaryObjects"))
|
||||
{
|
||||
if(controlDict.subDict("cacheTemporaryObjects").found(name()))
|
||||
{
|
||||
controlDict.subDict("cacheTemporaryObjects").lookup(name())
|
||||
>> cacheTemporaryObjects;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
controlDict.lookup("cacheTemporaryObjects")
|
||||
>> cacheTemporaryObjects;
|
||||
}
|
||||
|
||||
forAll(cacheTemporaryObjects, i)
|
||||
{
|
||||
cacheTemporaryObjects_.insert
|
||||
(
|
||||
cacheTemporaryObjects[i],
|
||||
{false, false}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::objectRegistry::objectRegistry
|
||||
@ -67,7 +107,8 @@ Foam::objectRegistry::objectRegistry
|
||||
time_(t),
|
||||
parent_(t),
|
||||
dbDir_(name()),
|
||||
event_(1)
|
||||
event_(1),
|
||||
cacheTemporaryObjectsSet_(false)
|
||||
{}
|
||||
|
||||
|
||||
@ -82,7 +123,8 @@ Foam::objectRegistry::objectRegistry
|
||||
time_(io.time()),
|
||||
parent_(io.db()),
|
||||
dbDir_(parent_.dbDir()/local()/name()),
|
||||
event_(1)
|
||||
event_(1),
|
||||
cacheTemporaryObjectsSet_(false)
|
||||
{
|
||||
writeOpt() = IOobject::AUTO_WRITE;
|
||||
}
|
||||
@ -92,6 +134,7 @@ Foam::objectRegistry::objectRegistry
|
||||
|
||||
Foam::objectRegistry::~objectRegistry()
|
||||
{
|
||||
cacheTemporaryObjects_.clear();
|
||||
clear();
|
||||
}
|
||||
|
||||
@ -290,6 +333,75 @@ void Foam::objectRegistry::clear()
|
||||
}
|
||||
|
||||
|
||||
void Foam::objectRegistry::resetCacheTemporaryObject
|
||||
(
|
||||
const regIOobject& ob
|
||||
) const
|
||||
{
|
||||
if (cacheTemporaryObjects_.size())
|
||||
{
|
||||
HashTable<Pair<bool>>::iterator iter
|
||||
(
|
||||
cacheTemporaryObjects_.find(ob.name())
|
||||
);
|
||||
|
||||
// If object ob if is in the cacheTemporaryObjects list
|
||||
// and has been cached reset the cached flag
|
||||
if (iter != cacheTemporaryObjects_.end())
|
||||
{
|
||||
iter().first() = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Foam::objectRegistry::checkCacheTemporaryObjects() const
|
||||
{
|
||||
bool enabled = cacheTemporaryObjects_.size();
|
||||
|
||||
forAllConstIter(HashTable<regIOobject*>, *this, iter)
|
||||
{
|
||||
const objectRegistry* orPtr_ =
|
||||
dynamic_cast<const objectRegistry*>(iter());
|
||||
|
||||
// Protect against re-searching the top-level registry
|
||||
if (orPtr_ && orPtr_ != this)
|
||||
{
|
||||
enabled = orPtr_->checkCacheTemporaryObjects() || enabled;
|
||||
}
|
||||
}
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
forAllIter
|
||||
(
|
||||
typename HashTable<Pair<bool>>,
|
||||
cacheTemporaryObjects_,
|
||||
iter
|
||||
)
|
||||
{
|
||||
if (!iter().second())
|
||||
{
|
||||
Warning
|
||||
<< "Could not find temporary object " << iter.key()
|
||||
<< " in registry " << name() << nl
|
||||
<< "Available temporary objects "
|
||||
<< temporaryObjects_
|
||||
<< endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter().second() = false;
|
||||
}
|
||||
}
|
||||
|
||||
temporaryObjects_.clear();
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
|
||||
void Foam::objectRegistry::rename(const word& newName)
|
||||
{
|
||||
regIOobject::rename(newName);
|
||||
|
||||
@ -38,6 +38,8 @@ SourceFiles
|
||||
#include "HashTable.H"
|
||||
#include "regIOobject.H"
|
||||
#include "wordReList.H"
|
||||
#include "HashSet.H"
|
||||
#include "Pair.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -67,6 +69,17 @@ class objectRegistry
|
||||
//- Current event
|
||||
mutable label event_;
|
||||
|
||||
//- Table of temporary object names with current state
|
||||
mutable HashTable<Pair<bool>> cacheTemporaryObjects_;
|
||||
|
||||
//- State of cacheTemporaryObjects_, set true after reading
|
||||
mutable bool cacheTemporaryObjectsSet_;
|
||||
|
||||
//- Accumulated list of temporary objects available to cache
|
||||
// Used to provide diagnostics in case the requested object is not
|
||||
// available
|
||||
mutable HashSet<word> temporaryObjects_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
@ -74,6 +87,8 @@ class objectRegistry
|
||||
// Used to terminate searching within the ancestors
|
||||
bool parentNotTime() const;
|
||||
|
||||
void readCacheTemporaryObjects() const;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
@ -199,6 +214,17 @@ public:
|
||||
//- Remove all regIOobject owned by the registry
|
||||
void clear();
|
||||
|
||||
template<class Object>
|
||||
bool cacheTemporaryObject(Object& ob) const;
|
||||
|
||||
//- Reset cache state of the given object
|
||||
// in the cacheTemporaryObjects set
|
||||
void resetCacheTemporaryObject(const regIOobject& ob) const;
|
||||
|
||||
//- Check that all objects in the cacheTemporaryObjects set
|
||||
// were cached
|
||||
bool checkCacheTemporaryObjects() const;
|
||||
|
||||
|
||||
// Reading
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -211,4 +211,64 @@ Type& Foam::objectRegistry::lookupObjectRef(const word& name) const
|
||||
}
|
||||
|
||||
|
||||
template<class Object>
|
||||
bool Foam::objectRegistry::cacheTemporaryObject(Object& ob) const
|
||||
{
|
||||
readCacheTemporaryObjects();
|
||||
|
||||
if (cacheTemporaryObjects_.size())
|
||||
{
|
||||
temporaryObjects_.insert(ob.name());
|
||||
|
||||
HashTable<Pair<bool>>::iterator iter
|
||||
(
|
||||
cacheTemporaryObjects_.find(ob.name())
|
||||
);
|
||||
|
||||
// Cache object ob if is in the cacheTemporaryObjects list
|
||||
// and hasn't been cached yet
|
||||
if (iter != cacheTemporaryObjects_.end() && iter().first() == false)
|
||||
{
|
||||
iter().first() = true;
|
||||
iter().second() = true;
|
||||
|
||||
if (ob.db().template foundObject<Object>(ob.name()))
|
||||
{
|
||||
Object& cachedOb =
|
||||
ob.db().template lookupObjectRef<Object>(ob.name());
|
||||
|
||||
// If the object is already cached in the database delete it
|
||||
if (&cachedOb != &ob && cachedOb.ownedByRegistry())
|
||||
{
|
||||
cachedOb.release();
|
||||
cachedOb.checkOut();
|
||||
cachedOb.rename(cachedOb.name() + "Cached");
|
||||
delete &cachedOb;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Info<< "Caching " << ob.name()
|
||||
<< " of type " << ob.type() << endl;
|
||||
}
|
||||
|
||||
ob.release();
|
||||
ob.checkOut();
|
||||
store(new Object(move(ob)));
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -162,6 +162,8 @@ Foam::regIOobject::~regIOobject()
|
||||
}
|
||||
}
|
||||
|
||||
db().resetCacheTemporaryObject(*this);
|
||||
|
||||
// Check out of objectRegistry if not owned by the registry
|
||||
if (!ownedByRegistry_)
|
||||
{
|
||||
|
||||
@ -57,19 +57,6 @@ class regIOobject
|
||||
:
|
||||
public IOobject
|
||||
{
|
||||
|
||||
protected:
|
||||
|
||||
//- Helper: check readOpt flags and read if necessary
|
||||
bool readHeaderOk
|
||||
(
|
||||
const IOstream::streamFormat PstreamFormat,
|
||||
const word& typeName
|
||||
);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Private Data
|
||||
|
||||
//- Is this object registered with the registry
|
||||
@ -97,6 +84,16 @@ private:
|
||||
void operator=(const regIOobject&);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
//- Helper: check readOpt flags and read if necessary
|
||||
bool readHeaderOk
|
||||
(
|
||||
const IOstream::streamFormat PstreamFormat,
|
||||
const word& typeName
|
||||
);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Static data
|
||||
|
||||
@ -25,6 +25,7 @@ License
|
||||
|
||||
#include "DimensionedField.H"
|
||||
#include "dimensionedType.H"
|
||||
#include "Time.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -382,7 +383,9 @@ DimensionedField<Type, GeoMesh>::New
|
||||
|
||||
template<class Type, class GeoMesh>
|
||||
DimensionedField<Type, GeoMesh>::~DimensionedField()
|
||||
{}
|
||||
{
|
||||
db().cacheTemporaryObject(*this);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
@ -933,6 +933,8 @@ Foam::GeometricField<Type, PatchField, GeoMesh>::New
|
||||
template<class Type, template<class> class PatchField, class GeoMesh>
|
||||
Foam::GeometricField<Type, PatchField, GeoMesh>::~GeometricField()
|
||||
{
|
||||
this->db().cacheTemporaryObject(*this);
|
||||
|
||||
deleteDemandDrivenData(field0Ptr_);
|
||||
deleteDemandDrivenData(fieldPrevIterPtr_);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user