Newer
Older
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2015-2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "functionObjectList.H"
#include "Time.H"
#include "timeControlFunctionObject.H"
#include "dictionaryEntry.H"
#include "stringOps.H"
#include "etcFiles.H"
#include "IOdictionary.H"
/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
Foam::fileName Foam::functionObjectList::functionObjectDictPath
(
"caseDicts/postProcessing"
);
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
void Foam::functionObjectList::createStateDict() const
{
// Cannot set the state dictionary on construction since Time has not
// been fully initialised
stateDictPtr_.reset
(
new IOdictionary
(
IOobject
(
"functionObjectProperties",
time_.timeName(),
"uniform"/word("functionObjects"),
time_,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE
)
)
);
}
void Foam::functionObjectList::createOutputRegistry() const
{
objectsRegistryPtr_.reset
(
new objectRegistry
(
IOobject
(
"functionObjectObjects",
time_.timeName(),
time_,
IOobject::NO_READ,
IOobject::NO_WRITE
)
)
);
}
Foam::autoPtr<Foam::functionObject> Foam::functionObjectList::remove
(
const word& key,
label& oldIndex
)
auto iter = indices_.find(key); // Index of existing functionObject
// Remove pointer from the old list
oldptr = this->set(oldIndex, nullptr);
indices_.erase(iter);
else
{
oldIndex = -1;
}
Henry Weller
committed
void Foam::functionObjectList::listDir
(
const fileName& dir,
wordHashSet& available
Henry Weller
committed
)
{
// Search specified directory for functionObject configuration files
for (const fileName& f : fileHandler().readDir(dir))
Henry Weller
committed
{
if (f.ext().empty())
Henry Weller
committed
{
available.insert(f);
Henry Weller
committed
}
}
// Recurse into sub-directories
for (const fileName& d : fileHandler().readDir(dir, fileName::DIRECTORY))
Henry Weller
committed
{
listDir(dir/d, available);
Henry Weller
committed
}
}
Henry Weller
committed
void Foam::functionObjectList::list()
{
wordHashSet available;
Henry Weller
committed
for (const fileName& d : findEtcDirs(functionObjectDictPath))
Henry Weller
committed
{
listDir(d, available);
Henry Weller
committed
}
Info<< nl
<< "Available configured functionObjects:"
<< available.sortedToc()
Henry Weller
committed
<< nl;
}
Foam::fileName Foam::functionObjectList::findDict(const word& funcName)
{
// First check for functionObject dictionary file in globalCase system/
fileName dictFile = stringOps::expand("<system>")/funcName;
if (isFile(dictFile))
{
return dictFile;
}
for (const fileName& d : findEtcDirs(functionObjectDictPath))
{
dictFile = search(funcName, d);
if (!dictFile.empty())
}
}
return fileName::null;
}
Henry Weller
committed
bool Foam::functionObjectList::readFunctionObject
const string& funcNameArgs,
dictionary& functionsDict,
HashSet<wordRe>& requiredFields,
Henry Weller
committed
const word& region
// Parse the optional functionObject arguments:
// 'Q(U)' -> funcName = Q; args = (U); field = U
//
// Supports named arguments:
// 'patchAverage(patch=inlet, p)' -> funcName = patchAverage;
// args = (patch=inlet, p); field = p
word funcName(funcNameArgs);
Henry Weller
committed
int argLevel = 0;
wordReList args;
List<Tuple2<word, string>> namedArgs;
word::size_type start = 0;
word::size_type i = 0;
for
(
word::const_iterator iter = funcNameArgs.begin();
iter != funcNameArgs.end();
++iter
)
{
char c = *iter;
if (c == '(')
{
Henry Weller
committed
if (argLevel == 0)
{
funcName = funcNameArgs.substr(start, i - start);
Henry Weller
committed
start = i+1;
}
++argLevel;
else if (c == ',' || c == ')')
Henry Weller
committed
if (argLevel == 1)
{
{
namedArgs.append
(
Tuple2<word, string>
(
argName,
funcNameArgs.substr(start, i - start)
}
else
{
args.append
(
wordRe
word::validate
(
funcNameArgs.substr(start, i - start)
)
Henry Weller
committed
start = i+1;
}
Henry Weller
committed
{
if (argLevel == 1)
{
break;
}
--argLevel;
Henry Weller
committed
}
}
else if (c == '=')
{
(
funcNameArgs.substr(start, i - start)
);
}
++i;
}
// Search for the functionObject dictionary
fileName path = functionObjectList::findDict(funcName);
if (path == fileName::null)
{
WarningInFunction
<< "Cannot find functionObject file " << funcName << endl;
Henry Weller
committed
return false;
}
// Read the functionObject dictionary
autoPtr<ISstream> fileStreamPtr(fileHandler().NewIFstream(path));
ISstream& fileStream = fileStreamPtr();
dictionary funcsDict(fileStream);
dictionary* funcDictPtr = funcsDict.findDict(funcName);
dictionary& funcDict = (funcDictPtr ? *funcDictPtr : funcsDict);
// Insert the 'field' and/or 'fields' entry corresponding to the optional
// arguments or read the 'field' or 'fields' entry and add the required
Henry Weller
committed
// fields to requiredFields
if (args.size() == 1)
{
funcDict.set("field", args[0]);
funcDict.set("fields", args);
Henry Weller
committed
requiredFields.insert(args[0]);
}
else if (args.size() > 1)
{
funcDict.set("fields", args);
requiredFields.insert(args);
}
else if (funcDict.found("field"))
{
requiredFields.insert(funcDict.get<wordRe>("field"));
}
else if (funcDict.found("fields"))
{
requiredFields.insert(funcDict.get<wordRes>("fields"));
// Insert named arguments
for (const Tuple2<word, string>& namedArg : namedArgs)
{
IStringStream entryStream
(
namedArg.first() + ' ' + namedArg.second() + ';'
funcDict.set(entry::New(entryStream).ptr());
}
Henry Weller
committed
// Insert the region name if specified
if (region != word::null)
{
funcDict.set("region", region);
}
// Merge this functionObject dictionary into functionsDict
dictionary funcArgsDict;
funcArgsDict.add(word::validate(funcNameArgs), funcDict);
Henry Weller
committed
functionsDict.merge(funcArgsDict);
return true;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjectList::functionObjectList
(
const bool execution
)
:
PtrList<functionObject>(),
digests_(),
time_(runTime),
parentDict_(runTime.controlDict()),
objectsRegistryPtr_(),
execution_(execution),
updated_(false)
{}
Foam::functionObjectList::functionObjectList
(
const bool execution
)
:
PtrList<functionObject>(),
digests_(),
objectsRegistryPtr_(),
execution_(execution),
updated_(false)
Foam::autoPtr<Foam::functionObjectList> Foam::functionObjectList::New
(
const argList& args,
const Time& runTime,
Henry Weller
committed
dictionary& controlDict,
HashSet<wordRe>& requiredFields
// Merge any functions from the provided controlDict
Henry Weller
committed
controlDict.add
dictionaryEntry("functions", controlDict, dictionary::null),
true
Henry Weller
committed
dictionary& functionsDict = controlDict.subDict("functions");
const word regionName = args.opt<word>("region", "");
Henry Weller
committed
bool modifiedControlDict = false;
Henry Weller
committed
if (args.found("dict"))
modifiedControlDict = true;
controlDict.merge
(
IOdictionary
args["dict"],
runTime,
IOobject::MUST_READ_IF_MODIFIED
if (args.found("func"))
{
modifiedControlDict = true;
readFunctionObject
(
args["func"],
functionsDict,
requiredFields,
regionName
if (args.found("funcs"))
{
modifiedControlDict = true;
wordList funcNames = args.getList<word>("funcs");
for (const word& funcName : funcNames)
Henry Weller
committed
readFunctionObject
(
Henry Weller
committed
functionsDict,
requiredFields,
regionName
Henry Weller
committed
);
autoPtr<functionObjectList> functionsPtr;
if (modifiedControlDict)
{
Henry Weller
committed
functionsPtr.reset(new functionObjectList(runTime, controlDict));
functionsPtr.reset(new functionObjectList(runTime));
functionsPtr->start();
return functionsPtr;
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::label Foam::functionObjectList::triggerIndex() const
{
label triggeri = labelMin;
stateDict().readIfPresent("triggerIndex", triggeri);
return triggeri;
}
Andrew Heather
committed
void Foam::functionObjectList::resetState()
{
// Reset (re-read) the state dictionary
stateDictPtr_.clear();
createStateDict();
}
Foam::IOdictionary& Foam::functionObjectList::stateDict()
{
if (!stateDictPtr_.valid())
{
createStateDict();
}
}
const Foam::IOdictionary& Foam::functionObjectList::stateDict() const
{
if (!stateDictPtr_.valid())
{
createStateDict();
}
Foam::objectRegistry& Foam::functionObjectList::storedObjects()
{
if (!objectsRegistryPtr_.valid())
{
createOutputRegistry();
}
return *objectsRegistryPtr_;
}
const Foam::objectRegistry& Foam::functionObjectList::storedObjects() const
{
if (!objectsRegistryPtr_.valid())
{
createOutputRegistry();
}
return *objectsRegistryPtr_;
}
void Foam::functionObjectList::clear()
{
PtrList<functionObject>::clear();
digests_.clear();
indices_.clear();
updated_ = false;
}
Foam::label Foam::functionObjectList::findObjectID(const word& name) const
{
label id = 0;
for (const functionObject& funcObj : functions())
}
return -1;
}
void Foam::functionObjectList::on()
{
execution_ = true;
}
void Foam::functionObjectList::off()
{
// For safety, also force a read() when execution is resumed
updated_ = execution_ = false;
}
bool Foam::functionObjectList::status() const
{
return execution_;
}
bool Foam::functionObjectList::start()
{
bool Foam::functionObjectList::execute()
for (functionObject& funcObj : functions())
const word& objName = funcObj.name();
{
addProfiling(fo, "functionObject::" + objName + "::execute");
}
{
addProfiling(fo, "functionObject::" + objName + "::write");
}
// Force writing of state dictionary after function object execution
if (time_.writeTime())
{
label oldPrecision = IOstream::precision_;
IOstream::precision_ = 16;
stateDictPtr_->writeObject
(
IOstream::ASCII,
IOstream::currentVersion,
time_.writeCompression(),
true
);
IOstream::precision_ = oldPrecision;
}
bool Foam::functionObjectList::execute(const label subIndex)
{
bool ok = execution_;
if (ok)
{
for (functionObject& funcObj : functions())
{
ok = funcObj.execute(subIndex) && ok;
}
}
return ok;
}
bool Foam::functionObjectList::execute
(
const UList<wordRe>& functionNames,
const label subIndex
)
{
bool ok = execution_;
if (ok && functionNames.size())
{
for (functionObject& funcObj : functions())
if (stringOps::match(functionNames, funcObj.name()))
{
ok = funcObj.execute(subIndex) && ok;
}
}
}
return ok;
}
bool Foam::functionObjectList::end()
{
bool ok = true;
if (execution_)
{
if (!updated_)
{
read();
}
for (functionObject& funcObj : functions())
const word& objName = funcObj.name();
addProfiling(fo, "functionObject::" + objName + "::end");
}
}
return ok;
}
Sergio Ferraris
committed
bool Foam::functionObjectList::adjustTimeStep()
{
bool ok = true;
if (execution_)
{
if (!updated_)
{
read();
}
for (functionObject& funcObj : functions())
Sergio Ferraris
committed
{
const word& objName = funcObj.name();
addProfiling(fo, "functionObject::" + objName + "::adjustTimeStep");
ok = funcObj.adjustTimeStep() && ok;
Sergio Ferraris
committed
}
}
return ok;
}
bool Foam::functionObjectList::read()
{
if (!stateDictPtr_.valid())
{
createStateDict();
}
Andrew Heather
committed
// Avoid reading/initializing if execution is off
Henry Weller
committed
return true;
// Update existing and add new functionObjects
const entry* entryPtr =
parentDict_.findEntry("functions", keyType::LITERAL);
if (!entryPtr)
{
// No functions
PtrList<functionObject>::clear();
digests_.clear();
indices_.clear();
}
else if (!entryPtr->isDict())
{
// Bad entry type
ok = false;
FatalIOErrorInFunction(parentDict_)
<< "'functions' entry is not a dictionary"
<< exit(FatalIOError);
}
else
{
const dictionary& functionsDict = entryPtr->dict();
PtrList<functionObject> newPtrs(functionsDict.size());
List<SHA1Digest> newDigs(functionsDict.size());
HashTable<label> newIndices;
Henry Weller
committed
addProfiling(fo, "functionObjects::read");
Henry Weller
committed
const_cast<Time&>(time_).libs().open
(
functionsDict,
"libs",
functionObject::dictionaryConstructorTablePtr_
);
for (const entry& dEntry : functionsDict)
Henry Weller
committed
{
const word& key = dEntry.keyword();
if (!dEntry.isDict())
if (key != "libs")
IOWarningInFunction(parentDict_)
<< "Entry " << key << " is not a dictionary" << endl;
Henry Weller
committed
continue;
}
const dictionary& dict = dEntry.dict();
Henry Weller
committed
bool enabled = dict.lookupOrDefault("enabled", true);
Henry Weller
committed
newDigs[nFunc] = dict.digest();
label oldIndex = -1;
autoPtr<functionObject> objPtr = remove(key, oldIndex);
Henry Weller
committed
if (objPtr)
{
// Re-read if dictionary content changed for
// existing functionObject
if (enabled && newDigs[nFunc] != digests_[oldIndex])
addProfiling
(
fo2,
"functionObject::" + objPtr->name() + "::read"
);
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
if (functionObjects::timeControl::entriesPresent(dict))
{
if (isA<functionObjects::timeControl>(objPtr()))
{
// Already a time control - normal read
enabled = objPtr->read(dict);
}
else
{
// Was not a time control - need to re-create
objPtr.reset
(
new functionObjects::timeControl
(
key,
time_,
dict
)
);
enabled = true;
}
}
else
{
// Plain function object - normal read
enabled = objPtr->read(dict);
}
if (!enabled)
// Delete disabled or an invalid(read) functionObject
objPtr.clear();
Henry Weller
committed
continue;
Henry Weller
committed
else if (enabled)
Henry Weller
committed
autoPtr<functionObject> foPtr;
// Throw FatalError, FatalIOError as exceptions
const bool throwingError = FatalError.throwExceptions();
const bool throwingIOerr = FatalIOError.throwExceptions();
Henry Weller
committed
try
Andrew Heather
committed
// New functionObject
addProfiling
(
fo2,
"functionObject::" + key + "::new"
if (functionObjects::timeControl::entriesPresent(dict))
(
new functionObjects::timeControl(key, time_, dict)
);
}
else
{
foPtr = functionObject::New(key, time_, dict);
}
catch (const Foam::IOerror& ioErr)
Henry Weller
committed
Info<< ioErr << nl << endl;
::exit(1);
catch (const Foam::error& err)
Henry Weller
committed
{
// Bit of trickery to get the original message
err.write(Warning, false);
<< "--> while loading function object '" << key << "'"
<< nl << endl;
Henry Weller
committed
}
// Restore previous exception throwing state
FatalError.throwExceptions(throwingError);
FatalIOError.throwExceptions(throwingIOerr);
// Required functionObject to be valid on all processors
if (returnReduce(foPtr.valid(), andOp<bool>()))
Henry Weller
committed
ok = false;
Henry Weller
committed
}
// Insert active functionObject into the list
Henry Weller
committed
if (objPtr)
{
newPtrs.set(nFunc, objPtr);
newIndices.insert(key, nFunc);
newPtrs.resize(nFunc);
newDigs.resize(nFunc);
// Updating PtrList of functionObjects deletes any
Henry Weller
committed
// existing unused functionObjects
PtrList<functionObject>::transfer(newPtrs);
bool Foam::functionObjectList::filesModified() const
{
bool ok = false;
if (execution_)
{
for (const functionObject& funcObj : functions())
bool changed = funcObj.filesModified();
ok = ok || changed;
}
}
return ok;
}
void Foam::functionObjectList::updateMesh(const mapPolyMesh& mpm)
{
if (execution_)
{
for (functionObject& funcObj : functions())
}
}
}
void Foam::functionObjectList::movePoints(const polyMesh& mesh)
{
if (execution_)
{
for (functionObject& funcObj : functions())
// ************************************************************************* //