diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files
index 3ef3831e163c6b199ffa5bbe3a8f8c3c2a802edb..4b71bd073e4c1dcc5b80af8861f9ac5a5c5a56c5 100644
--- a/src/OpenFOAM/Make/files
+++ b/src/OpenFOAM/Make/files
@@ -145,6 +145,12 @@ $(expr)/exprEntry/expressionEntryBool.C
 $(expr)/exprEntry/expressionEntryDimensioned.C
 $(expr)/exprEntry/expressionEntryStrings.C
 $(expr)/exprEntry/expressionEntryVectors.C
+$(expr)/exprResult/exprResult.C
+$(expr)/exprResult/exprResultGlobals.C
+$(expr)/exprResult/exprResultDelayed.C
+$(expr)/exprResult/exprResultStack.C
+$(expr)/exprResult/exprResultStored.C
+$(expr)/exprResult/exprResultStoredStack.C
 $(expr)/exprString/exprString.C
 $(expr)/exprTools/exprTools.C
 
diff --git a/src/OpenFOAM/expressions/exprResult/exprResult.C b/src/OpenFOAM/expressions/exprResult/exprResult.C
new file mode 100644
index 0000000000000000000000000000000000000000..6cf76e2d108b7ebd1aed5ecb924de4e828df5b2f
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResult.C
@@ -0,0 +1,735 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "exprResult.H"
+#include "vector.H"
+#include "tensor.H"
+#include "symmTensor.H"
+#include "sphericalTensor.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+    defineTypeNameAndDebug(exprResult,0);
+
+    defineRunTimeSelectionTable(exprResult, dictionary);
+    defineRunTimeSelectionTable(exprResult, empty);
+
+    addToRunTimeSelectionTable(exprResult, exprResult, dictionary);
+    addToRunTimeSelectionTable(exprResult, exprResult, empty);
+
+} // End namespace expressions
+} // End namespace Foam
+
+
+const Foam::expressions::exprResult Foam::expressions::exprResult::null;
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::expressions::exprResult::singleValue::singleValue()
+{
+    std::memset(static_cast<void*>(this), '\0', sizeof(*this));
+}
+
+
+Foam::expressions::exprResult::singleValue::singleValue
+(
+    const singleValue& val
+)
+{
+    std::memcpy(static_cast<void*>(this), &val, sizeof(*this));
+}
+
+
+void Foam::expressions::exprResult::singleValue::operator=
+(
+    const singleValue& val
+)
+{
+    if (this != &val)
+    {
+        // Self-assignment is a no-op
+        std::memcpy(static_cast<void*>(this), &val, sizeof(*this));
+    }
+}
+
+
+Foam::expressions::exprResult::exprResult()
+:
+    refCount(),
+    valType_(),
+    isUniform_(false),
+    isPointVal_(false),
+    noReset_(false),
+    needsReset_(false),
+    size_(0),
+    single_(),
+    fieldPtr_(nullptr),
+    objectPtr_(nullptr)
+{
+    clear();
+}
+
+
+Foam::expressions::exprResult::exprResult(const exprResult& rhs)
+:
+    exprResult()
+{
+    this->operator=(rhs);
+}
+
+
+Foam::expressions::exprResult::exprResult(exprResult&& rhs)
+:
+    exprResult()
+{
+    this->operator=(std::move(rhs));
+}
+
+
+Foam::expressions::exprResult::exprResult
+(
+    const dictionary& dict,
+    bool uniform,
+    bool needsValue
+)
+:
+    refCount(),
+    valType_(dict.getOrDefault<word>("valueType", "")),
+    isUniform_(dict.getOrDefault("isSingleValue", uniform)),
+    isPointVal_(dict.getOrDefault("isPointValue", false)),
+    noReset_(dict.getOrDefault("noReset", false)),
+    needsReset_(false),
+    size_(0),
+    single_(),
+    fieldPtr_(nullptr),
+    objectPtr_(nullptr)
+{
+    DebugInFunction << nl;
+
+    if (dict.found("value"))
+    {
+        const label len =
+        (
+            isUniform_
+          ? dict.getOrDefault<label>("fieldSize", 1)
+          : dict.get<label>("fieldSize")
+        );
+
+        if (isUniform_)
+        {
+            const bool created =
+            (
+                createUniformChecked<bool>("value", dict, len)
+             || createUniformChecked<scalar>("value", dict, len)
+             || createUniformChecked<vector>("value", dict, len)
+             || createUniformChecked<tensor>("value", dict, len)
+             || createUniformChecked<symmTensor>("value", dict, len)
+             || createUniformChecked<sphericalTensor>("value", dict, len)
+            );
+
+            if (!created)
+            {
+                if (valType_.empty())
+                {
+                    // For the error message only
+                    valType_ = "None";
+                }
+
+                FatalErrorInFunction
+                    << "Don't know how to read data type "
+                    << valType_
+                    << " as a single value" << nl
+                    << exit(FatalError);
+            }
+        }
+        else
+        {
+            const bool created =
+            (
+                createNonUniformChecked<bool>("value", dict, len)
+             || createNonUniformChecked<scalar>("value", dict, len)
+             || createNonUniformChecked<vector>("value", dict, len)
+             || createNonUniformChecked<tensor>("value", dict, len)
+             || createNonUniformChecked<symmTensor>("value", dict, len)
+             || createNonUniformChecked<sphericalTensor>("value", dict, len)
+            );
+
+            if (!created)
+            {
+                if (valType_.empty())
+                {
+                    // For the error message only
+                    valType_ = "None";
+                }
+
+                FatalErrorInFunction
+                    << "Don't know how to read data type " << valType_ << nl
+                    << exit(FatalError);
+            }
+        }
+    }
+    else if (needsValue)
+    {
+        FatalIOErrorInFunction(dict)
+            << "No entry 'value' defined in " << dict.name() << nl
+            << exit(FatalIOError);
+    }
+}
+
+
+Foam::autoPtr<Foam::expressions::exprResult>
+Foam::expressions::exprResult::New
+(
+    const dictionary& dict
+)
+{
+    const word resultType
+    (
+        dict.getOrDefault<word>("resultType", "exprResult")
+    );
+
+    if (dict.getOrDefault("unsetValue", false))
+    {
+        auto cstrIter = emptyConstructorTablePtr_->cfind(resultType);
+
+        if (!cstrIter.found())
+        {
+            FatalErrorInLookup
+            (
+                "resultType",
+                resultType,
+                *emptyConstructorTablePtr_
+            ) << exit(FatalError);
+        }
+
+        DebugInfo
+            << "Creating unset result of type " << resultType << nl;
+
+        return autoPtr<exprResult>(cstrIter()());
+    }
+
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(resultType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInLookup
+        (
+            "resultType",
+            resultType,
+            *dictionaryConstructorTablePtr_
+        ) << exit(FatalError);
+    }
+
+    DebugInfo
+        << "Creating result of type " << resultType << nl;
+
+    return autoPtr<exprResult>(cstrIter()(dict));
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::expressions::exprResult::~exprResult()
+{
+    DebugInFunction << nl;
+
+    uglyDelete();
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::expressions::exprResult::resetImpl()
+{
+    clear();
+}
+
+
+bool Foam::expressions::exprResult::reset(bool force)
+{
+    if (force || !noReset_ || needsReset_)
+    {
+        this->resetImpl();
+        return true;
+    }
+
+    return false;
+}
+
+
+void Foam::expressions::exprResult::clear()
+{
+    uglyDelete();
+    valType_.clear();
+    objectPtr_.reset();
+    size_ = 0;
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+void Foam::expressions::exprResult::uglyDelete()
+{
+    if (fieldPtr_)
+    {
+        const bool ok =
+        (
+            deleteChecked<scalar>()
+         || deleteChecked<vector>()
+         || deleteChecked<tensor>()
+         || deleteChecked<symmTensor>()
+         || deleteChecked<sphericalTensor>()
+         || deleteChecked<bool>()
+        );
+
+        if (!ok)
+        {
+            FatalErrorInFunction
+                << "Unknown type " << valType_
+                << " probable memory loss" << nl
+                << exit(FatalError);
+        }
+
+        fieldPtr_ = nullptr;
+        size_ = 0;
+    }
+}
+
+
+Foam::expressions::exprResult
+Foam::expressions::exprResult::getUniform
+(
+    const label size,
+    const bool noWarn,
+    const bool parRun
+) const
+{
+    if (fieldPtr_ == nullptr)
+    {
+        FatalErrorInFunction
+            << "Not set. Cannot construct uniform value" << nl
+            << exit(FatalError);
+    }
+
+    exprResult ret;
+
+    const bool ok =
+    (
+        getUniformChecked<scalar>(ret, size, noWarn, parRun)
+     || getUniformChecked<vector>(ret, size, noWarn, parRun)
+     || getUniformChecked<tensor>(ret, size, noWarn, parRun)
+     || getUniformChecked<symmTensor>(ret, size, noWarn, parRun)
+     || getUniformChecked<sphericalTensor>(ret, size, noWarn, parRun)
+    );
+
+    if (!ok)
+    {
+        FatalErrorInFunction
+            << "Cannot get uniform value for type " << valType_ << nl
+            << exit(FatalError);
+    }
+
+    return ret;
+}
+
+
+void Foam::expressions::exprResult::testIfSingleValue()
+{
+    if (fieldPtr_ == nullptr)
+    {
+        FatalErrorInFunction
+            << "Not set. Cannot determine if uniform" << nl
+            << exit(FatalError);
+    }
+
+    const bool ok =
+    (
+        setAverageValueChecked<scalar>()
+     || setAverageValueChecked<vector>()
+     || setAverageValueChecked<tensor>()
+     || setAverageValueChecked<symmTensor>()
+     || setAverageValueChecked<sphericalTensor>()
+    );
+
+    if (!ok)
+    {
+        if (isBool())
+        {
+            FatalErrorInFunction
+                << "This specialisation is not implemented" << nl
+                << exit(FatalError);
+        }
+
+        FatalErrorInFunction
+            << "Unknown type " << valType_ << nl
+            << exit(FatalError);
+    }
+}
+
+
+void Foam::expressions::exprResult::operator=(const exprResult& rhs)
+{
+    if (this == &rhs)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    DebugInFunction << "rhs:" << rhs << nl;
+
+    clear();
+
+    valType_ = rhs.valType_;
+    isUniform_ = rhs.isUniform_;
+    isPointVal_ = rhs.isPointVal_;
+    single_ = rhs.single_;
+
+    if (rhs.fieldPtr_)
+    {
+        const bool ok =
+        (
+            duplicateFieldChecked<scalar>(rhs.fieldPtr_)
+         || duplicateFieldChecked<vector>(rhs.fieldPtr_)
+         || duplicateFieldChecked<tensor>(rhs.fieldPtr_)
+         || duplicateFieldChecked<symmTensor>(rhs.fieldPtr_)
+         || duplicateFieldChecked<sphericalTensor>(rhs.fieldPtr_)
+         || duplicateFieldChecked<bool>(rhs.fieldPtr_)
+        );
+
+        if (!ok)
+        {
+            FatalErrorInFunction
+                << " Type " << valType_ << " can not be copied" << nl
+                << exit(FatalError);
+        }
+    }
+    else if (objectPtr_.valid())
+    {
+        FatalErrorInFunction
+            << "Assignment with general content not possible" << nl
+            << exit(FatalError);
+    }
+}
+
+
+void Foam::expressions::exprResult::operator=(exprResult&& rhs)
+{
+    if (this == &rhs)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    clear();
+
+    valType_ = rhs.valType_;
+    isUniform_ = rhs.isUniform_;
+    isPointVal_ = rhs.isPointVal_;
+    noReset_ = rhs.noReset_;
+    needsReset_ = rhs.needsReset_;
+    size_ = rhs.size_;
+
+    single_ = rhs.single_;
+    fieldPtr_ = rhs.fieldPtr_;
+
+    objectPtr_.reset(rhs.objectPtr_.release());
+
+    rhs.fieldPtr_ = nullptr;  // Took ownership of field pointer
+    rhs.clear();
+}
+
+
+void Foam::expressions::exprResult::writeEntry
+(
+    const word& keyword,
+    Ostream& os
+) const
+{
+    const bool ok =
+    (
+        writeEntryChecked<scalar>(keyword, os)
+     || writeEntryChecked<vector>(keyword, os)
+     || writeEntryChecked<tensor>(keyword, os)
+     || writeEntryChecked<symmTensor>(keyword, os)
+     || writeEntryChecked<sphericalTensor>(keyword, os)
+     || writeEntryChecked<bool>(keyword, os)
+    );
+
+    if (!ok)
+    {
+        WarningInFunction
+            << "Unknown data type " << valType_ << endl;
+    }
+}
+
+
+void Foam::expressions::exprResult::writeDict
+(
+    Ostream& os,
+    const bool subDict
+) const
+{
+    // const auto oldFmt = os.format(IOstream::ASCII);
+
+    DebugInFunction
+        << Foam::name(this) << nl
+        << "Format: "
+        << IOstreamOption::formatNames[os.format()] << nl;
+
+    if (subDict)
+    {
+        os.beginBlock();
+    }
+
+    os.writeEntry("resultType", valueType());
+    os.writeEntryIfDifferent<Switch>("noReset_", false, noReset_);
+
+    if (fieldPtr_ == nullptr)
+    {
+        os.writeEntry<Switch>("unsetValue", true);
+    }
+    else
+    {
+        os.writeEntry("valueType", valType_);
+
+        os.writeEntryIfDifferent<Switch>("isPointValue", false, isPointVal_);
+        os.writeEntry<Switch>("isSingleValue", isUniform_);
+
+        const bool ok =
+        (
+            writeValueChecked<scalar>(os)
+         || writeValueChecked<vector>(os)
+         || writeValueChecked<tensor>(os)
+         || writeValueChecked<symmTensor>(os)
+         || writeValueChecked<sphericalTensor>(os)
+         || writeValueChecked<bool>(os)
+        );
+
+        if (!ok)
+        {
+            WarningInFunction
+                << "Unknown data type " << valType_ << endl;
+        }
+    }
+
+    if (subDict)
+    {
+        os.endBlock();
+    }
+
+    // os.format(oldFmt);
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+Foam::expressions::exprResult&
+Foam::expressions::exprResult::operator*=
+(
+    const scalar& b
+)
+{
+    if (isObject())
+    {
+        FatalErrorInFunction
+            << "Can only multiply Field-type exprResult. Not "
+            << valType_ << nl
+            << exit(FatalError);
+    }
+    if (!fieldPtr_)
+    {
+        FatalErrorInFunction
+            << "Can not multiply. Unallocated field of type" << valType_ << nl
+            << exit(FatalError);
+    }
+
+    const bool ok =
+    (
+        multiplyEqChecked<scalar>(b)
+     || multiplyEqChecked<vector>(b)
+     || multiplyEqChecked<tensor>(b)
+     || multiplyEqChecked<symmTensor>(b)
+     || multiplyEqChecked<sphericalTensor>(b)
+    );
+
+    if (!ok)
+    {
+        FatalErrorInFunction
+            << "Can not multiply field of type "
+            << valType_ << nl
+            << exit(FatalError);
+    }
+
+    return *this;
+}
+
+
+Foam::expressions::exprResult&
+Foam::expressions::exprResult::operator+=
+(
+    const exprResult& b
+)
+{
+    if (isObject())
+    {
+        FatalErrorInFunction
+            << "Can only add Field-type, not type: "
+            << valType_ << nl
+            << exit(FatalError);
+    }
+    if (!fieldPtr_)
+    {
+        FatalErrorInFunction
+            << "Can not add. Unallocated field of type " << valType_ << nl
+            << exit(FatalError);
+    }
+
+    if (this->size() != b.size())
+    {
+        FatalErrorInFunction
+            << "Different sizes " << this->size() << " and " << b.size() << nl
+            << exit(FatalError);
+    }
+
+    const bool ok =
+    (
+        plusEqChecked<scalar>(b)
+     || plusEqChecked<vector>(b)
+     || plusEqChecked<tensor>(b)
+     || plusEqChecked<symmTensor>(b)
+     || plusEqChecked<sphericalTensor>(b)
+    );
+
+    if (!ok)
+    {
+        FatalErrorInFunction
+            << "Can not add Field-type exprResult of type"
+            << valType_ << nl
+            << exit(FatalError);
+    }
+
+    return *this;
+}
+
+
+// * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
+
+Foam::Istream& Foam::operator>>
+(
+    Istream& is,
+    expressions::exprResult& data
+)
+{
+    dictionary dict(is);
+
+    data = expressions::exprResult(dict);
+
+    return is;
+}
+
+
+Foam::Ostream& Foam::operator<<
+(
+    Ostream& os,
+    const expressions::exprResult& data
+)
+{
+    data.writeDict(os);
+
+    return os;
+}
+
+
+Foam::expressions::exprResult Foam::operator*
+(
+    const scalar& a,
+    const expressions::exprResult& b
+)
+{
+    expressions::exprResult result(b);
+    return result *= a;
+}
+
+
+Foam::expressions::exprResult Foam::operator*
+(
+    const expressions::exprResult& a,
+    const scalar& b
+)
+{
+    expressions::exprResult result(a);
+    result *= b;
+
+    return result;
+}
+
+
+Foam::expressions::exprResult Foam::operator+
+(
+    const expressions::exprResult& a,
+    const expressions::exprResult& b
+)
+{
+    expressions::exprResult result(a);
+    result += b;
+
+    return result;
+}
+
+
+const void* Foam::expressions::exprResult::dataAddress() const
+{
+    #undef  defineExpressionMethod
+    #define defineExpressionMethod(Type)                                      \
+        if (isType<Type>())                                                   \
+        {                                                                     \
+            return static_cast<Field<Type>*>(fieldPtr_)->cdata();             \
+        }
+
+    defineExpressionMethod(scalar);
+    defineExpressionMethod(vector);
+    defineExpressionMethod(tensor);
+    defineExpressionMethod(symmTensor);
+    defineExpressionMethod(sphericalTensor);
+
+    #undef defineExpressionMethod
+
+    FatalErrorInFunction
+        << "Unsupported type" << valType_ << nl
+        << exit(FatalError);
+
+    return nullptr;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResult.H b/src/OpenFOAM/expressions/exprResult/exprResult.H
new file mode 100644
index 0000000000000000000000000000000000000000..d5dcf4d2f0eea51d524775f5afd9f5f1794310aa
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResult.H
@@ -0,0 +1,562 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::expressions::exprResult
+
+Description
+    A polymorphic field/result from evaluating an expression
+
+    \heading Dictionary parameters
+    \table
+        Property    | Description                           | Required | Default
+        resultType  | The type of result                    | no  | exprResult
+        unsetValue  | Create without reading the dictionary | no  | false
+        noReset     | Suppress reset on time                | no  | false
+    \endtable
+
+    When creating with values
+    \table
+        Property    | Description                           | Required | Default
+        valueType   | Result value type (scalar, vector,..) | yes |
+        isSingleValue | A single field value                | no  | false
+        isPointValue  | Interpret values as point values    | no  | false
+        value       | The field values                      | yes |
+        fieldSize   | The size of the field (when not single-value) | no  |
+    \endtable
+
+SourceFiles
+    exprResult.C
+    exprResultI.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef expressions_exprResult_H
+#define expressions_exprResult_H
+
+#include "vector.H"
+#include "tensor.H"
+#include "sphericalTensor.H"
+#include "symmTensor.H"
+#include "dimensionedType.H"
+#include "IOField.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class exprResult Declaration
+\*---------------------------------------------------------------------------*/
+
+class exprResult
+:
+    public refCount
+{
+    // Private Data
+
+        //- The value type as string,
+        //- normally corresponds to pTraits or typeName
+        word valType_;
+
+        //- Is single, uniform value (can be a non-field)
+        bool isUniform_;
+
+        //- Is a point value
+        bool isPointVal_;
+
+        //- Whether or not the variable will be reset
+        bool noReset_;
+
+        //- Allow override of noReset_, but only accessible for subclasses
+        bool needsReset_;
+
+        //- Size of field or object
+        label size_;
+
+        //- A %union of single values, including standard VectorSpace types
+        union singleValue
+        {
+            bool bool_;
+            scalar scalar_;
+            vector vector_;
+            tensor tensor_;
+            symmTensor symmTensor_;
+            sphericalTensor sphTensor_;
+
+            //- Construct null, zero-initialized
+            singleValue();
+
+            //- Copy construct
+            singleValue(const singleValue& val);
+
+            //- Copy assignment
+            void operator=(const singleValue& val);
+
+            //- Return current value for specified type.
+            template<class T>
+            inline const T& get() const
+            {
+                NotImplemented;
+                return pTraits<T>::zero;
+            }
+
+            //- Set new value for specified type. Returns updated value.
+            template<class T>
+            inline const T& set(const T& val)
+            {
+                NotImplemented;
+                return pTraits<T>::zero;
+            }
+        };
+
+        //- The single value
+        singleValue single_;
+
+        //- Allocated plain field (eg, scalarField)
+        void *fieldPtr_;
+
+        //- Alternative storage for non-plain fields (eg, volScalarField)
+        autoPtr<regIOobject> objectPtr_;
+
+
+    // Private Member Functions
+
+        //- Type-checked deletion of the value pointer.
+        //  \return True if the type check was satisfied
+        template<class Type>
+        inline bool deleteChecked();
+
+        //- Dispatch to type-checked pointer deletion
+        void uglyDelete();
+
+        //- Type-checked creation of uniform field from dictionary
+        //  \return True if the type check was satisfied
+        template<class Type>
+        inline bool createUniformChecked
+        (
+            const word& key,
+            const dictionary& dict,
+            const label len
+        );
+
+        //- Type-checked creation of non-uniform field from dictionary
+        //  \return True if the type check was satisfied
+        template<class Type>
+        inline bool createNonUniformChecked
+        (
+            const word& key,
+            const dictionary& dict,
+            const label len
+        );
+
+        //- Type-checked retrieval of uniform field from current results
+        //  \return True if the type check was satisfied
+        template<class Type>
+        bool getUniformChecked
+        (
+            exprResult& result,
+            const label size,
+            const bool noWarn,
+            const bool parallel
+        ) const;
+
+        //- Type-checked determination of centre value (min/max)
+        //  \return True if the type check was satisfied
+        template<class Type>
+        bool setAverageValueChecked();
+
+        //- Type-checked copy of field
+        //  \return True if the type check was satisfied
+        template<class Type>
+        bool duplicateFieldChecked(const void* ptr);
+
+        //- Type-checked writing of "value" entry
+        //  \return True if the type check was satisfied
+        template<class Type>
+        bool writeValueChecked(Ostream& os) const;
+
+        //- Type-checked forwarding to Field::writeEntry
+        //  \return True if the type check was satisfied
+        template<class Type>
+        bool writeEntryChecked(const word& keyword, Ostream& os) const;
+
+        //- Type-checked field addition with another expression field
+        //  \return True if the type check was satisfied
+        template<class Type>
+        bool plusEqChecked(const exprResult& b);
+
+        //- Type-checked field multiplication with a scalar
+        //  \return True if the type check was satisfied
+        template<class Type>
+        bool multiplyEqChecked(const scalar& b);
+
+
+        template<class Type>
+        inline void setResultImpl(Field<Type>*, bool isPointVal=false);
+
+        template<class Type>
+        inline void setResultImpl(const Field<Type>&, bool isPointVal=false);
+
+        template<class Type>
+        inline void setResultImpl(Field<Type>&&, bool isPointVal=false);
+
+        template<class Type>
+        inline void setResultImpl(const Type& val, const label len);
+
+        template<class Type>
+        inline void setSingleValueImpl(const Type& val);
+
+        template<class Type>
+        inline void setObjectResultImpl(Type* ptr);
+
+        template<class Type>
+        inline void setObjectResultImpl(autoPtr<Type>& ap);
+
+        template<class Type>
+        inline void setObjectResultImpl(autoPtr<Type>&& ap);
+
+
+protected:
+
+    // Protected Member Functions
+
+        //- Simulate virtual templated methods
+        inline virtual exprResult& target() { return *this; }
+
+        //- Reset at new timestep according to the derived class type
+        virtual void resetImpl();
+
+        //- Reset at new timestep according to type
+        //  \return true if it was actually reset
+        bool reset(bool force=false);
+
+        //- Adjusts the internal needsReset value
+        void needsReset(bool val) { needsReset_ = val; }
+
+
+public:
+
+        //- An empty result
+        static const exprResult null;
+
+        //- Friendship with globals
+        friend class exprResultGlobals;
+
+
+        //- Runtime type information
+        TypeName("exprResult");
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            exprResult,
+            dictionary,
+            (
+                const dictionary& dict
+            ),
+            (dict)
+        );
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            exprResult,
+            empty,
+            (),
+            ()
+        );
+
+
+    // Constructors
+
+        //- Construct null
+        exprResult();
+
+        //- Copy construct
+        exprResult(const exprResult& expr);
+
+        //- Move construct
+        exprResult(exprResult&& expr);
+
+        //- Construct from a dictionary
+        explicit exprResult
+        (
+            const dictionary& dict,
+            const bool uniform = false,
+            const bool needsValue = false
+        );
+
+        //- Construct by copying a field
+        template<class Type>
+        exprResult(const Field<Type>& f);
+
+        //- Construct by moving a field
+        template<class Type>
+        exprResult(Field<Type>&& f);
+
+        //- Construct for an IOobject
+        template<class Type>
+        exprResult(autoPtr<Type>& ap);
+
+        //- Construct for an IOobject
+        template<class Type>
+        exprResult(autoPtr<Type>&& ap);
+
+        //- Construct from a dimensioned value
+        template<class Type>
+        exprResult(const dimensioned<Type>& f);
+
+        #undef exprResult_Construct
+        #define exprResult_Construct(Type)                                \
+            /*! Construct from single value of Type */                    \
+            explicit exprResult(const Type& val) : exprResult()           \
+            {                                                             \
+                setSingleValue(val);                                      \
+            }
+
+        exprResult_Construct(bool);
+        exprResult_Construct(scalar);
+        exprResult_Construct(vector);
+        exprResult_Construct(tensor);
+        exprResult_Construct(symmTensor);
+        exprResult_Construct(sphericalTensor);
+
+        #undef exprResult_Construct
+
+
+    // Selectors
+
+        //- Return a reference to the selected value driver
+        static autoPtr<exprResult> New(const dictionary& dict);
+
+        //- Clone
+        virtual autoPtr<exprResult> clone() const
+        {
+            return autoPtr<exprResult>::New(*this);
+        }
+
+
+    //- Destructor
+    virtual ~exprResult();
+
+
+    // Member Functions
+
+    // Access
+
+        //- Has a value?
+        inline bool hasValue() const;
+
+        //- Basic type for the field or single value
+        inline const word& valueType() const;
+
+        //- True if representing point values, or test if same as isPointVal
+        inline bool isPointValue(const bool isPointVal = true) const;
+
+        //- True if single, uniform value
+        inline bool isUniform() const;
+
+        //- True if valueType corresponds to the given Type
+        template<class Type>
+        inline bool isType() const;
+
+        //- True if valueType is a bool
+        inline bool isBool() const;
+
+        //- True if the object pointer is being used
+        inline bool isObject() const;
+
+        //- The field or object size
+        inline label size() const;
+
+        //- The address of the field data content.
+        //  Fatal for unknown types.
+        //  Used, for example, for python integration
+        const void* dataAddress() const;
+
+
+    // Edit
+
+        //- Clear (zero) the result
+        void clear();
+
+        //- Change reset behaviour
+        void noReset() { noReset_ = true; }
+
+        //- Change reset behaviour
+        void allowReset() { noReset_ = false; }
+
+        //- Test if field corresponds to a single-value and thus uniform.
+        //  Uses field min/max to establish uniformity.
+        void testIfSingleValue();
+
+
+
+    // Set results
+
+        //- Set result field, taking ownership of the pointer
+        template<class Type>
+        inline void setResult(Field<Type>*, bool isPointVal=false);
+
+        //- Set result field, taking copy of the field contents
+        template<class Type>
+        inline void setResult(const Field<Type>& fld, bool isPointVal=false);
+
+        //- Set result field, moving field contents
+        template<class Type>
+        inline void setResult(Field<Type>&&, bool isPointVal=false);
+
+        //- Set uniform result field of given size
+        template<class Type>
+        inline void setResult(const Type& val, const label size);
+
+        //- Set single-value uniform result
+        template<class Type>
+        inline void setSingleValue(const Type& val);
+
+        template<class Type>
+        inline void setObjectResult(autoPtr<Type>& o);
+
+        template<class Type>
+        inline void setObjectResult(autoPtr<Type>&& o);
+
+
+    // Access/Get results
+
+        //- Return const reference to the field
+        template<class Type>
+        inline const Field<Type>& cref() const;
+
+        //- Return non-const reference to the field
+        template<class Type>
+        inline Field<Type>& ref();
+
+        //- Return non-const reference to the field, casting away constness
+        template<class Type>
+        inline Field<Type>& getRef() const;
+
+        //- Return tmp field of the contents,
+        //- optionally keeping a copy in cache
+        template<class Type>
+        inline tmp<Field<Type>> getResult(bool cacheCopy=false);
+
+        //- Get object result (Caution - potentially fragile)
+        //- optionally keeping a copy in cache
+        template<class Type>
+        inline tmp<Type> getObjectResult(bool cacheCopy=false);
+
+        //- Construct a uniform field from the current results
+        //  Uses the field average. Optionally warning if the min/max
+        //  deviation is larger than SMALL.
+        exprResult getUniform
+        (
+            const label size,
+            const bool noWarn,
+            const bool parRun = Pstream::parRun()
+        ) const;
+
+        //- Get a reduced result
+        template<template<class> class BinaryOp, class Type>
+        inline Type getReduced
+        (
+            const BinaryOp<Type>& bop,
+            const Type& initial = pTraits<Type>::zero
+        );
+
+
+    // Write
+
+        //- Forwarding to Field::writeEntry
+        void writeEntry(const word& keyword, Ostream& os) const;
+
+        //- Write entry as dictionary contents
+        void writeDict(Ostream& os, const bool subDict=true) const;
+
+
+    // Member Operators
+
+        //- Copy assignment
+        virtual void operator=(const exprResult& rhs);
+
+        //- Move assignment
+        virtual void operator=(exprResult&& rhs);
+
+
+        //- Scalar multiplication
+        exprResult& operator*=(const scalar& b);
+
+        //- Addition of results
+        exprResult& operator+=(const exprResult& b);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace expressions
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Operators
+
+expressions::exprResult operator*
+(
+    const scalar& a,
+    const expressions::exprResult& b
+);
+expressions::exprResult operator*
+(
+    const expressions::exprResult& a,
+    const scalar& b
+);
+expressions::exprResult operator+
+(
+    const expressions::exprResult& a,
+    const expressions::exprResult& b
+);
+
+
+// IO Operator
+Istream& operator>>(Istream& os, expressions::exprResult& data);
+Ostream& operator<<(Ostream& os, const expressions::exprResult& data);
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "exprResultI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResultDelayed.C b/src/OpenFOAM/expressions/exprResult/exprResultDelayed.C
new file mode 100644
index 0000000000000000000000000000000000000000..dfd43f13a26b010aed5e7dfb7e0e749d6edbdff4
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResultDelayed.C
@@ -0,0 +1,333 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "exprResultDelayed.H"
+#include "vector.H"
+#include "tensor.H"
+#include "symmTensor.H"
+#include "sphericalTensor.H"
+#include "addToRunTimeSelectionTable.H"
+
+// #include <cassert>
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+    defineTypeNameAndDebug(exprResultDelayed, 0);
+
+    addToRunTimeSelectionTable
+    (
+        exprResult,
+        exprResultDelayed,
+        dictionary
+    );
+    addToRunTimeSelectionTable
+    (
+        exprResult,
+        exprResultDelayed,
+        empty
+    );
+
+} // End namespace expressions
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::expressions::exprResultDelayed::exprResultDelayed()
+:
+    exprResult(),
+    name_("none"),
+    startExpr_(),
+    settingResult_(),
+    storeInterval_(1),
+    delay_(10)
+{}
+
+
+Foam::expressions::exprResultDelayed::exprResultDelayed
+(
+    const exprResultDelayed& rhs
+)
+:
+    exprResult(rhs),
+    name_(rhs.name_),
+    startExpr_(rhs.startExpr_),
+    settingResult_(rhs.settingResult_),
+    storedValues_(rhs.storedValues_),
+    storeInterval_(rhs.storeInterval_),
+    delay_(rhs.delay_)
+{}
+
+
+Foam::expressions::exprResultDelayed::exprResultDelayed
+(
+    const dictionary& dict
+)
+:
+    exprResult(dict.subOrEmptyDict("value")),
+    name_(dict.get<word>("name")),
+    startExpr_(dict.get<string>("startupValue"), dict),
+    storeInterval_(dict.get<scalar>("storeInterval")),
+    delay_(dict.get<scalar>("delay"))
+{
+    const entry *eptr = dict.findEntry("storedValues");
+
+    if (eptr)
+    {
+        storedValues_ = DLList<ValueAtTime>(eptr->stream());
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::expressions::exprResultDelayed::updateReadValue
+(
+    const scalar& timeVal
+)
+{
+    if (storedValues_.empty())
+    {
+        return false;
+    }
+
+    const ValueAtTime& first = storedValues_.first();
+
+    if (first.first() > (timeVal-delay_))
+    {
+        // No matching data yet
+        return false;
+    }
+
+    if (storedValues_.size() <= 1)
+    {
+        FatalErrorInFunction
+            << "Only one stored value at time " << timeVal
+            << " for delayedVariable " << name() << nl
+            << "Check the values for the interval " << storeInterval_
+            << " and delay " << delay_ << nl
+            << "Probably the interval is too large" << nl << endl
+            << exit(FatalError);
+    }
+
+    auto current = storedValues_.cbegin();
+    auto next = current;
+    ++next;
+
+    // The time without the delay offset
+    const scalar newTime = (timeVal - delay_);
+
+    while (next != storedValues_.end())
+    {
+        if (newTime >= current().first() && newTime <= next().first())
+        {
+            break;
+        }
+
+        current = next;
+        ++next;
+    }
+
+    const scalar f =
+    (
+        (newTime - current().first())
+      / (next().first() - current().first())
+    );
+
+    exprResult val((1-f)*current().second() + f*next().second());
+
+    setReadValue(val);
+
+    return true;
+}
+
+
+void Foam::expressions::exprResultDelayed::setReadValue
+(
+    const exprResult& val
+)
+{
+    exprResult::operator=(val);
+}
+
+
+void Foam::expressions::exprResultDelayed::storeValue
+(
+    const scalar& currTime
+)
+{
+    bool append = storedValues_.empty();
+
+    if (!append)
+    {
+        const scalar lastTime = storedValues_.last().first();
+
+        if (lastTime + SMALL >= currTime)
+        {
+            // Times are essentially identical - replace value
+        }
+        else if ((currTime - lastTime) >= 0.999*storeInterval_)
+        {
+            append = true;
+        }
+        else
+        {
+            // Cannot store in the middle - abandon the attempt
+            return;
+        }
+    }
+
+    if (append)
+    {
+        // Append value
+
+        const scalar oldLastTime =
+        (
+            storedValues_.empty()
+          ? 0
+          : storedValues_.last().first()
+        );
+
+        storedValues_.append(ValueAtTime(currTime, settingResult_));
+
+        while
+        (
+            storedValues_.size() > 1
+         && (oldLastTime - storedValues_.first().first()) >= delay_
+        )
+        {
+            // Remove values that are older than delay_
+            storedValues_.removeHead();
+        }
+    }
+    else
+    {
+        // Replace value
+
+        storedValues_.last().second() = settingResult_;
+    }
+}
+
+
+void Foam::expressions::exprResultDelayed::writeDict(Ostream& os) const
+{
+    os.beginBlock();
+
+    os.writeEntry("name", name_);
+
+    os.writeEntry("startupValue", startExpr_);
+
+    if (!settingResult_.valueType().empty())
+    {
+        os.writeEntry("settingResult", settingResult_);
+    }
+
+    os.writeEntry("storedValues", storedValues_);
+    os.writeEntry("storeInterval", storeInterval_);
+    os.writeEntry("delay", delay_);
+
+    os.writeKeyword("value");
+    os << static_cast<const exprResult&>(*this);
+
+    os.endBlock();
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+void Foam::expressions::exprResultDelayed::operator=
+(
+    const exprResultDelayed& rhs
+)
+{
+    if (this == &rhs)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    exprResult::operator=(rhs);
+
+    name_ = rhs.name_;
+    startExpr_ = rhs.startExpr_;
+    settingResult_ = rhs.settingResult_;
+    storedValues_ = rhs.storedValues_;
+    storeInterval_ = rhs.storeInterval_;
+    delay_ = rhs.delay_;
+}
+
+
+void Foam::expressions::exprResultDelayed::operator=
+(
+    const exprResult& rhs
+)
+{
+    settingResult_ = rhs;
+}
+
+
+void Foam::expressions::exprResultDelayed::operator=
+(
+    exprResult&& rhs
+)
+{
+    settingResult_ = std::move(rhs);
+}
+
+
+// * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
+
+Foam::Istream& Foam::operator>>
+(
+    Istream& is,
+    expressions::exprResultDelayed& data
+)
+{
+    dictionary dict(is);
+
+    data = expressions::exprResultDelayed(dict);
+
+    return is;
+}
+
+
+Foam::Ostream& Foam::operator<<
+(
+    Ostream& os,
+    const expressions::exprResultDelayed& data
+)
+{
+    data.writeDict(os);
+    return os;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResultDelayed.H b/src/OpenFOAM/expressions/exprResult/exprResultDelayed.H
new file mode 100644
index 0000000000000000000000000000000000000000..c969356e0d22d03974d8b5f687f1e7570aa18da1
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResultDelayed.H
@@ -0,0 +1,210 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::expressions::exprResultDelayed
+
+Description
+    An exprResult with an additional delay before evaluation
+
+    \heading Dictionary parameters
+    \table
+        Property    | Description                           | Required | Default
+        name        | The result name                       | yes |
+        delay       | The delay before starting             | yes |
+        storeInterval | The storage interval (time)         | yes |
+        startupValue | The initial startup value            | yes |
+        value        | The expression result (dictionary)   | no  |
+        storedValues | The list of stored values            | yes |
+    \endtable
+
+SourceFiles
+    exprResultDelayed.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef expressions_exprResultDelayed_H
+#define expressions_exprResultDelayed_H
+
+#include "exprResult.H"
+#include "exprString.H"
+#include "Tuple2.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class exprResultDelayed Declaration
+\*---------------------------------------------------------------------------*/
+
+class exprResultDelayed
+:
+    public expressions::exprResult
+{
+    // Typedefs
+
+        //- Expression at a given time value.
+        typedef Tuple2<scalar, expressions::exprResult> ValueAtTime;
+
+
+    // Private Data
+
+        //- The name of the expression
+        word name_;
+
+        //- The initial value expression
+        expressions::exprString startExpr_;
+
+        //- The pending result to be set
+        expressions::exprResult settingResult_;
+
+        //- The old results
+        DLList<ValueAtTime> storedValues_;
+
+        //- How often values should be stored
+        scalar storeInterval_;
+
+        //- The size of the delay
+        scalar delay_;
+
+
+protected:
+
+    // Protected Member Functions
+
+        //- Simulate virtual templated methods
+        inline expressions::exprResult& target() { return settingResult_; }
+
+
+public:
+
+    //- Runtime type information
+    TypeName("exprResultDelayed");
+
+
+    // Constructors
+
+        //- Construct null
+        exprResultDelayed();
+
+        //- Copy construct
+        exprResultDelayed(const exprResultDelayed&);
+
+        //- Construct from a dictionary
+        exprResultDelayed(const dictionary& dict);
+
+        //- Clone
+        virtual autoPtr<exprResult> clone() const
+        {
+            return autoPtr<exprResult>
+            (
+                new exprResultDelayed(*this)
+            );
+        }
+
+
+    //- Destructor
+    virtual ~exprResultDelayed() = default;
+
+
+    // Member Functions
+
+        //- The expression name
+        const word& name() const
+        {
+            return name_;
+        }
+
+        //- The initial value expression
+        const expressions::exprString& startupValueExpression() const
+        {
+            return startExpr_;
+        }
+
+        //- Update the read-value
+        //  return true if there was a valid value.
+        //  this does not do the work of setReadValue because we have no
+        //  access to the Parser
+        bool updateReadValue(const scalar& timeVal);
+
+        //- Set the readValue with a calculated value
+        void setReadValue(const exprResult& val);
+
+        //- Add a stored value
+        void storeValue(const scalar& timeVal);
+
+
+    // Write
+
+        void writeDict(Ostream& os) const;
+
+
+    // Member Operators
+
+        //- Copy assignment
+        void operator=(const exprResultDelayed& rhs);
+
+        //- Copy assignment
+        void operator=(const exprResult& rhs);
+
+        //- Move assignment
+        void operator=(exprResult&& rhs);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace expressions
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+inline bool operator!=
+(
+    const expressions::exprResultDelayed&,
+    const expressions::exprResultDelayed&
+)
+{
+    return false;
+}
+
+// IO Operators
+Istream& operator>>(Istream& is, expressions::exprResultDelayed& data);
+Ostream& operator<<(Ostream& os, const expressions::exprResultDelayed& data);
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResultGlobals.C b/src/OpenFOAM/expressions/exprResult/exprResultGlobals.C
new file mode 100644
index 0000000000000000000000000000000000000000..cd3d302fcba462515283c2b796032f84e27afb84
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResultGlobals.C
@@ -0,0 +1,334 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "exprResultGlobals.H"
+#include "Time.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+
+    defineTypeNameAndDebug(exprResultGlobals, 0);
+
+} // End namespace expressions
+} // End namespace Foam
+
+
+Foam::autoPtr<Foam::expressions::exprResultGlobals>
+    Foam::expressions::exprResultGlobals::singleton_;
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::expressions::exprResultGlobals::exprResultGlobals
+(
+    const objectRegistry& obr
+)
+:
+    regIOobject
+    (
+        IOobject
+        (
+            "exprResultGlobals",
+            obr.time().timeName(),
+            "expressions",
+            obr.time(),
+            IOobject::READ_IF_PRESENT,
+            IOobject::AUTO_WRITE
+        )
+    ),
+    timeIndex_(obr.time().timeIndex())
+{
+    if (headerOk())
+    {
+        readData
+        (
+            readStream("exprResultGlobals", true)
+        );
+    }
+}
+
+
+Foam::expressions::exprResultGlobals::Table::Table()
+:
+    HashPtrTable<exprResult>()
+{}
+
+
+Foam::expressions::exprResultGlobals::Table::Table(const Table& tbl)
+:
+    HashPtrTable<exprResult>(tbl.capacity())
+{
+    for (auto iter = tbl.cbegin(); iter != tbl.cend(); ++iter)
+    {
+        this->set(iter.key(), (*iter)->clone());
+    }
+}
+
+
+Foam::expressions::exprResultGlobals::Table::Table(Table&& tbl)
+:
+    HashPtrTable<exprResult>(std::move(tbl))
+{}
+
+
+Foam::expressions::exprResultGlobals::Table::Table(Istream& is)
+:
+    HashPtrTable<exprResult>(is)
+{}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::expressions::exprResultGlobals::reset()
+{
+    forAllIters(variables_, tablesIter)
+    {
+        forAllIters((*tablesIter), iter)
+        {
+            (*iter)->reset();
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::expressions::exprResultGlobals::writeData(Ostream& os) const
+{
+    // Enforce ASCII to avoid any potential binary issues
+    const auto oldFmt = os.format(IOstream::ASCII);
+
+    os << variables_;
+
+    os.format(oldFmt);
+
+    return os.good();
+}
+
+
+bool Foam::expressions::exprResultGlobals::readData(Istream& is)
+{
+    // Enforce ASCII to avoid any potential binary issues
+    const auto oldFmt = is.format(IOstream::ASCII);
+
+    is >> variables_;
+
+    is.format(oldFmt);
+
+    return !is.bad();
+}
+
+
+Foam::expressions::exprResultGlobals&
+Foam::expressions::exprResultGlobals::New
+(
+    const objectRegistry& obr
+)
+{
+    if (!singleton_)
+    {
+        singleton_.reset(new exprResultGlobals(obr));
+    }
+
+    if (singleton_->timeIndex_ != obr.time().timeIndex())
+    {
+        // Time changes, reset variables
+
+        singleton_->timeIndex_ = obr.time().timeIndex();
+        singleton_->reset();
+    }
+
+    return *singleton_;
+}
+
+
+Foam::expressions::exprResultGlobals::Table&
+Foam::expressions::exprResultGlobals::getNamespace(const word& name)
+{
+    return variables_[name];
+}
+
+
+const Foam::expressions::exprResult&
+Foam::expressions::exprResultGlobals::get
+(
+    const word& name,
+    const wordUList& scopes
+) const
+{
+    for (const word& scopeName : scopes)
+    {
+        const auto tableIter = variables_.find(scopeName);
+
+        if (tableIter.found())
+        {
+            const auto resultIter = (*tableIter).find(name);
+
+            if (resultIter.found())
+            {
+                return *(*resultIter);
+            }
+        }
+        #ifdef FULLDEBUG
+        else
+        {
+            WarningInFunction
+                << "No scope " << scopeName << " for " << name << nl
+                << "Known global scopes: " << variables_.sortToc() << nl;
+        }
+        #endif
+    }
+
+    return exprResult::null;
+}
+
+
+Foam::expressions::exprResult&
+Foam::expressions::exprResultGlobals::addValue
+(
+    const word& name,
+    const word& scope,
+    const exprResult& value,
+    const bool overwrite
+)
+{
+    Table& tbl = getOrCreateScope(scope);
+
+    auto iter = tbl.find(name);
+
+    if (!iter.found())
+    {
+        tbl.set(name, new exprResult(value));
+        iter = tbl.find(name);
+    }
+    else if (overwrite)
+    {
+        *(*iter) = value;
+    }
+
+    return *(*iter);
+}
+
+
+Foam::expressions::exprResult&
+Foam::expressions::exprResultGlobals::addValue
+(
+    const word& name,
+    const word& scope,
+    autoPtr<exprResult>& value,
+    const bool overwrite
+)
+{
+    Table& tbl = getOrCreateScope(scope);
+
+    if (overwrite || !tbl.found(name))
+    {
+        tbl.set(name, value);
+    }
+
+    return *tbl[name];
+}
+
+
+Foam::expressions::exprResult&
+Foam::expressions::exprResultGlobals::addValue
+(
+    const word& name,
+    const word& scope,
+    autoPtr<exprResult>&& value,
+    const bool overwrite
+)
+{
+    Table& tbl = getOrCreateScope(scope);
+
+    if (overwrite || !tbl.found(name))
+    {
+        tbl.set(name, value);
+    }
+
+    return *tbl[name];
+}
+
+
+Foam::expressions::exprResult&
+Foam::expressions::exprResultGlobals::addValue
+(
+    const dictionary& dict,
+    const word& scope,
+    const bool overwrite
+)
+{
+    word scopeName(scope);
+
+    const word name(dict.get<word>("globalName"));
+
+    if (scopeName.empty())
+    {
+        scopeName = dict.get<word>("globalScope");
+    }
+
+    if (dict.found("resultType"))
+    {
+        return addValue
+        (
+            name,
+            scopeName,
+            exprResult::New(dict),
+            overwrite
+        );
+    }
+    else
+    {
+        return addValue
+        (
+            name,
+            scopeName,
+            exprResult(dict, true),
+            overwrite
+        );
+    }
+}
+
+
+bool Foam::expressions::exprResultGlobals::removeValue
+(
+    const word& name,
+    const word& scope
+)
+{
+    auto iter = variables_.find(scope);
+
+    return (iter.found() && (*iter).erase(name));
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResultGlobals.H b/src/OpenFOAM/expressions/exprResult/exprResultGlobals.H
new file mode 100644
index 0000000000000000000000000000000000000000..764017b7a6acd5aa021ca25aef6f6a1c8f21d970
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResultGlobals.H
@@ -0,0 +1,202 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::expressions::exprResultGlobals
+
+Description
+    A globally available registry of expression results
+
+SourceFiles
+    exprResultGlobals.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef expressions_exprResultGlobals_H
+#define expressions_exprResultGlobals_H
+
+#include "exprResult.H"
+#include "autoPtr.H"
+#include "HashPtrTable.H"
+#include "regIOobject.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class exprResultGlobals Declaration
+\*---------------------------------------------------------------------------*/
+
+class exprResultGlobals
+:
+    public regIOobject
+{
+public:
+
+    // Public Classes
+
+        //- The table of results
+        class Table
+        :
+            public HashPtrTable<exprResult>
+        {
+        public:
+
+            Table();
+            Table(const Table& tbl);
+            Table(Table&& tbl);
+            Table(Istream& is);
+        };
+
+
+private:
+
+    // Private Data
+
+        //- The scoped table of results
+        HashTable<Table> variables_;
+
+        //- The currently (or previously) used time-index
+        label timeIndex_;
+
+        //- Only one instance of this repository
+        static autoPtr<exprResultGlobals> singleton_;
+
+
+    // Private Member Functions
+
+        //- Construct
+        explicit exprResultGlobals(const objectRegistry& obr);
+
+        //- Reset all variables
+        void reset();
+
+        //- Get or create a table for the scope
+        Table& getOrCreateScope(const word& scope)
+        {
+            return variables_(scope);
+        }
+
+
+public:
+
+    //- Runtime type information
+    TypeName("exprResultGlobals");
+
+
+    // Constructors
+
+        //- Get the singleton
+        static exprResultGlobals& New(const objectRegistry& obr);
+
+
+    //- Destructor
+    virtual ~exprResultGlobals() = default;
+
+
+    // Member Functions
+
+        //- Get an existing table for the namespace
+        Table& getNamespace(const word& name);
+
+
+        //- Return a global variable, if it exists, or a exprResult::null
+        const exprResult& get
+        (
+            const word& name,
+            const wordUList& scopes
+        ) const;
+
+        //- Add named result to specified scope
+        exprResult& addValue
+        (
+            const word& name,
+            const word& scope,
+            const exprResult& value,
+            const bool overwrite = true
+        );
+
+        //- Add named result to specified scope
+        exprResult& addValue
+        (
+            const word& name,
+            const word& scope,
+            autoPtr<exprResult>& value,
+            const bool overwrite = true
+        );
+
+        //- Add named result to specified scope
+        exprResult& addValue
+        (
+            const word& name,
+            const word& scope,
+            autoPtr<exprResult>&& value,
+            const bool overwrite = true
+        );
+
+        //- Extract result from dictionary and add to the scope
+        //
+        //  Controlled by dictionary entries:
+        //  - globalName (mandatory)
+        //  - globalScope (optional)
+        //  - resultType (optional)
+        exprResult& addValue
+        (
+            const dictionary& dict,
+            const word& scope = "",
+            const bool overwrite = true
+        );
+
+        //- Remove named result from specified scope
+        //  \return true if result was removed
+        bool removeValue
+        (
+            const word& name,
+            const word& scope
+        );
+
+        //- Write variables
+        virtual bool writeData(Ostream& os) const;
+
+        //- Read variables
+        virtual bool readData(Istream& os);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace expressions
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResultI.H b/src/OpenFOAM/expressions/exprResult/exprResultI.H
new file mode 100644
index 0000000000000000000000000000000000000000..2ff92efb8674308e1081f6691a23b18d6da157f0
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResultI.H
@@ -0,0 +1,790 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * Template Specializations  * * * * * * * * * * * * //
+
+namespace Foam
+{
+    #undef  defineExpressionMethod
+    #define defineExpressionMethod(Type, Var)                                 \
+        template<> inline const Type&                                         \
+        expressions::exprResult::singleValue::get<Type>() const               \
+        {                                                                     \
+            return Var;                                                       \
+        }                                                                     \
+                                                                              \
+        template<> inline const Type&                                         \
+        expressions::exprResult::singleValue::set(const Type& val)            \
+        {                                                                     \
+            Var = val;                                                        \
+            return Var;                                                       \
+        }
+
+    defineExpressionMethod(bool, bool_);
+    defineExpressionMethod(scalar, scalar_);
+    defineExpressionMethod(vector, vector_);
+    defineExpressionMethod(tensor, tensor_);
+    defineExpressionMethod(symmTensor, symmTensor_);
+    defineExpressionMethod(sphericalTensor, sphTensor_);
+
+    #undef defineExpressionMethod
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+template<class Type>
+inline bool Foam::expressions::exprResult::deleteChecked()
+{
+    const bool ok = isType<Type>();
+    if (ok && fieldPtr_ != nullptr)
+    {
+        delete static_cast<Field<Type>*>(fieldPtr_);
+        fieldPtr_ = nullptr;
+        size_ = 0;
+    }
+
+    return ok;
+}
+
+
+template<class Type>
+inline bool Foam::expressions::exprResult::createUniformChecked
+(
+    const word& key,
+    const dictionary& dict,
+    const label len
+)
+{
+    const bool ok = isType<Type>();
+    if (ok)
+    {
+        uglyDelete();
+
+        const Type val(dict.get<Type>(key));
+
+        size_ = len;
+        fieldPtr_ = new Field<Type>(size_, val);
+
+        single_.set(val);
+        isUniform_ = true;
+    }
+
+    return ok;
+}
+
+
+template<class Type>
+inline bool Foam::expressions::exprResult::createNonUniformChecked
+(
+    const word& key,
+    const dictionary& dict,
+    const label len
+)
+{
+    const bool ok = isType<Type>();
+    if (ok)
+    {
+        uglyDelete();
+
+        size_ = len;
+        fieldPtr_ = new Field<Type>(key, dict, size_);
+
+        isUniform_ = false;
+    }
+
+    return ok;
+}
+
+
+template<class Type>
+bool Foam::expressions::exprResult::getUniformChecked
+(
+    exprResult& result,
+    const label size,
+    const bool noWarn,
+    const bool parRun
+) const
+{
+    if (!isType<Type>())
+    {
+        return false;
+    }
+
+    result.clear();
+
+    const Field<Type>& fld = *static_cast<const Field<Type>*>(fieldPtr_);
+
+    const Type avg = (parRun ? gAverage(fld) : average(fld));
+
+    if (!noWarn)
+    {
+        const MinMax<Type> limits = (parRun ? gMinMax(fld) : minMax(fld));
+
+        if (limits.mag() > SMALL)
+        {
+            WarningInFunction
+                << "Different min/max values: " << limits
+                << " Using the average " << avg << nl;
+        }
+    }
+
+    result.setResult(avg, size);
+
+    return true;
+}
+
+
+template<class Type>
+bool Foam::expressions::exprResult::plusEqChecked
+(
+    const exprResult& b
+)
+{
+    const bool ok = isType<Type>();
+
+    if (ok)
+    {
+          *static_cast<Field<Type>*>(fieldPtr_)
+       += *static_cast<const Field<Type>*>(b.fieldPtr_);
+    }
+
+    return ok;
+}
+
+
+template<class Type>
+bool Foam::expressions::exprResult::multiplyEqChecked
+(
+    const scalar& b
+)
+{
+    const bool ok = isType<Type>();
+
+    if (ok)
+    {
+        *static_cast<Field<Type>*>(fieldPtr_) *= b;
+    }
+
+    return ok;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+template<class Type>
+Foam::expressions::exprResult::exprResult(const Field<Type>& f)
+:
+    exprResult()
+{
+    DebugInFunction << nl;
+
+    setResult(f);
+}
+
+
+template<class Type>
+Foam::expressions::exprResult::exprResult(Field<Type>&& f)
+:
+    exprResult()
+{
+    DebugInFunction << nl;
+
+    setResult(std::move(f));
+}
+
+
+template<class Type>
+Foam::expressions::exprResult::exprResult(autoPtr<Type>& o)
+:
+    exprResult()
+{
+    setObjectResult(o);
+}
+
+
+template<class Type>
+Foam::expressions::exprResult::exprResult(autoPtr<Type>&& o)
+:
+    exprResult()
+{
+    setObjectResult(o);
+}
+
+
+template<class Type>
+Foam::expressions::exprResult::exprResult(const dimensioned<Type>& f)
+:
+    exprResult()
+{
+    DebugInFunction << nl;
+    setSingleValue(f.value());
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+inline bool Foam::expressions::exprResult::hasValue() const
+{
+    return (!valType_.empty() && fieldPtr_ != nullptr);
+}
+
+
+inline const Foam::word& Foam::expressions::exprResult::valueType() const
+{
+    return valType_;
+}
+
+
+inline bool Foam::expressions::exprResult::isPointValue
+(
+    const bool isPointVal
+) const
+{
+    return isPointVal_ == isPointVal;
+}
+
+
+inline bool Foam::expressions::exprResult::isUniform() const
+{
+    return isUniform_;
+}
+
+
+template<class Type>
+inline bool Foam::expressions::exprResult::isType() const
+{
+    return valType_ == pTraits<Type>::typeName;
+}
+
+
+inline bool Foam::expressions::exprResult::isBool() const
+{
+    return valType_ == pTraits<bool>::typeName;
+}
+
+
+inline bool Foam::expressions::exprResult::isObject() const
+{
+    return objectPtr_.valid();
+}
+
+
+inline Foam::label Foam::expressions::exprResult::size() const
+{
+    return size_;
+}
+
+
+template<class Type>
+void Foam::expressions::exprResult::setResult
+(
+    const Field<Type>& val,
+    bool isPointVal
+)
+{
+    DebugInFunction << nl;
+
+    target().setResultImpl(val, isPointVal);
+}
+
+
+template<class Type>
+void Foam::expressions::exprResult::setResult
+(
+    Field<Type>&& val,
+    bool isPointVal
+)
+{
+    DebugInFunction << nl;
+
+    target().setResultImpl(val, isPointVal);
+}
+
+
+template<class Type>
+void Foam::expressions::exprResult::setResultImpl
+(
+    const Field<Type>& fld,
+    bool isPointVal
+)
+{
+    DebugInFunction << nl;
+
+    clear();
+
+    isUniform_ = false;
+    isPointVal_ = isPointVal;
+
+    size_ = fld.size();
+    valType_ = pTraits<Type>::typeName;
+    fieldPtr_ = new Field<Type>(fld);
+
+    DebugInFunction << nl;
+}
+
+
+template<class Type>
+void Foam::expressions::exprResult::setResultImpl
+(
+    Field<Type>&& fld,
+    bool isPointVal
+)
+{
+    DebugInFunction << nl;
+
+    clear();
+
+    isUniform_ = false;
+    isPointVal_ = isPointVal;
+
+    size_ = fld.size();
+    valType_ = pTraits<Type>::typeName;
+    fieldPtr_ = new Field<Type>(std::move(fld));
+
+    DebugInFunction << nl;
+}
+
+
+template<class Type>
+void Foam::expressions::exprResult::setObjectResult(autoPtr<Type>& ap)
+{
+    target().setObjectResultImpl(ap.ptr());
+}
+
+
+template<class Type>
+void Foam::expressions::exprResult::setObjectResult(autoPtr<Type>&& ap)
+{
+    target().setObjectResultImpl(ap.ptr());
+}
+
+
+template<class T>
+void Foam::expressions::exprResult::setObjectResultImpl(T* ptr)
+{
+    DebugInFunction << nl;
+
+    isUniform_ = false;
+    isPointVal_ = false;
+
+    size_ = ptr->size();
+    valType_ = ptr->typeName;
+    objectPtr_.reset(ptr);
+}
+
+
+template<class T>
+void Foam::expressions::exprResult::setObjectResultImpl(autoPtr<T>& o)
+{
+    setObjectResultImpl(o.ptr());
+}
+
+
+template<class T>
+void Foam::expressions::exprResult::setObjectResultImpl(autoPtr<T>&& o)
+{
+    setObjectResultImpl(o.ptr());
+}
+
+
+template<class Type>
+void Foam::expressions::exprResult::setResult
+(
+    Field<Type>* fldPtr,
+    bool isPointVal
+)
+{
+    target().setResultImpl(fldPtr, isPointVal);
+}
+
+
+template<class Type>
+void Foam::expressions::exprResult::setResultImpl
+(
+    Field<Type>* fldPtr,
+    bool isPointVal
+)
+{
+    DebugInFunction << nl;
+
+    clear();
+
+    isPointVal_ = isPointVal;
+    isUniform_ = false;
+
+    size_ = fldPtr->size();
+    valType_ = pTraits<Type>::typeName;
+    fieldPtr_ = fldPtr;
+}
+
+
+template<class Type>
+void Foam::expressions::exprResult::setResult
+(
+    const Type& val,
+    const label size
+)
+{
+    target().setResultImpl(val, size);
+}
+
+
+template<class Type>
+void Foam::expressions::exprResult::setResultImpl
+(
+    const Type& val,
+    const label len
+)
+{
+    DebugInFunction << nl;
+
+    clear();
+
+    isPointVal_ = false;
+
+    size_ = len;
+    valType_ = pTraits<Type>::typeName;
+    fieldPtr_ = new Field<Type>(size_, val);
+
+    isUniform_ = true;
+    single_.set(val);
+}
+
+
+template<class Type>
+void Foam::expressions::exprResult::setSingleValue(const Type& val)
+{
+    target().setSingleValueImpl(val);
+}
+
+
+template<class Type>
+bool Foam::expressions::exprResult::writeValueChecked(Ostream& os) const
+{
+    if (!isType<Type>())
+    {
+        return false;
+    }
+
+    if (this->size() <= 0)
+    {
+        if (isUniform_)
+        {
+            const Type& val = single_.get<Type>();
+            os.writeEntry("value", val);
+        }
+        else
+        {
+            // Zero-sized
+            const Field<Type> fld;
+            fld.writeEntry("value", os);
+        }
+    }
+    else
+    {
+        const Field<Type>& fld = *static_cast<const Field<Type>*>(fieldPtr_);
+
+        if (isUniform_)
+        {
+            os.writeEntry("value", fld.first());
+        }
+        else
+        {
+            fld.writeEntry("value", os);
+        }
+    }
+
+    return true;
+}
+
+
+template<class Type>
+bool Foam::expressions::exprResult::writeEntryChecked
+(
+    const word& keyword,
+    Ostream& os
+) const
+{
+    if (!isType<Type>())
+    {
+        return false;
+    }
+
+    if (this->size() <= 0)
+    {
+        if (isUniform_ && is_contiguous<Type>::value)
+        {
+            const Type& val = single_.get<Type>();
+
+            os  << "uniform " << val
+                << token::END_STATEMENT << nl;
+        }
+        else
+        {
+            // Zero-sized
+            const Field<Type> fld;
+            fld.writeEntry(keyword, os);
+        }
+    }
+    else
+    {
+        const Field<Type>& fld = *static_cast<const Field<Type>*>(fieldPtr_);
+
+        if (isUniform_ && is_contiguous<Type>::value)
+        {
+            os  << "uniform " << fld.first()
+                << token::END_STATEMENT << nl;
+        }
+        else
+        {
+            fld.writeEntry(keyword, os);
+        }
+    }
+
+    return true;
+}
+
+
+template<class Type>
+bool Foam::expressions::exprResult::setAverageValueChecked()
+{
+    if (!isType<Type>())
+    {
+        return false;
+    }
+
+    const Field<Type>& fld = *static_cast<const Field<Type>*>(fieldPtr_);
+
+    const MinMax<Type> limits = gMinMax(fld);
+
+    isUniform_ = (limits.mag() <= SMALL);
+
+    const Type avg = limits.centre();
+
+    single_.set(avg);
+
+    return true;
+}
+
+
+template<class Type>
+bool Foam::expressions::exprResult::duplicateFieldChecked(const void* ptr)
+{
+    if (!isType<Type>())
+    {
+        return false;
+    }
+
+    if (fieldPtr_)
+    {
+        deleteChecked<Type>();
+    }
+
+    const Field<Type>& fld = *static_cast<const Field<Type>*>(ptr);
+
+    size_ = fld.size();
+    fieldPtr_ = new Field<Type>(fld);
+
+    return true;
+}
+
+
+template<class Type>
+void Foam::expressions::exprResult::setSingleValueImpl(const Type& val)
+{
+    DebugInFunction << nl;
+
+    clear();
+
+    isPointVal_ = false;
+    isUniform_ = true;
+
+    single_.set(val);
+    size_ = 1;
+
+    valType_ = pTraits<Type>::typeName;
+    fieldPtr_ = new Field<Type>(size_, val);
+}
+
+
+template<class Type>
+inline Foam::tmp<Foam::Field<Type>>
+Foam::expressions::exprResult::getResult(bool cacheCopy)
+{
+    DebugInFunction << nl;
+
+    if (!isType<Type>())
+    {
+        FatalErrorInFunction
+            << "The expected return type " << pTraits<Type>::typeName
+            << " is different from the stored result type "
+            << valType_ << nl << nl
+            << exit(FatalError);
+    }
+
+    if (fieldPtr_ == nullptr)
+    {
+        FatalErrorInFunction
+            << "Cannot create tmp from nullptr." << nl
+            << "This error message should never appear!!" << nl
+            << exit(FatalError);
+    }
+
+    Field<Type>* ptr = static_cast<Field<Type>*>(fieldPtr_);
+
+    if (cacheCopy)
+    {
+        // Leave field intact, return a duplicate field
+        // Or return reference instead??
+        return tmp<Field<Type>>::New(*ptr);
+    }
+
+
+    tmp<Field<Type>> result(ptr);
+
+    fieldPtr_ = nullptr;  // Took ownership of field pointer
+    clear();
+
+    return result;
+}
+
+
+template<class Type>
+inline const Foam::Field<Type>&
+Foam::expressions::exprResult::cref() const
+{
+    DebugInFunction << nl;
+
+    if (!isType<Type>())
+    {
+        FatalErrorInFunction
+            << "The expected return type " << pTraits<Type>::typeName
+            << " is different from the stored result type "
+            << valType_ << nl << nl
+            << exit(FatalError);
+    }
+
+    if (fieldPtr_ == nullptr)
+    {
+        FatalErrorInFunction
+            << "Cannot return reference from nullptr." << nl
+            << "This error message should never appear!!" << nl
+            << exit(FatalError);
+    }
+
+    return *static_cast<const Field<Type>*>(fieldPtr_);
+}
+
+
+template<class Type>
+inline Foam::Field<Type>&
+Foam::expressions::exprResult::ref()
+{
+    return const_cast<Field<Type>&>(this->cref<Type>());
+}
+
+
+template<class Type>
+inline Foam::Field<Type>&
+Foam::expressions::exprResult::getRef() const
+{
+    return const_cast<Field<Type>&>(this->cref<Type>());
+}
+
+
+template<class Type>
+inline Foam::tmp<Type>
+Foam::expressions::exprResult::getObjectResult(bool cacheCopy)
+{
+    DebugInFunction << nl;
+
+    if (!isType<Type>())
+    {
+        FatalErrorInFunction
+            << "The expected return type " << pTraits<Type>::typeName
+            << " is different from the stored result type "
+            << valType_ << nl << nl
+            << exit(FatalError);
+    }
+
+    Type* ptr = dynamic_cast<Type*>(objectPtr_.get());
+
+    if (!ptr)
+    {
+        WarningInFunction
+            << "Cannot cast object pointer to " << pTraits<Type>::typeName
+            << nl << nl;
+
+        return nullptr;
+    }
+
+    if (cacheCopy)
+    {
+        // Return duplicated content
+        return tmp<Type>::New(*ptr);
+    }
+
+    objectPtr_.release();  // Take ownership in ptr
+
+    clear();
+
+    return tmp<Type>(ptr);
+}
+
+
+template<template<class> class BinaryOp, class Type>
+inline Type Foam::expressions::exprResult::getReduced
+(
+    const BinaryOp<Type>& bop,
+    const Type& initial
+)
+{
+    if (!isType<Type>())
+    {
+        FatalErrorInFunction
+            << "The expected return type " << pTraits<Type>::typeName
+            << " is different from the stored result type "
+            << valType_ << nl << nl
+            << exit(FatalError);
+    }
+
+    Type result = initial;
+
+    const Field<Type>& fld = *static_cast<Field<Type>*>(fieldPtr_);
+
+    for (const Type& val : fld)
+    {
+        result = bop(result, val);
+    }
+
+    return returnReduce(result, bop);
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResultStack.C b/src/OpenFOAM/expressions/exprResult/exprResultStack.C
new file mode 100644
index 0000000000000000000000000000000000000000..3431d27535769650884d2f84c65243ede6cffe61
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResultStack.C
@@ -0,0 +1,207 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "exprResultStack.H"
+#include "vector.H"
+#include "tensor.H"
+#include "symmTensor.H"
+#include "sphericalTensor.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+
+    defineTypeNameAndDebug(exprResultStack, 0);
+    addToRunTimeSelectionTable
+    (
+        exprResult,
+        exprResultStack,
+        dictionary
+    );
+    addToRunTimeSelectionTable
+    (
+        exprResult,
+        exprResultStack,
+        empty
+    );
+
+} // End namespace expressions
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::expressions::exprResultStack::exprResultStack()
+:
+    expressions::exprResult()
+{
+    needsReset(true);  // Requires reset every timestep to work
+}
+
+
+Foam::expressions::exprResultStack::exprResultStack
+(
+    const exprResultStack& rhs
+)
+:
+    expressions::exprResult(rhs)
+{
+    needsReset(true);  // Requires reset every timestep to work
+}
+
+
+Foam::expressions::exprResultStack::exprResultStack
+(
+    const dictionary &dict
+)
+:
+    expressions::exprResult(dict)
+{
+    needsReset(true);  // Requires reset every timestep to work
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::expressions::exprResult
+Foam::expressions::exprResultStack::pop()
+{
+    exprResult result;
+
+    if (this->size() <= 0)
+    {
+        FatalErrorInFunction
+            << "Trying to pop result from a empty queue" << endl
+            << abort(FatalError);
+
+        return result;
+    }
+
+    const bool ok =
+    (
+        popChecked<scalar>(result)
+     || popChecked<vector>(result)
+     || popChecked<tensor>(result)
+     || popChecked<symmTensor>(result)
+     || popChecked<sphericalTensor>(result)
+    );
+
+    if (!ok)
+    {
+        FatalErrorInFunction
+            << "Unsupported value type " << valueType() << nl
+            << abort(FatalError);
+    }
+
+    return result;
+}
+
+
+void Foam::expressions::exprResultStack::push(const exprResult& result)
+{
+    DebugInFunction << nl << "Pushing: " << result << nl;
+
+    if (!hasValue())
+    {
+        // This is the first push
+        exprResult::operator=(result);
+    }
+    else
+    {
+        if (valueType() != result.valueType())
+        {
+            FatalErrorInFunction
+                << "Type of pushed value " << result.valueType()
+                << " is not the expected type " << valueType() << nl
+                << abort(FatalError);
+        }
+
+        const bool ok =
+        (
+            pushChecked<scalar>(result)
+         || pushChecked<vector>(result)
+         || pushChecked<tensor>(result)
+         || pushChecked<symmTensor>(result)
+         || pushChecked<sphericalTensor>(result)
+        );
+
+        if (!ok)
+        {
+            FatalErrorInFunction
+                << "Unsupported value type " << valueType() << nl
+                << abort(FatalError);
+        }
+    }
+
+    DebugInFunction << "After push: " << *this << nl;
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+void Foam::expressions::exprResultStack::operator=
+(
+    const exprResultStack& rhs
+)
+{
+    if (this == &rhs)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    static_cast<exprResult&>(*this) = rhs;
+}
+
+
+void Foam::expressions::exprResultStack::operator=
+(
+    const exprResult& rhs
+)
+{
+    if (this == &rhs)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    DebugInFunction << nl;
+
+    exprResult exprValue
+    (
+        // Issue warning if the other result is not really uniform
+        rhs.getUniform(1, false)
+    );
+
+    this->push(exprValue);
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResultStack.H b/src/OpenFOAM/expressions/exprResult/exprResultStack.H
new file mode 100644
index 0000000000000000000000000000000000000000..6efdd0b1279e74a2d97e10ba4ffc0ab5deacb2a6
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResultStack.H
@@ -0,0 +1,140 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::expressions::exprResultStack
+
+Description
+    A stack of polymorphic fields.
+    Can be used to build a list of results one at a time.
+
+SourceFiles
+    exprResultStack.C
+    exprResultStackTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef expressions_exprResultStack_H
+#define expressions_exprResultStack_H
+
+#include "exprResult.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class exprResultStack Declaration
+\*---------------------------------------------------------------------------*/
+
+class exprResultStack
+:
+    public expressions::exprResult
+{
+    // Private Data
+
+        //- Type-checked pop value.
+        //  \return True if the type check was satisfied
+        template<class T>
+        bool popChecked(exprResult& result);
+
+        //- Type-checked push value.
+        //  \return True if the type check was satisfied
+        template<class T>
+        bool pushChecked(const exprResult& result);
+
+
+public:
+
+        //- Runtime type information
+        TypeName("exprResultStack");
+
+
+    // Constructors
+
+        //- Construct null
+        exprResultStack();
+
+        //- Copy construct
+        exprResultStack(const exprResultStack& rhs);
+
+        //- Construct from a dictionary
+        explicit exprResultStack(const dictionary& dict);
+
+
+    // Selectors
+
+        virtual autoPtr<exprResult> clone() const
+        {
+            return autoPtr<exprResult>
+            (
+                new exprResultStack(*this)
+            );
+        }
+
+
+    //- Destructor
+    virtual ~exprResultStack() = default;
+
+
+    // Member Functions
+
+        //- Pop the last value as an expression result
+        exprResult pop();
+
+        //- Push an expression result value
+        void push(const exprResult& result);
+
+
+    // Member Operators
+
+        //- Copy assignment
+        void operator=(const exprResultStack& rhs);
+
+        //- Copy assignment
+        void operator=(const exprResult& rhs);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace expressions
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "exprResultStackTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResultStackTemplates.C b/src/OpenFOAM/expressions/exprResult/exprResultStackTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..e85d66c9fefba901d35f9632ac59159600b779a1
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResultStackTemplates.C
@@ -0,0 +1,84 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+template<class T>
+bool Foam::expressions::exprResultStack::pushChecked
+(
+    const exprResult& result
+)
+{
+    if (!isType<T>())
+    {
+        return false;
+    }
+
+    // The value to push
+    T val(Zero);
+
+    const Field<T>& resultField = result.cref<T>();
+
+    if (!resultField.empty())
+    {
+        val = resultField.first();
+    }
+
+    this->ref<T>().append(val);
+
+    return true;
+}
+
+
+template<class T>
+bool Foam::expressions::exprResultStack::popChecked
+(
+    exprResult& result
+)
+{
+    if (!isType<T>())
+    {
+        return false;
+    }
+
+    // The popped value
+    T val(Zero);
+
+    Field<T>& oldField = this->ref<T>();
+
+    if (!oldField.empty())
+    {
+        val = oldField.last();
+        oldField.resize(oldField.size()-1);
+    }
+
+    result.setSingleValue(val);
+
+    return true;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResultStored.C b/src/OpenFOAM/expressions/exprResult/exprResultStored.C
new file mode 100644
index 0000000000000000000000000000000000000000..9530ea9026fe33e9190cfcb73bfee05fd47434c0
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResultStored.C
@@ -0,0 +1,165 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "exprResultStored.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+    defineTypeNameAndDebug(exprResultStored, 0);
+
+    addToRunTimeSelectionTable
+    (
+        exprResult,
+        exprResultStored,
+        dictionary
+    );
+    addToRunTimeSelectionTable
+    (
+        exprResult,
+        exprResultStored,
+        empty
+    );
+
+} // End namespace expressions
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::expressions::exprResultStored::exprResultStored()
+:
+    expressions::exprResult(),
+    name_("none"),
+    startExpr_()
+{}
+
+
+Foam::expressions::exprResultStored::exprResultStored
+(
+    const exprResultStored& rhs
+)
+:
+    expressions::exprResult(rhs),
+    name_(rhs.name_),
+    startExpr_(rhs.startExpr_)
+{}
+
+
+Foam::expressions::exprResultStored::exprResultStored
+(
+    const dictionary& dict
+)
+:
+    expressions::exprResult(dict.subOrEmptyDict("value")),
+    name_(dict.get<word>("name")),
+    startExpr_(dict.get<string>("initialValue"), dict)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::expressions::exprResultStored::writeDict(Ostream& os) const
+{
+    os.beginBlock();
+
+    os.writeEntry("name", name_);
+    os.writeEntry("initialValue", startExpr_);
+
+    os.writeKeyword("value");
+    os << static_cast<const exprResult&>(*this);
+
+    os.endBlock();
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+void Foam::expressions::exprResultStored::operator=
+(
+    const exprResultStored& rhs
+)
+{
+    if (this == &rhs)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    this->exprResult::operator=(rhs);
+
+    name_ = rhs.name_;
+    startExpr_ = rhs.startExpr_;
+}
+
+
+void Foam::expressions::exprResultStored::operator=
+(
+    const exprResult& rhs
+)
+{
+    if (this == &rhs)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    this->exprResult::operator=(rhs);
+}
+
+
+// * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
+
+Foam::Istream& Foam::operator>>
+(
+    Istream& is,
+    expressions::exprResultStored& data
+)
+{
+    dictionary dict(is);
+    data = expressions::exprResultStored(dict);
+
+    return is;
+}
+
+
+Foam::Ostream& Foam::operator<<
+(
+    Ostream& os,
+    const expressions::exprResultStored& data
+)
+{
+    data.writeDict(os);
+
+    return os;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResultStored.H b/src/OpenFOAM/expressions/exprResult/exprResultStored.H
new file mode 100644
index 0000000000000000000000000000000000000000..5d0a9a07d1e8a8eb1cf5f2f972a93f237c16ff9f
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResultStored.H
@@ -0,0 +1,174 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::expressions::exprResultStored
+
+Description
+    An exprResult with persistence.
+
+    \heading Dictionary parameters
+    \table
+        Property    | Description                           | Required | Default
+        name        | The result name                       | yes |
+        initialValue | The initial value                    | yes |
+        value        | The expression result (dictionary)   | no  |
+    \endtable
+
+SourceFiles
+    StoredExpressionResult.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef expressions_exprResultStored_H
+#define expressions_exprResultStored_H
+
+#include "exprResult.H"
+#include "exprString.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class exprResultStored Declaration
+\*---------------------------------------------------------------------------*/
+
+class exprResultStored
+:
+    public expressions::exprResult
+{
+    // Private Data
+
+        //- The name of the expression
+        word name_;
+
+        //- The initial value expression
+        expressions::exprString startExpr_;
+
+
+protected:
+
+    // Protected Member Functions
+
+        //- Reset at new timestep - disabling locally
+        virtual void resetImpl() {}
+
+
+public:
+
+    //- Runtime type information
+    TypeName("exprResultStored");
+
+
+    // Constructors
+
+        //- Construct null
+        exprResultStored();
+
+        //- Copy construct
+        exprResultStored(const exprResultStored& rhs);
+
+        //- Construct from a dictionary
+        explicit exprResultStored(const dictionary& dict);
+
+
+    // Selectors
+
+        virtual autoPtr<exprResult> clone() const
+        {
+            return autoPtr<exprResult>
+            (
+                new exprResultStored(*this)
+            );
+        }
+
+
+    //- Destructor
+    virtual ~exprResultStored() = default;
+
+
+    // Member Functions
+
+        //- The name of the expression
+        const word& name() const
+        {
+            return name_;
+        }
+
+        //- The initial value expression
+        const expressions::exprString& initialValueExpression() const
+        {
+            return startExpr_;
+        }
+
+
+        void writeDict(Ostream& os) const;
+
+
+    // Member Operators
+
+        //- Copy assignment
+        void operator=(const exprResultStored& rhs);
+
+        //- Copy assignment
+        void operator=(const exprResult& rhs);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace expressions
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// IO Operators
+Istream& operator>>(Istream& is, expressions::exprResultStored& data);
+Ostream& operator<<(Ostream& is, const expressions::exprResultStored& data);
+
+// Comparison
+inline bool operator!=
+(
+    const expressions::exprResultStored& a,
+    const expressions::exprResultStored& b
+)
+{
+    return (&a != &b);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResultStoredStack.C b/src/OpenFOAM/expressions/exprResult/exprResultStoredStack.C
new file mode 100644
index 0000000000000000000000000000000000000000..528b71ebdf3c106b0c2c3fa81b726becb3be40a8
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResultStoredStack.C
@@ -0,0 +1,106 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "exprResultStoredStack.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+
+    defineTypeNameAndDebug(exprResultStoredStack,0);
+
+    addToRunTimeSelectionTable
+    (
+        exprResult,
+        exprResultStoredStack,
+        dictionary
+    );
+    addToRunTimeSelectionTable
+    (
+        exprResult,
+        exprResultStoredStack,
+        empty
+    );
+
+} // End namespace expressions
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::expressions::exprResultStoredStack::exprResultStoredStack()
+:
+    expressions::exprResultStack()
+{
+    needsReset(false);  // Override parent: does not reset every timestep
+}
+
+
+Foam::expressions::exprResultStoredStack::exprResultStoredStack
+(
+    const exprResultStoredStack& rhs
+)
+:
+    expressions::exprResultStack(rhs)
+{
+    needsReset(false);  // Override parent: does not reset every timestep
+}
+
+
+Foam::expressions::exprResultStoredStack::exprResultStoredStack
+(
+    const dictionary& dict
+)
+:
+    expressions::exprResultStack(dict)
+{
+    needsReset(false);  // Override parent: does not reset every timestep
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+void Foam::expressions::exprResultStoredStack::operator=
+(
+    const exprResultStoredStack& rhs
+)
+{
+    if (this == &rhs)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    exprResultStack::operator=(rhs);
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/expressions/exprResult/exprResultStoredStack.H b/src/OpenFOAM/expressions/exprResult/exprResultStoredStack.H
new file mode 100644
index 0000000000000000000000000000000000000000..8475e49f8fe7fd1d229c7f53b4e79b28b9cceaa6
--- /dev/null
+++ b/src/OpenFOAM/expressions/exprResult/exprResultStoredStack.H
@@ -0,0 +1,115 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2012-2018 Bernhard Gschaider <bgschaid@hfd-research.com>
+    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 <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::expressions::exprResultStoredStack
+
+Description
+    An exprResultStack with persistence.
+
+SourceFiles
+    exprResultStoredStack.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef expressions_exprResultStoredStack_H
+#define expressions_exprResultStoredStack_H
+
+#include "exprResultStack.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace expressions
+{
+
+/*---------------------------------------------------------------------------*\
+                    Class exprResultStoredStack Declaration
+\*---------------------------------------------------------------------------*/
+
+class exprResultStoredStack
+:
+    public expressions::exprResultStack
+{
+protected:
+
+    // Protected Member Functions
+
+        //- Reset at new timestep - disabling locally
+        virtual void resetImpl() {}
+
+
+public:
+
+    //- Runtime type information
+    TypeName("exprResultStoredStack");
+
+
+    // Constructors
+
+        //- Construct null
+        exprResultStoredStack();
+
+        //- Copy construct
+        exprResultStoredStack(const exprResultStoredStack& rhs);
+
+        //- Construct from a dictionary
+        explicit exprResultStoredStack(const dictionary& dict);
+
+
+    // Selectors
+
+        virtual autoPtr<exprResult> clone() const
+        {
+            return autoPtr<exprResult>
+            (
+                new exprResultStoredStack(*this)
+            );
+        }
+
+
+    //- Destructor
+    virtual ~exprResultStoredStack() = default;
+
+
+    // Member Operators
+
+        //- Copy assignment
+        void operator=(const exprResultStoredStack& rhs);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace expressions
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //