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:
Henry Weller
2019-07-22 10:31:36 +01:00
parent 403bc05870
commit fdf1216ef5
9 changed files with 237 additions and 18 deletions

View File

@ -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();
}
}

View File

@ -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_;

View File

@ -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);

View File

@ -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

View File

@ -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;
}
}
// ************************************************************************* //

View File

@ -162,6 +162,8 @@ Foam::regIOobject::~regIOobject()
}
}
db().resetCacheTemporaryObject(*this);
// Check out of objectRegistry if not owned by the registry
if (!ownedByRegistry_)
{

View File

@ -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

View File

@ -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 * * * * * * * * * * * * * //

View File

@ -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_);
}