diff --git a/src/OpenFOAM/fields/Fields/Field/FieldOps.C b/src/OpenFOAM/fields/Fields/Field/FieldOps.C
new file mode 100644
index 0000000000000000000000000000000000000000..0c9d997166cd29672d0ac03d2f9d002471c32038
--- /dev/null
+++ b/src/OpenFOAM/fields/Fields/Field/FieldOps.C
@@ -0,0 +1,157 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2019 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include <algorithm>
+
+// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
+
+template<class Tout, class T1, class UnaryOp>
+void Foam::FieldOps::assign
+(
+    Field<Tout>& result,
+    const Field<T1>& a,
+    const UnaryOp& op
+)
+{
+    #ifdef FULLDEBUG
+    if (result.size() != a.size())
+    {
+        FatalErrorInFunction
+            << "Field sizes do not match: " << result.size() << " ("
+            << a.size() << ')' << nl
+            << abort(FatalError);
+    }
+    #endif
+
+    std::transform(a.cbegin(), a.cend(), result.begin(), op);
+}
+
+
+template<class Tout, class T1, class T2, class BinaryOp>
+void Foam::FieldOps::assign
+(
+    Field<Tout>& result,
+    const Field<T1>& a,
+    const Field<T2>& b,
+    const BinaryOp& bop
+)
+{
+    #ifdef FULLDEBUG
+    if (result.size() != a.size() || result.size() != b.size())
+    {
+        FatalErrorInFunction
+            << "Field sizes do not match: " << result.size() << " ("
+            << a.size() << ' ' << b.size() << ')' << nl
+            << abort(FatalError);
+    }
+    #endif
+
+    std::transform(a.cbegin(), a.cend(), b.cbegin(), result.begin(), bop);
+}
+
+
+template<class T, class BinaryOp>
+void Foam::FieldOps::ternary
+(
+    Field<T>& result,
+    const Field<T>& a,
+    const Field<T>& b,
+    const BinaryOp& bop
+)
+{
+    #ifdef FULLDEBUG
+    if (result.size() != a.size() || result.size() != b.size())
+    {
+        FatalErrorInFunction
+            << "Field sizes do not match: " << result.size() << " ("
+            << a.size() << ' ' << b.size() << ')' << nl
+            << abort(FatalError);
+    }
+    #endif
+
+    forAll(result, i)
+    {
+        result[i] = bop(a[i], b[i]) ? a[i] : b[i];
+    }
+}
+
+
+template<class T, class BoolListType, class FlipOp>
+void Foam::FieldOps::ternarySelect
+(
+    Field<T>& result,
+    const BoolListType& cond,
+    const Field<T>& a,
+    const Field<T>& b,
+    const FlipOp& flip
+)
+{
+    #ifdef FULLDEBUG
+    if (result.size() != a.size() || result.size() != b.size())
+    {
+        FatalErrorInFunction
+            << "Field sizes do not match: " << result.size() << " ("
+            << a.size() << ' ' << b.size() << ')' << nl
+            << abort(FatalError);
+    }
+    #endif
+
+    forAll(result, i)
+    {
+        result[i] = flip(cond[i]) ? a[i] : b[i];
+    }
+}
+
+
+template<class T, class FlipOp>
+void Foam::FieldOps::ternarySelect
+(
+    Field<T>& result,
+    const bitSet& cond,
+    const Field<T>& a,
+    const Field<T>& b,
+    const FlipOp& flip
+)
+{
+    #ifdef FULLDEBUG
+    if (result.size() != a.size() || result.size() != b.size())
+    {
+        FatalErrorInFunction
+            << "Field sizes do not match: " << result.size() << " ("
+            << a.size() << ' ' << b.size() << ')' << nl
+            << abort(FatalError);
+    }
+    #endif
+
+    forAll(result, i)
+    {
+        result[i] = flip(cond[i]) ? a[i] : b[i];
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/fields/Fields/Field/FieldOps.H b/src/OpenFOAM/fields/Fields/Field/FieldOps.H
new file mode 100644
index 0000000000000000000000000000000000000000..47ebf2917f6b4201930ac7b595f09410d02e61d6
--- /dev/null
+++ b/src/OpenFOAM/fields/Fields/Field/FieldOps.H
@@ -0,0 +1,208 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2019 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Namespace
+    Foam::FieldOps
+
+Description
+    Various utility functions to work on Fields
+
+SourceFiles
+    FieldOps.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef FieldOps_H
+#define FieldOps_H
+
+#include "flipOp.H"
+#include "ListOps.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace FieldOps
+{
+
+/*---------------------------------------------------------------------------*\
+                        Namespace FieldOps Declarations
+\*---------------------------------------------------------------------------*/
+
+//- Populate a field as the result of a unary operation on an input.
+//  It is permissible for inputs/outputs to refer to the same field(s),
+//  but partially overlapping regions are ill-defined.
+//
+//  Examples,
+//  \code
+//    boolField result(sfield1.size());
+//
+//    FieldOps::assign(result, sfield1, lessOp1<scalar>(0.5));
+//    FieldOps::assign(result, lfield1, std::logical_not<bool>());
+//  \endcode
+//
+//  Example of using the Random::uniformGeneratorOp unary operator
+//  to populate a random field,
+//  \code
+//    FieldOps::assign
+//    (
+//        sfield,
+//        sfield,
+//        Random::uniformGeneratorOp<scalar>(-15, 25)
+//    );
+//  \endcode
+//
+//  \note wraps std::transform
+template<class Tout, class T1, class UnaryOp>
+void assign
+(
+    Field<Tout>& result,
+    const Field<T1>& a,
+    const UnaryOp& op
+);
+
+
+//- Populate a field as the result of a binary operation on two inputs.
+//  It is permissible for inputs/outputs to refer to the same field(s),
+//  but partially overlapping regions are ill-defined.
+//
+//  Examples,
+//  \code
+//    FieldOps::assign(result, sfield1, sfield2, std::less<scalar>());
+//    FieldOps::assign(result, lfield1, lfield2, std::logical_or<bool>());
+//  \endcode
+//
+//  \note wraps std::transform
+template<class Tout, class T1, class T2, class BinaryOp>
+void assign
+(
+    Field<Tout>& result,
+    const Field<T1>& a,
+    const Field<T2>& b,
+    const BinaryOp& bop
+);
+
+
+//- Emulate a ternary operation, selecting values from a or b
+//- depending on the binary predicate.
+//
+//  Examples,
+//  \code
+//    FieldOps::ternary(result, sfield1, sfield2, std::less<scalar>());
+//  \endcode
+template<class T, class BinaryOp>
+void ternary
+(
+    Field<T>& result,
+    const Field<T>& a,
+    const Field<T>& b,
+    const BinaryOp& bop
+);
+
+
+//- Emulate a ternary operation, selecting values from a or b
+//- depending on the conditional.
+//
+//  The meaning of the conditional is adjusted by the flip operation,
+//  which is typically Foam::noOp() or Foam::flipBoolOp()
+//
+//  Similar parameter requirements as Foam::subset()
+//
+//  Examples,
+//  \code
+//    FieldOps::ternarySelect(result, selector, sfield1, sfield2);
+//  \endcode
+template<class T, class BoolListType, class FlipOp>
+void ternarySelect
+(
+    Field<T>& result,
+    const BoolListType& cond,
+    const Field<T>& a,
+    const Field<T>& b,
+    const FlipOp& flip
+);
+
+
+//- Emulate a ternary operation, selecting values from a or b
+//- depending on the conditional.
+//
+//  The meaning of the conditional is adjusted by the flip operation,
+//  which is typically Foam::noOp() or Foam::flipBoolOp()
+template<class T, class FlipOp>
+void ternarySelect
+(
+    Field<T>& result,
+    const bitSet& cond,
+    const Field<T>& a,
+    const Field<T>& b,
+    const FlipOp& flip
+);
+
+
+//- Emulated ternary operation, without condition flipping
+template<class T, class BoolListType>
+void ternarySelect
+(
+    Field<T>& result,
+    const BoolListType& cond,
+    const Field<T>& a,
+    const Field<T>& b
+)
+{
+    ternarySelect(result, cond, a, b, noOp());
+}
+
+
+//- Emulated ternary operation, without condition flipping
+template<class T>
+void ternarySelect
+(
+    Field<T>& result,
+    const bitSet& cond,
+    const Field<T>& a,
+    const Field<T>& b
+)
+{
+    ternarySelect(result, cond, a, b, noOp());
+}
+
+
+} // End namespace FieldOps
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "FieldOps.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricFieldOps.H b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricFieldOps.H
new file mode 100644
index 0000000000000000000000000000000000000000..a7fc88765f7399ad9165f9abe333d1d2fe970446
--- /dev/null
+++ b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricFieldOps.H
@@ -0,0 +1,228 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2019 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+InNamespace
+    Foam::FieldOps
+
+Description
+    Various utility functions to work on geometric fields
+
+SourceFiles
+    GeometricFieldOps.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef GeometricFieldOps_H
+#define GeometricFieldOps_H
+
+#include "FieldOps.H"
+#include "GeometricField.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace FieldOps
+{
+
+/*---------------------------------------------------------------------------*\
+                        Namespace FieldOps Declarations
+\*---------------------------------------------------------------------------*/
+
+//- Populate a geometric field as the result of a unary operation on an input.
+//  It is permissible for inputs/outputs to refer to the same field(s),
+//  but partially overlapping regions are ill-defined.
+template
+<
+    class Tout, class T1, class UnaryOp,
+    template<class> class PatchField, class GeoMesh
+>
+void assign
+(
+    GeometricField<Tout, PatchField, GeoMesh>& result,
+    const GeometricField<T1, PatchField, GeoMesh>& a,
+    const UnaryOp& op
+)
+{
+    FieldOps::assign
+    (
+        result.primitiveFieldRef(),
+        a.primitiveField(),
+        op
+    );
+
+    auto& bfld = result.boundaryFieldRef();
+
+    const label len = bfld.size();
+
+    for (label i = 0; i < len; ++i)
+    {
+        FieldOps::assign
+        (
+            bfld[i],
+            a.boundaryField()[i],
+            op
+        );
+    }
+}
+
+
+//- Populate a geometric field from the binary operation on two inputs.
+//  It is permissible for inputs/outputs to refer to the same field(s),
+//  but partially overlapping regions are ill-defined.
+template
+<
+    class Tout, class T1, class T2, class BinaryOp,
+    template<class> class PatchField, class GeoMesh
+>
+void assign
+(
+    GeometricField<Tout, PatchField, GeoMesh>& result,
+    const GeometricField<T1, PatchField, GeoMesh>& a,
+    const GeometricField<T1, PatchField, GeoMesh>& b,
+    const BinaryOp& bop
+)
+{
+    FieldOps::assign
+    (
+        result.primitiveFieldRef(),
+        a.primitiveField(),
+        b.primitiveField(),
+        bop
+    );
+
+    auto& bfld = result.boundaryFieldRef();
+
+    const label len = bfld.size();
+
+    for (label i = 0; i < len; ++i)
+    {
+        FieldOps::assign
+        (
+            bfld[i],
+            a.boundaryField()[i],
+            b.boundaryField()[i],
+            bop
+        );
+    }
+}
+
+
+//- Emulate a ternary operation, selecting values from a or b
+//- depending on the binary predicate.
+template
+<
+    class T, class BinaryOp,
+    template<class> class PatchField, class GeoMesh
+>
+void ternary
+(
+    GeometricField<T, PatchField, GeoMesh>& result,
+    const GeometricField<T, PatchField, GeoMesh>& a,
+    const GeometricField<T, PatchField, GeoMesh>& b,
+    const BinaryOp& bop
+)
+{
+    FieldOps::ternary
+    (
+        result.primitiveFieldRef(),
+        a.primitiveField(),
+        b.primitiveField(),
+        bop
+    );
+
+    auto& bfld = result.boundaryFieldRef();
+
+    const label len = bfld.size();
+
+    for (label i = 0; i < len; ++i)
+    {
+        FieldOps::ternary
+        (
+            bfld[i],
+            a.boundaryField()[i],
+            b.boundaryField()[i],
+            bop
+        );
+    }
+}
+
+
+//- Emulate a ternary operation, selecting field values from a or b
+//- depending on the conditional.
+//
+//  Since boolean fields are not normally used, a flip operation is
+//  a general requirement.
+template
+<
+    class T, class BoolType, class FlipOp,
+    template<class> class PatchField, class GeoMesh
+>
+void ternarySelect
+(
+    GeometricField<T, PatchField, GeoMesh>& result,
+    const GeometricField<BoolType, PatchField, GeoMesh>& cond,
+    const GeometricField<T, PatchField, GeoMesh>& a,
+    const GeometricField<T, PatchField, GeoMesh>& b,
+    const FlipOp& flip
+)
+{
+    FieldOps::ternarySelect
+    (
+        result.primitiveFieldRef(),
+        cond.primitiveField(),
+        a.primitiveField(),
+        b.primitiveField(),
+        flip
+    );
+
+    auto& bfld = result.boundaryFieldRef();
+
+    const label len = bfld.size();
+
+    for (label i = 0; i < len; ++i)
+    {
+        FieldOps::ternarySelect
+        (
+            bfld[i],
+            cond.boundaryField()[i],
+            a.boundaryField()[i],
+            b.boundaryField()[i],
+            flip
+        );
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace FieldOps
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //