From 27e57c29f7bbf4a120e2cfc54ca2f0f7bcf0474a Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Wed, 1 Dec 2021 15:45:41 +0100
Subject: [PATCH] BUG: dangling dictionary reference for expression BCs

- exposed by the new embedded function handling.

  Requires local copies of dictionary content instead
  (similar to coded BCs handling)

BUG: incorrect formatting for expression function output

ENH: simpler copyDict version taking wordList instead of wordRes

- corresponds to the most common use case at the moment

ENH: expression string writeEntry method

- write as verbatim for better readability
---
 .../dictionaryContent/dictionaryContent.C     | 122 ++++++++++++++----
 .../dictionaryContent/dictionaryContent.H     |  16 ++-
 .../Function1/Function1Expression.C           |  10 +-
 .../Function1/Function1Expression.H           |   6 +
 .../expressions/exprDriver/exprDriver.C       |   5 +-
 .../expressions/exprDriver/exprDriver.H       |  17 ++-
 .../exprDriver/exprDriverFunctions.C          |   5 +-
 .../expressions/exprString/exprString.C       |  34 ++++-
 .../expressions/exprString/exprString.H       |  13 ++
 .../expressions/fields/fieldExprDriver.C      |   5 +-
 .../expressions/fields/fieldExprDriver.H      |  18 ++-
 .../PatchFunction1/PatchFunction1Expression.C |  12 +-
 .../expressions/base/fvExprDriver.C           |   5 +-
 .../expressions/base/fvExprDriver.H           |  12 +-
 .../fields/base/patchExprFieldBase.C          |  18 +--
 .../exprFixedValueFvPatchField.C              |  57 +++++---
 .../exprFixedValueFvPatchField.H              |   9 +-
 .../fvPatchFields/exprMixedFvPatchField.C     |  59 ++++++---
 .../fvPatchFields/exprMixedFvPatchField.H     |   9 +-
 .../exprValuePointPatchField.C                |  63 ++++++---
 .../exprValuePointPatchField.H                |  10 +-
 .../expressions/patch/patchExprDriver.C       |   5 +-
 .../expressions/patch/patchExprDriver.H       |  26 ++--
 .../expressions/volume/volumeExprDriver.C     |   5 +-
 .../expressions/volume/volumeExprDriver.H     |  26 ++--
 25 files changed, 398 insertions(+), 169 deletions(-)

diff --git a/src/OpenFOAM/db/dictionary/dictionaryContent/dictionaryContent.C b/src/OpenFOAM/db/dictionary/dictionaryContent/dictionaryContent.C
index 4a7e8e6b51a..f2037f4f143 100644
--- a/src/OpenFOAM/db/dictionary/dictionaryContent/dictionaryContent.C
+++ b/src/OpenFOAM/db/dictionary/dictionaryContent/dictionaryContent.C
@@ -27,21 +27,18 @@ License
 
 #include "dictionaryContent.H"
 
-// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
 
-Foam::dictionary
-Foam::dictionaryContent::copyDict
+namespace Foam
+{
+
+template<class UnaryPredicate>
+static dictionary copyFilteredDict
 (
     const dictionary& input,
-    const wordRes& allow,
-    const wordRes& deny
+    const UnaryPredicate& pred
 )
 {
-    if (allow.empty() && deny.empty())
-    {
-        return dictionary(input);
-    }
-
     dictionary dict;
     dict.name() = input.name();  // rename
 
@@ -57,20 +54,9 @@ Foam::dictionaryContent::copyDict
             // - could also have a "pruneRegex" flag (for example)
             accept = true;
         }
-        else if (allow.size())
-        {
-            const auto result = allow.matched(key);
-
-            accept =
-            (
-                result == wordRe::LITERAL
-              ? true
-              : (result == wordRe::REGEX && !deny.match(key))
-            );
-        }
         else
         {
-            accept = !deny.match(key);
+            accept = pred(key);
         }
 
         if (accept)
@@ -82,5 +68,97 @@ Foam::dictionaryContent::copyDict
     return dict;
 }
 
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+Foam::dictionary
+Foam::dictionaryContent::copyDict
+(
+    const dictionary& input,
+    const wordList& allow,
+    const wordList& deny
+)
+{
+    if (allow.empty())
+    {
+        if (deny.empty())
+        {
+            // Pass-through
+            return dictionary(input);
+        }
+
+        // Deny only
+        return copyFilteredDict
+        (
+            input,
+            [&](const std::string& key) { return !deny.found(key); }
+        );
+    }
+
+    // Allow is non-empty
+
+    // No general case with deny as well
+    return copyFilteredDict
+    (
+        input,
+        [&](const std::string& key) { return allow.found(key); }
+    );
+}
+
+
+Foam::dictionary
+Foam::dictionaryContent::copyDict
+(
+    const dictionary& input,
+    const wordRes& allow,
+    const wordRes& deny
+)
+{
+    if (allow.empty())
+    {
+        if (deny.empty())
+        {
+            // Pass-through
+            return dictionary(input);
+        }
+
+        // Deny only
+        return copyFilteredDict
+        (
+            input,
+            [&](const std::string& key) { return !deny.match(key); }
+        );
+    }
+
+    // Allow is non-empty
+
+    if (deny.empty())
+    {
+        return copyFilteredDict
+        (
+            input,
+            [&](const std::string& key) { return allow.match(key); }
+        );
+    }
+
+    // General case - have both deny and allow
+    return copyFilteredDict
+    (
+        input,
+        [&](const std::string& key)
+        {
+            const auto result = allow.matched(key);
+            return
+            (
+                result == wordRe::LITERAL
+              ? true
+              : (result == wordRe::REGEX && !deny.match(key))
+            );
+        }
+    );
+}
+
 
 // ************************************************************************* //
diff --git a/src/OpenFOAM/db/dictionary/dictionaryContent/dictionaryContent.H b/src/OpenFOAM/db/dictionary/dictionaryContent/dictionaryContent.H
index b4c454230c1..c1137f1eef1 100644
--- a/src/OpenFOAM/db/dictionary/dictionaryContent/dictionaryContent.H
+++ b/src/OpenFOAM/db/dictionary/dictionaryContent/dictionaryContent.H
@@ -86,6 +86,19 @@ public:
 
     // Member Functions
 
+        //- Copy construct a dictionary,
+        //- filtered by simple allow/deny lists
+        //
+        //  An empty 'allow' list accepts everything not in the 'deny' list.
+        //
+        //  \return filtered dictionary copy
+        static dictionary copyDict
+        (
+            const dictionary& input,
+            const wordList& allow = wordList(),
+            const wordList& deny = wordList()
+        );
+
         //- Copy construct a dictionary,
         //- filtered by a combination of allow/deny lists
         //
@@ -104,10 +117,11 @@ public:
         static dictionary copyDict
         (
             const dictionary& input,
-            const wordRes& allow = wordRes(),
+            const wordRes& allow,
             const wordRes& deny = wordRes()
         );
 
+
         //- Read-access to the content
         const dictionary& dict() const noexcept
         {
diff --git a/src/OpenFOAM/expressions/Function1/Function1Expression.C b/src/OpenFOAM/expressions/Function1/Function1Expression.C
index a33c1f01a2e..a0461b59f66 100644
--- a/src/OpenFOAM/expressions/Function1/Function1Expression.C
+++ b/src/OpenFOAM/expressions/Function1/Function1Expression.C
@@ -38,7 +38,7 @@ Foam::Function1Types::Function1Expression<Type>::Function1Expression
 )
 :
     Function1<Type>(entryName, dict, obrPtr),
-    dict_(dict),
+    dict_(dict),  // Deep copy
     valueExpr_(),
     driver_(1, dict_)
 {
@@ -48,8 +48,8 @@ Foam::Function1Types::Function1Expression<Type>::Function1Expression
     }
 
     string expr;
-    dict.readEntry("expression", expr);
-    valueExpr_ = expressions::exprString(expr, dict);
+    dict_.readEntry("expression", expr);
+    valueExpr_ = expressions::exprString(std::move(expr), dict_);
 
     // Basic sanity
     if (valueExpr_.empty())
@@ -70,9 +70,9 @@ Foam::Function1Types::Function1Expression<Type>::Function1Expression
 )
 :
     Function1<Type>(rhs),
-    dict_(rhs.dict_),
+    dict_(rhs.dict_),  // Deep copy
     valueExpr_(rhs.valueExpr_),
-    driver_(1, rhs.driver_)
+    driver_(1, rhs.driver_, dict_)
 {}
 
 
diff --git a/src/OpenFOAM/expressions/Function1/Function1Expression.H b/src/OpenFOAM/expressions/Function1/Function1Expression.H
index 824f84312ef..69ecf324246 100644
--- a/src/OpenFOAM/expressions/Function1/Function1Expression.H
+++ b/src/OpenFOAM/expressions/Function1/Function1Expression.H
@@ -124,6 +124,12 @@ public:
         //- Copy construct
         explicit Function1Expression(const Function1Expression<Type>& rhs);
 
+        //- Construct and return a clone
+        virtual tmp<Function1<Type>> clone() const
+        {
+            return tmp<Function1<Type>>(new Function1Expression<Type>(*this));
+        }
+
 
     //- Destructor
     virtual ~Function1Expression() = default;
diff --git a/src/OpenFOAM/expressions/exprDriver/exprDriver.C b/src/OpenFOAM/expressions/exprDriver/exprDriver.C
index 9bc1f75b11c..d28d84d735b 100644
--- a/src/OpenFOAM/expressions/exprDriver/exprDriver.C
+++ b/src/OpenFOAM/expressions/exprDriver/exprDriver.C
@@ -199,10 +199,11 @@ Foam::expressions::exprDriver::exprDriver
 
 Foam::expressions::exprDriver::exprDriver
 (
-    const exprDriver& rhs
+    const exprDriver& rhs,
+    const dictionary& dict
 )
 :
-    dict_(rhs.dict_),
+    dict_(dict),
     result_(rhs.result_),
     variableStrings_(rhs.variableStrings_),
     variables_(rhs.variables_),
diff --git a/src/OpenFOAM/expressions/exprDriver/exprDriver.H b/src/OpenFOAM/expressions/exprDriver/exprDriver.H
index ccefb049b35..11590e51a3b 100644
--- a/src/OpenFOAM/expressions/exprDriver/exprDriver.H
+++ b/src/OpenFOAM/expressions/exprDriver/exprDriver.H
@@ -277,16 +277,21 @@ protected:
         virtual exprResult getRemoteResult(const exprDriver& other) const;
 
 
-        //- No copy assignment
-        void operator=(const exprDriver&) = delete;
-
-
 public:
 
     //- Runtime type information
     TypeName("exprDriver");
 
 
+    // Generated Methods
+
+        //- No copy construct
+        exprDriver(const exprDriver&) = delete;
+
+        //- No copy assignment
+        void operator=(const exprDriver&) = delete;
+
+
     // Constructors
 
         //- Default construct, and default construct with search preferences
@@ -296,8 +301,8 @@ public:
             const dictionary& dict = dictionary::null
         );
 
-        //- Copy construct
-        exprDriver(const exprDriver& rhs);
+        //- Copy construct with new dictionary reference
+        exprDriver(const exprDriver& rhs, const dictionary& dict);
 
         //- Construct from a dictionary
         explicit exprDriver(const dictionary& dict);
diff --git a/src/OpenFOAM/expressions/exprDriver/exprDriverFunctions.C b/src/OpenFOAM/expressions/exprDriver/exprDriverFunctions.C
index 95f90b81ea2..195eef4301d 100644
--- a/src/OpenFOAM/expressions/exprDriver/exprDriverFunctions.C
+++ b/src/OpenFOAM/expressions/exprDriver/exprDriverFunctions.C
@@ -188,10 +188,7 @@ static void writeFuncsImpl
                 os.beginBlock(subDictName);
             }
 
-            os.beginBlock(entryName);
-            os.writeEntry("type", (*funcPtr).type());
-            (*funcPtr).writeEntries(os);
-            os.endBlock();
+            (*funcPtr).writeData(os);
         }
     }
 
diff --git a/src/OpenFOAM/expressions/exprString/exprString.C b/src/OpenFOAM/expressions/exprString/exprString.C
index 2d6bd03bc09..43cbbb36084 100644
--- a/src/OpenFOAM/expressions/exprString/exprString.C
+++ b/src/OpenFOAM/expressions/exprString/exprString.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -86,4 +86,36 @@ Foam::expressions::exprString::expand
 }
 
 
+bool Foam::expressions::exprString::writeEntry
+(
+    const word& keyword,
+    Ostream& os,
+    bool writeEmpty
+) const
+{
+    const bool ok = (writeEmpty || !empty());
+
+    if (ok)
+    {
+        if (!keyword.empty())
+        {
+            os.writeKeyword(keyword);
+        }
+
+        // Write as regular or verbatim string
+
+        token tok(*this);
+        if (!empty())
+        {
+            tok.setType(token::tokenType::VERBATIM);
+        }
+
+        os.write(tok);
+        os.endEntry();
+    }
+
+    return ok;
+}
+
+
 // ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprString/exprString.H b/src/OpenFOAM/expressions/exprString/exprString.H
index 9a670930f2b..f1d5bef94fb 100644
--- a/src/OpenFOAM/expressions/exprString/exprString.H
+++ b/src/OpenFOAM/expressions/exprString/exprString.H
@@ -183,6 +183,19 @@ public:
 
         //- Move assign from string. No expansions, no comment stripping
         inline exprString& operator=(std::string&& str);
+
+
+    // Write
+
+        //- Dictionary entry for expression string, normally suppressing
+        //- empty strings. Generally used verbatim output (readability)
+        //  \return true if entry was written
+        bool writeEntry
+        (
+            const word& keyword,
+            Ostream& os,
+            bool writeEmpty = false
+        ) const;
 };
 
 
diff --git a/src/OpenFOAM/expressions/fields/fieldExprDriver.C b/src/OpenFOAM/expressions/fields/fieldExprDriver.C
index 5959596d0c2..9fd1092bee4 100644
--- a/src/OpenFOAM/expressions/fields/fieldExprDriver.C
+++ b/src/OpenFOAM/expressions/fields/fieldExprDriver.C
@@ -75,11 +75,12 @@ Foam::expressions::fieldExpr::parseDriver::parseDriver
 Foam::expressions::fieldExpr::parseDriver::parseDriver
 (
     const label len,
-    const parseDriver& rhs
+    const parseDriver& rhs,
+    const dictionary& dict
 )
 :
     parsing::genericRagelLemonDriver(),
-    expressions::exprDriver(rhs),
+    expressions::exprDriver(rhs, dict),
     size_(len)
 {}
 
diff --git a/src/OpenFOAM/expressions/fields/fieldExprDriver.H b/src/OpenFOAM/expressions/fields/fieldExprDriver.H
index c1d7ed04c88..70ae0d2d91b 100644
--- a/src/OpenFOAM/expressions/fields/fieldExprDriver.H
+++ b/src/OpenFOAM/expressions/fields/fieldExprDriver.H
@@ -82,8 +82,11 @@ protected:
         //- The field size
         label size_;
 
+public:
+
+    ClassName("fieldExpr::driver");
 
-    // Protected Member Functions
+    // Generated Methods
 
         // No copy copy construct
         parseDriver(const parseDriver&) = delete;
@@ -92,10 +95,6 @@ protected:
         void operator=(const parseDriver&) = delete;
 
 
-public:
-
-    ClassName("fieldExpr::driver");
-
     // Constructors
 
         //- Default construct (size=1), or with specified size
@@ -104,8 +103,13 @@ public:
         //- Construct for specified size with given dictionary
         parseDriver(const label len, const dictionary& dict);
 
-        //- Construct for specified size with copy of driver context
-        parseDriver(const label len, const parseDriver& rhs);
+        //- Construct for specified size, copy of driver context
+        parseDriver
+        (
+            const label len,
+            const parseDriver& rhs,
+            const dictionary& dict
+        );
 
 
     //- Destructor
diff --git a/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.C b/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.C
index 72211dba9e5..72e19ce8a22 100644
--- a/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.C
+++ b/src/finiteVolume/expressions/PatchFunction1/PatchFunction1Expression.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2020 OpenCFD Ltd.
+    Copyright (C) 2020-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -41,7 +41,7 @@ Foam::PatchFunction1Types::PatchExprField<Type>::PatchExprField
 )
 :
     PatchFunction1<Type>(pp, entryName, dict, faceValues),
-    dict_(dict),
+    dict_(dict),  // Deep copy
     valueExpr_(),
     driver_(fvPatch::lookupPatch(this->patch()), dict_)
 {
@@ -51,8 +51,8 @@ Foam::PatchFunction1Types::PatchExprField<Type>::PatchExprField
     }
 
     string expr;
-    dict.readEntry("expression", expr);
-    valueExpr_ = expressions::exprString(expr, dict);
+    dict_.readEntry("expression", expr);
+    valueExpr_ = expressions::exprString(std::move(expr), dict_);
 
     // Basic sanity
     if (valueExpr_.empty())
@@ -84,9 +84,9 @@ Foam::PatchFunction1Types::PatchExprField<Type>::PatchExprField
 )
 :
     PatchFunction1<Type>(rhs, pp),
-    dict_(rhs.dict_),
+    dict_(rhs.dict_),  // Deep copy
     valueExpr_(rhs.valueExpr_),
-    driver_(fvPatch::lookupPatch(this->patch()), rhs.driver_)
+    driver_(fvPatch::lookupPatch(this->patch()), rhs.driver_, dict_)
 {}
 
 
diff --git a/src/finiteVolume/expressions/base/fvExprDriver.C b/src/finiteVolume/expressions/base/fvExprDriver.C
index bbf7f6d80a4..a30649c39cd 100644
--- a/src/finiteVolume/expressions/base/fvExprDriver.C
+++ b/src/finiteVolume/expressions/base/fvExprDriver.C
@@ -110,10 +110,11 @@ Foam::expressions::fvExprDriver::fvExprDriver
 
 Foam::expressions::fvExprDriver::fvExprDriver
 (
-    const fvExprDriver& rhs
+    const fvExprDriver& rhs,
+    const dictionary& dict
 )
 :
-    expressions::exprDriver(rhs),
+    expressions::exprDriver(rhs, dict),
     globalScopes_(rhs.globalScopes_),
     delayedVariables_(rhs.delayedVariables_),
     storedVariables_(rhs.storedVariables_),
diff --git a/src/finiteVolume/expressions/base/fvExprDriver.H b/src/finiteVolume/expressions/base/fvExprDriver.H
index 60b4c418274..5c4f78f04ea 100644
--- a/src/finiteVolume/expressions/base/fvExprDriver.H
+++ b/src/finiteVolume/expressions/base/fvExprDriver.H
@@ -368,8 +368,12 @@ public:
             const dictionary& dict = dictionary::null
         );
 
-        //- Copy construct
-        fvExprDriver(const fvExprDriver&);
+        //- Copy construct with dictionary reference
+        explicit fvExprDriver
+        (
+            const fvExprDriver& rhs,
+            const dictionary& dict
+        );
 
         //- Construct from a dictionary
         explicit fvExprDriver(const dictionary& dict);
@@ -396,8 +400,8 @@ public:
             const fvMesh& mesh
         );
 
-        //- Clone
-        virtual autoPtr<fvExprDriver> clone() const = 0;
+        //- Not generally clonable
+        virtual autoPtr<fvExprDriver> clone() = delete;
 
 
     //- Destructor
diff --git a/src/finiteVolume/expressions/fields/base/patchExprFieldBase.C b/src/finiteVolume/expressions/fields/base/patchExprFieldBase.C
index 8d0e5e39748..f304e5e5658 100644
--- a/src/finiteVolume/expressions/fields/base/patchExprFieldBase.C
+++ b/src/finiteVolume/expressions/fields/base/patchExprFieldBase.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2018 Bernhard Gschaider
-    Copyright (C) 2019-2020 OpenCFD Ltd.
+    Copyright (C) 2019-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -170,18 +170,10 @@ void Foam::expressions::patchExprFieldBase::write(Ostream& os) const
 
     // Do not emit debug_ value
 
-    if (!valueExpr_.empty())
-    {
-        os.writeEntry("valueExpr", valueExpr_);
-    }
-    if (!gradExpr_.empty())
-    {
-        os.writeEntry("gradientExpr", gradExpr_);
-    }
-    if (!fracExpr_.empty())
-    {
-        os.writeEntry("fractionExpr", fracExpr_);
-    }
+    // Write expression, but not empty ones
+    valueExpr_.writeEntry("valueExpr", os, false);
+    gradExpr_.writeEntry("gradientExpr", os, false);
+    fracExpr_.writeEntry("fractionExpr", os, false);
 }
 
 
diff --git a/src/finiteVolume/expressions/fields/fvPatchFields/exprFixedValueFvPatchField.C b/src/finiteVolume/expressions/fields/fvPatchFields/exprFixedValueFvPatchField.C
index a7d22e0b98d..71fa7dc3916 100644
--- a/src/finiteVolume/expressions/fields/fvPatchFields/exprFixedValueFvPatchField.C
+++ b/src/finiteVolume/expressions/fields/fvPatchFields/exprFixedValueFvPatchField.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2009-2018 Bernhard Gschaider
-    Copyright (C) 2019-2020 OpenCFD Ltd.
+    Copyright (C) 2019-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -27,6 +27,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "exprFixedValueFvPatchField.H"
+#include "dictionaryContent.H"
 
 // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
 
@@ -49,8 +50,9 @@ Foam::exprFixedValueFvPatchField<Type>::exprFixedValueFvPatchField
     const DimensionedField<Type, volMesh>& iF
 )
 :
-    fixedValueFvPatchField<Type>(p, iF),
+    parent_bctype(p, iF),
     expressions::patchExprFieldBase(),
+    dict_(),
     driver_(this->patch())
 {}
 
@@ -58,15 +60,16 @@ Foam::exprFixedValueFvPatchField<Type>::exprFixedValueFvPatchField
 template<class Type>
 Foam::exprFixedValueFvPatchField<Type>::exprFixedValueFvPatchField
 (
-    const exprFixedValueFvPatchField<Type>& ptf,
+    const exprFixedValueFvPatchField<Type>& rhs,
     const fvPatch& p,
     const DimensionedField<Type, volMesh>& iF,
     const fvPatchFieldMapper& mapper
 )
 :
-    fixedValueFvPatchField<Type>(ptf, p, iF, mapper),
-    expressions::patchExprFieldBase(ptf),
-    driver_(this->patch(), ptf.driver_)
+    parent_bctype(rhs, p, iF, mapper),
+    expressions::patchExprFieldBase(rhs),
+    dict_(rhs.dict_),  // Deep copy
+    driver_(this->patch(), rhs.driver_, dict_)
 {
     setDebug();
     DebugInFunction << nl;
@@ -82,13 +85,27 @@ Foam::exprFixedValueFvPatchField<Type>::exprFixedValueFvPatchField
     const bool valueRequired
 )
 :
-    fixedValueFvPatchField<Type>(p, iF),
+    parent_bctype(p, iF),
     expressions::patchExprFieldBase
     (
         dict,
         expressions::patchExprFieldBase::expectedTypes::VALUE_TYPE
     ),
-    driver_(this->patch(), dict)
+    dict_
+    (
+        // Copy dictionary without "heavy" data chunks
+        dictionaryContent::copyDict
+        (
+            dict,
+            wordList(),  // allow
+            wordList     // deny
+            ({
+                "type",  // redundant
+                "value"
+            })
+        )
+    ),
+    driver_(this->patch(), dict_)
 {
     setDebug();
     DebugInFunction << nl;
@@ -102,7 +119,7 @@ Foam::exprFixedValueFvPatchField<Type>::exprFixedValueFvPatchField
     }
 
 
-    driver_.readDict(dict);
+    driver_.readDict(dict_);
 
     if (dict.found("value"))
     {
@@ -134,12 +151,13 @@ Foam::exprFixedValueFvPatchField<Type>::exprFixedValueFvPatchField
 template<class Type>
 Foam::exprFixedValueFvPatchField<Type>::exprFixedValueFvPatchField
 (
-    const exprFixedValueFvPatchField<Type>& ptf
+    const exprFixedValueFvPatchField<Type>& rhs
 )
 :
-    fixedValueFvPatchField<Type>(ptf),
-    expressions::patchExprFieldBase(ptf),
-    driver_(this->patch(), ptf.driver_)
+    parent_bctype(rhs),
+    expressions::patchExprFieldBase(rhs),
+    dict_(rhs.dict_),  // Deep copy
+    driver_(this->patch(), rhs.driver_, dict_)
 {
     setDebug();
     DebugInFunction << nl;
@@ -149,13 +167,14 @@ Foam::exprFixedValueFvPatchField<Type>::exprFixedValueFvPatchField
 template<class Type>
 Foam::exprFixedValueFvPatchField<Type>::exprFixedValueFvPatchField
 (
-    const exprFixedValueFvPatchField<Type>& ptf,
+    const exprFixedValueFvPatchField<Type>& rhs,
     const DimensionedField<Type, volMesh>& iF
 )
 :
-    fixedValueFvPatchField<Type>(ptf, iF),
-    expressions::patchExprFieldBase(ptf),
-    driver_(this->patch(), ptf.driver_)
+    parent_bctype(rhs, iF),
+    expressions::patchExprFieldBase(rhs),
+    dict_(rhs.dict_),  // Deep copy
+    driver_(this->patch(), rhs.driver_, dict_)
 {
     setDebug();
     DebugInFunction << nl;
@@ -199,14 +218,14 @@ void Foam::exprFixedValueFvPatchField<Type>::updateCoeffs()
         }
     }
 
-    fixedValueFvPatchField<Type>::updateCoeffs();
+    this->parent_bctype::updateCoeffs();
 }
 
 
 template<class Type>
 void Foam::exprFixedValueFvPatchField<Type>::write(Ostream& os) const
 {
-    fixedValueFvPatchField<Type>::write(os);
+    this->parent_bctype::write(os);
     expressions::patchExprFieldBase::write(os);
 
     driver_.writeCommon(os, this->debug_ || debug);
diff --git a/src/finiteVolume/expressions/fields/fvPatchFields/exprFixedValueFvPatchField.H b/src/finiteVolume/expressions/fields/fvPatchFields/exprFixedValueFvPatchField.H
index 5ef74552ed2..fba2f2ed988 100644
--- a/src/finiteVolume/expressions/fields/fvPatchFields/exprFixedValueFvPatchField.H
+++ b/src/finiteVolume/expressions/fields/fvPatchFields/exprFixedValueFvPatchField.H
@@ -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.
@@ -67,10 +67,17 @@ class exprFixedValueFvPatchField
     public fixedValueFvPatchField<Type>,
     public expressions::patchExprFieldBase
 {
+    //- The parent boundary condition type
+    typedef fixedValueFvPatchField<Type> parent_bctype;
+
+
 protected:
 
     // Protected Data
 
+        //- Dictionary contents for the boundary condition
+        dictionary dict_;
+
         //- The expression driver
         expressions::patchExpr::parseDriver driver_;
 
diff --git a/src/finiteVolume/expressions/fields/fvPatchFields/exprMixedFvPatchField.C b/src/finiteVolume/expressions/fields/fvPatchFields/exprMixedFvPatchField.C
index e16d95ab671..9fd80b6a794 100644
--- a/src/finiteVolume/expressions/fields/fvPatchFields/exprMixedFvPatchField.C
+++ b/src/finiteVolume/expressions/fields/fvPatchFields/exprMixedFvPatchField.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2009-2018 Bernhard Gschaider
-    Copyright (C) 2019-2020 OpenCFD Ltd.
+    Copyright (C) 2019-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -26,6 +26,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "exprMixedFvPatchField.H"
+#include "dictionaryContent.H"
 
 // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
 
@@ -48,8 +49,9 @@ Foam::exprMixedFvPatchField<Type>::exprMixedFvPatchField
     const DimensionedField<Type, volMesh>& iF
 )
 :
-    mixedFvPatchField<Type>(p, iF),
+    parent_bctype(p, iF),
     expressions::patchExprFieldBase(),
+    dict_(),
     driver_(this->patch())
 {
     this->refValue() = Zero;
@@ -61,15 +63,16 @@ Foam::exprMixedFvPatchField<Type>::exprMixedFvPatchField
 template<class Type>
 Foam::exprMixedFvPatchField<Type>::exprMixedFvPatchField
 (
-    const exprMixedFvPatchField<Type>& ptf,
+    const exprMixedFvPatchField<Type>& rhs,
     const fvPatch& p,
     const DimensionedField<Type, volMesh>& iF,
     const fvPatchFieldMapper& mapper
 )
 :
-    mixedFvPatchField<Type>(ptf, p, iF, mapper),
-    expressions::patchExprFieldBase(ptf),
-    driver_(this->patch(), ptf.driver_)
+    parent_bctype(rhs, p, iF, mapper),
+    expressions::patchExprFieldBase(rhs),
+    dict_(rhs.dict_),  // Deep copy
+    driver_(this->patch(), rhs.driver_, dict_)
 {
     setDebug();
     DebugInFunction << nl;
@@ -84,13 +87,27 @@ Foam::exprMixedFvPatchField<Type>::exprMixedFvPatchField
     const dictionary& dict
 )
 :
-    mixedFvPatchField<Type>(p, iF),
+    parent_bctype(p, iF),
     expressions::patchExprFieldBase
     (
         dict,
         expressions::patchExprFieldBase::expectedTypes::MIXED_TYPE
     ),
-    driver_(this->patch(), dict)
+    dict_
+    (
+        // Copy dictionary without "heavy" data chunks
+        dictionaryContent::copyDict
+        (
+            dict,
+            wordList(),  // allow
+            wordList     // deny
+            ({
+                "type",  // redundant
+                "value", "refValue", "refGradient", "valueFraction"
+            })
+        )
+    ),
+    driver_(this->patch(), dict_)
 {
     setDebug();
     DebugInFunction << nl;
@@ -144,7 +161,7 @@ Foam::exprMixedFvPatchField<Type>::exprMixedFvPatchField
     }
 
 
-    driver_.readDict(dict);
+    driver_.readDict(dict_);
 
     // Similar to fvPatchField constructor, which we have bypassed
     dict.readIfPresent("patchType", this->patchType());
@@ -217,7 +234,7 @@ Foam::exprMixedFvPatchField<Type>::exprMixedFvPatchField
         // but avoid our own updateCoeffs
         if (!this->updated())
         {
-            this->mixedFvPatchField<Type>::updateCoeffs();
+            this->parent_bctype::updateCoeffs();
         }
 
         Field<Type>::operator=
@@ -239,12 +256,13 @@ Foam::exprMixedFvPatchField<Type>::exprMixedFvPatchField
 template<class Type>
 Foam::exprMixedFvPatchField<Type>::exprMixedFvPatchField
 (
-    const exprMixedFvPatchField<Type>& ptf
+    const exprMixedFvPatchField<Type>& rhs
 )
 :
-    mixedFvPatchField<Type>(ptf),
-    expressions::patchExprFieldBase(ptf),
-    driver_(this->patch(), ptf.driver_)
+    parent_bctype(rhs),
+    expressions::patchExprFieldBase(rhs),
+    dict_(rhs.dict_),  // Deep copy
+    driver_(this->patch(), rhs.driver_, dict_)
 {
     setDebug();
     DebugInFunction << nl;
@@ -254,13 +272,14 @@ Foam::exprMixedFvPatchField<Type>::exprMixedFvPatchField
 template<class Type>
 Foam::exprMixedFvPatchField<Type>::exprMixedFvPatchField
 (
-    const exprMixedFvPatchField<Type>& ptf,
+    const exprMixedFvPatchField<Type>& rhs,
     const DimensionedField<Type, volMesh>& iF
 )
 :
-    mixedFvPatchField<Type>(ptf, iF),
-    expressions::patchExprFieldBase(ptf),
-    driver_(this->patch(), ptf.driver_)
+    parent_bctype(rhs, iF),
+    expressions::patchExprFieldBase(rhs),
+    dict_(rhs.dict_),  // Deep copy
+    driver_(this->patch(), rhs.driver_, dict_)
 {
     setDebug();
     DebugInFunction << nl;
@@ -366,14 +385,14 @@ void Foam::exprMixedFvPatchField<Type>::updateCoeffs()
         }
     }
 
-    mixedFvPatchField<Type>::updateCoeffs();
+    this->parent_bctype::updateCoeffs();
 }
 
 
 template<class Type>
 void Foam::exprMixedFvPatchField<Type>::write(Ostream& os) const
 {
-    mixedFvPatchField<Type>::write(os);
+    this->parent_bctype::write(os);
     expressions::patchExprFieldBase::write(os);
 
     driver_.writeCommon(os, this->debug_ || debug);
diff --git a/src/finiteVolume/expressions/fields/fvPatchFields/exprMixedFvPatchField.H b/src/finiteVolume/expressions/fields/fvPatchFields/exprMixedFvPatchField.H
index 0dc8ce7dcef..6d395e078fe 100644
--- a/src/finiteVolume/expressions/fields/fvPatchFields/exprMixedFvPatchField.H
+++ b/src/finiteVolume/expressions/fields/fvPatchFields/exprMixedFvPatchField.H
@@ -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.
@@ -73,10 +73,17 @@ class exprMixedFvPatchField
     public mixedFvPatchField<Type>,
     public expressions::patchExprFieldBase
 {
+    //- The parent boundary condition type
+    typedef mixedFvPatchField<Type> parent_bctype;
+
+
 protected:
 
     // Protected Data
 
+        //- Dictionary contents for the boundary condition
+        dictionary dict_;
+
         //- The expression driver
         expressions::patchExpr::parseDriver driver_;
 
diff --git a/src/finiteVolume/expressions/fields/pointPatchFields/exprValuePointPatchField.C b/src/finiteVolume/expressions/fields/pointPatchFields/exprValuePointPatchField.C
index 1ba5e16d834..4b663133c04 100644
--- a/src/finiteVolume/expressions/fields/pointPatchFields/exprValuePointPatchField.C
+++ b/src/finiteVolume/expressions/fields/pointPatchFields/exprValuePointPatchField.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2010-2018 Bernhard Gschaider
-    Copyright (C) 2019-2020 OpenCFD Ltd.
+    Copyright (C) 2019-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,8 +28,8 @@ License
 
 #include "exprValuePointPatchField.H"
 #include "pointPatchFieldMapper.H"
-#include "typeInfo.H"
 #include "facePointPatch.H"
+#include "dictionaryContent.H"
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
@@ -40,8 +40,9 @@ Foam::exprValuePointPatchField<Type>::exprValuePointPatchField
     const DimensionedField<Type, pointMesh>& iF
 )
 :
-    valuePointPatchField<Type>(p, iF),
+    parent_bctype(p, iF),
     expressions::patchExprFieldBase(),
+    dict_(),
     driver_
     (
         fvPatch::lookupPatch
@@ -55,21 +56,23 @@ Foam::exprValuePointPatchField<Type>::exprValuePointPatchField
 template<class Type>
 Foam::exprValuePointPatchField<Type>::exprValuePointPatchField
 (
-    const exprValuePointPatchField<Type>& ptf,
+    const exprValuePointPatchField<Type>& rhs,
     const pointPatch& p,
     const DimensionedField<Type, pointMesh>& iF,
     const pointPatchFieldMapper& mapper
 )
 :
-    valuePointPatchField<Type>(ptf, p, iF, mapper),
-    expressions::patchExprFieldBase(ptf),
+    parent_bctype(rhs, p, iF, mapper),
+    expressions::patchExprFieldBase(rhs),
+    dict_(rhs.dict_),  // Deep copy
     driver_
     (
         fvPatch::lookupPatch
         (
             dynamicCast<const facePointPatch>(this->patch()).patch()
         ),
-        ptf.driver_
+        rhs.driver_,
+        dict_
     )
 {}
 
@@ -82,12 +85,26 @@ Foam::exprValuePointPatchField<Type>::exprValuePointPatchField
     const dictionary& dict
 )
 :
-    valuePointPatchField<Type>(p, iF),
+    parent_bctype(p, iF),
     expressions::patchExprFieldBase
     (
         dict,
         expressions::patchExprFieldBase::expectedTypes::VALUE_TYPE,
-        true // pointValue
+        true  // pointValue
+    ),
+    dict_
+    (
+        // Copy dictionary without "heavy" data chunks
+        dictionaryContent::copyDict
+        (
+            dict,
+            wordList(),  // allow
+            wordList     // deny
+            ({
+                "type",  // redundant
+                "value"
+            })
+        )
     ),
     driver_
     (
@@ -95,7 +112,7 @@ Foam::exprValuePointPatchField<Type>::exprValuePointPatchField
         (
             dynamicCast<const facePointPatch>(this->patch()).patch()
         ),
-        dict
+        dict_
     )
 {
     // Require valueExpr
@@ -107,7 +124,7 @@ Foam::exprValuePointPatchField<Type>::exprValuePointPatchField
     }
 
 
-    driver_.readDict(dict);
+    driver_.readDict(dict_);
 
     if (dict.found("value"))
     {
@@ -136,19 +153,21 @@ Foam::exprValuePointPatchField<Type>::exprValuePointPatchField
 template<class Type>
 Foam::exprValuePointPatchField<Type>::exprValuePointPatchField
 (
-    const exprValuePointPatchField<Type>& ptf,
+    const exprValuePointPatchField<Type>& rhs,
     const DimensionedField<Type, pointMesh>& iF
 )
 :
-    valuePointPatchField<Type>(ptf, iF),
-    expressions::patchExprFieldBase(ptf),
+    parent_bctype(rhs, iF),
+    expressions::patchExprFieldBase(rhs),
+    dict_(rhs.dict_),  // Deep copy
     driver_
     (
         fvPatch::lookupPatch
         (
             dynamicCast<const facePointPatch>(this->patch()).patch()
         ),
-        ptf.driver_
+        rhs.driver_,
+        dict_
     )
 {}
 
@@ -156,18 +175,20 @@ Foam::exprValuePointPatchField<Type>::exprValuePointPatchField
 template<class Type>
 Foam::exprValuePointPatchField<Type>::exprValuePointPatchField
 (
-    const exprValuePointPatchField<Type>& ptf
+    const exprValuePointPatchField<Type>& rhs
 )
 :
-    valuePointPatchField<Type>(ptf),
-    expressions::patchExprFieldBase(ptf),
+    parent_bctype(rhs),
+    expressions::patchExprFieldBase(rhs),
+    dict_(rhs.dict_),  // Deep copy
     driver_
     (
         fvPatch::lookupPatch
         (
             dynamicCast<const facePointPatch>(this->patch()).patch()
         ),
-        ptf.driver_
+        rhs.driver_,
+        dict_
     )
 {}
 
@@ -212,14 +233,14 @@ void Foam::exprValuePointPatchField<Type>::updateCoeffs()
         }
     }
 
-    valuePointPatchField<Type>::updateCoeffs();
+    this->parent_bctype::updateCoeffs();
 }
 
 
 template<class Type>
 void Foam::exprValuePointPatchField<Type>::write(Ostream& os) const
 {
-    valuePointPatchField<Type>::write(os);
+    this->parent_bctype::write(os);
     expressions::patchExprFieldBase::write(os);
 
     this->writeEntry("value", os);
diff --git a/src/finiteVolume/expressions/fields/pointPatchFields/exprValuePointPatchField.H b/src/finiteVolume/expressions/fields/pointPatchFields/exprValuePointPatchField.H
index 3d6105d6fc7..4ab37195de6 100644
--- a/src/finiteVolume/expressions/fields/pointPatchFields/exprValuePointPatchField.H
+++ b/src/finiteVolume/expressions/fields/pointPatchFields/exprValuePointPatchField.H
@@ -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.
@@ -63,10 +63,17 @@ class exprValuePointPatchField
     public valuePointPatchField<Type>,
     public expressions::patchExprFieldBase
 {
+    //- The parent boundary condition type
+    typedef valuePointPatchField<Type> parent_bctype;
+
+
 protected:
 
     // Protected Data
 
+        //- Dictionary contents for the boundary condition
+        dictionary dict_;
+
         //- The expression driver
         expressions::patchExpr::parseDriver driver_;
 
@@ -129,7 +136,6 @@ public:
             );
         }
 
-
         //- Construct and return a clone setting internal field reference
         virtual autoPtr<pointPatchField<Type>> clone
         (
diff --git a/src/finiteVolume/expressions/patch/patchExprDriver.C b/src/finiteVolume/expressions/patch/patchExprDriver.C
index 1263b444860..e772a7da9e1 100644
--- a/src/finiteVolume/expressions/patch/patchExprDriver.C
+++ b/src/finiteVolume/expressions/patch/patchExprDriver.C
@@ -117,11 +117,12 @@ Foam::expressions::patchExpr::parseDriver::parseDriver
 Foam::expressions::patchExpr::parseDriver::parseDriver
 (
     const fvPatch& p,
-    const parseDriver& rhs
+    const parseDriver& rhs,
+    const dictionary& dict
 )
 :
     parsing::genericRagelLemonDriver(),
-    expressions::fvExprDriver(rhs),
+    expressions::fvExprDriver(rhs, dict),
     patch_(p)
 {
     resetTimeReference(nullptr);
diff --git a/src/finiteVolume/expressions/patch/patchExprDriver.H b/src/finiteVolume/expressions/patch/patchExprDriver.H
index 5a752ccd6e1..e864b5dd66b 100644
--- a/src/finiteVolume/expressions/patch/patchExprDriver.H
+++ b/src/finiteVolume/expressions/patch/patchExprDriver.H
@@ -126,6 +126,12 @@ protected:
         ) const;
 
 
+public:
+
+    ClassName("patchExpr::driver");
+
+    // Generated Methods
+
         // No copy copy construct
         parseDriver(const parseDriver&) = delete;
 
@@ -133,10 +139,6 @@ protected:
         void operator=(const parseDriver&) = delete;
 
 
-public:
-
-    ClassName("patchExpr::driver");
-
     // Constructors
 
         //- Construct for specified patch, with dictionary information
@@ -147,7 +149,12 @@ public:
         );
 
         //- Construct for specified patch with copy of driver context
-        parseDriver(const fvPatch& p, const parseDriver& driver);
+        parseDriver
+        (
+            const fvPatch& p,
+            const parseDriver& driver,
+            const dictionary& dict  // = dictionary::null
+        );
 
         //- Construct with patchName for the given mesh
         parseDriver(const word& patchName, const fvMesh& mesh);
@@ -157,14 +164,7 @@ public:
         parseDriver(const dictionary& dict, const fvMesh& mesh);
 
 
-        //- Clone
-        virtual autoPtr<expressions::fvExprDriver> clone() const
-        {
-            return autoPtr<expressions::fvExprDriver>
-            (
-                new parseDriver(this->patch_, *this)
-            );
-        }
+    // Not generally clonable
 
 
     //- Destructor
diff --git a/src/finiteVolume/expressions/volume/volumeExprDriver.C b/src/finiteVolume/expressions/volume/volumeExprDriver.C
index c1e7eccb705..f41b2b467d1 100644
--- a/src/finiteVolume/expressions/volume/volumeExprDriver.C
+++ b/src/finiteVolume/expressions/volume/volumeExprDriver.C
@@ -105,11 +105,12 @@ Foam::expressions::volumeExpr::parseDriver::parseDriver
 Foam::expressions::volumeExpr::parseDriver::parseDriver
 (
     const fvMesh& mesh,
-    const parseDriver& driver
+    const parseDriver& driver,
+    const dictionary& dict
 )
 :
     parsing::genericRagelLemonDriver(),
-    expressions::fvExprDriver(driver),
+    expressions::fvExprDriver(driver, dict),
     mesh_(mesh),
     resultType_(),
     isLogical_(false),
diff --git a/src/finiteVolume/expressions/volume/volumeExprDriver.H b/src/finiteVolume/expressions/volume/volumeExprDriver.H
index 985b3f27e27..47042f2ad08 100644
--- a/src/finiteVolume/expressions/volume/volumeExprDriver.H
+++ b/src/finiteVolume/expressions/volume/volumeExprDriver.H
@@ -165,6 +165,12 @@ protected:
         ) const;
 
 
+public:
+
+    ClassName("volumeExpr::driver");
+
+    // Generated Methods
+
         // No copy copy construct
         parseDriver(const parseDriver&) = delete;
 
@@ -172,10 +178,6 @@ protected:
         void operator=(const parseDriver&) = delete;
 
 
-public:
-
-    ClassName("volumeExpr::driver");
-
     // Constructors
 
         //- Construct for specified mesh, with dictionary information
@@ -186,7 +188,12 @@ public:
         );
 
         //- Construct for specified mesh with copy of driver context
-        parseDriver(const fvMesh& mesh, const parseDriver& driver);
+        parseDriver
+        (
+            const fvMesh& mesh,
+            const parseDriver& driver,
+            const dictionary& dict
+        );
 
         //- Construct with meshName for the given mesh
         parseDriver(const word& meshName, const fvMesh& mesh);
@@ -195,14 +202,7 @@ public:
         parseDriver(const dictionary& dict, const fvMesh& mesh);
 
 
-        //- Clone
-        virtual autoPtr<expressions::fvExprDriver> clone() const
-        {
-            return autoPtr<expressions::fvExprDriver>
-            (
-                new parseDriver(this->mesh_, *this)
-            );
-        }
+    // Not generally clonable
 
 
     //- Destructor
-- 
GitLab