diff --git a/applications/utilities/preProcessing/setExprBoundaryFields/Make/files b/applications/utilities/preProcessing/setExprBoundaryFields/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..c20222837bd1d4fb54a82ed4f4af6e6d5b3bd61e
--- /dev/null
+++ b/applications/utilities/preProcessing/setExprBoundaryFields/Make/files
@@ -0,0 +1,3 @@
+setExprBoundaryFields.C
+
+EXE = $(FOAM_APPBIN)/setExprBoundaryFields
diff --git a/applications/utilities/preProcessing/setExprBoundaryFields/Make/options b/applications/utilities/preProcessing/setExprBoundaryFields/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..969020c4afaf5d784299462b9e1af282040ba6b4
--- /dev/null
+++ b/applications/utilities/preProcessing/setExprBoundaryFields/Make/options
@@ -0,0 +1,8 @@
+EXE_INC = \
+ -I$(LIB_SRC)/finiteVolume/lnInclude \
+ -I$(LIB_SRC)/meshTools/lnInclude
+
+EXE_LIBS = \
+ -lfiniteVolume \
+ -lmeshTools \
+ -lgenericPatchFields
diff --git a/applications/utilities/preProcessing/setExprBoundaryFields/setExprBoundaryFields.C b/applications/utilities/preProcessing/setExprBoundaryFields/setExprBoundaryFields.C
new file mode 100644
index 0000000000000000000000000000000000000000..179361cdc36a2b2b726ac778778bc47011b34b6d
--- /dev/null
+++ b/applications/utilities/preProcessing/setExprBoundaryFields/setExprBoundaryFields.C
@@ -0,0 +1,262 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2019 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 .
+
+Application
+ setExprFields
+
+Group
+ grpPreProcessingUtilities
+
+Description
+ Set boundary values using an expression
+
+Note
+ Based on funkySetBoundaryFields
+ Copyright 2006-2018 Bernhard Gschaider
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "fvMesh.H"
+#include "pointMesh.H"
+#include "volFields.H"
+#include "surfaceFields.H"
+#include "surfaceFields.H"
+#include "pointFields.H"
+#include "patchExprDriver.H"
+#include "timeSelector.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// Main program:
+
+int main(int argc, char *argv[])
+{
+ argList::noFunctionObjects(true);
+
+ // No -constant, no special treatment for 0/
+ timeSelector::addOptions(false);
+
+ argList::addOption
+ (
+ "dict",
+ "file",
+ "Alternative dictionary for setExprBoundaryFieldsDict"
+ );
+
+ argList::addBoolOption
+ (
+ "cache-fields",
+ "Cache fields between calls",
+ true // Advanced
+ );
+ argList::addBoolOption
+ (
+ "backup",
+ "Preserve sub-entry as .backup",
+ true // Advanced
+ );
+
+ argList::addBoolOption
+ (
+ "dry-run",
+ "Evaluate but do not write"
+ );
+
+ #include "addRegionOption.H"
+ #include "setRootCase.H"
+
+ const bool dryrun = args.found("dry-run");
+ const bool backup = args.found("backup");
+ const bool cacheFields = args.found("cache-fields");
+
+ if (cacheFields)
+ {
+ Warning
+ << "The current cache-fields behaviour (caching disk reads) "
+ << "may lead to unexpected behaviour as previous modifications "
+ << "will not be visible."
+ << endl;
+ }
+
+ const word dictName("setExprBoundaryFieldsDict");
+
+ #include "createTime.H"
+
+ instantList times = timeSelector::select0(runTime, args);
+
+ if (times.size() < 1)
+ {
+ FatalErrorInFunction
+ << "No times selected." << exit(FatalError);
+ }
+
+ #include "createNamedMesh.H"
+
+ #include "setSystemMeshDictionaryIO.H"
+ IOdictionary setExprDict(dictIO);
+
+ forAll(times, timei)
+ {
+ runTime.setTime(times[timei], timei);
+
+ Info<< "\nTime = " << runTime.timeName() << endl;
+
+ mesh.readUpdate();
+
+ for (const entry& dEntry : setExprDict)
+ {
+ if (!dEntry.isDict())
+ {
+ Info<< "Ignoring non-dictionary entry "
+ << dEntry.keyword() << nl;
+ continue;
+ }
+
+ const dictionary& dict = dEntry.dict();
+
+ const word fieldName(dict.get("field"));
+
+ List exprDicts;
+ dict.readEntry("expressions", exprDicts);
+
+ if (exprDicts.empty())
+ {
+ Info<< "No expressions for " << fieldName << nl;
+ continue;
+ }
+
+
+ // Read dictionary
+ // Note: disable class type checking so we can load field
+ const word oldTypeName = IOdictionary::typeName;
+ const_cast(IOdictionary::typeName) = word::null;
+
+ IOobject fieldHeader
+ (
+ fieldName,
+ mesh.thisDb().time().timeName(),
+ mesh.thisDb(),
+ IOobject::MUST_READ_IF_MODIFIED,
+ IOobject::NO_WRITE,
+ false
+ );
+
+ const bool headOk = fieldHeader.typeHeaderOk(false);
+
+ if (!headOk)
+ {
+ // Restore type
+ const_cast(IOdictionary::typeName) = oldTypeName;
+
+ WarningInFunction
+ << "Requested field to change " << fieldName
+ << " does not exist in " << fieldHeader.path() << endl;
+ continue;
+ }
+
+ IOdictionary fieldDict(fieldHeader);
+
+ // Restore type
+ const_cast(IOdictionary::typeName) = oldTypeName;
+
+ // Fake type back to what was in field
+ const_cast(fieldDict.type()) = fieldDict.headerClassName();
+
+ Info<< "Processing field " << fieldName << nl;
+
+ dictionary& boundaryFieldDict = fieldDict.subDict("boundaryField");
+
+ for (const dictionary& currDict : exprDicts)
+ {
+ const word targetName = currDict.get("target");
+ const word patchName = currDict.get("patch");
+
+ dictionary& patchDict = boundaryFieldDict.subDict(patchName);
+
+ expressions::exprString expr
+ (
+ currDict.get("expression"),
+ currDict,
+ true // strip comments
+ );
+
+ Info<< "Set boundaryField/" << patchName << '/'
+ << targetName << nl
+ << "with expression" << nl
+ << "<<<<" << nl
+ << expr.c_str() << nl
+ << ">>>>" << nl;
+
+ expressions::patchExprDriver driver(currDict, mesh);
+
+ // Search on disc
+ driver.setSearchBehaviour(cacheFields, false, true);
+
+ driver.clearVariables();
+ driver.parse(expr);
+
+ // Serializing via Field::writeEntry etc
+ OStringStream serialize;
+ driver.result().writeEntry("", serialize);
+
+ if (backup && !dryrun)
+ {
+ patchDict.changeKeyword
+ (
+ targetName,
+ word(targetName + ".backup"),
+ true // Overwrite
+ );
+ }
+
+ patchDict.set(targetName, serialize.str().c_str());
+
+ if (dryrun)
+ {
+ Info<< "Evaluated:" << nl
+ << "<<<<" << nl
+ << serialize.str().c_str() // (already includes nl)
+ << ">>>>" << nl;
+ }
+ }
+
+ if (!dryrun)
+ {
+ Info<< "Write " << fieldDict.filePath() << nl;
+ fieldDict.regIOobject::write();
+ }
+ }
+ }
+
+ Info<< "\nEnd\n" << endl;
+
+ return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/preProcessing/setExprBoundaryFields/setExprBoundaryFieldsDict b/applications/utilities/preProcessing/setExprBoundaryFields/setExprBoundaryFieldsDict
new file mode 100644
index 0000000000000000000000000000000000000000..53724eb90e7baf9a543693485b41561050986dd1
--- /dev/null
+++ b/applications/utilities/preProcessing/setExprBoundaryFields/setExprBoundaryFieldsDict
@@ -0,0 +1,34 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| ========= | |
+| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
+| \\ / O peration | Version: v1912 |
+| \\ / A nd | Website: www.openfoam.com |
+| \\/ M anipulation | |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+ version 2.0;
+ format ascii;
+ class dictionary;
+ object setExprBoundaryFieldsDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+pattern
+{
+ field T;
+
+ expressions
+ (
+ {
+ patch bottom;
+ target theta0;
+ expression #{ (pos().x() < 1e-4 ? 60 : 120) #};
+ }
+ );
+
+ keepPatches true;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/preProcessing/setExprFields/Make/files b/applications/utilities/preProcessing/setExprFields/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..3212112fdc50ac8119e431b38483d06a64182064
--- /dev/null
+++ b/applications/utilities/preProcessing/setExprFields/Make/files
@@ -0,0 +1,3 @@
+setExprFields.C
+
+EXE = $(FOAM_APPBIN)/setExprFields
diff --git a/applications/utilities/preProcessing/setExprFields/Make/options b/applications/utilities/preProcessing/setExprFields/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..969020c4afaf5d784299462b9e1af282040ba6b4
--- /dev/null
+++ b/applications/utilities/preProcessing/setExprFields/Make/options
@@ -0,0 +1,8 @@
+EXE_INC = \
+ -I$(LIB_SRC)/finiteVolume/lnInclude \
+ -I$(LIB_SRC)/meshTools/lnInclude
+
+EXE_LIBS = \
+ -lfiniteVolume \
+ -lmeshTools \
+ -lgenericPatchFields
diff --git a/applications/utilities/preProcessing/setExprFields/setExprFields.C b/applications/utilities/preProcessing/setExprFields/setExprFields.C
new file mode 100644
index 0000000000000000000000000000000000000000..21a609124c86503fcd00029462a02d1e27497e7e
--- /dev/null
+++ b/applications/utilities/preProcessing/setExprFields/setExprFields.C
@@ -0,0 +1,915 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2019 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 .
+
+Application
+ setExprFields
+
+Group
+ grpPreProcessingUtilities
+
+Description
+ Set values on a selected set of cells/patch-faces via a dictionary.
+
+Note
+ Based on funkySetFields
+ Copyright 2006-2018 Bernhard Gschaider
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "fvMesh.H"
+#include "pointMesh.H"
+#include "volFields.H"
+#include "surfaceFields.H"
+#include "surfaceFields.H"
+#include "pointFields.H"
+#include "exprOps.H"
+#include "volumeExprDriver.H"
+#include "timeSelector.H"
+#include "dlLibraryTable.H"
+
+
+using namespace Foam;
+
+using FieldAssociation = expressions::volumeExpr::FieldAssociation;
+
+word fieldGeoType(const FieldAssociation geoType)
+{
+ switch (geoType)
+ {
+ case FieldAssociation::VOLUME_DATA : return "cells"; break;
+ case FieldAssociation::SURFACE_DATA : return "faces"; break;
+ case FieldAssociation::POINT_DATA : return "points"; break;
+ default: break;
+ }
+
+ return "unknown";
+}
+
+
+//- Simple control structure to with collected switches to simplify passing
+struct setExprFieldsControl
+{
+ bool dryRun;
+ bool debugParsing;
+ bool cacheVariables;
+ bool useDimension;
+ bool createNew;
+ bool keepPatches;
+ bool correctPatches;
+ bool correctBCs;
+};
+
+
+template
+void doCorrectBoundaryConditions
+(
+ bool correctBCs,
+ GeometricField& field
+)
+{
+ if (correctBCs)
+ {
+ Info<< "Correcting boundary conditions: " << field.name() << nl;
+ field.correctBoundaryConditions();
+ }
+}
+
+
+template
+void doCorrectBoundaryConditions
+(
+ bool correctBCs,
+ GeometricField& field
+)
+{
+ if (correctBCs)
+ {
+ Info<< "Correcting boundary conditions: " << field.name() << nl;
+ field.correctBoundaryConditions();
+ }
+}
+
+
+template
+void doCorrectBoundaryConditions
+(
+ bool correctBCs,
+ GeometricField& field
+)
+{}
+
+
+template
+void setField
+(
+ const word& fieldName,
+ const Mesh& mesh,
+ const GeoField& result,
+ const scalarField& cond,
+ const dimensionSet& dims,
+ const wordList& valuePatches,
+
+ const setExprFieldsControl& ctrl
+)
+{
+ Info<< "setField(" << fieldName << "): "
+ << pTraits::typeName << endl;
+
+ tmp toutput;
+
+ if (ctrl.createNew)
+ {
+ // Create with zero
+ toutput = GeoField::New
+ (
+ fieldName,
+ mesh,
+ dimensioned(dims)
+ );
+ }
+ else
+ {
+ // Read
+ toutput = tmp::New
+ (
+ IOobject
+ (
+ fieldName,
+ mesh.thisDb().time().timeName(),
+ mesh.thisDb(),
+ IOobject::MUST_READ,
+ IOobject::NO_WRITE,
+ false // No register
+ ),
+ mesh
+ );
+ }
+
+ auto& output = toutput.ref();
+
+ label setCells = 0;
+
+ if (cond.empty())
+ {
+ // No condition
+ output = result;
+
+ setCells = output.size();
+ }
+ else
+ {
+ forAll(output, celli)
+ {
+ if (expressions::boolOp()(cond[celli]))
+ {
+ output[celli] = result[celli];
+ ++setCells;
+ }
+ }
+ }
+
+ const label totalCells = returnReduce(output.size(), plusOp