diff --git a/src/functionObjects/utilities/Make/files b/src/functionObjects/utilities/Make/files index aed6a6fa70dd76862b514715b14d950ddc2789c8..9da1341dfa4c24e926fd98462203b5aec976a3d3 100644 --- a/src/functionObjects/utilities/Make/files +++ b/src/functionObjects/utilities/Make/files @@ -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 diff --git a/src/functionObjects/utilities/foamReport/foamReport.C b/src/functionObjects/utilities/foamReport/foamReport.C new file mode 100644 index 0000000000000000000000000000000000000000..349fbf777bed5ea7d048a43d5f2a8019d01bf07d --- /dev/null +++ b/src/functionObjects/utilities/foamReport/foamReport.C @@ -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; +} + + +// ************************************************************************* // diff --git a/src/functionObjects/utilities/foamReport/foamReport.H b/src/functionObjects/utilities/foamReport/foamReport.H new file mode 100644 index 0000000000000000000000000000000000000000..52651560cf3de5493d33138cad390c990a3c62c3 --- /dev/null +++ b/src/functionObjects/utilities/foamReport/foamReport.H @@ -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 + +// ************************************************************************* // diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/dictionaryValue/dictionaryValue.C b/src/functionObjects/utilities/foamReport/substitutionModels/dictionaryValue/dictionaryValue.C new file mode 100644 index 0000000000000000000000000000000000000000..d754ff598c4574d5d6606bbc0332411326389328 --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/dictionaryValue/dictionaryValue.C @@ -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(); +} + + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/dictionaryValue/dictionaryValue.H b/src/functionObjects/utilities/foamReport/substitutionModels/dictionaryValue/dictionaryValue.H new file mode 100644 index 0000000000000000000000000000000000000000..e1cd47506a623f857311cf8c6050ef5d38724ccf --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/dictionaryValue/dictionaryValue.H @@ -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 + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/environmentVariable/environmentVariable.C b/src/functionObjects/utilities/foamReport/substitutionModels/environmentVariable/environmentVariable.C new file mode 100644 index 0000000000000000000000000000000000000000..49e1951e02ae586b20e856b542f434baf753185d --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/environmentVariable/environmentVariable.C @@ -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(); +} + + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/environmentVariable/environmentVariable.H b/src/functionObjects/utilities/foamReport/substitutionModels/environmentVariable/environmentVariable.H new file mode 100644 index 0000000000000000000000000000000000000000..d72088e823b4219b27e19741fe0e3a1f6a8672bf --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/environmentVariable/environmentVariable.H @@ -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 + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/fileRegEx/fileRegEx.C b/src/functionObjects/utilities/foamReport/substitutionModels/fileRegEx/fileRegEx.C new file mode 100644 index 0000000000000000000000000000000000000000..37fc3f0d68c9dbc76f873adec166d5d1b8251ce2 --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/fileRegEx/fileRegEx.C @@ -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(); +} + + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/fileRegEx/fileRegEx.H b/src/functionObjects/utilities/foamReport/substitutionModels/fileRegEx/fileRegEx.H new file mode 100644 index 0000000000000000000000000000000000000000..891a1d6858f27fd5551322afb3b4997e0246ef37 --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/fileRegEx/fileRegEx.H @@ -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 + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/functionObjectValue/functionObjectValue.C b/src/functionObjects/utilities/foamReport/substitutionModels/functionObjectValue/functionObjectValue.C new file mode 100644 index 0000000000000000000000000000000000000000..34f5188331581d43a6d755bc923f424c9a829aa3 --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/functionObjectValue/functionObjectValue.C @@ -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(); +} + + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/functionObjectValue/functionObjectValue.H b/src/functionObjects/utilities/foamReport/substitutionModels/functionObjectValue/functionObjectValue.H new file mode 100644 index 0000000000000000000000000000000000000000..024ef6774c50e7234bcad368ab41432d8472f13e --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/functionObjectValue/functionObjectValue.H @@ -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 + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/substitutionModel/substitutionModel.C b/src/functionObjects/utilities/foamReport/substitutionModels/substitutionModel/substitutionModel.C new file mode 100644 index 0000000000000000000000000000000000000000..bac232c9516473341f34ff89750da8498f07bd43 --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/substitutionModel/substitutionModel.C @@ -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) +{} + + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/substitutionModel/substitutionModel.H b/src/functionObjects/utilities/foamReport/substitutionModels/substitutionModel/substitutionModel.H new file mode 100644 index 0000000000000000000000000000000000000000..d4c474416bba3df2798ac03fecad09a5aae11e87 --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/substitutionModel/substitutionModel.H @@ -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 + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/substitutionModel/substitutionModelNew.C b/src/functionObjects/utilities/foamReport/substitutionModels/substitutionModel/substitutionModelNew.C new file mode 100644 index 0000000000000000000000000000000000000000..c284136c373d29e39bd032209b7696deaabb0798 --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/substitutionModel/substitutionModelNew.C @@ -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)); +} + + +// ************************************************************************* // diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/substitutionModel/substitutionModelTemplates.C b/src/functionObjects/utilities/foamReport/substitutionModels/substitutionModel/substitutionModelTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..71a4a90b83a73e8e021e45cdd5cc1cfaaa963d38 --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/substitutionModel/substitutionModelTemplates.C @@ -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()); +} + + +// ************************************************************************* // diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/userValue/userValue.C b/src/functionObjects/utilities/foamReport/substitutionModels/userValue/userValue.C new file mode 100644 index 0000000000000000000000000000000000000000..4c05164c32f3692b880c810bb5bfdece26bfb96c --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/userValue/userValue.C @@ -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(); +} + + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/foamReport/substitutionModels/userValue/userValue.H b/src/functionObjects/utilities/foamReport/substitutionModels/userValue/userValue.H new file mode 100644 index 0000000000000000000000000000000000000000..78ec3a48183d533cbafed4d645c2bf40448f4d40 --- /dev/null +++ b/src/functionObjects/utilities/foamReport/substitutionModels/userValue/userValue.H @@ -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 + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/graphFunctionObject/SVGTools.H b/src/functionObjects/utilities/graphFunctionObject/SVGTools.H new file mode 100644 index 0000000000000000000000000000000000000000..18ec80537bf16377e63970da41a284fc77a0165c --- /dev/null +++ b/src/functionObjects/utilities/graphFunctionObject/SVGTools.H @@ -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 + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/graphFunctionObject/graphFunctionObject.C b/src/functionObjects/utilities/graphFunctionObject/graphFunctionObject.C new file mode 100644 index 0000000000000000000000000000000000000000..1627dbf6f26e4718a2050f246f4c9f0244bec989 --- /dev/null +++ b/src/functionObjects/utilities/graphFunctionObject/graphFunctionObject.C @@ -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; +} + + +// ************************************************************************* // \ No newline at end of file diff --git a/src/functionObjects/utilities/graphFunctionObject/graphFunctionObject.H b/src/functionObjects/utilities/graphFunctionObject/graphFunctionObject.H new file mode 100644 index 0000000000000000000000000000000000000000..73ddbac9d934e96ba7456027beaa07f94ea78749 --- /dev/null +++ b/src/functionObjects/utilities/graphFunctionObject/graphFunctionObject.H @@ -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 + +// ************************************************************************* // \ No newline at end of file diff --git a/tutorials/incompressible/simpleFoam/motorBike/system/controlDict b/tutorials/incompressible/simpleFoam/motorBike/system/controlDict index 6a42118c719acefc87b101e6a3b491494806f159..2e17d5d2c6ad8bf9e70372eaa456b86bb1c75e53 100644 --- a/tutorials/incompressible/simpleFoam/motorBike/system/controlDict +++ b/tutorials/incompressible/simpleFoam/motorBike/system/controlDict @@ -51,6 +51,10 @@ functions #include "cuttingPlane" #include "forceCoeffs" #include "ensightWrite" + + #include "solverInfo" + #include "graphFunctionObject" + #include "foamReport" } diff --git a/tutorials/incompressible/simpleFoam/motorBike/system/foamReport b/tutorials/incompressible/simpleFoam/motorBike/system/foamReport new file mode 100644 index 0000000000000000000000000000000000000000..f90a2f0683950dce6208530a4ca46dd067b86e7f --- /dev/null +++ b/tutorials/incompressible/simpleFoam/motorBike/system/foamReport @@ -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"; + } + } + } +} + diff --git a/tutorials/incompressible/simpleFoam/motorBike/system/graphFunctionObject b/tutorials/incompressible/simpleFoam/motorBike/system/graphFunctionObject new file mode 100644 index 0000000000000000000000000000000000000000..ba4f9a4a6716c67f135e5ab386f96c664a521204 --- /dev/null +++ b/tutorials/incompressible/simpleFoam/motorBike/system/graphFunctionObject @@ -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); + } + } +} + + +// ************************************************************************* // diff --git a/tutorials/incompressible/simpleFoam/motorBike/system/myReportTemplate.md b/tutorials/incompressible/simpleFoam/motorBike/system/myReportTemplate.md new file mode 100644 index 0000000000000000000000000000000000000000..5cdb747cd42fdc0ad5da2cf5cd08a12c8a04fef5 --- /dev/null +++ b/tutorials/incompressible/simpleFoam/motorBike/system/myReportTemplate.md @@ -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 + + + +--- + +## Results + +Forces + + + +--- + +Made using Open∇FOAM v2412 from https://openfoam.com diff --git a/tutorials/incompressible/simpleFoam/motorBike/system/solverInfo b/tutorials/incompressible/simpleFoam/motorBike/system/solverInfo new file mode 100644 index 0000000000000000000000000000000000000000..5c764aa47136cebc257d965e36ba6a6d0a5792f5 --- /dev/null +++ b/tutorials/incompressible/simpleFoam/motorBike/system/solverInfo @@ -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; +} + + +// ************************************************************************* //