From 5105154b886aeecdd2a852e529a68dd3533c7136 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Fri, 22 May 2020 18:11:49 +0200
Subject: [PATCH] ENH: expression versions of Function1 and PatchFunction1
 (#1709)

---
 applications/test/Function1/Test-Function1.C  | 201 ++++++++--------
 .../case1/constant/function1Properties        |  64 +++++
 .../system/controlDict}                       |  11 +-
 src/OpenFOAM/Make/files                       |   2 +
 .../Function1/Function1Expression.C           | 133 +++++++++++
 .../Function1/Function1Expression.H           | 165 +++++++++++++
 .../Function1/makeFunction1Expression.C       |  42 ++++
 .../expressions/fields/fieldExprDriver.C      |   6 +-
 .../expressions/fields/fieldExprDriver.H      |   6 +-
 src/finiteVolume/Make/files                   |   2 +
 .../PatchFunction1/PatchFunction1Expression.C | 165 +++++++++++++
 .../PatchFunction1/PatchFunction1Expression.H | 221 ++++++++++++++++++
 .../makePatchFunction1Expression.C            |  42 ++++
 13 files changed, 958 insertions(+), 102 deletions(-)
 create mode 100644 applications/test/Function1/case1/constant/function1Properties
 rename applications/test/Function1/{function1Properties => case1/system/controlDict} (85%)
 create mode 100644 src/OpenFOAM/expressions/Function1/Function1Expression.C
 create mode 100644 src/OpenFOAM/expressions/Function1/Function1Expression.H
 create mode 100644 src/OpenFOAM/expressions/Function1/makeFunction1Expression.C
 create mode 100644 src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.C
 create mode 100644 src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.H
 create mode 100644 src/finiteVolume/expressions/PatchFunction1/makePatchFunction1Expression.C

diff --git a/applications/test/Function1/Test-Function1.C b/applications/test/Function1/Test-Function1.C
index 65ffd2b68e8..43973975826 100644
--- a/applications/test/Function1/Test-Function1.C
+++ b/applications/test/Function1/Test-Function1.C
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -34,6 +35,7 @@ Description
 #include "fvCFD.H"
 #include "Function1.H"
 #include "scalarIndList.H"
+#include "scalarField.H"
 #include "IOdictionary.H"
 #include "linearInterpolationWeights.H"
 #include "splineInterpolationWeights.H"
@@ -42,104 +44,121 @@ Description
 
 int main(int argc, char *argv[])
 {
-    #include "setRootCase.H"
-    #include "createTime.H"
-    #include "createMesh.H"
+    argList::noParallel();
 
-{
-    scalarField samples(4);
-    samples[0] = 0;
-    samples[1] = 1;
-    samples[2] = 2;
-    samples[3] = 3;
-    scalarField values(4);
-    values = 1.0;
-    //values[0] = 0.0;
-    //values[1] = 1.0;
-
-    linearInterpolationWeights interpolator
-    //splineInterpolationWeights interpolator
-    (
-        samples
-    );
-    labelList indices;
-    scalarField weights;
-
-    interpolator.integrationWeights(1.1, 1.2, indices, weights);
-    Pout<< "indices:" << indices << endl;
-    Pout<< "weights:" << weights << endl;
-
-    scalar baseSum = interpolator.weightedSum
-    (
-        weights,
-        scalarUIndList(values, indices)
-    );
-    Pout<< "baseSum=" << baseSum << nl << nl << endl;
-
-
-//    interpolator.integrationWeights(-0.01, 0, indices, weights);
-//    scalar partialSum = interpolator.weightedSum
-//    (
-//        weights,
-//        scalarUIndList(values, indices)
-//    );
-//    Pout<< "partialSum=" << partialSum << nl << nl << endl;
-//
-//
-//    interpolator.integrationWeights(-0.01, 1, indices, weights);
-//    //Pout<< "samples:" << samples << endl;
-//    //Pout<< "indices:" << indices << endl;
-//    //Pout<< "weights:" << weights << endl;
-//    scalar sum = interpolator.weightedSum
-//    (
-//        weights,
-//        scalarUIndList(values, indices)
-//    );
-//    Pout<< "integrand=" << sum << nl << nl << endl;
-
-
-    return 1;
-}
+    const word dictName("function1Properties");
 
-    IOdictionary function1Properties
-    (
-        IOobject
-        (
-            "function1Properties",
-            runTime.constant(),
-            mesh,
-            IOobject::MUST_READ_IF_MODIFIED,
-            IOobject::NO_WRITE
-        )
-    );
-
-    autoPtr<Function1<scalar>> function1
-    (
-        Function1<scalar>::New
-        (
-            "function1",
-            function1Properties
-        )
-    );
+    argList::addBoolOption("all", "Test all functions in function1Properties");
 
-    scalar x0 = function1Properties.get<scalar>("x0");
-    scalar x1 = function1Properties.get<scalar>("x1");
+    argList::addArgument("function1");
+    argList::addArgument("...");
+    argList::addArgument("functionN");
+    argList::noMandatoryArgs();
 
-    Info<< "Data entry type: " << function1().type() << nl << endl;
+    #include "setRootCase.H"
+    #include "createTime.H"
+
+    {
+        scalarField samples({0, 1, 2, 3});
 
-    Info<< "Inputs" << nl
-        << "    x0 = " << x0 << nl
-        << "    x1 = " << x1 << nl
-        << endl;
+        scalarField values(4, scalar(1));
 
-    Info<< "Interpolation" << nl
-        << "    f(x0) = " << function1().value(x0) << nl
-        << "    f(x1) = " << function1().value(x1) << nl
-        << endl;
+        linearInterpolationWeights interpolator
+        //splineInterpolationWeights interpolator
+        (
+            samples
+        );
+        labelList indices;
+        scalarField weights;
+
+        interpolator.integrationWeights(1.1, 1.2, indices, weights);
+        Pout<< "indices:" << indices << nl
+            << "weights:" << weights << nl;
 
-    Info<< "Integration" << nl
-        << "    int(f(x)) lim(x0->x1) = " << function1().integrate(x0, x1) << nl
-        << endl;
+        scalar baseSum = interpolator.weightedSum
+        (
+            weights,
+            scalarUIndList(values, indices)
+        );
+        Pout<< "baseSum=" << baseSum << nl << nl << endl;
+
+        // interpolator.integrationWeights(-0.01, 0, indices, weights);
+        // scalar partialSum = interpolator.weightedSum
+        // (
+        //     weights,
+        //     scalarUIndList(values, indices)
+        // );
+        // Pout<< "partialSum=" << partialSum << nl << nl << endl;
+
+        // interpolator.integrationWeights(-0.01, 1, indices, weights);
+        // //Pout<< "samples:" << samples << endl;
+        // //Pout<< "indices:" << indices << endl;
+        // //Pout<< "weights:" << weights << endl;
+        // scalar sum = interpolator.weightedSum
+        // (
+        //     weights,
+        //     scalarUIndList(values, indices)
+        // );
+        // Pout<< "integrand=" << sum << nl << nl << endl;
+    }
+
+    if (args.found("all") || args.size() > 1)
+    {
+        #include "setConstantRunTimeDictionaryIO.H"
+
+        IOdictionary propsDict(dictIO);
+
+        const scalarField xvals(propsDict.lookup("x"));
+
+        Info<< "Entries" << flatOutput(propsDict.toc()) << nl << nl;
+
+        Info<< "Inputs" << nl
+            << "    x = " << xvals << nl
+            << endl;
+
+        DynamicList<word> functionNames;
+
+        auto nameFilter = [](const word& val)
+        {
+            return !(val == "x" || val.ends_with("Coeffs"));
+        };
+
+        if (args.found("all"))
+        {
+            for (const word& f : propsDict.toc())
+            {
+                if (nameFilter(f))
+                {
+                    functionNames.append(f);
+                }
+            }
+        }
+        else
+        {
+            for (label argi=1; argi < args.size(); ++argi)
+            {
+                functionNames.append(args[argi]);
+            }
+        }
+
+        for (const word& funName : functionNames)
+        {
+            auto function1 = Function1<scalar>::New(funName, propsDict);
+
+            // Info<< "Data entry type: " << function1().type() << nl;
+            Info<< "////" << nl;
+            function1().writeData(Info);
+            Info<< nl;
+
+            Info<< "Values" << nl;
+            for (const scalar& x : xvals)
+            {
+                Info<< "    f(" << x << ") = " << function1().value(x) << nl;
+            }
+
+            Info<< endl;
+        }
+    }
 
     return 0;
 }
diff --git a/applications/test/Function1/case1/constant/function1Properties b/applications/test/Function1/case1/constant/function1Properties
new file mode 100644
index 00000000000..99b8f968065
--- /dev/null
+++ b/applications/test/Function1/case1/constant/function1Properties
@@ -0,0 +1,64 @@
+/*--------------------------------*- 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;
+    location    "constant";
+    object      function1Properties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// The 'x' values for evaluation
+x
+(
+    0
+    0.25
+    0.5
+    0.75
+    1
+);
+
+
+function1 table
+(
+    (0 0)(10 1)
+);
+
+function2
+{
+    type        expression;
+    expression  #{ sqr(arg()) #};
+}
+
+function2b expression;
+
+function2bCoeffs
+{
+    type        expression;
+    expression  #{ sqr(arg()) #};
+}
+
+
+stepf1
+{
+    type        step;
+    start       0.24;
+    duration    0.5;
+}
+
+rampf1
+{
+    type        linearRamp;
+    start       0.24;
+    duration    0.5;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/Function1/function1Properties b/applications/test/Function1/case1/system/controlDict
similarity index 85%
rename from applications/test/Function1/function1Properties
rename to applications/test/Function1/case1/system/controlDict
index 7c9c1440126..25587f76820 100644
--- a/applications/test/Function1/function1Properties
+++ b/applications/test/Function1/case1/system/controlDict
@@ -10,16 +10,17 @@ FoamFile
     version     2.0;
     format      ascii;
     class       dictionary;
-    location    "constant";
-    object      function1Properties;
+    location    "system";
+    object      controlDict;
 }
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-x0  0.5;
-x1  1;
+application     none;
 
+deltaT          1;
 
-function1 table ((0 0)(10 1));
+writeControl    timeStep;
 
+writeInterval   10;
 
 // ************************************************************************* //
diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files
index 10b7ac0c9e8..96ba27c4042 100644
--- a/src/OpenFOAM/Make/files
+++ b/src/OpenFOAM/Make/files
@@ -164,6 +164,8 @@ $(fieldExpr)/fieldExprDriverFields.C
 $(fieldExpr)/fieldExprLemonParser.lyy-m4
 $(fieldExpr)/fieldExprScanner.cc
 
+$(expr)/Function1/makeFunction1Expression.C
+
 
 ops = primitives/ops
 $(ops)/flipOp.C
diff --git a/src/OpenFOAM/expressions/Function1/Function1Expression.C b/src/OpenFOAM/expressions/Function1/Function1Expression.C
new file mode 100644
index 00000000000..92b935381b8
--- /dev/null
+++ b/src/OpenFOAM/expressions/Function1/Function1Expression.C
@@ -0,0 +1,133 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 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 "Function1Expression.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+template<class Type>
+Foam::Function1Types::Function1Expression<Type>::Function1Expression
+(
+    const word& entryName,
+    const dictionary& dict
+)
+:
+    Function1<Type>(entryName),
+    dict_(dict),
+    valueExpr_(),
+    driver_(1, dict_)
+{
+    if (dict.getOrDefault("debug", false))
+    {
+        debug |= 1;
+    }
+
+    string expr;
+    dict.readEntry("expression", expr);
+    valueExpr_ = expressions::exprString(expr, dict);
+
+    // Basic sanity
+    if (valueExpr_.empty())
+    {
+        FatalIOErrorInFunction(dict_)
+            << "The expression was not defined!" << nl
+            << exit(FatalIOError);
+    }
+
+    driver_.readDict(dict_);
+}
+
+
+template<class Type>
+Foam::Function1Types::Function1Expression<Type>::Function1Expression
+(
+    const Function1Expression<Type>& rhs
+)
+:
+    Function1<Type>(rhs),
+    dict_(rhs.dict_),
+    valueExpr_(rhs.valueExpr_),
+    driver_(1, rhs.driver_)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class Type>
+Type Foam::Function1Types::Function1Expression<Type>::value
+(
+    const scalar x
+) const
+{
+    // Expression evaluation
+    driver_.clearVariables();
+
+    driver_.setArgument(x);
+
+    driver_.parse(this->valueExpr_);
+
+    expressions::exprResult result(driver_.result());
+
+    DebugInfo
+        << "Evaluated: " << result << nl;
+
+    if (!result.hasValue() || !result.size() || !result.isType<Type>())
+    {
+        FatalErrorInFunction
+            << "Could not evaluate: " << this->valueExpr_
+            << exit(FatalError);
+    }
+
+    return result.cref<Type>().first();
+}
+
+
+template<class Type>
+Type Foam::Function1Types::Function1Expression<Type>::integrate
+(
+    const scalar x1,
+    const scalar x2
+) const
+{
+    NotImplemented;
+    return Zero;
+}
+
+
+template<class Type>
+void Foam::Function1Types::Function1Expression<Type>::writeData
+(
+    Ostream& os
+) const
+{
+    // Function1-from-subdict so out dictionary contains
+    // only the relevant entries.
+    dict_.writeEntry(this->name(), os);
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/Function1/Function1Expression.H b/src/OpenFOAM/expressions/Function1/Function1Expression.H
new file mode 100644
index 00000000000..d0f7f8f3487
--- /dev/null
+++ b/src/OpenFOAM/expressions/Function1/Function1Expression.H
@@ -0,0 +1,165 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 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::Function1Types::Function1Expression
+
+Description
+    Function1 with values supplied by a parsed expression.
+
+Usage
+    Example:
+    \verbatim
+    <patchName>
+    {
+        type            uniformFixedValue;
+        uniformValue
+        {
+            type            expression;
+
+            // optional variables for use within the expression
+            variables
+            (
+                "start = 0.5"
+                "stop  = 1"
+            );
+
+            // A step function
+            expression
+            #{
+                mag(arg() > start && arg() < stop) * vector(1, 0, 0)
+            #};
+        }
+    }
+    \endverbatim
+
+Very much like '#eval' but runtime
+
+See also
+    Foam::exprFixedValueFvPatchField
+
+SourceFiles
+    Function1Expression.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef Function1Types_expression_H
+#define Function1Types_expression_H
+
+#include "Function1.H"
+#include "fieldExprDriver.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace Function1Types
+{
+
+/*---------------------------------------------------------------------------*\
+                     Class Function1Expression Declaration
+\*---------------------------------------------------------------------------*/
+
+template<class Type>
+class Function1Expression
+:
+    public Function1<Type>
+{
+    // Private Data
+
+        //- Dictionary contents for the function
+        const dictionary dict_;
+
+        //- The expression
+        expressions::exprString valueExpr_;
+
+        //- The expression driver
+        mutable expressions::fieldExprDriver driver_;
+
+
+    // Private Member Functions
+
+        //- No copy assignment
+        void operator=(const Function1Expression<Type>&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("expression");
+
+
+    // Constructors
+
+        //- Construct from patch, entry name and dictionary
+        //  The patch must correspond to an fvPatch!
+        Function1Expression
+        (
+            const word& entryName,
+            const dictionary& dict
+        );
+
+        //- Copy construct
+        explicit Function1Expression(const Function1Expression<Type>& rhs);
+
+
+    //- Destructor
+    virtual ~Function1Expression() = default;
+
+
+    // Member Functions
+
+        //- Return value.
+        //  The parameter 'x' is accessible as 'arg' in the function
+        virtual Type value(const scalar x) const;
+
+        //- Integrate between two values
+        virtual Type integrate
+        (
+            const scalar x1,
+            const scalar x2
+        ) const;
+
+        //- Write in dictionary format
+        virtual void writeData(Ostream& os) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Function1Types
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "Function1Expression.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/Function1/makeFunction1Expression.C b/src/OpenFOAM/expressions/Function1/makeFunction1Expression.C
new file mode 100644
index 00000000000..f090968f75e
--- /dev/null
+++ b/src/OpenFOAM/expressions/Function1/makeFunction1Expression.C
@@ -0,0 +1,42 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 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 "Function1Expression.H"
+#include "fieldTypes.H"
+#include "addToRunTimeSelectionTable.H"
+
+namespace Foam
+{
+    makeFunction1Type(Function1Expression, scalar);
+    makeFunction1Type(Function1Expression, vector);
+    makeFunction1Type(Function1Expression, sphericalTensor);
+    makeFunction1Type(Function1Expression, symmTensor);
+    makeFunction1Type(Function1Expression, tensor);
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/fields/fieldExprDriver.C b/src/OpenFOAM/expressions/fields/fieldExprDriver.C
index 325c517d39c..91ab582f170 100644
--- a/src/OpenFOAM/expressions/fields/fieldExprDriver.C
+++ b/src/OpenFOAM/expressions/fields/fieldExprDriver.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -81,11 +81,11 @@ Foam::expressions::fieldExpr::parseDriver::parseDriver
 Foam::expressions::fieldExpr::parseDriver::parseDriver
 (
     const label len,
-    const parseDriver& driver_
+    const parseDriver& rhs
 )
 :
     parsing::genericRagelLemonDriver(),
-    expressions::exprDriver(driver_),
+    expressions::exprDriver(rhs),
     size_(len)
 {}
 
diff --git a/src/OpenFOAM/expressions/fields/fieldExprDriver.H b/src/OpenFOAM/expressions/fields/fieldExprDriver.H
index 0221efe4aa8..29bfbdbd543 100644
--- a/src/OpenFOAM/expressions/fields/fieldExprDriver.H
+++ b/src/OpenFOAM/expressions/fields/fieldExprDriver.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -98,7 +98,7 @@ public:
 
     // Constructors
 
-        //- Construct null - uses size = 1
+        //- Default construct - uses size = 1
         parseDriver();
 
         //- Construct with specified size
@@ -108,7 +108,7 @@ public:
         parseDriver(const label len, const dictionary& dict);
 
         //- Construct for specified size with copy of driver context
-        parseDriver(const label len, const parseDriver& driver_);
+        parseDriver(const label len, const parseDriver& rhs);
 
 
     //- Destructor
diff --git a/src/finiteVolume/Make/files b/src/finiteVolume/Make/files
index 3999c34c43c..eef2fd9473f 100644
--- a/src/finiteVolume/Make/files
+++ b/src/finiteVolume/Make/files
@@ -267,6 +267,8 @@ $(patchExpr)/patchExprDriverFields.C
 $(patchExpr)/patchExprLemonParser.lyy-m4
 $(patchExpr)/patchExprScanner.cc
 
+$(expr)/PatchFunction1/makePatchFunction1Expression.C
+
 volumeExpr = $(expr)/volume
 $(volumeExpr)/volumeExpr.C
 $(volumeExpr)/volumeExprDriver.C
diff --git a/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.C b/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.C
new file mode 100644
index 00000000000..2ff54719b55
--- /dev/null
+++ b/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.C
@@ -0,0 +1,165 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 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 "PatchFunction1Expression.H"
+#include "fvPatch.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+template<class Type>
+Foam::PatchFunction1Types::PatchExprField<Type>::PatchExprField
+(
+    const polyPatch& pp,
+    const word& type,
+    const word& entryName,
+    const dictionary& dict,
+    const bool faceValues
+)
+:
+    PatchFunction1<Type>(pp, entryName, dict, faceValues),
+    dict_(dict),
+    valueExpr_(),
+    driver_(fvPatch::lookupPatch(this->patch()), dict_)
+{
+    if (dict.getOrDefault("debug", false))
+    {
+        debug |= 1;
+    }
+
+    string expr;
+    dict.readEntry("expression", expr);
+    valueExpr_ = expressions::exprString(expr, dict);
+
+    // Basic sanity
+    if (valueExpr_.empty())
+    {
+        FatalIOErrorInFunction(dict_)
+            << "The expression was not defined!" << nl
+            << exit(FatalIOError);
+    }
+
+    driver_.readDict(dict_);
+}
+
+
+template<class Type>
+Foam::PatchFunction1Types::PatchExprField<Type>::PatchExprField
+(
+    const PatchExprField<Type>& rhs
+)
+:
+    PatchFunction1<Type>(rhs),
+    dict_(rhs.dict_),
+    valueExpr_(rhs.valueExpr_),
+    driver_(fvPatch::lookupPatch(this->patch()), rhs.driver_)
+{}
+
+
+template<class Type>
+Foam::PatchFunction1Types::PatchExprField<Type>::PatchExprField
+(
+    const PatchExprField<Type>& rhs,
+    const polyPatch& pp
+)
+:
+    PatchFunction1<Type>(rhs, pp),
+    dict_(rhs.dict_),
+    valueExpr_(rhs.valueExpr_),
+    driver_(fvPatch::lookupPatch(this->patch()), rhs.driver_)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class Type>
+Foam::tmp<Foam::Field<Type>>
+Foam::PatchFunction1Types::PatchExprField<Type>::value
+(
+    const scalar x
+) const
+{
+    // Expression evaluation
+    driver_.clearVariables();
+
+    driver_.setArgument(x);
+
+    tmp<Field<Type>> tresult(driver_.evaluate<Type>(this->valueExpr_));
+
+    DebugInfo
+        << "Evaluated: " << tresult() << nl;
+
+    return tresult;
+}
+
+
+template<class Type>
+Foam::tmp<Foam::Field<Type>>
+Foam::PatchFunction1Types::PatchExprField<Type>::integrate
+(
+    const scalar x1,
+    const scalar x2
+) const
+{
+    NotImplemented;
+    return nullptr;
+}
+
+
+template<class Type>
+void Foam::PatchFunction1Types::PatchExprField<Type>::autoMap
+(
+    const FieldMapper& mapper
+)
+{
+    PatchFunction1<Type>::autoMap(mapper);
+}
+
+
+template<class Type>
+void Foam::PatchFunction1Types::PatchExprField<Type>::rmap
+(
+    const PatchFunction1<Type>& pf1,
+    const labelList& addr
+)
+{
+    PatchFunction1<Type>::rmap(pf1, addr);
+}
+
+
+template<class Type>
+void Foam::PatchFunction1Types::PatchExprField<Type>::writeData
+(
+    Ostream& os
+) const
+{
+    // PatchFunction1-from-subdict so out dictionary contains
+    // only the relevant entries.
+    dict_.writeEntry(this->name(), os);
+}
+
+
+// ************************************************************************* //
diff --git a/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.H b/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.H
new file mode 100644
index 00000000000..d8f8f1881a2
--- /dev/null
+++ b/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.H
@@ -0,0 +1,221 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 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::PatchFunction1Types::PatchExprField
+
+Description
+    PatchFunction1 with values supplied by a parsed expression.
+
+Usage
+    Example:
+    \verbatim
+    <patchName>
+    {
+        type            uniformFixedValue;
+        uniformValue
+        {
+            type            expression;
+
+            // optional variables for use within the expression
+            variables
+            (
+                "start = 0.5"
+                "stop  = 1"
+            );
+
+            // A step function
+            expression
+            #{
+                scalar(arg() > start && arg() < stop) * vector(1, 0, 0)
+            #};
+        }
+    }
+    \endverbatim
+
+See also
+    Foam::exprFixedValueFvPatchField
+
+SourceFiles
+    PatchFunction1Expression.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef PatchFunction1Types_expression_H
+#define PatchFunction1Types_expression_H
+
+#include "PatchFunction1.H"
+#include "patchExprDriver.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace PatchFunction1Types
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class PatchExprField Declaration
+\*---------------------------------------------------------------------------*/
+
+template<class Type>
+class PatchExprField
+:
+    public PatchFunction1<Type>
+{
+    // Private Data
+
+        //- Dictionary contents for the function
+        const dictionary dict_;
+
+        //- The expression
+        expressions::exprString valueExpr_;
+
+        //- The expression driver
+        mutable expressions::patchExpr::parseDriver driver_;
+
+
+    // Private Member Functions
+
+        //- No copy assignment
+        void operator=(const PatchExprField<Type>&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("expression");
+
+
+    // Constructors
+
+        //- Construct from patch, entry name and dictionary
+        //  The patch must correspond to an fvPatch!
+        PatchExprField
+        (
+            const polyPatch& pp,
+            const word& type,
+            const word& entryName,
+            const dictionary& dict,
+            const bool faceValues = true
+        );
+
+        //- Copy construct
+        explicit PatchExprField(const PatchExprField<Type>& rhs);
+
+        //- Copy construct setting patch
+        explicit PatchExprField
+        (
+            const PatchExprField<Type>& rhs,
+            const polyPatch& pp
+        );
+
+        //- Construct and return a clone
+        virtual tmp<PatchFunction1<Type>> clone() const
+        {
+            return tmp<PatchFunction1<Type>>
+            (
+                new PatchExprField<Type>(*this)
+            );
+        }
+
+        //- Construct and return a clone setting patch
+        virtual tmp<PatchFunction1<Type>> clone(const polyPatch& pp) const
+        {
+            return tmp<PatchFunction1<Type>>
+            (
+                new PatchExprField<Type>(*this, pp)
+            );
+        }
+
+
+    //- Destructor
+    virtual ~PatchExprField() = default;
+
+
+    // Member Functions
+
+    // Evaluation
+
+        //- Return value.
+        // The parameter 'x' is accessible as 'arg' in the function
+        virtual tmp<Field<Type>> value(const scalar x) const;
+
+        //- Is value constant (i.e. independent of x)
+        virtual inline bool constant() const
+        {
+            return false;
+        }
+
+        //- Is value uniform (i.e. independent of coordinate)
+        virtual inline bool uniform() const
+        {
+            return false;
+        }
+
+        //- Integrate between two values
+        virtual tmp<Field<Type>> integrate
+        (
+            const scalar x1,
+            const scalar x2
+        ) const;
+
+
+    // Mapping
+
+        //- Map (and resize as needed) from self given a mapping object
+        virtual void autoMap(const FieldMapper& mapper);
+
+        //- Reverse map the given PatchFunction1 onto this PatchFunction1
+        virtual void rmap
+        (
+            const PatchFunction1<Type>& pf1,
+            const labelList& addr
+        );
+
+
+    // IO
+
+        //- Write in dictionary format
+        virtual void writeData(Ostream& os) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace PatchFunction1Types
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "PatchFunction1Expression.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/finiteVolume/expressions/PatchFunction1/makePatchFunction1Expression.C b/src/finiteVolume/expressions/PatchFunction1/makePatchFunction1Expression.C
new file mode 100644
index 00000000000..e665db80886
--- /dev/null
+++ b/src/finiteVolume/expressions/PatchFunction1/makePatchFunction1Expression.C
@@ -0,0 +1,42 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 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 "PatchFunction1Expression.H"
+#include "SubField.H"
+#include "addToRunTimeSelectionTable.H"
+
+namespace Foam
+{
+    makePatchFunction1Type(PatchExprField, scalar);
+    makePatchFunction1Type(PatchExprField, vector);
+    makePatchFunction1Type(PatchExprField, sphericalTensor);
+    makePatchFunction1Type(PatchExprField, symmTensor);
+    makePatchFunction1Type(PatchExprField, tensor);
+}
+
+
+// ************************************************************************* //
-- 
GitLab