From fdf1216ef5c8c42e39b2c5a4fa9dc79ea4ba08ea Mon Sep 17 00:00:00 2001 From: Henry Weller Date: Mon, 22 Jul 2019 10:31:36 +0100 Subject: [PATCH] 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); } } --- src/OpenFOAM/db/Time/Time.C | 16 ++- src/OpenFOAM/db/Time/Time.H | 3 + .../db/objectRegistry/objectRegistry.C | 116 +++++++++++++++++- .../db/objectRegistry/objectRegistry.H | 26 ++++ .../objectRegistry/objectRegistryTemplates.C | 62 +++++++++- src/OpenFOAM/db/regIOobject/regIOobject.C | 2 + src/OpenFOAM/db/regIOobject/regIOobject.H | 23 ++-- .../DimensionedField/DimensionedField.C | 5 +- .../GeometricField/GeometricField.C | 2 + 9 files changed, 237 insertions(+), 18 deletions(-) diff --git a/src/OpenFOAM/db/Time/Time.C b/src/OpenFOAM/db/Time/Time.C index 33b98f0959..62e6ed1ea9 100644 --- a/src/OpenFOAM/db/Time/Time.C +++ b/src/OpenFOAM/db/Time/Time.C @@ -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(); } } diff --git a/src/OpenFOAM/db/Time/Time.H b/src/OpenFOAM/db/Time/Time.H index 7d95352b24..aff3a14040 100644 --- a/src/OpenFOAM/db/Time/Time.H +++ b/src/OpenFOAM/db/Time/Time.H @@ -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_; diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistry.C b/src/OpenFOAM/db/objectRegistry/objectRegistry.C index 926c4b43b0..8d00a9426b 100644 --- a/src/OpenFOAM/db/objectRegistry/objectRegistry.C +++ b/src/OpenFOAM/db/objectRegistry/objectRegistry.C @@ -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>::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, *this, iter) + { + const objectRegistry* orPtr_ = + dynamic_cast(iter()); + + // Protect against re-searching the top-level registry + if (orPtr_ && orPtr_ != this) + { + enabled = orPtr_->checkCacheTemporaryObjects() || enabled; + } + } + + if (enabled) + { + forAllIter + ( + typename HashTable>, + 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); diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistry.H b/src/OpenFOAM/db/objectRegistry/objectRegistry.H index 98248c6a9b..e6cbfd4ae6 100644 --- a/src/OpenFOAM/db/objectRegistry/objectRegistry.H +++ b/src/OpenFOAM/db/objectRegistry/objectRegistry.H @@ -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> 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 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 + 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 diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C b/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C index 301959b01f..d12c595bb2 100644 --- a/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C +++ b/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C @@ -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 +bool Foam::objectRegistry::cacheTemporaryObject(Object& ob) const +{ + readCacheTemporaryObjects(); + + if (cacheTemporaryObjects_.size()) + { + temporaryObjects_.insert(ob.name()); + + HashTable>::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(ob.name())) + { + Object& cachedOb = + ob.db().template lookupObjectRef(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; + } +} + + // ************************************************************************* // diff --git a/src/OpenFOAM/db/regIOobject/regIOobject.C b/src/OpenFOAM/db/regIOobject/regIOobject.C index 76355ec71b..07119fb1cd 100644 --- a/src/OpenFOAM/db/regIOobject/regIOobject.C +++ b/src/OpenFOAM/db/regIOobject/regIOobject.C @@ -162,6 +162,8 @@ Foam::regIOobject::~regIOobject() } } + db().resetCacheTemporaryObject(*this); + // Check out of objectRegistry if not owned by the registry if (!ownedByRegistry_) { diff --git a/src/OpenFOAM/db/regIOobject/regIOobject.H b/src/OpenFOAM/db/regIOobject/regIOobject.H index bc66bd12b8..a17504a0c1 100644 --- a/src/OpenFOAM/db/regIOobject/regIOobject.H +++ b/src/OpenFOAM/db/regIOobject/regIOobject.H @@ -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 diff --git a/src/OpenFOAM/fields/DimensionedFields/DimensionedField/DimensionedField.C b/src/OpenFOAM/fields/DimensionedFields/DimensionedField/DimensionedField.C index c2d9156eaf..8164b8fa76 100644 --- a/src/OpenFOAM/fields/DimensionedFields/DimensionedField/DimensionedField.C +++ b/src/OpenFOAM/fields/DimensionedFields/DimensionedField/DimensionedField.C @@ -25,6 +25,7 @@ License #include "DimensionedField.H" #include "dimensionedType.H" +#include "Time.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -382,7 +383,9 @@ DimensionedField::New template DimensionedField::~DimensionedField() -{} +{ + db().cacheTemporaryObject(*this); +} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // diff --git a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.C b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.C index b3a85950c1..eba598ae9a 100644 --- a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.C +++ b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.C @@ -933,6 +933,8 @@ Foam::GeometricField::New template class PatchField, class GeoMesh> Foam::GeometricField::~GeometricField() { + this->db().cacheTemporaryObject(*this); + deleteDemandDrivenData(field0Ptr_); deleteDemandDrivenData(fieldPrevIterPtr_); }