Merge branch 'feature-reporting' into 'develop'

Reporting tools

See merge request Development/openfoam!716
This commit is contained in:
Kutalmış Berçin 2024-12-20 12:46:56 +00:00
commit 8bf1108677
25 changed files with 4151 additions and 0 deletions

View File

@ -9,6 +9,17 @@ areaWrite/areaWrite.C
ensightWrite/ensightWrite.C
ensightWrite/ensightWriteUpdate.C
foamReport/foamReport.C
foamReport/substitutionModels/substitutionModel/substitutionModel.C
foamReport/substitutionModels/substitutionModel/substitutionModelNew.C
foamReport/substitutionModels/dictionaryValue/dictionaryValue.C
foamReport/substitutionModels/functionObjectValue/functionObjectValue.C
foamReport/substitutionModels/fileRegEx/fileRegEx.C
foamReport/substitutionModels/environmentVariable/environmentVariable.C
foamReport/substitutionModels/userValue/userValue.C
graphFunctionObject/graphFunctionObject.C
vtkWrite/vtkWrite.C
vtkWrite/vtkWriteUpdate.C

View File

@ -0,0 +1,350 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "foamReport.H"
#include "addToRunTimeSelectionTable.H"
#include "argList.H"
#include "clock.H"
#include "cloud.H"
#include "foamVersion.H"
#include "fvMesh.H"
#include "IFstream.H"
#include "stringOps.H"
#include "substitutionModel.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
defineTypeNameAndDebug(foamReport, 0);
addToRunTimeSelectionTable(functionObject, foamReport, dictionary);
}
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::functionObjects::foamReport::setStaticBuiltins()
{
substitutionModel::addBuiltinStr("OF_HOST", Foam::hostName());
substitutionModel::addBuiltinStr
(
"OF_PROC_ZERO_DIR",
Pstream::parRun() ? "processor0" : ""
);
substitutionModel::addBuiltin("OF_API", foamVersion::api);
substitutionModel::addBuiltinStr("OF_PATCH", foamVersion::patch);
substitutionModel::addBuiltinStr("OF_BUILD", foamVersion::build);
substitutionModel::addBuiltinStr("OF_BUILD_ARCH", foamVersion::buildArch);
substitutionModel::addBuiltinStr("OF_VERSION", foamVersion::version);
substitutionModel::addBuiltinStr("OF_DATE_START", clock::date());
substitutionModel::addBuiltinStr("OF_CLOCK_START", clock::clockTime());
substitutionModel::addBuiltinStr("OF_EXECUTABLE", argList::envExecutable());
substitutionModel::addBuiltinStr("OF_CASE_PATH", argList::envGlobalPath());
substitutionModel::addBuiltinStr("OF_CASE_NAME", time().globalCaseName());
substitutionModel::addBuiltin("OF_NPROCS", Pstream::nProcs());
// Set mesh builtins when there is only 1 mesh
const auto meshes = time_.lookupClass<fvMesh>();
if (meshes.size() == 1)
{
const auto& mesh = *(meshes.begin().val());
substitutionModel::addBuiltin("OF_MESH_NCELLS", mesh.nCells());
substitutionModel::addBuiltin("OF_MESH_NFACES", mesh.nFaces());
substitutionModel::addBuiltin("OF_MESH_NEDGES", mesh.nEdges());
substitutionModel::addBuiltin("OF_MESH_NPOINTS", mesh.nPoints());
substitutionModel::addBuiltin
(
"OF_MESH_NINTERNALFACES",
mesh.nInternalFaces()
);
substitutionModel::addBuiltin
(
"OF_MESH_NBOUNDARYFACES",
mesh.nBoundaryFaces()
);
substitutionModel::addBuiltin
(
"OF_MESH_NPATCHES",
mesh.boundaryMesh().nNonProcessor()
);
substitutionModel::addBuiltin
(
"OF_MESH_BOUNDS_MIN",
mesh.bounds().min()
);
substitutionModel::addBuiltin
(
"OF_MESH_BOUNDS_MAX",
mesh.bounds().max()
);
}
}
void Foam::functionObjects::foamReport::setDynamicBuiltins()
{
// Overwrite existing entries
substitutionModel::setBuiltinStr("OF_TIME", time().timeName());
substitutionModel::setBuiltin("OF_NTIMES", time().times().size());
substitutionModel::setBuiltin("OF_TIME_INDEX", time().timeIndex());
substitutionModel::setBuiltin("OF_TIME_DELTAT", time().deltaTValue());
substitutionModel::setBuiltinStr("OF_DATE_NOW", clock::date());
substitutionModel::setBuiltinStr("OF_CLOCK_NOW", clock::clockTime());
substitutionModel::setBuiltin("OF_NREGIONS", time().names<fvMesh>().size());
substitutionModel::setBuiltin("OF_NCLOUDS", time().names<cloud>().size());
}
bool Foam::functionObjects::foamReport::parseTemplate(const fileName& fName)
{
Info<< " Reading template from " << fName << endl;
IFstream is(fName);
if (!is.good())
{
FatalErrorInFunction
<< "Unable to open file " << fName << endl;
}
DynamicList<string> contents;
string buffer;
label lineNo = 0;
while (is.good())
{
is.getLine(buffer);
// Collect keys for this line and clean the buffer
const wordList keys(substitutionModel::getKeys(buffer));
Tuple2<label, DynamicList<label>> nullValue(-1, DynamicList<label>());
// Assemble table of keyword and lines where the keyword appears
for (const word& key : keys)
{
if (modelKeys_.insert(key, nullValue))
{
// Set substitution model responsible for this keyword
label modeli = -1;
forAll(substitutions_, i)
{
if (substitutions_[i].valid(key))
{
modeli = i;
break;
}
}
// Note: cannot check that key/model is set here
// - dynamic builtins not ready yet...
modelKeys_[key].first() = modeli;
}
DynamicList<label>& lineNos = modelKeys_[key].second();
lineNos.push_back(lineNo);
}
contents.push_back(buffer);
++lineNo;
}
templateContents_.transfer(contents);
return templateContents_.size() > 0;
}
bool Foam::functionObjects::foamReport::apply(Ostream& os) const
{
List<string> out(templateContents_);
forAllConstIters(modelKeys_, iter)
{
const word& key = iter.key();
const label modeli = iter.val().first();
const DynamicList<label>& lineNos = iter.val().second();
DebugInfo<< "key:" << key << endl;
for (const label linei : lineNos)
{
if (modeli == -1)
{
if (!substitutionModel::replaceBuiltin(key, out[linei]))
{
WarningInFunction
<< "Unable to find substitution for " << key
<< " on line " << linei << endl;
}
}
else
{
substitutions_[modeli].apply(key, out[linei]);
}
}
}
for (const auto& line : out)
{
os << line.c_str() << nl;
}
return true;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjects::foamReport::foamReport
(
const word& name,
const Time& runTime,
const dictionary& dict
)
:
stateFunctionObject(name, runTime),
writeFile(runTime, name, typeName, dict),
templateFile_(),
modelKeys_(),
substitutions_(),
debugKeys_(dict.getOrDefault<bool>("debugKeys", false))
{
read(dict);
setStaticBuiltins();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionObjects::foamReport::read(const dictionary& dict)
{
if (stateFunctionObject::read(dict))
{
Info<< type() << " " << name() << ":" << nl;
dict.readEntry("template", templateFile_);
Info<< " Template: " << templateFile_ << endl;
const word ext = templateFile_.ext();
if (ext.size())
{
setExt("." + ext);
}
else
{
setExt(ext);
}
Info<< " Reading substitutions" << endl;
const dictionary& subsDict = dict.subDict("substitutions");
substitutions_.resize(subsDict.size());
label i = 0;
for (const entry& e : subsDict)
{
if (!e.isDict())
{
FatalIOErrorInFunction(subsDict)
<< "Substitution models must be provided in dictionary "
<< "format"
<< exit(FatalIOError);
}
substitutions_.set(i++, substitutionModel::New(e.dict(), time()));
}
parseTemplate(templateFile_.expand());
Info<< endl;
return true;
}
return false;
}
bool Foam::functionObjects::foamReport::execute()
{
for (auto& sub : substitutions_)
{
sub.update();
}
return true;
}
bool Foam::functionObjects::foamReport::write()
{
if (!Pstream::master()) return true;
setDynamicBuiltins();
auto filePtr = newFileAtTime(name(), time().value());
auto& os = filePtr();
// Reset stream width (by default assumes fixed width tabular output)
os.width(0);
// Perform the substitutions
apply(os);
if (debugKeys_)
{
os << "Model keys:" << nl;
for (const auto& model : substitutions_)
{
os << model.type() << ":" << model.keys() << nl;
}
os << "Builtins:" << nl;
substitutionModel::writeBuiltins(os);
}
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,273 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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/>.
Class
Foam::functionObjects::foamReport
Group
grpUtilitiesFunctionObjects
Description
Replaces user-supplied keywords by run-time computed values in a text file.
Operands:
\table
Operand | Type | Location
input | - | -
output file | TBA <!--
--> | postProcessing/\<FO\>/\<time\>/\<file\>(s)
\endtable
Usage
Example using \c system/controlDict.functions:
\verbatim
foamReport1
{
// Mandatory entries
type foamReport;
libs (utilityFunctionObjects);
template "<system>/myTemplate.md";
substitutions
{
divSchemes1
{
type dictionaryValue;
object fvSchemes;
entries
{
divSchemes "divSchemes";
}
}
fvSolution1
{
type dictionaryValue;
path "<system>/fvSolution";
entries
{
solver_p "solvers/p/solver";
solver_p_tol "solvers/p/tolerance";
solver_p_reltol "solvers/p/relTol";
solver_U "solvers/U/solver";
solver_U_tol "solvers/U/tolerance";
solver_U_reltol "solvers/U/relTol";
}
}
controlDict1
{
type dictionaryValue;
path "<system>/controlDict";
entries
{
initial_deltaT "deltaT";
}
}
continuityErrors
{
type functionObjectValue;
functionObject continuityError1;
entries
{
cont_error_local local;
cont_error_global global;
cont_error_cumulative cumulative;
}
}
}
// Optional entries
debugKeys <bool>;
// Inherited entries
...
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: foamReport | word | yes | -
libs | Library name: utilityFunctionObjects | word | yes | -
template | Path to user-supplied text template | string | yes | -
substitutions | Dictionary of substitution models | dictionary | yes | -
debugKeys | Flag to write all known keys | bool | no | false
\endtable
The \c entries sections typically define a dictionary of keys (to use in
your template) and method to set the key value, e.g. for a dictionaryValue
model used to set values from the \c fvSolution file:
\verbatim
type dictionaryValue;
path "<system>/fvSolution";
entries
{
solver_p "solvers/p/solver";
solver_p_tol "solvers/p/tolerance";
}
\endverbatim
The inherited entries are elaborated in:
- \link substitutionModel.H \endlink
- \link stateFunctionObject.H \endlink
- \link writeFile.H \endlink
See also
- Foam::functionObject
- Foam::functionObjects::stateFunctionObject
- Foam::functionObjects::writeFile
- Foam::substitutionModel
SourceFiles
foamReport.C
foamReportTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef functionObjects_foamReport_H
#define functionObjects_foamReport_H
#include "stateFunctionObject.H"
#include "writeFile.H"
#include "Tuple2.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
class substitutionModel;
namespace functionObjects
{
/*---------------------------------------------------------------------------*\
Class foamReport Declaration
\*---------------------------------------------------------------------------*/
class foamReport
:
public stateFunctionObject,
public writeFile
{
protected:
// Protected Data
//- Path to user-supplied template
fileName templateFile_;
//- Mapping from keyword to substitution model index and line
//- numbers of template file where keyword is used
HashTable<Tuple2<label, DynamicList<label>>> modelKeys_;
//- Template file contents split into lines
List<string> templateContents_;
//- List of substitution models
PtrList<substitutionModel> substitutions_;
//- Debug flag to write all known keys
// Helps when assembling template file...
bool debugKeys_;
// Protected Member Functions
//- Parse the template and collect keyword information
bool parseTemplate(const fileName& fName);
//- Set static builtin entries
void setStaticBuiltins();
//- Set dynamic (potentially changing per execution step) builtin
//- entries
void setDynamicBuiltins();
//- Apply the substitution models to the template
bool apply(Ostream& os) const;
// Generated Methods
//- No copy construct
foamReport(const foamReport&) = delete;
//- No copy assignment
void operator=(const foamReport&) = delete;
public:
//- Runtime type information
TypeName("foamReport");
// Constructors
//- Construct from Time and dictionary
foamReport
(
const word& name,
const Time& runTime,
const dictionary& dict
);
//- Destructor
virtual ~foamReport() = default;
// Member Functions
//- Read foamReport settings
virtual bool read(const dictionary&);
//- Execute foamReport
virtual bool execute();
//- Write foamReport results
virtual bool write();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace functionObjects
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,219 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "dictionaryValue.H"
#include "addToRunTimeSelectionTable.H"
#include "IFstream.H"
#include "polyMesh.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace substitutionModels
{
defineTypeNameAndDebug(dictionaryValue, 0);
addToRunTimeSelectionTable(substitutionModel, dictionaryValue, dictionary);
}
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
bool Foam::substitutionModels::dictionaryValue::processDict
(
const dictionary& dict,
const word& key,
string& buffer
) const
{
const string& lookup = entries_[key];
OStringStream oss;
if (lookup.empty())
{
// Add complete dictionary
oss << dict;
}
else
{
const entry* ePtr = dict.findScoped(lookup);
if (!ePtr)
{
WarningInFunction
<< "Unable to find entry " << lookup
<< endl;
return false;
}
if (ePtr->isDict())
{
const dictionary& de = ePtr->dict();
// Write dictionary contents
oss << de.dictName() << de;
}
else
{
for (const auto& t : ePtr->stream())
{
if (oss.count()) oss << separator_;
oss << t;
}
}
}
buffer.replaceAll(keyify(key), oss.str());
return true;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::substitutionModels::dictionaryValue::dictionaryValue
(
const dictionary& dict,
const Time& time
)
:
substitutionModel(dict, time),
object_(),
region_(polyMesh::defaultRegion),
path_(),
separator_(dict.getOrDefault<word>("separator", " ")),
entries_()
{
const auto* oPtr = dict.findEntry("object");
const auto* pPtr = dict.findEntry("path");
if (oPtr && pPtr)
{
FatalIOErrorInFunction(dict)
<< "Specify either 'object' or 'path' but not both"
<< exit(FatalIOError);
}
if (oPtr)
{
// Optionally read the region
dict.readIfPresent<word>("region", region_);
// Must read the object name to look up
object_ = dict.get<word>("object");
}
if (pPtr)
{
path_ = dict.get<fileName>("path").expand();
}
// Populate entries
const dictionary& entriesDict = dict.subDict("entries");
for (const auto& e : entriesDict)
{
entries_.insert(cleanKey(e.keyword()), string(e.stream()));
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::substitutionModels::dictionaryValue::valid(const word& keyName) const
{
return entries_.found(keyName);
}
bool Foam::substitutionModels::dictionaryValue::apply
(
const word& key,
string& buffer
) const
{
if (!valid(key)) return false;
if (path_.size())
{
fileName path(path_);
if (replaceBuiltin(path))
{
path.clean();
}
IFstream is(path);
if (!is.good())
{
WarningInFunction
<< "Unable to find dictionary at " << path
<< ". Deactivating." << endl;
return false;
}
return processDict(dictionary(is), key, buffer);
}
else
{
const auto* obrPtr = time_.cfindObject<objectRegistry>(region_);
if (!obrPtr)
{
WarningInFunction
<< "Unable to find region " << region_
<< ". Deactivating." << endl;
return false;
}
// Find object; recursive lookup into parent
const auto* dictPtr = obrPtr->cfindObject<IOdictionary>(object_, true);
if (!dictPtr)
{
WarningInFunction
<< "Unable find dictionary " << object_
<< " on region " << region_
<< ". Deactivating." << endl;
return false;
}
return processDict(*dictPtr, key, buffer);
}
}
Foam::wordList Foam::substitutionModels::dictionaryValue::keys() const
{
return entries_.sortedToc();
}
// ************************************************************************* //

View File

@ -0,0 +1,182 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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/>.
Class
Foam::substitutionModels::dictionaryValue
Description
The \c dictionaryValue substitution model. Dictionaries can be retrieved
from an object registry, e.g. time, mesh, or from file.
The example below shows how the keywords \c p_solver and \c u_solver are set
by retrieving values from the \c fvSolution dictionary.
\verbatim
dictionaryValues1
{
// Mandatory entries
type dictionaryValue;
entries
{
p_solver "solvers/p/solver";
u_solver "solvers/u/solver";
}
// Conditional entries
// Option-1
object "fvSolution"; // registry-based retrieval
// region "fluidMesh";
// Option-2
// path "<system>/fvSolution"; // file-based retrieval
// Optional entries
separator <word>;
// Inherited entries
...
}
\endverbatim
The entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: dictionaryValue | word | yes | -
entries | keyword lookup pairs | dictionary | yes | -
object | Name of registered dictionary | string | no | -
region | Name of mesh region | word | no | region0
path | Path to dictionary file | string | no | -
separator | Sep. when lookup value has multiple tokens | word | no | -
\endtable
The inherited entries are elaborated in:
- \link substitutionModel.H \endlink
SourceFiles
dictionaryValue.C
---------------------------------------------------------------------------*/
#ifndef Foam_substitutionModels_dictionaryValue_H
#define Foam_substitutionModels_dictionaryValue_H
#include "substitutionModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace substitutionModels
{
/*---------------------------------------------------------------------------*\
Class dictionaryValue Declaration
\*---------------------------------------------------------------------------*/
class dictionaryValue
:
public substitutionModel
{
// Private Data
//- Dictionary name for registry-based lookup
word object_;
//- Region name for registry-based lookup
word region_;
//- Path to dictionary for file-based lookup
fileName path_;
//- Separator when lookup value has multiple tokens
const word separator_;
//- Hash table for key and entry-lookup pairs
HashTable<string> entries_;
// Private Functions
//- No copy construct
dictionaryValue(const dictionaryValue&) = delete;
//- No copy assignment
void operator=(const dictionaryValue&) = delete;
protected:
// Protected Member Functions
//- Main function to process the dictionary
bool processDict
(
const dictionary& dict,
const word& key,
string& buffer
) const;
public:
//- Runtime type information
TypeName("dictionaryValue");
//- Constructor
dictionaryValue(const dictionary& dict, const Time& time);
//- Destructor
virtual ~dictionaryValue() = default;
// Member Functions
//- Return true of model applies to this keyName
virtual bool valid(const word& keyName) const;
//- Apply substitutions to this string buffer
virtual bool apply(const word& key, string& buffer) const;
//- Return a word list of the keys
virtual wordList keys() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace substitutionModels
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,101 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "environmentVariable.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace substitutionModels
{
defineTypeNameAndDebug(environmentVariable, 0);
addToRunTimeSelectionTable
(
substitutionModel,
environmentVariable,
dictionary
);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::substitutionModels::environmentVariable::environmentVariable
(
const dictionary& dict,
const Time& time
)
:
substitutionModel(dict, time),
entries_()
{
// Populate entries
const dictionary& entriesDict = dict.subDict("entries");
for (const auto& e : entriesDict)
{
entries_.insert(cleanKey(e.keyword()), string(e.stream()));
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::substitutionModels::environmentVariable::valid
(
const word& keyName
) const
{
return entries_.found(keyName);
}
bool Foam::substitutionModels::environmentVariable::apply
(
const word& key,
string& buffer
) const
{
if (!valid(key)) return false;
const string env(Foam::getEnv(entries_[key]));
buffer.replaceAll(keyify(key), env);
return true;
}
Foam::wordList Foam::substitutionModels::environmentVariable::keys() const
{
return entries_.sortedToc();
}
// ************************************************************************* //

View File

@ -0,0 +1,136 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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/>.
Class
Foam::substitutionModels::environmentVariable
Description
The \c environmentVariable substitution model.
\verbatim
environmentVariables1
{
// Mandatory entries
type environmentVariable;
entries
{
home "HOME";
ldpath "LD_LIBRARY_PATH";
}
// Inherited entries
...
}
\endverbatim
The entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: environmentVariable | word | yes | -
entries | Keyword lookup pairs | dictionary | yes | -
\endtable
The inherited entries are elaborated in:
- \link substitutionModel.H \endlink
SourceFiles
environmentVariable.C
---------------------------------------------------------------------------*/
#ifndef Foam_substitutionModels_environmentVariable_H
#define Foam_substitutionModels_environmentVariable_H
#include "substitutionModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace substitutionModels
{
/*---------------------------------------------------------------------------*\
Class environmentVariable Declaration
\*---------------------------------------------------------------------------*/
class environmentVariable
:
public substitutionModel
{
// Private Data
//- Hash table for key and environment variable pairs
HashTable<string> entries_;
// Private Functions
//- No copy construct
environmentVariable(const environmentVariable&) = delete;
//- No copy assignment
void operator=(const environmentVariable&) = delete;
public:
//- Runtime type information
TypeName("environmentVariable");
//- Constructor
environmentVariable(const dictionary& dict, const Time& time);
//- Destructor
virtual ~environmentVariable() = default;
// Member Functions
//- Return true of model applies to this keyName
virtual bool valid(const word& keyName) const;
//- Apply substitutions to this string buffer
virtual bool apply(const word& key, string& buffer) const;
//- Return a word list of the keys
virtual wordList keys() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace substitutionModels
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,163 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "fileRegEx.H"
#include "addToRunTimeSelectionTable.H"
#include "IFstream.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace substitutionModels
{
defineTypeNameAndDebug(fileRegEx, 0);
addToRunTimeSelectionTable(substitutionModel, fileRegEx, dictionary);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::substitutionModels::fileRegEx::fileRegEx
(
const dictionary& dict,
const Time& time
)
:
substitutionModel(dict, time),
path_(dict.get<fileName>("path")),
entries_(),
sectionSeparator_
(
dict.getOrDefault<string>
(
"sectionSeparator",
"Time ="
)
),
matchSeparator_(dict.getOrDefault<string>("matchSeparator", " ")),
lastMatch_(dict.getOrDefault<bool>("lastMatch", true))
{
// Populate entries
const dictionary& entriesDict = dict.subDict("entries");
for (const auto& e : entriesDict)
{
entries_.insert(cleanKey(e.keyword()), string(e.stream()));
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::substitutionModels::fileRegEx::valid(const word& keyName) const
{
return entries_.found(keyName);
}
bool Foam::substitutionModels::fileRegEx::apply
(
const word& key,
string& buffer
) const
{
if (!valid(key)) return false;
fileName path(path_);
replaceBuiltin(path);
IFstream is(path);
if (!is.good())
{
WarningInFunction
<< "Unable to find file at " << path_
<< ". Deactivating." << endl;
return false;
}
Info<< "Scanning for sections beginning with "
<< sectionSeparator_ << endl;
// For log files containing multiple time steps
// - put strings for last time step into a string list
DynamicList<string> lines(96);
string line;
bool started = sectionSeparator_.empty() ? true : false;
while (is.good())
{
is.getLine(line);
if (line.starts_with(sectionSeparator_))
{
started = true;
lines.clear();
}
if (started)
{
lines.append(line);
}
}
Info<< "Cached " << lines.size() << " lines" << endl;
OStringStream oss;
regExp re(entries_[key].c_str());
for (const string& data : lines)
{
regExp::results_type match;
if (re.match(data, match))
{
oss.reset();
for (size_t i = 1; i < match.size(); ++i)
{
if (i > 1) oss << matchSeparator_;
oss << match[i].str().c_str();
}
if (!lastMatch_) break;
}
}
if (oss.count())
{
buffer.replaceAll(keyify(key), oss.str());
return true;
}
return false;
}
Foam::wordList Foam::substitutionModels::fileRegEx::keys() const
{
return entries_.sortedToc();
}
// ************************************************************************* //

View File

@ -0,0 +1,162 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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/>.
Class
Foam::substitutionModels::fileRegEx
Description
The \c fileRegEx substitution model.
The example below shows how the keyword \c executionTime is set by
applying a regular expression (string) to a log file.
\verbatim
fileRegEx1
{
// Mandatory entries
type fileRegEx;
path "log.simpleFoam";
entries
{
executionTime "ExecutionTime = (.*) s Clock.*";
}
// Optional entries
sectionSeparator <string>;
matchSeparator <string>;
lastMatch <bool>;
// Inherited entries
...
}
\endverbatim
The entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: functionObjectValue | word | yes | -
path | Path to file | string | yes | -
entries | Keyword regular-expression pairs | dictionary | yes | -
sectionSeparator | Marker used to separate files into sections <!--
--!> | string | no | "Time ="
matchSeparator | Separator used to join multiple values <!--
--!> | string | no | " "
lastMatch | Flag to use last file section | bool | no | yes
\endtable
The inherited entries are elaborated in:
- \link substitutionModel.H \endlink
SourceFiles
fileRegEx.C
---------------------------------------------------------------------------*/
#ifndef Foam_substitutionModels_fileRegEx_H
#define Foam_substitutionModels_fileRegEx_H
#include "substitutionModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace substitutionModels
{
/*---------------------------------------------------------------------------*\
Class fileRegEx Declaration
\*---------------------------------------------------------------------------*/
class fileRegEx
:
public substitutionModel
{
// Private Data
//- Path to dictionary
const fileName path_;
//- Hash table for key and regular expression pairs
HashTable<string> entries_;
//- Section separator to dive log files, e.g. into time step info
const string sectionSeparator_;
//- Separator to apply between (multiple) matches
const string matchSeparator_;
//- Last match wins flag
bool lastMatch_;
// Private Functions
//- No copy construct
fileRegEx(const fileRegEx&) = delete;
//- No copy assignment
void operator=(const fileRegEx&) = delete;
public:
//- Runtime type information
TypeName("fileRegEx");
//- Constructor
fileRegEx(const dictionary& dict, const Time& time);
//- Destructor
virtual ~fileRegEx() = default;
// Member Functions
//- Return true of model applies to this keyName
virtual bool valid(const word& keyName) const;
//- Apply substitutions to this string buffer
virtual bool apply(const word& key, string& buffer) const;
//- Return a word list of the keys
virtual wordList keys() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace substitutionModels
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,149 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "functionObjectValue.H"
#include "addToRunTimeSelectionTable.H"
#include "IFstream.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace substitutionModels
{
defineTypeNameAndDebug(functionObjectValue, 0);
addToRunTimeSelectionTable
(
substitutionModel,
functionObjectValue,
dictionary
);
}
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class Type>
bool Foam::substitutionModels::functionObjectValue::getValue
(
OStringStream& oss,
const word& lookup
) const
{
const auto& foProps = time_.functionObjects().propsDict();
Type result;
if (foProps.getObjectResult(functionObject_, lookup, result))
{
oss << result;
return true;
}
return false;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::substitutionModels::functionObjectValue::functionObjectValue
(
const dictionary& dict,
const Time& time
)
:
substitutionModel(dict, time),
functionObject_(dict.get<word>("functionObject")),
entries_(),
debugValues_(dict.getOrDefault<bool>("debugValues", false))
{
// Populate entries
const dictionary& entriesDict = dict.subDict("entries");
for (const auto& e : entriesDict)
{
entries_.insert(cleanKey(e.keyword()), word(e.stream()));
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::substitutionModels::functionObjectValue::update()
{
if (debugValues_)
{
Info<< nl << "Function object results:" << nl;
time_.functionObjects().propsDict().writeAllResultEntries(Info);
}
return true;
}
bool Foam::substitutionModels::functionObjectValue::valid
(
const word& keyName
) const
{
return entries_.found(keyName);
}
bool Foam::substitutionModels::functionObjectValue::apply
(
const word& key,
string& buffer
) const
{
if (!valid(key)) return false;
OStringStream oss;
const word& lookup = entries_[key];
bool ok =
getValue<label>(oss, lookup)
|| getValue<scalar>(oss, lookup)
|| getValue<vector>(oss, lookup)
|| getValue<sphericalTensor>(oss, lookup)
|| getValue<symmTensor>(oss, lookup)
|| getValue<tensor>(oss, lookup);
if (!ok) return false;
buffer.replaceAll(keyify(key), oss.str());
return true;
}
Foam::wordList Foam::substitutionModels::functionObjectValue::keys() const
{
return entries_.sortedToc();
}
// ************************************************************************* //

View File

@ -0,0 +1,167 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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/>.
Class
Foam::substitutionModels::functionObjectValue
Description
functionObjectValue substitution model.
Usage
The \c functionObjectValue substitution model.
The example below shows how the keywords \c cont_error_* are set by
retrieving the values \c local, \c global, \c cumulative from the function
object \c functionObjectValue.
\verbatim
functionObjectValue1
{
// Mandatory entries
type functionObjectValue;
functionObject continuityError1;
entries
{
cont_error_local local;
cont_error_global global;
cont_error_cumulative cumulative;
}
// Optional entries
debugValues <bool>;
// Inherited entries
...
}
\endverbatim
The entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: functionObjectValue | word | yes | -
functionObject | Name of function object to query | word | yes | -
entries | Keyword-lookup pairs | dictionary | yes | -
debugValues | Flag to show available function values | bool | no | false
\endtable
The inherited entries are elaborated in:
- \link substitutionModel.H \endlink
SourceFiles
functionObjectValue.C
---------------------------------------------------------------------------*/
#ifndef Foam_substitutionModels_functionObjectValue_H
#define Foam_substitutionModels_functionObjectValue_H
#include "substitutionModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace substitutionModels
{
/*---------------------------------------------------------------------------*\
Class functionObjectValue Declaration
\*---------------------------------------------------------------------------*/
class functionObjectValue
:
public substitutionModel
{
// Private Data
//- Name of function object
const word functionObject_;
//- Hash table for key and entry-lookup pairs
HashTable<word> entries_;
//- Debug - shows available function values
bool debugValues_;
// Private Functions
//- Get the result value from the function object
template<class Type>
bool getValue(OStringStream& oss, const word& lookup) const;
//- No copy construct
functionObjectValue(const functionObjectValue&) = delete;
//- No copy assignment
void operator=(const functionObjectValue&) = delete;
public:
//- Runtime type information
TypeName("functionObjectValue");
//- Constructor
functionObjectValue
(
const dictionary& dict,
const Time& time
);
//- Destructor
virtual ~functionObjectValue() = default;
// Member Functions
//- Update model local data
virtual bool update();
//- Return true of model applies to this keyName
virtual bool valid(const word& keyName) const;
//- Apply substitutions to this string buffer
virtual bool apply(const word& key, string& buffer) const;
//- Return a word list of the keys
virtual wordList keys() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace substitutionModels
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,167 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "substitutionModel.H"
#include "stringOps.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(substitutionModel, 0);
defineRunTimeSelectionTable(substitutionModel, dictionary);
}
const Foam::word Foam::substitutionModel::KEY_BEGIN = "{{";
const Foam::word Foam::substitutionModel::KEY_END = "}}";
Foam::HashTable<Foam::string> Foam::substitutionModel::builtin_;
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::string Foam::substitutionModel::keyify(const word& w)
{
return KEY_BEGIN + w + KEY_END;
}
Foam::word Foam::substitutionModel::cleanKey(const string& str)
{
return stringOps::upper(stringOps::trim(str));
};
Foam::wordList Foam::substitutionModel::getKeys(string& buffer)
{
const label lBegin = KEY_BEGIN.length();
const label lEnd = KEY_END.length();
wordHashSet keys;
size_t pos0 = 0;
size_t pos = 0;
string cleanedBuffer = "";
while (((pos = buffer.find(KEY_BEGIN, pos)) != string::npos))
{
cleanedBuffer += buffer.substr(pos0, pos-pos0);
size_t posEnd = buffer.find(KEY_END, pos);
if (posEnd != string::npos)
{
const word k(cleanKey(buffer.substr(pos+lBegin, posEnd-pos-lEnd)));
keys.insert(k);
cleanedBuffer += keyify(k);
}
pos = posEnd + lEnd;
pos0 = pos;
}
cleanedBuffer += buffer.substr(pos0, buffer.length() - pos0);
buffer = cleanedBuffer;
return keys.toc();
}
void Foam::substitutionModel::addBuiltinStr
(
const word& key,
const string& value
)
{
builtin_.insert(cleanKey(key), value.c_str());
}
bool Foam::substitutionModel::containsBuiltin(const word& key)
{
return builtin_.contains(key);
}
void Foam::substitutionModel::setBuiltinStr
(
const word& key,
const string& value
)
{
builtin_.set(cleanKey(key), value.c_str());
}
bool Foam::substitutionModel::replaceBuiltin(const word& key, string& str)
{
if (builtin_.found(key))
{
str.replaceAll(keyify(key), builtin_[key].c_str());
return true;
}
return false;
}
bool Foam::substitutionModel::replaceBuiltin(string& str)
{
const string str0 = str;
// Quick exit if there are no keys in the string
if (str.find(KEY_BEGIN) == string::npos) return false;
forAllConstIters(builtin_, iter)
{
str.replaceAll(keyify(iter.key()), iter.val().c_str());
}
return str != str0;
}
void Foam::substitutionModel::writeBuiltins(Ostream& os)
{
for (const auto& iter : builtin_.csorted())
{
os << keyify(iter.key()).c_str() << " : " << iter.val() << nl;
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::substitutionModel::substitutionModel
(
const dictionary& dict,
const Time& time
)
:
dict_(dict),
time_(time)
{}
// ************************************************************************* //

View File

@ -0,0 +1,206 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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/>.
Class
Foam::substitutionModel
Description
Base class for substitution models.
Provides a static hash table for builtin keyword-value pairs and functions
to manipulate/interact.
SourceFiles
substitutionModel.C
substitutionModelNew.C
---------------------------------------------------------------------------*/
#ifndef Foam_substitutionModel_H
#define Foam_substitutionModel_H
#include "runTimeSelectionTables.H"
#include "dictionary.H"
#include "Time.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class substitutionModel Declaration
\*---------------------------------------------------------------------------*/
class substitutionModel
{
public:
// Static Data Members
//- Keyword starting characters
static const word KEY_BEGIN;
//- Keyword ending characters
static const word KEY_END;
//- Built-in substitutions
static HashTable<string> builtin_;
// Static Member Functions
//- Return a key representation from a word
static string keyify(const word& w);
//- Clean the key text
static word cleanKey(const string& str);
//- Return all keys from a string buffer
// Also cleans the key strings in the buffer
static wordList getKeys(string& buffer);
//- Add a builtin to the hash table - does not overwrite
static void addBuiltinStr(const word& key, const string& value);
//- Add a builtin to the hash table - does not overwrite
template<class Type>
static void addBuiltin(const word& key, const Type& value);
//- Return true if key is builtin
static bool containsBuiltin(const word& key);
//- Set a builtin to the hash table
static void setBuiltinStr(const word& key, const string& value);
//- Set a builtin to the hash table
template<class Type>
static void setBuiltin(const word& key, const Type& value);
//- Replace key in string
static bool replaceBuiltin(const word& key, string& str);
//- Replace all occurrences of key in string
static bool replaceBuiltin(string& str);
//- Write all builtins to stream
static void writeBuiltins(Ostream& os);
private:
// Private Functions
//- No copy construct
substitutionModel(const substitutionModel&) = delete;
//- No copy assignment
void operator=(const substitutionModel&) = delete;
protected:
// Protected Data
//- Construction dictionary
const dictionary dict_;
//- Reference to the time database
const Time& time_;
public:
//- Runtime type information
TypeName("substitutionModel");
// Declare run-time constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
substitutionModel,
dictionary,
(
const dictionary& dict,
const Time& time
),
(dict, time)
);
// Selectors
//- Return a reference to the selected substitution model
static autoPtr<substitutionModel> New
(
const dictionary& dict,
const Time& time
);
//- Constructor
substitutionModel
(
const dictionary& dict,
const Time& time
);
//- Destructor
virtual ~substitutionModel() = default;
// Member Functions
//- Update model local data
virtual bool update() { return true; }
//- Return true of model applies to this keyName
virtual bool valid(const word& keyName) const = 0;
//- Apply substitutions to this string buffer
virtual bool apply(const word& key, string& buffer) const = 0;
//- Return a word list of the keys
virtual wordList keys() const = 0;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "substitutionModelTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,60 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "substitutionModel.H"
#include "error.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Foam::autoPtr<Foam::substitutionModel> Foam::substitutionModel::New
(
const dictionary& dict,
const Time& time
)
{
const word modelType(dict.get<word>("type"));
Info<< " Selecting substitution model " << modelType << endl;
auto* ctorPtr = dictionaryConstructorTable(modelType);
if (!ctorPtr)
{
FatalIOErrorInLookup
(
dict,
"substitutionModel",
modelType,
*dictionaryConstructorTablePtr_
) << exit(FatalIOError);
}
return autoPtr<substitutionModel>(ctorPtr(dict, time));
}
// ************************************************************************* //

View File

@ -0,0 +1,47 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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/>.
\*---------------------------------------------------------------------------*/
template<class Type>
void Foam::substitutionModel::addBuiltin(const word& key, const Type& value)
{
OStringStream oss;
oss << value;
addBuiltinStr(key, oss.str());
}
template<class Type>
void Foam::substitutionModel::setBuiltin(const word& key, const Type& value)
{
OStringStream oss;
oss << value;
setBuiltinStr(key, oss.str());
}
// ************************************************************************* //

View File

@ -0,0 +1,99 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "userValue.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace substitutionModels
{
defineTypeNameAndDebug(userValue, 0);
addToRunTimeSelectionTable
(
substitutionModel,
userValue,
dictionary
);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::substitutionModels::userValue::userValue
(
const dictionary& dict,
const Time& time
)
:
substitutionModel(dict, time),
entries_()
{
// Populate entries
const dictionary& entriesDict = dict.subDict("entries");
for (const auto& e : entriesDict)
{
entries_.insert(cleanKey(e.keyword()), string(e.stream()));
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::substitutionModels::userValue::valid
(
const word& keyName
) const
{
return entries_.found(keyName);
}
bool Foam::substitutionModels::userValue::apply
(
const word& key,
string& buffer
) const
{
if (!valid(key)) return false;
buffer.replaceAll(keyify(key), entries_[key]);
return true;
}
Foam::wordList Foam::substitutionModels::userValue::keys() const
{
return entries_.sortedToc();
}
// ************************************************************************* //

View File

@ -0,0 +1,137 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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/>.
Class
Foam::substitutionModels::userValue
Description
The \c userValue substitution model. Dictionaries can be retrieved from
an object registry, e.g. time, mesh, or from a file.
\verbatim
userValues1
{
// Mandatory entries
type userValue;
entries
{
my_keyword1 "My local string value";
my_keyword2 "My local string value";
}
// Inherited entries
...
}
\endverbatim
The entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: userValue | word | yes | -
entries | Keyword lookup pairs | dictionary | yes | -
\endtable
The inherited entries are elaborated in:
- \link substitutionModel.H \endlink
SourceFiles
userValue.C
---------------------------------------------------------------------------*/
#ifndef Foam_substitutionModels_userValue_H
#define Foam_substitutionModels_userValue_H
#include "substitutionModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace substitutionModels
{
/*---------------------------------------------------------------------------*\
Class userValue Declaration
\*---------------------------------------------------------------------------*/
class userValue
:
public substitutionModel
{
// Private Data
//- Hash table for key and environment variable pairs
HashTable<string> entries_;
// Private Functions
//- No copy construct
userValue(const userValue&) = delete;
//- No copy assignment
void operator=(const userValue&) = delete;
public:
//- Runtime type information
TypeName("userValue");
//- Constructor
userValue(const dictionary& dict, const Time& time);
//- Destructor
virtual ~userValue() = default;
// Member Functions
//- Return true of model applies to this keyName
virtual bool valid(const word& keyName) const;
//- Apply substitutions to this string buffer
virtual bool apply(const word& key, string& buffer) const;
//- Return a word list of the keys
virtual wordList keys() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace substitutionModels
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,238 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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/>.
Namespace
Foam::SVG
Description
Collection of tools to generate SVG strings
SourceFiles
SVGTools.H
\*---------------------------------------------------------------------------*/
#ifndef Foam_SVGTools_H
#define Foam_SVGTools_H
#include "Ostream.H"
#include "OStringStream.H"
#include "List.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Namespace SVG Declaration
\*---------------------------------------------------------------------------*/
namespace SVG
{
typedef std::pair<const char*, string> entryType;
struct element;
Ostream& operator<<(Ostream& os, const element& e);
// Base SVG element
struct element
{
const word key_;
DynamicList<entryType> styles_;
DynamicList<entryType> elems_;
element
(
const word& key,
const std::initializer_list<entryType>& styles = {},
const std::initializer_list<entryType>& elems = {}
)
:
key_(key),
styles_(styles),
elems_(elems)
{}
template<class Type>
void addAttr(const char* key, const Type& value)
{
OStringStream oss;
oss << value;
elems_.push_back(entryType(key, oss.str().c_str()));
}
void addAttrStr(const char* key, const string& str)
{
elems_.push_back(entryType(key, str.c_str()));
}
friend Ostream& operator<<(Ostream& os, const element& ele)
{
os << "<" << ele.key_;
for (const auto& e : ele.elems_)
{
os << " " << e.first << "=" << e.second;
}
os << " style=\"";
for (const auto& s : ele.styles_)
{
os << s.first << ":" << s.second.c_str() << ";";
}
os << "\">";
return os;
}
const word end = "</" + key_ + ">";
};
struct text;
Ostream& operator<<(Ostream& os, const text& t);
// Text
struct text
:
element
{
const string text_;
text
(
const string text,
const label left,
const label top,
const std::initializer_list<entryType>& styles = {},
const word anchor = "middle",
const std::initializer_list<entryType>& elems = {}
)
:
element("text", styles, elems),
text_(text)
{
elems_.push_back(entryType("x", Foam::name(left)));
elems_.push_back(entryType("y", Foam::name(top)));
elems_.push_back(entryType("text-anchor", anchor));
elems_.push_back
(
entryType("font-family", "Arial, Helvetica, sans-serif")
);
}
friend Ostream& operator<<(Ostream& os, const text& t)
{
// element::operator<<(os, t);
os << static_cast<const element&>(t);
os << t.text_.c_str();
os << t.end;
return os;
}
};
struct line;
Ostream& operator<<(Ostream& os, const line& l);
// Line
struct line
:
element
{
line
(
const label x1,
const label y1,
const label x2,
const label y2,
const std::initializer_list<entryType>& styles = {},
const std::initializer_list<entryType>& elems = {}
)
:
element("line", styles, elems)
{
elems_.push_back(entryType("x1", Foam::name(x1)));
elems_.push_back(entryType("y1", Foam::name(y1)));
elems_.push_back(entryType("x2", Foam::name(x2)));
elems_.push_back(entryType("y2", Foam::name(y2)));
}
friend Ostream& operator<<(Ostream& os, const line& l)
{
// element::operator<<(os, l);
os << static_cast<const element&>(l);
os << l.end;
return os;
}
};
struct header;
Ostream& operator<<(Ostream& os, const header& h);
// Header
struct header
{
label width_;
label height_;
header(const label width, const label height)
:
width_(width),
height_(height)
{}
friend Ostream& operator<<(Ostream& os, const header& h)
{
os << "<svg viewBox=\"0 0 " << h.width_ << ' ' << h.height_ << "\""
<< " xmlns=\"http://www.w3.org/2000/svg\""
<< " xmlns:xlink=\"http://www.w3.org/1999/xlink\""
<< " xmlns:bx=\"https://www.boxy-svg.com/bx\">";
return os;
}
};
// Close SVG element
const char* end = "</svg>";
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace SVG
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,654 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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 "graphFunctionObject.H"
#include "addToRunTimeSelectionTable.H"
#include "OFstream.H"
#include "labelVector.H"
#include "FlatOutput.H"
#include "SVGTools.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
defineTypeNameAndDebug(graphFunctionObject, 0);
addToRunTimeSelectionTable
(
functionObject,
graphFunctionObject,
dictionary
);
}
}
// 'Muted' colour scheme from https://personal.sron.nl/~pault/ (12.07.24)
Foam::wordList Foam::functionObjects::graphFunctionObject::defaultColours
({
"#CC6677",
"#332288",
"#DDCC77",
"#117733",
"#88CCEE",
"#882255",
"#44AA99",
"#999933",
"#AA4499"
});
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class Type>
bool Foam::functionObjects::graphFunctionObject::getValue
(
const label objecti,
label& valuei
)
{
const word& object = objects_[objecti];
const word& entry = entries_[objecti];
Type result;
if (!this->getObjectResult(object, entry, result))
{
return false;
}
auto& cols = objectToCol_[objecti];
if (cols.empty())
{
for (direction d = 0; d < pTraits<Type>::nComponents; ++d)
{
cols.push_back(valuei++);
values_.push_back(DynamicList<scalar>());
}
}
for (direction d = 0; d < pTraits<Type>::nComponents; ++d)
{
scalar v = component(result, d);
if (logScaleY_)
{
v = (v < SMALL) ? 1 : log10(v);
}
values_[cols[d]].push_back(v);
}
return true;
}
Foam::label Foam::functionObjects::graphFunctionObject::setAxisProps
(
const bool logScale,
scalar& xmin,
scalar& xmax,
scalar& xtick
) const
{
DebugInfo
<< "1 -- xmin:" << xmin << " xmax:" << xmax
<< " xtick:" << xtick << endl;
/*
Divisions Based on (12.07.24):
https://peltiertech.com/calculate-nice-axis-scales-in-your-excel-worksheet
*/
const scalar range = xmax - xmin;
const scalar eps = 0.01*range;
// Extend xmin and xmax by eps
if (mag(xmin) < SMALL)
{
xmin = 0;
}
else
{
xmin = (xmin > 0) ? max(0, xmin - eps) : xmin - eps;
}
if (mag(xmax) < SMALL)
{
xmax = mag(xmin) < SMALL ? 1 : 0;
}
else
{
xmax = (xmax < 0) ? min(0, xmax + eps) : xmax + eps;
}
DebugInfo
<< "2 -- xmin:" << xmin << " xmax:" << xmax
<< " xtick:" << xtick << endl;
auto lookup = [](const scalar x) -> scalar
{
if (x < 2.5) { return 0.2; }
if (x < 5.0) { return 0.5; }
if (x < 10.0) { return 2.0; }
return 10.0;
};
const scalar power = log10(range);
const scalar factor = pow(10, power - floor(power));
xtick = lookup(factor)*pow(10, floor(power));
xmin = xtick*floor(xmin/xtick);
xmax = xtick*(floor(xmax/xtick) + 1);
// Convert ticks to integer powers of 10 for log scales
if (logScale)
{
xmin = floor(xmin);
xmax = ceil(xmax);
xtick = 1;
}
DebugInfo
<< "power:" << power << " factor:" << factor
<< " xmin:" << xmin << " xmax:" << xmax
<< " xtick:" << xtick << endl;
return round((xmax - xmin)/xtick);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjects::graphFunctionObject::graphFunctionObject
(
const word& name,
const Time& runTime,
const dictionary& dict
)
:
stateFunctionObject(name, runTime),
writeFile(runTime, name, typeName, dict, true, ".svg"),
objects_(),
entries_(),
titles_(),
colours_(),
dashes_(),
times_(),
values_(),
objectToCol_(),
xMin_(dict.getOrDefault<scalar>("xMin", GREAT)),
xMax_(dict.getOrDefault<scalar>("xMax", GREAT)),
yMin_(dict.getOrDefault<scalar>("yMin", GREAT)),
yMax_(dict.getOrDefault<scalar>("yMax", GREAT)),
xlabel_(dict.getOrDefault<string>("xlabel", "Iteration/Time")),
ylabel_(dict.getOrDefault<string>("ylabel", "Property")),
width_(dict.getOrDefault<label>("width", 800)),
height_(dict.getOrDefault<label>("height", 600)),
strokeWidth_(dict.getOrDefault<label>("strokeWidth", 2)),
logScaleX_(dict.getOrDefault<bool>("logScaleX", false)),
logScaleY_(dict.getOrDefault<bool>("logScaleY", false)),
drawGrid_(dict.getOrDefault<bool>("drawGrid", true))
{
const dictionary& functions = dict.subDict("functions");
objects_.setSize(functions.size());
entries_.setSize(functions.size());
titles_.setSize(functions.size());
colours_.setSize(functions.size());
dashes_.setSize(functions.size());
objectToCol_.setSize(functions.size());
label defaultColouri = 0;
label entryi = 0;
for (const auto& e : functions)
{
if (!e.isDict())
{
FatalIOErrorInFunction(functions)
<< "Functions must be provided in dictionary format"
<< exit(FatalIOError);
}
const dictionary& d = e.dict();
objects_[entryi] = d.get<word>("object");
entries_[entryi] = d.get<word>("entry");
titles_[entryi] = d.getOrDefault<string>("title", e.keyword());
labelVector colour;
if (d.readIfPresent("colour", colour))
{
// Warn/error if outside 0-255 range?
colour[0] = min(255, max(0, colour[0]));
colour[1] = min(255, max(0, colour[1]));
colour[2] = min(255, max(0, colour[2]));
OStringStream oss;
oss << "rgb" << flatOutput(colour, FlatOutput::ParenComma{});
colours_[entryi] = oss.str();
}
else
{
colours_[entryi] = defaultColours[defaultColouri++];
if (defaultColouri == defaultColours.size())
{
// Lots of lines to plot - exhausted list of default colours.
// Restarting ...
defaultColouri = 0;
}
}
{
labelList dashes;
if (d.readIfPresent("dashes", dashes))
{
OStringStream oss;
oss << flatOutput(dashes, FlatOutput::BareSpace{});
dashes_[entryi] = oss.str();
}
else
{
// Solid line
dashes_[entryi] = "0";
}
}
++entryi;
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionObjects::graphFunctionObject::execute()
{
if (!Pstream::master()) return true;
scalar& graphTime = times_.emplace_back(time_.timeOutputValue());
if (logScaleX_)
{
graphTime = log10(max(graphTime, SMALL));
}
label valuei = 0;
forAll(objects_, objecti)
{
bool ok =
getValue<label>(objecti, valuei)
|| getValue<scalar>(objecti, valuei)
|| getValue<vector>(objecti, valuei)
|| getValue<sphericalTensor>(objecti, valuei)
|| getValue<symmTensor>(objecti, valuei)
|| getValue<tensor>(objecti, valuei);
if (!ok)
{
// Entry not found
Log << type() << " " << name() << " execute: "
<< "Unable to get value for object:" << objects_[objecti]
<< " entry:" << entries_[objecti] << endl;
}
}
return true;
}
bool Foam::functionObjects::graphFunctionObject::write()
{
if (!Pstream::master()) return true;
// DebugVar(values_);
auto filePtr = newFileAtTime(name(), time().value());
auto& os = filePtr();
scalar ymin = GREAT;
scalar ymax = -GREAT;
bool valid = false;
for (const auto& data : values_)
{
for (const auto& value : data)
{
ymin = min(ymin, value);
ymax = max(ymax, value);
valid = true;
}
}
// Early exit if there is no data
if (!valid)
{
Log << type() << " " << name() << " write:" << nl
<< " No data to plot - skipping" << nl;
// Empty graph
os << SVG::header(width_, height_) << nl << SVG::end << endl;
return false;
}
auto applyLimits = [](const scalar val, const scalar lim, const bool lg)
{
if (lim < 0.99*GREAT)
{
return lg ? log10(lim) : lim;
}
return val;
};
// Set y axis limits if user-supplied
ymin = applyLimits(ymin, yMin_, logScaleY_);
ymax = applyLimits(ymax, yMax_, logScaleY_);
scalar ytick = 0;
const label ny = setAxisProps(logScaleY_, ymin, ymax, ytick);
const scalar border = 0.1;
const scalar w = width_*(1.0 - 2*border);
const scalar h = height_*(1.0 - 2*border);
// Set x axis limits if user-supplied
scalar xmin = applyLimits(0, xMin_, logScaleX_);
scalar xmax = applyLimits(max(times_), xMax_, logScaleX_);
// Set x axis properties; return the number of tic divisions
scalar xtick = 0;
const label nx = setAxisProps(logScaleX_, xmin, xmax, xtick);
// Top pixel co-ordinate
auto top = [=](const scalar y)
{
const scalar ratio = (y - ymin)/(ymax - ymin + ROOTVSMALL);
return round(height_ - ratio*h - border*height_);
};
// Left pixel co-ordinate
auto left = [=](const scalar x)
{
return round(x/(xmax - xmin + ROOTVSMALL)*w + border*width_);
};
const scalar fontpx = min(20, h/(2*values_.size()));
const scalar fontdy = 1.5*fontpx;
// Legend - top right: text (right aligned), coloured line (fixed positions)
const label legendLineRight = border*width_ + w - fontpx;
const label legendLineLeft = legendLineRight - 0.5*border*width_;
const label legendLabelRight = legendLineLeft - 0.5*fontpx;
// Graph box and tick colour
const word colour = "rgb(105,105,105)";
os << SVG::header(width_, height_) << nl;
// Graph bounding box
SVG::element bounds("rect", {{"fill", "none"}, {"stroke", colour}});
bounds.addAttr("x", round(border*width_));
bounds.addAttr("y", round(border*height_));
bounds.addAttr("width", round(w));
bounds.addAttr("height", round(h));
os << bounds << bounds.end << nl;
// X axis label
os << SVG::text
(
xlabel_,
0.5*width_,
height_ - 0.5*(border*height_) + fontpx,
{{"font-size", Foam::name(1.2*fontpx)}},
"middle"
)
<< nl;
// Y axis label - text rotated
SVG::text ytext
(
ylabel_,
0,
0,
{{"font-size", Foam::name(1.2*fontpx)}},
"middle"
);
ytext.addAttr("alignment-baseline", "middle");
ytext.addAttrStr
(
"transform",
"translate(" + Foam::name(left(xmin) - 3*fontpx) + ","
+ Foam::name(0.5*height_) + ") rotate(270)"
);
os << ytext << nl;
const label dTick = 0.2*fontpx;
// Background grid
if (drawGrid_)
{
const word colourGrid = "rgb(200,200,200)";
for (label i = 1; i < nx; ++i)
{
const label x = left(xmin + i*xtick);
const label y1 = top(ymin);
const label y2 = top(ymax);
// Dashed grid lines
os << SVG::line
(
x,
y1,
x,
y2,
{
{"stroke", colourGrid},
{"stroke-width", "1"},
{"stroke-dasharray", "4"}
}
) << nl;
}
for (label i = 1; i < ny; ++i)
{
const label y = top(ymin + i*ytick);
const label x1 = left(xmin);
const label x2 = left(xmax);
// Dashed grid lines
os << SVG::line
(
x1,
y,
x2,
y,
{
{"stroke", colourGrid},
{"stroke-width", "1"},
{"stroke-dasharray", "4"}
}
) << nl;
}
}
// Axis labels
for (label i = 0; i <= nx; ++i)
{
const scalar v = xmin + i*xtick;
const label x = left(v);
const scalar y0 = ymin;
const label y1 = top(y0);
const label y2 = y1 + dTick;
const string tickLabel = logScaleX_
? "<tspan>10<tspan style=\"font-size:"
+ Foam::name(label(0.75*fontpx))
+ "px\" dy=\"" + Foam::name(-0.4*fontpx) + "\">"
+ Foam::name(v)
+ "</tspan></tspan>"
: Foam::name(v);
// Ticks
os << SVG::line
(
x,
y1,
x,
y2,
{
{"stroke", colour},
{"stroke-width", Foam::name(strokeWidth_)}
}
) << nl;
// Labels
os << SVG::text
(
tickLabel,
x,
y2 + 1.25*fontpx,
{{"font-size", Foam::name(fontpx)}},
"middle"
) << nl;
}
for (label i = 0; i <= ny; ++i)
{
const scalar v = ymin + i*ytick;
const label y = top(v);
const label y2 = y + 0.4*fontpx;
const scalar x0 = xmin;
const label x1 = left(x0);
const label x2 = x1 - dTick;
const string tickLabel = logScaleY_
? "<tspan>10<tspan style=\"font-size:"
+ Foam::name(label(0.6*fontpx))
+ "px\" dy=\"" + Foam::name(-0.4*fontpx) + "\">"
+ Foam::name(v)
+ "</tspan></tspan>"
: Foam::name(v);
// Ticks
os << SVG::line
(
x1,
y,
x2,
y,
{{"stroke", colour},{"stroke-width", "1"}}
) << nl;
// Labels
os << SVG::text
(
tickLabel,
x2 - 0.5*fontpx,
y2,
{{"font-size", Foam::name(fontpx)}},
"end"
) << nl;
}
forAll(objects_, objecti)
{
const word& colour = colours_[objecti];
const auto& cols = objectToCol_[objecti];
for (const label c : cols)
{
const word cmpt = cols.size() > 1 ? Foam::name(c) : "";
label legendTop = border*height_ + fontdy*(c+1);
os << SVG::text
(
titles_[objecti] + cmpt,
legendLabelRight,
legendTop,
{{"font-size", Foam::name(fontpx)}},
"end"
) << nl;
os << SVG::line
(
legendLineLeft,
legendTop - 0.5*fontpx,
legendLineRight,
legendTop - 0.5*fontpx,
{{"stroke", colour},{"stroke-width", "2"}},
{{"stroke-dasharray", dashes_[objecti]}}
) << nl;
os << "<path d=\"";
const auto& data = values_[c];
bool firstPoint = true;
forAll(data, i)
{
const scalar t = times_[i];
const scalar v = data[i];
if ((v > ymin) && (v < ymax))
{
if (firstPoint)
{
os << " M ";
}
else
{
os << " L ";
}
os << left(t) << ' ' << top(v);
firstPoint = false;
}
else
{
firstPoint = true;
}
}
os << "\""
<< " style=\"stroke:" << colour << ";"
<< " fill:none; stroke-width:2;\""
<< " stroke-dasharray=\"" << dashes_[objecti].c_str() << "\" />"
<< nl;
}
}
os << SVG::end << endl;
Log << type() << " " << name() << " write:" << nl
<< " Written file " << os.name() << nl << endl;
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,300 @@
/*---------------------------------------------------------------------------*\
========= |
\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\ / O peration |
\ / A nd | www.openfoam.com
\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 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/>.
Class
Foam::functionObjects::graphFunctionObject
Description
Accumulates function object result values and renders into a graph in
SVG format.
Operands:
\table
Operand | Type | Location
input | Function object results | Memory; <!--
--> $FOAM_CASE/\<time\>/uniform/functionObjects/functionObjectProperties
output file | SVG | <!--
--> $FOAM_CASE/postProcessing/<functionObject>/<time>/<functionObject>.svg
\endtable
Usage
Minimal example by using \c system/controlDict.functions to plot the
residuals from the \c solverInfo function object:
\verbatim
residualGraph
{
// Mandatory entries
type graphFunctionObject;
libs (utilityFunctionObjects);
functions
{
entry
{
// Mandatory entries
object <word>;
entry <word>;
// Optional entries
title <string>;
colour <labelVector>;
dashes <labelList>;
}
line1
{
object solverInfo1;
entry Ux_initial;
}
line2
{
object solverInfo1;
entry p_initial;
}
}
// Optional entries
xMin <scalar>;
xMax <scalar>;
yMin <scalar>;
yMax <scalar>;
xlabel <string>; // "Iteration";
ylabel <string>; // "log10(Initial residual)";
width <label>;
height <label>;
strokeWidth <label>;
logScaleX <bool>;
logScaleY <bool>;
drawGrid <bool>;
// Inherited entries
...
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: graphFunctionObject | word | yes | -
libs | Library name: utilityFunctionObjects | word | yes | -
functions | Dictionary of lines to draw | dictionary | yes | -
width | Output SVG width in pixel | label| no | 800
height | Output SVG height in pixel | label| no | 600
xMin | User defined minimum x axis limit | scalar | no | calculated
xMax | User defined maximum x axis limit | scalar | no | calculated
yMin | User defined minimum y axis limit | scalar | no | calculated
yMax | User defined maximum y axis limit | scalar | no | calculated
xLabel | X axis label | string | no | Iteration/Time
yLabel | Y axis label | string | no | Property
strokeWidth | Line stroke width in pixel | label | no | 2
logScaleX | Use log scale for x axis | bool | no | false
logScaleY | Use log scale for y axis | bool | no | false
drawGrid | Draw background grid | bool | no | true
\endtable
The inherited entries are elaborated in:
- \link stateFunctionObject.H \endlink
- \link writeFile.H \endlink
Each line corresponds to the history of function object result values, e.g.
\verbatim
line1
{
object solverInfo1;
entry Ux_initial;
colour (255 0 0);
dashes (4 1);
title Ux;
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
object | Function object name | word | yes | -
entry | Function object result entry name | word | yes | -
colour | Line colour | label vector | no | auto
dashes | Line dash array | label vector | no | auto
title | Title | string | no | dict name
\endtable
See also
- Foam::functionObjects::solverInfo
SourceFiles
graphFunctionObject.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_functionObjects_graphFunctionObject_H
#define Foam_functionObjects_graphFunctionObject_H
#include "stateFunctionObject.H"
#include "writeFile.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
/*---------------------------------------------------------------------------*\
Class graphFunctionObject Declaration
\*---------------------------------------------------------------------------*/
class graphFunctionObject
:
public stateFunctionObject,
public writeFile
{
// Private Data
//- List of default curve colours
static wordList defaultColours;
//- Names of function objects
List<word> objects_;
//- Function object entries
List<word> entries_;
//- Line titles
List<string> titles_;
//- Line colours - hex string
List<word> colours_;
//- Line dash array
List<string> dashes_;
//- Times
DynamicList<scalar> times_;
//- Time vs. flattened values
DynamicList<DynamicList<scalar>> values_;
//- Mapping from object to column index in values_
List<DynamicList<label>> objectToCol_;
//- User-supplied minimum x value
scalar xMin_;
//- User-supplied maximum x value
scalar xMax_;
//- User-supplied minimum y value
scalar yMin_;
//- User-supplied maximum y value
scalar yMax_;
//- X axis label
const string xlabel_;
//- Y axis label
const string ylabel_;
//- Width in px
const label width_;
//- Height in px
const label height_;
//- Line width in px
const label strokeWidth_;
//- Flag to use log scale on x-axis
bool logScaleX_;
//- Flag to use log scale on y-axis
bool logScaleY_;
//- Draw background grid
const bool drawGrid_;
// Private Functions
//- Get the result value from the function object
// \returns true if the value was found
template<class Type>
bool getValue(const label objecti, label& valuei);
//- Set axis min, max, tick
// \returns number of ticks
label setAxisProps
(
const bool logScale,
scalar& xmin,
scalar& xmax,
scalar& xtick
) const;
//- No copy construct
graphFunctionObject(const graphFunctionObject&) = delete;
//- No copy assignment
void operator=(const graphFunctionObject&) = delete;
public:
//- Runtime type information
TypeName("graphFunctionObject");
//- Construct from Time and dictionary
graphFunctionObject
(
const word& name,
const Time& runTime,
const dictionary& dict
);
//- Destructor
virtual ~graphFunctionObject() = default;
// Member Functions
//- Execute
virtual bool execute();
//- Write
virtual bool write();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace functionObjects
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -51,6 +51,10 @@ functions
#include "cuttingPlane"
#include "forceCoeffs"
#include "ensightWrite"
#include "solverInfo"
#include "graphFunctionObject"
#include "foamReport"
}

View File

@ -0,0 +1,59 @@
foamReport1
{
type foamReport;
libs (utilityFunctionObjects);
writeControl writeTime;
template "<system>/myReportTemplate.md";
substitutions
{
timing1
{
type fileRegEx;
path "log.simpleFoam";
entries
{
executionTime "ExecutionTime = (.*) s Clock.*";
}
}
divSchemes1
{
type dictionaryValue;
path "<system>/fvSchemes";
entries
{
divSchemes "divSchemes";
}
}
fvSolution1
{
type dictionaryValue;
path "<system>/fvSolution";
entries
{
solver_p "solvers/p/solver";
solver_p_tol "solvers/p/tolerance";
solver_p_reltol "solvers/p/relTol";
solver_U "solvers/U/solver";
solver_U_tol "solvers/U/tolerance";
solver_U_reltol "solvers/U/relTol";
}
}
controlDict1
{
type dictionaryValue;
path "<system>/controlDict";
entries
{
initial_deltaT "deltaT";
}
}
}
}

View File

@ -0,0 +1,142 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2406 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
residualGraph1
{
// Mandatory entries
type graphFunctionObject;
libs (utilityFunctionObjects);
functions
{
Ux
{
// Mandatory entries
object solverInfo1;
entry Ux_initial;
// Optional entries
// title <string>;
// colour <labelVector>;
// dashes <labelList>;
}
Uy
{
object solverInfo1;
entry Uy_initial;
}
Uz
{
object solverInfo1;
entry Uz_initial;
}
p
{
object solverInfo1;
entry p_initial;
}
}
// Optional entries
logScaleX no;
logScaleY yes;
xlabel "Iteration";
ylabel "log10(Initial residual)";
// xMin <scalar>;
// xMax <scalar>;
// yMin <scalar>;
// yMax <scalar>;
// width <label>;
// height <label>;
// strokeWidth <label>;
// drawGrid <bool>;
// Inherited entries
writePrecision 6;
writeToFile true;
useUserTime true;
region region0;
enabled true;
log true;
timeStart 0;
timeEnd 1000;
executeControl timeStep;
executeInterval 1;
writeControl writeTime;
writeInterval -1;
}
forceCoeffsGraph1
{
type graphFunctionObject;
libs (utilityFunctionObjects);
writeControl writeTime;
logScaleX no;
logScaleY no;
xlabel "Iteration";
ylabel "Coefficient";
yMin -1;
yMax 1;
functions
{
Cd
{
object forceCoeffs1;
entry Cd;
}
// CdMean
// {
// object valueAverage1;
// entry CdMean;
// }
Cd(f)
{
object forceCoeffs1;
entry Cd(f);
}
Cd(r)
{
object forceCoeffs1;
entry Cd(r);
}
Cl
{
object forceCoeffs1;
entry Cl;
//colour (0, 0, 0);
}
// ClMean
// {
// object valueAverage1;
// entry ClMean;
// }
Cl(f)
{
object forceCoeffs1;
entry Cl(f);
//colour (0, 0, 0);
title Cl(f);
}
Cl(r)
{
object forceCoeffs1;
entry Cl(r);
//colour (0, 0, 0);
title Cl(r);
}
}
}
// ************************************************************************* //

View File

@ -0,0 +1,104 @@
---
marp: true
paginate: true
---
<style>
:root {
font-size: 20px;
}
td {
width: 1000px;
}
table {
width: 100%;
}
img {
display: block;
margin-left: auto;
margin-right: auto;
width: 60%;
}
</style>
# {{OF_EXECUTABLE}} : {{OF_CASE_NAME}} tutorial
- Case: {{OF_CASE_PATH}}
- Submission: {{OF_CLOCK_START}} on {{OF_DATE_START}}
- Report time: {{OF_CLOCK_NOW}} on {{OF_DATE_NOW}}
---
## Run information
| Property | Value |
|----------------|--------------------|
| Host | {{OF_HOST}} |
| Processors | {{OF_NPROCS}} |
| Time steps | {{OF_TIME_INDEX}} |
| Initial deltaT | {{initial_deltaT}} |
| Current deltaT | {{OF_TIME_DELTAT}} |
| Execution time | {{executionTime}} |
---
## OpenFOAM information
| Property | Value |
|----------------|--------------------|
| Version | {{OF_VERSION}} |
| API | {{OF_API}} |
| Patch | {{OF_PATCH}} |
| Build | {{OF_BUILD}} |
| Architecture | {{OF_BUILD_ARCH}} |
---
## Mesh statistics
| Property | Value |
|-------------------|----------------------|
| Bounds | {{OF_MESH_BOUNDS_MIN}}{{OF_MESH_BOUNDS_MAX}} |
| Number of cells | {{OF_MESH_NCELLS}} |
| Number of faces | {{OF_MESH_NFACES}} |
| Number of points | {{OF_MESH_NPOINTS}} |
| Number of patches | {{OF_MESH_NPATCHES}} |
---
## Linear solvers
| Property | Value | tolerance(rel) | Tolerance(abs) |
|----------|----------------|------------------|---------------------|
| p | `{{solver_p}}` | {{solver_p_tol}} | {{solver_p_reltol}} |
| U | `{{solver_U}}` | {{solver_u_tol}} | {{solver_u_reltol}} |
---
## Numerical scehemes
The chosen divergence schemes comprised:
~~~
{{divSchemes}}
~~~
---
## Graphs
Residuals
![]({{OF_CASE_PATH}}/postProcessing/residualGraph1/{{OF_TIME}}/residualGraph1.svg)
---
## Results
Forces
![]({{OF_CASE_PATH}}/postProcessing/forceCoeffsGraph1/{{OF_TIME}}/forceCoeffsGraph1.svg)
---
Made using Open&nabla;FOAM v2412 from https://openfoam.com

View File

@ -0,0 +1,21 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2406 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
solverInfo1
{
// Mandatory entries
type solverInfo;
libs (utilityFunctionObjects);
fields (U p);
// Optional entries
writeResidualFields no;
}
// ************************************************************************* //