diff --git a/etc/controlDict b/etc/controlDict
index d4f03805bee70cee4eb241e39ee8bc4f87f27eb9..5d447ff1d775bc641ee722d2ea2defa2088fe387 100644
--- a/etc/controlDict
+++ b/etc/controlDict
@@ -590,7 +590,6 @@ DebugSwitches
     fvMotionSolver      0;
     fvPatchField        0;
     fvScalarMatrix      0;
-    fvSchemes           0;
     fvSphericalTensorMatrix 0;
     fvSymmTensorMatrix  0;
     fvTensorMatrix      0;
diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files
index e7b0357b089fc25cee085b2c7dc39f4c1f9c15f1..2bfb23509ab95ea807ad98a96cbf3b94ff22d91c 100644
--- a/src/OpenFOAM/Make/files
+++ b/src/OpenFOAM/Make/files
@@ -376,6 +376,8 @@ dimensionedTypes/dimensionedTensor/dimensionedTensor.C
 
 orientedType/orientedType.C
 
+matrices/schemes/schemesLookup.C
+matrices/schemes/schemesLookupDetail.C
 matrices/solution/solution.C
 
 scalarMatrices = matrices/scalarMatrices
diff --git a/src/OpenFOAM/matrices/schemes/schemesLookup.C b/src/OpenFOAM/matrices/schemes/schemesLookup.C
new file mode 100644
index 0000000000000000000000000000000000000000..9bdfbe8b819360a3e7ba187a302d4c4bb83c4eba
--- /dev/null
+++ b/src/OpenFOAM/matrices/schemes/schemesLookup.C
@@ -0,0 +1,273 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2011-2015 OpenFOAM Foundation
+    Copyright (C) 2019-2021 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 "schemesLookup.H"
+#include "Switch.H"
+#include "Time.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+int Foam::schemesLookup::debug(Foam::debug::debugSwitch("schemesLookup", 0));
+
+
+// * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
+
+void Foam::schemesLookup::clear()
+{
+    ddtSchemes_.clear();
+    d2dt2Schemes_.clear();
+    interpSchemes_.clear();
+    divSchemes_.clear();        // optional
+    gradSchemes_.clear();       // optional
+    lnGradSchemes_.clear();
+    snGradSchemes_.clear();
+    laplacianSchemes_.clear();  // optional
+
+    // Do not clear fluxRequired settings
+}
+
+
+void Foam::schemesLookup::checkSteady()
+{
+    ITstream& is = ddtSchemes_.fallback();
+
+    word schemeName;
+    if (is.peek().isWord())
+    {
+        is >> schemeName;
+    }
+
+    steady_ =
+    (
+        schemeName == "steady"
+     || schemeName == "steadyState"
+    );
+}
+
+
+void Foam::schemesLookup::read(const dictionary& dict)
+{
+    ddtSchemes_.populate(dict, "none");
+    d2dt2Schemes_.populate(dict, "none");
+    interpSchemes_.populate(dict, "linear");
+    divSchemes_.populate(dict, "", true);           // Mandatory entry
+    gradSchemes_.populate(dict, "", true);          // Mandatory entry
+    lnGradSchemes_.populate(dict, "corrected");     // (finiteArea)
+    snGradSchemes_.populate(dict, "corrected");     // (finiteVolume)
+    laplacianSchemes_.populate(dict, "", true);     // Mandatory entry
+
+    const dictionary* fluxDictPtr = dict.findDict("fluxRequired");
+    if (fluxDictPtr)
+    {
+        fluxRequired_.merge(*fluxDictPtr);
+
+        if (fluxRequired_.found("default"))
+        {
+            Switch sw(fluxRequired_.lookup("default").peek());
+
+            if (sw.good() && sw.type() != Switch::NONE)
+            {
+                fluxRequiredDefault_ = bool(sw);
+            }
+        }
+    }
+
+    checkSteady();
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::schemesLookup::schemesLookup
+(
+    const objectRegistry& obr,
+    const word& dictName,
+    const dictionary* fallback
+)
+:
+    IOdictionary
+    (
+        IOobject
+        (
+            dictName,
+            obr.time().system(),
+            obr,
+            (
+                obr.readOpt() == IOobject::MUST_READ
+             || obr.readOpt() == IOobject::READ_IF_PRESENT
+              ? IOobject::MUST_READ_IF_MODIFIED
+              : obr.readOpt()
+            ),
+            IOobject::NO_WRITE
+        ),
+        fallback
+    ),
+
+    // Named, but empty dictionaries and default schemes
+
+    ddtSchemes_("ddtSchemes", objectPath()),
+    d2dt2Schemes_("d2dt2Schemes", objectPath()),
+    interpSchemes_("interpolationSchemes", objectPath()),
+    divSchemes_("divSchemes", objectPath()),
+    gradSchemes_("gradSchemes", objectPath()),
+    lnGradSchemes_("lnGradSchemes", objectPath()),
+    snGradSchemes_("snGradSchemes", objectPath()),
+    laplacianSchemes_("laplacianSchemes", objectPath()),
+
+    fluxRequired_(objectPath() + ".fluxRequired"),
+    fluxRequiredDefault_(false),
+    steady_(false)
+{
+    if
+    (
+        readOpt() == IOobject::MUST_READ
+     || readOpt() == IOobject::MUST_READ_IF_MODIFIED
+     || (readOpt() == IOobject::READ_IF_PRESENT && headerOk())
+    )
+    {
+        read(schemesDict());
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::schemesLookup::read()
+{
+    if (regIOobject::read())
+    {
+        clear();  // Clear current settings except fluxRequired
+
+        read(schemesDict());
+
+        return true;
+    }
+
+    return false;
+}
+
+
+const Foam::dictionary& Foam::schemesLookup::schemesDict() const
+{
+    if (found("select"))
+    {
+        return subDict(word(lookup("select")));
+    }
+    return *this;
+}
+
+
+Foam::ITstream& Foam::schemesLookup::ddtScheme(const word& name) const
+{
+    DebugInfo<< "Lookup ddtScheme for " << name << endl;
+    return ddtSchemes_.lookup(name);
+}
+
+
+Foam::ITstream& Foam::schemesLookup::d2dt2Scheme(const word& name) const
+{
+    DebugInfo<< "Lookup d2dt2Scheme for " << name << endl;
+    return d2dt2Schemes_.lookup(name);
+}
+
+
+Foam::ITstream& Foam::schemesLookup::interpolationScheme(const word& name) const
+{
+    DebugInfo<< "Lookup interpolationScheme for " << name << endl;
+    return interpSchemes_.lookup(name);
+}
+
+
+Foam::ITstream& Foam::schemesLookup::divScheme(const word& name) const
+{
+    DebugInfo<< "Lookup divScheme for " << name << endl;
+    return divSchemes_.lookup(name);
+}
+
+
+Foam::ITstream& Foam::schemesLookup::gradScheme(const word& name) const
+{
+    DebugInfo<< "Lookup gradScheme for " << name << endl;
+    return gradSchemes_.lookup(name);
+}
+
+
+Foam::ITstream& Foam::schemesLookup::lnGradScheme(const word& name) const
+{
+    DebugInfo<< "Lookup lnGradScheme for " << name << endl;
+    return lnGradSchemes_.lookup(name);
+}
+
+
+Foam::ITstream& Foam::schemesLookup::snGradScheme(const word& name) const
+{
+    DebugInfo<< "Lookup snGradScheme for " << name << endl;
+    return snGradSchemes_.lookup(name);
+}
+
+
+Foam::ITstream& Foam::schemesLookup::laplacianScheme(const word& name) const
+{
+    DebugInfo<< "Lookup laplacianScheme for " << name << endl;
+    return laplacianSchemes_.lookup(name);
+}
+
+
+void Foam::schemesLookup::setFluxRequired(const word& name) const
+{
+    DebugInfo<< "Setting fluxRequired for " << name << endl;
+    fluxRequired_.add(name, true, true);
+}
+
+
+bool Foam::schemesLookup::fluxRequired(const word& name) const
+{
+    DebugInfo<< "Lookup fluxRequired for " << name << endl;
+    return (fluxRequired_.found(name) || fluxRequiredDefault_);
+}
+
+
+void Foam::schemesLookup::writeDicts(Ostream& os) const
+{
+    ddtSchemes_.writeEntryOptional(os);
+    d2dt2Schemes_.writeEntryOptional(os);
+    interpSchemes_.writeEntryOptional(os);
+    divSchemes_.writeEntry(os);  // Mandatory entry
+    gradSchemes_.writeEntry(os); // Mandatory entry
+    lnGradSchemes_.writeEntryOptional(os);  // (finiteArea)
+    snGradSchemes_.writeEntryOptional(os);  // (finiteVolume)
+    laplacianSchemes_.writeEntry(os); // Mandatory entry
+
+    if (!fluxRequired_.empty())
+    {
+        fluxRequired_.writeEntry(os);
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/matrices/schemes/schemesLookup.H b/src/OpenFOAM/matrices/schemes/schemesLookup.H
new file mode 100644
index 0000000000000000000000000000000000000000..347d8d693b41a92f0ca0f7f55803e74d312dfce0
--- /dev/null
+++ b/src/OpenFOAM/matrices/schemes/schemesLookup.H
@@ -0,0 +1,361 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2011-2015 OpenFOAM Foundation
+    Copyright (C) 2020-2021 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::schemesLookup
+
+Description
+    Selector class for finite area/finite volume differencing schemes.
+
+SourceFiles
+    schemesLookup.C
+    schemesLookupDetail.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef schemesLookup_H
+#define schemesLookup_H
+
+#include "IOdictionary.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class schemesLookup Declaration
+\*---------------------------------------------------------------------------*/
+
+class schemesLookup
+:
+    public IOdictionary
+{
+    // Private Class
+
+        //- Lightweight grouping of scheme dictionary and default
+        struct lookupDetail
+        {
+            word name_;
+            dictionary dict_;
+            ITstream default_;
+
+
+        // Constructors
+
+            //- Construct empty with given sub-dictionary name
+            lookupDetail
+            (
+                const word& dictName,
+                const fileName& parentDictPath
+            );
+
+
+        // Member Functions
+
+            //- Clear dictionary and default scheme
+            void clear();
+
+            //- Return the default scheme (if any)
+            ITstream& fallback() const;
+
+            //- Lookup named scheme from dictionary, or return default
+            ITstream& lookup(const word& name) const;
+
+            //- Populate dictionary and/or default
+            void populate
+            (
+                const dictionary& dict,
+                const word& defaultName,
+                const bool mandatory = false
+            );
+
+            //- Write dictionary entry
+            void writeEntry(Ostream& os) const;
+
+            //- Write dictionary entry if non-empty
+            void writeEntryOptional(Ostream& os) const;
+        };
+
+
+    // Private Data
+
+        //- ddt
+        lookupDetail ddtSchemes_;
+
+        //- d2dt2
+        lookupDetail d2dt2Schemes_;
+
+        //- interpolation
+        lookupDetail interpSchemes_;
+
+        //- div
+        lookupDetail divSchemes_;
+
+        //- grad
+        lookupDetail gradSchemes_;
+
+        //- lnGrad (finiteArea)
+        lookupDetail lnGradSchemes_;
+
+        //- snGrad (finiteVolume)
+        lookupDetail snGradSchemes_;
+
+        //- laplacian
+        lookupDetail laplacianSchemes_;
+
+        //- flux
+        mutable dictionary fluxRequired_;
+        bool fluxRequiredDefault_;
+
+        //- True if default ddtScheme is steady-state
+        bool steady_;
+
+
+    // Private Member Functions
+
+        //- Clear dictionaries and streams before reading
+        void clear();
+
+        //- Check if default ddtScheme is steady-state
+        void checkSteady();
+
+        //- Read settings from the dictionary
+        void read(const dictionary& dict);
+
+        //- No copy construct
+        schemesLookup(const schemesLookup&) = delete;
+
+        //- No copy assignment
+        void operator=(const schemesLookup&) = delete;
+
+
+public:
+
+    //- Debug switch
+    static int debug;
+
+
+    // Constructors
+
+        //- Construct for objectRegistry, system dictName, and optional
+        //- fallback dictionary content (for a NO_READ or missing file)
+        //  A null dictionary pointer is treated like an empty dictionary.
+        schemesLookup
+        (
+            const objectRegistry& obr,
+            const word& dictName,
+            const dictionary* fallback = nullptr
+        );
+
+
+    // Member Functions
+
+        //- The current schemes dictionary, respects the "select" keyword
+        const dictionary& schemesDict() const;
+
+        //- True if default ddtScheme is steady-state
+        bool steady() const noexcept
+        {
+            return steady_;
+        }
+
+        //- True if default ddtScheme is not steady-state
+        bool transient() const noexcept
+        {
+            return !steady_;
+        }
+
+
+    // Lookup Access
+
+        //- Get ddt scheme for given name, or default
+        ITstream& ddtScheme(const word& name) const;
+
+        //- Get d2dt2 scheme for given name, or default
+        ITstream& d2dt2Scheme(const word& name) const;
+
+        //- Get interpolation scheme for given name, or default
+        ITstream& interpolationScheme(const word& name) const;
+
+        //- Get div scheme for given name, or default
+        ITstream& divScheme(const word& name) const;
+
+        //- Get grad scheme for given name, or default
+        ITstream& gradScheme(const word& name) const;
+
+        //- Get (finiteArea) lnGrad scheme for given name, or default
+        ITstream& lnGradScheme(const word& name) const;
+
+        //- Get (finiteVolume) snGrad scheme for given name, or default
+        ITstream& snGradScheme(const word& name) const;
+
+        //- Get laplacian scheme for given name, or default
+        ITstream& laplacianScheme(const word& name) const;
+
+        //- Get flux-required for given name, or default
+        void setFluxRequired(const word& name) const;
+
+        //- Set flux-required for given name (mutable)
+        bool fluxRequired(const word& name) const;
+
+
+    // Read Access
+
+        //- Access ddt schemes dictionary
+        const dictionary& ddtSchemes() const noexcept
+        {
+            return ddtSchemes_.dict_;
+        }
+
+        //- Access d2dt2 schemes dictionary
+        const dictionary& d2dt2Schemes() const noexcept
+        {
+            return d2dt2Schemes_.dict_;
+        }
+
+        //- Access interpolation schemes dictionary
+        const dictionary& interpolationSchemes() const noexcept
+        {
+            return interpSchemes_.dict_;
+        }
+
+        //- Access div schemes dictionary
+        const dictionary& divSchemes() const noexcept
+        {
+            return divSchemes_.dict_;
+        }
+
+        //- Access grad schemes dictionary
+        const dictionary& gradSchemes() const noexcept
+        {
+            return gradSchemes_.dict_;
+        }
+
+        //- Access lnGrad schemes dictionary (finiteArea)
+        const dictionary& lnGradSchemes() const noexcept
+        {
+            return lnGradSchemes_.dict_;
+        }
+
+        //- Access snGrad schemes dictionary (finiteVolume)
+        const dictionary& snGradSchemes() const noexcept
+        {
+            return snGradSchemes_.dict_;
+        }
+
+        //- Access laplacian schemes dictionary
+        const dictionary& laplacianSchemes() const noexcept
+        {
+            return laplacianSchemes_.dict_;
+        }
+
+        //- Access to flux required dictionary
+        const dictionary& fluxRequired() const noexcept
+        {
+            return fluxRequired_;
+        }
+
+
+    // Edit Access
+
+        //- Access ddt schemes dictionary
+        dictionary& ddtSchemes() noexcept
+        {
+            return ddtSchemes_.dict_;
+        }
+
+        //- Access d2dt2 schemes dictionary
+        dictionary& d2dt2Schemes() noexcept
+        {
+            return d2dt2Schemes_.dict_;
+        }
+
+        //- Access interpolation schemes dictionary
+        dictionary& interpolationSchemes() noexcept
+        {
+            return interpSchemes_.dict_;
+        }
+
+        //- Access div schemes dictionary
+        dictionary& divSchemes() noexcept
+        {
+            return divSchemes_.dict_;
+        }
+
+        //- Access grad schemes dictionary
+        dictionary& gradSchemes() noexcept
+        {
+            return gradSchemes_.dict_;
+        }
+
+        //- Access lnGrad schemes dictionary (finiteArea)
+        dictionary& lnGradSchemes() noexcept
+        {
+            return lnGradSchemes_.dict_;
+        }
+
+        //- Access snGrad schemes dictionary (finiteVolume)
+        dictionary& snGradSchemes() noexcept
+        {
+            return snGradSchemes_.dict_;
+        }
+
+        //- Access laplacian schemes dictionary
+        dictionary& laplacianSchemes() noexcept
+        {
+            return laplacianSchemes_.dict_;
+        }
+
+        //- Access to flux required dictionary
+        dictionary& fluxRequired() noexcept
+        {
+            return fluxRequired_;
+        }
+
+
+    // Read
+
+        //- Read schemes from IOdictionary, respects the "select" keyword
+        bool read();
+
+
+    // Write
+
+        //- Write dictionary (possibly modified) settings
+        void writeDicts(Ostream& os) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/matrices/schemes/schemesLookupDetail.C b/src/OpenFOAM/matrices/schemes/schemesLookupDetail.C
new file mode 100644
index 0000000000000000000000000000000000000000..1358ec64022467d0cf511a8ff128d06cbc0961f6
--- /dev/null
+++ b/src/OpenFOAM/matrices/schemes/schemesLookupDetail.C
@@ -0,0 +1,142 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2021 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 "schemesLookup.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::schemesLookup::lookupDetail::lookupDetail
+(
+    const word& dictName,
+    const fileName& parentDictPath
+)
+:
+    name_(dictName),
+    dict_(),
+    default_()
+{
+    if (parentDictPath.empty())
+    {
+        dict_.name() = name_;
+    }
+    else if (name_.empty())
+    {
+        dict_.name() = parentDictPath;
+        name_ = dict_.dictName();
+    }
+    else
+    {
+        dict_.name() = parentDictPath + "." + name_;
+    }
+    default_.name() = dict_.name() + ".default";
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::schemesLookup::lookupDetail::clear()
+{
+    dict_.clear();
+    default_.clear();
+}
+
+
+Foam::ITstream& Foam::schemesLookup::lookupDetail::fallback() const
+{
+    ITstream& is = const_cast<ITstream&>(default_);
+    is.rewind();
+    return is;
+}
+
+
+Foam::ITstream& Foam::schemesLookup::lookupDetail::lookup
+(
+    const word& name
+) const
+{
+    if (dict_.found(name) || default_.empty())
+    {
+        // Fails when 'name' is not found and no default is available,
+        // which provides some traceback error messages
+        return dict_.lookup(name);
+    }
+
+    return fallback();
+}
+
+
+void Foam::schemesLookup::lookupDetail::populate
+(
+    const dictionary& dict,
+    const word& defaultName,
+    const bool mandatory
+)
+{
+    if (mandatory || dict.found(name_))
+    {
+        // Fails when 'name' is not found but it is mandatory,
+        // which provides some traceback error messages
+        dict_ = dict.subDict(name_);
+    }
+    else if (!defaultName.empty() && !dict_.found("default"))
+    {
+        dict_.add("default", defaultName);
+    }
+
+    // Clear or set the default stream
+    if
+    (
+        !dict_.found("default")
+     || dict_.lookup("default").peek() == "none"
+    )
+    {
+        default_.clear();
+        default_.rewind();
+    }
+    else
+    {
+        default_ = dict_.lookup("default");
+    }
+}
+
+
+void Foam::schemesLookup::lookupDetail::writeEntry(Ostream& os) const
+{
+    dict_.writeEntry(os);
+}
+
+
+void Foam::schemesLookup::lookupDetail::writeEntryOptional(Ostream& os) const
+{
+    if (!dict_.empty())
+    {
+        dict_.writeEntry(os);
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/matrices/solution/solution.C b/src/OpenFOAM/matrices/solution/solution.C
index 25c61427f7af32771e968c33010f558b61b64cb2..63389c2aa8e11ccd6d2d08774e870764bcf61e23 100644
--- a/src/OpenFOAM/matrices/solution/solution.C
+++ b/src/OpenFOAM/matrices/solution/solution.C
@@ -157,17 +157,6 @@ Foam::solution::solution
 }
 
 
-Foam::solution::solution
-(
-    const objectRegistry& obr,
-    const fileName& dictName,
-    const dictionary& dict
-)
-:
-    solution(obr, dictName, &dict)
-{}
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 Foam::label Foam::solution::upgradeSolverDict
@@ -237,9 +226,7 @@ bool Foam::solution::cache(const word& name) const
 {
     if (caching_)
     {
-        DebugInfo
-            << "Cache: find entry for " << name << endl;
-
+        DebugInfo<< "Cache: find entry for " << name << endl;
         return cache_.found(name);
     }
 
@@ -259,17 +246,14 @@ bool Foam::solution::relaxField(const word& name) const
 
 bool Foam::solution::relaxEquation(const word& name) const
 {
-    DebugInfo
-        << "Find equation relaxation factor for " << name << endl;
-
+    DebugInfo<< "Find equation relaxation factor for " << name << endl;
     return eqnRelaxDict_.found(name) || eqnRelaxDict_.found("default");
 }
 
 
 Foam::scalar Foam::solution::fieldRelaxationFactor(const word& name) const
 {
-    DebugInfo
-        << "Lookup variable relaxation factor for " << name << endl;
+    DebugInfo<< "Lookup variable relaxation factor for " << name << endl;
 
     if (fieldRelaxDict_.found(name))
     {
@@ -291,8 +275,7 @@ Foam::scalar Foam::solution::fieldRelaxationFactor(const word& name) const
 
 Foam::scalar Foam::solution::equationRelaxationFactor(const word& name) const
 {
-    DebugInfo
-        << "Lookup equation relaxation factor for " << name << endl;
+    DebugInfo<< "Lookup equation relaxation factor for " << name << endl;
 
     if (eqnRelaxDict_.found(name))
     {
@@ -325,18 +308,14 @@ const Foam::dictionary& Foam::solution::solutionDict() const
 
 const Foam::dictionary& Foam::solution::solverDict(const word& name) const
 {
-    DebugInfo
-        << "Lookup solver for " << name << endl;
-
+    DebugInfo<< "Lookup solver for " << name << endl;
     return solvers_.subDict(name);
 }
 
 
 const Foam::dictionary& Foam::solution::solver(const word& name) const
 {
-    DebugInfo
-        << "Lookup solver for " << name << endl;
-
+    DebugInfo<< "Lookup solver for " << name << endl;
     return solvers_.subDict(name);
 }
 
diff --git a/src/OpenFOAM/matrices/solution/solution.H b/src/OpenFOAM/matrices/solution/solution.H
index 2ae631a9f4524d58879b145cf902c237cc51ccd8..d9ae37e35393a7d07d46ac7ee7e0377400f7eb14 100644
--- a/src/OpenFOAM/matrices/solution/solution.H
+++ b/src/OpenFOAM/matrices/solution/solution.H
@@ -119,7 +119,10 @@ public:
             const objectRegistry& obr,
             const fileName& dictName,
             const dictionary& dict
-        );
+        )
+        :
+            solution(obr, dictName, &dict)
+        {}
 
 
     // Member Functions
diff --git a/src/finiteArea/Make/files b/src/finiteArea/Make/files
index a61dab59417d2d266df98a37ba0a533079b2bcb5..e21879123296469a793dc1f06c1320c4b4164fcb 100644
--- a/src/finiteArea/Make/files
+++ b/src/finiteArea/Make/files
@@ -85,7 +85,6 @@ $(schemes)/blended/blendedEdgeInterpolationMake.C
 $(schemes)/skewCorrected/skewCorrectedEdgeInterpolationMake.C
 
 finiteArea/fa/fa.C
-finiteArea/faSchemes/faSchemes.C
 
 ddtSchemes = finiteArea/ddtSchemes
 $(ddtSchemes)/faDdtScheme/faDdtSchemes.C
diff --git a/src/finiteArea/faSolution/faSolution.H b/src/finiteArea/faSolution/faSolution.H
index de176a7bd7cc0884cfadb24db223eddb0a14614f..e8f62e728dbf0b161e94062d62e19f50e41d8ba5 100644
--- a/src/finiteArea/faSolution/faSolution.H
+++ b/src/finiteArea/faSolution/faSolution.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2016-2017 Wikki Ltd
+    Copyright (C) 2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -55,22 +56,41 @@ class faSolution
 :
     public solution
 {
-    // Private Member Functions
-
-        //- No copy construct
-        faSolution(const faSolution&) = delete;
-
-        //- No copy assignment
-        void operator=(const faSolution&) = delete;
-
-
 public:
 
-    //- Construct from objectRegistry
-    faSolution(const objectRegistry& obr)
-    :
-        solution(obr, "faSolution")
-    {}
+    //- No copy construct
+    faSolution(const faSolution&) = delete;
+
+    //- No copy assignment
+    void operator=(const faSolution&) = delete;
+
+
+    // Constructors
+
+        //- Construct for objectRegistry, dictionary name and optional
+        //- fallback dictionary content (for a NO_READ or missing file)
+        //  A null dictionary pointer is treated like an empty dictionary.
+        faSolution
+        (
+            const objectRegistry& obr,
+            const word& dictName,
+            const dictionary* fallback = nullptr
+        )
+        :
+            solution(obr, dictName, fallback)
+        {}
+
+        //- Construct for objectRegistry, and optional
+        //- fallback dictionary content (for a NO_READ or missing file)
+        //  A null dictionary pointer is treated like an empty dictionary.
+        explicit faSolution
+        (
+            const objectRegistry& obr,
+            const dictionary* fallback = nullptr
+        )
+        :
+            faSolution(obr, "faSolution", fallback)
+        {}
 };
 
 
diff --git a/src/finiteArea/finiteArea/faSchemes/faSchemes.C b/src/finiteArea/finiteArea/faSchemes/faSchemes.C
deleted file mode 100644
index 026022736aef7c3c36c6754a385e14c73b960ea2..0000000000000000000000000000000000000000
--- a/src/finiteArea/finiteArea/faSchemes/faSchemes.C
+++ /dev/null
@@ -1,508 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | www.openfoam.com
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-    Copyright (C) 2016-2017 Wikki Ltd
-    Copyright (C) 2019-2021 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 "faSchemes.H"
-#include "Time.H"
-
-// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
-
-int Foam::faSchemes::debug(Foam::debug::debugSwitch("faSchemes", 0));
-
-
-// * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
-
-void Foam::faSchemes::clear()
-{
-    ddtSchemes_.clear();
-    ddtSchemeDefault_.clear();
-
-    d2dt2Schemes_.clear();
-    d2dt2SchemeDefault_.clear();
-
-    interpolationSchemes_.clear();
-    interpolationSchemeDefault_.clear();
-
-    divSchemes_.clear(); // optional
-    divSchemeDefault_.clear();
-
-    gradSchemes_.clear(); // optional
-    gradSchemeDefault_.clear();
-
-    lnGradSchemes_.clear();
-    lnGradSchemeDefault_.clear();
-
-    laplacianSchemes_.clear(); // optional
-    laplacianSchemeDefault_.clear();
-
-    fluxRequired_.clear();
-    fluxRequiredDefault_ = false;
-}
-
-
-void Foam::faSchemes::read(const dictionary& dict)
-{
-    if (dict.found("ddtSchemes"))
-    {
-        ddtSchemes_ = dict.subDict("ddtSchemes");
-    }
-    else
-    {
-        ddtSchemes_.set("default", "none");
-    }
-
-    if
-    (
-        ddtSchemes_.found("default")
-     && word(ddtSchemes_.lookup("default")) != "none"
-    )
-    {
-        ddtSchemeDefault_ = ddtSchemes_.lookup("default");
-    }
-
-
-    if (dict.found("d2dt2Schemes"))
-    {
-        d2dt2Schemes_ = dict.subDict("d2dt2Schemes");
-    }
-    else
-    {
-        d2dt2Schemes_.set("default", "none");
-    }
-
-    if
-    (
-        d2dt2Schemes_.found("default")
-     && word(d2dt2Schemes_.lookup("default")) != "none"
-    )
-    {
-        d2dt2SchemeDefault_ = d2dt2Schemes_.lookup("default");
-    }
-
-
-    if (dict.found("interpolationSchemes"))
-    {
-        interpolationSchemes_ = dict.subDict("interpolationSchemes");
-    }
-    else if (!interpolationSchemes_.found("default"))
-    {
-        interpolationSchemes_.add("default", "linear");
-    }
-
-    if
-    (
-        interpolationSchemes_.found("default")
-     && word(interpolationSchemes_.lookup("default")) != "none"
-    )
-    {
-        interpolationSchemeDefault_ =
-            interpolationSchemes_.lookup("default");
-    }
-
-
-    divSchemes_ = dict.subDict("divSchemes");
-
-    if
-    (
-        divSchemes_.found("default")
-     && word(divSchemes_.lookup("default")) != "none"
-    )
-    {
-        divSchemeDefault_ = divSchemes_.lookup("default");
-    }
-
-
-    gradSchemes_ = dict.subDict("gradSchemes");
-
-    if
-    (
-        gradSchemes_.found("default")
-     && word(gradSchemes_.lookup("default")) != "none"
-    )
-    {
-        gradSchemeDefault_ = gradSchemes_.lookup("default");
-    }
-
-
-    if (dict.found("lnGradSchemes"))
-    {
-        lnGradSchemes_ = dict.subDict("lnGradSchemes");
-    }
-    else if (!lnGradSchemes_.found("default"))
-    {
-        lnGradSchemes_.add("default", "corrected");
-    }
-
-    if
-    (
-        lnGradSchemes_.found("default")
-     && word(lnGradSchemes_.lookup("default")) != "none"
-    )
-    {
-        lnGradSchemeDefault_ = lnGradSchemes_.lookup("default");
-    }
-
-
-    laplacianSchemes_ = dict.subDict("laplacianSchemes");
-
-    if
-    (
-        laplacianSchemes_.found("default")
-     && word(laplacianSchemes_.lookup("default")) != "none"
-    )
-    {
-        laplacianSchemeDefault_ = laplacianSchemes_.lookup("default");
-    }
-
-
-    if (dict.found("fluxRequired"))
-    {
-        fluxRequired_.merge(dict.subDict("fluxRequired"));
-
-        if
-        (
-            fluxRequired_.found("default")
-         && fluxRequired_.get<word>("default") != "none"
-        )
-        {
-            fluxRequiredDefault_ = fluxRequired_.get<bool>("default");
-        }
-    }
-}
-
-
-void Foam::faSchemes::writeDicts(Ostream& os) const
-{
-    // Write dictionaries
-    ddtSchemes_.writeEntry(os);
-    d2dt2Schemes_.writeEntry(os);
-    interpolationSchemes_.writeEntry(os);
-    divSchemes_.writeEntry(os);
-    gradSchemes_.writeEntry(os);
-    lnGradSchemes_.writeEntry(os);
-    laplacianSchemes_.writeEntry(os);
-    fluxRequired_.writeEntry(os);
-}
-
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::faSchemes::faSchemes
-(
-    const objectRegistry& obr,
-    const word& dictName,
-    const dictionary* fallback
-)
-:
-    IOdictionary
-    (
-        IOobject
-        (
-            dictName,
-            obr.time().system(),
-            obr,
-            (
-                obr.readOpt() == IOobject::MUST_READ
-             || obr.readOpt() == IOobject::READ_IF_PRESENT
-              ? IOobject::MUST_READ_IF_MODIFIED
-              : obr.readOpt()
-            ),
-            IOobject::NO_WRITE
-        ),
-        fallback
-    ),
-
-    // Named, but empty dictionaries and default schemes
-    ddtSchemes_
-    (
-        objectPath() + ".ddtSchemes"
-    ),
-    ddtSchemeDefault_
-    (
-        zero{},
-        ddtSchemes_.name() + ".default"
-    ),
-    d2dt2Schemes_
-    (
-        objectPath() + ".d2dt2Schemes"
-    ),
-    d2dt2SchemeDefault_
-    (
-        zero{},
-        d2dt2Schemes_.name() + ".default"
-    ),
-    interpolationSchemes_
-    (
-        objectPath() + ".interpolationSchemes"
-    ),
-    interpolationSchemeDefault_
-    (
-        zero{},
-        interpolationSchemes_.name() + ".default"
-    ),
-    divSchemes_
-    (
-        objectPath() + ".divSchemes"
-    ),
-    divSchemeDefault_
-    (
-        zero{},
-        divSchemes_.name() + ".default"
-    ),
-    gradSchemes_
-    (
-        objectPath() + ".gradSchemes"
-    ),
-    gradSchemeDefault_
-    (
-        zero{},
-        gradSchemes_.name() + ".default"
-    ),
-    lnGradSchemes_
-    (
-        objectPath() + ".lnGradSchemes"
-    ),
-    lnGradSchemeDefault_
-    (
-        zero{},
-        lnGradSchemes_.name() + ".default"
-    ),
-    laplacianSchemes_
-    (
-        objectPath() + ".laplacianSchemes"
-    ),
-    laplacianSchemeDefault_
-    (
-        zero{},
-        laplacianSchemes_.name() + ".default"
-    ),
-    fluxRequired_
-    (
-        objectPath() + ".fluxRequired"
-    ),
-    fluxRequiredDefault_(false)
-{
-    if
-    (
-        readOpt() == IOobject::MUST_READ
-     || readOpt() == IOobject::MUST_READ_IF_MODIFIED
-     || (readOpt() == IOobject::READ_IF_PRESENT && headerOk())
-    )
-    {
-        read(schemesDict());
-    }
-}
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-bool Foam::faSchemes::read()
-{
-    if (regIOobject::read())
-    {
-        // Clear current settings except fluxRequired
-        clear();
-
-        read(schemesDict());
-
-        return true;
-    }
-
-    return false;
-}
-
-
-const Foam::dictionary& Foam::faSchemes::schemesDict() const
-{
-    if (found("select"))
-    {
-        return subDict(word(lookup("select")));
-    }
-
-    return *this;
-}
-
-
-Foam::ITstream& Foam::faSchemes::ddtScheme(const word& name) const
-{
-    DebugInfo<< "Lookup ddtScheme for " << name << endl;
-
-    if (ddtSchemes_.found(name) || ddtSchemeDefault_.empty())
-    {
-        return ddtSchemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(ddtSchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-Foam::ITstream& Foam::faSchemes::d2dt2Scheme(const word& name) const
-{
-    DebugInfo<< "Lookup d2dt2Scheme for " << name << endl;
-
-    if (d2dt2Schemes_.found(name) || d2dt2SchemeDefault_.empty())
-    {
-        return d2dt2Schemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(d2dt2SchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-Foam::ITstream& Foam::faSchemes::interpolationScheme(const word& name) const
-{
-    DebugInfo<< "Lookup interpolationScheme for " << name << endl;
-
-    if
-    (
-        interpolationSchemes_.found(name)
-     || interpolationSchemeDefault_.empty()
-    )
-    {
-        return interpolationSchemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(interpolationSchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-Foam::ITstream& Foam::faSchemes::divScheme(const word& name) const
-{
-    DebugInfo<< "Lookup divScheme for " << name << endl;
-
-    if (divSchemes_.found(name) || divSchemeDefault_.empty())
-    {
-        return divSchemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(divSchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-Foam::ITstream& Foam::faSchemes::gradScheme(const word& name) const
-{
-    DebugInfo<< "Lookup gradScheme for " << name << endl;
-
-    if (gradSchemes_.found(name) || gradSchemeDefault_.empty())
-    {
-        return gradSchemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(gradSchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-Foam::ITstream& Foam::faSchemes::lnGradScheme(const word& name) const
-{
-    DebugInfo<< "Lookup lnGradScheme for " << name << endl;
-
-    if (lnGradSchemes_.found(name) || lnGradSchemeDefault_.empty())
-    {
-        return lnGradSchemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(lnGradSchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-Foam::ITstream& Foam::faSchemes::laplacianScheme(const word& name) const
-{
-    DebugInfo<< "Lookup laplacianScheme for " << name << endl;
-
-    if (laplacianSchemes_.found(name) || laplacianSchemeDefault_.empty())
-    {
-        return laplacianSchemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(laplacianSchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-void Foam::faSchemes::setFluxRequired(const word& name) const
-{
-    DebugInfo<< "Setting fluxRequired for " << name << endl;
-
-    fluxRequired_.add(name, true, true);
-}
-
-
-bool Foam::faSchemes::fluxRequired(const word& name) const
-{
-    DebugInfo<< "Lookup fluxRequired for " << name << endl;
-
-    if (fluxRequired_.found(name))
-    {
-        return true;
-    }
-
-    return fluxRequiredDefault_;
-}
-
-
-bool Foam::faSchemes::writeData(Ostream& os) const
-{
-    this->writeDicts(os);
-    return true;
-}
-
-
-// ************************************************************************* //
diff --git a/src/finiteArea/finiteArea/faSchemes/faSchemes.H b/src/finiteArea/finiteArea/faSchemes/faSchemes.H
index cde8cbb1b9f1b984c2ff71e73719e9c8093bc4e8..78a3db571be24df66d9732a494af308af25d87ee 100644
--- a/src/finiteArea/finiteArea/faSchemes/faSchemes.H
+++ b/src/finiteArea/finiteArea/faSchemes/faSchemes.H
@@ -29,18 +29,17 @@ Class
 
 Description
     Selector class for finite area differencing schemes.
-    faMesh is derived from faShemes so that all fields have access to the
+    faMesh is derived from faSchemes so that all fields have access to the
     faSchemes from the mesh reference they hold.
 
 SourceFiles
-    faSchemes.C
 
 \*---------------------------------------------------------------------------*/
 
 #ifndef faSchemes_H
 #define faSchemes_H
 
-#include "IOdictionary.H"
+#include "schemesLookup.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -53,73 +52,31 @@ namespace Foam
 
 class faSchemes
 :
-    public IOdictionary
+    public schemesLookup
 {
-    // Private Data
-
-        dictionary ddtSchemes_;
-        ITstream ddtSchemeDefault_;
-
-        dictionary d2dt2Schemes_;
-        ITstream d2dt2SchemeDefault_;
-
-        dictionary interpolationSchemes_;
-        ITstream interpolationSchemeDefault_;
-
-        dictionary divSchemes_;
-        ITstream divSchemeDefault_;
-
-        dictionary gradSchemes_;
-        ITstream gradSchemeDefault_;
-
-        dictionary lnGradSchemes_;
-        ITstream lnGradSchemeDefault_;
-
-        dictionary laplacianSchemes_;
-        ITstream laplacianSchemeDefault_;
-
-        mutable dictionary fluxRequired_;
-        bool fluxRequiredDefault_;
-
-
-    // Private Member Functions
-
-        //- Clear the dictionaries and streams before reading
-        void clear();
-
-        //- Read settings from the dictionary
-        void read(const dictionary&);
-
-        //- Write dictionary (possibly modified) settings
-        void writeDicts(Ostream& os) const;
+public:
 
-        //- No copy construct
-        faSchemes(const faSchemes&) = delete;
+    //- No copy construct
+    faSchemes(const faSchemes&) = delete;
 
-        //- No copy assignment
-        void operator=(const faSchemes&) = delete;
+    //- No copy assignment
+    void operator=(const faSchemes&) = delete;
 
 
     // Constructors
 
-        //- Construct for objectRegistry, system dictName, and optional
+        //- Construct for objectRegistry, dictionary name and optional
         //- fallback dictionary content (for a NO_READ or missing file)
         //  A null dictionary pointer is treated like an empty dictionary.
         faSchemes
         (
             const objectRegistry& obr,
             const word& dictName,
-            const dictionary* fallback
-        );
-
-
-public:
-
-    //- Debug switch
-    static int debug;
-
-
-    // Constructors
+            const dictionary* fallback = nullptr
+        )
+        :
+            schemesLookup(obr, dictName, fallback)
+        {}
 
         //- Construct for objectRegistry, and optional
         //- fallback dictionary content (for a NO_READ or missing file)
@@ -139,94 +96,6 @@ public:
         :
             faSchemes(obr, "faSchemes", &dict)
         {}
-
-
-    // Member Functions
-
-        // Access
-
-            const dictionary& schemesDict() const;
-
-            ITstream& ddtScheme(const word& name) const;
-
-            ITstream& d2dt2Scheme(const word& name) const;
-
-            ITstream& interpolationScheme(const word& name) const;
-
-            ITstream& divScheme(const word& name) const;
-
-            ITstream& gradScheme(const word& name) const;
-
-            ITstream& lnGradScheme(const word& name) const;
-
-            ITstream& laplacianScheme(const word& name) const;
-
-            void setFluxRequired(const word& name) const;
-
-            bool fluxRequired(const word& name) const;
-
-
-        // Edit
-
-            //- Return access to ddt schemes
-            dictionary& ddtSchemes() noexcept
-            {
-                return ddtSchemes_;
-            }
-
-            //- Return access to d2dt2 schemes
-            dictionary& d2dt2Schemes() noexcept
-            {
-                return d2dt2Schemes_;
-            }
-
-            //- Return access to interpolation schemes
-            dictionary& interpolationSchemes() noexcept
-            {
-                return interpolationSchemes_;
-            }
-
-            //- Return access to div schemes
-            dictionary& divSchemes() noexcept
-            {
-                return divSchemes_;
-            }
-
-            //- Return access to grad schemes
-            dictionary& gradSchemes() noexcept
-            {
-                return gradSchemes_;
-            }
-
-            //- Return access to lnGrad schemes
-            dictionary& lnGradSchemes() noexcept
-            {
-                return lnGradSchemes_;
-            }
-
-            //- Return access to laplacian schemes
-            dictionary& laplacianSchemes() noexcept
-            {
-                return laplacianSchemes_;
-            }
-
-            //- Return access to flux required
-            dictionary& fluxRequired() noexcept
-            {
-                return fluxRequired_;
-            }
-
-
-        // Read
-
-            //- Read the faSchemes
-            bool read();
-
-
-        // Write
-
-            //- WriteData function required for regIOobject write operation
-            virtual bool writeData(Ostream&) const;
 };
 
 
diff --git a/src/finiteVolume/Make/files b/src/finiteVolume/Make/files
index e2f15cf369cbbc36b3d41e4126e47b138ba8b663..a251a1fe4f479d7f2a2c5acaa9f7331dc9dbd81f 100644
--- a/src/finiteVolume/Make/files
+++ b/src/finiteVolume/Make/files
@@ -405,7 +405,6 @@ $(multivariateSchemes)/limitedLinear/multivariateLimitedLinear.C
 $(multivariateSchemes)/limitedCubic/multivariateLimitedCubic.C
 
 finiteVolume/fv/fv.C
-finiteVolume/fvSchemes/fvSchemes.C
 
 ddtSchemes = finiteVolume/ddtSchemes
 $(ddtSchemes)/ddtScheme/ddtSchemeBase.C
diff --git a/src/finiteVolume/finiteVolume/fvSchemes/fvSchemes.C b/src/finiteVolume/finiteVolume/fvSchemes/fvSchemes.C
deleted file mode 100644
index d4e6dd97aef8da32dff165b401050a9751d8d803..0000000000000000000000000000000000000000
--- a/src/finiteVolume/finiteVolume/fvSchemes/fvSchemes.C
+++ /dev/null
@@ -1,507 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | www.openfoam.com
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-    Copyright (C) 2011-2015 OpenFOAM Foundation
-    Copyright (C) 2019-2021 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 "fvSchemes.H"
-#include "Time.H"
-#include "steadyStateDdtScheme.H"
-
-// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
-
-int Foam::fvSchemes::debug(Foam::debug::debugSwitch("fvSchemes", 0));
-
-
-// * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
-
-void Foam::fvSchemes::clear()
-{
-    ddtSchemes_.clear();
-    ddtSchemeDefault_.clear();
-
-    d2dt2Schemes_.clear();
-    d2dt2SchemeDefault_.clear();
-
-    interpolationSchemes_.clear();
-    interpolationSchemeDefault_.clear();
-
-    divSchemes_.clear();
-    divSchemeDefault_.clear();
-
-    gradSchemes_.clear();
-    gradSchemeDefault_.clear();
-
-    snGradSchemes_.clear();
-    snGradSchemeDefault_.clear();
-
-    laplacianSchemes_.clear();
-    laplacianSchemeDefault_.clear();
-
-    // Do not clear fluxRequired settings
-}
-
-
-void Foam::fvSchemes::read(const dictionary& dict)
-{
-    if (dict.found("ddtSchemes"))
-    {
-        ddtSchemes_ = dict.subDict("ddtSchemes");
-    }
-    else
-    {
-        ddtSchemes_.set("default", "none");
-    }
-
-    if
-    (
-        ddtSchemes_.found("default")
-     && word(ddtSchemes_.lookup("default")) != "none"
-    )
-    {
-        ddtSchemeDefault_ = ddtSchemes_.lookup("default");
-        steady_ =
-        (
-            word(ddtSchemeDefault_)
-         == fv::steadyStateDdtScheme<scalar>::typeName
-        );
-    }
-
-
-    if (dict.found("d2dt2Schemes"))
-    {
-        d2dt2Schemes_ = dict.subDict("d2dt2Schemes");
-    }
-    else
-    {
-        d2dt2Schemes_.set("default", "none");
-    }
-
-    if
-    (
-        d2dt2Schemes_.found("default")
-     && word(d2dt2Schemes_.lookup("default")) != "none"
-    )
-    {
-        d2dt2SchemeDefault_ = d2dt2Schemes_.lookup("default");
-    }
-
-
-    if (dict.found("interpolationSchemes"))
-    {
-        interpolationSchemes_ = dict.subDict("interpolationSchemes");
-    }
-    else if (!interpolationSchemes_.found("default"))
-    {
-        interpolationSchemes_.add("default", "linear");
-    }
-
-    if
-    (
-        interpolationSchemes_.found("default")
-     && word(interpolationSchemes_.lookup("default")) != "none"
-    )
-    {
-        interpolationSchemeDefault_ =
-            interpolationSchemes_.lookup("default");
-    }
-
-
-    divSchemes_ = dict.subDict("divSchemes");
-
-    if
-    (
-        divSchemes_.found("default")
-     && word(divSchemes_.lookup("default")) != "none"
-    )
-    {
-        divSchemeDefault_ = divSchemes_.lookup("default");
-    }
-
-
-    gradSchemes_ = dict.subDict("gradSchemes");
-
-    if
-    (
-        gradSchemes_.found("default")
-     && word(gradSchemes_.lookup("default")) != "none"
-    )
-    {
-        gradSchemeDefault_ = gradSchemes_.lookup("default");
-    }
-
-
-    if (dict.found("snGradSchemes"))
-    {
-        snGradSchemes_ = dict.subDict("snGradSchemes");
-    }
-    else if (!snGradSchemes_.found("default"))
-    {
-        snGradSchemes_.add("default", "corrected");
-    }
-
-    if
-    (
-        snGradSchemes_.found("default")
-     && word(snGradSchemes_.lookup("default")) != "none"
-    )
-    {
-        snGradSchemeDefault_ = snGradSchemes_.lookup("default");
-    }
-
-
-    laplacianSchemes_ = dict.subDict("laplacianSchemes");
-
-    if
-    (
-        laplacianSchemes_.found("default")
-     && word(laplacianSchemes_.lookup("default")) != "none"
-    )
-    {
-        laplacianSchemeDefault_ = laplacianSchemes_.lookup("default");
-    }
-
-
-    if (dict.found("fluxRequired"))
-    {
-        fluxRequired_.merge(dict.subDict("fluxRequired"));
-
-        if
-        (
-            fluxRequired_.found("default")
-         && fluxRequired_.get<word>("default") != "none"
-        )
-        {
-            fluxRequiredDefault_ = fluxRequired_.get<bool>("default");
-        }
-    }
-}
-
-
-void Foam::fvSchemes::writeDicts(Ostream& os) const
-{
-    // Write dictionaries
-    ddtSchemes_.writeEntry(os);
-    d2dt2Schemes_.writeEntry(os);
-    interpolationSchemes_.writeEntry(os);
-    divSchemes_.writeEntry(os);
-    gradSchemes_.writeEntry(os);
-    snGradSchemes_.writeEntry(os);
-    laplacianSchemes_.writeEntry(os);
-    fluxRequired_.writeEntry(os);
-}
-
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::fvSchemes::fvSchemes
-(
-    const objectRegistry& obr,
-    const word& dictName,
-    const dictionary* fallback
-)
-:
-    IOdictionary
-    (
-        IOobject
-        (
-            dictName,
-            obr.time().system(),
-            obr,
-            (
-                obr.readOpt() == IOobject::MUST_READ
-             || obr.readOpt() == IOobject::READ_IF_PRESENT
-              ? IOobject::MUST_READ_IF_MODIFIED
-              : obr.readOpt()
-            ),
-            IOobject::NO_WRITE
-        ),
-        fallback
-    ),
-
-    // Named, but empty dictionaries and default schemes
-    ddtSchemes_
-    (
-        objectPath() + ".ddtSchemes"
-    ),
-    ddtSchemeDefault_
-    (
-        zero{},
-        ddtSchemes_.name() + ".default"
-    ),
-    d2dt2Schemes_
-    (
-        objectPath() + ".d2dt2Schemes"
-    ),
-    d2dt2SchemeDefault_
-    (
-        zero{},
-        d2dt2Schemes_.name() + ".default"
-    ),
-    interpolationSchemes_
-    (
-        objectPath() + ".interpolationSchemes"
-    ),
-    interpolationSchemeDefault_
-    (
-        zero{},
-        interpolationSchemes_.name() + ".default"
-    ),
-    divSchemes_
-    (
-        objectPath() + ".divSchemes"
-    ),
-    divSchemeDefault_
-    (
-        zero{},
-        divSchemes_.name() + ".default"
-    ),
-    gradSchemes_
-    (
-        objectPath() + ".gradSchemes"
-    ),
-    gradSchemeDefault_
-    (
-        zero{},
-        gradSchemes_.name() + ".default"
-    ),
-    snGradSchemes_
-    (
-        objectPath() + ".snGradSchemes"
-    ),
-    snGradSchemeDefault_
-    (
-        zero{},
-        snGradSchemes_.name() + ".default"
-    ),
-    laplacianSchemes_
-    (
-        objectPath() + ".laplacianSchemes"
-    ),
-    laplacianSchemeDefault_
-    (
-        zero{},
-        laplacianSchemes_.name() + ".default"
-    ),
-    fluxRequired_
-    (
-        objectPath() + ".fluxRequired"
-    ),
-    fluxRequiredDefault_(false),
-    steady_(false)
-{
-    if
-    (
-        readOpt() == IOobject::MUST_READ
-     || readOpt() == IOobject::MUST_READ_IF_MODIFIED
-     || (readOpt() == IOobject::READ_IF_PRESENT && headerOk())
-    )
-    {
-        read(schemesDict());
-    }
-}
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-bool Foam::fvSchemes::read()
-{
-    if (regIOobject::read())
-    {
-        // Clear current settings except fluxRequired
-        clear();
-
-        read(schemesDict());
-
-        return true;
-    }
-
-    return false;
-}
-
-
-const Foam::dictionary& Foam::fvSchemes::schemesDict() const
-{
-    if (found("select"))
-    {
-        return subDict(word(lookup("select")));
-    }
-
-    return *this;
-}
-
-
-Foam::ITstream& Foam::fvSchemes::ddtScheme(const word& name) const
-{
-    DebugInfo<< "Lookup ddtScheme for " << name << endl;
-
-    if (ddtSchemes_.found(name) || ddtSchemeDefault_.empty())
-    {
-        return ddtSchemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(ddtSchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-Foam::ITstream& Foam::fvSchemes::d2dt2Scheme(const word& name) const
-{
-    DebugInfo<< "Lookup d2dt2Scheme for " << name << endl;
-
-    if (d2dt2Schemes_.found(name) || d2dt2SchemeDefault_.empty())
-    {
-        return d2dt2Schemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(d2dt2SchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-Foam::ITstream& Foam::fvSchemes::interpolationScheme(const word& name) const
-{
-    DebugInfo<< "Lookup interpolationScheme for " << name << endl;
-
-    if
-    (
-        interpolationSchemes_.found(name)
-     || interpolationSchemeDefault_.empty()
-    )
-    {
-        return interpolationSchemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(interpolationSchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-Foam::ITstream& Foam::fvSchemes::divScheme(const word& name) const
-{
-    DebugInfo<< "Lookup divScheme for " << name << endl;
-
-    if (divSchemes_.found(name) || divSchemeDefault_.empty())
-    {
-        return divSchemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(divSchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-Foam::ITstream& Foam::fvSchemes::gradScheme(const word& name) const
-{
-    DebugInfo<< "Lookup gradScheme for " << name << endl;
-
-    if (gradSchemes_.found(name) || gradSchemeDefault_.empty())
-    {
-        return gradSchemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(gradSchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-Foam::ITstream& Foam::fvSchemes::snGradScheme(const word& name) const
-{
-    DebugInfo<< "Lookup snGradScheme for " << name << endl;
-
-    if (snGradSchemes_.found(name) || snGradSchemeDefault_.empty())
-    {
-        return snGradSchemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(snGradSchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-Foam::ITstream& Foam::fvSchemes::laplacianScheme(const word& name) const
-{
-    DebugInfo<< "Lookup laplacianScheme for " << name << endl;
-
-    if (laplacianSchemes_.found(name) || laplacianSchemeDefault_.empty())
-    {
-        return laplacianSchemes_.lookup(name);
-    }
-    else
-    {
-        // Default scheme
-        ITstream& is = const_cast<ITstream&>(laplacianSchemeDefault_);
-        is.rewind();
-        return is;
-    }
-}
-
-
-void Foam::fvSchemes::setFluxRequired(const word& name) const
-{
-    DebugInfo<< "Setting fluxRequired for " << name << endl;
-
-    fluxRequired_.add(name, true, true);
-}
-
-
-bool Foam::fvSchemes::fluxRequired(const word& name) const
-{
-    DebugInfo<< "Lookup fluxRequired for " << name << endl;
-
-    if (fluxRequired_.found(name))
-    {
-        return true;
-    }
-
-    return fluxRequiredDefault_;
-}
-
-
-// ************************************************************************* //
diff --git a/src/finiteVolume/finiteVolume/fvSchemes/fvSchemes.H b/src/finiteVolume/finiteVolume/fvSchemes/fvSchemes.H
index 6d4f219158ff36a7df6830c09abf973de4ff330c..048974f4a0d40184e2dc5f68690359e4de8db8b4 100644
--- a/src/finiteVolume/finiteVolume/fvSchemes/fvSchemes.H
+++ b/src/finiteVolume/finiteVolume/fvSchemes/fvSchemes.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2011-2015 OpenFOAM Foundation
+    Copyright (C) 2011 OpenFOAM Foundation
     Copyright (C) 2020-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
@@ -29,18 +29,17 @@ Class
 
 Description
     Selector class for finite volume differencing schemes.
-    fvMesh is derived from fvShemes so that all fields have access to the
+    fvMesh is derived from fvSchemes so that all fields have access to the
     fvSchemes from the mesh reference they hold.
 
 SourceFiles
-    fvSchemes.C
 
 \*---------------------------------------------------------------------------*/
 
 #ifndef fvSchemes_H
 #define fvSchemes_H
 
-#include "IOdictionary.H"
+#include "schemesLookup.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -53,49 +52,11 @@ namespace Foam
 
 class fvSchemes
 :
-    public IOdictionary
+    public schemesLookup
 {
-    // Private Data
-
-        dictionary ddtSchemes_;
-        ITstream ddtSchemeDefault_;
-
-        dictionary d2dt2Schemes_;
-        ITstream d2dt2SchemeDefault_;
-
-        dictionary interpolationSchemes_;
-        ITstream interpolationSchemeDefault_;
-
-        dictionary divSchemes_;
-        ITstream divSchemeDefault_;
-
-        dictionary gradSchemes_;
-        ITstream gradSchemeDefault_;
-
-        dictionary snGradSchemes_;
-        ITstream snGradSchemeDefault_;
-
-        dictionary laplacianSchemes_;
-        ITstream laplacianSchemeDefault_;
-
-        mutable dictionary fluxRequired_;
-        bool fluxRequiredDefault_;
-
-        //- Steady-state run indicator
-        //  Set true if the default ddtScheme is steadyState
-        bool steady_;
-
-
-    // Private Member Functions
-
-        //- Clear the dictionaries and streams before reading
-        void clear();
-
-        //- Read settings from the dictionary
-        void read(const dictionary&);
+public:
 
-        //- Write dictionary (possibly modified) settings
-        void writeDicts(Ostream& os) const;
+    // Constructors
 
         //- No copy construct
         fvSchemes(const fvSchemes&) = delete;
@@ -103,27 +64,18 @@ class fvSchemes
         //- No copy assignment
         void operator=(const fvSchemes&) = delete;
 
-
-    // Constructors
-
-        //- Construct for objectRegistry, system dictName, and optional
+        //- Construct for objectRegistry, dictionary name and optional
         //- fallback dictionary content (for a NO_READ or missing file)
         //  A null dictionary pointer is treated like an empty dictionary.
         fvSchemes
         (
             const objectRegistry& obr,
             const word& dictName,
-            const dictionary* fallback
-        );
-
-
-public:
-
-    //- Debug switch
-    static int debug;
-
-
-    // Constructors
+            const dictionary* fallback = nullptr
+        )
+        :
+            schemesLookup(obr, dictName, fallback)
+        {}
 
         //- Construct for objectRegistry, and optional
         //- fallback dictionary content (for a NO_READ or missing file)
@@ -143,49 +95,6 @@ public:
         :
             fvSchemes(obr, "fvSchemes", &dict)
         {}
-
-
-    // Member Functions
-
-        // Access
-
-            const dictionary& schemesDict() const;
-
-            ITstream& ddtScheme(const word& name) const;
-
-            ITstream& d2dt2Scheme(const word& name) const;
-
-            ITstream& interpolationScheme(const word& name) const;
-
-            ITstream& divScheme(const word& name) const;
-
-            ITstream& gradScheme(const word& name) const;
-
-            ITstream& snGradScheme(const word& name) const;
-
-            ITstream& laplacianScheme(const word& name) const;
-
-            void setFluxRequired(const word& name) const;
-
-            bool fluxRequired(const word& name) const;
-
-            //- True if the default ddtScheme is steadyState
-            bool steady() const noexcept
-            {
-                return steady_;
-            }
-
-            //- True if the default ddtScheme is not steadyState
-            bool transient() const noexcept
-            {
-                return !steady_;
-            }
-
-
-        // Read
-
-            //- Read the fvSchemes
-            bool read();
 };
 
 
diff --git a/src/finiteVolume/finiteVolume/fvSolution/fvSolution.H b/src/finiteVolume/finiteVolume/fvSolution/fvSolution.H
index bdafb4c86b47dd718ed124a4f6d0b5140bf5e690..2ab4af99ef08fa4c086ebe7928c7d6b067673696 100644
--- a/src/finiteVolume/finiteVolume/fvSolution/fvSolution.H
+++ b/src/finiteVolume/finiteVolume/fvSolution/fvSolution.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011 OpenFOAM Foundation
-    Copyright (C) 2020 OpenCFD Ltd.
+    Copyright (C) 2020-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -52,29 +52,46 @@ class fvSolution
 :
     public solution
 {
-    // Private Member Functions
-
-        //- No copy construct
-        fvSolution(const fvSolution&) = delete;
+public:
 
-        //- No copy assignment
-        void operator=(const fvSolution&) = delete;
+    //- No copy construct
+    fvSolution(const fvSolution&) = delete;
 
+    //- No copy assignment
+    void operator=(const fvSolution&) = delete;
 
-public:
 
     // Constructors
 
-        //- Construct for objectRegistry
-        fvSolution(const objectRegistry& obr)
+        //- Construct for objectRegistry, dictionary name and optional
+        //- fallback dictionary content (for a NO_READ or missing file)
+        //  A null dictionary pointer is treated like an empty dictionary.
+        fvSolution
+        (
+            const objectRegistry& obr,
+            const word& dictName,
+            const dictionary* fallback = nullptr
+        )
+        :
+            solution(obr, dictName, fallback)
+        {}
+
+        //- Construct for objectRegistry, and optional
+        //- fallback dictionary content (for a NO_READ or missing file)
+        //  A null dictionary pointer is treated like an empty dictionary.
+        explicit fvSolution
+        (
+            const objectRegistry& obr,
+            const dictionary* fallback = nullptr
+        )
         :
-            solution(obr, "fvSolution")
+            fvSolution(obr, "fvSolution", fallback)
         {}
 
         //- Construct for objectRegistry and optional contents
         fvSolution(const objectRegistry& obr, const dictionary& dict)
         :
-            solution(obr, "fvSolution", dict)
+            fvSolution(obr, "fvSolution", &dict)
         {}
 };