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-2017 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 "IFstream.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
)
)
);
}
Foam::functionObject* Foam::functionObjectList::remove
(
const word& key,
label& oldIndex
)
functionObject* ptr = nullptr;
// Find index of existing functionObject
HashTable<label>::iterator fnd = indices_.find(key);
if (fnd != indices_.end())
{
Andrew Heather
committed
// Retrieve the pointer and remove it from the old list
ptr = this->set(oldIndex, 0).ptr();
else
{
oldIndex = -1;
}
Henry Weller
committed
void Foam::functionObjectList::listDir
(
const fileName& dir,
HashSet<word>& foMap
)
{
// Search specified directory for functionObject configuration files
{
fileNameList foFiles(fileHandler().readDir(dir));
Henry Weller
committed
forAll(foFiles, f)
{
if (foFiles[f].ext().empty())
{
foMap.insert(foFiles[f]);
}
}
}
// Recurse into sub-directories
{
fileNameList foDirs(fileHandler().readDir(dir, fileName::DIRECTORY));
Henry Weller
committed
forAll(foDirs, fd)
{
listDir(dir/foDirs[fd], foMap);
}
}
}
Henry Weller
committed
void Foam::functionObjectList::list()
{
HashSet<word> foMap;
fileNameList etcDirs(findEtcDirs(functionObjectDictPath));
forAll(etcDirs, ed)
{
Henry Weller
committed
listDir(etcDirs[ed], foMap);
Henry Weller
committed
}
Info<< nl
<< "Available configured functionObjects:"
<< foMap.sortedToc()
<< nl;
}
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
Foam::fileName Foam::functionObjectList::findDict(const word& funcName)
{
// First check if there is a functionObject dictionary file in the
// case system directory
fileName dictFile = stringOps::expand("$FOAM_CASE")/"system"/funcName;
if (isFile(dictFile))
{
return dictFile;
}
else
{
fileNameList etcDirs(findEtcDirs(functionObjectDictPath));
forAll(etcDirs, i)
{
dictFile = search(funcName, etcDirs[i]);
if (!dictFile.empty())
{
return dictFile;
}
}
}
return fileName::null;
}
Henry Weller
committed
bool Foam::functionObjectList::readFunctionObject
const string& funcNameArgs,
dictionary& functionsDict,
Henry Weller
committed
HashSet<word>& requiredFields,
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;
wordList args;
List<Tuple2<word, string>> namedArgs;
bool namedArg = false;
word argName;
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)
{
if (namedArg)
{
namedArgs.append
(
Tuple2<word, string>
(
argName,
funcNameArgs.substr(start, i - start)
)
);
namedArg = false;
}
else
{
args.append
(
(
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)
);
start = i+1;
namedArg = true;
}
++i;
}
// Search for the functionObject dictionary
fileName path = findDict(funcName);
if (path == fileName::null)
{
WarningInFunction
<< "Cannot find functionObject file " << funcName << endl;
Henry Weller
committed
return false;
}
// Read the functionObject dictionary
//IFstream fileStream(path);
autoPtr<ISstream> fileStreamPtr(fileHandler().NewIFstream(path));
ISstream& fileStream = fileStreamPtr();
dictionary funcsDict(fileStream);
dictionary* funcDictPtr = &funcsDict;
if (funcsDict.found(funcName) && funcsDict.isDict(funcName))
{
funcDictPtr = &funcsDict.subDict(funcName);
}
dictionary& funcDict = *funcDictPtr;
// 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);
Henry Weller
committed
requiredFields.insert(args);
}
else if (funcDict.found("field"))
{
Henry Weller
committed
requiredFields.insert(word(funcDict.lookup("field")));
}
else if (funcDict.found("fields"))
{
Henry Weller
committed
requiredFields.insert(wordList(funcDict.lookup("fields")));
// Insert named arguments
forAll(namedArgs, i)
{
IStringStream entryStream
(
namedArgs[i].first() + ' ' + namedArgs[i].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()),
execution_(execution),
updated_(false)
{}
Foam::functionObjectList::functionObjectList
(
const bool execution
)
:
PtrList<functionObject>(),
digests_(),
execution_(execution),
updated_(false)
Foam::autoPtr<Foam::functionObjectList> Foam::functionObjectList::New
(
const argList& args,
const Time& runTime,
Henry Weller
committed
dictionary& controlDict,
HashSet<word>& requiredFields
autoPtr<functionObjectList> functionsPtr;
Henry Weller
committed
controlDict.add
Henry Weller
committed
dictionaryEntry("functions", controlDict, dictionary::null)
Henry Weller
committed
dictionary& functionsDict = controlDict.subDict("functions");
Henry Weller
committed
word region = word::null;
// Set the region name if specified
if (args.optionFound("region"))
{
region = args["region"];
}
if
(
args.optionFound("dict")
|| args.optionFound("func")
|| args.optionFound("funcs")
)
if (args.optionFound("dict"))
{
Henry Weller
committed
controlDict.merge
IOdictionary
(
IOobject
(
args["dict"],
runTime,
IOobject::MUST_READ_IF_MODIFIED
)
)
);
}
if (args.optionFound("func"))
{
Henry Weller
committed
readFunctionObject
(
args["func"],
functionsDict,
requiredFields,
region
);
}
if (args.optionFound("funcs"))
{
wordList funcs(args.optionLookup("funcs")());
forAll(funcs, i)
{
Henry Weller
committed
readFunctionObject
(
funcs[i],
functionsDict,
requiredFields,
region
);
}
}
Henry Weller
committed
functionsPtr.reset(new functionObjectList(runTime, controlDict));
functionsPtr.reset(new functionObjectList(runTime));
functionsPtr->start();
return functionsPtr;
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::functionObjectList::~functionObjectList()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
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();
}
return stateDictPtr_();
}
const Foam::IOdictionary& Foam::functionObjectList::stateDict() const
{
if (!stateDictPtr_.valid())
{
createStateDict();
}
return stateDictPtr_();
}
void Foam::functionObjectList::clear()
{
PtrList<functionObject>::clear();
digests_.clear();
indices_.clear();
updated_ = false;
}
Foam::label Foam::functionObjectList::findObjectID(const word& name) const
{
forAll(*this, objectI)
{
if (operator[](objectI).name() == name)
{
return objectI;
}
}
return -1;
}
void Foam::functionObjectList::on()
{
execution_ = true;
}
void Foam::functionObjectList::off()
{
Andrew Heather
committed
// For safety, also force a read() when execution is turned back on
updated_ = execution_ = false;
}
bool Foam::functionObjectList::status() const
{
return execution_;
}
bool Foam::functionObjectList::start()
{
bool Foam::functionObjectList::execute()
const word& objName = operator[](objectI).name();
{
addProfiling(fo, "functionObject::" + objName + "::execute");
ok = operator[](objectI).execute() && ok;
}
{
addProfiling(fo, "functionObject::" + objName + "::write");
ok = operator[](objectI).write() && ok;
}
// Force writing of state dictionary after function object execution
if (time_.outputTime())
{
label oldPrecision = IOstream::precision_;
IOstream::precision_ = 16;
stateDictPtr_->writeObject
(
IOstream::ASCII,
IOstream::currentVersion,
time_.writeCompression(),
true
);
IOstream::precision_ = oldPrecision;
}
bool Foam::functionObjectList::end()
{
bool ok = true;
if (execution_)
{
if (!updated_)
{
read();
}
const word& objName = operator[](objectI).name();
addProfiling(fo, "functionObject::" + objName + "::end");
ok = operator[](objectI).end() && ok;
}
}
return ok;
}
Sergio Ferraris
committed
bool Foam::functionObjectList::adjustTimeStep()
{
bool ok = true;
if (execution_)
{
if (!updated_)
{
read();
}
forAll(*this, objectI)
{
const word& objName = operator[](objectI).name();
addProfiling(fo, "functionObject::" + objName + "::adjustTimeStep");
Sergio Ferraris
committed
ok = operator[](objectI).adjustTimeStep() && ok;
}
}
return ok;
}
bool Foam::functionObjectList::read()
{
if (!stateDictPtr_.valid())
{
createStateDict();
}
bool ok = true;
updated_ = execution_;
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_.lookupEntryPtr
(
"functions",
false,
false
);
PtrList<functionObject> newPtrs;
addProfiling(fo,"functionObjects::read");
Henry Weller
committed
if (!entryPtr->isDict())
Henry Weller
committed
FatalIOErrorInFunction(parentDict_)
<< "'functions' entry is not a dictionary"
<< exit(FatalIOError);
}
Henry Weller
committed
const dictionary& functionsDict = entryPtr->dict();
Henry Weller
committed
const_cast<Time&>(time_).libs().open
(
functionsDict,
"libs",
functionObject::dictionaryConstructorTablePtr_
);
newPtrs.setSize(functionsDict.size());
newDigs.setSize(functionsDict.size());
Henry Weller
committed
forAllConstIter(dictionary, functionsDict, iter)
Henry Weller
committed
{
const word& key = iter().keyword();
Henry Weller
committed
if (!iter().isDict())
if (key != "libs")
IOWarningInFunction(parentDict_)
<< "Entry " << key << " is not a dictionary" << endl;
Henry Weller
committed
continue;
}
const dictionary& dict = iter().dict();
bool enabled = dict.lookupOrDefault("enabled", true);
Henry Weller
committed
newDigs[nFunc] = dict.digest();
Henry Weller
committed
label oldIndex;
functionObject* objPtr = remove(key, oldIndex);
if (objPtr)
{
if (enabled)
Henry Weller
committed
// Dictionary changed for an existing functionObject
if (newDigs[nFunc] != digests_[oldIndex])
{
addProfiling
(
fo2,
"functionObject::" + objPtr->name() + "::read"
);
enabled = objPtr->read(dict);
ok = enabled && ok;
if (!enabled)
// Delete the disabled/invalid(read) functionObject
Henry Weller
committed
delete objPtr;
objPtr = nullptr;
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))
{
foPtr.set
(
new functionObjects::timeControl(key, time_, dict)
);
}
else
{
foPtr = functionObject::New(key, time_, dict);
}
Henry Weller
committed
catch (Foam::IOerror& ioErr)
Henry Weller
committed
Info<< ioErr << nl << endl;
::exit(1);
Henry Weller
committed
catch (Foam::error& err)
{
WarningInFunction
<< "Caught FatalError " << err << nl << endl;
}
// Restore previous exception throwing state
FatalError.throwExceptions(throwingError);
FatalIOError.throwExceptions(throwingIOerr);
// If one processor only has thrown an exception (so exited the
// constructor) invalidate the whole functionObject
if (returnReduce(foPtr.valid(), andOp<bool>()))
Henry Weller
committed
objPtr = foPtr.ptr();
Henry Weller
committed
ok = false;
Henry Weller
committed
}
Henry Weller
committed
// Insert active functionObjects into the list
if (objPtr)
{
newPtrs.set(nFunc, objPtr);
newIndices.insert(key, nFunc);
nFunc++;
Henry Weller
committed
// Updating the PtrList of functionObjects deletes any
// existing unused functionObjects
PtrList<functionObject>::transfer(newPtrs);
PtrList<functionObject>::clear();
bool Foam::functionObjectList::filesModified() const
{
bool ok = false;
if (execution_)
{
forAll(*this, objectI)
{
bool changed = operator[](objectI).filesModified();
ok = ok || changed;
}
}
return ok;
}
void Foam::functionObjectList::updateMesh(const mapPolyMesh& mpm)
{
if (execution_)
{
forAll(*this, objectI)
{
operator[](objectI).updateMesh(mpm);
}
}
}
void Foam::functionObjectList::movePoints(const polyMesh& mesh)
{
if (execution_)
{
forAll(*this, objectI)
{
operator[](objectI).movePoints(mesh);
}
}
}
// ************************************************************************* //