From 510ffb332219fd55b158441dbfcb4509868a9b2b Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Tue, 7 Dec 2021 18:06:45 +0100 Subject: [PATCH] ENH: code reduction, improvements for expressions - literal lookups only for expression strings - code reduction for setExprFields. - changed keyword "condition" to "fieldMask" (option -field-mask). This is a better description of its purpose and avoids possible naming ambiguities with functionObject triggers (for example) if we apply similar syntax elsewhere. BUG: erroneous check in volumeExpr::parseDriver::isResultType() - not triggered since this method is not used anywhere (may remove in future version) --- .../setExprBoundaryFields.C | 15 +- .../setExprFields/setExprFields.C | 396 ++++++++---------- .../setExprFields/setExprFieldsDict | 4 +- etc/caseDicts/annotated/setExprFieldsDict | 4 +- .../Function1/Function1Expression.C | 4 +- .../expressions/exprDriver/exprDriver.H | 13 +- .../expressions/exprResult/exprResult.H | 9 +- .../expressions/exprString/exprString.C | 56 ++- .../expressions/exprString/exprString.H | 34 +- .../expressions/fields/fieldExprDriver.H | 4 +- .../PatchFunction1/PatchFunction1Expression.C | 4 +- .../expressions/base/fvExprDriver.H | 6 +- .../fields/base/patchExprFieldBase.C | 11 +- .../expressions/patch/patchExprDriver.H | 4 +- .../expressions/volume/volumeExprDriver.C | 108 ++++- .../expressions/volume/volumeExprDriver.H | 22 +- .../expressions/volume/volumeExprDriverI.H | 14 + .../volume/volumeExprDriverTemplates.C | 26 +- .../TJunctionAverage/system/setExprFieldsDict | 2 +- 19 files changed, 441 insertions(+), 295 deletions(-) diff --git a/applications/utilities/preProcessing/setExprBoundaryFields/setExprBoundaryFields.C b/applications/utilities/preProcessing/setExprBoundaryFields/setExprBoundaryFields.C index 5cafecddffe..b421782f290 100644 --- a/applications/utilities/preProcessing/setExprBoundaryFields/setExprBoundaryFields.C +++ b/applications/utilities/preProcessing/setExprBoundaryFields/setExprBoundaryFields.C @@ -231,18 +231,21 @@ int main(int argc, char *argv[]) dictionary& patchDict = boundaryFieldDict.subDict(patchName); - expressions::exprString expr + auto valueExpr_ ( - currDict.get<string>("expression"), - currDict, - true // strip comments + expressions::exprString::getEntry + ( + "expression", + currDict, + true // strip comments + ) ); Info<< "Set boundaryField/" << patchName << '/' << targetName << nl << "with expression" << nl << "<<<<" << nl - << expr.c_str() << nl + << valueExpr_.c_str() << nl << ">>>>" << nl; expressions::patchExprDriver driver(currDict, mesh); @@ -255,7 +258,7 @@ int main(int argc, char *argv[]) ); driver.clearVariables(); - driver.parse(expr); + driver.parse(valueExpr_); // Serializing via Field::writeEntry etc OStringStream serialize; diff --git a/applications/utilities/preProcessing/setExprFields/setExprFields.C b/applications/utilities/preProcessing/setExprFields/setExprFields.C index 402b6679f5c..98be5699bb8 100644 --- a/applications/utilities/preProcessing/setExprFields/setExprFields.C +++ b/applications/utilities/preProcessing/setExprFields/setExprFields.C @@ -64,7 +64,6 @@ word fieldGeoType(const FieldAssociation geoType) case FieldAssociation::VOLUME_DATA : return "cells"; break; default: break; } - return "unknown"; } @@ -75,7 +74,7 @@ struct setExprFieldsControl bool dryRun; bool debugParsing; bool cacheVariables; - bool useDimensions; + bool hasDimensions; bool createNew; bool keepPatches; bool correctPatches; @@ -123,13 +122,12 @@ void doCorrectBoundaryConditions {} -template<class GeoField, class Mesh> -void setField +template<class GeoField> +bool setField ( const word& fieldName, - const Mesh& mesh, - const GeoField& result, - const scalarField& cond, + const GeoField& evaluated, + const boolField& fieldMask, const dimensionSet& dims, const wordList& valuePatches, @@ -139,6 +137,8 @@ void setField Info<< "setField(" << fieldName << "): " << pTraits<GeoField>::typeName << endl; + const auto& mesh = evaluated.mesh(); + tmp<GeoField> toutput; if (ctrl.createNew) @@ -171,55 +171,57 @@ void setField auto& output = toutput.ref(); - label setCells = 0; + label numValuesChanged = 0; - if (cond.empty()) + // Internal field + if (fieldMask.empty()) { - // No condition - set all - output = result; + // No field-mask - set entire internal field + numValuesChanged = output.size(); - setCells = output.size(); + output.primitiveFieldRef() = evaluated; } else { - forAll(output, celli) + auto& internal = output.primitiveFieldRef(); + + forAll(internal, idx) { - if (expressions::boolOp<scalar>()(cond[celli])) + if (fieldMask[idx]) { - output[celli] = result[celli]; - ++setCells; + internal[idx] = evaluated[idx]; + ++numValuesChanged; } } } - const label totalCells = returnReduce(output.size(), plusOp<label>()); - reduce(setCells, plusOp<label>()); - - forAll(result.boundaryField(), patchi) + // Boundary fields + forAll(evaluated.boundaryField(), patchi) { auto& pf = output.boundaryFieldRef()[patchi]; if (pf.patch().coupled()) { - pf == result.boundaryField()[patchi]; + pf == evaluated.boundaryField()[patchi]; } } + doCorrectBoundaryConditions(ctrl.correctBCs, output); + + const label numTotal = returnReduce(output.size(), plusOp<label>()); + reduce(numValuesChanged, plusOp<label>()); - if (setCells == totalCells) + if (numValuesChanged == numTotal) { Info<< "Set all "; } else { - Info<< "Set " << setCells << " of "; + Info<< "Set " << numValuesChanged << " of "; } - Info<< totalCells << " cells" << endl; - - - doCorrectBoundaryConditions(ctrl.correctBCs, output); + Info<< numTotal << " values" << endl; - if (ctrl.useDimensions) + if (ctrl.hasDimensions) { Info<< "Setting dimensions to " << dims << endl; output.dimensions().reset(dims); @@ -234,6 +236,8 @@ void setField Info<< "Writing to " << output.name() << nl; output.writeObject(ctrl.streamOpt, true); } + + return true; } @@ -241,8 +245,8 @@ void evaluate ( const fvMesh& mesh, const word& fieldName, - const expressions::exprString& expression, - const expressions::exprString& condition, + const expressions::exprString& valueExpr_, + const expressions::exprString& maskExpr_, const dictionary& dict, const dimensionSet& dims, const wordList& valuePatches, @@ -273,10 +277,8 @@ void evaluate if (oldFieldType == IOobject::typeName) { FatalErrorInFunction - << "Field " << fieldName << " is " - << oldFieldType - << ". Seems that it does not exist. Use 'create'" - << nl + << "Field " << fieldName << "(type: " << oldFieldType + << ") seems to be missing. Use 'create'" << nl << exit(FatalError); } @@ -284,17 +286,21 @@ void evaluate << " (type " << oldFieldType << ')'; } + Info<< " time=" << mesh.thisDb().time().timeName() << nl << "Expression:" << nl << ">>>>" << nl - << expression.c_str() << nl + << valueExpr_.c_str() << nl << "<<<<" << nl; - if (condition.size() && condition != "true") + bool evalFieldMask = + (maskExpr_.size() && maskExpr_ != "true" && maskExpr_ != "1"); + + if (evalFieldMask) { - Info<< "Condition:" << nl + Info<< "field-mask:" << nl << ">>>>" << nl - << condition.c_str() << nl + << maskExpr_.c_str() << nl << "<<<<" << nl; } @@ -318,129 +324,95 @@ void evaluate if (ctrl.debugParsing) { - Info<< "Parsing expression: " << expression << "\nand condition " - << condition << nl << endl; + Info<< "Parsing expression: " << valueExpr_ << "\nand field-mask " + << maskExpr_ << nl << endl; driver.setDebugging(true, true); } driver.clearVariables(); - scalarField conditionField; - bool evaluatedCondition = false; + // Handle "field-mask" evaluation - FieldAssociation conditionDataType(FieldAssociation::VOLUME_DATA); + boolField fieldMask; + FieldAssociation maskFieldAssoc(FieldAssociation::NO_DATA); - if (condition.size() && condition != "true") + if (evalFieldMask) { if (ctrl.debugParsing) { - Info<< "Parsing condition:" << condition << endl; + Info<< "Parsing field-mask:" << maskExpr_ << endl; } - driver.parse(condition); + driver.parse(maskExpr_); if (ctrl.debugParsing) { - Info<< "Parsed condition" << endl; + Info<< "Parsed field-mask" << endl; } - // Process any/all scalar fields. May help with diagnosis - - bool goodCond = true; - while (goodCond) + if (driver.isLogical()) { - // volScalarField - { - const auto* ptr = driver.isResultType<volScalarField>(); - if (ptr) - { - conditionField = ptr->internalField(); - // VOLUME_DATA - break; - } - } - - // surfaceScalarField - { - const auto* ptr = driver.isResultType<surfaceScalarField>(); - if (ptr) - { - conditionField = ptr->internalField(); - conditionDataType = FieldAssociation::FACE_DATA; - break; - } - } - - // pointScalarField + auto& result = driver.result(); + if (result.is_bool()) { - const auto* ptr = driver.isResultType<pointScalarField>(); - if (ptr) - { - conditionField = ptr->internalField(); - conditionDataType = FieldAssociation::POINT_DATA; - break; - } + fieldMask = result.getResult<bool>(); + maskFieldAssoc = driver.fieldAssociation(); } - - // No matching field types - goodCond = false; } - // Verify that it also logical - goodCond = goodCond && driver.isLogical(); + // Slightly pedantic... + driver.clearField(); + driver.clearResult(); - if (!goodCond) + evalFieldMask = (maskFieldAssoc != FieldAssociation::NO_DATA); + + if (!evalFieldMask) { FatalErrorInFunction - << " condition: " << condition + << " mask: " << maskExpr_ << " does not evaluate to a logical expression: " << driver.resultType() << nl #ifdef FULLDEBUG - << "contents: " << conditionField + << "contents: " << fieldMask #endif << exit(FatalError); } if (ctrl.debugParsing) { - Info<< "Condition evaluates to " - << conditionField << nl; + Info<< "Field-mask evaluates to " + << fieldMask << nl; } - - evaluatedCondition = true; } if (ctrl.debugParsing) { - Info<< "Parsing expression:" << expression << endl; + Info<< "Parsing expression:" << valueExpr_ << endl; } - driver.parse(expression); + driver.parse(valueExpr_); if (ctrl.debugParsing) { Info<< "Parsed expression" << endl; } - if (evaluatedCondition) + if (evalFieldMask && maskFieldAssoc != driver.fieldAssociation()) { - if (conditionDataType != driver.fieldAssociation()) - { - FatalErrorInFunction - << "Mismatch between condition geometric type (" - << fieldGeoType(conditionDataType) << ") and" << nl - << "expression geometric type (" - << fieldGeoType(driver.fieldAssociation()) << ')' << nl - << nl - << "Expression: " << expression << nl - << "Condition: " << condition << nl - << nl - << exit(FatalError); - } + FatalErrorInFunction + << "Mismatch between field-mask geometric type (" + << fieldGeoType(maskFieldAssoc) << ") and" << nl + << "expression geometric type (" + << fieldGeoType(driver.fieldAssociation()) << ')' << nl + << nl + << "expression: " << valueExpr_ << nl + << "field-mask: " << maskExpr_ << nl + << nl + << exit(FatalError); } - if (!ctrl.createNew && driver.resultType() != oldFieldType) + if (!oldFieldType.empty() && driver.resultType() != oldFieldType) { FatalErrorInFunction << "Inconsistent types: " << fieldName << " is " @@ -452,81 +424,69 @@ void evaluate Info<< "Dispatch ... " << driver.resultType() << nl; - #undef setFieldDispatch - #define setFieldDispatch(FieldType) \ - { \ - /* FieldType */ \ - const auto* ptr = driver.isResultType<FieldType>(); \ - if (ptr) \ - { \ - /* driver.getResult<FieldType>(correctPatches), */ \ - \ - setField \ - ( \ - fieldName, \ - mesh, \ - *ptr, \ - conditionField, \ - dims, \ - valuePatches, \ - ctrl \ - ); \ - return; \ - } \ - } \ - - - setFieldDispatch(volScalarField); - setFieldDispatch(volVectorField); - setFieldDispatch(volTensorField); - setFieldDispatch(volSymmTensorField); - setFieldDispatch(volSphericalTensorField); - - setFieldDispatch(surfaceScalarField); - setFieldDispatch(surfaceVectorField); - setFieldDispatch(surfaceTensorField); - setFieldDispatch(surfaceSymmTensorField); - setFieldDispatch(surfaceSphericalTensorField); - - #undef setFieldDispatch - #define setFieldDispatch(FieldType) \ - { \ - /* FieldType */ \ - const auto* ptr = driver.isResultType<FieldType>(); \ - \ - if (ptr) \ - { \ - /* driver.getResult<FieldType>(correctPatches), */ \ - \ - setField \ - ( \ - fieldName, \ - pointMesh::New(mesh), \ - *ptr, \ - conditionField, \ - dims, \ - valuePatches, \ - ctrl \ - ); \ - return; \ - } \ - } \ - - setFieldDispatch(pointScalarField); - setFieldDispatch(pointVectorField); - setFieldDispatch(pointTensorField); - setFieldDispatch(pointSymmTensorField); - setFieldDispatch(pointSphericalTensorField); - - #undef setFieldDispatch - - // Nothing dispatched? - - FatalErrorInFunction - << "Expression evaluates to an unsupported type: " - << driver.resultType() << nl << nl - << "Expression " << expression << nl << endl - << exit(FatalError); + + bool applied = false; + switch (driver.fieldAssociation()) + { + #undef doLocalCode + #define doLocalCode(GeoField) \ + { \ + const auto* ptr = driver.isResultType<GeoField>(); \ + if (ptr) \ + { \ + applied = setField \ + ( \ + fieldName, \ + *ptr, \ + fieldMask, \ + dims, \ + valuePatches, \ + ctrl \ + ); \ + break; \ + } \ + } + + case FieldAssociation::VOLUME_DATA: + { + doLocalCode(volScalarField); + doLocalCode(volVectorField); + doLocalCode(volTensorField); + doLocalCode(volSymmTensorField); + doLocalCode(volSphericalTensorField); + break; + } + case FieldAssociation::FACE_DATA: + { + doLocalCode(surfaceScalarField); + doLocalCode(surfaceVectorField); + doLocalCode(surfaceTensorField); + doLocalCode(surfaceSymmTensorField); + doLocalCode(surfaceSphericalTensorField); + break; + } + case FieldAssociation::POINT_DATA: + { + doLocalCode(pointScalarField); + doLocalCode(pointVectorField); + doLocalCode(pointTensorField); + doLocalCode(pointSymmTensorField); + doLocalCode(pointSphericalTensorField); + break; + } + + default: break; + #undef doLocalCode + } + + if (!applied) + { + FatalErrorInFunction + << "Expression evaluates to an unsupported type: " + << driver.resultType() << nl << nl + << "Expression " << valueExpr_ << nl << endl + << exit(FatalError); + } } @@ -584,12 +544,13 @@ int main(int argc, char *argv[]) ); argList::addOption ( - "condition", + "field-mask", "logic", - "The logical condition when to apply the expression" + "The field mask (logical condition) when to apply the expression" " (command-line operation)", true // Advanced option ); + argList::addOptionCompat("field-mask", {"condition", 2106}); argList::addOption ( "dimensions", @@ -726,7 +687,7 @@ int main(int argc, char *argv[]) wordHashSet badOptions ({ "create", "keepPatches", "value-patches", - "condition", "expression", "dimensions" + "field-mask", "expression", "dimensions" }); badOptions.retain(args.options()); @@ -802,25 +763,24 @@ int main(int argc, char *argv[]) ctrl.keepPatches = args.found("keepPatches"); ctrl.correctPatches = !args.found("noCorrectPatches"); ctrl.correctBCs = args.found("correctResultBoundaryFields"); - ctrl.useDimensions = args.found("dimensions"); + ctrl.hasDimensions = args.found("dimensions"); ctrl.streamOpt.format(runTime.writeFormat()); if (args.found("ascii")) { ctrl.streamOpt.format(IOstream::ASCII); } - expressions::exprString - expression - ( - args["expression"], - dictionary::null - ); + expressions::exprString valueExpr_ + ( + args["expression"], + dictionary::null + ); - expressions::exprString condition; - args.readIfPresent("condition", condition); + expressions::exprString maskExpr_; + args.readIfPresent("field-mask", maskExpr_); dimensionSet dims; - if (ctrl.useDimensions) + if (ctrl.hasDimensions) { ITstream is(args.lookup("dimensions")); is >> dims; @@ -830,8 +790,8 @@ int main(int argc, char *argv[]) ( mesh, fieldName, - expression, - condition, + valueExpr_, + maskExpr_, dictionary::null, dims, args.getList<word>("value-patches", false), @@ -899,22 +859,28 @@ int main(int argc, char *argv[]) const word fieldName(dict.get<word>("field")); - expressions::exprString expression + auto valueExpr_ ( - dict.get<string>("expression"), - dict + expressions::exprString::getEntry + ( + "expression", + dict + ) ); - expressions::exprString condition; - - if (dict.found("condition")) + expressions::exprString maskExpr_; { - condition = - expressions::exprString - ( - dict.get<string>("condition"), - dict - ); + const entry* eptr = dict.findCompat + ( + "fieldMask", {{"condition", 2106}}, + keyType::LITERAL + ); + + if (eptr) + { + maskExpr_.readEntry(eptr->keyword(), dict); + maskExpr_.trim(); + } } dimensionSet dims; @@ -928,7 +894,7 @@ int main(int argc, char *argv[]) { dimPtr->stream() >> dims; } - ctrl.useDimensions = bool(dimPtr); + ctrl.hasDimensions = bool(dimPtr); } if (args.verbose() && !timei) @@ -941,8 +907,8 @@ int main(int argc, char *argv[]) ( mesh, fieldName, - expression, - condition, + valueExpr_, + maskExpr_, dict, dims, dict.getOrDefault<wordList>("valuePatches", wordList()), diff --git a/applications/utilities/preProcessing/setExprFields/setExprFieldsDict b/applications/utilities/preProcessing/setExprFields/setExprFieldsDict index 834dfb55d6c..d555cc989e7 100644 --- a/applications/utilities/preProcessing/setExprFields/setExprFieldsDict +++ b/applications/utilities/preProcessing/setExprFields/setExprFieldsDict @@ -1,7 +1,7 @@ /*--------------------------------*- C++ -*----------------------------------*\ | ========= | | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | -| \\ / O peration | Version: v2106 | +| \\ / O peration | Version: v2112 | | \\ / A nd | Website: www.openfoam.com | | \\/ M anipulation | | \*---------------------------------------------------------------------------*/ @@ -31,7 +31,7 @@ expressions "radius = 0.1" ); - condition + fieldMask #{ // Within the radius (mag(pos() - $[(vector)constants.centre]) < radius) diff --git a/etc/caseDicts/annotated/setExprFieldsDict b/etc/caseDicts/annotated/setExprFieldsDict index f5672ed2a62..98196eafeb7 100644 --- a/etc/caseDicts/annotated/setExprFieldsDict +++ b/etc/caseDicts/annotated/setExprFieldsDict @@ -1,7 +1,7 @@ /*--------------------------------*- C++ -*----------------------------------*\ | ========= | | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | -| \\ / O peration | Version: v2106 | +| \\ / O peration | Version: v2112 | | \\ / A nd | Website: www.openfoam.com | | \\/ M anipulation | | \*---------------------------------------------------------------------------*/ @@ -34,7 +34,7 @@ expressions "radius = 0.1" ); - condition + fieldMask #{ // Within the radius (mag(pos() - $[(vector)constants.centre]) < radius) diff --git a/src/OpenFOAM/expressions/Function1/Function1Expression.C b/src/OpenFOAM/expressions/Function1/Function1Expression.C index a0461b59f66..bbd05ce3047 100644 --- a/src/OpenFOAM/expressions/Function1/Function1Expression.C +++ b/src/OpenFOAM/expressions/Function1/Function1Expression.C @@ -47,9 +47,7 @@ Foam::Function1Types::Function1Expression<Type>::Function1Expression debug |= 1; } - string expr; - dict_.readEntry("expression", expr); - valueExpr_ = expressions::exprString(std::move(expr), dict_); + valueExpr_.readEntry("expression", dict_); // Basic sanity if (valueExpr_.empty()) diff --git a/src/OpenFOAM/expressions/exprDriver/exprDriver.H b/src/OpenFOAM/expressions/exprDriver/exprDriver.H index 11590e51a3b..3db249aff80 100644 --- a/src/OpenFOAM/expressions/exprDriver/exprDriver.H +++ b/src/OpenFOAM/expressions/exprDriver/exprDriver.H @@ -314,13 +314,13 @@ public: // Public Member Functions - //- The underlying field size for the expression + //- The natural field size for the expression virtual label size() const { return 1; } - //- The underlying point field size for the expression + //- The point field size for the expression virtual label pointSize() const { return 1; @@ -358,6 +358,7 @@ public: void clearResult(); //- Return the expression result as a tmp field + // This also clears the result and associated memory. template<class Type> tmp<Field<Type>> getResult(bool wantPointData=false); @@ -426,7 +427,7 @@ public: // Variables - //- Clear temporary variables and resets from expression strings + //- Clear temporary variables, reset from expression strings virtual void clearVariables(); //- Set special-purpose scalar reference argument. @@ -555,7 +556,8 @@ public: size_t len = std::string::npos ) = 0; - //- Evaluate the expression and return the field + //- Evaluate the expression and return the field. + // This also clears the result and associated memory. template<class Type> inline tmp<Field<Type>> evaluate @@ -564,7 +566,8 @@ public: bool wantPointData = false ); - //- Evaluate the expression and return a single value + //- Evaluate the expression and return a single value. + // Does not clear the result. template<class Type> inline Type evaluateUniform ( diff --git a/src/OpenFOAM/expressions/exprResult/exprResult.H b/src/OpenFOAM/expressions/exprResult/exprResult.H index 3e9d19f6bc8..793381351fd 100644 --- a/src/OpenFOAM/expressions/exprResult/exprResult.H +++ b/src/OpenFOAM/expressions/exprResult/exprResult.H @@ -415,10 +415,10 @@ public: void clear(); //- Change reset behaviour - void noReset() { noReset_ = true; } + void noReset() noexcept { noReset_ = true; } //- Change reset behaviour - void allowReset() { noReset_ = false; } + void allowReset() noexcept { noReset_ = false; } //- Test if field corresponds to a single-value and thus uniform. // Uses field min/max to establish uniformity. @@ -468,11 +468,6 @@ public: template<class Type> inline tmp<Field<Type>> getResult(bool cacheCopy=false); - //- Get object result (Caution - potentially fragile) - //- optionally keeping a copy in cache - template<class Type> - inline tmp<Type> getObjectResult(bool cacheCopy=false); - //- Construct a uniform field from the current results // Uses the field average. Optionally warning if the min/max // deviation is larger than SMALL. diff --git a/src/OpenFOAM/expressions/exprString/exprString.C b/src/OpenFOAM/expressions/exprString/exprString.C index 43cbbb36084..5fd48fb4e3b 100644 --- a/src/OpenFOAM/expressions/exprString/exprString.C +++ b/src/OpenFOAM/expressions/exprString/exprString.C @@ -48,20 +48,30 @@ void Foam::expressions::exprString::inplaceExpand Foam::expressions::exprString -Foam::expressions::exprString::getExpression +Foam::expressions::exprString::getEntry ( - const word& name, + const word& key, const dictionary& dict, const bool stripComments ) { - string orig(dict.get<string>(name)); + exprString expr; + expr.readEntry(key, dict, true, stripComments); // mandatory - // No validation - expressions::exprString expr; - expr.assign(std::move(orig)); + return expr; +} - inplaceExpand(expr, dict, stripComments); + +Foam::expressions::exprString +Foam::expressions::exprString::getOptional +( + const word& key, + const dictionary& dict, + const bool stripComments +) +{ + exprString expr; + expr.readEntry(key, dict, false, stripComments); // optional return expr; } @@ -69,8 +79,7 @@ Foam::expressions::exprString::getExpression // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -Foam::expressions::exprString& -Foam::expressions::exprString::expand +void Foam::expressions::exprString::expand ( const dictionary& dict, const bool stripComments @@ -81,8 +90,35 @@ Foam::expressions::exprString::expand #ifdef FULLDEBUG (void)valid(); #endif +} + + +void Foam::expressions::exprString::trim() +{ + stringOps::inplaceTrim(*this); +} - return *this; + +bool Foam::expressions::exprString::readEntry +( + const word& keyword, + const dictionary& dict, + bool mandatory, + const bool stripComments +) +{ + const bool ok = dict.readEntry(keyword, *this, keyType::LITERAL, mandatory); + + if (ok && !empty()) + { + this->expand(dict, stripComments); // strip comments + } + else + { + clear(); + } + + return ok; } diff --git a/src/OpenFOAM/expressions/exprString/exprString.H b/src/OpenFOAM/expressions/exprString/exprString.H index f1d5bef94fb..84ac3eccc3e 100644 --- a/src/OpenFOAM/expressions/exprString/exprString.H +++ b/src/OpenFOAM/expressions/exprString/exprString.H @@ -135,13 +135,22 @@ public: //- Get and expand expression with dictionary entries, //- optionally strip C/C++ comments from the input. - // // Expansion behaviour as per inplaceExpand - static exprString getExpression + static exprString getEntry + ( + const word& keyword, //!< Lookup key. Uses LITERAL (not REGEX) + const dictionary& dict, + const bool stripComments = true + ); + + //- Get and expand expression with dictionary entries, + //- optionally strip C/C++ comments from the input. + // Expansion behaviour as per inplaceExpand + static exprString getOptional ( - const word& name, + const word& keyword, //!< Lookup key. Uses LITERAL (not REGEX) const dictionary& dict, - const bool stripComments = false + const bool stripComments = true ); //- Copy convert string to exprString. @@ -155,17 +164,26 @@ public: // Member Functions + //- Check for unexpanded '$' entries. Fatal if any exist. + inline bool valid() const; + //- Inplace expansion with dictionary variables, //- and strip C/C++ comments from the input - exprString& expand + void expand(const dictionary& dict, const bool stripComments = true); + + //- Inplace trim leading and trailing whitespace + void trim(); + + //- Read/expand entry with dictionary variables, + //- and strip C/C++ comments from the input + bool readEntry ( + const word& keyword, //!< Lookup key. Uses LITERAL (not REGEX) const dictionary& dict, + bool mandatory = true, const bool stripComments = true ); - //- Check for unexpanded '$' entries. Fatal if any exist. - inline bool valid() const; - // Member Operators diff --git a/src/OpenFOAM/expressions/fields/fieldExprDriver.H b/src/OpenFOAM/expressions/fields/fieldExprDriver.H index 70ae0d2d91b..657bcb5ee4a 100644 --- a/src/OpenFOAM/expressions/fields/fieldExprDriver.H +++ b/src/OpenFOAM/expressions/fields/fieldExprDriver.H @@ -118,13 +118,13 @@ public: // Public Member Functions - //- The underlying field size for the expression + //- The natural field size for the expression virtual label size() const { return size_; } - //- The underlying point field size for the expression + //- The point field size for the expression virtual label pointSize() const { return size_; diff --git a/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.C b/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.C index 72e19ce8a22..0c200969a04 100644 --- a/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.C +++ b/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.C @@ -50,9 +50,7 @@ Foam::PatchFunction1Types::PatchExprField<Type>::PatchExprField debug |= 1; } - string expr; - dict_.readEntry("expression", expr); - valueExpr_ = expressions::exprString(std::move(expr), dict_); + valueExpr_.readEntry("expression", dict_); // Basic sanity if (valueExpr_.empty()) diff --git a/src/finiteVolume/expressions/base/fvExprDriver.H b/src/finiteVolume/expressions/base/fvExprDriver.H index 5c4f78f04ea..1ecd04caa54 100644 --- a/src/finiteVolume/expressions/base/fvExprDriver.H +++ b/src/finiteVolume/expressions/base/fvExprDriver.H @@ -410,10 +410,10 @@ public: // Public Member Functions - //- The underlying field size for the expression + //- The natural field size for the expression virtual label size() const = 0; - //- The underlying point field size for the expression + //- The point field size for the expression virtual label pointSize() const = 0; @@ -425,7 +425,7 @@ public: // Variables - //- Clear temporary variables and resets from expression strings + //- Clear temporary variables, reset from expression strings virtual void clearVariables(); //- True if named variable exists diff --git a/src/finiteVolume/expressions/fields/base/patchExprFieldBase.C b/src/finiteVolume/expressions/fields/base/patchExprFieldBase.C index f304e5e5658..d8f77bccb50 100644 --- a/src/finiteVolume/expressions/fields/base/patchExprFieldBase.C +++ b/src/finiteVolume/expressions/fields/base/patchExprFieldBase.C @@ -57,18 +57,21 @@ void Foam::expressions::patchExprFieldBase::readExpressions if (expectedTypes::VALUE_TYPE == expectedType) { // Mandatory - evalValue = dict.readEntry("valueExpr", exprValue); + evalValue = dict.readEntry("valueExpr", exprValue, keyType::LITERAL); } else if (expectedTypes::GRADIENT_TYPE == expectedType) { // Mandatory - evalGrad = dict.readEntry("gradientExpr", exprGrad); + evalGrad = dict.readEntry("gradientExpr", exprGrad, keyType::LITERAL); } else { // MIXED_TYPE - evalValue = dict.readIfPresent("valueExpr", exprValue); - evalGrad = dict.readIfPresent("gradientExpr", exprGrad); + evalValue = + dict.readIfPresent("valueExpr", exprValue, keyType::LITERAL); + + evalGrad = + dict.readIfPresent("gradientExpr", exprGrad, keyType::LITERAL); if (!evalValue && !evalGrad) { diff --git a/src/finiteVolume/expressions/patch/patchExprDriver.H b/src/finiteVolume/expressions/patch/patchExprDriver.H index e864b5dd66b..51a2c5fb235 100644 --- a/src/finiteVolume/expressions/patch/patchExprDriver.H +++ b/src/finiteVolume/expressions/patch/patchExprDriver.H @@ -179,13 +179,13 @@ public: return patch_.boundaryMesh().mesh(); } - //- The underlying field size for the expression + //- The natural field size for the expression virtual label size() const { return patch_.patch().size(); } - //- The underlying point field size for the expression + //- The point field size for the expression virtual label pointSize() const { return patch_.patch().nPoints(); diff --git a/src/finiteVolume/expressions/volume/volumeExprDriver.C b/src/finiteVolume/expressions/volume/volumeExprDriver.C index f41b2b467d1..35ce03da28b 100644 --- a/src/finiteVolume/expressions/volume/volumeExprDriver.C +++ b/src/finiteVolume/expressions/volume/volumeExprDriver.C @@ -94,8 +94,9 @@ Foam::expressions::volumeExpr::parseDriver::parseDriver mesh_(mesh), resultType_(), isLogical_(false), + hasDimensions_(false), fieldGeoType_(NO_DATA), - resultDimension_() + resultDimensions_() { resetTimeReference(nullptr); resetDb(mesh_.thisDb()); @@ -105,17 +106,18 @@ Foam::expressions::volumeExpr::parseDriver::parseDriver Foam::expressions::volumeExpr::parseDriver::parseDriver ( const fvMesh& mesh, - const parseDriver& driver, + const parseDriver& rhs, const dictionary& dict ) : parsing::genericRagelLemonDriver(), - expressions::fvExprDriver(driver, dict), + expressions::fvExprDriver(rhs, dict), mesh_(mesh), resultType_(), isLogical_(false), + hasDimensions_(false), fieldGeoType_(NO_DATA), - resultDimension_() + resultDimensions_() { resetTimeReference(nullptr); resetDb(mesh_.thisDb()); @@ -146,7 +148,7 @@ Foam::expressions::volumeExpr::parseDriver::parseDriver resultType_(), isLogical_(false), fieldGeoType_(NO_DATA), - resultDimension_() + resultDimensions_() { resetTimeReference(nullptr); resetDb(mesh_.thisDb()); @@ -161,7 +163,15 @@ bool Foam::expressions::volumeExpr::parseDriver::readDict ) { expressions::fvExprDriver::readDict(dict); - dict.readIfPresent("dimensions", resultDimension_); + + resultDimensions_.clear(); // Avoid stickiness + + hasDimensions_ = resultDimensions_.readEntry + ( + "dimensions", + dict, + false // mandatory=false + ); return true; } @@ -184,4 +194,90 @@ unsigned Foam::expressions::volumeExpr::parseDriver::parse } +void Foam::expressions::volumeExpr::parseDriver::clearField() +{ + resultField_.reset(nullptr); + + // Characteristics + resultType_.clear(); + isLogical_ = false; + fieldGeoType_ = NO_DATA; +} + + +Foam::autoPtr<Foam::regIOobject> +Foam::expressions::volumeExpr::parseDriver::dupZeroField() const +{ + const auto* regIOobjectPtr = resultField_.get(); + + if (!regIOobjectPtr) + { + return nullptr; + } + + autoPtr<regIOobject> zField; + + switch (fieldGeoType_) + { + #undef doLocalCode + #define doLocalCode(GeoField) \ + { \ + const auto* ptr = dynamic_cast<const GeoField*>(regIOobjectPtr); \ + typedef typename GeoField::value_type Type; \ + \ + if (ptr) \ + { \ + zField.reset \ + ( \ + GeoField::New \ + ( \ + word(pTraits<Type>::typeName) + word("(zero)"), \ + (*ptr).mesh(), \ + dimensioned<Type>(Zero) \ + ).ptr() \ + ); \ + break; \ + } \ + } + + case FieldAssociation::VOLUME_DATA: + { + doLocalCode(volScalarField); + doLocalCode(volVectorField); + doLocalCode(volTensorField); + doLocalCode(volSymmTensorField); + doLocalCode(volSphericalTensorField); + break; + } + case FieldAssociation::FACE_DATA: + { + doLocalCode(surfaceScalarField); + doLocalCode(surfaceVectorField); + doLocalCode(surfaceTensorField); + doLocalCode(surfaceSymmTensorField); + doLocalCode(surfaceSphericalTensorField); + break; + } + case FieldAssociation::POINT_DATA: + { + doLocalCode(pointScalarField); + doLocalCode(pointVectorField); + doLocalCode(pointTensorField); + doLocalCode(pointSymmTensorField); + doLocalCode(pointSphericalTensorField); + break; + } + default: break; + #undef doLocalCode + } + + // if (!zField) + // { + // // Report + // } + + return zField; +} + + // ************************************************************************* // diff --git a/src/finiteVolume/expressions/volume/volumeExprDriver.H b/src/finiteVolume/expressions/volume/volumeExprDriver.H index 47042f2ad08..b4c182ab629 100644 --- a/src/finiteVolume/expressions/volume/volumeExprDriver.H +++ b/src/finiteVolume/expressions/volume/volumeExprDriver.H @@ -126,11 +126,14 @@ protected: //- A logical (bool-like) field (but actually a scalar) bool isLogical_; + //- Requested use of dimensions + bool hasDimensions_; + //- A volume/surface/point field expressions::FieldAssociation fieldGeoType_; //- The result dimensions - dimensionSet resultDimension_; + dimensionSet resultDimensions_; // Protected Member Functions @@ -217,13 +220,13 @@ public: return mesh_; } - //- The underlying field size for the expression + //- The natural field size for the expression virtual label size() const { return mesh_.nCells(); } - //- The underlying point field size for the expression + //- The point field size for the expression virtual label pointSize() const { return mesh_.nPoints(); @@ -232,6 +235,16 @@ public: //- Field size associated with different geometric field types inline label size(const FieldAssociation geoType) const; + //- Apply dimensions() to geometric fields + inline bool hasDimensions() const noexcept; + + //- The preferred result dimensions (if any) + inline const dimensionSet& dimensions() const noexcept; + + + //- Clear out local copies of the field + void clearField(); + // Reading @@ -304,6 +317,9 @@ public: template<class GeoField> const GeoField* isResultType(bool logical, bool dieOnNull=false) const; + //- A zero-initialized field with the same type as the result field. + autoPtr<regIOobject> dupZeroField() const; + // Set Fields diff --git a/src/finiteVolume/expressions/volume/volumeExprDriverI.H b/src/finiteVolume/expressions/volume/volumeExprDriverI.H index 8c6d00bb50b..0c1383e69fc 100644 --- a/src/finiteVolume/expressions/volume/volumeExprDriverI.H +++ b/src/finiteVolume/expressions/volume/volumeExprDriverI.H @@ -50,6 +50,20 @@ inline Foam::label Foam::expressions::volumeExpr::parseDriver::size } +inline bool Foam::expressions::volumeExpr::parseDriver::hasDimensions() +const noexcept +{ + return hasDimensions_; +} + + +inline const Foam::dimensionSet& +Foam::expressions::volumeExpr::parseDriver::dimensions() const noexcept +{ + return resultDimensions_; +} + + inline Foam::tmp<Foam::volScalarField> Foam::expressions::volumeExpr::parseDriver::parseDriver::field_cellSet ( diff --git a/src/finiteVolume/expressions/volume/volumeExprDriverTemplates.C b/src/finiteVolume/expressions/volume/volumeExprDriverTemplates.C index 60c54f2d40d..ba39f568b58 100644 --- a/src/finiteVolume/expressions/volume/volumeExprDriverTemplates.C +++ b/src/finiteVolume/expressions/volume/volumeExprDriverTemplates.C @@ -68,17 +68,17 @@ void Foam::expressions::volumeExpr::parseDriver::setResult { typedef GeometricField<Type, fvPatchField, volMesh> fieldType; - resultField_.clear(); + resultField_.reset(nullptr); // Characteristics resultType_ = pTraits<fieldType>::typeName; isLogical_ = logical; fieldGeoType_ = VOLUME_DATA; - // Always strip out dimensions? - if (!resultDimension_.dimensionless()) + // Assign dimensions + if (hasDimensions_ && !logical) { - ptr->dimensions().reset(resultDimension_); + ptr->dimensions().reset(resultDimensions_); } setInternalFieldResult(ptr->primitiveField()); @@ -97,17 +97,17 @@ void Foam::expressions::volumeExpr::parseDriver::setResult { typedef GeometricField<Type, fvsPatchField, surfaceMesh> fieldType; - resultField_.clear(); + resultField_.reset(nullptr); // Characteristics resultType_ = pTraits<fieldType>::typeName; isLogical_ = logical; fieldGeoType_ = FACE_DATA; - // Always strip out dimensions? - if (!resultDimension_.dimensionless()) + // Assign dimensions + if (hasDimensions_ && !logical) { - ptr->dimensions().reset(resultDimension_); + ptr->dimensions().reset(resultDimensions_); } setInternalFieldResult(ptr->primitiveField()); @@ -126,17 +126,17 @@ void Foam::expressions::volumeExpr::parseDriver::setResult { typedef GeometricField<Type, pointPatchField, pointMesh> fieldType; - resultField_.clear(); + resultField_.reset(nullptr); // Characteristics resultType_ = pTraits<fieldType>::typeName; isLogical_ = logical; fieldGeoType_ = POINT_DATA; - // Always strip out dimensions? - if (!resultDimension_.dimensionless()) + // Assign dimensions + if (hasDimensions_ && !logical) { - ptr->dimensions().reset(resultDimension_); + ptr->dimensions().reset(resultDimensions_); } setInternalFieldResult(ptr->primitiveField()); @@ -164,7 +164,7 @@ Foam::expressions::volumeExpr::parseDriver::isResultType { const regIOobject* ptr = resultField_.get(); - if (dieOnNull && ptr != nullptr) + if (dieOnNull && !ptr) { FatalErrorInFunction << "No result available. Requested " diff --git a/tutorials/compressible/rhoPimpleFoam/RAS/TJunctionAverage/system/setExprFieldsDict b/tutorials/compressible/rhoPimpleFoam/RAS/TJunctionAverage/system/setExprFieldsDict index 834dfb55d6c..f9c23f4f18c 100644 --- a/tutorials/compressible/rhoPimpleFoam/RAS/TJunctionAverage/system/setExprFieldsDict +++ b/tutorials/compressible/rhoPimpleFoam/RAS/TJunctionAverage/system/setExprFieldsDict @@ -31,7 +31,7 @@ expressions "radius = 0.1" ); - condition + fieldMask #{ // Within the radius (mag(pos() - $[(vector)constants.centre]) < radius) -- GitLab