mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
Merge branch 'feature-fvExpressionField' into 'develop'
New "exprField" function object See merge request Development/openfoam!516
This commit is contained in:
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2019-2020 OpenCFD Ltd.
|
||||
Copyright (C) 2019-2021 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -54,7 +54,7 @@ void Foam::PDRparams::readDefaults(const dictionary& dict)
|
||||
|
||||
outer_orthog = dict.found("outer_orthog");
|
||||
|
||||
dict.readIfPresent("debugLevel", debugLevel);
|
||||
dict.readIfPresent("debug.level", debugLevel);
|
||||
dict.readIfPresent("nFacesToBlockC", nFacesToBlockC);
|
||||
dict.readIfPresent("nPairsToBlockC", nPairsToBlockC);
|
||||
dict.readIfPresent("overlaps", overlaps);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
if (setCells == totalCells)
|
||||
const label numTotal = returnReduce(output.size(), plusOp<label>());
|
||||
reduce(numValuesChanged, plusOp<label>());
|
||||
|
||||
if (numValuesChanged == numTotal)
|
||||
{
|
||||
Info<< "Set all ";
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Set " << setCells << " of ";
|
||||
Info<< "Set " << numValuesChanged << " of ";
|
||||
}
|
||||
Info<< totalCells << " cells" << endl;
|
||||
Info<< numTotal << " values" << endl;
|
||||
|
||||
|
||||
doCorrectBoundaryConditions(ctrl.correctBCs, output);
|
||||
|
||||
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
|
||||
auto& result = driver.result();
|
||||
if (result.is_bool())
|
||||
{
|
||||
const auto* ptr = driver.isResultType<volScalarField>();
|
||||
if (ptr)
|
||||
{
|
||||
conditionField = ptr->internalField();
|
||||
// VOLUME_DATA
|
||||
break;
|
||||
}
|
||||
fieldMask = result.getResult<bool>();
|
||||
maskFieldAssoc = driver.fieldAssociation();
|
||||
}
|
||||
|
||||
// surfaceScalarField
|
||||
{
|
||||
const auto* ptr = driver.isResultType<surfaceScalarField>();
|
||||
if (ptr)
|
||||
{
|
||||
conditionField = ptr->internalField();
|
||||
conditionDataType = FieldAssociation::FACE_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pointScalarField
|
||||
{
|
||||
const auto* ptr = driver.isResultType<pointScalarField>();
|
||||
if (ptr)
|
||||
{
|
||||
conditionField = ptr->internalField();
|
||||
conditionDataType = FieldAssociation::POINT_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 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; \
|
||||
} \
|
||||
} \
|
||||
|
||||
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; \
|
||||
} \
|
||||
}
|
||||
|
||||
setFieldDispatch(volScalarField);
|
||||
setFieldDispatch(volVectorField);
|
||||
setFieldDispatch(volTensorField);
|
||||
setFieldDispatch(volSymmTensorField);
|
||||
setFieldDispatch(volSphericalTensorField);
|
||||
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;
|
||||
}
|
||||
|
||||
setFieldDispatch(surfaceScalarField);
|
||||
setFieldDispatch(surfaceVectorField);
|
||||
setFieldDispatch(surfaceTensorField);
|
||||
setFieldDispatch(surfaceSymmTensorField);
|
||||
setFieldDispatch(surfaceSphericalTensorField);
|
||||
default: break;
|
||||
#undef doLocalCode
|
||||
}
|
||||
|
||||
#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);
|
||||
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()),
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -189,8 +189,8 @@ Foam::expressions::exprDriver::exprDriver
|
||||
stashedTokenId_(0),
|
||||
|
||||
// Controls
|
||||
debugScanner_(dict.getOrDefault("debugScanner", false)),
|
||||
debugParser_(dict.getOrDefault("debugParser", false)),
|
||||
debugScanner_(dict.getOrDefault("debug.scanner", false)),
|
||||
debugParser_(dict.getOrDefault("debug.parser", false)),
|
||||
allowShadowing_(dict.getOrDefault("allowShadowing", false)),
|
||||
prevIterIsOldTime_(dict.getOrDefault("prevIterIsOldTime", false)),
|
||||
searchCtrl_(search)
|
||||
@ -298,7 +298,7 @@ bool Foam::expressions::exprDriver::readDict
|
||||
const dictionary& dict
|
||||
)
|
||||
{
|
||||
dict.readIfPresent("debugBaseDriver", debug);
|
||||
dict.readIfPresent("debug.driver", debug);
|
||||
|
||||
// Regular variables
|
||||
variableStrings_ = readVariableStrings(dict);
|
||||
|
||||
@ -43,10 +43,10 @@ Description
|
||||
|
||||
Debug Properties
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
debugBaseDriver | Debug level (int) for base driver | no |
|
||||
debugScanner | Add debug for scanner | no | false
|
||||
debugParser | Add debug for parser | no | false
|
||||
Property | Description | Required | Default
|
||||
debug.driver | Debug level (int) for base driver | no |
|
||||
debug.scanner | Add debug for scanner | no | false
|
||||
debug.parser | Add debug for parser | no | false
|
||||
\endtable
|
||||
|
||||
The \c lookup<scalar> and \c lookup<vector> are dictionaries
|
||||
@ -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
|
||||
(
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
return *this;
|
||||
|
||||
void Foam::expressions::exprString::trim()
|
||||
{
|
||||
stringOps::inplaceTrim(*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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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& name,
|
||||
const word& keyword, //!< Lookup key. Uses LITERAL (not REGEX)
|
||||
const dictionary& dict,
|
||||
const bool stripComments = false
|
||||
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& keyword, //!< Lookup key. Uses LITERAL (not REGEX)
|
||||
const dictionary& dict,
|
||||
const bool stripComments = true
|
||||
);
|
||||
|
||||
//- Copy convert string to exprString.
|
||||
@ -155,17 +164,26 @@ public:
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- Inplace expansion with dictionary variables,
|
||||
//- and strip C/C++ comments from the input
|
||||
exprString& expand
|
||||
(
|
||||
const dictionary& dict,
|
||||
const bool stripComments = true
|
||||
);
|
||||
|
||||
//- 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
|
||||
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
|
||||
);
|
||||
|
||||
|
||||
// Member Operators
|
||||
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -44,10 +44,10 @@ Description
|
||||
|
||||
Debug Properties
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
debugBaseDriver | Debug level (int) for base driver | no |
|
||||
debugScanner | Add debug for scanner | no | false
|
||||
debugParser | Add debug for parser | no | false
|
||||
Property | Description | Required | Default
|
||||
debug.driver | Debug level (int) for base driver | no |
|
||||
debug.scanner | Add debug for scanner | no | false
|
||||
debug.parser | Add debug for parser | no | false
|
||||
\endtable
|
||||
|
||||
SourceFiles
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
(
|
||||
|
||||
@ -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 "
|
||||
|
||||
@ -6,6 +6,8 @@ continuityError/continuityError.C
|
||||
|
||||
derivedFields/derivedFields.C
|
||||
|
||||
expressions/fvExpressionField.C
|
||||
|
||||
fieldAverage/fieldAverage.C
|
||||
fieldAverage/fieldAverageItem/fieldAverageItem.C
|
||||
fieldAverage/fieldAverageItem/fieldAverageItemIO.C
|
||||
|
||||
696
src/functionObjects/field/expressions/fvExpressionField.C
Normal file
696
src/functionObjects/field/expressions/fvExpressionField.C
Normal file
@ -0,0 +1,696 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2021 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 "fvExpressionField.H"
|
||||
#include "volFields.H"
|
||||
#include "surfaceFields.H"
|
||||
#include "pointMesh.H"
|
||||
#include "pointFields.H"
|
||||
#include "volumeExprDriver.H"
|
||||
#include "calculatedFvPatchField.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
namespace functionObjects
|
||||
{
|
||||
defineTypeNameAndDebug(fvExpressionField, 0);
|
||||
addToRunTimeSelectionTable(functionObject, fvExpressionField, dictionary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const Foam::Enum
|
||||
<
|
||||
Foam::functionObjects::fvExpressionField::actionType
|
||||
>
|
||||
Foam::functionObjects::fvExpressionField::actionNames_
|
||||
({
|
||||
{ actionType::opNone, "none" },
|
||||
{ actionType::opNew, "new" },
|
||||
{ actionType::opModify, "modify" },
|
||||
});
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
word fieldGeoType(const expressions::FieldAssociation geoType)
|
||||
{
|
||||
switch (geoType)
|
||||
{
|
||||
case expressions::FieldAssociation::POINT_DATA : return "points"; break;
|
||||
case expressions::FieldAssociation::FACE_DATA : return "faces"; break;
|
||||
case expressions::FieldAssociation::VOLUME_DATA : return "cells"; break;
|
||||
default: break;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
static void doCorrectBoundaryConditions
|
||||
(
|
||||
bool correctBCs,
|
||||
GeometricField<Type, fvPatchField, volMesh>& field
|
||||
)
|
||||
{
|
||||
if (correctBCs)
|
||||
{
|
||||
// Info<< "Correcting boundary conditions: " << field.name() << nl;
|
||||
field.correctBoundaryConditions();
|
||||
|
||||
// Ensure that calculated patches are updated
|
||||
for (auto& pf : field.boundaryFieldRef())
|
||||
{
|
||||
if (isA<calculatedFvPatchField<Type>>(pf))
|
||||
{
|
||||
pf = pf.patchInternalField();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
void doCorrectBoundaryConditions
|
||||
(
|
||||
bool correctBCs,
|
||||
GeometricField<Type, pointPatchField, pointMesh>& field
|
||||
)
|
||||
{
|
||||
if (correctBCs)
|
||||
{
|
||||
// Info<< "Correcting boundary conditions: " << field.name() << nl;
|
||||
field.correctBoundaryConditions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
void doCorrectBoundaryConditions
|
||||
(
|
||||
bool correctBCs,
|
||||
GeometricField<Type, fvsPatchField, surfaceMesh>& field
|
||||
)
|
||||
{}
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class FieldType>
|
||||
bool Foam::functionObjects::fvExpressionField::loadAndStore(const IOobject& io)
|
||||
{
|
||||
if (FieldType::typeName == io.headerClassName())
|
||||
{
|
||||
// Store field on mesh database
|
||||
Log << " Reading " << io.name()
|
||||
<< " (" << FieldType::typeName << ')' << endl;
|
||||
|
||||
mesh_.objectRegistry::store(new FieldType(io, mesh_));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
bool Foam::functionObjects::fvExpressionField::loadField(const IOobject& io)
|
||||
{
|
||||
typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
|
||||
// typedef typename VolFieldType::Internal IntVolFieldType;
|
||||
typedef GeometricField<Type, fvsPatchField, surfaceMesh> SurfaceFieldType;
|
||||
|
||||
return
|
||||
(
|
||||
loadAndStore<VolFieldType>(io)
|
||||
/// || loadAndStore<IntVolFieldType>(io)
|
||||
|| loadAndStore<SurfaceFieldType>(io)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::functionObjects::fvExpressionField::loadFields
|
||||
(
|
||||
const UList<word>& fieldSet_
|
||||
)
|
||||
{
|
||||
label nLoaded = 0;
|
||||
|
||||
for (const word& fieldName : fieldSet_)
|
||||
{
|
||||
// Already loaded?
|
||||
const auto* ptr = mesh_.cfindObject<regIOobject>(fieldName);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
++nLoaded;
|
||||
DebugInfo
|
||||
<< "readFields : "
|
||||
<< ptr->name() << " (" << ptr->type()
|
||||
<< ") already in database" << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Load field as necessary
|
||||
IOobject io
|
||||
(
|
||||
fieldName,
|
||||
mesh_.time().timeName(),
|
||||
mesh_,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE
|
||||
);
|
||||
|
||||
const bool ok =
|
||||
(
|
||||
io.typeHeaderOk<regIOobject>(false) // Preload header info
|
||||
&& !io.headerClassName().empty() // Extra safety
|
||||
&&
|
||||
(
|
||||
loadField<scalar>(io)
|
||||
|| loadField<vector>(io)
|
||||
|| loadField<sphericalTensor>(io)
|
||||
|| loadField<symmTensor>(io)
|
||||
|| loadField<tensor>(io)
|
||||
)
|
||||
);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
++nLoaded;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugInfo
|
||||
<< "readFields : failed to load " << fieldName << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return nLoaded;
|
||||
}
|
||||
|
||||
|
||||
template<class GeoField>
|
||||
bool Foam::functionObjects::fvExpressionField::setField
|
||||
(
|
||||
GeoField& output,
|
||||
const GeoField& evaluated,
|
||||
const boolField& fieldMask
|
||||
)
|
||||
{
|
||||
label numValuesChanged = 0;
|
||||
|
||||
// Internal field
|
||||
if (fieldMask.empty())
|
||||
{
|
||||
// No field-mask - set all
|
||||
numValuesChanged = output.size();
|
||||
|
||||
output.primitiveFieldRef() = evaluated;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& internal = output.primitiveFieldRef();
|
||||
|
||||
forAll(internal, idx)
|
||||
{
|
||||
if (fieldMask[idx])
|
||||
{
|
||||
internal[idx] = evaluated[idx];
|
||||
++numValuesChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Boundary fields
|
||||
forAll(evaluated.boundaryField(), patchi)
|
||||
{
|
||||
auto& pf = output.boundaryFieldRef()[patchi];
|
||||
|
||||
if (pf.patch().coupled())
|
||||
{
|
||||
pf == evaluated.boundaryField()[patchi];
|
||||
}
|
||||
}
|
||||
|
||||
doCorrectBoundaryConditions(true, output);
|
||||
|
||||
if (action_ == actionType::opModify && log)
|
||||
{
|
||||
const label numTotal = returnReduce(output.size(), plusOp<label>());
|
||||
reduce(numValuesChanged, plusOp<label>());
|
||||
|
||||
Info<< this->name() << ": set ";
|
||||
if (numValuesChanged == numTotal)
|
||||
{
|
||||
Info<< "all ";
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< numValuesChanged << " of ";
|
||||
}
|
||||
Info<< numTotal << " values (field: "
|
||||
<< output.name() << ')' << nl << endl;
|
||||
}
|
||||
|
||||
if (hasDimensions_)
|
||||
{
|
||||
// Log<< "Setting dimensions to " << dims << endl;
|
||||
output.dimensions().reset(dimensions_);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::functionObjects::fvExpressionField::fvExpressionField
|
||||
(
|
||||
const word& name,
|
||||
const Time& runTime,
|
||||
const dictionary& dict,
|
||||
const bool loadFromFiles
|
||||
)
|
||||
:
|
||||
fvMeshFunctionObject(name, runTime, dict),
|
||||
dict_(dict), // Deep copy
|
||||
fieldName_(),
|
||||
preloadFields_(),
|
||||
maskExpr_(),
|
||||
valueExpr_(),
|
||||
dimensions_(),
|
||||
action_(actionType::opNew),
|
||||
autowrite_(false),
|
||||
store_(true),
|
||||
hasDimensions_(false),
|
||||
loadFromFiles_(loadFromFiles)
|
||||
{
|
||||
read(dict);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::functionObjects::fvExpressionField::~fvExpressionField()
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
Foam::word Foam::functionObjects::fvExpressionField::fieldName() const
|
||||
{
|
||||
switch (action_)
|
||||
{
|
||||
case actionType::opNone:
|
||||
{
|
||||
break; // No-op
|
||||
}
|
||||
case actionType::opNew:
|
||||
{
|
||||
return scopedName(fieldName_);
|
||||
}
|
||||
case actionType::opModify:
|
||||
{
|
||||
return fieldName_;
|
||||
}
|
||||
}
|
||||
|
||||
return word::null;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::functionObjects::fvExpressionField::read(const dictionary& dict)
|
||||
{
|
||||
fvMeshFunctionObject::read(dict);
|
||||
|
||||
action_ = actionNames_.getOrDefault("action", dict, actionType::opNew);
|
||||
|
||||
fieldName_ = dict.get<word>("field");
|
||||
const word fldName = fieldName();
|
||||
|
||||
Log << type() << ' ' << this->name() << ':' << nl
|
||||
<< " action = " << actionNames_[action_] << nl
|
||||
<< " field = " << fldName << nl;
|
||||
|
||||
maskExpr_.clear();
|
||||
valueExpr_.clear();
|
||||
|
||||
preloadFields_.clear();
|
||||
dict.readIfPresent("readFields", preloadFields_);
|
||||
|
||||
switch (action_)
|
||||
{
|
||||
case actionType::opNone:
|
||||
{
|
||||
// No-op
|
||||
break;
|
||||
}
|
||||
case actionType::opModify:
|
||||
{
|
||||
// Optional <fieldMask> for modify
|
||||
maskExpr_.readEntry("fieldMask", dict, false);
|
||||
[[fallthrough]];
|
||||
}
|
||||
case actionType::opNew:
|
||||
{
|
||||
// Mandatory <expression> for new and modify
|
||||
valueExpr_.readEntry("expression", dict);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
autowrite_ = dict.getOrDefault("autowrite", false);
|
||||
store_ = dict.getOrDefault("autowrite", true);
|
||||
|
||||
// "dimensions" is optional
|
||||
dimensions_.clear();
|
||||
hasDimensions_ = dimensions_.readEntry("dimensions", dict, false);
|
||||
|
||||
if (action_ == actionType::opNew)
|
||||
{
|
||||
if (!hasDimensions_)
|
||||
{
|
||||
Log << " no 'dimensions' : treat '" << fldName
|
||||
<< "' as dimensionless" << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore for none/modify
|
||||
hasDimensions_ = false;
|
||||
}
|
||||
|
||||
|
||||
if (action_ == actionType::opNone)
|
||||
{
|
||||
driver_.reset(nullptr);
|
||||
return true; // Done
|
||||
}
|
||||
|
||||
driver_.reset
|
||||
(
|
||||
new expressions::volumeExprDriver(mesh_, dict_)
|
||||
);
|
||||
|
||||
driver_->setSearchBehaviour
|
||||
(
|
||||
expressions::exprDriver::searchControls
|
||||
(
|
||||
int(expressions::exprDriver::SEARCH_REGISTRY)
|
||||
| (
|
||||
loadFromFiles_
|
||||
? int(expressions::exprDriver::SEARCH_FILES)
|
||||
: int(0)
|
||||
)
|
||||
),
|
||||
false // No caching
|
||||
);
|
||||
|
||||
driver_->readDict(dict_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::functionObjects::fvExpressionField::performAction(bool doWrite)
|
||||
{
|
||||
using FieldAssociation = expressions::FieldAssociation;
|
||||
|
||||
if (!driver_ || action_ == actionType::opNone)
|
||||
{
|
||||
// No-op
|
||||
return true;
|
||||
}
|
||||
|
||||
const word fldName = fieldName();
|
||||
|
||||
if (loadFromFiles_)
|
||||
{
|
||||
loadFields(preloadFields_);
|
||||
}
|
||||
|
||||
if (action_ == actionType::opModify && loadFromFiles_)
|
||||
{
|
||||
loadFields(wordList({fldName}));
|
||||
}
|
||||
|
||||
auto& driver = *driver_;
|
||||
|
||||
|
||||
// Current availability
|
||||
auto* regIOobjectPtr = mesh_.getObjectPtr<regIOobject>(fldName);
|
||||
|
||||
if (action_ == actionType::opModify && !regIOobjectPtr)
|
||||
{
|
||||
// Cannot continue
|
||||
FatalErrorInFunction
|
||||
<< type() << ' ' << this->name() << ':' << nl
|
||||
<< " missing-field: " << fldName << nl
|
||||
<< exit(FatalError);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Handle "field-mask" evaluation
|
||||
bool evalFieldMask
|
||||
(
|
||||
(action_ == actionType::opModify)
|
||||
&& maskExpr_.size() && maskExpr_ != "true" && maskExpr_ != "1"
|
||||
);
|
||||
|
||||
boolField fieldMask;
|
||||
FieldAssociation maskFieldAssoc(FieldAssociation::NO_DATA);
|
||||
|
||||
if (evalFieldMask)
|
||||
{
|
||||
driver.parse(maskExpr_);
|
||||
|
||||
if (driver.isLogical())
|
||||
{
|
||||
auto& result = driver.result();
|
||||
if (result.is_bool())
|
||||
{
|
||||
fieldMask = result.getResult<bool>();
|
||||
maskFieldAssoc = driver.fieldAssociation();
|
||||
}
|
||||
}
|
||||
|
||||
// Slightly pedantic...
|
||||
driver.clearField();
|
||||
driver.clearResult();
|
||||
|
||||
evalFieldMask = (maskFieldAssoc != FieldAssociation::NO_DATA);
|
||||
|
||||
if (!evalFieldMask)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "field-mask: " << maskExpr_
|
||||
<< " does not evaluate to a logical expression: "
|
||||
<< driver.resultType() << nl
|
||||
#ifdef FULLDEBUG
|
||||
<< "contents: " << fieldMask
|
||||
#endif
|
||||
<< exit(FatalError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Start "expression" evaluation
|
||||
|
||||
bool applied = false;
|
||||
autoPtr<regIOobject> toutputField;
|
||||
|
||||
{
|
||||
driver.clearVariables();
|
||||
|
||||
driver.parse(valueExpr_);
|
||||
|
||||
if (evalFieldMask && maskFieldAssoc != driver.fieldAssociation())
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// The output field does not appear to exist
|
||||
// - create a new 'blank slate'
|
||||
if (!regIOobjectPtr)
|
||||
{
|
||||
toutputField.reset(driver.dupZeroField());
|
||||
|
||||
if (toutputField)
|
||||
{
|
||||
toutputField->rename(fldName);
|
||||
|
||||
if (autowrite_)
|
||||
{
|
||||
toutputField->writeOpt(IOobject::AUTO_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!store_)
|
||||
{
|
||||
// Local (non-registered) field only
|
||||
regIOobjectPtr = toutputField.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (toutputField->checkIn() && toutputField->store())
|
||||
{
|
||||
// Register and transfer ownership to registry
|
||||
toutputField.release();
|
||||
}
|
||||
|
||||
regIOobjectPtr = mesh_.getObjectPtr<regIOobject>(fldName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Additional checks (TBD):
|
||||
|
||||
if (!regIOobjectPtr)
|
||||
{
|
||||
// Cannot continue
|
||||
FatalErrorInFunction
|
||||
<< type() << ' ' << this->name() << ':' << nl
|
||||
<< " missing-field: " << fldName << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
// const word oldFieldType = regIOobjectPtr->type();
|
||||
|
||||
// if (driver.resultType() != oldFieldType)
|
||||
// {
|
||||
// FatalErrorInFunction
|
||||
// << "Inconsistent types: " << fldName << " is "
|
||||
// << oldFieldType
|
||||
// << " but the expression evaluates to "
|
||||
// << driver.resultType()
|
||||
// << exit(FatalError);
|
||||
// }
|
||||
|
||||
switch (driver.fieldAssociation())
|
||||
{
|
||||
#undef doLocalCode
|
||||
#define doLocalCode(GeoField) \
|
||||
{ \
|
||||
/* FieldType */ \
|
||||
auto* outPtr = dynamic_cast<GeoField*>(regIOobjectPtr); \
|
||||
const auto* ptr = driver.isResultType<GeoField>(); \
|
||||
\
|
||||
if (outPtr && ptr) \
|
||||
{ \
|
||||
applied = setField(*outPtr, *ptr, fieldMask); \
|
||||
if (doWrite) \
|
||||
{ \
|
||||
outPtr->write(); \
|
||||
} \
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Clear out heavier data
|
||||
driver.clearResult();
|
||||
driver.clearField();
|
||||
|
||||
if (!applied)
|
||||
{
|
||||
// Or error?
|
||||
WarningInFunction
|
||||
<< type() << ' ' << this->name() << ": Failed to apply "
|
||||
<< actionNames_[action_] << " for " << fldName
|
||||
<< nl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::functionObjects::fvExpressionField::execute()
|
||||
{
|
||||
return performAction(false);
|
||||
}
|
||||
|
||||
|
||||
bool Foam::functionObjects::fvExpressionField::write()
|
||||
{
|
||||
return performAction(true);
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
248
src/functionObjects/field/expressions/fvExpressionField.H
Normal file
248
src/functionObjects/field/expressions/fvExpressionField.H
Normal file
@ -0,0 +1,248 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2021 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::fvExpressionField
|
||||
|
||||
Group
|
||||
grpFieldFunctionObjects
|
||||
|
||||
Description
|
||||
Function object that generates or modifies a field based on expressions.
|
||||
|
||||
Usage
|
||||
A minimal example:
|
||||
\verbatim
|
||||
<name1>
|
||||
{
|
||||
type exprField;
|
||||
libs (fieldFunctionObjects);
|
||||
field pTotal;
|
||||
|
||||
expression "p + 0.5*(rho*magSqr(U))";
|
||||
dimensions [ Pa ];
|
||||
}
|
||||
|
||||
// Modify an existing field
|
||||
<name2>
|
||||
{
|
||||
type exprField;
|
||||
libs (fieldFunctionObjects);
|
||||
field pTotal;
|
||||
action modify;
|
||||
|
||||
// Static pressure only in these regions
|
||||
fieldMask "(mag(pos()) < 0.05) && (pos().y() > 0)";
|
||||
expression "p";
|
||||
}
|
||||
\endverbatim
|
||||
|
||||
where the entries mean:
|
||||
\table
|
||||
Property | Description | Type | Reqd | Dflt
|
||||
type | Type name: exprField | word | yes |
|
||||
libs | Libraries: fieldFunctionObjects | wordList | yes |
|
||||
field | Name of input or output field | word | yes |
|
||||
expression | Field evaluation expression | string | yes |
|
||||
action | Type of operation: see below | word | no | new
|
||||
autowrite | Add AUTO_WRITE to created field | bool | no | false
|
||||
store | Store calculated field | bool | no | true
|
||||
fieldMask | Masking as logical expression | string | no | ""
|
||||
dimensions | Apply specified dimensions to created field | dim-spec | no |
|
||||
readFields | Preload named fields (post-process mode) | wordList | no |
|
||||
useNamePrefix | Add prefix scoping to output name | bool | no | false
|
||||
\endtable
|
||||
|
||||
Options for the \c action entry:
|
||||
\plaintable
|
||||
none | No operation
|
||||
new | Define field based on expression (default)
|
||||
modify | Adjust field according to expression and fieldMask
|
||||
\endplaintable
|
||||
|
||||
Note
|
||||
The \c useNamePrefix entry is always ignored for the \c modify action.
|
||||
|
||||
SourceFiles
|
||||
fvExpressionField.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef functionObjects_fvExpressionField_H
|
||||
#define functionObjects_fvExpressionField_H
|
||||
|
||||
#include "fvMeshFunctionObject.H"
|
||||
#include "volumeExprDriver.H"
|
||||
#include "Enum.H"
|
||||
#include "dimensionSet.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
namespace functionObjects
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class fvExpressionField Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class fvExpressionField
|
||||
:
|
||||
public fvMeshFunctionObject
|
||||
{
|
||||
public:
|
||||
|
||||
// Public Data Types
|
||||
|
||||
//- Action type enumeration
|
||||
enum actionType : unsigned char
|
||||
{
|
||||
opNone = 0, //!< No operation
|
||||
opNew, //!< Create/overwrite field (default)
|
||||
opModify //!< Modify existing field
|
||||
};
|
||||
|
||||
//- Action type names
|
||||
static const Enum<actionType> actionNames_;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Private Data
|
||||
|
||||
//- The context dictionary
|
||||
dictionary dict_;
|
||||
|
||||
//- Name of the field
|
||||
word fieldName_;
|
||||
|
||||
//- Names fields to preload
|
||||
wordList preloadFields_;
|
||||
|
||||
//- The field-mask expression (modify mode)
|
||||
expressions::exprString maskExpr_;
|
||||
|
||||
//- Expression to evaluate
|
||||
expressions::exprString valueExpr_;
|
||||
|
||||
//- Dimensions for new field
|
||||
dimensionSet dimensions_;
|
||||
|
||||
//- Operation mode
|
||||
actionType action_;
|
||||
|
||||
//- Set AUTO_WRITE for new field
|
||||
bool autowrite_;
|
||||
|
||||
//- Store calculated field
|
||||
bool store_;
|
||||
|
||||
//- True if dimensions_ should be used (creation)
|
||||
bool hasDimensions_;
|
||||
|
||||
//- Load fields from files (not from objectRegistry)
|
||||
bool loadFromFiles_;
|
||||
|
||||
autoPtr<expressions::volumeExprDriver> driver_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Attempt load from io, store on database if successful
|
||||
template<class FieldType>
|
||||
bool loadAndStore(const IOobject& io);
|
||||
|
||||
//- Forward to loadAndStore for supported types
|
||||
template<class Type>
|
||||
bool loadField(const IOobject& io);
|
||||
|
||||
//- Attempt to load specified fields
|
||||
label loadFields(const UList<word>& fieldSet_);
|
||||
|
||||
template<class GeoField>
|
||||
bool setField
|
||||
(
|
||||
GeoField& output,
|
||||
const GeoField& evaluated,
|
||||
const boolField& cond
|
||||
);
|
||||
|
||||
bool performAction(bool doWrite);
|
||||
|
||||
public:
|
||||
|
||||
//- Runtime type information
|
||||
TypeName("exprField");
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from Time and dictionary
|
||||
fvExpressionField
|
||||
(
|
||||
const word& name,
|
||||
const Time& runTime,
|
||||
const dictionary& dict,
|
||||
const bool loadFromFiles = false
|
||||
);
|
||||
|
||||
//- No copy construct
|
||||
fvExpressionField(const fvExpressionField&) = delete;
|
||||
|
||||
//- No copy assignment
|
||||
void operator=(const fvExpressionField&) = delete;
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~fvExpressionField();
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- Qualified/unqualified field name (depends on action)
|
||||
virtual word fieldName() const;
|
||||
|
||||
//- Read the data
|
||||
virtual bool read(const dictionary& dict);
|
||||
|
||||
//- Execute
|
||||
virtual bool execute();
|
||||
|
||||
//- Write
|
||||
virtual bool write();
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace functionObjects
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -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 | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
@ -42,17 +42,17 @@ boundaryField
|
||||
{
|
||||
type exprFixedValue;
|
||||
value $internalField;
|
||||
// debug true;
|
||||
// debug.scanner true;
|
||||
// debug.parser true;
|
||||
|
||||
valueExpr "0.5*(pInlet + pOutlet2)";
|
||||
variables
|
||||
(
|
||||
"pInlet{inlet} = weightAverage(p)"
|
||||
"pOutlet2{outlet2} = p"
|
||||
);
|
||||
|
||||
// debug true;
|
||||
// debugScanner true;
|
||||
// debugParser true;
|
||||
valueExpr "0.5*(pInlet + pOutlet2)";
|
||||
}
|
||||
|
||||
outlet2
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
- 15/8/8 Simple T-junction.
|
||||
## Simple T-junction.
|
||||
|
||||
- Inlet on left, one outlet at bottom, one at top.
|
||||
- To test multiple outlets.
|
||||
- Enable debugScanner/debugParser for a verbose view of the parsing engine.
|
||||
- Enable debug.scanner/debug.parser for a verbose view of the parsing engine.
|
||||
|
||||
@ -31,7 +31,7 @@ expressions
|
||||
"radius = 0.1"
|
||||
);
|
||||
|
||||
condition
|
||||
fieldMask
|
||||
#{
|
||||
// Within the radius
|
||||
(mag(pos() - $[(vector)constants.centre]) < radius)
|
||||
|
||||
@ -24,4 +24,42 @@ derivedFields
|
||||
}
|
||||
|
||||
|
||||
exprField1
|
||||
{
|
||||
// Mandatory entries
|
||||
type exprField;
|
||||
libs (fieldFunctionObjects);
|
||||
field pTot;
|
||||
/// action new;
|
||||
///autowrite false;
|
||||
///store true;
|
||||
useNamePrefix false;
|
||||
|
||||
// Use expression to define total pressure
|
||||
|
||||
executeControl timeStep;
|
||||
writeControl none;
|
||||
|
||||
expression "p + 0.5*(rho * magSqr(U))";
|
||||
dimensions [ Pa ];
|
||||
}
|
||||
|
||||
|
||||
exprField1.mod0
|
||||
{
|
||||
// Mandatory entries
|
||||
type exprField;
|
||||
libs (fieldFunctionObjects);
|
||||
field pTot;
|
||||
action modify;
|
||||
|
||||
executeControl timeStep;
|
||||
writeControl writeTime;
|
||||
|
||||
// Static pressure only in these regions
|
||||
fieldMask "(mag(pos()) < 0.05) && (pos().y() > 0) || cellZone(inlet)";
|
||||
expression "p";
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -69,7 +69,7 @@ sampled
|
||||
|
||||
surfaceFormat none;
|
||||
|
||||
fields (p rho U T rhoU pTotal);
|
||||
fields (p rho U T rhoU pTotal pTot);
|
||||
|
||||
// Remove derived fields we created prior
|
||||
removeFieldsOnExecute (rhoU pTotal);
|
||||
@ -182,7 +182,7 @@ areaAverage
|
||||
operation weightedAreaAverage;
|
||||
weightField rhoU;
|
||||
weightFields ( rho U none ); // 2012 and later
|
||||
fields ( p pTotal );
|
||||
fields ( p pTotal pTot );
|
||||
}
|
||||
|
||||
areaIntegrate
|
||||
|
||||
Reference in New Issue
Block a user