diff --git a/applications/solvers/incompressible/adjointOptimisationFoam/Make/files b/applications/solvers/incompressible/adjointOptimisationFoam/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..3734dc051c316af8c77629440c024d44e094240b
--- /dev/null
+++ b/applications/solvers/incompressible/adjointOptimisationFoam/Make/files
@@ -0,0 +1,3 @@
+adjointOptimisationFoam.C
+
+EXE = $(FOAM_APPBIN)/adjointOptimisationFoam
diff --git a/applications/solvers/incompressible/adjointOptimisationFoam/Make/options b/applications/solvers/incompressible/adjointOptimisationFoam/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..f45d173cbf6627664fed271a99503a547c77fb51
--- /dev/null
+++ b/applications/solvers/incompressible/adjointOptimisationFoam/Make/options
@@ -0,0 +1,21 @@
+EXE_INC = \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/fvOptions/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/sampling/lnInclude \
+    -I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
+    -I$(LIB_SRC)/TurbulenceModels/incompressible/lnInclude \
+    -I$(LIB_SRC)/transportModels \
+    -I$(LIB_SRC)/transportModels/incompressible/singlePhaseTransportModel \
+    -I$(LIB_SRC)/optimisation/adjointOptimisation/adjoint/lnInclude
+
+
+EXE_LIBS = \
+    -lfiniteVolume \
+    -lfvOptions \
+    -lmeshTools \
+    -lsampling \
+    -lturbulenceModels \
+    -lincompressibleTurbulenceModels \
+    -lincompressibleTransportModels \
+    -ladjointOptimisation
diff --git a/applications/solvers/incompressible/adjointOptimisationFoam/adjointOptimisationFoam.C b/applications/solvers/incompressible/adjointOptimisationFoam/adjointOptimisationFoam.C
new file mode 100644
index 0000000000000000000000000000000000000000..683bc951338d3ed007ab3e771f635a87ef065730
--- /dev/null
+++ b/applications/solvers/incompressible/adjointOptimisationFoam/adjointOptimisationFoam.C
@@ -0,0 +1,87 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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/>.
+
+Application
+    adjointOptimisation
+
+Description
+    An automated adjoint-based optimisation loop. Supports multiple types
+    of optimisation (shape, topology etc)
+
+\*---------------------------------------------------------------------------*/
+
+#include "fvCFD.H"
+#include "optimisationManager.H"
+#include "primalSolver.H"
+#include "adjointSolverManager.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+int main(int argc, char *argv[])
+{
+    #include "setRootCase.H"
+    #include "createTime.H"
+    #include "createMesh.H"
+    #include "createFields.H"
+
+    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+
+    Info<< "\nStarting time loop\n" << endl;
+
+    for (om++; !om.end(); om++)
+    {
+        Info<< "* * * * * * * * * * * * * * * * * * *" << endl;
+        Info<< "Time = " << runTime.timeName()         << endl;
+        Info<< "* * * * * * * * * * * * * * * * * * *" << endl;
+
+        if (om.update())
+        {
+            // Update design variables and solve all primal equations
+            om.updateDesignVariables();
+        }
+        else
+        {
+            // Solve all primal equations
+            om.solvePrimalEquations();
+        }
+
+        // Update primal-based quantities of the adjoint solvers
+        om.updatePrimalBasedQuantities();
+
+        // Solve all adjoint equations
+        om.solveAdjointEquations();
+
+        // Compute all sensitivities
+        om.computeSensitivities();
+    }
+    Info<< "End\n" << endl;
+
+    return(0);
+}
+
+
+// ************************************************************************* //
diff --git a/applications/solvers/incompressible/adjointOptimisationFoam/createFields.H b/applications/solvers/incompressible/adjointOptimisationFoam/createFields.H
new file mode 100644
index 0000000000000000000000000000000000000000..637b683fafd598d8b81208d2940342268c4864a6
--- /dev/null
+++ b/applications/solvers/incompressible/adjointOptimisationFoam/createFields.H
@@ -0,0 +1,6 @@
+    // Construct optimisation manager
+    autoPtr<optimisationManager> optManagerPtr
+    (
+        optimisationManager::New(mesh)
+    );
+    optimisationManager& om = optManagerPtr();
diff --git a/applications/utilities/postProcessing/optimisation/computeSensitivities/Make/files b/applications/utilities/postProcessing/optimisation/computeSensitivities/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..0d733c0656f0fc764a3c822d510548b4a3a03879
--- /dev/null
+++ b/applications/utilities/postProcessing/optimisation/computeSensitivities/Make/files
@@ -0,0 +1,3 @@
+computeSensitivities.C
+
+EXE = $(FOAM_APPBIN)/computeSensitivities
diff --git a/applications/utilities/postProcessing/optimisation/computeSensitivities/Make/options b/applications/utilities/postProcessing/optimisation/computeSensitivities/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..48d2719706a80ae142e83772adfb175bd917abe3
--- /dev/null
+++ b/applications/utilities/postProcessing/optimisation/computeSensitivities/Make/options
@@ -0,0 +1,23 @@
+EXE_INC = \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/fvOptions/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/sampling/lnInclude \
+    -I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
+    -I$(LIB_SRC)/TurbulenceModels/incompressible/lnInclude \
+    -I$(LIB_SRC)/transportModels \
+    -I$(LIB_SRC)/transportModels/incompressible/singlePhaseTransportModel \
+    -I$(LIB_SRC)/optimisation/adjointOptimisation/adjoint/lnInclude
+
+
+EXE_LIBS = \
+    -lfiniteVolume \
+    -lfvOptions \
+    -lmeshTools \
+    -lsampling \
+    -lturbulenceModels \
+    -lincompressibleTransportModels \
+    -lincompressibleTurbulenceModels \
+    -lfileFormats \
+    -lsurfMesh \
+    -ladjointOptimisation
diff --git a/applications/utilities/postProcessing/optimisation/computeSensitivities/computeSensitivities.C b/applications/utilities/postProcessing/optimisation/computeSensitivities/computeSensitivities.C
new file mode 100644
index 0000000000000000000000000000000000000000..cc915c5eedf0ef795192c76af4cc3e65f5171b39
--- /dev/null
+++ b/applications/utilities/postProcessing/optimisation/computeSensitivities/computeSensitivities.C
@@ -0,0 +1,76 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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/>.
+
+Application
+    computeSensitivities
+
+Description
+    Computes the sensitivities wrt what is defined in the optimisationDict
+
+\*---------------------------------------------------------------------------*/
+
+#include "fvCFD.H"
+#include "optimisationManager.H"
+#include "primalSolver.H"
+#include "adjointSolver.H"
+#include "incompressibleVars.H"
+#include "incompressibleAdjointVars.H"
+#include "adjointBoundaryCondition.H"
+#include "adjointSolverManager.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+int main(int argc, char *argv[])
+{
+    #include "setRootCase.H"
+    #include "createTime.H"
+    #include "createMesh.H"
+    #include "createFields.H"
+
+    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+    forAll(adjointSolverManagers, amI)
+    {
+        PtrList<adjointSolver>& adjointSolvers =
+            adjointSolverManagers[amI].adjointSolvers();
+        forAll(adjointSolvers, asI)
+        {
+            adjointSolvers[asI].getObjectiveManager().updateAndWrite();
+            adjointSolvers[asI].computeObjectiveSensitivities();
+        }
+    }
+
+    Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
+        << "  ClockTime = " << runTime.elapsedClockTime() << " s"
+        << nl << endl;
+
+    Info<< "End" << endl;
+
+    return(0);
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/optimisation/computeSensitivities/createFields.H b/applications/utilities/postProcessing/optimisation/computeSensitivities/createFields.H
new file mode 100644
index 0000000000000000000000000000000000000000..6c87fffe1c97eb35519e17cf62eabdf2400f7834
--- /dev/null
+++ b/applications/utilities/postProcessing/optimisation/computeSensitivities/createFields.H
@@ -0,0 +1,9 @@
+// Construct optimisation manager
+autoPtr<optimisationManager> optManagerPtr
+(
+    optimisationManager::New(mesh)
+);
+optimisationManager& om = optManagerPtr();
+
+PtrList<adjointSolverManager>& adjointSolverManagers =
+    om.adjointSolverManagers();
diff --git a/bin/tools/CleanFunctions b/bin/tools/CleanFunctions
index 1886ff1d46924a855b14efd8d864aeef8a776893..c667bb7e4ecc246f2869dae0a3781e8b9e7ef6d7 100644
--- a/bin/tools/CleanFunctions
+++ b/bin/tools/CleanFunctions
@@ -73,6 +73,13 @@ cleanSnappyFiles()
 }
 
 
+cleanOptimisation()
+{
+    rm -rf optimisation
+    rm -rf constant/controlPoints
+}
+
+
 cleanPostProcessing()
 {
     rm -rf Ensight EnSight ensightWrite insitu VTK > /dev/null 2>&1
@@ -87,6 +94,7 @@ cleanCase()
     cleanTimeDirectories
     cleanPostProcessing
     cleanDynamicCode
+    cleanOptimisation
 
     rm -rf processor* > /dev/null 2>&1
     rm -rf TDAC > /dev/null 2>&1
diff --git a/src/Allwmake b/src/Allwmake
index c693a09ba7ed1c5065831b6307df84dbc6e02c00..f3c927a490aba365adcfb4cf1d541a93f0dc441f 100755
--- a/src/Allwmake
+++ b/src/Allwmake
@@ -107,6 +107,7 @@ wmake $targetType rigidBodyDynamics
 wmake $targetType rigidBodyMeshMotion
 wmake $targetType semiPermeableBaffle
 wmake $targetType atmosphericModels
+wmake $targetType optimisation/adjointOptimisation/adjoint
 
 phaseSystemModels/Allwmake $targetType $*
 
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModel.C b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModel.C
new file mode 100644
index 0000000000000000000000000000000000000000..775f83ed7dbd315c6cec2747e68b13aae56a40ff
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModel.C
@@ -0,0 +1,263 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "ATCModel.H"
+#include "localMin.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(ATCModel, 0);
+defineRunTimeSelectionTable(ATCModel, dictionary);
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+void ATCModel::computeLimiter()
+{
+    computeLimiter(ATClimiter_, zeroATCcells_->getZeroATCcells(), nSmooth_);
+}
+
+
+void ATCModel::smoothATC()
+{
+    ATC_ *= ATClimiter_;
+    DebugInfo<<
+        "max ATC mag " << gMax(ATC_) << endl;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+ATCModel::ATCModel
+(
+    const fvMesh& mesh,
+    const incompressibleVars& primalVars,
+    const incompressibleAdjointVars& adjointVars,
+    const dictionary& dict
+)
+:
+    regIOobject
+    (
+        IOobject
+        (
+            "ATCModel" + adjointVars.solverName(),
+            mesh.time().timeName(),
+            mesh,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        )
+    ),
+    mesh_(mesh),
+    primalVars_(primalVars),
+    adjointVars_(adjointVars),
+    dict_(dict),
+    extraConvection_(dict_.lookupOrDefault<scalar>("extraConvection", Zero)),
+    extraDiffusion_(dict_.lookupOrDefault<scalar>("extraDiffusion", Zero)),
+    nSmooth_(dict_.lookupOrDefault<label>("nSmooth", 0)),
+    reconstructGradients_
+    (
+        dict_.lookupOrDefault<bool>("reconstructGradients", false)
+    ),
+    adjointSolverName_(adjointVars.solverName()),
+    zeroATCcells_(zeroATCcells::New(mesh, dict_)),
+    ATClimiter_
+    (
+        IOobject
+        (
+            "ATClimiter" + adjointSolverName_,
+            mesh_.time().timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        mesh_,
+        dimensionedScalar("limiter", dimless, 1.0),
+        zeroGradientFvPatchField<scalar>::typeName
+    ),
+    ATC_
+    (
+        IOobject
+        (
+            "ATCField" + adjointSolverName_,
+            mesh_.time().timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        mesh_,
+        dimensionedVector(dimensionSet(0, 1, -2, 0, 0), Zero)
+    )
+{
+    // Compute ATC limiter
+    computeLimiter();
+}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+autoPtr<ATCModel> ATCModel::New
+(
+    const fvMesh& mesh,
+    const incompressibleVars& primalVars,
+    const incompressibleAdjointVars& adjointVars,
+    const dictionary& dict
+)
+{
+    const word modelType(dict.get<word>("ATCModel"));
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
+
+    Info<< "ATCModel type " << modelType << endl;
+
+    if (!cstrIter.found())
+    {
+        FatalIOErrorInFunction(dict)
+            << "Unknown ATCModel type " << modelType << nl << nl
+            << "Valid ATCModel types are :" << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalIOError);
+    }
+
+    return autoPtr<ATCModel>
+    (
+        cstrIter()(mesh, primalVars, adjointVars, dict)
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+const labelList& ATCModel::getZeroATCcells()
+{
+    return zeroATCcells_->getZeroATCcells();
+}
+
+
+scalar ATCModel::getExtraConvectionMultiplier()
+{
+    return extraConvection_;
+}
+
+
+scalar ATCModel::getExtraDiffusionMultiplier()
+{
+    return extraDiffusion_;
+}
+
+
+const volScalarField& ATCModel::getLimiter() const
+{
+    return ATClimiter_;
+}
+
+
+void ATCModel::computeLimiter
+(
+    volScalarField& limiter,
+    const labelList& cells,
+    const label nSmooth
+)
+{
+    // Restore values
+    limiter.primitiveFieldRef() = 1;
+    limiter.correctBoundaryConditions();
+
+    // Set to zero in predefined cells
+    for (const label celli : cells)
+    {
+        limiter[celli] = Zero;
+    }
+
+    // Correct bcs to get the correct value for boundary faces
+    limiter.correctBoundaryConditions();
+
+    // Apply "laplacian" smoother
+    const fvMesh& mesh = limiter.mesh();
+    const localMin<scalar> scheme(mesh);
+    for (label iLimit = 0; iLimit < nSmooth; ++iLimit)
+    {
+        surfaceScalarField faceLimiter
+        (
+            scheme.interpolate(limiter)
+        );
+        limiter = fvc::average(faceLimiter);
+    }
+}
+
+
+tmp<volScalarField> ATCModel::createLimiter
+(
+    const fvMesh& mesh,
+    const dictionary& dict
+)
+{
+    autoPtr<zeroATCcells> zeroType(zeroATCcells::New(mesh, dict));
+    const labelList& zeroCells = zeroType->getZeroATCcells();
+    const label nSmooth = dict.lookupOrDefault<label>("nSmooth", 0);
+
+    tmp<volScalarField> tlimiter
+    (
+        new volScalarField
+        (
+           IOobject
+           (
+               "limiter",
+               mesh.time().timeName(),
+               mesh,
+               IOobject::NO_READ,
+               IOobject::NO_WRITE
+           ),
+           mesh,
+           dimensionedScalar("limiter", dimless, 1.0),
+           zeroGradientFvPatchField<scalar>::typeName
+        )
+    );
+    volScalarField& limiter = tlimiter.ref();
+
+    computeLimiter(limiter, zeroCells, nSmooth);
+
+    return tlimiter;
+}
+
+
+bool ATCModel::writeData(Ostream&) const
+{
+    // Does nothing
+    return true;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModel.H b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModel.H
new file mode 100644
index 0000000000000000000000000000000000000000..9911248648a3ac2c33ee36c2318e10e25ef5c954
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModel.H
@@ -0,0 +1,220 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::ATCModel
+
+Description
+    Base class for selecting the adjoint transpose convection model.
+    Inherits from regIOobject to add lookup functionality
+
+
+SourceFiles
+    ATCModel.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ATCModel_H
+#define ATCModel_H
+
+#include "regIOobject.H"
+#include "autoPtr.H"
+#include "zeroATCcells.H"
+#include "incompressibleVars.H"
+#include "incompressibleAdjointVars.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                          Class ATCModel Declaration
+\*---------------------------------------------------------------------------*/
+
+class ATCModel
+:
+    public regIOobject
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        ATCModel(const ATCModel&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const ATCModel&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        const fvMesh& mesh_;
+        const incompressibleVars& primalVars_;
+        const incompressibleAdjointVars& adjointVars_;
+
+
+        const dictionary& dict_;
+        const scalar extraConvection_;
+        const scalar extraDiffusion_;
+        const label nSmooth_;
+        const bool reconstructGradients_;
+        word adjointSolverName_;
+        autoPtr<zeroATCcells> zeroATCcells_;
+        volScalarField ATClimiter_;
+        volVectorField ATC_;
+
+
+    // Protected functions
+
+        //- Compute limiter based on the cells given by zeroATCcells
+        void computeLimiter();
+
+        //- Limit ATC field using ATClimiter_
+        void smoothATC();
+
+
+public:
+
+    //- Runtime type information
+    TypeName("ATCModel");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            ATCModel,
+            dictionary,
+            (
+                const fvMesh& mesh,
+                const incompressibleVars& primalVars,
+                const incompressibleAdjointVars& adjointVars,
+                const dictionary& dict
+            ),
+            (mesh, primalVars, adjointVars, dict)
+        );
+
+
+    // Constructors
+
+        //- Construct from components
+        ATCModel
+        (
+            const fvMesh& mesh,
+            const incompressibleVars& primalVars,
+            const incompressibleAdjointVars& adjointVars,
+            const dictionary& dict
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<ATCModel> New
+        (
+            const fvMesh& mesh,
+            const incompressibleVars& primalVars,
+            const incompressibleAdjointVars& adjointVars,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~ATCModel() = default;
+
+
+    // Member Functions
+
+        //- Add ATC to the given matrix
+        virtual void addATC(fvVectorMatrix& UaEqn) = 0;
+
+        //- Get the list of cells on which to zero ATC
+        const labelList& getZeroATCcells();
+
+        //- Get the extra convection multiplier
+        scalar getExtraConvectionMultiplier();
+
+        //- Get the extra diffusion multiplier
+        scalar getExtraDiffusionMultiplier();
+
+        //- Get the list of cells on which to zero ATC
+        const volScalarField& getLimiter() const;
+
+        //- Compute limiter based on the prescribed cells and number of
+        //- smoothing iterations
+        static void computeLimiter
+        (
+            volScalarField& limiter,
+            const labelList& smoothCells,
+            const label nSmooth
+        );
+
+        //- Return a limiter based on given cells.
+        //- For use with classes other than ATC which employ the same smoothing
+        //- mechanism
+        static tmp<volScalarField> createLimiter
+        (
+            const fvMesh& mesh,
+            const dictionary& dict
+        );
+
+        //- Smooth an arbitrary field on a given list of cells
+        template<class Type>
+        void smoothFieldBasedOnCells
+        (
+            GeometricField<Type, fvPatchField, volMesh>& vf,
+            const labelList& cells
+        );
+
+        //- Get the FI sensitivity derivatives term coming from the ATC
+        virtual tmp<volTensorField> getFISensitivityTerm() const = 0;
+
+        //- Dummy writeData function required from regIOobject
+        virtual bool writeData(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+#   include "ATCModelTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModelTemplates.C b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModelTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..cbd6f1f376c6603f5660367ab2b808279113ed0e
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModelTemplates.C
@@ -0,0 +1,63 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "ATCModel.H"
+#include "zeroGradientFvPatchField.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+void Foam::ATCModel::smoothFieldBasedOnCells
+(
+    GeometricField<Type, fvPatchField, volMesh>& vf,
+    const labelList& cells
+)
+{
+    volScalarField limiter
+    (
+        IOobject
+        (
+            vf.name() + "Limiter",
+            mesh_.time().timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        mesh_,
+        dimensionedScalar("limiter", dimless, 1.0),
+        zeroGradientFvPatchField<scalar>::typeName
+    );
+
+    computeLimiter(limiter, cells, nSmooth_);
+
+    //Limit actual field
+    vf *= limiter;
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCUaGradU/ATCUaGradU.C b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCUaGradU/ATCUaGradU.C
new file mode 100644
index 0000000000000000000000000000000000000000..f3564e627aaad3d4dc21493aedb39c0008c596b3
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCUaGradU/ATCUaGradU.C
@@ -0,0 +1,141 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "ATCUaGradU.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(ATCUaGradU, 0);
+addToRunTimeSelectionTable
+(
+    ATCModel,
+    ATCUaGradU,
+    dictionary
+);
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+ATCUaGradU::ATCUaGradU
+(
+    const fvMesh& mesh,
+    const incompressibleVars& primalVars,
+    const incompressibleAdjointVars& adjointVars,
+    const dictionary& dict
+)
+:
+    ATCModel(mesh, primalVars, adjointVars, dict)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void ATCUaGradU::addATC(fvVectorMatrix& UaEqn)
+{
+    const volVectorField& U = primalVars_.U();
+    const volVectorField& Ua = adjointVars_.UaInst();
+    const surfaceScalarField& phi = primalVars_.phi();
+    const surfaceScalarField& phia = adjointVars_.phiaInst();
+
+    // Build Ua to go into the ATC term, based on whether to smooth field or not
+    autoPtr<volVectorField> UaForATC(nullptr);
+    if (reconstructGradients_)
+    {
+        UaForATC.reset(new volVectorField(fvc::reconstruct(phia)));
+    }
+    else
+    {
+        UaForATC.reset(new volVectorField(Ua));
+    }
+
+    // Main ATC term
+    ATC_ = -fvc::grad(UaForATC(), "gradUaATC") & U;
+
+    if (extraConvection_ > 0)
+    {
+        // Implicit part added to increase diagonal dominance
+        // Note: Maybe this needs to be multiplied with the ATClimiter ??
+        UaEqn += extraConvection_*fvm::div(-phi, Ua);
+
+        // correct rhs due to implicitly augmenting the adjoint convection
+        ATC_ += extraConvection_*(fvc::grad(UaForATC(), "gradUaATC")().T() & U);
+    }
+
+    // Zero ATC on cells next to given patch types
+    smoothATC();
+
+    // Actual ATC term
+    UaEqn += fvm::Su(ATC_, Ua);
+}
+
+
+tmp<volTensorField> ATCUaGradU::getFISensitivityTerm() const
+{
+    tmp<volTensorField> tvolSDTerm
+    (
+        new volTensorField
+        (
+            IOobject
+            (
+                "ATCFISensitivityTerm" + type(),
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedTensor(sqr(dimLength)/pow(dimTime, 3), Zero)
+        )
+    );
+    volTensorField& volSDTerm = tvolSDTerm.ref();
+
+    const volVectorField& U = primalVars_.U();
+    const volVectorField& Ua = adjointVars_.Ua();
+
+    //const volScalarField& mask = getLimiter();
+
+    volSDTerm -=
+        Ua.component(0) * fvc::grad(U.component(0) * U)
+      + Ua.component(1) * fvc::grad(U.component(1) * U)
+      + Ua.component(2) * fvc::grad(U.component(2) * U);
+
+    return tvolSDTerm;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCUaGradU/ATCUaGradU.H b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCUaGradU/ATCUaGradU.H
new file mode 100644
index 0000000000000000000000000000000000000000..e3d55729439e5b346ca98db6fe9312b35ef697fb
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCUaGradU/ATCUaGradU.H
@@ -0,0 +1,109 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::ATCUaGradU
+
+Description
+    The ATC formualtion resulting by differentiating the
+    Conservative form of the Momentum equations.
+
+SourceFiles
+    ATCUaGradU.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ATCUaGradU_H
+#define ATCUaGradU_H
+
+#include "ATCModel.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                            Class ATCUaGradU Declaration
+\*---------------------------------------------------------------------------*/
+
+class ATCUaGradU
+:
+    public ATCModel
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        ATCUaGradU(const ATCUaGradU&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const ATCUaGradU&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("UaGradU");
+
+
+    // Constructors
+
+        //- Construct from components
+        ATCUaGradU
+        (
+            const fvMesh& mesh,
+            const incompressibleVars& primalVars,
+            const incompressibleAdjointVars& adjointVars,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~ATCUaGradU() = default;
+
+
+    // Member Functions
+
+        //- Add ATC
+        virtual void addATC(fvVectorMatrix& UaEqn);
+
+        //- Get the FI sensitivity derivatives term coming from the ATC
+        virtual tmp<volTensorField> getFISensitivityTerm() const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCstandard/ATCstandard.C b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCstandard/ATCstandard.C
new file mode 100644
index 0000000000000000000000000000000000000000..ec1df4bedff15c6937d9504e0474234a2cb70503
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCstandard/ATCstandard.C
@@ -0,0 +1,155 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "ATCstandard.H"
+#include "addToRunTimeSelectionTable.H"
+#include "wallFvPatch.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(ATCstandard, 0);
+addToRunTimeSelectionTable
+(
+    ATCModel,
+    ATCstandard,
+    dictionary
+);
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+ATCstandard::ATCstandard
+(
+    const fvMesh& mesh,
+    const incompressibleVars& primalVars,
+    const incompressibleAdjointVars& adjointVars,
+    const dictionary& dict
+)
+:
+    ATCModel(mesh, primalVars, adjointVars, dict)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void ATCstandard::addATC(fvVectorMatrix& UaEqn)
+{
+    const volVectorField& U = primalVars_.U();
+    const volVectorField& Ua = adjointVars_.UaInst();
+    const surfaceScalarField& phi = primalVars_.phi();
+
+    // Build U to go into the ATC term, based on whether to smooth field or not
+    autoPtr<volVectorField> UForATC(nullptr);
+    if (reconstructGradients_)
+    {
+        UForATC.reset(new volVectorField(fvc::reconstruct(phi)));
+    }
+    else
+    {
+        UForATC.reset(new volVectorField(U));
+    }
+
+    // Main ATC term
+    ATC_ = (fvc::grad(UForATC(), "gradUATC") & Ua);
+
+    if (extraConvection_ > 0)
+    {
+        // Implicit part added to increase diagonal dominance
+        // Note: Maybe this needs to be multiplied with the ATClimiter ??
+        UaEqn += extraConvection_*fvm::div(-phi, Ua);
+
+        // correct rhs due to implicitly augmenting the adjoint convection
+        ATC_ += extraConvection_*(fvc::grad(Ua, "gradUaATC")().T() & U);
+    }
+
+    //zero ATC on cells next to given patch types
+    smoothATC();
+
+    // actual ATC term
+    UaEqn += fvm::Su(ATC_, Ua);
+}
+
+
+tmp<volTensorField> ATCstandard::getFISensitivityTerm() const
+{
+    tmp<volTensorField> tvolSDTerm
+    (
+        new volTensorField
+        (
+            IOobject
+            (
+                "ATCFISensitivityTerm" + type(),
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedTensor(sqr(dimLength)/pow(dimTime, 3), Zero)
+        )
+    );
+
+    volTensorField& volSDTerm = tvolSDTerm.ref();
+
+    const volVectorField& U = primalVars_.U();
+    const volVectorField& Ua = adjointVars_.Ua();
+
+    volTensorField gradU(fvc::grad(U));
+
+    // Explicitly correct the boundary gradient to get rid of the
+    // tangential component
+    forAll(mesh_.boundary(), patchI)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        if (isA<wallFvPatch>(patch))
+        {
+            tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
+            const vectorField& nf = tnf();
+            gradU.boundaryFieldRef()[patchI] =
+                nf*U.boundaryField()[patchI].snGrad();
+        }
+    }
+
+    const volScalarField& mask = getLimiter();
+
+    volSDTerm = -(gradU & Ua)*U*mask;
+
+    return tvolSDTerm;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCstandard/ATCstandard.H b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCstandard/ATCstandard.H
new file mode 100644
index 0000000000000000000000000000000000000000..7aa76015d80d109c082531376228e733fd59e215
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCstandard/ATCstandard.H
@@ -0,0 +1,109 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::ATCstandard
+
+Description
+    The ATC formualtion resulting by differentiating the
+    Non-conservative form of the momentum equations.
+
+SourceFiles
+    ATCstandard.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ATCstandard_H
+#define ATCstandard_H
+
+#include "ATCModel.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                           Class ATCstandard Declaration
+\*---------------------------------------------------------------------------*/
+
+class ATCstandard
+:
+    public ATCModel
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        ATCstandard(const ATCstandard&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const ATCstandard&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("standard");
+
+
+    // Constructors
+
+        //- Construct from components
+        ATCstandard
+        (
+            const fvMesh& mesh,
+            const incompressibleVars& primalVars,
+            const incompressibleAdjointVars& adjointVars,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~ATCstandard() = default;
+
+
+    // Member Functions
+
+        //- Add ATC
+        virtual void addATC(fvVectorMatrix& UaEqn);
+
+        //- Get the FI sensitivity derivatives term coming from the ATC
+        virtual tmp<volTensorField> getFISensitivityTerm() const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/cancelATC/cancelATC.C b/src/optimisation/adjointOptimisation/adjoint/ATCModel/cancelATC/cancelATC.C
new file mode 100644
index 0000000000000000000000000000000000000000..8284875d59ae66df02d5c7597e8f80b0e2584457
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/cancelATC/cancelATC.C
@@ -0,0 +1,93 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "cancelATC.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(cancelATC, 0);
+addToRunTimeSelectionTable
+(
+    ATCModel,
+    cancelATC,
+    dictionary
+);
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+cancelATC::cancelATC
+(
+    const fvMesh& mesh,
+    const incompressibleVars& primalVars,
+    const incompressibleAdjointVars& adjointVars,
+    const dictionary& dict
+)
+:
+    ATCModel(mesh, primalVars, adjointVars, dict)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void cancelATC::addATC(fvVectorMatrix& UaEqn)
+{
+    // Do nothing
+}
+
+
+tmp<volTensorField> cancelATC::getFISensitivityTerm() const
+{
+    return
+        tmp<volTensorField>::New
+        (
+            IOobject
+            (
+                "ATCFISensitivityTerm" + type(),
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedTensor(sqr(dimLength)/pow3(dimTime), Zero)
+        );
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/cancelATC/cancelATC.H b/src/optimisation/adjointOptimisation/adjoint/ATCModel/cancelATC/cancelATC.H
new file mode 100644
index 0000000000000000000000000000000000000000..4c7a5c58cf134fabaad7d8069f87b06bbd7f83f6
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/cancelATC/cancelATC.H
@@ -0,0 +1,110 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::cancelATC
+
+Description
+    Return a zero ATC field. Seriously influences computed sensitivities
+
+
+SourceFiles
+    cancelATC.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef cancelATC_H
+#define cancelATC_H
+
+#include "ATCModel.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                           Class adjointTurbulenceModel Declaration
+\*---------------------------------------------------------------------------*/
+
+class cancelATC
+:
+    public ATCModel
+{
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        cancelATC(const cancelATC&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const cancelATC&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("cancel");
+
+
+    // Constructors
+
+        //- Construct from components
+        cancelATC
+        (
+            const fvMesh& mesh,
+            const incompressibleVars& primalVars,
+            const incompressibleAdjointVars& adjointVars,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~cancelATC() = default;
+
+
+    // Member Functions
+
+        //- Add ATC
+        virtual void addATC(fvVectorMatrix& UaEqn);
+
+        //- Get the FI sensitivity derivatives term coming from the ATC
+        virtual tmp<volTensorField> getFISensitivityTerm() const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/faceCells/faceCells.C b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/faceCells/faceCells.C
new file mode 100644
index 0000000000000000000000000000000000000000..a89cf925a6556ad3302ae076ee74f54ac1124f0f
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/faceCells/faceCells.C
@@ -0,0 +1,84 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "faceCells.H"
+#include "fvMesh.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(faceCells, 0);
+addToRunTimeSelectionTable(zeroATCcells, faceCells, dictionary);
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+faceCells::faceCells
+(
+    const fvMesh& mesh,
+    const dictionary& dict
+)
+:
+    zeroATCcells(mesh, dict)
+{
+    for (const fvPatch& patch : mesh_.boundary())
+    {
+        for (const word& patchType : zeroATCPatches_)
+        {
+            if (patch.type() == patchType)
+            {
+                const labelList& faceCells_ = patch.faceCells();
+                zeroATCcells_.append(faceCells_);
+            }
+        }
+    }
+
+    for (const label zoneID: zeroATCZones_)
+    {
+        if (zoneID !=-1)
+        {
+            const labelList& zoneCells = mesh_.cellZones()[zoneID];
+            zeroATCcells_.append(zoneCells);
+        }
+    }
+    label size = zeroATCcells_.size();
+    reduce(size, sumOp<label>());
+    Info<< "Setting limiter on " << size << " cells" << nl << endl;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/faceCells/faceCells.H b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/faceCells/faceCells.H
new file mode 100644
index 0000000000000000000000000000000000000000..080ee0aa8ddac25533f25e3f47b1bb6028710c49
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/faceCells/faceCells.H
@@ -0,0 +1,101 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::faceCells
+
+Description
+    Smooth ATC in cells next to a set of patches supplied by type
+
+SourceFiles
+    faceCells.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef faceCells_H
+#define faceCells_H
+
+#include "zeroATCcells.H"
+#include "IOdictionary.H"
+#include "autoPtr.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                           Class adjointTurbulenceModel Declaration
+\*---------------------------------------------------------------------------*/
+
+class faceCells
+:
+    public zeroATCcells
+{
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        faceCells(const faceCells&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const faceCells&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("faceCells");
+
+
+    // Constructors
+
+        //- Construct from components
+        faceCells
+        (
+            const fvMesh& mesh,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~faceCells() = default;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/pointCells/pointCells.C b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/pointCells/pointCells.C
new file mode 100644
index 0000000000000000000000000000000000000000..ba7c40aed2aaccd12504cedb6eec21e769a40d43
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/pointCells/pointCells.C
@@ -0,0 +1,92 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "pointCells.H"
+#include "fvMesh.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(pointCells, 0);
+addToRunTimeSelectionTable(zeroATCcells, pointCells, dictionary);
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+pointCells::pointCells
+(
+    const fvMesh& mesh,
+    const dictionary& dict
+)
+:
+    zeroATCcells(mesh, dict)
+{
+    forAll(mesh_.boundary(), patchI)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        for (const word& patchType : zeroATCPatches_)
+        {
+            if (patch.type() == patchType)
+            {
+                const labelList& meshPoints =
+                    mesh_.boundaryMesh()[patchI].meshPoints();
+
+                for (const label pointI : meshPoints)
+                {
+                    const labelList& pointCells = mesh_.pointCells()[pointI];
+                    zeroATCcells_.append(pointCells);
+                }
+            }
+        }
+    }
+    forAll(zeroATCZones_, zI)
+    {
+        const label& zoneID = zeroATCZones_[zI];
+        if (zoneID != -1)
+        {
+            const labelList& zoneCells = mesh_.cellZones()[zoneID];
+            zeroATCcells_.append(zoneCells);
+        }
+    }
+    /*
+    label size = zeroATCcells_.size();
+    reduce(size, sumOp<label>());
+    Info<< "Zeroing ATC on "<< size << " cells" << nl << endl;
+    */
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/pointCells/pointCells.H b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/pointCells/pointCells.H
new file mode 100644
index 0000000000000000000000000000000000000000..a1545a81b8dfb9fb963aa022047aaee4e63b8d1b
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/pointCells/pointCells.H
@@ -0,0 +1,100 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::pointCells
+
+Description
+    Smooth ATC in cells having a point to a set of patches supplied by type
+
+SourceFiles
+    pointCells.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef pointCells_H
+#define pointCells_H
+
+#include "zeroATCcells.H"
+#include "IOdictionary.H"
+#include "autoPtr.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                           Class adjointTurbulenceModel Declaration
+\*---------------------------------------------------------------------------*/
+
+class pointCells
+:
+    public zeroATCcells
+{
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        pointCells(const pointCells&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const pointCells&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("pointCells");
+
+    // Constructors
+
+        //- Construct from components
+        pointCells
+        (
+            const fvMesh& mesh,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~pointCells() = default;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/zeroATCcells/zeroATCcells.C b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/zeroATCcells/zeroATCcells.C
new file mode 100644
index 0000000000000000000000000000000000000000..4afa06e624107de8d4138ebb6f9ae2809c4f626c
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/zeroATCcells/zeroATCcells.C
@@ -0,0 +1,111 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "zeroATCcells.H"
+#include "fvMesh.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(zeroATCcells, 0);
+defineRunTimeSelectionTable(zeroATCcells, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+zeroATCcells::zeroATCcells
+(
+    const fvMesh& mesh,
+    const dictionary& dict
+)
+:
+    mesh_(mesh),
+    zeroATCPatches_
+    (
+        dict.lookupOrDefault<wordList>("zeroATCPatchTypes", wordList())
+    ),
+    zeroATCZones_(0),
+    zeroATCcells_(0)
+{
+    if (dict.found("zeroATCZones"))
+    {
+        const wordList zeroATCZoneNames(dict.get<wordList>("zeroATCZones"));
+        zeroATCZones_ = labelList(zeroATCZoneNames.size(), -1);
+        forAll(zeroATCZoneNames, zI)
+        {
+            label zoneID = mesh.cellZones().findZoneID(zeroATCZoneNames[zI]);
+            if (zoneID == -1)
+            {
+                WarningInFunction
+                    << "cannot find cellZone "
+                    << zeroATCZoneNames[zI]
+                    << " for smoothing ATC"
+                    << endl;
+            }
+            zeroATCZones_[zI] = zoneID;
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+autoPtr<zeroATCcells> zeroATCcells::New
+(
+    const fvMesh& mesh,
+    const dictionary& dict
+)
+{
+    const word modelType
+    (
+        dict.lookupOrDefault<word>("maskType", "faceCells")
+    );
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
+
+    if (!cstrIter.found())
+    {
+        FatalIOErrorInFunction(dict)
+            << "Unknown zeroATCcells type " << modelType << nl << nl
+            << "Valid zeroATCcells types are :" << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalIOError);
+    }
+
+    return autoPtr<zeroATCcells> (cstrIter()(mesh,dict));
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/zeroATCcells/zeroATCcells.H b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/zeroATCcells/zeroATCcells.H
new file mode 100644
index 0000000000000000000000000000000000000000..5155f87f0fb9c889dc74238ce2a38ea6e814558c
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/zeroATCcells/zeroATCcells.H
@@ -0,0 +1,141 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::zeroATCcells
+
+Description
+    Base class for selecting cells on which to zero the ATC term
+
+SourceFiles
+    zeroATCcells.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef zeroATCcells_H
+#define zeroATCcells_H
+
+#include "IOdictionary.H"
+#include "autoPtr.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+class fvMesh;
+
+/*---------------------------------------------------------------------------*\
+                           Class adjointTurbulenceModel Declaration
+\*---------------------------------------------------------------------------*/
+
+class zeroATCcells
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        zeroATCcells(const zeroATCcells&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const zeroATCcells&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        const fvMesh& mesh_;
+        wordList zeroATCPatches_;
+        labelList zeroATCZones_;
+        labelList zeroATCcells_;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("zeroATCcells");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            zeroATCcells,
+            dictionary,
+            (
+                const fvMesh& mesh,
+                const dictionary& dict
+            ),
+            (mesh, dict)
+        );
+
+    // Constructors
+
+        //- Construct from components
+        zeroATCcells
+        (
+            const fvMesh& mesh,
+            const dictionary& dict
+        );
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<zeroATCcells> New
+        (
+            const fvMesh& mesh,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~zeroATCcells() = default;
+
+
+    // Member Functions
+
+        //- Get the zeroATCcells
+        inline const labelList& getZeroATCcells()
+        {
+            return zeroATCcells_;
+        }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/Make/files b/src/optimisation/adjointOptimisation/adjoint/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..b736bb15cc27e993e02795f1a606d0b47507171b
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/Make/files
@@ -0,0 +1,116 @@
+/* TURBULENCE MODEL VARIABLE REFS */
+turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.C
+turbulenceModels/turbulenceModelVariables/RAS/laminar/laminar.C
+turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.C
+turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.C
+turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.C
+turbulenceModels/turbulenceModelVariables/RAS/LaunderSharmaKE/LaunderSharmaKE.C
+
+/* VARIABLES SET */
+solvers/variablesSet/variablesSet/variablesSet.C
+solvers/variablesSet/incompressible/incompressibleVars.C
+solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.C
+solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.C
+
+/* SOLVER CONTROL */
+solvers/solverControl/solverControl/solverControl.C
+solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.C
+solvers/solverControl/SIMPLEControl/singleRun/SIMPLEControlSingleRun.C
+
+/* SOLVERS */
+solvers/solver/solver.C
+solvers/primalSolvers/primalSolver/primalSolver.C
+solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.C
+solvers/primalSolvers/incompressible/simple/simple.C
+solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.C
+solvers/adjointSolvers/adjointSolver/adjointSolver.C
+solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.C
+solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C
+
+/* ADJOINT SOLVER MANAGER */
+solvers/adjointSolverManager/adjointSolverManager.C
+
+/* ZERO ATC CELLS OPTIONS*/
+ATCModel/zeroATCcells/zeroATCcells/zeroATCcells.C
+ATCModel/zeroATCcells/faceCells/faceCells.C
+ATCModel/zeroATCcells/pointCells/pointCells.C
+
+/* ATC MODELS */
+ATCModel/ATCModel/ATCModel.C
+ATCModel/ATCstandard/ATCstandard.C
+ATCModel/ATCUaGradU/ATCUaGradU.C
+ATCModel/cancelATC/cancelATC.C
+
+/* ADJOINT FVOPTIONS */
+fvOptionsAdjoint/fvOptions/fvOptionAdjoint.C
+fvOptionsAdjoint/fvOptions/fvOptionAdjointList.C
+fvOptionsAdjoint/fvOptions/fvIOoptionListAdjoint.C
+
+/* OBJECTIVES */
+objectives/objective/objective.C
+objectives/incompressible/objectiveIncompressible/objectiveIncompressible.C
+objectives/incompressible/objectiveForce/objectiveForce.C
+objectives/incompressible/objectiveMoment/objectiveMoment.C
+objectives/incompressible/objectivePtLosses/objectivePtLosses.C
+
+/* OBJECTIVE MANAGER*/
+objectiveManager/objectiveManager/objectiveManager.C
+objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.C
+
+/* BOUNDARY ADJOINT CONTRIBUTIONS */
+boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.C
+boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.C
+
+/* ADJOINT TURBULENCE MODELS*/
+turbulenceModels/incompressibleAdjoint/adjointTurbulenceModel/adjointTurbulenceModel.C
+turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.C
+turbulenceModels/incompressibleAdjoint/adjointRAS/adjointLaminar/adjointLaminar.C
+turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.C
+turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointInletNuaTilda/adjointInletNuaTildaFvPatchScalarField.C
+turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTilda/adjointOutletNuaTildaFvPatchScalarField.C
+turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointFarFieldNuaTilda/adjointFarFieldNuaTildaFvPatchScalarField.C
+turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTildaFlux/adjointOutletNuaTildaFluxFvPatchScalarField.C
+turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletFlux/adjointOutletFluxFvPatchScalarField.C
+
+/* ADJOINT BOUNDARY CONDITIONS */
+adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryCondition.C
+adjointBoundaryConditions/adjointInletVelocity/adjointInletVelocityFvPatchVectorField.C
+adjointBoundaryConditions/adjointOutletVelocity/adjointOutletVelocityFvPatchVectorField.C
+adjointBoundaryConditions/adjointWallVelocity/adjointWallVelocityFvPatchVectorField.C
+adjointBoundaryConditions/adjointWallVelocityLowRe/adjointWallVelocityLowReFvPatchVectorField.C
+adjointBoundaryConditions/adjointOutletPressure/adjointOutletPressureFvPatchScalarField.C
+adjointBoundaryConditions/adjointFarFieldPressure/adjointFarFieldPressureFvPatchScalarField.C
+adjointBoundaryConditions/adjointFarFieldVelocity/adjointFarFieldVelocityFvPatchVectorField.C
+adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchFields.C
+adjointBoundaryConditions/adjointOutletVelocityFlux/adjointOutletVelocityFluxFvPatchVectorField.C
+
+/* DELTA BOUNDARY */
+deltaBoundary/deltaBoundary.C
+
+/* ADJOINT SENSITIVITY */
+optimisation/adjointSensitivity/sensitivity/sensitivity.C
+incoSens=optimisation/adjointSensitivity/incompressible
+$(incoSens)/adjointSensitivity/adjointSensitivityIncompressible.C
+$(incoSens)/adjointEikonalSolver/adjointEikonalSolverIncompressible.C
+$(incoSens)/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.C
+$(incoSens)/sensitivitySurface/sensitivitySurfaceIncompressible.C
+$(incoSens)/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.C
+$(incoSens)/sensitivityMultiple/sensitivityMultipleIncompressible.C
+
+/* LINE SEARCH */
+optimisation/lineSearch/lineSearch/lineSearch.C
+optimisation/lineSearch/stepUpdate/stepUpdate/stepUpdate.C
+
+/* UPDATE METHOD */
+optimisation/updateMethod/updateMethod/updateMethod.C
+optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.C
+
+/* OPTIMIZATION TYPE */
+incoOptType=optimisation/optimisationType/incompressible
+$(incoOptType)/optimisationType/optimisationTypeIncompressible.C
+
+/* OPTIMIZATION MANAGER */
+optimisation/optimisationManager/optimisationManager/optimisationManager.C
+optimisation/optimisationManager/singleRun/singleRun.C
+
+LIB = $(FOAM_LIBBIN)/libadjointOptimisation
diff --git a/src/optimisation/adjointOptimisation/adjoint/Make/options b/src/optimisation/adjointOptimisation/adjoint/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..44dec84580915e1aaa7dbfd4be72b95d756be05e
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/Make/options
@@ -0,0 +1,25 @@
+EXE_INC = \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/surfMesh/lnInclude \
+    -I$(LIB_SRC)/sampling/lnInclude \
+    -I$(LIB_SRC)/TurbulenceModels/turbulenceModels \
+    -I$(LIB_SRC)/TurbulenceModels/incompressible/lnInclude \
+    -I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
+    -I$(LIB_SRC)/transportModels \
+    -I$(LIB_SRC)/transportModels/incompressible/singlePhaseTransportModel \
+    -I$(LIB_SRC)/fvMotionSolver/lnInclude \
+    -I$(LIB_SRC)/dynamicMesh/lnInclude \
+    -I$(LIB_SRC)/fvOptions/lnInclude
+
+LIB_LIBS = \
+    -lfiniteVolume \
+    -lmeshTools \
+    -lsurfMesh \
+    -lsampling \
+    -lturbulenceModels \
+    -lincompressibleTurbulenceModels \
+    -lincompressibleTransportModels \
+    -lfvMotionSolvers \
+    -ldynamicMesh \
+    -lfvOptions
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryCondition.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryCondition.C
new file mode 100644
index 0000000000000000000000000000000000000000..34efed7088a30f24c51efcc8d37efe8bad7f765d
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryCondition.C
@@ -0,0 +1,151 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointBoundaryCondition.H"
+#include "ATCUaGradU.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(adjointBoundaryCondition, 0);
+
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+bool adjointBoundaryCondition::addATCUaGradUTerm()
+{
+    if (addATCUaGradUTerm_.empty())
+    {
+        addATCUaGradUTerm_.reset(new bool(isA<ATCUaGradU>(getATC())));
+    }
+    return addATCUaGradUTerm_();
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointBoundaryCondition::adjointBoundaryCondition
+(
+    const adjointBoundaryCondition& adjointBC
+)
+:
+    patch_(adjointBC.patch_),
+    managerName_(adjointBC.managerName_),
+    adjointSolverName_(adjointBC.adjointSolverName_),
+    simulationType_(adjointBC.simulationType_),
+    boundaryContrPtr_
+    (
+        boundaryAdjointContribution::New
+        (
+            adjointBC.managerName_,
+            adjointBC.adjointSolverName_,
+            adjointBC.simulationType_,
+            adjointBC.patch_
+        )
+    ),
+    addATCUaGradUTerm_(adjointBC.addATCUaGradUTerm_)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+const word& adjointBoundaryCondition::objectiveManagerName() const
+{
+    return managerName_;
+}
+
+
+const word& adjointBoundaryCondition::adjointSolverName() const
+{
+    return adjointSolverName_;
+}
+
+
+const word& adjointBoundaryCondition::simulationType() const
+{
+    return simulationType_;
+}
+
+
+void adjointBoundaryCondition::setBoundaryContributionPtr()
+{
+    // Note:
+    // Check whether there is an objectiveFunctionManager object in the registry
+    // Necessary for decomposePar if the libadjoint is loaded
+    // through controlDict. A nicer way should be found
+    const fvMesh& meshRef = patch_.boundaryMesh().mesh();
+    if (meshRef.foundObject<regIOobject>(managerName_))
+    {
+        boundaryContrPtr_.reset
+        (
+            boundaryAdjointContribution::New
+            (
+                managerName_,
+                adjointSolverName_,
+                simulationType_,
+                patch_
+            ).ptr()
+        );
+    }
+    else
+    {
+        WarningInFunction
+            << "No objectiveManager " << managerName_ << " available." << nl
+            << "Setting boundaryAdjointContributionPtr to nullptr. " << nl
+            << "OK for decomposePar."
+            << endl;
+    }
+}
+
+
+boundaryAdjointContribution&
+adjointBoundaryCondition::getBoundaryAdjContribution()
+{
+    return boundaryContrPtr_();
+}
+
+
+const ATCModel& adjointBoundaryCondition::getATC() const
+{
+    return
+        patch_.boundaryMesh().mesh().lookupObject<ATCModel>
+        (
+            "ATCModel" + adjointSolverName_
+        );
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryCondition.H b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryCondition.H
new file mode 100644
index 0000000000000000000000000000000000000000..5d2b306400212305f2da897104a059ea663775c9
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryCondition.H
@@ -0,0 +1,159 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointBoundaryCondition
+
+Description
+    Base class for solution control classes
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointBoundaryCondition_H
+#define adjointBoundaryCondition_H
+
+#include "boundaryAdjointContribution.H"
+#include "ATCModel.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                  Class adjointBoundaryCondition Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointBoundaryCondition
+{
+protected:
+
+    // Protected data
+
+        //- Reference to patch
+        const fvPatch& patch_;
+
+        //- objectiveManager name corresponding to field
+        word managerName_;
+
+        //- adjointSolver name corresponding to field
+        word adjointSolverName_;
+
+        //- simulationType corresponding to field.
+        //  A placeholder for now
+        word simulationType_;
+
+        //- Engine to manage contributions of the objective functions
+        //- to the adjoint boundary conditions
+        autoPtr<boundaryAdjointContribution> boundaryContrPtr_;
+
+
+        //- Whether to add the extra term from the UaGradU formulation
+        //  autoPtr since ATCModel has not been allocated at the time
+        //  adjointBoundaryConditions are constructed
+        autoPtr<bool> addATCUaGradUTerm_;
+
+
+    // Protected Member Functions
+
+        //- Get gradient of field on a specific boundary
+        template<class Type>
+        tmp
+        <
+            Field<typename Foam::outerProduct<Foam::vector, Type>::type>
+        > computePatchGrad(word name);
+
+        //- Whether to add the extra term from the UaGradU formulation
+        bool addATCUaGradUTerm();
+
+
+public:
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("adjointBoundaryCondition");
+
+
+    // Constructors
+
+        //- Construct from field and base name
+        template<class Type>
+        adjointBoundaryCondition
+        (
+            const fvPatch& p,
+            const DimensionedField<Type, volMesh>& iF,
+            const word& solverName
+        );
+
+        //- Construct as copy
+        adjointBoundaryCondition(const adjointBoundaryCondition&);
+
+
+    //- Destructor
+    virtual ~adjointBoundaryCondition() = default;
+
+
+    // Member Functions
+
+        // Access
+
+            //- Return objectiveManager name
+            const word& objectiveManagerName() const;
+
+            //- Return adjointSolverName
+            const word& adjointSolverName() const;
+
+            //- Return the simulationType
+            const word& simulationType() const;
+
+            //- Set the ptr to the correct boundaryAdjointContribution
+            void setBoundaryContributionPtr();
+
+            //- Get boundaryContribution
+            boundaryAdjointContribution& getBoundaryAdjContribution();
+
+            //- ATC type might be useful for a number of BCs. Return here
+            const ATCModel& getATC() const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "adjointBoundaryConditionTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryConditionTemplates.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryConditionTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..61d9f9075bf2a89ab48a1aabb8f2e3f41dc29270
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryConditionTemplates.C
@@ -0,0 +1,166 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "emptyFvPatch.H"
+#include "adjointBoundaryCondition.H"
+#include "adjointSolverManager.H"
+#include "HashTable.H"
+#include "surfaceInterpolationScheme.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+template<class Type>
+tmp
+<
+    Field<typename Foam::outerProduct<Foam::vector, Type>::type>
+>
+adjointBoundaryCondition::computePatchGrad(word name)
+{
+    // Return field
+    typedef typename outerProduct<vector, Type>::type GradType;
+    auto tresGrad = tmp<Field<GradType>>::New(patch_.size(), Zero);
+    auto& resGrad = tresGrad.ref();
+
+    const labelList& faceCells = patch_.faceCells();
+    const fvMesh& mesh = patch_.boundaryMesh().mesh();
+    const cellList& cells = mesh.cells();
+
+    // Go through the surfaceInterpolation scheme defined in gradSchemes for
+    // consistency
+    const GeometricField<Type, fvPatchField, volMesh>& field =
+        mesh.lookupObject<volVectorField>(name);
+
+    // Gives problems when grad(AdjointVar) is computed using a limited scheme,
+    // since it is not possible to know a priori how many words to expect in the
+    // stream.
+    // Interpolation scheme is now read through interpolation schemes.
+    /*
+    word  gradSchemeName       ("grad(" + name + ')');
+    Istream& is = mesh.gradScheme(gradSchemeName);
+    word schemeData(is);
+    */
+
+    tmp<surfaceInterpolationScheme<Type>> tinterpScheme
+    (
+        surfaceInterpolationScheme<Type>::New
+        (
+            mesh,
+            mesh.interpolationScheme("interpolate(" + name + ")")
+        )
+    );
+
+    GeometricField<Type, fvsPatchField, surfaceMesh> surfField
+    (
+        tinterpScheme().interpolate(field)
+    );
+
+    // Auxiliary fields
+    const surfaceVectorField& Sf = mesh.Sf();
+    tmp<vectorField> tnf = patch_.nf();
+    const vectorField& nf = tnf();
+    const scalarField& V = mesh.V();
+    const labelUList& owner = mesh.owner();
+
+    // Compute grad value of cell adjacent to the boundary
+    forAll(faceCells, fI)
+    {
+        const label cI = faceCells[fI];
+        const cell& cellI = cells[cI];
+        for (const label faceI : cellI) // global face numbering
+        {
+            label patchID = mesh.boundaryMesh().whichPatch(faceI);
+            if (patchID == -1) //face is internal
+            {
+                const label own = owner[faceI];
+                tensor flux = Sf[faceI]*surfField[faceI];
+                if (cI == own)
+                {
+                    resGrad[fI] += flux;
+                }
+                else
+                {
+                    resGrad[fI] -= flux;
+                }
+            }
+            else  // Face is boundary. Covers coupled patches as well
+            {
+                if (!isA<emptyFvPatch>(mesh.boundary()[patchID]))
+                {
+                    const fvPatch& patchForFlux = mesh.boundary()[patchID];
+                    const label boundaryFaceI = faceI - patchForFlux.start();
+                    const vectorField& Sfb = Sf.boundaryField()[patchID];
+                    resGrad[fI] +=
+                        Sfb[boundaryFaceI]
+                       *surfField.boundaryField()[patchID][boundaryFaceI];
+                }
+            }
+        }
+        resGrad[fI] /= V[cI];
+    }
+
+    // This has concluded the computation of the grad at the cell next to the
+    // boundary. We now need to compute the grad at the boundary face
+    const fvPatchField<Type>& bField = field.boundaryField()[patch_.index()];
+    resGrad = nf*bField.snGrad() + (resGrad - nf*(nf & resGrad));
+
+    return tresGrad;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+template<class Type>
+adjointBoundaryCondition::adjointBoundaryCondition
+(
+    const fvPatch& p,
+    const DimensionedField<Type, volMesh>& iF,
+    const word& solverName
+)
+:
+    patch_(p),
+    managerName_("objectiveManager" + solverName),
+    adjointSolverName_(solverName),
+    simulationType_("incompressible"),
+    boundaryContrPtr_(nullptr),
+    addATCUaGradUTerm_(nullptr)
+{
+    // Set the boundaryContribution pointer
+    setBoundaryContributionPtr();
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointFarFieldPressure/adjointFarFieldPressureFvPatchScalarField.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointFarFieldPressure/adjointFarFieldPressureFvPatchScalarField.C
new file mode 100644
index 0000000000000000000000000000000000000000..faa9b4c86f28bdaa50ba817c85584d62b07c08fa
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointFarFieldPressure/adjointFarFieldPressureFvPatchScalarField.C
@@ -0,0 +1,474 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointFarFieldPressureFvPatchScalarField.H"
+#include "addToRunTimeSelectionTable.H"
+#include "fvPatchFieldMapper.H"
+#include "volFields.H"
+#include "surfaceFields.H"
+#include "ATCUaGradU.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::adjointFarFieldPressureFvPatchScalarField::
+adjointFarFieldPressureFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(p, iF),
+    adjointBoundaryCondition(p, iF, word::null)
+{}
+
+
+Foam::adjointFarFieldPressureFvPatchScalarField::
+adjointFarFieldPressureFvPatchScalarField
+(
+    const adjointFarFieldPressureFvPatchScalarField& ptf,
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchScalarField(ptf, p, iF, mapper),
+    adjointBoundaryCondition(p, iF, ptf.adjointSolverName_)
+{}
+
+
+Foam::adjointFarFieldPressureFvPatchScalarField::
+adjointFarFieldPressureFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchScalarField(p, iF),
+    adjointBoundaryCondition(p, iF, dict.get<word>("solverName"))
+{
+    fvPatchField<scalar>::operator=
+    (
+        scalarField("value", dict, p.size())
+    );
+}
+
+
+Foam::adjointFarFieldPressureFvPatchScalarField::
+adjointFarFieldPressureFvPatchScalarField
+(
+    const adjointFarFieldPressureFvPatchScalarField& tppsf,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(tppsf, iF),
+    adjointBoundaryCondition(tppsf)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::updateCoeffs()
+{
+    if (updated())
+    {
+        return;
+    }
+
+    // Patch normal and surface
+    const scalarField& magSf = patch().magSf();
+    const vectorField nf(patch().nf());
+
+    // Primal flux
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+
+    // Adjoint flux
+    //const fvsPatchField<scalar>& phiap =
+    //    patch().lookupPatchField<surfaceScalarField, scalar>("phia");
+
+    // Primal velocity
+    const fvPatchField<vector>& Up = boundaryContrPtr_->Ub();
+
+    // Adjoint velocity
+    const fvPatchField<vector>& Uap = boundaryContrPtr_->Uab();
+
+    // Patch-adjacent normal adjoint velocity
+    scalarField Uac_n(Uap.patchInternalField()() & nf);
+
+    // Patch normal adjoint velocity
+    scalarField Uap_n(Uap & nf);
+    //scalarField Uap_n = phiap/magSf;
+
+    // Patch normal velocity Uap_n
+    scalarField phiOverSurf(phip/magSf);
+
+    // Patch deltas
+    const scalarField& delta = patch().deltaCoeffs();
+
+    // snGrad Ua_n
+    scalarField snGradUan(delta*(Uap_n - Uac_n));
+
+    // Momentum diffusion coefficient
+    tmp<scalarField> tmomentumDiffusion =
+        boundaryContrPtr_->momentumDiffusion();
+    scalarField& momentumDiffusion = tmomentumDiffusion.ref();
+
+    // Objective function and other explicit contributions
+    tmp<scalarField> tsource = boundaryContrPtr_->pressureSource();
+    scalarField source = tsource.ref();
+
+    // Contribution from the ATC part (if UaGradU)
+    if (addATCUaGradUTerm())
+    {
+        source += Uap & Up;
+    }
+
+    operator==
+    (
+        // Inlet
+        neg(phip)*(patchInternalField())
+
+        // Outlet
+      + pos(phip)*
+        (
+            Uap_n*phiOverSurf
+          + 2*momentumDiffusion*snGradUan
+          + source
+        )
+    );
+
+    fixedValueFvPatchScalarField::updateCoeffs();
+}
+
+
+Foam::tmp<Foam::Field<Foam::scalar>>
+Foam::adjointFarFieldPressureFvPatchScalarField::snGrad() const
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+
+    return tmp<Field<scalar>>
+    (
+        new Field<scalar>
+        (
+            pos(phip)*patch().deltaCoeffs()*(*this - patchInternalField())
+        )
+    );
+}
+
+
+Foam::tmp<Foam::Field<Foam::scalar>>
+Foam::adjointFarFieldPressureFvPatchScalarField::valueInternalCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+
+    return tmp<Field<scalar>>
+    (
+        new Field<scalar>
+        (
+            neg(phip)*pTraits<scalar>::one
+        )
+    );
+}
+
+
+Foam::tmp<Foam::Field<Foam::scalar>>
+Foam::adjointFarFieldPressureFvPatchScalarField::valueBoundaryCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+
+    return tmp<Field<scalar>>
+    (
+        new Field<scalar>
+        (
+            pos(phip)*(*this)
+        )
+    );
+}
+
+
+Foam::tmp<Foam::Field<Foam::scalar>>
+Foam::adjointFarFieldPressureFvPatchScalarField::gradientInternalCoeffs() const
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+
+    // Act as a zeroGradient pa bc
+    return tmp<Field<scalar>>
+    (
+        new Field<scalar>
+        (
+            -pos(phip)*pTraits<scalar>::one*(this->patch().deltaCoeffs())
+        )
+    );
+}
+
+
+Foam::tmp<Foam::Field<Foam::scalar>>
+Foam::adjointFarFieldPressureFvPatchScalarField::gradientBoundaryCoeffs() const
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+
+    // Act as a zeroGradient pa bc
+    return tmp<Field<scalar>>
+    (
+        new Field<scalar>
+        (
+            pos(phip)*(this->patch().deltaCoeffs()*(*this))
+        )
+    );
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::write(Ostream& os) const
+{
+    fvPatchScalarField::write(os);
+    writeEntry("value", os);
+    os.writeEntry("solverName", adjointSolverName_);
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator=
+(
+    const UList<scalar>& ul
+)
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*ul + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator=
+(
+    const fvPatchField<scalar>& ptf
+)
+{
+    check(ptf);
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*ptf + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator+=
+(
+    const fvPatchField<scalar>& ptf
+)
+{
+    check(ptf);
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*((*this) + ptf) + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator-=
+(
+    const fvPatchField<scalar>& ptf
+)
+{
+    check(ptf);
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*((*this) - ptf) + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator*=
+(
+    const fvPatchField<scalar>& ptf
+)
+{
+    if (&patch() != &ptf.patch())
+    {
+        FatalErrorInFunction
+            << "Incompatible patches for patch fields"
+            << abort(FatalError);
+    }
+
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*((*this)*ptf) + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator/=
+(
+    const fvPatchField<scalar>& ptf
+)
+{
+    if (&patch() != &ptf.patch())
+    {
+        FatalErrorInFunction
+            << "Incompatible patches for patch fields"
+            << abort(FatalError);
+    }
+
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*((*this)/ptf) + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator+=
+(
+    const Field<scalar>& tf
+)
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*((*this) + tf) + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator-=
+(
+    const Field<scalar>& tf
+)
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*((*this)-tf) + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator*=
+(
+    const scalarField& tf
+)
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*((*this)*tf) + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator/=
+(
+    const scalarField& tf
+)
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*((*this)/tf) + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator=
+(
+    const scalar t
+)
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*t + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator+=
+(
+    const scalar t
+)
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*((*this) + t) + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator-=
+(
+    const scalar t
+)
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value
+    (
+        neg(phip)*((*this)-t)
+      + pos(phip)*(*this)
+    );
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator*=
+(
+    const scalar s
+)
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*((*this)*s) + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+void Foam::adjointFarFieldPressureFvPatchScalarField::operator/=
+(
+    const scalar s
+)
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    scalarField value(neg(phip)*((*this)/s) + pos(phip)*(*this));
+
+    Field<scalar>::operator=(value);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    makePatchTypeField
+    (
+        fvPatchScalarField,
+        adjointFarFieldPressureFvPatchScalarField
+    );
+}
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointFarFieldPressure/adjointFarFieldPressureFvPatchScalarField.H b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointFarFieldPressure/adjointFarFieldPressureFvPatchScalarField.H
new file mode 100644
index 0000000000000000000000000000000000000000..dc7aacfcc068f07330d8269d21b5d3ddc40e4e38
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointFarFieldPressure/adjointFarFieldPressureFvPatchScalarField.H
@@ -0,0 +1,196 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointFarFieldPressureFvPatchScalarField
+
+Description
+
+SourceFiles
+    adjointFarFieldPressureFvPatchScalarField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointFarFieldPressureFvPatchScalarField_H
+#define adjointFarFieldPressureFvPatchScalarField_H
+
+#include "fvPatchFields.H"
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                Class adjointOutletPressureFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointFarFieldPressureFvPatchScalarField
+:
+    public fixedValueFvPatchScalarField,
+    public adjointBoundaryCondition
+{
+public:
+
+    //- Runtime type information
+    TypeName("adjointFarFieldPressure");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointFarFieldPressureFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointFarFieldPressureFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given adjointOutletPressureFvPatchScalarField
+        // onto a new patch
+        adjointFarFieldPressureFvPatchScalarField
+        (
+            const adjointFarFieldPressureFvPatchScalarField&,
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchScalarField> clone() const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointFarFieldPressureFvPatchScalarField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointFarFieldPressureFvPatchScalarField
+        (
+            const adjointFarFieldPressureFvPatchScalarField&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchScalarField> clone
+        (
+            const DimensionedField<scalar, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointFarFieldPressureFvPatchScalarField(*this, iF)
+            );
+        }
+
+
+    // Member functions
+
+        //- Return true if this patch field fixes a value.
+        //  Needed to check if a level has to be specified while solving
+        //  Poissons equations.
+        /*
+        virtual bool fixesValue() const
+        {
+            return true;
+        }
+        */
+        //- Return gradient at boundary
+        virtual tmp<Field<scalar>> snGrad() const;
+
+        //- Return the matrix diagonal coefficients corresponding to the
+        //- evaluation of the value of this patchField with given weights
+        virtual tmp<Field<scalar>> valueInternalCoeffs
+        (
+            const tmp<scalarField>&
+        ) const;
+
+        //- Return the matrix source coefficients corresponding to the
+        //  evaluation of the value of this patchField with given weights
+        virtual tmp<Field<scalar>> valueBoundaryCoeffs
+        (
+            const tmp<scalarField>&
+        ) const;
+
+        //- Return the matrix diagonal coefficients corresponding to the
+        //- evaluation of the gradient of this patchField
+        virtual tmp<Field<scalar>> gradientInternalCoeffs() const;
+
+        //- Return the matrix source coefficients corresponding to the
+        //- evaluation of the gradient of this patchField
+        virtual tmp<Field<scalar>> gradientBoundaryCoeffs() const;
+
+        //- Update the coefficients associated with the patch field
+        virtual void updateCoeffs();
+
+        //- Write
+        virtual void write(Ostream&) const;
+
+
+    // Member operators
+
+        virtual void operator=(const UList<scalar>&);
+
+        virtual void operator=(const fvPatchField<scalar>&);
+        virtual void operator+=(const fvPatchField<scalar>&);
+        virtual void operator-=(const fvPatchField<scalar>&);
+        virtual void operator*=(const fvPatchField<scalar>&);
+        virtual void operator/=(const fvPatchField<scalar>&);
+
+        virtual void operator+=(const Field<scalar>&);
+        virtual void operator-=(const Field<scalar>&);
+
+        virtual void operator*=(const Field<scalar>&);
+        virtual void operator/=(const Field<scalar>&);
+
+        virtual void operator=(const scalar);
+        virtual void operator+=(const scalar);
+        virtual void operator-=(const scalar);
+        virtual void operator*=(const scalar);
+        virtual void operator/=(const scalar);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointFarFieldVelocity/adjointFarFieldVelocityFvPatchVectorField.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointFarFieldVelocity/adjointFarFieldVelocityFvPatchVectorField.C
new file mode 100644
index 0000000000000000000000000000000000000000..1c805ae87b188f9021f119a717bd64b7dd479c92
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointFarFieldVelocity/adjointFarFieldVelocityFvPatchVectorField.C
@@ -0,0 +1,204 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointFarFieldVelocityFvPatchVectorField.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::adjointFarFieldVelocityFvPatchVectorField::
+adjointFarFieldVelocityFvPatchVectorField
+(
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF
+)
+:
+    fixedValueFvPatchVectorField(p, iF),
+    adjointBoundaryCondition(p, iF, word::null)
+{}
+
+
+Foam::adjointFarFieldVelocityFvPatchVectorField::
+adjointFarFieldVelocityFvPatchVectorField
+(
+    const adjointFarFieldVelocityFvPatchVectorField& ptf,
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchVectorField(ptf, p, iF, mapper),
+    adjointBoundaryCondition(p, iF, ptf.adjointSolverName_)
+{}
+
+
+Foam::adjointFarFieldVelocityFvPatchVectorField::
+adjointFarFieldVelocityFvPatchVectorField
+(
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchVectorField(p, iF),
+    adjointBoundaryCondition(p, iF, dict.get<word>("solverName"))
+{
+    fvPatchField<vector>::operator=
+    (
+        vectorField("value", dict, p.size())
+    );
+}
+
+
+Foam::adjointFarFieldVelocityFvPatchVectorField::
+adjointFarFieldVelocityFvPatchVectorField
+(
+    const adjointFarFieldVelocityFvPatchVectorField& pivpvf,
+    const DimensionedField<vector, volMesh>& iF
+)
+:
+    fixedValueFvPatchVectorField(pivpvf, iF),
+    adjointBoundaryCondition(pivpvf)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::adjointFarFieldVelocityFvPatchVectorField::updateCoeffs()
+{
+    if (updated())
+    {
+        return;
+    }
+
+    const scalarField& faceMag = patch().magSf();
+    const vectorField nf(patch().nf());
+
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+
+    scalarField phiOverSurf(phip/faceMag);
+
+    // Ua patch adjacent
+    vectorField Uac(this->patchInternalField());
+
+    // Tangent component of internalField
+    vectorField Uac_t(Uac - nf*(Uac & nf));
+
+    // Inverse distance
+    const scalarField& delta = patch().deltaCoeffs();
+
+    // Objective function and other explicit contributions for
+    // zeroGradient boundaries
+    tmp<vectorField> tsourceVelocity =
+        boundaryContrPtr_->tangentVelocitySource();
+    vectorField& sourceVelocity = tsourceVelocity.ref();
+
+    // Objective function contribution for fixedValue boundaries
+    tmp<vectorField> tsourcePressure =
+        boundaryContrPtr_->normalVelocitySource();
+    vectorField& sourcePressure = tsourcePressure.ref();
+
+    // Momentum diffusion coefficient
+    tmp<scalarField> tmomentumDiffusion =
+        boundaryContrPtr_->momentumDiffusion();
+    scalarField& momentumDiffusion = tmomentumDiffusion.ref();
+
+    scalarField denom(phiOverSurf + momentumDiffusion*delta);
+
+    operator==
+    (
+        // Inlet
+      - neg(phip)*sourcePressure
+
+        // Outlet
+      + pos(phip)
+       *((Uac&nf)*nf + (Uac_t*(momentumDiffusion*delta) - sourceVelocity)/denom)
+    );
+
+    fixedValueFvPatchVectorField::updateCoeffs();
+}
+
+
+Foam::tmp<Foam::Field<Foam::vector>>
+Foam::adjointFarFieldVelocityFvPatchVectorField::valueInternalCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+
+    // For fixedValue U patches
+    return tmp<Field<vector>>
+    (
+        new Field<vector>
+        (
+            neg(phip)*pTraits<vector>::one
+        )
+    );
+}
+
+
+Foam::tmp<Foam::Field<Foam::vector>>
+Foam::adjointFarFieldVelocityFvPatchVectorField::valueBoundaryCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+
+    // For zeroGradient U patches
+    return tmp<Field<vector>>
+    (
+        new Field<vector>
+        (
+            pos(phip)*(*this)
+        )
+    );
+}
+
+
+void Foam::adjointFarFieldVelocityFvPatchVectorField::write(Ostream& os) const
+{
+    fvPatchVectorField::write(os);
+    writeEntry("value", os);
+    os.writeEntry("solverName", adjointSolverName_);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    makePatchTypeField
+    (
+        fvPatchVectorField,
+        adjointFarFieldVelocityFvPatchVectorField
+    );
+}
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointFarFieldVelocity/adjointFarFieldVelocityFvPatchVectorField.H b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointFarFieldVelocity/adjointFarFieldVelocityFvPatchVectorField.H
new file mode 100644
index 0000000000000000000000000000000000000000..5fe8b76b64b2a4feabbf6c28dd228ebf0923b8fe
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointFarFieldVelocity/adjointFarFieldVelocityFvPatchVectorField.H
@@ -0,0 +1,153 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointFarFieldVelocityFvPatchVectorField
+
+Description
+
+SourceFiles
+    adjointFarFieldVelocityFvPatchVectorField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointFarFieldVelocityFvPatchVectorField_H
+#define adjointFarFieldVelocityFvPatchVectorField_H
+
+#include "fvPatchFields.H"
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+               Class adjointFarFieldVelocityFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointFarFieldVelocityFvPatchVectorField
+:
+    public fixedValueFvPatchVectorField,
+    public adjointBoundaryCondition
+{
+public:
+
+    //- Runtime type information
+    TypeName("adjointFarFieldVelocity");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointFarFieldVelocityFvPatchVectorField
+        (
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointFarFieldVelocityFvPatchVectorField
+        (
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given adjointFarFieldVelocityFvPatchVectorField
+        //- onto a new patch
+        adjointFarFieldVelocityFvPatchVectorField
+        (
+            const adjointFarFieldVelocityFvPatchVectorField&,
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchVectorField> clone() const
+        {
+            return tmp<fvPatchVectorField>
+            (
+                new adjointFarFieldVelocityFvPatchVectorField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointFarFieldVelocityFvPatchVectorField
+        (
+            const adjointFarFieldVelocityFvPatchVectorField&,
+            const DimensionedField<vector, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchVectorField> clone
+        (
+            const DimensionedField<vector, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchVectorField>
+            (
+                new adjointFarFieldVelocityFvPatchVectorField(*this, iF)
+            );
+        }
+
+
+    // Member functions
+
+        //- Update the coefficients associated with the patch field
+        virtual void updateCoeffs();
+
+        //- Return the matrix diagonal coefficients corresponding to the
+        //- evaluation of the value of this patchField with given weights
+        virtual tmp<Field<vector>> valueInternalCoeffs
+        (
+            const tmp<scalarField>&
+        ) const;
+
+        //- Return the matrix source coefficients corresponding to the
+        //- evaluation of the value of this patchField with given weights
+        virtual tmp<Field<vector>> valueBoundaryCoeffs
+        (
+            const tmp<scalarField>&
+        ) const;
+
+        //- Write
+        virtual void write(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointInletVelocity/adjointInletVelocityFvPatchVectorField.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointInletVelocity/adjointInletVelocityFvPatchVectorField.C
new file mode 100644
index 0000000000000000000000000000000000000000..0b5b20a15e1b67857db64930f02b1d4ef799c84c
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointInletVelocity/adjointInletVelocityFvPatchVectorField.C
@@ -0,0 +1,150 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointInletVelocityFvPatchVectorField.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::adjointInletVelocityFvPatchVectorField::
+adjointInletVelocityFvPatchVectorField
+(
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF
+)
+:
+    fixedValueFvPatchVectorField(p, iF),
+    adjointBoundaryCondition(p, iF, word::null)
+{}
+
+
+Foam::adjointInletVelocityFvPatchVectorField::
+adjointInletVelocityFvPatchVectorField
+(
+    const adjointInletVelocityFvPatchVectorField& ptf,
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchVectorField(ptf, p, iF, mapper),
+    adjointBoundaryCondition(p, iF, ptf.adjointSolverName_)
+{}
+
+
+Foam::adjointInletVelocityFvPatchVectorField::
+adjointInletVelocityFvPatchVectorField
+(
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchVectorField(p, iF),
+    adjointBoundaryCondition(p, iF, dict.get<word>("solverName"))
+{
+    fvPatchField<vector>::operator=
+    (
+        vectorField("value", dict, p.size())
+    );
+}
+
+
+Foam::adjointInletVelocityFvPatchVectorField::
+adjointInletVelocityFvPatchVectorField
+(
+    const adjointInletVelocityFvPatchVectorField& pivpvf,
+    const DimensionedField<vector, volMesh>& iF
+)
+:
+    fixedValueFvPatchVectorField(pivpvf, iF),
+    adjointBoundaryCondition(pivpvf)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::adjointInletVelocityFvPatchVectorField::updateCoeffs()
+{
+    if (updated())
+    {
+        return;
+    }
+
+    // Objective function contribution
+    tmp<vectorField> tsource = boundaryContrPtr_->normalVelocitySource();
+    const vectorField& source = tsource();
+
+    operator==(-source);
+
+    fixedValueFvPatchVectorField::updateCoeffs();
+}
+
+
+Foam::tmp<Foam::Field<Foam::vector>>
+Foam::adjointInletVelocityFvPatchVectorField::valueInternalCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    return tmp<Field<vector>>::New(this->size(), pTraits<vector>::one);
+}
+
+
+Foam::tmp<Foam::Field<Foam::vector>>
+Foam::adjointInletVelocityFvPatchVectorField::valueBoundaryCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    return tmp<Field<vector>>::New(this->size(), pTraits<vector>::zero);
+}
+
+
+void Foam::adjointInletVelocityFvPatchVectorField::write(Ostream& os) const
+{
+    fvPatchVectorField::write(os);
+    writeEntry("value", os);
+    os.writeEntry("solverName", adjointSolverName_);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    makePatchTypeField
+    (
+        fvPatchVectorField,
+        adjointInletVelocityFvPatchVectorField
+    );
+}
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointInletVelocity/adjointInletVelocityFvPatchVectorField.H b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointInletVelocity/adjointInletVelocityFvPatchVectorField.H
new file mode 100644
index 0000000000000000000000000000000000000000..30ba7eb3a9298386b00841314de59078a519949c
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointInletVelocity/adjointInletVelocityFvPatchVectorField.H
@@ -0,0 +1,157 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointInletVelocityFvPatchVectorField
+
+Description
+
+SourceFiles
+    adjointInletVelocityFvPatchVectorField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointInletVelocityFvPatchVectorField_H
+#define adjointInletVelocityFvPatchVectorField_H
+
+#include "fvPatchFields.H"
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                 Class adjointInletVelocityFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointInletVelocityFvPatchVectorField
+:
+    public fixedValueFvPatchVectorField,
+    public adjointBoundaryCondition
+{
+public:
+
+    //- Runtime type information
+    TypeName("adjointInletVelocity");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointInletVelocityFvPatchVectorField
+        (
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointInletVelocityFvPatchVectorField
+        (
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given adjointInletVelocityFvPatchVectorField
+        //- onto a new patch
+        adjointInletVelocityFvPatchVectorField
+        (
+            const adjointInletVelocityFvPatchVectorField&,
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchVectorField> clone() const
+        {
+            return tmp<fvPatchVectorField>
+            (
+                new adjointInletVelocityFvPatchVectorField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointInletVelocityFvPatchVectorField
+        (
+            const adjointInletVelocityFvPatchVectorField&,
+            const DimensionedField<vector, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchVectorField> clone
+        (
+            const DimensionedField<vector, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchVectorField>
+            (
+                new adjointInletVelocityFvPatchVectorField(*this, iF)
+            );
+        }
+
+
+    // Member functions
+
+        //- Add explicit sink to zero adjoint velocity tangential motion
+        //- at the cells next to the inlet
+        //virtual void manipulateMatrix(fvMatrix<vector>& matrix);
+
+        //- Update the coefficients associated with the patch field
+        virtual void updateCoeffs();
+
+        //- Return the matrix diagonal coefficients corresponding to the
+        //- evaluation of the value of this patchField with given weights
+        virtual tmp<Field<vector>> valueInternalCoeffs
+        (
+            const tmp<scalarField>&
+        ) const;
+
+        //- Return the matrix source coefficients corresponding to the
+        //- evaluation of the value of this patchField with given weights
+        virtual tmp<Field<vector>> valueBoundaryCoeffs
+        (
+            const tmp<scalarField>&
+        ) const;
+
+        //- Write
+        virtual void write(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletPressure/adjointOutletPressureFvPatchScalarField.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletPressure/adjointOutletPressureFvPatchScalarField.C
new file mode 100644
index 0000000000000000000000000000000000000000..8a9ddf6a8b3a17dfc544d7ed132d7eb959f7bc7e
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletPressure/adjointOutletPressureFvPatchScalarField.C
@@ -0,0 +1,179 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointOutletPressureFvPatchScalarField.H"
+#include "addToRunTimeSelectionTable.H"
+#include "fvPatchFieldMapper.H"
+#include "volFields.H"
+#include "surfaceFields.H"
+#include "emptyFvPatch.H"
+#include "ATCUaGradU.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::adjointOutletPressureFvPatchScalarField::
+adjointOutletPressureFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(p, iF),
+    adjointBoundaryCondition(p, iF, word::null)
+{}
+
+
+Foam::adjointOutletPressureFvPatchScalarField::
+adjointOutletPressureFvPatchScalarField
+(
+    const adjointOutletPressureFvPatchScalarField& ptf,
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchScalarField(ptf, p, iF, mapper),
+    adjointBoundaryCondition(p, iF, ptf.adjointSolverName_)
+{}
+
+
+Foam::adjointOutletPressureFvPatchScalarField::
+adjointOutletPressureFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchScalarField(p, iF),
+    adjointBoundaryCondition(p, iF, dict.get<word>("solverName"))
+{
+    fvPatchField<scalar>::operator=
+    (
+        scalarField("value", dict, p.size())
+    );
+}
+
+
+Foam::adjointOutletPressureFvPatchScalarField::
+adjointOutletPressureFvPatchScalarField
+(
+    const adjointOutletPressureFvPatchScalarField& tppsf,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(tppsf, iF),
+    adjointBoundaryCondition(tppsf)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::adjointOutletPressureFvPatchScalarField::updateCoeffs()
+{
+    if (updated())
+    {
+        return;
+    }
+
+    // Patch normal and surface
+    const scalarField& magSf = patch().magSf();
+    const vectorField nf(patch().nf());
+
+    // Primal flux
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    const fvPatchField<vector>& Up = boundaryContrPtr_->Ub();
+
+    // Adjoint velocity
+    const fvPatchField<vector>& Uap = boundaryContrPtr_->Uab();
+    scalarField snGradUan(Uap.snGrad() & nf);
+
+    // Patch normal adjoint velocity
+    scalarField Uap_n(Uap & nf);
+
+    // Patch normal velocity
+    scalarField phiOverSurf(phip/magSf);
+
+    // Momentum diffusion coefficient
+    tmp<scalarField> tmomentumDiffusion =
+        boundaryContrPtr_->momentumDiffusion();
+    const scalarField& momentumDiffusion = tmomentumDiffusion();
+
+    // Part of the diffusive flux related to div(nuEff*dev(grad(Ua).T()))
+    const word& UaName = boundaryContrPtr_->Uab().internalField().name();
+    tmp<tensorField> tgradUab = computePatchGrad<vector>(UaName);
+    const tensorField& gradUab = tgradUab();
+    vectorField explDiffusiveFlux
+    (
+        momentumDiffusion*(gradUab - sphericalTensor::oneThirdI*tr(gradUab))
+      & nf
+    );
+    scalarField normalExplDifFlux(explDiffusiveFlux & nf);
+
+    // Objective function and other explicit contributions
+    tmp<scalarField> tsource = boundaryContrPtr_->pressureSource();
+    scalarField& source = tsource.ref();
+
+    // Contribution from the ATC part (if UaGradU)
+    if (addATCUaGradUTerm())
+    {
+        source += Uap & Up;
+    }
+
+    operator==
+    (
+        (Uap_n*phiOverSurf)
+      + momentumDiffusion*snGradUan
+      + normalExplDifFlux
+      + source
+    );
+
+    fixedValueFvPatchScalarField::updateCoeffs();
+}
+
+
+void Foam::adjointOutletPressureFvPatchScalarField::write(Ostream& os) const
+{
+    fvPatchScalarField::write(os);
+    writeEntry("value", os);
+    os.writeEntry("solverName", adjointSolverName_);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    makePatchTypeField
+    (
+        fvPatchScalarField,
+        adjointOutletPressureFvPatchScalarField
+    );
+}
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletPressure/adjointOutletPressureFvPatchScalarField.H b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletPressure/adjointOutletPressureFvPatchScalarField.H
new file mode 100644
index 0000000000000000000000000000000000000000..802ab7511140a350b24805112f8b03568da20bca
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletPressure/adjointOutletPressureFvPatchScalarField.H
@@ -0,0 +1,142 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointOutletPressureFvPatchScalarField
+
+Description
+
+SourceFiles
+    adjointOutletPressureFvPatchScalarField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointOutletPressureFvPatchScalarField_H
+#define adjointOutletPressureFvPatchScalarField_H
+
+#include "fvPatchFields.H"
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                Class adjointOutletPressureFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointOutletPressureFvPatchScalarField
+:
+    public fixedValueFvPatchScalarField,
+    public adjointBoundaryCondition
+{
+public:
+
+    //- Runtime type information
+    TypeName("adjointOutletPressure");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointOutletPressureFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointOutletPressureFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given
+        //- adjointOutletPressureFvPatchScalarField- onto a new patch
+        adjointOutletPressureFvPatchScalarField
+        (
+            const adjointOutletPressureFvPatchScalarField&,
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchScalarField> clone() const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointOutletPressureFvPatchScalarField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointOutletPressureFvPatchScalarField
+        (
+            const adjointOutletPressureFvPatchScalarField&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchScalarField> clone
+        (
+            const DimensionedField<scalar, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointOutletPressureFvPatchScalarField(*this, iF)
+            );
+        }
+
+
+    // Member functions
+
+        // Evaluation functions
+
+            //- Update the coefficients associated with the patch field
+            virtual void updateCoeffs();
+
+
+        //- Write
+        virtual void write(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletVelocity/adjointOutletVelocityFvPatchVectorField.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletVelocity/adjointOutletVelocityFvPatchVectorField.C
new file mode 100644
index 0000000000000000000000000000000000000000..6738d0e89f5898dbff130f804e9062f226d24a5b
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletVelocity/adjointOutletVelocityFvPatchVectorField.C
@@ -0,0 +1,194 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointOutletVelocityFvPatchVectorField.H"
+#include "addToRunTimeSelectionTable.H"
+#include "emptyFvPatch.H"
+
+// * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
+
+void Foam::adjointOutletVelocityFvPatchVectorField::assignBoundaryValue()
+{
+    const scalarField& magSf = patch().magSf();
+    tmp<vectorField> tnf(patch().nf());
+    const vectorField& nf = tnf();
+
+    // Primal normal velocity
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+    const scalarField phiOverSurf(phip/magSf);
+
+    // Ua patch adjacent
+    vectorField Uac(this->patchInternalField());
+
+    // Tangent component of internalField
+    vectorField Uac_t(Uac - nf*(Uac & nf));
+
+    // Adjoint normal velocity
+    const fvsPatchField<scalar>& phiab = boundaryContrPtr_->phiab();
+
+    // Inverse distance
+    const scalarField& delta = patch().deltaCoeffs();
+
+    // Objective function and other explicit contributions
+    tmp<vectorField> tsource(boundaryContrPtr_->tangentVelocitySource());
+    const vectorField& source = tsource();
+
+    // Momentum diffusion coefficient
+    tmp<scalarField> tmomentumDiffusion
+    (
+        boundaryContrPtr_->momentumDiffusion()
+    );
+    const scalarField& momentumDiffusion = tmomentumDiffusion();
+
+    // Part of the diffusive flux related to div(nuEff*dev(grad(Ua).T()))
+    const word& fieldName = internalField().name();
+    tmp<tensorField> tgradUaf(computePatchGrad<vector>(fieldName));
+    const tensorField& gradUaf = tgradUaf();
+    const vectorField explDiffusiveFlux
+    (
+        momentumDiffusion
+       *(gradUaf - sphericalTensor::oneThirdI*tr(gradUaf)) & nf
+    );
+    const vectorField explDiffusiveFlux_t
+    (
+        explDiffusiveFlux - (explDiffusiveFlux & nf)*nf
+    );
+
+    // Auxiliary quantities
+    scalarField nd(momentumDiffusion*delta);
+    // Denominator. Susceptible to zero values in case of back flow
+    // Should use adjointOutletVelocityFlux in such cases.
+    scalarField denom(phiOverSurf + nd);
+
+    vectorField Uat((nd*Uac_t - explDiffusiveFlux_t - source)/denom);
+
+    operator==((phiab/magSf)*nf + Uat);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::adjointOutletVelocityFvPatchVectorField::
+adjointOutletVelocityFvPatchVectorField
+(
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF
+)
+:
+    fixedValueFvPatchVectorField(p, iF),
+    adjointBoundaryCondition(p, iF, word::null)
+{}
+
+
+Foam::adjointOutletVelocityFvPatchVectorField::
+adjointOutletVelocityFvPatchVectorField
+(
+    const adjointOutletVelocityFvPatchVectorField& ptf,
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchVectorField(ptf, p, iF, mapper),
+    adjointBoundaryCondition(p, iF, ptf.adjointSolverName_)
+{}
+
+
+Foam::adjointOutletVelocityFvPatchVectorField::
+adjointOutletVelocityFvPatchVectorField
+(
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchVectorField(p, iF),
+    adjointBoundaryCondition(p, iF, dict.get<word>("solverName"))
+{
+    fvPatchField<vector>::operator=
+    (
+         vectorField("value", dict, p.size())
+    );
+}
+
+
+Foam::adjointOutletVelocityFvPatchVectorField::
+adjointOutletVelocityFvPatchVectorField
+(
+    const adjointOutletVelocityFvPatchVectorField& pivpvf,
+    const DimensionedField<vector, volMesh>& iF
+)
+:
+    fixedValueFvPatchVectorField(pivpvf, iF),
+    adjointBoundaryCondition(pivpvf)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::adjointOutletVelocityFvPatchVectorField::evaluate
+(
+    const Pstream::commsTypes
+)
+{
+    assignBoundaryValue();
+    fvPatchVectorField::evaluate();
+}
+
+
+void Foam::adjointOutletVelocityFvPatchVectorField::write(Ostream& os) const
+{
+    fvPatchVectorField::write(os);
+    writeEntry("value", os);
+    os.writeEntry("solverName", adjointSolverName_);
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+void Foam::adjointOutletVelocityFvPatchVectorField::operator=
+(
+    const fvPatchField<vector>& pvf
+)
+{
+    fvPatchField<vector>::operator=(patch().nf()*(patch().nf() & pvf));
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    makePatchTypeField
+    (
+        fvPatchVectorField,
+        adjointOutletVelocityFvPatchVectorField
+    );
+}
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletVelocity/adjointOutletVelocityFvPatchVectorField.H b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletVelocity/adjointOutletVelocityFvPatchVectorField.H
new file mode 100644
index 0000000000000000000000000000000000000000..4f16a968af32324528b52c589cba17cb410dc1ea
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletVelocity/adjointOutletVelocityFvPatchVectorField.H
@@ -0,0 +1,170 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointOutletVelocityFvPatchVectorField
+
+Description
+    Provides the adjoint outlet velocity values (i.e. adjoint velocity in
+    case of a zeroGradient U boundary condition). Can have stability issues
+    in cases of backflow of the primal velocity.
+    The adjointOutletVelocityFlux should preferably be used.
+
+
+SourceFiles
+    adjointOutletVelocityFvPatchVectorField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointOutletVelocityFvPatchVectorField_H
+#define adjointOutletVelocityFvPatchVectorField_H
+
+#include "fvPatchFields.H"
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                Class adjointOutletVelocityFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointOutletVelocityFvPatchVectorField
+:
+    public fixedValueFvPatchVectorField,
+    public adjointBoundaryCondition
+{
+    // Private Member Functions
+
+        void assignBoundaryValue();
+
+
+public:
+
+    //- Runtime type information
+    TypeName("adjointOutletVelocity");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointOutletVelocityFvPatchVectorField
+        (
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointOutletVelocityFvPatchVectorField
+        (
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given adjointOutletVelocityFvPatchVectorField
+        //- onto a new patch
+        adjointOutletVelocityFvPatchVectorField
+        (
+            const adjointOutletVelocityFvPatchVectorField&,
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchVectorField> clone() const
+        {
+            return tmp<fvPatchVectorField>
+            (
+                new adjointOutletVelocityFvPatchVectorField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointOutletVelocityFvPatchVectorField
+        (
+            const adjointOutletVelocityFvPatchVectorField&,
+            const DimensionedField<vector, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchVectorField> clone
+        (
+            const DimensionedField<vector, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchVectorField>
+            (
+                new adjointOutletVelocityFvPatchVectorField(*this, iF)
+            );
+        }
+
+
+
+    // Member functions
+
+        //- Return true: Allow adjoint solvers to obtain the outlet phia
+        //  value through HbyA
+        virtual bool assignable() const
+        {
+            return true;
+        }
+
+        //- Update the coefficients associated with the patch field
+        //  Apply adjoint BCs through evaluate rather than updateCoeffs
+        //  in order to have the correct Ua boundaryField when computing the
+        //  adjoint pressure BC
+        virtual void evaluate
+        (
+            const Pstream::commsTypes commsType = Pstream::commsTypes::blocking
+        );
+
+        //virtual void updateCoeffs();
+
+        //- Write
+        virtual void write(Ostream&) const;
+
+
+    // Member operators
+
+        virtual void operator=(const fvPatchField<vector>& pvf);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletVelocityFlux/adjointOutletVelocityFluxFvPatchVectorField.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletVelocityFlux/adjointOutletVelocityFluxFvPatchVectorField.C
new file mode 100644
index 0000000000000000000000000000000000000000..71f90d10e35ef5d32c76674287b815e12939d58e
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletVelocityFlux/adjointOutletVelocityFluxFvPatchVectorField.C
@@ -0,0 +1,232 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointOutletVelocityFluxFvPatchVectorField.H"
+#include "emptyFvPatch.H"
+#include "fvMatrix.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::adjointOutletVelocityFluxFvPatchVectorField::
+adjointOutletVelocityFluxFvPatchVectorField
+(
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF
+)
+:
+    fixedValueFvPatchVectorField(p, iF),
+    adjointBoundaryCondition(p, iF, word::null)
+{}
+
+
+Foam::adjointOutletVelocityFluxFvPatchVectorField::
+adjointOutletVelocityFluxFvPatchVectorField
+(
+    const adjointOutletVelocityFluxFvPatchVectorField& ptf,
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchVectorField(ptf, p, iF, mapper),
+    adjointBoundaryCondition(p, iF, ptf.adjointSolverName_)
+{}
+
+
+Foam::adjointOutletVelocityFluxFvPatchVectorField::
+adjointOutletVelocityFluxFvPatchVectorField
+(
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchVectorField(p, iF),
+    adjointBoundaryCondition(p, iF, dict.get<word>("solverName"))
+{
+    fvPatchField<vector>::operator=
+    (
+         vectorField("value", dict, p.size())
+    );
+}
+
+
+Foam::adjointOutletVelocityFluxFvPatchVectorField::
+adjointOutletVelocityFluxFvPatchVectorField
+(
+    const adjointOutletVelocityFluxFvPatchVectorField& pivpvf,
+    const DimensionedField<vector, volMesh>& iF
+)
+:
+    fixedValueFvPatchVectorField(pivpvf, iF),
+    adjointBoundaryCondition(pivpvf)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::adjointOutletVelocityFluxFvPatchVectorField::manipulateMatrix
+(
+    fvMatrix<vector>& matrix
+)
+{
+    vectorField& source = matrix.source();
+    const vectorField& Sf = patch().Sf();
+    const labelList& faceCells = patch().faceCells();
+    const scalarField& magSf = patch().magSf();
+    tmp<vectorField> tvelocitySource(boundaryContrPtr_->velocitySource());
+    const vectorField& velocitySource = tvelocitySource();
+    const fvPatchScalarField& pab = boundaryContrPtr_->pab();
+    const word& fieldName = internalField().name();
+    tmp<tensorField> tgradUab(computePatchGrad<vector>(fieldName));
+    const tensorField& gradUab = tgradUab();
+
+    // Momentum diffusion coefficient
+    tmp<scalarField> tmomentumDiffusion(boundaryContrPtr_->momentumDiffusion());
+    const scalarField& momentumDiffusion = tmomentumDiffusion();
+
+    vectorField explDiffusiveFlux
+    (
+        -momentumDiffusion*(gradUab - sphericalTensor::oneThirdI*tr(gradUab))
+       & Sf
+    );
+
+//  const fvPatchVectorField& Ub = boundaryContrPtr_->Ub();
+//  const fvPatchVectorField& Uab = boundaryContrPtr_->Uab();
+//  vectorField cmFormTerm = (Ub & Uab)*Sf;
+
+    forAll(faceCells, fI)
+    {
+        const label cI = faceCells[fI];
+        // Contributions from the convection and diffusion term (except from
+        // the transpose part) will be canceled out through the value and
+        // gradient coeffs. The pressure flux will be inserted later through
+        // grad(pa), so it must be canceled out here. Once the typical fluxes
+        // have been canceled out, add the objective flux. velocitySource
+        // includes also fluxes from the adjoint turbulence-dependent terms
+        // found in the adjoint momentum equations.
+        source[cI] +=
+            pab[fI]*Sf[fI]
+//        - cmFormTerm[fI]
+          + explDiffusiveFlux[fI]
+          - velocitySource[fI]*magSf[fI];
+    }
+}
+
+
+void Foam::adjointOutletVelocityFluxFvPatchVectorField::updateCoeffs()
+{
+    if (updated())
+    {
+        return;
+    }
+
+    tmp<vectorField> tnf = patch().nf();
+    const vectorField& nf = tnf();
+
+    // vectorField Ua = (patchInternalField() & nf) * nf;
+    const fvsPatchScalarField& phia = boundaryContrPtr_->phiab();
+    vectorField Ua((phia/patch().magSf())*nf);
+
+    operator==(Ua);
+
+    fixedValueFvPatchVectorField::updateCoeffs();
+}
+
+
+Foam::tmp<Foam::Field<Foam::vector>>
+Foam::adjointOutletVelocityFluxFvPatchVectorField::valueInternalCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    return tmp<Field<vector>>::New(this->size(), pTraits<vector>::zero);
+}
+
+
+Foam::tmp<Foam::Field<Foam::vector>>
+Foam::adjointOutletVelocityFluxFvPatchVectorField::valueBoundaryCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    return tmp<Field<vector>>::New(this->size(), pTraits<vector>::zero);
+}
+
+
+Foam::tmp<Foam::Field<Foam::vector>>
+Foam::adjointOutletVelocityFluxFvPatchVectorField::
+gradientBoundaryCoeffs() const
+{
+    return tmp<Field<vector>>::New(this->size(), pTraits<vector>::zero);
+}
+
+
+Foam::tmp<Foam::Field<Foam::vector>>
+Foam::adjointOutletVelocityFluxFvPatchVectorField::
+gradientInternalCoeffs() const
+{
+    return tmp<Field<vector>>::New(this->size(), pTraits<vector>::zero);
+}
+
+
+void Foam::adjointOutletVelocityFluxFvPatchVectorField::write
+(
+    Ostream& os
+) const
+{
+    fvPatchVectorField::write(os);
+    writeEntry("value", os);
+    os.writeEntry("solverName", adjointSolverName_);
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+void Foam::adjointOutletVelocityFluxFvPatchVectorField::operator=
+(
+    const fvPatchField<vector>& pvf
+)
+{
+    fvPatchField<vector>::operator=(patch().nf()*(patch().nf() & pvf));
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    makePatchTypeField
+    (
+        fvPatchVectorField,
+        adjointOutletVelocityFluxFvPatchVectorField
+    );
+}
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletVelocityFlux/adjointOutletVelocityFluxFvPatchVectorField.H b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletVelocityFlux/adjointOutletVelocityFluxFvPatchVectorField.H
new file mode 100644
index 0000000000000000000000000000000000000000..74ef39a4b8879310e6e659938de85d26038e803c
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointOutletVelocityFlux/adjointOutletVelocityFluxFvPatchVectorField.H
@@ -0,0 +1,190 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointOutletVelocityFluxFvPatchVectorField
+
+Description
+
+    An outlet boundary condition for patches in which the primal flow exhibits
+    recirculation. Adds the contribution of the objective as an adjoint
+    momentum flux directly to the PDEs, without the need to first compute an
+    adjoint outlet velocity, circumventing thus the division with (almost) zero
+    that manifests in case of primal flow recirculation.
+
+SourceFiles
+    adjointOutletVelocityFluxFvPatchVectorField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointOutletVelocityFluxFvPatchVectorField_H
+#define adjointOutletVelocityFluxFvPatchVectorField_H
+
+#include "fvPatchFields.H"
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+               Class adjointOutletVelocityFluxFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointOutletVelocityFluxFvPatchVectorField
+:
+    public fixedValueFvPatchVectorField,
+    public adjointBoundaryCondition
+{
+    // Private Member Functions
+
+        tmp<tensorField> computeLocalGrad();
+
+
+public:
+
+    //- Runtime type information
+    TypeName("adjointOutletVelocityFlux");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointOutletVelocityFluxFvPatchVectorField
+        (
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointOutletVelocityFluxFvPatchVectorField
+        (
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given
+        //- adjointOutletVelocityFluxFvPatchVectorField
+        //- onto a new patch
+        adjointOutletVelocityFluxFvPatchVectorField
+        (
+            const adjointOutletVelocityFluxFvPatchVectorField&,
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchVectorField> clone() const
+        {
+            return tmp<fvPatchVectorField>
+            (
+                new adjointOutletVelocityFluxFvPatchVectorField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointOutletVelocityFluxFvPatchVectorField
+        (
+            const adjointOutletVelocityFluxFvPatchVectorField&,
+            const DimensionedField<vector, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchVectorField> clone
+        (
+            const DimensionedField<vector, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchVectorField>
+            (
+                new adjointOutletVelocityFluxFvPatchVectorField(*this, iF)
+            );
+        }
+
+
+
+    // Member functions
+
+        //- Return true: Allow adjoint solvers to obtain the outlet phia
+        //  value through HbyA
+        virtual bool assignable() const
+        {
+            return true;
+        }
+
+        //- add source term in the first cells off the wall due to adjoint WF
+        virtual void manipulateMatrix(fvMatrix<vector>& matrix);
+
+        //- Update the coefficients associated with the patch field
+        virtual void updateCoeffs();
+
+        //- Return the matrix diagonal coefficients corresponding to the
+        //- evaluation of the value of this patchField with given weights
+        virtual tmp<Field<vector>> valueInternalCoeffs
+        (
+            const tmp<scalarField>&
+        ) const;
+
+        //- Return the matrix source coefficients corresponding to the
+        //- evaluation of the value of this patchField with given weights
+        virtual tmp<Field<vector>> valueBoundaryCoeffs
+        (
+            const tmp<scalarField>&
+
+        ) const;
+
+        //- Return the matrix source coefficients corresponding to the
+        //- evaluation of the gradient of this patchField
+        virtual tmp<Field<vector>> gradientBoundaryCoeffs() const;
+
+        //- Return the matrix diagonal coefficients corresponding to the
+        //- evaluation of the gradient of this patchField
+        virtual tmp<Field<vector>> gradientInternalCoeffs() const;
+
+        //- Write
+        virtual void write(Ostream&) const;
+
+
+    // Member operators
+
+        virtual void operator=(const fvPatchField<vector>& pvf);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocity/adjointWallVelocityFvPatchVectorField.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocity/adjointWallVelocityFvPatchVectorField.C
new file mode 100644
index 0000000000000000000000000000000000000000..35a01bf65086e6d637c80f8630f70a7f268d4c96
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocity/adjointWallVelocityFvPatchVectorField.C
@@ -0,0 +1,241 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointWallVelocityFvPatchVectorField.H"
+#include "nutUSpaldingWallFunctionFvPatchScalarField.H"
+#include "fvMatrix.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::adjointWallVelocityFvPatchVectorField::
+adjointWallVelocityFvPatchVectorField
+(
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF
+)
+:
+    fixedValueFvPatchVectorField(p, iF),
+    adjointBoundaryCondition(p, iF, word::null),
+    kappa_(0.41),
+    E_(9.8)
+{}
+
+
+Foam::adjointWallVelocityFvPatchVectorField::
+adjointWallVelocityFvPatchVectorField
+(
+    const adjointWallVelocityFvPatchVectorField& ptf,
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchVectorField(ptf, p, iF, mapper),
+    adjointBoundaryCondition(p, iF, ptf.adjointSolverName_),
+    kappa_(ptf.kappa_),
+    E_(ptf.E_)
+{}
+
+
+Foam::adjointWallVelocityFvPatchVectorField::
+adjointWallVelocityFvPatchVectorField
+(
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchVectorField(p, iF),
+    adjointBoundaryCondition(p, iF, dict.get<word>("solverName")),
+    kappa_(dict.lookupOrDefault<scalar>("kappa", 0.41)),
+    E_(dict.lookupOrDefault<scalar>("E", 9.8))
+{
+    fvPatchField<vector>::operator=
+    (
+        vectorField("value", dict, p.size())
+    );
+}
+
+
+Foam::adjointWallVelocityFvPatchVectorField::
+adjointWallVelocityFvPatchVectorField
+(
+    const adjointWallVelocityFvPatchVectorField& pivpvf,
+    const DimensionedField<vector, volMesh>& iF
+)
+:
+    fixedValueFvPatchVectorField(pivpvf, iF),
+    adjointBoundaryCondition(pivpvf),
+    kappa_(pivpvf.kappa_),
+    E_(pivpvf.E_)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::adjointWallVelocityFvPatchVectorField::manipulateMatrix
+(
+    fvMatrix<vector>& matrix
+)
+{
+    // Grab ref to the diagonal matrix
+    vectorField& source = matrix.source();
+
+    // Define boundary condition type
+    typedef Foam::nutUSpaldingWallFunctionFvPatchScalarField
+        SAwallFunctionPatchField;
+
+    if
+    (
+        isA<SAwallFunctionPatchField>(boundaryContrPtr_->turbulentDiffusivity())
+     && patch().size() != 0
+    )
+    {
+        const tmp<vectorField> tnf = patch().nf();
+        const vectorField& nf = tnf();
+        const scalarField& magSf = patch().magSf();
+
+        const fvPatchField<vector>& Up = boundaryContrPtr_->Ub();
+        const fvPatchField<vector>& Uap = *this;
+
+        const vectorField Uc(Up.patchInternalField());
+        const vectorField Uc_t(Uc - (Uc & nf)*nf);
+
+        // By convention, tf has the direction of the tangent PRIMAL velocity
+        // at the first cell off the wall
+        const vectorField tf(Uc_t/mag(Uc_t));
+
+        tmp<scalarField> tnuw = boundaryContrPtr_->momentumDiffusion();
+        const scalarField& nuw = tnuw();
+        tmp<scalarField> tnu = boundaryContrPtr_->laminarDiffusivity();
+        const scalarField& nu = tnu();
+        tmp<scalarField> tyC = boundaryContrPtr_->wallDistance();
+        const scalarField& yC = tyC();
+
+        const scalarField magGradU(mag(Up.snGrad()));
+        const scalarField vtau(sqrt(nuw*magGradU));
+        const scalarField uPlus(mag(Uc)/vtau);
+        const scalarField yPlus(yC*vtau/nu);
+        const scalarField kUu(min(kappa_*uPlus, scalar(50)));
+        const scalarField auxA((kappa_/E_)*(exp(kUu)-1 - kUu - 0.5*kUu*kUu));
+        const scalarField auxB(-(1 + auxA)/(yPlus + uPlus*(1 + auxA)));
+
+        // Tangent components are according to tf
+        tmp<vectorField> tsource = boundaryContrPtr_->normalVelocitySource();
+        const scalarField rt(tsource() & tf);
+        const scalarField Uap_t(Uap & tf);
+
+        forAll(Up, faceI)
+        {
+            label cellI = patch().faceCells()[faceI];
+            source[cellI] +=
+                2*auxB[faceI]*vtau[faceI]*((rt[faceI] + Uap_t[faceI]))
+               *(Uc[faceI]/mag(Uc[faceI]))*magSf[faceI];
+        }
+    }
+}
+
+
+void Foam::adjointWallVelocityFvPatchVectorField::updateCoeffs()
+{
+    if (updated())
+    {
+        return;
+    }
+
+    const fvPatchField<vector>& Up = boundaryContrPtr_->Ub();
+
+    // Patch geometry
+    tmp<vectorField> tnf = patch().nf();
+    const vectorField& nf = tnf();
+
+    // Internal fields
+    vectorField Uac(this->patchInternalField());
+    vectorField Uc(Up.patchInternalField());
+
+    // Tangent vector based on the  direction of Vc
+    vectorField Uc_t(Uc - (Uc & nf)*nf);
+    vectorField tf1(Uc_t/mag(Uc_t));
+
+    // Tangent vector as the cross product of tf1 x nf
+    vectorField tf2((tf1 ^ nf)/mag(tf1 ^ nf));
+
+    // Normal adjoint component comes from the objective function
+    tmp<vectorField> tsource = boundaryContrPtr_->normalVelocitySource();
+    vectorField Uan(-(tsource() & nf)*nf);
+
+    // Tangential adjoint velocity in the t1 direction depends on the primal
+    // wall function used
+    vectorField Uap_t1(patch().size(), vector::zero);
+    typedef Foam::nutUSpaldingWallFunctionFvPatchScalarField
+        SAwallFunctionPatchField;
+
+    const fvPatchScalarField& nutb = boundaryContrPtr_->turbulentDiffusivity();
+    if (isA<SAwallFunctionPatchField>(nutb))
+    {
+        Uap_t1 = (Uac & tf1)*tf1;
+        // leaving out second term for now
+        //- (1./delta)*((gradUaC & nf) & tf1)*tf1;
+    }
+    else
+    {
+        Uap_t1 = - (tsource() & tf1)*tf1;
+    }
+
+    // Adjoint velocity in the t2 direction
+    vectorField Uap_t2(-(tsource() & tf2)*tf2);
+
+    operator==(Uan + Uap_t1 + Uap_t2);
+
+    fixedValueFvPatchVectorField::updateCoeffs();
+}
+
+
+void Foam::adjointWallVelocityFvPatchVectorField::write(Ostream& os) const
+{
+    fvPatchVectorField::write(os);
+    writeEntry("value", os);
+    os.writeEntry("kappa", kappa_);
+    os.writeEntry("E", E_);
+    os.writeEntry("solverName", adjointSolverName_);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    makePatchTypeField
+    (
+        fvPatchVectorField,
+        adjointWallVelocityFvPatchVectorField
+    );
+}
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocity/adjointWallVelocityFvPatchVectorField.H b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocity/adjointWallVelocityFvPatchVectorField.H
new file mode 100644
index 0000000000000000000000000000000000000000..04ad6765d61692db6d69ed0fcb9b32b9b985e494
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocity/adjointWallVelocityFvPatchVectorField.H
@@ -0,0 +1,165 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointWallVelocityFvPatchVectorField
+
+Description
+    Adjoint wall velocity boundary condition.  If nutUSpaldingWallFunction is
+    employed in the flow solution, the corresponding adjoint wall function is
+    used. Otherwise, the typical low-Re boundary condition is applied
+
+    Reference:
+    \verbatim
+        For both the low- and high-Re variants
+
+            Papoutsis-Kiachagias, E. M., & Giannakoglou, K. C. (2014).
+            Continuous Adjoint Methods for Turbulent Flows, Applied to Shape
+            and Topology Optimization: Industrial Applications.
+            Archives of Computational Methods in Engineering, 23(2), 255-299.
+            http://doi.org/10.1007/s11831-014-9141-9
+    \endverbatim
+
+SourceFiles
+    adjointWallVelocityFvPatchVectorField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointWallVelocityFvPatchVectorField_H
+#define adjointWallVelocityFvPatchVectorField_H
+
+#include "fvPatchFields.H"
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                     Class adjointWallVelocity Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointWallVelocityFvPatchVectorField
+:
+    public fixedValueFvPatchVectorField,
+    public adjointBoundaryCondition
+{
+private:
+
+    // Private Data
+
+        scalar kappa_;
+        scalar E_;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("adjointWallVelocity");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointWallVelocityFvPatchVectorField
+        (
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointWallVelocityFvPatchVectorField
+        (
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given adjointWallVelocityFvPatchVectorField
+        //- onto a new patch
+        adjointWallVelocityFvPatchVectorField
+        (
+            const adjointWallVelocityFvPatchVectorField&,
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchVectorField> clone() const
+        {
+            return tmp<fvPatchVectorField>
+            (
+                new adjointWallVelocityFvPatchVectorField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointWallVelocityFvPatchVectorField
+        (
+            const adjointWallVelocityFvPatchVectorField&,
+            const DimensionedField<vector, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchVectorField> clone
+        (
+            const DimensionedField<vector, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchVectorField>
+            (
+                new adjointWallVelocityFvPatchVectorField(*this, iF)
+            );
+        }
+
+
+    // Member functions
+
+        //- In case of High-Re runs based on the nutUSpaldingWallFunction
+        //- add source terms in the first cell centre off the wall
+        virtual void manipulateMatrix(fvMatrix<vector>& matrix);
+
+        //- Update the coefficients associated with the patch field
+        virtual void updateCoeffs();
+
+        //- Write
+        virtual void write(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocityLowRe/adjointWallVelocityLowReFvPatchVectorField.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocityLowRe/adjointWallVelocityLowReFvPatchVectorField.C
new file mode 100644
index 0000000000000000000000000000000000000000..37f1ae938b67de03f9e78d5f39ca2ef514bc0a31
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocityLowRe/adjointWallVelocityLowReFvPatchVectorField.C
@@ -0,0 +1,130 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointWallVelocityLowReFvPatchVectorField.H"
+#include "addToRunTimeSelectionTable.H"
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::adjointWallVelocityLowReFvPatchVectorField::
+adjointWallVelocityLowReFvPatchVectorField
+(
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF
+)
+:
+    fixedValueFvPatchVectorField(p, iF),
+    adjointBoundaryCondition(p, iF, "Ua")
+{}
+
+
+Foam::adjointWallVelocityLowReFvPatchVectorField::
+adjointWallVelocityLowReFvPatchVectorField
+(
+    const adjointWallVelocityLowReFvPatchVectorField& ptf,
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchVectorField(ptf, p, iF, mapper),
+    adjointBoundaryCondition(p, iF, "Ua")
+{}
+
+
+Foam::adjointWallVelocityLowReFvPatchVectorField::
+adjointWallVelocityLowReFvPatchVectorField
+(
+    const fvPatch& p,
+    const DimensionedField<vector, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchVectorField(p, iF),
+    adjointBoundaryCondition(p, iF, "Ua")
+{
+    fvPatchField<vector>::operator=
+    (
+        vectorField("value", dict, p.size())
+    );
+}
+
+
+Foam::adjointWallVelocityLowReFvPatchVectorField::
+adjointWallVelocityLowReFvPatchVectorField
+(
+    const adjointWallVelocityLowReFvPatchVectorField& pivpvf,
+    const DimensionedField<vector, volMesh>& iF
+)
+:
+    fixedValueFvPatchVectorField(pivpvf, iF),
+    adjointBoundaryCondition(pivpvf)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::adjointWallVelocityLowReFvPatchVectorField::updateCoeffs()
+{
+    if (updated())
+    {
+        return;
+    }
+
+    // Objective function contribution
+    tmp<vectorField> tsource = boundaryContrPtr_->normalVelocitySource();
+    vectorField& source = tsource.ref();
+
+    operator==(-source);
+
+    fixedValueFvPatchVectorField::updateCoeffs();
+}
+
+
+void Foam::adjointWallVelocityLowReFvPatchVectorField::write(Ostream& os) const
+{
+    fvPatchVectorField::write(os);
+    writeEntry("value", os);
+    os.writeEntry("solverName", adjointSolverName_);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    makePatchTypeField
+    (
+        fvPatchVectorField,
+        adjointWallVelocityLowReFvPatchVectorField
+    );
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocityLowRe/adjointWallVelocityLowReFvPatchVectorField.H b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocityLowRe/adjointWallVelocityLowReFvPatchVectorField.H
new file mode 100644
index 0000000000000000000000000000000000000000..5c288f856059bb8bfafa9b708f1761f06f023bb6
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocityLowRe/adjointWallVelocityLowReFvPatchVectorField.H
@@ -0,0 +1,139 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointWallVelocityLowReFvPatchVectorField
+
+Description
+
+SourceFiles
+    adjointWallVelocityLowReFvPatchVectorField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointWallVelocityLowReFvPatchVectorField_H
+#define adjointWallVelocityLowReFvPatchVectorField_H
+
+#include "fvPatchFields.H"
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                  Class adjointWallVelocityLowReFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointWallVelocityLowReFvPatchVectorField
+:
+    public fixedValueFvPatchVectorField,
+    public adjointBoundaryCondition
+{
+public:
+
+    //- Runtime type information
+    TypeName("adjointWallVelocityLowRe");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointWallVelocityLowReFvPatchVectorField
+        (
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointWallVelocityLowReFvPatchVectorField
+        (
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given
+        //- adjointWallVelocityLowReFvPatchVectorField onto a new patch
+        adjointWallVelocityLowReFvPatchVectorField
+        (
+            const adjointWallVelocityLowReFvPatchVectorField&,
+            const fvPatch&,
+            const DimensionedField<vector, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchVectorField> clone() const
+        {
+            return tmp<fvPatchVectorField>
+            (
+                new adjointWallVelocityLowReFvPatchVectorField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointWallVelocityLowReFvPatchVectorField
+        (
+            const adjointWallVelocityLowReFvPatchVectorField&,
+            const DimensionedField<vector, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchVectorField> clone
+        (
+            const DimensionedField<vector, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchVectorField>
+            (
+                new adjointWallVelocityLowReFvPatchVectorField(*this, iF)
+            );
+        }
+
+
+    // Member functions
+
+        //- Update the coefficients associated with the patch field
+        virtual void updateCoeffs();
+
+        //- Write
+        virtual void write(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchField.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchField.C
new file mode 100644
index 0000000000000000000000000000000000000000..62247819a56ea3b70b2e9af65b8f90cfec76327e
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchField.C
@@ -0,0 +1,106 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointZeroInletFvPatchField.H"
+#include "addToRunTimeSelectionTable.H"
+#include "volFields.H"
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+template<class Type>
+Foam::adjointZeroInletFvPatchField<Type>::adjointZeroInletFvPatchField
+(
+    const fvPatch& p,
+    const DimensionedField<Type, volMesh>& iF
+)
+:
+    fixedValueFvPatchField<Type>(p, iF, pTraits<Type>::zero)
+{}
+
+
+template<class Type>
+Foam::adjointZeroInletFvPatchField<Type>::adjointZeroInletFvPatchField
+(
+    const adjointZeroInletFvPatchField<Type>& ptf,
+    const fvPatch& p,
+    const DimensionedField<Type, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchField<Type>(p, iF, pTraits<Type>::zero)
+{}
+
+
+template<class Type>
+Foam::adjointZeroInletFvPatchField<Type>::adjointZeroInletFvPatchField
+(
+    const fvPatch& p,
+    const DimensionedField<Type, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchField<Type>(p, iF, pTraits<Type>::zero)
+{}
+
+
+template<class Type>
+Foam::adjointZeroInletFvPatchField<Type>::adjointZeroInletFvPatchField
+(
+    const adjointZeroInletFvPatchField<Type>& azipf,
+    const DimensionedField<Type, volMesh>& iF
+)
+:
+    fixedValueFvPatchField<Type>(azipf, iF)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class Type>
+Foam::tmp<Foam::Field<Type>>
+Foam::adjointZeroInletFvPatchField<Type>::valueInternalCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    return tmp<Field<Type>>::New(this->size(), pTraits<Type>::one);
+}
+
+
+template<class Type>
+Foam::tmp<Foam::Field<Type>>
+Foam::adjointZeroInletFvPatchField<Type>::valueBoundaryCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    return tmp<Field<Type>>::New(this->size(), pTraits<Type>::zero);
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchField.H b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchField.H
new file mode 100644
index 0000000000000000000000000000000000000000..43d80059764916e15b89229956692c23b22c9818
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchField.H
@@ -0,0 +1,153 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointZeroInletFvPatchField
+
+Description
+
+SourceFiles
+    adjointZeroInletFvPatchField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointZeroInletFvPatchField_H
+#define adjointZeroInletFvPatchField_H
+
+#include "fvPatchFields.H"
+#include "fixedValueFvPatchFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                   Class adjointZeroInletFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+
+template<class Type>
+class adjointZeroInletFvPatchField
+:
+    public fixedValueFvPatchField<Type>
+{
+public:
+
+    //- Runtime type information
+    TypeName("adjointZeroInlet");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointZeroInletFvPatchField
+        (
+            const fvPatch&,
+            const DimensionedField<Type, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointZeroInletFvPatchField
+        (
+            const fvPatch&,
+            const DimensionedField<Type, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given adjointZeroInletFvPatchField
+        //- onto a new patch
+        adjointZeroInletFvPatchField
+        (
+            const adjointZeroInletFvPatchField&,
+            const fvPatch&,
+            const DimensionedField<Type, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchField<Type>> clone() const
+        {
+            return tmp<fvPatchField<Type>>
+            (
+                new adjointZeroInletFvPatchField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointZeroInletFvPatchField
+        (
+            const adjointZeroInletFvPatchField&,
+            const DimensionedField<Type, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchField<Type>> clone
+        (
+            const DimensionedField<Type, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchField<Type>>
+            (
+                new adjointZeroInletFvPatchField(*this, iF)
+            );
+        }
+
+
+    // Member functions
+
+        //- Return the matrix diagonal coefficients corresponding to the
+        //- evaluation of the value of this patchField with given weights
+        virtual tmp<Field<Type>> valueInternalCoeffs
+        (
+            const tmp<scalarField>&
+        ) const;
+
+        //- Return the matrix source coefficients corresponding to the
+        //- evaluation of the value of this patchField with given weights
+        virtual tmp<Field<Type>> valueBoundaryCoeffs
+        (
+            const tmp<scalarField>&
+        ) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+#   include "adjointZeroInletFvPatchField.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchFields.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchFields.C
new file mode 100644
index 0000000000000000000000000000000000000000..797b4c03cf120c8b6f2e2251452a39ade0bd5b8a
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchFields.C
@@ -0,0 +1,46 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointZeroInletFvPatchFields.H"
+#include "volFields.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+makePatchFields(adjointZeroInlet);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchFields.H b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchFields.H
new file mode 100644
index 0000000000000000000000000000000000000000..b7ab131bf6ac0638a709bc73cdb06390e47b4673
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchFields.H
@@ -0,0 +1,53 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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/>.
+
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointZeroInletFvPatchFields_H
+#define adjointZeroInletFvPatchFields_H
+
+#include "adjointZeroInletFvPatchField.H"
+#include "fieldTypes.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+makePatchTypeFieldTypedefs(adjointZeroInlet);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchFieldsFwd.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchFieldsFwd.C
new file mode 100644
index 0000000000000000000000000000000000000000..1bde9322bd564526cdc390e5824e7a2166670da5
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointZeroInlet/adjointZeroInletFvPatchFieldsFwd.C
@@ -0,0 +1,53 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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/>.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointZeroInletFvPatchFieldsFwd_H
+#define adjointZeroInletFvPatchFieldsFwd_H
+
+#include "fieldTypes.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type> class adjointZeroInletFvPatchField;
+
+makePatchTypeFieldTypedefs(adjointZeroInlet);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.C b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.C
new file mode 100644
index 0000000000000000000000000000000000000000..22610d7759f7a9cfe0768a7e782c03506945d20c
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.C
@@ -0,0 +1,133 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "boundaryAdjointContribution.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(boundaryAdjointContribution, 0);
+defineRunTimeSelectionTable(boundaryAdjointContribution, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+boundaryAdjointContribution::boundaryAdjointContribution
+(
+    const word& managerName,
+    const word& adjointSolverName,
+    const word& simulationType,
+    const fvPatch& patch
+)
+:
+    patch_(patch)
+{}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+autoPtr<boundaryAdjointContribution> boundaryAdjointContribution::New
+(
+    const word& managerName,
+    const word& adjointSolverName,
+    const word& simulationType,
+    const fvPatch& patch
+)
+{
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(simulationType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown boundaryAdjointContribution type " << simulationType
+            << endl << endl
+            << "Valid boundaryAdjointContribution types are :" << endl
+            << dictionaryConstructorTablePtr_->toc()
+            << exit(FatalError);
+    }
+
+    return
+        autoPtr<boundaryAdjointContribution>
+        (
+            cstrIter()
+            (
+                managerName,
+                adjointSolverName,
+                simulationType,
+                patch
+            )
+        );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+tmp<scalarField> boundaryAdjointContribution::adjointTMVariable1Source()
+{
+    return tmp<scalarField>::New(patch_.size(), Zero);
+}
+
+
+tmp<scalarField> boundaryAdjointContribution::adjointTMVariable2Source()
+{
+    return tmp<scalarField>::New(patch_.size(), Zero);
+}
+
+
+tmp<scalarField> boundaryAdjointContribution::TMVariable1Diffusion()
+{
+    return tmp<scalarField>::New(patch_.size(), Zero);
+}
+
+
+tmp<scalarField> boundaryAdjointContribution::TMVariable2Diffusion()
+{
+    return tmp<scalarField>::New(patch_.size(), Zero);
+}
+
+
+tmp<scalarField> boundaryAdjointContribution::TMVariable1()
+{
+    return tmp<scalarField>::New(patch_.size(), Zero);
+}
+
+
+tmp<scalarField> boundaryAdjointContribution::TMVariable2()
+{
+    return tmp<scalarField>::New(patch_.size(), Zero);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.H b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.H
new file mode 100644
index 0000000000000000000000000000000000000000..25163b958af726d9a4362ee86b38312135185aff
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.H
@@ -0,0 +1,175 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::boundaryAdjointContribution
+
+Description
+    Abstract base class for computing contributions of the objective functions
+    to the adjoint boundary conditions
+
+SourceFiles
+    boundaryAdjointContribution.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef boundaryAdjointContribution_H
+#define boundaryAdjointContribution_H
+
+#include "IOdictionary.H"
+#include "autoPtr.H"
+#include "runTimeSelectionTables.H"
+#include "fvPatchFields.H"
+#include "fvsPatchFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                 Class boundaryAdjointContribution Declaration
+\*---------------------------------------------------------------------------*/
+
+class boundaryAdjointContribution
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        boundaryAdjointContribution
+        (
+            const boundaryAdjointContribution&
+        ) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const boundaryAdjointContribution&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        const fvPatch& patch_;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("boundaryAdjointContribution");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            boundaryAdjointContribution,
+            dictionary,
+            (
+                const word& managerName,
+                const word& adjointSolverName,
+                const word& simulationType,
+                const fvPatch& patch
+            ),
+            (managerName, adjointSolverName, simulationType, patch)
+        );
+
+    // Constructors
+
+        //- Construct from components
+        boundaryAdjointContribution
+        (
+            const word& managerName,
+            const word& adjointSolverName,
+            const word& simulationType,
+            const fvPatch& patch
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<boundaryAdjointContribution> New
+        (
+            const word& managerName,
+            const word& adjointSolverName,
+            const word& simulationType,
+            const fvPatch& patch
+        );
+
+
+    //- Destructor
+    virtual ~boundaryAdjointContribution() = default;
+
+
+    // Member Functions
+
+        // Contribution to surface sensitivities for a specific patch
+        virtual tmp<scalarField> pressureSource() = 0;
+        virtual tmp<vectorField> velocitySource() = 0;
+        virtual tmp<vectorField> tangentVelocitySource() = 0;
+        virtual tmp<vectorField> normalVelocitySource() = 0;
+        virtual tmp<scalarField> adjointTMVariable1Source();
+        virtual tmp<scalarField> adjointTMVariable2Source();
+        virtual tmp<scalarField> energySource() = 0;
+
+        virtual tmp<scalarField> momentumDiffusion() = 0;
+        virtual tmp<scalarField> laminarDiffusivity() = 0;
+        virtual tmp<scalarField> thermalDiffusion() = 0;
+        virtual tmp<scalarField> wallDistance() = 0;
+
+        virtual tmp<scalarField> TMVariable1Diffusion();
+        virtual tmp<scalarField> TMVariable2Diffusion();
+        virtual tmp<scalarField> TMVariable1();
+        virtual tmp<scalarField> TMVariable2();
+
+        // References to primal and adjoint fields for the specific patch
+        virtual const fvPatchVectorField& Ub() const = 0;
+        virtual const fvPatchScalarField& pb() const = 0;
+        virtual const fvsPatchScalarField& phib() const = 0;
+        virtual const fvPatchScalarField& turbulentDiffusivity() const = 0;
+        virtual const fvPatchVectorField& Uab() const = 0;
+        virtual const fvPatchScalarField& pab() const = 0;
+        virtual const fvsPatchScalarField& phiab() const = 0;
+
+        // Field suffixes for primal and adjoint fields
+        virtual const word primalSolverName() const = 0;
+        virtual const word adjointSolverName() const = 0;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.C
new file mode 100644
index 0000000000000000000000000000000000000000..70906b0138780da799c948e1d47e761e1f2047de
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.C
@@ -0,0 +1,421 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "boundaryAdjointContributionIncompressible.H"
+#include "adjointRASModel.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(boundaryAdjointContributionIncompressible, 0);
+addToRunTimeSelectionTable
+(
+    boundaryAdjointContribution,
+    boundaryAdjointContributionIncompressible,
+    dictionary
+);
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+boundaryAdjointContributionIncompressible::
+boundaryAdjointContributionIncompressible
+(
+    const word& managerName,
+    const word& adjointSolverName,
+    const word& simulationType,
+    const fvPatch& patch
+)
+:
+    boundaryAdjointContribution
+    (
+        managerName,
+        adjointSolverName,
+        simulationType,
+        patch
+    ),
+    objectiveManager_
+    (
+        patch_.patch().boundaryMesh().mesh().
+            lookupObjectRef<objectiveManager>(managerName)
+    ),
+    primalVars_
+    (
+        patch_.patch().boundaryMesh().mesh().
+            lookupObject<incompressibleAdjointSolver>(adjointSolverName).
+                getPrimalVars()
+    ),
+    adjointSolver_
+    (
+        patch_.patch().boundaryMesh().mesh().
+            lookupObject<incompressibleAdjointSolver>(adjointSolverName)
+    )
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+tmp<vectorField> boundaryAdjointContributionIncompressible::velocitySource()
+{
+    // Objective function contribution
+    PtrList<objective>& objectives = objectiveManager_.getObjectiveFunctions();
+    tmp<vectorField> tsource =
+        sumContributions
+        (
+            objectives,
+            &objectiveIncompressible::boundarydJdv
+        );
+    vectorField& source = tsource.ref();
+
+    // Turbulence model differentiation contribution.
+    const autoPtr<incompressibleAdjoint::adjointRASModel>& adjointRAS =
+        adjointVars().adjointTurbulence();
+    source += adjointRAS().adjointMomentumBCSource()[patch_.index()];
+
+    return tsource;
+}
+
+
+tmp<scalarField> boundaryAdjointContributionIncompressible::pressureSource()
+{
+    // Objective function contribution
+    PtrList<objective>& objectives = objectiveManager_.getObjectiveFunctions();
+    tmp<scalarField> tsource =
+        sumContributions
+        (
+            objectives,
+            &objectiveIncompressible::boundarydJdvn
+        );
+
+    scalarField& source = tsource.ref();
+
+    // Turbulence model differentiation contribution.
+    const autoPtr<incompressibleAdjoint::adjointRASModel>& adjointRAS =
+        adjointVars().adjointTurbulence();
+    const vectorField& adjointTurbulenceContr =
+        adjointRAS().adjointMomentumBCSource()[patch_.index()];
+
+    tmp<vectorField> tnf = patch_.nf();
+    const vectorField& nf = tnf();
+
+    source += adjointTurbulenceContr & nf;
+
+    return (tsource);
+}
+
+
+tmp<vectorField>
+boundaryAdjointContributionIncompressible::tangentVelocitySource()
+{
+    // Objective function contribution
+    PtrList<objective>& objectives = objectiveManager_.getObjectiveFunctions();
+    tmp<vectorField> tsource =
+        sumContributions
+        (
+            objectives,
+            &objectiveIncompressible::boundarydJdvt
+        );
+
+    vectorField& source = tsource.ref();
+
+    // Turbulence model differentiation contribution.
+    const autoPtr<incompressibleAdjoint::adjointRASModel>& adjointRAS =
+        adjointVars().adjointTurbulence();
+    const vectorField& adjointTurbulenceContr =
+        adjointRAS().adjointMomentumBCSource()[patch_.index()];
+
+    tmp<vectorField> tnf = patch_.nf();
+    const vectorField& nf = tnf();
+
+    source += adjointTurbulenceContr - (adjointTurbulenceContr & nf)*nf;
+
+    return (tsource);
+}
+
+
+tmp<vectorField>
+boundaryAdjointContributionIncompressible::normalVelocitySource()
+{
+    PtrList<objective>& objectives = objectiveManager_.getObjectiveFunctions();
+    tmp<vectorField> tsource =
+        sumContributions
+        (
+            objectives,
+            &objectiveIncompressible::boundarydJdp
+        );
+
+    return (tsource);
+}
+
+
+tmp<scalarField> boundaryAdjointContributionIncompressible::energySource()
+{
+    PtrList<objective>& objectives = objectiveManager_.getObjectiveFunctions();
+    tmp<scalarField> tsource =
+        sumContributions
+        (
+            objectives,
+            &objectiveIncompressible::boundarydJdT
+        );
+
+    return (tsource);
+}
+
+
+tmp<scalarField>
+boundaryAdjointContributionIncompressible::adjointTMVariable1Source()
+{
+    PtrList<objective>& objectives = objectiveManager_.getObjectiveFunctions();
+    tmp<scalarField> tsource =
+        sumContributions
+        (
+            objectives,
+            &objectiveIncompressible::boundarydJdTMvar1
+        );
+
+    return (tsource);
+}
+
+
+tmp<scalarField>
+boundaryAdjointContributionIncompressible::adjointTMVariable2Source()
+{
+    PtrList<objective>& objectives = objectiveManager_.getObjectiveFunctions();
+    tmp<scalarField> tsource =
+        sumContributions
+        (
+            objectives,
+            &objectiveIncompressible::boundarydJdTMvar2
+        );
+
+    return (tsource);
+}
+
+
+tmp<scalarField> boundaryAdjointContributionIncompressible::momentumDiffusion()
+{
+    tmp<scalarField> tnuEff(new scalarField(patch_.size(), Zero));
+    scalarField& nuEff = tnuEff.ref();
+
+    const autoPtr<incompressibleAdjoint::adjointRASModel>&
+        adjointTurbulenceModel = adjointVars().adjointTurbulence();
+
+    nuEff = adjointTurbulenceModel().nuEff()().boundaryField()[patch_.index()];
+
+    return tnuEff;
+}
+
+
+tmp<scalarField> boundaryAdjointContributionIncompressible::laminarDiffusivity()
+{
+    tmp<scalarField> tnu(new scalarField(patch_.size(), Zero));
+    scalarField& nu = tnu.ref();
+
+    const autoPtr<incompressible::turbulenceModel>& turbulenceModel =
+        primalVars_.turbulence();
+
+    nu = turbulenceModel().nu()().boundaryField()[patch_.index()];
+
+    return tnu;
+}
+
+
+tmp<scalarField> boundaryAdjointContributionIncompressible::thermalDiffusion()
+{
+    /*
+    const polyMesh& mesh = patch_.patch().boundaryMesh().mesh();
+    const compressible::turbulenceModel& turbulenceModel =
+        mesh.lookupObject<compressible::turbulenceModel>("turbulenceModel");
+    tmp<scalarField> talphaEff = turbulenceModel.alphaEff(patch_.index());
+    */
+
+    tmp<scalarField> talphaEff(new scalarField(patch_.size(), Zero));
+
+    WarningInFunction
+        << "no abstract thermalDiffusion is implemented. Returning zero field";
+
+
+    return talphaEff;
+}
+
+
+tmp<scalarField> boundaryAdjointContributionIncompressible::wallDistance()
+{
+    tmp<scalarField> twallDist(new scalarField(patch_.size(), Zero));
+    scalarField& wallDist = twallDist.ref();
+
+    wallDist = primalVars_.turbulence()->y()[patch_.index()];
+
+    return twallDist;
+}
+
+
+tmp<scalarField>
+boundaryAdjointContributionIncompressible::TMVariable1Diffusion()
+{
+    const autoPtr<incompressibleAdjoint::adjointRASModel>& adjointRAS =
+        adjointVars().adjointTurbulence();
+
+    tmp<scalarField> tdiffCoeff =
+        adjointRAS().diffusionCoeffVar1(patch_.index());
+
+    return tdiffCoeff;
+}
+
+
+tmp<scalarField>
+boundaryAdjointContributionIncompressible::TMVariable2Diffusion()
+{
+    const autoPtr<incompressibleAdjoint::adjointRASModel>& adjointRAS =
+        adjointVars().adjointTurbulence();
+
+    tmp<scalarField> tdiffCoeff =
+        adjointRAS().diffusionCoeffVar2(patch_.index());
+
+    return tdiffCoeff;
+}
+
+
+tmp<scalarField> boundaryAdjointContributionIncompressible::TMVariable1()
+{
+    const autoPtr<incompressible::RASModelVariables>& RASVariables =
+        primalVars_.RASModelVariables();
+    tmp<scalarField> tboundField(new scalarField(patch_.size(), Zero));
+    scalarField& boundField = tboundField.ref();
+
+    boundField = RASVariables().TMVar1().boundaryField()[patch_.index()];
+
+    return tboundField;
+}
+
+
+tmp<scalarField> boundaryAdjointContributionIncompressible::TMVariable2()
+{
+    const autoPtr<incompressible::RASModelVariables>& RASVariables =
+        primalVars_.RASModelVariables();
+    tmp<scalarField> tboundField(new scalarField(patch_.size(), Zero));
+    scalarField& boundField = tboundField.ref();
+
+    boundField = RASVariables().TMVar2().boundaryField()[patch_.index()];
+
+    return tboundField;
+}
+
+
+const fvPatchVectorField& boundaryAdjointContributionIncompressible::Ub() const
+{
+    return primalVars_.U().boundaryField()[patch_.index()];
+}
+
+
+const fvPatchScalarField& boundaryAdjointContributionIncompressible::pb() const
+{
+    return primalVars_.p().boundaryField()[patch_.index()];
+}
+
+
+const fvsPatchScalarField&
+boundaryAdjointContributionIncompressible::phib() const
+{
+    return primalVars_.phi().boundaryField()[patch_.index()];
+}
+
+
+const fvPatchScalarField&
+boundaryAdjointContributionIncompressible::turbulentDiffusivity() const
+{
+    return
+        primalVars_.RASModelVariables()().nutRef().boundaryField()
+        [
+            patch_.index()
+        ];
+}
+
+
+const fvPatchVectorField& boundaryAdjointContributionIncompressible::Uab() const
+{
+    return adjointVars().UaInst().boundaryField()[patch_.index()];
+}
+
+
+const fvPatchScalarField& boundaryAdjointContributionIncompressible::pab() const
+{
+    return adjointVars().paInst().boundaryField()[patch_.index()];
+}
+
+
+const fvsPatchScalarField&
+boundaryAdjointContributionIncompressible::phiab() const
+{
+    return adjointVars().phiaInst().boundaryField()[patch_.index()];
+}
+
+
+const word boundaryAdjointContributionIncompressible::primalSolverName() const
+{
+    return primalVars_.solverName();
+}
+
+
+const word boundaryAdjointContributionIncompressible::adjointSolverName() const
+{
+    return adjointVars().solverName();
+}
+
+
+const incompressibleVars&
+boundaryAdjointContributionIncompressible::primalVars() const
+{
+    return primalVars_;
+}
+
+
+const incompressibleAdjointVars&
+boundaryAdjointContributionIncompressible::adjointVars() const
+{
+    return adjointSolver_.getAdjointVars();
+}
+
+
+objectiveManager&
+boundaryAdjointContributionIncompressible::getObjectiveManager()
+{
+    return objectiveManager_;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.H
new file mode 100644
index 0000000000000000000000000000000000000000..0a147e9b4266159dacd4c5b205a5cdba1aa61f54
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.H
@@ -0,0 +1,183 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::boundaryAdjointContributionIncompressible
+
+Description
+    Contributions of objective function differentiation to adjoint
+    boundary conditions for incompressible flows
+
+
+SourceFiles
+    boundaryAdjointContributionIncompressible.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef boundaryAdjointContributionIncompressible_H
+#define boundaryAdjointContributionIncompressible_H
+
+#include "boundaryAdjointContribution.H"
+#include "IOdictionary.H"
+#include "autoPtr.H"
+#include "runTimeSelectionTables.H"
+#include "objectiveManager.H"
+#include "objectiveIncompressible.H"
+#include "incompressibleAdjointSolver.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+          Class boundaryAdjointContributionIncompressible Declaration
+\*---------------------------------------------------------------------------*/
+
+class boundaryAdjointContributionIncompressible
+:
+    public boundaryAdjointContribution
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        boundaryAdjointContributionIncompressible
+        (
+            const boundaryAdjointContributionIncompressible&
+        ) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=
+        (
+            const boundaryAdjointContributionIncompressible&
+        ) = delete;
+
+
+protected:
+
+    // Protected data
+
+        objectiveManager& objectiveManager_;
+
+        const incompressibleVars& primalVars_;
+
+        //- Note: getting a reference to the adjoint vars in the contructor of
+        //- boundaryAdjointContributionIncompressible is dangerous since the
+        //- autoPtr that holds them has not been completed yet. Instead, get
+        //- a reference to the solver and grad the adjoint vars from there,
+        //- when necessary
+        const incompressibleAdjointSolver& adjointSolver_;
+
+
+    // Protected Member Functions
+
+        template<class returnType, class sourceType, class castType>
+        tmp<Field<returnType>> sumContributions
+        (
+            PtrList<sourceType>& sourceList,
+            const fvPatchField<returnType>&(castType::*boundaryFunction)
+                (const label)
+        );
+
+
+public:
+
+    //- Runtime type information
+    TypeName("incompressible");
+
+
+    // Constructors
+
+        //- Construct from components
+        boundaryAdjointContributionIncompressible
+        (
+            const word& managerName,
+            const word& adjointSolverName,
+            const word& simulationType,
+            const fvPatch& patch
+        );
+
+
+    //- Destructor
+    virtual ~boundaryAdjointContributionIncompressible() = default;
+
+
+    // Member Functions
+
+//      tmp<vectorField> boundarydJtotdv();
+        tmp<scalarField> pressureSource();
+        tmp<vectorField> velocitySource();
+        tmp<vectorField> tangentVelocitySource();
+        tmp<vectorField> normalVelocitySource();
+        tmp<scalarField> energySource();
+        tmp<scalarField> adjointTMVariable1Source();
+        tmp<scalarField> adjointTMVariable2Source();
+
+        tmp<scalarField> momentumDiffusion();
+        tmp<scalarField> laminarDiffusivity();
+        tmp<scalarField> thermalDiffusion();
+        tmp<scalarField> wallDistance();
+
+        tmp<scalarField> TMVariable1Diffusion();
+        tmp<scalarField> TMVariable2Diffusion();
+        tmp<scalarField> TMVariable1();
+        tmp<scalarField> TMVariable2();
+
+        const fvPatchVectorField& Ub() const;
+        const fvPatchScalarField& pb() const;
+        const fvsPatchScalarField& phib() const;
+        const fvPatchScalarField& turbulentDiffusivity() const;
+        const fvPatchVectorField& Uab() const;
+        const fvPatchScalarField& pab() const;
+        const fvsPatchScalarField& phiab() const;
+
+        const word primalSolverName() const;
+        const word adjointSolverName() const;
+
+        const incompressibleVars& primalVars()  const;
+        const incompressibleAdjointVars& adjointVars() const;
+        objectiveManager& getObjectiveManager();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+#   include "boundaryAdjointContributionIncompressibleTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressibleTemplates.C b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressibleTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..ba5764bed674908f738eda74b2072af6610ca878
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressibleTemplates.C
@@ -0,0 +1,57 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 returnType, class sourceType, class castType>
+Foam::tmp<Foam::Field<returnType>>
+Foam::boundaryAdjointContributionIncompressible::sumContributions
+(
+    PtrList<sourceType>& sourceList,
+    const fvPatchField<returnType>&(castType::*boundaryFunction)(const label)
+)
+{
+    // Objective function contribution
+    tmp<Field<returnType>> tdJtotdvar
+        (new Field<returnType>(patch_.size(), pTraits<returnType>::zero));
+    Field<returnType>& dJtotdvar = tdJtotdvar.ref();
+
+    // Get weighthed contribution
+    for (sourceType& funcI : sourceList)
+    {
+        castType& cfuncI = refCast<castType>(funcI);
+        const fvPatchField<returnType>& dJdvar =
+            (cfuncI.*boundaryFunction)(patch_.index());
+        dJtotdvar += cfuncI.weight()*dJdvar;
+    }
+
+    return tdJtotdvar;
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/deltaBoundary/deltaBoundary.C b/src/optimisation/adjointOptimisation/adjoint/deltaBoundary/deltaBoundary.C
new file mode 100644
index 0000000000000000000000000000000000000000..b1e3700862cb7131b2f931a3aed9ffe631590a55
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/deltaBoundary/deltaBoundary.C
@@ -0,0 +1,369 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "deltaBoundary.H"
+#include "fvMesh.H"
+#include "surfaceFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
+
+tensor deltaBoundary::tensorCrossVector(const tensor& T, const vector& v)
+{
+    // The correct approach when T is not a diagonal tensor
+    tensor res(tensor::zero);
+    vector vec1(T.xx(), T.yx(), T.zx());
+    vector res1(vec1 ^ v);
+    res.xx() = res1.x(); res.yx() = res1.y(); res.zx() = res1.z();
+
+    vector vec2(T.xy(), T.yy(), T.zy());
+    vector res2(vec2 ^ v);
+    res.xy() = res2.x(); res.yy() = res2.y(); res.zy() = res2.z();
+
+    vector vec3(T.xz(), T.yz(), T.zz());
+    vector res3(vec3 ^ v);
+    res.xz() = res3.x(); res.yz() = res3.y(); res.zz() = res3.z();
+
+    return res;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+deltaBoundary::deltaBoundary(const fvMesh& mesh)
+:
+    mesh_(mesh)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+vectorField deltaBoundary::makeFaceCentresAndAreas_d
+(
+    const pointField& p,
+    const pointField& p_d
+)
+{
+    vector fCtrs_d(vector::zero);
+    vector fAreas_d(vector::zero);
+    vector unitVector_d(vector::zero);
+
+    // Container field to return results
+    vectorField deltaVecs(3, vector::zero);
+
+    label nPoints = p.size();
+
+    // If the face is a triangle, do a direct calculation for efficiency
+    // and to avoid round-off error-related problems
+    if (nPoints == 3)
+    {
+        //fCtrs[facei] = (1.0/3.0)*(p[f[0]] + p[f[1]] + p[f[2]]);
+        vector fAreas = 0.5*((p[1] - p[0])^(p[2] - p[0]));
+
+        fCtrs_d  = (1.0/3.0)*(p_d[0] + p_d[1] + p_d[2]);
+        fAreas_d =
+            0.5*((p_d[1] - p_d[0])^(p[2] - p[0]))
+          + 0.5*((p[1] - p[0])^(p_d[2] - p_d[0]));
+        scalar ds = mag(fAreas);
+        unitVector_d = fAreas_d/ds - (fAreas*(fAreas&fAreas_d))/ds/ds/ds;
+
+        deltaVecs[0] = fCtrs_d;
+        deltaVecs[1] = fAreas_d;
+        deltaVecs[2] = unitVector_d;
+    }
+    else
+    {
+        vector sumN(vector::zero);
+        vector sumN_d(vector::zero);
+        scalar sumA = Zero;
+        scalar sumA_d = Zero;
+        vector sumAc = vector::zero;
+        vector sumAc_d = vector::zero;
+
+        point fCentre = p[0];
+        point fCentre_d = p_d[0];
+        for (label pi = 1; pi < nPoints; pi++)
+        {
+            fCentre += p[pi];
+            fCentre_d += p_d[pi];
+        }
+
+        fCentre /= nPoints;
+        fCentre_d /= nPoints;
+
+        for (label pi = 0; pi < nPoints; pi++)
+        {
+            const point& nextPoint = p[(pi + 1) % nPoints];
+            const point& nextPoint_d = p_d[(pi + 1) % nPoints];
+
+            vector c = p[pi] + nextPoint + fCentre;
+            vector c_d = p_d[pi] + nextPoint_d + fCentre_d;
+
+            vector n = (nextPoint - p[pi])^(fCentre - p[pi]);
+            vector n_d =
+                ((nextPoint_d - p_d[pi])^(fCentre - p[pi]))
+              + ((nextPoint - p[pi])^(fCentre_d - p_d[pi]));
+
+            scalar a = mag(n);
+            if (a < ROOTVSMALL)
+            {
+                // This shouldn't happen in general.
+                // Manually zero contribution from zero area face for now
+                WarningInFunction
+                    << "Zero area face sub triangle found " << endl
+                    << p[pi] << " " << nextPoint <<  " " << fCentre << endl
+                    << "Neglecting contributions of this element " << endl;
+            }
+            else
+            {
+                scalar a_d = (n&n_d)/mag(n);
+
+                sumN += n;
+                sumN_d += n_d;
+
+                sumA += a;
+                sumA_d += a_d;
+
+                sumAc += a*c;
+                sumAc_d += a_d*c + a*c_d;
+            }
+        }
+
+        // fCtrs[facei] = (1.0/3.0)*sumAc/(sumA + VSMALL);
+        vector fAreas = 0.5*sumN;
+        fCtrs_d = (1.0/3.0)*(sumAc_d*sumA - sumAc*sumA_d)/sumA/sumA;
+        fAreas_d = 0.5*sumN_d;
+        scalar ds = mag(fAreas);
+        unitVector_d = fAreas_d/ds - (fAreas*(fAreas&fAreas_d))/ds/ds/ds;
+
+        deltaVecs[0] = fCtrs_d;
+        deltaVecs[1] = fAreas_d;
+        deltaVecs[2] = unitVector_d;
+    }
+
+    return deltaVecs;
+}
+
+
+tensorField deltaBoundary::makeFaceCentresAndAreas_d
+(
+    const pointField& p,
+    const tensorField& p_d
+)
+{
+    label nPoints = p.size();
+    tensor fCtrs_d(tensor::zero);
+    tensor fAreas_d(tensor::zero);
+    tensor unitVector_d(tensor::zero);
+
+    // Container field to return results
+    tensorField deltaVecs(3, tensor::zero);
+
+    // If the face is a triangle, do a direct calculation for efficiency
+    // and to avoid round-off error-related problems
+    if (nPoints == 3)
+    {
+        vector fAreas = 0.5*((p[1] - p[0])^(p[2] - p[0]));
+
+        fCtrs_d  = (1.0/3.0)*(p_d[0] + p_d[1] + p_d[2]);
+        fAreas_d =
+            0.5*tensorCrossVector(p_d[1] - p_d[0], p[2] - p[0])
+            //minus sign since it is vector ^ tensor
+          - 0.5*tensorCrossVector(p_d[2] - p_d[0], p[1] - p[0]);
+        scalar ds = mag(fAreas);
+        unitVector_d = fAreas_d/ds - (fAreas*(fAreas&fAreas_d))/ds/ds/ds;
+
+        deltaVecs[0] = fCtrs_d;
+        deltaVecs[1] = fAreas_d;
+        deltaVecs[2] = unitVector_d;
+    }
+    else
+    {
+        vector sumN(vector::zero);
+        tensor sumN_d(tensor::zero);
+        scalar sumA = Zero;
+        vector sumA_d(vector::zero);
+        vector sumAc(vector::zero);
+        tensor sumAc_d(tensor::zero);
+
+        point fCentre = p[0];
+        tensor fCentre_d = p_d[0];
+        for (label pi = 1; pi < nPoints; pi++)
+        {
+            fCentre += p[pi];
+            fCentre_d += p_d[pi];
+        }
+
+        fCentre /= nPoints;
+        fCentre_d /= nPoints;
+
+        for (label pi = 0; pi < nPoints; pi++)
+        {
+            const point& nextPoint = p[(pi + 1) % nPoints];
+            const tensor& nextPoint_d = p_d[(pi + 1) % nPoints];
+
+            vector c = p[pi] + nextPoint + fCentre;
+            tensor c_d = p_d[pi] + nextPoint_d + fCentre_d;
+
+            vector n = (nextPoint - p[pi])^(fCentre - p[pi]);
+            tensor n_d =
+                tensorCrossVector(nextPoint_d - p_d[pi], fCentre - p[pi])
+                //minus sign since it is vector ^ tensor
+              - tensorCrossVector(fCentre_d - p_d[pi], nextPoint - p[pi]);
+
+            scalar a = mag(n);
+            if (a < ROOTVSMALL)
+            {
+                // This shouldn't happen in general.
+                // Manually zero contribution from zero area face for now
+                WarningInFunction
+                    << "Zero area face sub triangle found " << nl
+                    << p[pi] << " " << nextPoint <<  " " << fCentre << nl
+                    << "Neglecting contributions of this element " << endl;
+            }
+            else
+            {
+                vector a_d = (n & n_d)/a;
+
+                sumN += n;
+                sumN_d += n_d;
+
+                sumA += a;
+                sumA_d += a_d;
+
+                sumAc += a*c;
+                // c*a_d since we need to get the correct outer product
+                sumAc_d += (c*a_d) + a*c_d;
+            }
+        }
+
+        vector fAreas = 0.5*sumN;
+        fCtrs_d = (1.0/3.0)*(sumAc_d/sumA - (sumAc*sumA_d)/sqr(sumA));
+        fAreas_d = 0.5*sumN_d;
+        scalar ds = mag(fAreas);
+        unitVector_d = fAreas_d/ds - (fAreas*(fAreas&fAreas_d))/ds/ds/ds;
+
+        deltaVecs[0] = fCtrs_d;
+        deltaVecs[1] = fAreas_d;
+        deltaVecs[2] = unitVector_d;
+    }
+
+    return deltaVecs;
+}
+
+
+tmp<tensorField> deltaBoundary::cellCenters_d(const label pointI)
+{
+    const labelListList& pointCells(mesh_.pointCells());
+    const labelList& pointCellsI(pointCells[pointI]);
+    const pointField& points(mesh_.points());
+    tmp<tensorField> tC_d(new tensorField(pointCellsI.size(), tensor::zero));
+    tensorField& C_d(tC_d.ref());
+
+    const labelList& pointFaces(mesh_.pointFaces()[pointI]);
+    tensorField Cf_d(pointFaces.size(), tensor::zero);
+    tensorField Sf_d(pointFaces.size(), tensor::zero);
+
+    forAll(pointFaces, pfI)
+    {
+        const label pointFaceI = pointFaces[pfI];
+        const face& faceI = mesh_.faces()[pointFaceI];
+        tensorField p_d(faceI.size(), tensor::zero);
+        forAll(faceI, pI)
+        {
+            if (faceI[pI] == pointI)
+            {
+                p_d[pI] = tensor::I;
+                break;
+            }
+        }
+
+        pointField facePoints(faceI.points(points));
+
+        // Compute changes in the face
+        tensorField dFace(makeFaceCentresAndAreas_d(facePoints, p_d));
+        Cf_d[pfI] = dFace[0];
+        Sf_d[pfI] = dFace[1];
+    }
+
+    // Face variations have now been computed. Now, compute cell contributions
+    forAll(pointCellsI, pcI)
+    {
+        const label pointCellI = pointCellsI[pcI];
+        const cell& cellI(mesh_.cells()[pointCellI]);
+        vectorField fAreas(cellI.size(), vector::zero);
+        vectorField fCtrs(cellI.size(), vector::zero);
+        tensorField fAreas_d(cellI.size(), tensor::zero);
+        tensorField fCtrs_d(cellI.size(), tensor::zero);
+        forAll(cellI, fI)
+        {
+            const label globalFaceI = cellI[fI];
+
+            // Assign values to faceAreas and faceCtrs
+            if (globalFaceI < mesh_.nInternalFaces())
+            {
+                fAreas[fI] = mesh_.Sf()[globalFaceI];
+                fCtrs[fI] = mesh_.Cf()[globalFaceI];
+            }
+            else
+            {
+                const label whichPatch =
+                    mesh_.boundaryMesh().whichPatch(globalFaceI);
+                const fvPatch& patch = mesh_.boundary()[whichPatch];
+                const label patchStart = patch.patch().start();
+                const label localFace = globalFaceI - patchStart;
+                fAreas[fI] = patch.Sf()[localFace];
+                fCtrs[fI] = patch.Cf()[localFace];
+            }
+
+            // Assign values to differentiated face areas and centres
+            forAll(pointFaces, pfI)
+            {
+                if (pointFaces[pfI] == globalFaceI)
+                {
+                    fAreas_d[fI] = Sf_d[pfI];
+                    fCtrs_d[fI] = Cf_d[pfI];
+                }
+            }
+        }
+        C_d[pcI] = makeCellCentres_d(fAreas, fCtrs, fAreas_d, fCtrs_d);
+    }
+
+    return tC_d;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/deltaBoundary/deltaBoundary.H b/src/optimisation/adjointOptimisation/adjoint/deltaBoundary/deltaBoundary.H
new file mode 100644
index 0000000000000000000000000000000000000000..c30631c1207e8eef6f0689ba45d80e16f77bcbc3
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/deltaBoundary/deltaBoundary.H
@@ -0,0 +1,146 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::deltaBoundary
+
+Description
+    Differentiation of the mesh data structure
+
+SourceFiles
+    deltaBoundary.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef deltaBoundary_H
+#define deltaBoundary_H
+
+#include "fieldTypes.H"
+#include "vectorField.H"
+#include "tensorField.H"
+#include "pointField.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+class fvMesh;
+
+/*---------------------------------------------------------------------------*\
+                        Class deltaBoundary Declaration
+\*---------------------------------------------------------------------------*/
+
+class deltaBoundary
+{
+protected:
+
+    // Protected data
+
+        //- Reference to the mesh
+        const fvMesh& mesh_;
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        deltaBoundary(const deltaBoundary&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const deltaBoundary&) = delete;
+
+        //- Compute tensor-vector products
+        tensor tensorCrossVector(const tensor& T, const vector& v);
+
+
+public:
+
+    // Constructors
+
+        //- Construct from components
+        deltaBoundary(const fvMesh& mesh);
+
+
+    //- Destructor
+    ~deltaBoundary() = default;
+
+
+    // Member Functions
+
+        //- Given a face and the points to be moved in the normal direction,
+        //- find faceArea, faceCentre and unitVector changes
+        vectorField makeFaceCentresAndAreas_d
+        (
+            const pointField& p,
+            const pointField& p_d
+        );
+
+        //- Given a face and the points to be moved in an arbitrary direction,
+        //- find faceArea, faceCentre and unitVector changes
+        tensorField makeFaceCentresAndAreas_d
+        (
+            const pointField& p,
+            const tensorField& p_d
+        );
+
+        //- Compute cell center variation wrt
+        //- given face movement or derivative.
+        //  pT (perturbation type) should be a vector in case
+        //  of known face area and ctr movements
+        //  or a tensor for gradients
+        template<class pT>
+        pT makeCellCentres_d
+        (
+            const vectorField& fAreas,
+            const vectorField& fCtrs,
+            const Field<pT>& fAreas_d,
+            const Field<pT>& fCtrs_d
+        );
+
+        //- Compute the change of the cell centers of the pointCells
+        //- of pointI, for a unitary movement of pointI in all three directions
+        tmp<tensorField> cellCenters_d(const label pointI);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+#   include "deltaBoundaryTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/deltaBoundary/deltaBoundaryTemplates.C b/src/optimisation/adjointOptimisation/adjoint/deltaBoundary/deltaBoundaryTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..494b9f47afe8956930d904695088e5a94bce0ce7
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/deltaBoundary/deltaBoundaryTemplates.C
@@ -0,0 +1,111 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "deltaBoundary.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class pT>
+pT deltaBoundary::makeCellCentres_d
+(
+    const vectorField& fAreas,
+    const vectorField& fCtrs,
+    const Field<pT>& fAreas_d,
+    const Field<pT>& fCtrs_d
+)
+{
+    // Define type that in an order smaller than pT. Used for volume-related
+    // variations
+    typedef typename innerProduct<vector, pT>::type vT;
+
+    // First estimate the approximate cell centre as the average of
+    // face centres
+    vector cEst(vector::zero);
+    vector cellCtrs(vector::zero);
+    scalar cellVols(Zero);
+    pT cEst_d(pTraits<pT>::zero);
+    pT cellCtrs_d(pTraits<pT>::zero);
+    vT cellVols_d(pTraits<vT>::zero);
+
+    forAll(fAreas, facei)
+    {
+        cEst += fCtrs[facei];
+        cEst_d += fCtrs_d[facei];
+    }
+
+    cEst /= fAreas.size();
+    cEst_d /= fAreas.size();
+
+    forAll(fAreas, facei)
+    {
+        // Calculate 3*face-pyramid volume
+        scalar pyr3Vol =
+            mag(fAreas[facei] & (fCtrs[facei] - cEst));
+
+        vT pyr3Vol_d =
+            (fAreas[facei] & (fCtrs[facei] - cEst))
+           *(
+               ((fCtrs[facei] - cEst) & fAreas_d[facei])
+               // Reverse order to get the correct inner product
+             + (fAreas[facei] & (fCtrs_d[facei] - cEst_d))
+            )/pyr3Vol;
+
+        // Calculate face-pyramid centre
+        vector pc = (3.0/4.0)*fCtrs[facei] + (1.0/4.0)*cEst;
+        pT pc_d = (3.0/4.0)*fCtrs_d[facei] + (1.0/4.0)*cEst_d;
+
+        // Accumulate volume-weighted face-pyramid centre
+        cellCtrs += pyr3Vol*pc;
+
+        // Reverse order to get the correct outer product
+        cellCtrs_d += (pc*pyr3Vol_d + pyr3Vol*pc_d);
+
+        // Accumulate face-pyramid volume
+        cellVols += pyr3Vol;
+        cellVols_d += pyr3Vol_d;
+    }
+
+    cellCtrs /= cellVols;
+    cellCtrs_d = cellCtrs_d/cellVols - cellCtrs*cellVols_d/cellVols;
+    cellVols *= (1.0/3.0);
+    cellVols_d *= (1.0/3.0);
+
+    return cellCtrs_d;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/finiteVolume/interpolation/surfaceInterpolation/schemes/limitedSchemes/linearUpwindNormal/linearUpwindNormal.C b/src/optimisation/adjointOptimisation/adjoint/finiteVolume/interpolation/surfaceInterpolation/schemes/limitedSchemes/linearUpwindNormal/linearUpwindNormal.C
new file mode 100644
index 0000000000000000000000000000000000000000..c1bb6f1e37b4285860092e8a19d8220d07bd3cca
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/finiteVolume/interpolation/surfaceInterpolation/schemes/limitedSchemes/linearUpwindNormal/linearUpwindNormal.C
@@ -0,0 +1,148 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "linearUpwindNormal.H"
+#include "fvMesh.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+Foam::tmp<Foam::GeometricField<Type, Foam::fvsPatchField, Foam::surfaceMesh>>
+Foam::linearUpwindNormal<Type>::correction
+(
+    const GeometricField<Type, fvPatchField, volMesh>& vf
+) const
+{
+    const fvMesh& mesh = this->mesh();
+
+    tmp<GeometricField<Type, fvsPatchField, surfaceMesh>> tsfCorr
+    (
+        new GeometricField<Type, fvsPatchField, surfaceMesh>
+        (
+            IOobject
+            (
+                "linearUpwind::correction(" + vf.name() + ')',
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE,
+                false
+            ),
+            mesh,
+            dimensioned<Type>(vf.name(), vf.dimensions(), pTraits<Type>::zero)
+        )
+    );
+
+    GeometricField<Type, fvsPatchField, surfaceMesh>& sfCorr = tsfCorr();
+
+    const surfaceScalarField& faceFlux = this->faceFlux_;
+
+    const labelList& owner = mesh.owner();
+    const labelList& neighbour = mesh.neighbour();
+
+    const volVectorField& C = mesh.C();
+    const surfaceVectorField& Cf = mesh.Cf();
+
+    tmp
+    <
+        GeometricField
+        <
+            typename outerProduct<vector, Type>::type,
+            fvPatchField,
+            volMesh
+        >
+    > tgradVf = gradScheme_().grad(vf, gradSchemeName_);
+
+    GeometricField
+    <
+        typename outerProduct<vector, Type>::type,
+        fvPatchField,
+        volMesh
+    >& gradVf = tgradVf();
+    gradVf /= mag(gradVf) + 1.e-12;
+
+    forAll(faceFlux, facei)
+    {
+        label celli = (faceFlux[facei] > 0) ? owner[facei] : neighbour[facei];
+        sfCorr[facei] = (Cf[facei] - C[celli]) & gradVf[celli];
+    }
+
+
+    typename GeometricField<Type, fvsPatchField, surfaceMesh>::
+        GeometricBoundaryField& bSfCorr = sfCorr.boundaryField();
+
+    forAll(bSfCorr, patchi)
+    {
+        fvsPatchField<Type>& pSfCorr = bSfCorr[patchi];
+
+        if (pSfCorr.coupled())
+        {
+            const labelUList& pOwner =
+                mesh.boundary()[patchi].faceCells();
+
+            const vectorField& pCf = Cf.boundaryField()[patchi];
+
+            const scalarField& pFaceFlux = faceFlux.boundaryField()[patchi];
+
+            const Field<typename outerProduct<vector, Type>::type> pGradVfNei
+            (
+                gradVf.boundaryField()[patchi].patchNeighbourField()
+            );
+
+            // Build the d-vectors
+            vectorField pd(Cf.boundaryField()[patchi].patch().delta());
+
+            forAll(pOwner, facei)
+            {
+                label own = pOwner[facei];
+
+                if (pFaceFlux[facei] > 0)
+                {
+                    pSfCorr[facei] = (pCf[facei] - C[own]) & gradVf[own];
+                }
+                else
+                {
+                    pSfCorr[facei] =
+                        (pCf[facei] - pd[facei] - C[own]) & pGradVfNei[facei];
+                }
+            }
+        }
+    }
+
+    return tsfCorr;
+}
+
+
+namespace Foam
+{
+    //makelimitedSurfaceInterpolationScheme(linearUpwindNormal)
+    makelimitedSurfaceInterpolationTypeScheme(linearUpwindNormal, scalar)
+    makelimitedSurfaceInterpolationTypeScheme(linearUpwindNormal, vector)
+}
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/finiteVolume/interpolation/surfaceInterpolation/schemes/limitedSchemes/linearUpwindNormal/linearUpwindNormal.H b/src/optimisation/adjointOptimisation/adjoint/finiteVolume/interpolation/surfaceInterpolation/schemes/limitedSchemes/linearUpwindNormal/linearUpwindNormal.H
new file mode 100644
index 0000000000000000000000000000000000000000..e0f6a5059ce9e21a679a7d3ea27eac5e995d5a93
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/finiteVolume/interpolation/surfaceInterpolation/schemes/limitedSchemes/linearUpwindNormal/linearUpwindNormal.H
@@ -0,0 +1,167 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::linearUpwindNormal
+
+Description
+    linearUpwindNormal interpolation scheme class derived from upwind and
+    returns upwind weighting factors and also applies a gradient-based
+    explicit correction. The magnitude of the correcting gradient is equal to 1
+
+SourceFiles
+    linearUpwindNormal.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef linearUpwindNormal_H
+#define linearUpwindNormal_H
+
+#include "upwind.H"
+#include "gaussGrad.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class linearUpwindNormal Declaration
+\*---------------------------------------------------------------------------*/
+
+template<class Type>
+class linearUpwindNormal
+:
+    public upwind<Type>
+{
+    // Private Data
+
+        word gradSchemeName_;
+        tmp<fv::gradScheme<Type>> gradScheme_;
+
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        linearUpwindNormal(const linearUpwindNormal&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const linearUpwindNormal&);
+
+
+public:
+
+    //- Runtime type information
+    TypeName("linearUpwindNormal");
+
+
+    // Constructors
+
+        //- Construct from faceFlux
+        linearUpwindNormal
+        (
+            const fvMesh& mesh,
+            const surfaceScalarField& faceFlux
+        )
+        :
+            upwind<Type>(mesh, faceFlux),
+            gradSchemeName_("grad"),
+            gradScheme_
+            (
+                new fv::gaussGrad<Type>(mesh)
+            )
+        {}
+
+        //- Construct from Istream.
+        //  The name of the flux field is read from the Istream and looked-up
+        //  from the mesh objectRegistry
+        linearUpwindNormal
+        (
+            const fvMesh& mesh,
+            Istream& schemeData
+        )
+        :
+            upwind<Type>(mesh, schemeData),
+            gradSchemeName_(schemeData),
+            gradScheme_
+            (
+                fv::gradScheme<Type>::New
+                (
+                    mesh,
+                    mesh.gradScheme(gradSchemeName_)
+                )
+            )
+        {}
+
+        //- Construct from faceFlux and Istream
+        linearUpwindNormal
+        (
+            const fvMesh& mesh,
+            const surfaceScalarField& faceFlux,
+            Istream& schemeData
+        )
+        :
+            upwind<Type>(mesh, faceFlux, schemeData),
+            gradSchemeName_(schemeData),
+            gradScheme_
+            (
+                fv::gradScheme<Type>::New
+                (
+                    mesh,
+                    mesh.gradScheme(gradSchemeName_)
+                )
+            )
+        {}
+
+
+    // Member Functions
+
+        //- Return true if this scheme uses an explicit correction
+        virtual bool corrected() const
+        {
+            return true;
+        }
+
+        //- Return the explicit correction to the face-interpolate
+        virtual tmp<GeometricField<Type, fvsPatchField, surfaceMesh>>
+        correction
+        (
+            const GeometricField<Type, fvPatchField, volMesh>&
+        ) const;
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvIOoptionListAdjoint.C b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvIOoptionListAdjoint.C
new file mode 100644
index 0000000000000000000000000000000000000000..b218653bc7e7cf5d60854cd8c9d99ca56e785b72
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvIOoptionListAdjoint.C
@@ -0,0 +1,93 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "fvIOoptionListAdjoint.H"
+#include "fvMesh.H"
+#include "Time.H"
+
+// * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
+
+Foam::IOobject Foam::fv::IOoptionListAdjoint::createIOobject
+(
+    const fvMesh& mesh
+) const
+{
+    IOobject io
+    (
+        "fvOptionsAdjoint",
+        mesh.time().system(),
+        mesh,
+        IOobject::MUST_READ,
+        IOobject::NO_WRITE
+    );
+
+    if (io.typeHeaderOk<IOdictionary>(true))
+    {
+        Info<< "Creating fintite volume adjoint options from " << io.name()
+            << nl << endl;
+
+        io.readOpt() = IOobject::MUST_READ_IF_MODIFIED;
+        return io;
+    }
+    else
+    {
+        Info<< "No finite volume adjoint options present" << nl << endl;
+
+        io.readOpt() = IOobject::NO_READ;
+        return io;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::fv::IOoptionListAdjoint::IOoptionListAdjoint
+(
+    const fvMesh& mesh
+)
+:
+    IOdictionary(createIOobject(mesh)),
+    optionList(mesh, *this)
+{}
+
+
+bool Foam::fv::IOoptionListAdjoint::read()
+{
+    if (regIOobject::read())
+    {
+        optionList::read(*this);
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvIOoptionListAdjoint.H b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvIOoptionListAdjoint.H
new file mode 100644
index 0000000000000000000000000000000000000000..29c36696f641392db39350beff7742b08178ff06
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvIOoptionListAdjoint.H
@@ -0,0 +1,105 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::fv::IOoptionListAdjoint
+
+Description
+    IOoptionListAdjoint
+
+SourceFiles
+    IOoptionListAdjoint.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef IOoptionListAdjoint_H
+#define IOoptionListAdjoint_H
+
+#include "fvOptionList.H"
+#include "IOdictionary.H"
+#include "autoPtr.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace fv
+{
+
+/*---------------------------------------------------------------------------*\
+                     Class IOoptionListAdjoint Declaration
+\*---------------------------------------------------------------------------*/
+
+class IOoptionListAdjoint
+:
+    public IOdictionary,
+    public optionList
+{
+private:
+
+    // Private Member Functions
+
+        //- Create IO object if dictionary is present
+        IOobject createIOobject(const fvMesh& mesh) const;
+
+        //- Disallow default bitwise copy construct
+        IOoptionListAdjoint(const IOoptionListAdjoint&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const IOoptionListAdjoint&) = delete;
+
+
+public:
+
+    // Constructors
+
+        //- Construct from components with list of field names
+        IOoptionListAdjoint(const fvMesh& mesh);
+
+
+        //- Destructor
+        virtual ~IOoptionListAdjoint() = default;
+
+
+    // Member Functions
+
+        //- Read dictionary
+        virtual bool read();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace fv
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjoint.C b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjoint.C
new file mode 100644
index 0000000000000000000000000000000000000000..c3ddcc80904fcb1a7102517702e065463d88ce28
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjoint.C
@@ -0,0 +1,113 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "fvOptionAdjoint.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    namespace fv
+    {
+        defineTypeNameAndDebug(optionAdjoint, 0);
+        defineRunTimeSelectionTable(optionAdjoint, dictionary);
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::fv::optionAdjoint::optionAdjoint
+(
+    const word& name,
+    const word& modelType,
+    const dictionary& dict,
+    const fvMesh& mesh
+)
+:
+    option(name, modelType, dict, mesh)
+{}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+Foam::autoPtr<Foam::fv::optionAdjoint> Foam::fv::optionAdjoint::New
+(
+    const word& name,
+    const dictionary& coeffs,
+    const fvMesh& mesh
+)
+{
+    word modelType(coeffs.get<word>("type"));
+
+    Info<< indent
+        << "Selecting finite volume options model type " << modelType << endl;
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown Model type " << modelType << nl << nl
+            << "Valid model types are:" << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return autoPtr<optionAdjoint>(cstrIter()(name, modelType, coeffs, mesh));
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::tmp<Foam::volVectorField> Foam::fv::optionAdjoint::dxdbMult
+(
+    const incompressibleAdjointVars&
+)
+{
+    tmp<volVectorField> tdxdbMult
+    (
+        new volVectorField
+        (
+            IOobject
+            (
+                "fvOptionAdj::dxdbMult",
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedVector(dimLength/pow3(dimTime), Zero)
+        )
+    );
+    return tdxdbMult;
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjoint.H b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjoint.H
new file mode 100644
index 0000000000000000000000000000000000000000..822438c2fb071a528bd3e45b7970063f186d162f
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjoint.H
@@ -0,0 +1,135 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::fv::optionAdjoint
+
+Description
+    Similar to fv::option but with additional functionality to contribute to
+    the sensitivity deriavtives
+
+SourceFiles
+    fvOptionAdjoint.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef fvOptionAdjoint_H
+#define fvOptionAdjoint_H
+
+#include "fvOption.H"
+#include "incompressibleAdjointVars.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace fv
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class optionAdjoint Declaration
+\*---------------------------------------------------------------------------*/
+
+class optionAdjoint
+:
+    public option
+{
+public:
+
+    //- Runtime type information
+    TypeName("optionAdjoint");
+
+
+    // Constructors
+
+        //- Construct from components
+        optionAdjoint
+        (
+            const word& name,
+            const word& modelType,
+            const dictionary& dict,
+            const fvMesh& mesh
+        );
+
+        //- Return clone
+        autoPtr<optionAdjoint> clone() const
+        {
+            notImplemented("autoPtr<optionAdjoint> clone() const");
+            return autoPtr<optionAdjoint>(nullptr);
+        }
+
+
+     // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            optionAdjoint,
+            dictionary,
+            (
+                const word& name,
+                const word& modelType,
+                const dictionary& dict,
+                const fvMesh& mesh
+            ),
+            (name, modelType, dict, mesh)
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected fvOption model
+        static autoPtr<optionAdjoint> New
+        (
+            const word& name,
+            const dictionary& dict,
+            const fvMesh& mesh
+        );
+
+
+    //- Destructor
+    virtual ~optionAdjoint() = default;
+
+
+    // Member Functions
+    virtual tmp<volVectorField> dxdbMult(const incompressibleAdjointVars&);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace fv
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjointList.C b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjointList.C
new file mode 100644
index 0000000000000000000000000000000000000000..046addee8a1311c270696015750a651b942a1422
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjointList.C
@@ -0,0 +1,182 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "fvOptionAdjointList.H"
+#include "surfaceFields.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace fv
+{
+    defineTypeNameAndDebug(optionAdjointList, 0);
+}
+}
+
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+const Foam::dictionary& Foam::fv::optionAdjointList::optionAdjointsDict
+(
+    const dictionary& dict
+) const
+{
+    if (dict.found("optionAdjoints"))
+    {
+        return dict.subDict("optionAdjoints");
+    }
+    else
+    {
+        return dict;
+    }
+}
+
+
+bool Foam::fv::optionAdjointList::readOptionAdjoints(const dictionary& dict)
+{
+    checkTimeIndex_ = mesh_.time().timeIndex() + 2;
+
+    bool allOk = true;
+    forAll(*this, i)
+    {
+        optionAdjoint& bs = this->operator[](i);
+        bool ok = bs.read(dict.subDict(bs.name()));
+        allOk = (allOk && ok);
+    }
+    return allOk;
+}
+
+
+void Foam::fv::optionAdjointList::checkApplied() const
+{
+    if (mesh_.time().timeIndex() == checkTimeIndex_)
+    {
+        forAll(*this, i)
+        {
+            const optionAdjoint& bs = this->operator[](i);
+            bs.checkApplied();
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::fv::optionAdjointList::optionAdjointList
+(
+    const fvMesh& mesh,
+    const dictionary& dict
+)
+:
+    PtrList<optionAdjoint>(),
+    mesh_(mesh),
+    checkTimeIndex_(mesh_.time().startTimeIndex() + 2)
+{
+    reset(optionAdjointsDict(dict));
+}
+
+
+Foam::fv::optionAdjointList::optionAdjointList(const fvMesh& mesh)
+:
+    PtrList<optionAdjoint>(),
+    mesh_(mesh),
+    checkTimeIndex_(mesh_.time().startTimeIndex() + 2)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::fv::optionAdjointList::reset(const dictionary& dict)
+{
+    label count = 0;
+    forAllConstIter(dictionary, dict, iter)
+    {
+        // safety:
+        if (iter().isDict())
+        {
+            count++;
+        }
+    }
+
+    this->setSize(count);
+    label i = 0;
+    forAllConstIter(dictionary, dict, iter)
+    {
+        if (iter().isDict())
+        {
+            const word& name = iter().keyword();
+            const dictionary& sourceDict = iter().dict();
+
+            this->set
+            (
+                i++,
+                optionAdjoint::New(name, sourceDict, mesh_)
+            );
+        }
+    }
+}
+
+
+bool Foam::fv::optionAdjointList::read(const dictionary& dict)
+{
+    return readOptionAdjoints(optionAdjointsDict(dict));
+}
+
+
+bool Foam::fv::optionAdjointList::writeData(Ostream& os) const
+{
+    // Write list contents
+    forAll(*this, i)
+    {
+        os  << nl;
+        this->operator[](i).writeData(os);
+    }
+
+    // Check state of IOstream
+    return os.good();
+}
+
+
+// * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
+
+namespace Foam
+{
+    Ostream& operator<<
+    (
+        Ostream& os,
+        const fv::optionAdjointList& optionAdjoints
+    )
+    {
+        optionAdjoints.writeData(os);
+        return os;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjointList.H b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjointList.H
new file mode 100644
index 0000000000000000000000000000000000000000..bfc8b823393b9ff49519105394479005b0c4f2fa
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjointList.H
@@ -0,0 +1,220 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::fv::optionAdjointList
+
+DescriptionAdjoint
+    List of finite volume optionAdjoints
+
+SourceFile
+    optionAdjointList.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef optionAdjointList_H
+#define optionAdjointList_H
+
+#include "PtrList.H"
+#include "GeometricField.H"
+#include "fvPatchField.H"
+#include "fvOptionAdjoint.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace fv
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class optionAdjointList Declaration
+\*---------------------------------------------------------------------------*/
+
+class optionAdjointList
+:
+    public PtrList<optionAdjoint>
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        optionAdjointList(const optionAdjointList&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const optionAdjointList&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        //- Reference to the mesh database
+        const fvMesh& mesh_;
+
+        //- Time index to check that all defined sources have been applied
+        label checkTimeIndex_;
+
+
+    // Protected Member Functions
+
+        //- Return the "optionAdjoints" sub-dictionary if present otherwise
+        //- return dict
+        const dictionary& optionAdjointsDict(const dictionary& dict) const;
+
+        //- Read optionAdjoints dictionary
+        bool readOptionAdjoints(const dictionary& dict);
+
+        //- Check that all sources have been applied
+        void checkApplied() const;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("optionAdjointList");
+
+
+    // Constructors
+
+        //- Construct null
+        optionAdjointList(const fvMesh& mesh);
+
+        //- Construct from mesh and dictionary
+        optionAdjointList(const fvMesh& mesh, const dictionary& dict);
+
+
+    //- Destructor
+    virtual ~optionAdjointList() = default;
+
+
+    // Member Functions
+
+        //- Reset the source list
+        void reset(const dictionary& dict);
+
+        //- Correct
+        template<class Type>
+        void correct(GeometricField<Type, fvPatchField, volMesh>& fld);
+
+
+        // Sources
+
+            //- Return source for equation
+            template<class Type>
+            tmp<fvMatrix<Type>> operator()
+            (
+                GeometricField<Type, fvPatchField, volMesh>& fld
+            );
+
+            //- Return source for equation with specified name
+            template<class Type>
+            tmp<fvMatrix<Type>> operator()
+            (
+                GeometricField<Type, fvPatchField, volMesh>& fld,
+                const word& fieldName
+            );
+
+            //- Return source for equation
+            template<class Type>
+            tmp<fvMatrix<Type>> operator()
+            (
+                const volScalarField& rho,
+                GeometricField<Type, fvPatchField, volMesh>& fld
+            );
+
+            //- Return source for equation with specified name
+            template<class Type>
+            tmp<fvMatrix<Type>> operator()
+            (
+                const volScalarField& rho,
+                GeometricField<Type, fvPatchField, volMesh>& fld,
+                const word& fieldName
+            );
+
+            //- Return source for equation
+            template<class Type>
+            tmp<fvMatrix<Type>> operator()
+            (
+                const volScalarField& alpha,
+                const volScalarField& rho,
+                GeometricField<Type, fvPatchField, volMesh>& fld
+            );
+
+            //- Return source for equation with specified name
+            template<class Type>
+            tmp<fvMatrix<Type>> operator()
+            (
+                const volScalarField& alpha,
+                const volScalarField& rho,
+                GeometricField<Type, fvPatchField, volMesh>& fld,
+                const word& fieldName
+            );
+
+
+        // Constraints
+
+            //- Apply constraints to equation
+            template<class Type>
+            void constrain(fvMatrix<Type>& eqn);
+
+
+        // I-O
+
+            //- Read dictionary
+            virtual bool read(const dictionary& dict);
+
+            //- Write data to Ostream
+            virtual bool writeData(Ostream& os) const;
+
+            //- Ostream operator
+            friend Ostream& operator<<
+            (
+                Ostream& os,
+                const optionAdjointList& optionAdjoints
+            );
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace fv
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "fvOptionAdjointListTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjointListTemplates.C b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjointListTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..1484e4766576452c80abd47f15f0ddd02beb66e9
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/fvOptions/fvOptionAdjointListTemplates.C
@@ -0,0 +1,254 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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/>.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class Type>
+void Foam::fv::optionAdjointList::correct
+(
+    GeometricField<Type, fvPatchField, volMesh>& fld
+)
+{
+    const word& fieldName = fld.name();
+
+    forAll(*this, i)
+    {
+        optionAdjoint& source = this->operator[](i);
+
+        label fieldI = source.applyToField(fieldName);
+
+        if (fieldI != -1)
+        {
+            source.setApplied(fieldI);
+
+            if (source.isActive())
+            {
+                if (debug)
+                {
+                    Info<< "Correcting source " << source.name()
+                        << " for field " << fieldName << endl;
+                }
+
+                source.correct(fld);
+            }
+        }
+    }
+}
+
+
+template<class Type>
+Foam::tmp<Foam::fvMatrix<Type>> Foam::fv::optionAdjointList::operator()
+(
+    GeometricField<Type, fvPatchField, volMesh>& fld
+)
+{
+    return this->operator()(fld, fld.name());
+}
+
+
+template<class Type>
+Foam::tmp<Foam::fvMatrix<Type>> Foam::fv::optionAdjointList::operator()
+(
+    GeometricField<Type, fvPatchField, volMesh>& fld,
+    const word& fieldName
+)
+{
+    checkApplied();
+
+    const dimensionSet ds = fld.dimensions()/dimTime*dimVolume;
+
+    tmp<fvMatrix<Type>> tmtx(new fvMatrix<Type>(fld, ds));
+    fvMatrix<Type>& mtx = tmtx.ref();
+
+    forAll(*this, i)
+    {
+        optionAdjoint& source = this->operator[](i);
+
+        label fieldI = source.applyToField(fieldName);
+
+        if (fieldI != -1)
+        {
+            source.setApplied(fieldI);
+
+            if (source.isActive())
+            {
+                if (debug)
+                {
+                    Info<< "Applying source " << source.name() << " to field "
+                        << fieldName << endl;
+                }
+
+                source.addSup(mtx, fieldI);
+            }
+        }
+    }
+
+    return tmtx;
+}
+
+
+template<class Type>
+Foam::tmp<Foam::fvMatrix<Type>> Foam::fv::optionAdjointList::operator()
+(
+    const volScalarField& rho,
+    GeometricField<Type, fvPatchField, volMesh>& fld
+)
+{
+    return this->operator()(rho, fld, fld.name());
+}
+
+
+template<class Type>
+Foam::tmp<Foam::fvMatrix<Type>> Foam::fv::optionAdjointList::operator()
+(
+    const volScalarField& rho,
+    GeometricField<Type, fvPatchField, volMesh>& fld,
+    const word& fieldName
+)
+{
+    checkApplied();
+
+    const dimensionSet ds = rho.dimensions()*fld.dimensions()/dimTime*dimVolume;
+
+    tmp<fvMatrix<Type>> tmtx(new fvMatrix<Type>(fld, ds));
+    fvMatrix<Type>& mtx = tmtx.ref();
+
+    forAll(*this, i)
+    {
+        optionAdjoint& source = this->operator[](i);
+
+        label fieldI = source.applyToField(fieldName);
+
+        if (fieldI != -1)
+        {
+            source.setApplied(fieldI);
+
+            if (source.isActive())
+            {
+                if (debug)
+                {
+                    Info<< "Applying source " << source.name() << " to field "
+                        << fieldName << endl;
+                }
+
+                source.addSup(rho, mtx, fieldI);
+            }
+        }
+    }
+
+    return tmtx;
+}
+
+
+template<class Type>
+Foam::tmp<Foam::fvMatrix<Type>> Foam::fv::optionAdjointList::operator()
+(
+    const volScalarField& alpha,
+    const volScalarField& rho,
+    GeometricField<Type, fvPatchField, volMesh>& fld
+)
+{
+    return this->operator()(alpha, rho, fld, fld.name());
+}
+
+
+template<class Type>
+Foam::tmp<Foam::fvMatrix<Type>> Foam::fv::optionAdjointList::operator()
+(
+    const volScalarField& alpha,
+    const volScalarField& rho,
+    GeometricField<Type, fvPatchField, volMesh>& fld,
+    const word& fieldName
+)
+{
+    checkApplied();
+
+    const dimensionSet ds =
+        alpha.dimensions()*rho.dimensions()*fld.dimensions()/dimTime*dimVolume;
+
+    tmp<fvMatrix<Type>> tmtx(new fvMatrix<Type>(fld, ds));
+    fvMatrix<Type>& mtx = tmtx.ref();
+
+    forAll(*this, i)
+    {
+        optionAdjoint& source = this->operator[](i);
+
+        label fieldI = source.applyToField(fieldName);
+
+        if (fieldI != -1)
+        {
+            source.setApplied(fieldI);
+
+            if (source.isActive())
+            {
+                if (debug)
+                {
+                    Info<< "Applying source " << source.name() << " to field "
+                        << fieldName << endl;
+                }
+
+                source.addSup(alpha, rho, mtx, fieldI);
+            }
+        }
+    }
+
+    return tmtx;
+}
+
+
+template<class Type>
+void Foam::fv::optionAdjointList::constrain(fvMatrix<Type>& eqn)
+{
+    checkApplied();
+
+    forAll(*this, i)
+    {
+        optionAdjoint& source = this->operator[](i);
+
+        label fieldI = source.applyToField(eqn.psi().name());
+
+        if (fieldI != -1)
+        {
+            source.setApplied(fieldI);
+
+            if (source.isActive())
+            {
+                if (debug)
+                {
+                    Info<< "Applying constraint " << source.name()
+                        << " to field " << eqn.psi().name() << endl;
+                }
+
+                source.constrain(eqn, fieldI);
+            }
+        }
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/include/createFvOptionsAdjoint.H b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/include/createFvOptionsAdjoint.H
new file mode 100644
index 0000000000000000000000000000000000000000..baa10eadf0a2a8d90bcfa982439a811c6c815dfd
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/fvOptionsAdjoint/include/createFvOptionsAdjoint.H
@@ -0,0 +1 @@
+fv::IOoptionListAdjoint fvOptionsAdjoint(mesh);
diff --git a/src/optimisation/adjointOptimisation/adjoint/global/boundaryFieldsFwd.H b/src/optimisation/adjointOptimisation/adjoint/global/boundaryFieldsFwd.H
new file mode 100644
index 0000000000000000000000000000000000000000..69ea5da6b6ecdabe80ff71fbb9276d505d4c0dda
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/global/boundaryFieldsFwd.H
@@ -0,0 +1,72 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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/>.
+
+
+InClass
+    Foam::boundaryFieldsFwd
+
+Description
+    Useful typenames for fields defined only at the boundaries
+
+SourceFiles
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef boundaryFieldsFwd_H
+#define boundaryFieldsFwd_H
+
+#include "fieldTypes.H"
+#include "volFields.H"
+#include "List.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+//volFields
+typedef typename volScalarField::Boundary boundaryScalarField;
+typedef typename volVectorField::Boundary boundaryVectorField;
+typedef typename volTensorField::Boundary boundaryTensorField;
+
+//pointFields - actually a plain list of fields with dimension equal to the
+// number of points per patch
+typedef List<Field<scalar>> pointBoundaryScalarField;
+typedef List<Field<vector>> pointBoundaryVectorField;
+typedef List<Field<tensor>> pointBoundaryTensorField;
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/global/createZeroField.H b/src/optimisation/adjointOptimisation/adjoint/global/createZeroField.H
new file mode 100644
index 0000000000000000000000000000000000000000..2ef87a89f968c08da6ea26497d36d6bf81549498
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/global/createZeroField.H
@@ -0,0 +1,155 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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/>.
+
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifndef createZeroField_H
+#define createZeroField_H
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+template<class Type>
+autoPtr<GeometricField<Type, fvPatchField, volMesh>>
+createZeroFieldPtr
+(
+    const fvMesh& mesh,
+    const word& name,
+    const dimensionSet dims,
+    bool printAllocation = false
+)
+{
+    if (printAllocation)
+    {
+        Info<< "Allocating new volField " << name << nl << endl;
+    }
+
+    return
+    (
+        autoPtr<GeometricField<Type, fvPatchField, volMesh>>::New
+        (
+            IOobject
+            (
+               name,
+               mesh.time().timeName(),
+               mesh,
+               IOobject::NO_READ,
+               IOobject::NO_WRITE
+            ),
+            mesh,
+            dimensioned<Type>(dims, Zero)
+        )
+    );
+}
+
+
+template<class Type>
+autoPtr<typename GeometricField<Type, fvPatchField, volMesh>::Boundary>
+createZeroBoundaryPtr
+(
+    const fvMesh& mesh,
+    bool printAllocation = false
+)
+{
+    if (printAllocation)
+    {
+        Info<< "Allocating new boundaryField " << nl << endl;
+    }
+
+    typedef typename GeometricField<Type, fvPatchField, volMesh>::Boundary
+        Boundary;
+
+    autoPtr<Boundary> bPtr
+    (
+        new Boundary
+        (
+            mesh.boundary(),
+            mesh.V()*pTraits<Type>::zero,  // Dummy internal field,
+            calculatedFvPatchField<Type>::typeName
+        )
+    );
+
+    // Values are not assigned! Assign manually
+    Boundary& bRef = bPtr();
+    forAll(bRef, pI)
+    {
+        bRef[pI] = pTraits<Type>::zero;
+    }
+
+    return (bPtr);
+}
+
+
+template<class Type>
+autoPtr<List<Field<Type>>>
+createZeroBoundaryPointFieldPtr
+(
+    const fvMesh& mesh,
+    bool printAllocation = false
+)
+{
+    if (printAllocation)
+    {
+        Info<< "Allocating new point boundaryField " << nl << endl;
+    }
+
+    autoPtr<List<Field<Type>>> bPtr
+    (
+        new List<Field<Type>>
+        (
+            mesh.boundary().size()
+        )
+    );
+
+    List<Field<Type>>& bRef = bPtr();
+    forAll(bRef, pI)
+    {
+        bRef[pI] =
+            Field<Type>
+            (
+                mesh.boundaryMesh()[pI].nPoints(),
+                pTraits<Type>::zero
+            );
+    }
+
+    return (bPtr);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager/objectiveManager.C b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager/objectiveManager.C
new file mode 100644
index 0000000000000000000000000000000000000000..ebba238ff401abb7457fbe24ddd3a60c0631c856
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager/objectiveManager.C
@@ -0,0 +1,241 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "objectiveManager.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(objectiveManager, 0);
+defineRunTimeSelectionTable(objectiveManager, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+objectiveManager::objectiveManager
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    const word& adjointSolverName,
+    const word& primalSolverName
+)
+:
+    regIOobject
+    (
+        IOobject
+        (
+            "objectiveManager" + adjointSolverName,
+            mesh.time().system(),
+            mesh,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE,
+            true  //register object
+        )
+    ),
+    mesh_(mesh),
+    dict_(dict),
+    adjointSolverName_(adjointSolverName),
+    primalSolverName_(primalSolverName),
+    objectives_(0)
+{
+    // Construct objectives
+    //~~~~~~~~~~~~~~~~~~~~~
+    Info << "Constructing objective functions " << nl << endl;
+    const word objectiveType = dict.get<word>("type");
+    const dictionary& objectiveNamesDict(dict.subDict("objectiveNames"));
+    wordList objectiveNames(objectiveNamesDict.toc());
+    objectives_.setSize(objectiveNames.size());
+
+    forAll(objectiveNames, objectivei)
+    {
+        const word& objectiveName = objectiveNames[objectivei];
+
+        objectives_.set
+        (
+            objectivei,
+            objective::New
+            (
+                mesh_,
+                objectiveNamesDict.subDict(objectiveName),
+                objectiveType,
+                adjointSolverName,
+                primalSolverName
+            )
+        );
+    }
+
+    if (objectives_.empty())
+    {
+        FatalIOErrorInFunction(objectiveNamesDict)
+            << "No objectives have been set - cannot perform an optimisation"
+            << exit(FatalIOError);
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+autoPtr<objectiveManager> objectiveManager::New
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    const word& adjointSolverName,
+    const word& primalSolverName
+)
+{
+    // Determine type of objectiveManager from objectiveType
+    const word objectiveType(dict.get<word>("type"));
+    const word managerType("objectiveManager" & objectiveType);
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(managerType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown objectiveManagerType type " << managerType
+            << nl << nl
+            << "Valid objectiveManagerTypes are :" << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return autoPtr<objectiveManager>
+    (
+        cstrIter()(mesh, dict, adjointSolverName, primalSolverName)
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool objectiveManager::readDict(const dictionary& dict)
+{
+    for (objective& obj : objectives_)
+    {
+        obj.readDict
+        (
+            dict.subDict("objectiveNames").subDict(obj.objectiveName())
+        );
+    }
+
+    return true;
+}
+
+void objectiveManager::updateNormalizationFactor()
+{
+    // Update normalization factors for all objectives
+    for (objective& obj : objectives_)
+    {
+        obj.updateNormalizationFactor();
+    }
+}
+
+
+void objectiveManager::update()
+{
+    // Update all fields related to the objective function
+    for (objective& obj : objectives_)
+    {
+        obj.update();
+    }
+}
+
+
+scalar objectiveManager::print()
+{
+    scalar objValue(Zero);
+    for (objective& obj : objectives_)
+    {
+        scalar cost = obj.J();
+        scalar weight = obj.weight();
+        objValue += weight*cost;
+
+        Info<< obj.type() << " : " << cost << endl;
+    }
+
+    Info<< "Objective function manager" << nl
+        << "    Weighted Lagrangian " << " : " << objValue << nl << endl;
+
+    return objValue;
+}
+
+
+bool objectiveManager::write(const bool valid) const
+{
+    for (const objective& obj : objectives_)
+    {
+        // Write objective function to file
+        obj.write();
+        obj.writeMeanValue();
+    }
+
+    return true;
+}
+
+
+void objectiveManager::updateAndWrite()
+{
+    updateNormalizationFactor();
+    update();
+    print();
+    write();
+}
+
+
+PtrList<objective>& objectiveManager::getObjectiveFunctions()
+{
+    return objectives_;
+}
+
+
+const PtrList<objective>& objectiveManager::getObjectiveFunctions() const
+{
+    return objectives_;
+}
+
+
+const word& objectiveManager::adjointSolverName() const
+{
+    return adjointSolverName_;
+}
+
+
+const word& objectiveManager::primalSolverName() const
+{
+    return primalSolverName_;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager/objectiveManager.H b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager/objectiveManager.H
new file mode 100644
index 0000000000000000000000000000000000000000..a70bf47134e49a6c5e3cbb3bdd985042f83a2d53
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager/objectiveManager.H
@@ -0,0 +1,193 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::objectiveManager
+
+Description
+    class for managing incompressible objective functions.
+
+SourceFiles
+    objectiveManager.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef objectiveManager_H
+#define objectiveManager_H
+
+#include "fvMesh.H"
+#include "objective.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class objectiveManager Declaration
+\*---------------------------------------------------------------------------*/
+
+class objectiveManager
+:
+    public regIOobject
+{
+protected:
+
+    // Protected data
+
+        const fvMesh& mesh_;
+        const dictionary& dict_;
+        const word adjointSolverName_;
+        const word primalSolverName_;
+        PtrList<objective> objectives_;
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        objectiveManager(const objectiveManager&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const objectiveManager&) = delete;
+
+
+public:
+
+    TypeName("objectiveManager");
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            objectiveManager,
+            dictionary,
+            (
+                const fvMesh& mesh,
+                const dictionary& dict,
+                const word& adjointSolverName,
+                const word& primalSolverName
+            ),
+            (mesh, dict, adjointSolverName, primalSolverName)
+        );
+
+    // Constructors
+
+        //- Construct from components
+        objectiveManager
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            const word& adjointSolverName,
+            const word& primalSolverName
+        );
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<objectiveManager> New
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            const word& adjointSolverName,
+            const word& primalSolverName
+        );
+
+
+    //- Destructor
+    virtual ~objectiveManager() = default;
+
+
+    // Member Functions
+
+        virtual bool readDict(const dictionary& dict);
+
+        //- Update objective function related values
+        void updateNormalizationFactor();
+
+        //- Update objective function related values
+        void update();
+
+        //- Print to screen
+        scalar print();
+
+        //- Write objective function history
+        virtual bool write(const bool valid = true) const;
+
+        //- Call all functions required prior to the solution of the adjoint
+        //- equations
+        void updateAndWrite();
+
+        //- Return reference to objective functions
+        PtrList<objective>& getObjectiveFunctions();
+
+        //- Return constant reference to objective functions
+        const PtrList<objective>& getObjectiveFunctions() const;
+
+        //- Return name of adjointSolverManager
+        const word& adjointSolverManagerName() const;
+
+        //- Return name of the adjointSolver
+        const word& adjointSolverName() const;
+
+        //- Return name of the primalSolver
+        const word& primalSolverName() const;
+
+        //- Add contribution to adjoint momentum PDEs
+        virtual void addUaEqnSource(fvVectorMatrix& UaEqn) = 0;
+
+        //- Add contribution to adjoint momentum PDEs
+        virtual void addPaEqnSource(fvScalarMatrix& paEqn) = 0;
+
+        //- Add contribution to first adjoint turbulence model PDE
+        virtual void addTMEqn1Source(fvScalarMatrix& adjTMEqn1) = 0;
+
+        //- Add contribution to second adjoint turbulence model PDE
+        virtual void addTMEqn2Source(fvScalarMatrix& adjTMEqn2) = 0;
+
+
+    // IO
+
+        virtual bool writeData(Ostream&) const
+        {
+            return true;
+        }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.C
new file mode 100644
index 0000000000000000000000000000000000000000..cb7f229924b7f9470a689eb6cb9318e74e06750f
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.C
@@ -0,0 +1,131 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "objectiveManagerIncompressible.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(objectiveManagerIncompressible, 0);
+addToRunTimeSelectionTable
+(
+    objectiveManager,
+    objectiveManagerIncompressible,
+    dictionary
+);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+objectiveManagerIncompressible::objectiveManagerIncompressible
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    const word& adjointSolverName,
+    const word& primalSolverName
+)
+:
+    objectiveManager(mesh, dict, adjointSolverName, primalSolverName)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void objectiveManagerIncompressible::addUaEqnSource(fvVectorMatrix& UaEqn)
+{
+    // Add contributions from objective functions
+    for (objective& obj : objectives_)
+    {
+        auto& icoObj = refCast<objectiveIncompressible>(obj);
+
+        if (icoObj.hasdJdv())
+        {
+            scalar weight = icoObj.weight();
+            UaEqn += weight*icoObj.dJdv();
+        }
+    }
+}
+
+
+void objectiveManagerIncompressible::addPaEqnSource(fvScalarMatrix& paEqn)
+{
+    // Add contributions from objective functions
+    for (objective& obj : objectives_)
+    {
+        auto& icoObj = refCast<objectiveIncompressible>(obj);
+
+        if (icoObj.hasdJdp())
+        {
+            scalar weight = icoObj.weight();
+            paEqn += weight*icoObj.dJdp();
+        }
+    }
+}
+
+
+void objectiveManagerIncompressible::addTMEqn1Source(fvScalarMatrix& adjTMEqn1)
+{
+    // Add contributions from objective functions
+    for (objective& obj : objectives_)
+    {
+        auto& icoObj = refCast<objectiveIncompressible>(obj);
+
+        if (icoObj.hasdJdTMVar1())
+        {
+            scalar weight = icoObj.weight();
+            adjTMEqn1 += weight*icoObj.dJdTMvar1();
+        }
+    }
+}
+
+
+void objectiveManagerIncompressible::addTMEqn2Source(fvScalarMatrix& adjTMEqn2)
+{
+    // Add contributions from objective functions
+    for (objective& obj : objectives_)
+    {
+        auto& icoObj = refCast<objectiveIncompressible>(obj);
+
+        if (icoObj.hasdJdTMVar2())
+        {
+            scalar weight = icoObj.weight();
+            adjTMEqn2 += weight*icoObj.dJdTMvar2();
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.H
new file mode 100644
index 0000000000000000000000000000000000000000..abf5ab0b662e650dd670d86e3f1701d29be2a948
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.H
@@ -0,0 +1,117 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::objectiveManagerIncompressible
+
+Description
+    class for managing incompressible objective functions.
+
+SourceFiles
+    objectiveManagerIncompressible.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef objectiveManagerIncompressible_H
+#define objectiveManagerIncompressible_H
+
+#include "objectiveManager.H"
+#include "objectiveIncompressible.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+               Class objectiveManagerIncompressible Declaration
+\*---------------------------------------------------------------------------*/
+
+class objectiveManagerIncompressible
+:
+    public objectiveManager
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        objectiveManagerIncompressible
+        (
+            const objectiveManagerIncompressible&
+        ) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const objectiveManagerIncompressible&) = delete;
+
+
+public:
+
+    TypeName("objectiveManagerIncompressible");
+
+    // Constructors
+
+        //- Construct from components
+        objectiveManagerIncompressible
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            const word& adjointSolverName,
+            const word& primalSolverName
+        );
+
+
+    //- Destructor
+    virtual ~objectiveManagerIncompressible() = default;
+
+
+    // Member Functions
+
+        //- Add contribution to adjoint momentum PDEs
+        virtual void addUaEqnSource(fvVectorMatrix& UaEqn);
+
+        //- Add contribution to adjoint momentum PDEs
+        virtual void addPaEqnSource(fvScalarMatrix& paEqn);
+
+        //- Add contribution to adjoint turbulence model PDE
+        virtual void addTMEqn1Source(fvScalarMatrix& adjTMEqn1);
+
+        //- Add contribution to adjoint turbulence model PDE
+        virtual void addTMEqn2Source(fvScalarMatrix& adjTMEqn2);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveForce/objectiveForce.C b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveForce/objectiveForce.C
new file mode 100644
index 0000000000000000000000000000000000000000..7a3ac3402f06cc0d07b0001cceca95e777b4a869
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveForce/objectiveForce.C
@@ -0,0 +1,299 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "objectiveForce.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace objectives
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(objectiveForce, 0);
+addToRunTimeSelectionTable
+(
+    objectiveIncompressible,
+    objectiveForce,
+    dictionary
+);
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+objectiveForce::objectiveForce
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    const word& adjointSolverName,
+    const word& primalSolverName
+)
+:
+    objectiveIncompressible(mesh, dict, adjointSolverName, primalSolverName),
+    forcePatches_
+    (
+        mesh_.boundaryMesh().patchSet
+        (
+            wordReList(dict.get<wordRes>("patches"))
+        )
+    ),
+    forceDirection_(dict.get<vector>("direction")),
+    Aref_(dict.get<scalar>("Aref")),
+    rhoInf_(dict.get<scalar>("rhoInf")),
+    UInf_(dict.get<scalar>("UInf")),
+    stressXPtr_
+    (
+        Foam::createZeroFieldPtr<vector>
+        (
+            mesh_, "stressX", dimLength/sqr(dimTime)
+        )
+    ),
+    stressYPtr_
+    (
+        Foam::createZeroFieldPtr<vector>
+        (
+            mesh_, "stressY", dimLength/sqr(dimTime)
+        )
+    ),
+    stressZPtr_
+    (
+        Foam::createZeroFieldPtr<vector>
+        (
+            mesh_, "stressZ", dimLength/sqr(dimTime)
+        )
+    )
+{
+    // Sanity check and print info
+    if (forcePatches_.empty())
+    {
+        FatalErrorInFunction
+            << "No valid patch name on which to minimize " << type() << endl
+            << exit(FatalError);
+    }
+    if (debug)
+    {
+        Info<< "Minimizing " << type() << " in patches:" << endl;
+        for (const label patchI : forcePatches_)
+        {
+            Info<< "\t " << mesh_.boundary()[patchI].name() << endl;
+        }
+    }
+
+    // Allocate boundary field pointers
+    bdJdpPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    bdSdbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    bdxdbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    bdJdStressPtr_.reset(createZeroBoundaryPtr<tensor>(mesh_));
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+scalar objectiveForce::J()
+{
+    vector pressureForce(Zero);
+    vector viscousForce(Zero);
+    vector cumulativeForce(Zero);
+
+
+    const volScalarField& p = vars_.pInst();
+    const autoPtr<incompressible::turbulenceModel>&
+       turbulence = vars_.turbulence();
+
+    volSymmTensorField devReff(turbulence->devReff());
+
+    for (const label patchI : forcePatches_)
+    {
+        pressureForce += gSum
+        (
+            mesh_.Sf().boundaryField()[patchI] * p.boundaryField()[patchI]
+        );
+        // Viscous term calculated using the full tensor derivative
+        viscousForce += gSum
+        (
+            devReff.boundaryField()[patchI]
+          & mesh_.Sf().boundaryField()[patchI]
+        );
+    }
+
+    cumulativeForce = pressureForce + viscousForce;
+
+    scalar force = cumulativeForce & forceDirection_;
+
+    // Intentionally not using denom - derived might implement virtual denom()
+    // function differently
+    scalar Cforce = force/(0.5*UInf_*UInf_*Aref_);
+
+    DebugInfo
+        << "Force|Coeff " << force << "|" << Cforce << endl;
+
+    J_ = Cforce;
+
+    return Cforce;
+}
+
+
+void objectiveForce::update_boundarydJdp()
+{
+    for (const label patchI : forcePatches_)
+    {
+        bdJdpPtr_()[patchI] = forceDirection_/denom();
+    }
+}
+
+
+void objectiveForce::update_dSdbMultiplier()
+{
+    // Compute contributions with mean fields, if present
+    const volScalarField& p = vars_.p();
+    const volVectorField& U = vars_.U();
+    const autoPtr<incompressible::RASModelVariables>&
+        turbVars = vars_.RASModelVariables();
+    const singlePhaseTransportModel& lamTransp = vars_.laminarTransport();
+
+    tmp<volSymmTensorField> tdevReff = turbVars->devReff(lamTransp, U);
+    const volSymmTensorField& devReff = tdevReff();
+
+    for (const label patchI : forcePatches_)
+    {
+        bdSdbMultPtr_()[patchI] =
+        (
+            (
+                forceDirection_& devReff.boundaryField()[patchI]
+            )
+          + (forceDirection_)*p.boundaryField()[patchI]
+        )
+       /denom();
+    }
+}
+
+
+void objectiveForce::update_dxdbMultiplier()
+{
+    const volScalarField& p = vars_.p();
+    const volVectorField& U = vars_.U();
+
+    const autoPtr<incompressible::RASModelVariables>&
+        turbVars = vars_.RASModelVariables();
+    const singlePhaseTransportModel& lamTransp = vars_.laminarTransport();
+
+    //tmp<volSymmTensorField> tdevReff = turbVars->devReff(lamTransp, U);
+    //const volSymmTensorField& devReff = tdevReff();
+
+    volScalarField nuEff(lamTransp.nu() + turbVars->nutRef());
+    volTensorField gradU(fvc::grad(U));
+    volTensorField::Boundary& gradUbf = gradU.boundaryFieldRef();
+
+    // Explicitly correct the boundary gradient to get rid of
+    // the tangential component
+    forAll(mesh_.boundary(), patchI)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        if (isA<wallFvPatch>(patch))
+        {
+            tmp<vectorField> nf = patch.nf();
+            gradUbf[patchI] = nf*U.boundaryField()[patchI].snGrad();
+        }
+    }
+
+    volTensorField stress(nuEff*(gradU + T(gradU)));
+
+    stressXPtr_().replace(0, stress.component(0));
+    stressXPtr_().replace(1, stress.component(1));
+    stressXPtr_().replace(2, stress.component(2));
+
+    stressYPtr_().replace(0, stress.component(3));
+    stressYPtr_().replace(1, stress.component(4));
+    stressYPtr_().replace(2, stress.component(5));
+
+    stressZPtr_().replace(0, stress.component(6));
+    stressZPtr_().replace(1, stress.component(7));
+    stressZPtr_().replace(2, stress.component(8));
+
+    volTensorField gradStressX(fvc::grad(stressXPtr_()));
+    volTensorField gradStressY(fvc::grad(stressYPtr_()));
+    volTensorField gradStressZ(fvc::grad(stressZPtr_()));
+
+    // the notorious second-order derivative at the wall. Use with caution!
+    volVectorField gradp(fvc::grad(p));
+
+    for (const label patchI : forcePatches_)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        tmp<vectorField> tnf = patch.nf();
+        const vectorField& nf = tnf();
+        bdxdbMultPtr_()[patchI] =
+        (
+            (
+                (
+                   -(forceDirection_.x() * gradStressX.boundaryField()[patchI])
+                   -(forceDirection_.y() * gradStressY.boundaryField()[patchI])
+                   -(forceDirection_.z() * gradStressZ.boundaryField()[patchI])
+                ) & nf
+            )
+            + (forceDirection_ & nf)*gradp.boundaryField()[patchI]
+        )
+        /denom();
+    }
+}
+
+
+void objectiveForce::update_dJdStressMultiplier()
+{
+    for (const label patchI : forcePatches_)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        tmp<vectorField> tnf = patch.nf();
+        const vectorField& nf = tnf();
+        bdJdStressPtr_()[patchI] = (forceDirection_ * nf)/denom();
+    }
+}
+
+
+scalar objectiveForce::denom() const
+{
+    return 0.5*UInf_*UInf_*Aref_;
+}
+
+
+const vector& objectiveForce::forceDirection() const
+{
+    return forceDirection_;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace objectives
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveForce/objectiveForce.H b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveForce/objectiveForce.H
new file mode 100644
index 0000000000000000000000000000000000000000..2f2b6b20e2e2968aa51084eff0270f084cefeb0a
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveForce/objectiveForce.H
@@ -0,0 +1,133 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::objectives::objectiveForce
+
+Description
+
+SourceFiles
+    objectiveForce.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef objectiveForce_H
+#define objectiveForce_H
+
+#include "objectiveIncompressible.H"
+#include "wallFvPatch.H"
+#include "createZeroField.H"
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace objectives
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class objectiveForce Declaration
+\*---------------------------------------------------------------------------*/
+
+class objectiveForce
+:
+    public objectiveIncompressible
+{
+protected:
+
+    // Protected Data
+
+        labelHashSet forcePatches_;
+        vector forceDirection_;
+        scalar Aref_;
+        scalar rhoInf_;
+        scalar UInf_;
+
+        autoPtr<volVectorField> stressXPtr_;
+        autoPtr<volVectorField> stressYPtr_;
+        autoPtr<volVectorField> stressZPtr_;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("force");
+
+
+    // Constructors
+
+        //- Construct from components
+        objectiveForce
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            const word& adjointSolverName,
+            const word& primalSolverName
+        );
+
+
+    //- Destructor
+    virtual ~objectiveForce() = default;
+
+
+    // Member Functions
+
+        //- Return the objective function value
+        scalar J();
+
+        //- Update values to be added to the adjoint wall velocity
+        void update_boundarydJdp();
+
+        //- Update delta(n dS)/delta b multiplier
+        void update_dSdbMultiplier();
+
+        //- Update delta(x)/delta b multiplier
+        void update_dxdbMultiplier();
+
+        //- Update dJ/dStress multiplier
+        void update_dJdStressMultiplier();
+
+        //- Return denominator, without density
+        virtual scalar denom() const;
+
+        //- Return force direction
+        const vector& forceDirection() const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace objectives
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.C
new file mode 100644
index 0000000000000000000000000000000000000000..bb1c3d62881a391651b16ff64f17dfd6bf8d730d
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.C
@@ -0,0 +1,432 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "objectiveIncompressible.H"
+#include "incompressiblePrimalSolver.H"
+#include "createZeroField.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(objectiveIncompressible, 0);
+defineRunTimeSelectionTable(objectiveIncompressible, dictionary);
+addToRunTimeSelectionTable
+(
+    objective,
+    objectiveIncompressible,
+    objective
+);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+objectiveIncompressible::objectiveIncompressible
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    const word& adjointSolverName,
+    const word& primalSolverName
+)
+:
+    objective(mesh, dict, adjointSolverName, primalSolverName),
+
+    vars_
+    (
+        mesh.lookupObject<incompressiblePrimalSolver>(primalSolverName).
+            getVars()
+    ),
+
+    // Initialize pointers to nullptr.
+    // Not all of them are required for each objective function.
+    // Each child should allocate whatever is needed.
+
+    // Field adjoint Eqs
+    dJdvPtr_(nullptr),
+    dJdpPtr_(nullptr),
+    dJdTPtr_(nullptr),
+    dJdTMvar1Ptr_(nullptr),
+    dJdTMvar2Ptr_(nullptr),
+
+    // Adjoint boundary conditions
+    bdJdvPtr_(nullptr),
+    bdJdvnPtr_(nullptr),
+    bdJdvtPtr_(nullptr),
+    bdJdpPtr_(nullptr),
+    bdJdTPtr_(nullptr),
+    bdJdTMvar1Ptr_(nullptr),
+    bdJdTMvar2Ptr_(nullptr)
+{
+    weight_ = dict.get<scalar>("weight");
+    computeMeanFields_ = vars_.computeMeanFields();
+}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+autoPtr<objectiveIncompressible> objectiveIncompressible::New
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    const word& adjointSolverName,
+    const word& primalSolverName
+)
+{
+    const word objectiveName = dict.dictName();
+    const word modelType(dict.get<word>("type"));
+
+    Info<< "Creating objective function : " << objectiveName
+        << " of type " << modelType << endl;
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown objectiveIncompressible type " << modelType << nl << nl
+            << "Valid objectiveIncompressible types are :" << endl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return autoPtr<objectiveIncompressible>
+    (
+        cstrIter()(mesh, dict, adjointSolverName, primalSolverName)
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+const volVectorField& objectiveIncompressible::dJdv()
+{
+    if (dJdvPtr_.empty())
+    {
+        // If pointer is not set, set it to a zero field
+        dJdvPtr_.reset
+        (
+            createZeroFieldPtr<vector>
+            (
+                mesh_,
+                ("dJdv_"+type()),
+                dimensionSet(0, 3, -2, 0, 0, 0, 0)
+            )
+        );
+    }
+    return dJdvPtr_();
+}
+
+
+const volScalarField& objectiveIncompressible::dJdp()
+{
+    if (dJdpPtr_.empty())
+    {
+        // If pointer is not set, set it to a zero field
+        dJdpPtr_.reset
+        (
+            createZeroFieldPtr<scalar>
+            (
+                mesh_,
+                ("dJdp_"+type()),
+                dimensionSet(0, 3, -2, 0, 0, 0, 0)
+            )
+        );
+    }
+    return dJdpPtr_();
+}
+
+
+const volScalarField& objectiveIncompressible::dJdT()
+{
+    if (dJdTPtr_.empty())
+    {
+        // If pointer is not set, set it to a zero field
+        dJdTPtr_.reset
+        (
+            createZeroFieldPtr<scalar>
+            (
+                mesh_,
+                ("dJdT_"+type()),
+                dimensionSet(0, 3, -2, 0, 0, 0, 0)
+            )
+        );
+    }
+    return dJdTPtr_();
+}
+
+
+const volScalarField& objectiveIncompressible::dJdTMvar1()
+{
+    if (dJdTMvar1Ptr_.empty())
+    {
+        // If pointer is not set, set it to a zero field
+        dJdTMvar1Ptr_.reset
+        (
+            createZeroFieldPtr<scalar>
+            (
+                mesh_,
+                ("dJdTMvar1_"+type()),
+                dimensionSet(0, 0, -2, 0, 0, 0, 0)
+            )
+        );
+    }
+    return dJdTMvar1Ptr_();
+}
+
+
+const volScalarField& objectiveIncompressible::dJdTMvar2()
+{
+    if (dJdTMvar2Ptr_.empty())
+    {
+        // If pointer is not set, set it to a zero field
+        dJdTMvar2Ptr_.reset
+        (
+            createZeroFieldPtr<scalar>
+            (
+                mesh_,
+                ("dJdTMvar2_"+type()),
+                dimensionSet(0, 3, -2, 0, 0, 0, 0)
+            )
+        );
+    }
+    return dJdTMvar2Ptr_();
+}
+
+
+const fvPatchVectorField& objectiveIncompressible::boundarydJdv
+(
+    const label patchI
+)
+{
+    if (bdJdvPtr_.empty())
+    {
+        bdJdvPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdJdvPtr_()[patchI];
+}
+
+
+const fvPatchScalarField& objectiveIncompressible::boundarydJdvn
+(
+    const label patchI
+)
+{
+    if (bdJdvnPtr_.empty())
+    {
+        bdJdvnPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
+    }
+    return bdJdvnPtr_()[patchI];
+}
+
+
+const fvPatchVectorField& objectiveIncompressible::boundarydJdvt
+(
+    const label patchI
+)
+{
+    if (bdJdvtPtr_.empty())
+    {
+        bdJdvtPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdJdvtPtr_()[patchI];
+}
+
+
+const fvPatchVectorField& objectiveIncompressible::boundarydJdp
+(
+    const label patchI
+)
+{
+    if (bdJdpPtr_.empty())
+    {
+        bdJdpPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdJdpPtr_()[patchI];
+}
+
+
+const fvPatchScalarField& objectiveIncompressible::boundarydJdT
+(
+    const label patchI
+)
+{
+    if (bdJdTPtr_.empty())
+    {
+        bdJdTPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
+    }
+    return bdJdTPtr_()[patchI];
+}
+
+
+const fvPatchScalarField& objectiveIncompressible::boundarydJdTMvar1
+(
+    const label patchI
+)
+{
+    if (bdJdTMvar1Ptr_.empty())
+    {
+        bdJdTMvar1Ptr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
+    }
+    return bdJdTMvar1Ptr_()[patchI];
+}
+
+
+const fvPatchScalarField& objectiveIncompressible::boundarydJdTMvar2
+(
+    const label patchI
+)
+{
+    if (bdJdTMvar2Ptr_.empty())
+    {
+        bdJdTMvar2Ptr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
+    }
+    return bdJdTMvar2Ptr_()[patchI];
+}
+
+
+const boundaryVectorField& objectiveIncompressible::boundarydJdv()
+{
+    if (bdJdvPtr_.empty())
+    {
+        bdJdvPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdJdvPtr_();
+}
+
+
+const boundaryScalarField& objectiveIncompressible::boundarydJdvn()
+{
+    if (bdJdvnPtr_.empty())
+    {
+        bdJdvnPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
+    }
+    return bdJdvnPtr_();
+}
+
+
+const boundaryVectorField& objectiveIncompressible::boundarydJdvt()
+{
+    if (bdJdvtPtr_.empty())
+    {
+        bdJdvtPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdJdvtPtr_();
+}
+
+
+const boundaryVectorField& objectiveIncompressible::boundarydJdp()
+{
+    if (bdJdpPtr_.empty())
+    {
+        bdJdpPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdJdpPtr_();
+}
+
+
+const boundaryScalarField& objectiveIncompressible::boundarydJdT()
+{
+    if (bdJdTPtr_.empty())
+    {
+        bdJdTPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
+    }
+    return bdJdTPtr_();
+}
+
+
+const boundaryScalarField& objectiveIncompressible::boundarydJdTMvar1()
+{
+    if (bdJdTMvar1Ptr_.empty())
+    {
+        bdJdTMvar1Ptr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
+    }
+    return bdJdTMvar1Ptr_();
+}
+
+
+const boundaryScalarField& objectiveIncompressible::boundarydJdTMvar2()
+{
+    if (bdJdTMvar2Ptr_.empty())
+    {
+        bdJdTMvar2Ptr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
+    }
+    return bdJdTMvar2Ptr_();
+}
+
+
+void objectiveIncompressible::update()
+{
+    // Objective function value
+    J();
+
+    // Update mean values here since they might be used in the
+    // subsequent functions
+    update_meanValues();
+
+    // volFields
+    update_dJdv();
+    update_dJdp();
+    update_dJdT();
+    update_dJdTMvar1();
+    update_dJdTMvar2();
+    update_dJdb();
+    update_divDxDbMultiplier();
+    update_gradDxDbMultiplier();
+
+    // boundaryFields
+    update_boundarydJdv();
+    update_boundarydJdvn();
+    update_boundarydJdvt();
+    update_boundarydJdp();
+    update_boundarydJdT();
+    update_boundarydJdTMvar1();
+    update_boundarydJdTMvar2();
+    update_boundarydJdb();
+    update_dSdbMultiplier();
+    update_dndbMultiplier();
+    update_dxdbMultiplier();
+    update_dxdbDirectMultiplier();
+    update_boundaryEdgeContribution();
+    update_dJdStressMultiplier();
+}
+
+
+void objectiveIncompressible::write() const
+{
+    objective::write();
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.H
new file mode 100644
index 0000000000000000000000000000000000000000..d6782b216827cb723993d76a09eee00fcc48c319
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.H
@@ -0,0 +1,332 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::objectiveIncompressible
+
+Description
+    Abstract base class for objective functions in incompressible flows
+
+SourceFiles
+    objectiveIncompressible.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef objectiveIncompressible_H
+#define objectiveIncompressible_H
+
+#include "objective.H"
+#include "incompressibleVars.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                   Class objectiveIncompressible Declaration
+\*---------------------------------------------------------------------------*/
+
+class objectiveIncompressible
+:
+    public objective
+{
+protected:
+
+    // Protected data
+
+        const incompressibleVars& vars_;
+
+        // Contribution to field adjoint equations
+        // v,p,T and turbulence model variables
+        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        autoPtr<volVectorField> dJdvPtr_;
+        autoPtr<volScalarField> dJdpPtr_;
+        autoPtr<volScalarField> dJdTPtr_;
+
+        //- First  turbulence model variable
+        autoPtr<volScalarField> dJdTMvar1Ptr_;
+
+        //- Second turbulence model variable
+        autoPtr<volScalarField> dJdTMvar2Ptr_;
+
+        // Contribution to adjoint boundary conditions
+        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        autoPtr<boundaryVectorField> bdJdvPtr_;
+
+        //- Adjoint outlet pressure
+        autoPtr<boundaryScalarField> bdJdvnPtr_;
+
+        //- Adjoint outlet velocity
+        autoPtr<boundaryVectorField> bdJdvtPtr_;
+
+        //- Adjoint (intlet,wall) velocity
+        autoPtr<boundaryVectorField> bdJdpPtr_;
+
+        //- Adjoint outlet temperature
+        autoPtr<boundaryScalarField> bdJdTPtr_;
+
+        //- Adjoint outlet turbulence model var 1
+        autoPtr<boundaryScalarField> bdJdTMvar1Ptr_;
+
+        //- Adjoint outlet turbulence model var 2
+        autoPtr<boundaryScalarField> bdJdTMvar2Ptr_;
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        objectiveIncompressible(const objectiveIncompressible&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const objectiveIncompressible&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("incompressible");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            objectiveIncompressible,
+            dictionary,
+            (
+                const fvMesh& mesh,
+                const dictionary& dict,
+                const word& adjointSolverName,
+                const word& primalSolverName
+            ),
+            (mesh, dict, adjointSolverName, primalSolverName)
+        );
+
+
+    // Constructors
+
+        //- Construct from components
+        objectiveIncompressible
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            const word& adjointSolverName,
+            const word& primalSolverName
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<objectiveIncompressible> New
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            const word& adjointSolverName,
+            const word& primalSolverName
+        );
+
+
+    //- Destructor
+    virtual ~objectiveIncompressible() = default;
+
+
+    // Member Functions
+
+        //- Return the objective function value
+        virtual scalar J() = 0;
+
+        //- Contribution to field adjoint momentum eqs
+        const volVectorField& dJdv();
+
+        //- Contribution to field adjoint continuity eq
+        const volScalarField& dJdp();
+
+        //- Contribution to field adjoint energy eq
+        const volScalarField& dJdT();
+
+        //- Contribution to field adjoint turbulence model variable 1
+        const volScalarField& dJdTMvar1();
+
+        //- Contribution to field adjoint turbulence model variable 2
+        const volScalarField& dJdTMvar2();
+
+        //- Objective partial deriv wrt velocity for a specific patch
+        const fvPatchVectorField& boundarydJdv(const label);
+
+        //- Objective partial deriv wrt normal velocity for a specific patch
+        const fvPatchScalarField& boundarydJdvn(const label);
+
+        //- Objective partial deriv wrt tangent velocity for a specific patch
+        const fvPatchVectorField& boundarydJdvt(const label);
+
+        //- Objective partial deriv wrt pressure (times normal) for a specific
+        //- patch
+        const fvPatchVectorField& boundarydJdp(const label);
+
+        //- Objective partial deriv wrt temperature for a specific patch
+        const fvPatchScalarField& boundarydJdT(const label);
+
+        //- Objective partial deriv wrt turbulence model var 1 for a specific
+        //- patch
+        const fvPatchScalarField& boundarydJdTMvar1(const label);
+
+        //- Objective partial deriv wrt turbulence model var 2 for a specific
+        //- patch
+        const fvPatchScalarField& boundarydJdTMvar2(const label);
+
+        //- Objective partial deriv wrt velocity for all patches
+        const boundaryVectorField& boundarydJdv();
+
+        //- Objective partial deriv wrt normal velocity for all patches
+        const boundaryScalarField& boundarydJdvn();
+
+        //- Objective partial deriv wrt tangent velocity for all patches
+        const boundaryVectorField& boundarydJdvt();
+
+        //- Objective partial deriv wrt pressure (times normal) for all patches
+        const boundaryVectorField& boundarydJdp();
+
+        //- Objective partial deriv wrt temperature for all patches
+        const boundaryScalarField& boundarydJdT();
+
+        //- Objective partial deriv wrt turbulence model var 1 for all patches
+        const boundaryScalarField& boundarydJdTMvar1();
+
+        //- Objective partial deriv wrt turbulence model var 2 for all patches
+        const boundaryScalarField& boundarydJdTMvar2();
+
+        //- Update objective function derivatives
+        void update();
+
+        //- Update vol and boundary fields and derivatives
+        //  Do nothing in the base. The relevant ones should be overwritten
+        //  in the child objective functions
+        virtual void update_dJdv()
+        {}
+
+        virtual void update_dJdp()
+        {}
+
+        virtual void update_dJdT()
+        {}
+
+        virtual void update_dJdTMvar1()
+        {}
+
+        virtual void update_dJdTMvar2()
+        {}
+
+        virtual void update_dJdb()
+        {}
+
+        virtual void update_divDxDbMultiplier()
+        {}
+
+        virtual void update_gradDxDbMultiplier()
+        {}
+
+        virtual void update_boundarydJdv()
+        {}
+
+        virtual void update_boundarydJdvn()
+        {}
+
+        virtual void update_boundarydJdvt()
+        {}
+
+        virtual void update_boundarydJdp()
+        {}
+
+        virtual void update_boundarydJdT()
+        {}
+
+        virtual void update_boundarydJdTMvar1()
+        {}
+
+        virtual void update_boundarydJdTMvar2()
+        {}
+
+        virtual void update_boundarydJdb()
+        {}
+
+        virtual void update_dSdbMultiplier()
+        {}
+
+        virtual void update_dndbMultiplier()
+        {}
+
+        virtual void update_dxdbMultiplier()
+        {}
+
+        virtual void update_dxdbDirectMultiplier()
+        {}
+
+        //- Some objectives need to store some auxiliary values.
+        //- If averaging is enabled, update these mean values here.
+        //  By convention, the mean values (eg mean drag) refer to these flow
+        //  values computed using the mean fields, rather than averaging the
+        //  values themselves
+        virtual void update_meanValues()
+        {}
+
+        //- Write objective function history
+        virtual void write() const;
+
+        //- Inline functions for checking whether pointers are set or not
+        inline bool hasdJdv();
+        inline bool hasdJdp();
+        inline bool hasdJdT();
+        inline bool hasdJdTMVar1();
+        inline bool hasdJdTMVar2();
+        inline bool hasBoundarydJdv();
+        inline bool hasBoundarydJdvn();
+        inline bool hasBoundarydJdvt();
+        inline bool hasBoundarydJdp();
+        inline bool hasBoundarydJdT();
+        inline bool hasBoundarydJdTMVar1();
+        inline bool hasBoundarydJdTMVar2();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "objectiveIncompressibleI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressibleI.H b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressibleI.H
new file mode 100644
index 0000000000000000000000000000000000000000..075e17404e7e7ca56c1b19278fcdbe83f6fba995
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressibleI.H
@@ -0,0 +1,104 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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/>.
+
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+inline bool Foam::objectiveIncompressible::hasdJdv()
+{
+    return dJdvPtr_.valid();
+}
+
+
+inline bool Foam::objectiveIncompressible::hasdJdp()
+{
+    return dJdpPtr_.valid();
+}
+
+
+inline bool Foam::objectiveIncompressible::hasdJdT()
+{
+    return dJdTPtr_.valid();
+}
+
+
+inline bool Foam::objectiveIncompressible::hasdJdTMVar1()
+{
+    return dJdTMvar1Ptr_.valid();
+}
+
+
+inline bool Foam::objectiveIncompressible::hasdJdTMVar2()
+{
+    return dJdTMvar2Ptr_.valid();
+}
+
+
+inline bool Foam::objectiveIncompressible::hasBoundarydJdv()
+{
+    return bdJdvPtr_.valid();
+}
+
+
+inline bool Foam::objectiveIncompressible::hasBoundarydJdvn()
+{
+    return bdJdvnPtr_.valid();
+}
+
+
+inline bool Foam::objectiveIncompressible::hasBoundarydJdvt()
+{
+    return bdJdvtPtr_.valid();
+}
+
+
+inline bool Foam::objectiveIncompressible::hasBoundarydJdp()
+{
+    return bdJdpPtr_.valid();
+}
+
+
+inline bool Foam::objectiveIncompressible::hasBoundarydJdT()
+{
+    return bdJdTPtr_.valid();
+}
+
+
+inline bool Foam::objectiveIncompressible::hasBoundarydJdTMVar1()
+{
+    return bdJdTMvar1Ptr_.valid();
+}
+
+
+inline bool Foam::objectiveIncompressible::hasBoundarydJdTMVar2()
+{
+    return bdJdTMvar2Ptr_.valid();
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveMoment/objectiveMoment.C b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveMoment/objectiveMoment.C
new file mode 100644
index 0000000000000000000000000000000000000000..a66325de69467f629a6ba56ce53dfccf326fad4d
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveMoment/objectiveMoment.C
@@ -0,0 +1,313 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "objectiveMoment.H"
+#include "createZeroField.H"
+#include "wallFvPatch.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace objectives
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(objectiveMoment, 0);
+addToRunTimeSelectionTable
+(
+    objectiveIncompressible,
+    objectiveMoment,
+    dictionary
+);
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+objectiveMoment::objectiveMoment
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    const word& adjointSolverName,
+    const word& primalSolverName
+)
+:
+    objectiveIncompressible(mesh, dict, adjointSolverName, primalSolverName),
+    momentPatches_
+    (
+        mesh_.boundaryMesh().patchSet
+        (
+            wordReList(dict.get<wordRes>("patches"))
+        )
+    ),
+    momentDirection_(dict.get<vector>("direction")),
+    rotationCentre_(dict.get<vector>("rotationCenter")),
+    Aref_(dict.get<scalar>("Aref")),
+    lRef_(dict.get<scalar>("lRef")),
+    rhoInf_(dict.get<scalar>("rhoInf")),
+    UInf_(dict.get<scalar>("UInf")),
+    invDenom_(2./(rhoInf_*UInf_*UInf_*Aref_*lRef_)),
+    stressXPtr_
+    (
+        Foam::createZeroFieldPtr<vector>
+        (
+            mesh_, "stressX", dimLength/sqr(dimTime)
+        )
+    ),
+    stressYPtr_
+    (
+        Foam::createZeroFieldPtr<vector>
+        (
+            mesh_, "stressY", dimLength/sqr(dimTime)
+        )
+    ),
+    stressZPtr_
+    (
+        Foam::createZeroFieldPtr<vector>
+        (
+            mesh_, "stressZ", dimLength/sqr(dimTime)
+        )
+    ),
+    devReff_(vars_.turbulence()->devReff()())
+{
+    // Sanity check and print info
+    if (momentPatches_.empty())
+    {
+        FatalErrorInFunction
+            << "No valid patch name on which to minimize " << type() << endl
+            << exit(FatalError);
+    }
+    if (debug)
+    {
+        Info<< "Minimizing " << type() << " in patches:" << endl;
+        for (const label patchI : momentPatches_)
+        {
+            Info<< "\t " << mesh_.boundary()[patchI].name() << endl;
+        }
+    }
+
+    // Allocate boundary field pointers
+    bdJdpPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    bdSdbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    bdxdbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    bdxdbDirectMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+scalar objectiveMoment::J()
+{
+    vector pressureMoment(Zero);
+    vector viscousMoment(Zero);
+    vector cumulativeMoment(Zero);
+
+    // Update field here and use the same value for all functions
+    const volScalarField& p = vars_.pInst();
+    devReff_ = vars_.turbulence()->devReff()();
+
+    for (const label patchI : momentPatches_)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        const vectorField& Sf = patch.Sf();
+        vectorField dx(patch.Cf() - rotationCentre_);
+        pressureMoment += gSum
+        (
+            rhoInf_*(dx ^ Sf)*p.boundaryField()[patchI]
+        );
+
+        // Viscous term calculated using the full tensor derivative
+        viscousMoment += gSum
+        (
+            rhoInf_*(dx^(devReff_.boundaryField()[patchI] & Sf))
+        );
+    }
+
+    cumulativeMoment = pressureMoment + viscousMoment;
+
+    scalar moment = cumulativeMoment & momentDirection_;
+    scalar Cm = moment*invDenom_;
+    DebugInfo<<
+        "Moment|Coeff " << moment << "|" << Cm << endl;
+    J_ = Cm;
+    return Cm;
+}
+
+
+void objectiveMoment::update_meanValues()
+{
+    if (computeMeanFields_)
+    {
+        const volVectorField& U = vars_.U();
+        const autoPtr<incompressible::RASModelVariables>&
+           turbVars = vars_.RASModelVariables();
+        const singlePhaseTransportModel& lamTransp = vars_.laminarTransport();
+
+        devReff_ = turbVars->devReff(lamTransp, U)();
+    }
+}
+
+
+void objectiveMoment::update_boundarydJdp()
+{
+    for (const label patchI : momentPatches_)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        vectorField dx(patch.Cf() - rotationCentre_);
+        bdJdpPtr_()[patchI] = (momentDirection_ ^ dx)*invDenom_*rhoInf_;
+    }
+}
+
+
+void objectiveMoment::update_dSdbMultiplier()
+{
+    const volScalarField& p = vars_.p();
+
+    for (const label patchI : momentPatches_)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        const vectorField dx(patch.Cf() - rotationCentre_);
+        bdSdbMultPtr_()[patchI] =
+            (
+                (
+                    rhoInf_*
+                    (
+                        (momentDirection_^dx) &
+                        (
+                            devReff_.boundaryField()[patchI]
+                        )
+                    )
+                )
+              + rhoInf_ * (momentDirection_^dx) * p.boundaryField()[patchI]
+            )
+           *invDenom_;
+    }
+}
+
+
+void objectiveMoment::update_dxdbMultiplier()
+{
+    const volScalarField& p = vars_.p();
+    const volVectorField& U = vars_.U();
+
+    const autoPtr<incompressible::RASModelVariables>&
+       turbVars = vars_.RASModelVariables();
+    const singlePhaseTransportModel& lamTransp = vars_.laminarTransport();
+    volScalarField nuEff(lamTransp.nu() + turbVars->nutRef());
+    volTensorField gradU(fvc::grad(U));
+
+    // Explicitly correct the boundary gradient to get rid of the
+    // tangential component
+    forAll(mesh_.boundary(), patchI)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        if (isA<wallFvPatch>(patch))
+        {
+            tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
+            const vectorField& nf = tnf();
+            gradU.boundaryFieldRef()[patchI] =
+                nf * U.boundaryField()[patchI].snGrad();
+        }
+    }
+
+    volTensorField stress(nuEff*(gradU + T(gradU)));
+
+    stressXPtr_().replace(0, stress.component(0));
+    stressXPtr_().replace(1, stress.component(1));
+    stressXPtr_().replace(2, stress.component(2));
+
+    stressYPtr_().replace(0, stress.component(3));
+    stressYPtr_().replace(1, stress.component(4));
+    stressYPtr_().replace(2, stress.component(5));
+
+    stressZPtr_().replace(0, stress.component(6));
+    stressZPtr_().replace(1, stress.component(7));
+    stressZPtr_().replace(2, stress.component(8));
+
+    volTensorField gradStressX(fvc::grad(stressXPtr_()));
+    volTensorField gradStressY(fvc::grad(stressYPtr_()));
+    volTensorField gradStressZ(fvc::grad(stressZPtr_()));
+
+    volVectorField gradp(fvc::grad(p));
+
+    for (const label patchI : momentPatches_)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        tmp<vectorField> tnf = patch.nf();
+        const vectorField& nf = tnf();
+        vectorField dx(patch.Cf() - rotationCentre_);
+        vectorField aux(momentDirection_^dx);
+        bdxdbMultPtr_()[patchI] =
+        (
+            (
+                (
+                   -(aux.component(0) * gradStressX.boundaryField()[patchI])
+                   -(aux.component(1) * gradStressY.boundaryField()[patchI])
+                   -(aux.component(2) * gradStressZ.boundaryField()[patchI])
+                ) & nf
+            )
+            + (momentDirection_ & (dx^nf))*gradp.boundaryField()[patchI]
+        )
+        *invDenom_*rhoInf_;
+    }
+}
+
+
+void objectiveMoment::update_dxdbDirectMultiplier()
+{
+    const volScalarField& p = vars_.p();
+
+    for (const label patchI : momentPatches_)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        tmp<vectorField> tnf = patch.nf();
+        const vectorField& nf = tnf();
+        const vectorField dx(patch.Cf() - rotationCentre_);
+        const vectorField force
+        (
+            rhoInf_
+           *(
+                ((p.boundaryField()[patchI]*nf)
+              + (devReff_.boundaryField()[patchI] & nf))
+            )
+        );
+        bdxdbDirectMultPtr_()[patchI] =
+            (force^momentDirection_)*invDenom_*rhoInf_;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace objectives
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveMoment/objectiveMoment.H b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveMoment/objectiveMoment.H
new file mode 100644
index 0000000000000000000000000000000000000000..053569199e429b95e5a71d88120fbab16966d319
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveMoment/objectiveMoment.H
@@ -0,0 +1,132 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::objectives::objectiveMoment
+
+Description
+
+SourceFiles
+    objectiveMoment.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef objectiveMoment_H
+#define objectiveMoment_H
+
+#include "objectiveIncompressible.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace objectives
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class objectiveMoment Declaration
+\*---------------------------------------------------------------------------*/
+
+class objectiveMoment
+:
+    public objectiveIncompressible
+{
+    // Private data
+
+        labelHashSet momentPatches_;
+        vector momentDirection_;
+        vector rotationCentre_;
+        scalar Aref_;
+        scalar lRef_;
+        scalar rhoInf_;
+        scalar UInf_;
+        scalar invDenom_;
+
+        autoPtr<volVectorField> stressXPtr_;
+        autoPtr<volVectorField> stressYPtr_;
+        autoPtr<volVectorField> stressZPtr_;
+
+        // Store this in order to computed only once per objective call
+        volSymmTensorField devReff_;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("moment");
+
+
+    // Constructors
+
+        //- from components
+        objectiveMoment
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            const word& adjointSolverName,
+            const word& primalSolverName
+        );
+
+
+    //- Destructor
+    virtual ~objectiveMoment() = default;
+
+
+    // Member Functions
+
+        //- Return the objective function value
+        scalar J();
+
+        //- Update mean drag and lift values
+        void update_meanValues();
+
+        //- Update values to be added to the adjoint wall velocity
+        void update_boundarydJdp();
+
+        //- Update delta(n dS)/delta b multiplier
+        void update_dSdbMultiplier();
+
+        //- Update delta(x)/delta b multiplier
+        void update_dxdbMultiplier();
+
+        //- Update delta(x)/delta b multiplier coming directly from the
+        //- objective
+        void update_dxdbDirectMultiplier();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace objectiveMoment
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePtLosses/objectivePtLosses.C b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePtLosses/objectivePtLosses.C
new file mode 100644
index 0000000000000000000000000000000000000000..7527ce629cd3857fb56f6cc16b73a44955e44542
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePtLosses/objectivePtLosses.C
@@ -0,0 +1,279 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "objectivePtLosses.H"
+#include "createZeroField.H"
+#include "coupledFvPatch.H"
+#include "IOmanip.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace objectives
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(objectivePtLosses, 1);
+addToRunTimeSelectionTable
+(
+    objectiveIncompressible,
+    objectivePtLosses,
+    dictionary
+);
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+objectivePtLosses::objectivePtLosses
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    const word& adjointSolverName,
+    const word& primalSolverName
+)
+:
+    objectiveIncompressible(mesh, dict, adjointSolverName, primalSolverName),
+    patches_(0),
+    patchPt_(0)
+{
+    // Find inlet/outlet patches
+    initialize();
+
+    // Allocate boundary field pointers
+    bdJdpPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    bdJdvPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    bdJdvnPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
+    bdJdvtPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void objectivePtLosses::initialize()
+{
+    // If patches are prescribed, use them
+    if (dict().found("patches"))
+    {
+        labelHashSet patches
+        (
+            mesh_.boundaryMesh().patchSet
+            (
+                wordReList(dict().get<wordRes>("patches"))
+            )
+        );
+        patches_ = patches.toc();
+    }
+    // Otherwise, pick them up based on the mass flow.
+    // Note: a non-zero U initialisation should be used in order to pick up the
+    // outlet patches correctly
+    else
+    {
+        WarningInFunction
+            << "No patches provided to PtLosses. Chossing them according to "
+            << "the patch mass flows"
+            << endl;
+        DynamicList<label> objectiveReportPatches(mesh_.boundary().size());
+        const surfaceScalarField& phi = vars_.phiInst();
+        forAll(mesh_.boundary(), patchI)
+        {
+           const fvsPatchScalarField& phiPatch = phi.boundaryField()[patchI];
+           if (!isA<coupledFvPatch>(mesh_.boundary()[patchI]))
+           {
+                const scalar mass = gSum(phiPatch);
+                if (mag(mass) > SMALL)
+                {
+                    objectiveReportPatches.append(patchI);
+                }
+            }
+        }
+        patches_.transfer(objectiveReportPatches);
+    }
+    patchPt_.setSize(patches_.size());
+
+    if (patches_.empty())
+    {
+        FatalErrorInFunction
+            << "No valid patch name on which to minimize " << type() << endl
+            << exit(FatalError);
+    }
+    if (debug)
+    {
+        Info<< "Minimizing " << type() << " in patches:" << endl;
+        forAll(patches_, pI)
+        {
+            Info<< "\t " << mesh_.boundary()[patches_[pI]].name() << endl;
+        }
+    }
+}
+
+
+scalar objectivePtLosses::J()
+{
+    J_ = Zero;
+
+    // References
+    const volScalarField& p = vars_.pInst();
+    const volVectorField& U = vars_.UInst();
+
+    // Inlet/outlet patches
+    forAll(patches_, oI)
+    {
+        const label patchI = patches_[oI];
+        const vectorField& Sf = mesh_.boundary()[patchI].Sf();
+        scalar pt = -gSum
+        (
+            (U.boundaryField()[patchI] & Sf)
+           *(
+                p.boundaryField()[patchI]
+              + 0.5*magSqr(U.boundaryField()[patchI])
+            )
+        );
+        patchPt_[oI] = mag(pt);
+        J_ += pt;
+    }
+
+    return J_;
+}
+
+
+void objectivePtLosses::update_boundarydJdp()
+{
+    const volVectorField& U = vars_.U();
+
+    forAll(patches_, oI)
+    {
+        const label patchI = patches_[oI];
+
+        tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
+        const vectorField& nf = tnf();
+
+        bdJdpPtr_()[patchI] = -(U.boundaryField()[patchI] & nf)*nf;
+    }
+}
+
+
+void objectivePtLosses::update_boundarydJdv()
+{
+    const volScalarField& p = vars_.p();
+    const volVectorField& U = vars_.U();
+
+    forAll(patches_, oI)
+    {
+        const label patchI = patches_[oI];
+
+        tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
+        const vectorField& nf = tnf();
+        const fvPatchVectorField& Ub = U.boundaryField()[patchI];
+
+        bdJdvPtr_()[patchI] =
+          - (p.boundaryField()[patchI] + 0.5*magSqr(Ub))*nf
+          - (Ub & nf)*Ub;
+    }
+}
+
+
+void objectivePtLosses::update_boundarydJdvn()
+{
+    const volScalarField& p = vars_.p();
+    const volVectorField& U = vars_.U();
+
+    forAll(patches_, oI)
+    {
+        const label patchI = patches_[oI];
+
+        tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
+        const vectorField& nf = tnf();
+
+        bdJdvnPtr_()[patchI] =
+          - p.boundaryField()[patchI]
+          - 0.5*magSqr(U.boundaryField()[patchI])
+          - sqr(U.boundaryField()[patchI] & nf);
+    }
+}
+
+
+void objectivePtLosses::update_boundarydJdvt()
+{
+    const volVectorField& U = vars_.U();
+
+    forAll(patches_, oI)
+    {
+        const label patchI = patches_[oI];
+
+        tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
+        const vectorField& nf = tnf();
+        scalarField Un(U.boundaryField()[patchI] & nf);
+
+        bdJdvtPtr_()[patchI] = -Un*(U.boundaryField()[patchI] - Un*nf);
+    }
+}
+
+
+void objectivePtLosses::write() const
+{
+    if (Pstream::master())
+    {
+        // file is opened only upon invocation of the write function
+        // in order to avoid various instantiations of the same objective
+        // opening the same file
+        unsigned int width = IOstream::defaultPrecision() + 5;
+        if (objFunctionFilePtr_.empty())
+        {
+            setObjectiveFilePtr();
+            objFunctionFilePtr_() << setw(4)     << "#"        << " ";
+            objFunctionFilePtr_() << setw(width) << "ptLosses" << " ";
+            forAll(patches_, oI)
+            {
+                label patchI = patches_[oI];
+                objFunctionFilePtr_()
+                    << setw(width) << mesh_.boundary()[patchI].name() <<  " ";
+            }
+            objFunctionFilePtr_() << endl;
+        }
+
+        objFunctionFilePtr_() << setw(4)     << mesh_.time().value() << " ";
+        objFunctionFilePtr_() << setw(width) << J_ << " ";
+        forAll(patchPt_, pI)
+        {
+            objFunctionFilePtr_() << setw(width) << patchPt_[pI] << " ";
+        }
+        objFunctionFilePtr_() << endl;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace objectives
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePtLosses/objectivePtLosses.H b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePtLosses/objectivePtLosses.H
new file mode 100644
index 0000000000000000000000000000000000000000..5e7434ff190611f255bd6ca0df83554e570b1eee
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePtLosses/objectivePtLosses.H
@@ -0,0 +1,122 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::objectives::objectivePtLosses
+
+Description
+
+SourceFiles
+    objectivePtLosses.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef objectivePtLosses_H
+#define objectivePtLosses_H
+
+#include "objectiveIncompressible.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace objectives
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class objectivePtLosses Declaration
+\*---------------------------------------------------------------------------*/
+
+class objectivePtLosses
+:
+    public objectiveIncompressible
+{
+    // Private data
+
+        labelList patches_;
+
+        scalarField patchPt_;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("PtLosses");
+
+
+    // Constructors
+
+        //- from components
+        objectivePtLosses
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            const word& adjointSolverName,
+            const word& primalSolverName
+        );
+
+
+    //- Destructor
+    virtual ~objectivePtLosses() = default;
+
+
+    // Member Functions
+
+        //- Return the objectiveReportPatches
+        void initialize();
+
+        //- Return the objective function value
+        scalar J();
+
+        //- Update values to be added to the adjoint inlet velocity
+        void update_boundarydJdp();
+
+        //- Update values to be added to the adjoint outlet velocity
+        void update_boundarydJdv();
+
+        //- Update values to be added to the adjoint outlet pressure
+        void update_boundarydJdvn();
+
+        //- Update values to be added to the adjoint outlet tangential velocity
+        void update_boundarydJdvt();
+
+        //- Write objective function values and its contrituents
+        void write() const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace objectivePtLosses
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.C b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.C
new file mode 100644
index 0000000000000000000000000000000000000000..c8f79a682d8bd9c4ae3e755af023355512db33a9
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.C
@@ -0,0 +1,486 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "objective.H"
+#include "createZeroField.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(objective, 0);
+defineRunTimeSelectionTable(objective, objective);
+
+// * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
+
+void objective::makeFolder()
+{
+    if (Pstream::master())
+    {
+        const Time& time = mesh_.time();
+        objFunctionFolder_ =
+            time.globalPath()/"optimisation"/type()/time.timeName();
+
+        mkDir(objFunctionFolder_);
+    }
+}
+
+
+void objective::setObjectiveFilePtr() const
+{
+    objFunctionFilePtr_.reset
+    (
+        new OFstream(objFunctionFolder_/objectiveName_ + adjointSolverName_)
+    );
+}
+
+
+void objective::setInstantValueFilePtr() const
+{
+    instantValueFilePtr_.reset
+    (
+        new OFstream
+        (
+            objFunctionFolder_/objectiveName_ + "Instant" + adjointSolverName_
+        )
+    );
+}
+
+
+void objective::setMeanValueFilePtr() const
+{
+    meanValueFilePtr_.reset
+    (
+        new OFstream
+        (
+            objFunctionFolder_/objectiveName_ + "Mean" + adjointSolverName_
+        )
+    );
+}
+
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+const dictionary& objective::dict() const
+{
+    return dict_;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+objective::objective
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    const word& adjointSolverName,
+    const word& primalSolverName
+)
+:
+    mesh_(mesh),
+    dict_(dict),
+    adjointSolverName_(adjointSolverName),
+    primalSolverName_(primalSolverName),
+    objectiveName_(dict.dictName()),
+    computeMeanFields_(false), // is reset in derived classes
+
+    J_(Zero),
+    JMean_(Zero),
+    weight_(Zero),
+
+    // Initialize pointers to nullptr.
+    // Not all of them are required for each objective function.
+    // Each child should allocate whatever is needed.
+
+    dJdbPtr_(nullptr),
+    bdJdbPtr_(nullptr),
+    bdSdbMultPtr_(nullptr),
+    bdndbMultPtr_(nullptr),
+    bdxdbMultPtr_(nullptr),
+    bdxdbDirectMultPtr_(nullptr),
+    bEdgeContribution_(nullptr),
+    bdJdStressPtr_(nullptr),
+    divDxDbMultPtr_(nullptr),
+    gradDxDbMultPtr_(nullptr),
+
+    objFunctionFolder_("word"),
+    objFunctionFilePtr_(nullptr),
+    instantValueFilePtr_(nullptr),
+    meanValueFilePtr_(nullptr)
+{
+    makeFolder();
+}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+autoPtr<objective> objective::New
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    const word& objectiveType,
+    const word& adjointSolverName,
+    const word& primalSolverName
+)
+{
+    auto cstrIter = objectiveConstructorTablePtr_->cfind(objectiveType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown objective type " << objectiveType << nl << nl
+            << "Valid types are :" << nl
+            << objectiveConstructorTablePtr_->toc()
+            << exit(FatalError);
+    }
+
+    return autoPtr<objective>
+    (
+        cstrIter()
+        (
+            mesh,
+            dict,
+            adjointSolverName,
+            primalSolverName
+        )
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool objective::readDict(const dictionary& dict)
+{
+    dict_ = dict;
+    return true;
+}
+
+
+void objective::updateNormalizationFactor()
+{
+    // Does nothing in base
+}
+
+
+void objective::accumulateJMean(solverControl& solverControl)
+{
+    if (solverControl.doAverageIter())
+    {
+        const label iAverageIter = solverControl.averageIter();
+        if (iAverageIter == 0)
+        {
+            JMean_ = Zero;
+        }
+        scalar avIter(iAverageIter);
+        scalar oneOverItP1 = 1./(avIter + 1);
+        scalar mult = avIter*oneOverItP1;
+        JMean_ = JMean_*mult + J_*oneOverItP1;
+    }
+}
+
+
+scalar objective::weight() const
+{
+    return weight_;
+}
+
+
+const volScalarField& objective::dJdb()
+{
+    if (dJdbPtr_.empty())
+    {
+        // If pointer is not set, set it to a zero field
+        dJdbPtr_.reset
+        (
+            createZeroFieldPtr<scalar>
+            (
+                mesh_,
+                ("dJdb_" + objectiveName_),
+                dimensionSet(0, 5, -2, 0, 0, 0, 0)
+            )
+        );
+    }
+
+    return dJdbPtr_();
+}
+
+
+const fvPatchVectorField& objective::boundarydJdb(const label patchI)
+{
+    if (bdJdbPtr_.empty())
+    {
+        bdJdbPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdJdbPtr_()[patchI];
+}
+
+
+const fvPatchVectorField& objective::dSdbMultiplier(const label patchI)
+{
+    if (bdSdbMultPtr_.empty())
+    {
+        bdSdbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdSdbMultPtr_()[patchI];
+}
+
+
+const fvPatchVectorField& objective::dndbMultiplier(const label patchI)
+{
+    if (bdndbMultPtr_.empty())
+    {
+        bdndbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdndbMultPtr_()[patchI];
+}
+
+
+const fvPatchVectorField& objective::dxdbMultiplier(const label patchI)
+{
+    if (bdxdbMultPtr_.empty())
+    {
+        bdxdbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdxdbMultPtr_()[patchI];
+}
+
+
+const fvPatchVectorField& objective::dxdbDirectMultiplier(const label patchI)
+{
+    if (bdxdbDirectMultPtr_.empty())
+    {
+        bdxdbDirectMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdxdbDirectMultPtr_()[patchI];
+}
+
+
+const vectorField& objective::boundaryEdgeMultiplier
+(
+    const label patchI,
+    const label edgeI
+)
+{
+    if (bdxdbDirectMultPtr_.empty())
+    {
+        FatalErrorInFunction
+            << "Unallocated boundaryEdgeMultiplier field"
+            << exit(FatalError);
+    }
+    return bEdgeContribution_()[patchI][edgeI];
+}
+
+
+const fvPatchTensorField& objective::boundarydJdStress(const label patchI)
+{
+    if (bdJdStressPtr_.empty())
+    {
+        bdJdStressPtr_.reset(createZeroBoundaryPtr<tensor>(mesh_));
+    }
+    return bdJdStressPtr_()[patchI];
+}
+
+
+const boundaryVectorField& objective::boundarydJdb()
+{
+    if (bdJdbPtr_.empty())
+    {
+        bdJdbPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdJdbPtr_();
+}
+
+
+const boundaryVectorField& objective::dSdbMultiplier()
+{
+    if (bdSdbMultPtr_.empty())
+    {
+        bdSdbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdSdbMultPtr_();
+}
+
+
+const boundaryVectorField& objective::dndbMultiplier()
+{
+    if (bdndbMultPtr_.empty())
+    {
+        bdndbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdndbMultPtr_();
+}
+
+
+const boundaryVectorField& objective::dxdbMultiplier()
+{
+    if (bdxdbMultPtr_.empty())
+    {
+        bdxdbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdxdbMultPtr_();
+}
+
+
+const boundaryVectorField& objective::dxdbDirectMultiplier()
+{
+    if (bdxdbDirectMultPtr_.empty())
+    {
+        bdxdbDirectMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    }
+    return bdxdbDirectMultPtr_();
+}
+
+
+const vectorField3& objective::boundaryEdgeMultiplier()
+{
+    if (bdxdbDirectMultPtr_.empty())
+    {
+        FatalErrorInFunction
+            << "Unallocated boundaryEdgeMultiplier field"
+            << endl << endl
+            << exit(FatalError);
+    }
+    return bEdgeContribution_();
+}
+
+
+const boundaryTensorField& objective::boundarydJdStress()
+{
+    if (bdJdStressPtr_.empty())
+    {
+        bdJdStressPtr_.reset(createZeroBoundaryPtr<tensor>(mesh_));
+    }
+    return bdJdStressPtr_();
+}
+
+
+const volScalarField& objective::divDxDbMultiplier()
+{
+    if (divDxDbMultPtr_.empty())
+    {
+        // If pointer is not set, set it to a zero field
+        divDxDbMultPtr_.reset
+        (
+            createZeroFieldPtr<scalar>
+            (
+                mesh_,
+                ("divDxDbMult"+objectiveName_),
+                // Variable dimensions!!
+                // Dummy dimensionless. Only the internalField will be used
+                dimless
+            )
+        );
+    }
+    return divDxDbMultPtr_();
+}
+
+
+const volTensorField& objective::gradDxDbMultiplier()
+{
+    if (gradDxDbMultPtr_.empty())
+    {
+        // If pointer is not set, set it to a zero field
+        gradDxDbMultPtr_.reset
+        (
+            createZeroFieldPtr<tensor>
+            (
+                mesh_,
+                ("gradDxDbMult"+objectiveName_),
+                // Variable dimensions!!
+                dimensionSet(pow2(dimLength)/pow3(dimTime))
+            )
+        );
+    }
+    return gradDxDbMultPtr_();
+}
+
+
+void objective::write() const
+{
+    if (Pstream::master())
+    {
+        // File is opened only upon invocation of the write function
+        // in order to avoid various instantiations of the same objective
+        // opening the same file
+        if (objFunctionFilePtr_.empty())
+        {
+            setObjectiveFilePtr();
+        }
+
+        objFunctionFilePtr_() << mesh_.time().value() << tab << J_ << endl;
+    }
+}
+
+
+void objective::writeInstantaneousValue() const
+{
+    if (Pstream::master())
+    {
+        // File is opened only upon invocation of the write function
+        // in order to avoid various instantiations of the same objective
+        // opening the same file
+        if (instantValueFilePtr_.empty())
+        {
+            setInstantValueFilePtr();
+        }
+
+        instantValueFilePtr_() << mesh_.time().value() << tab << J_ << endl;
+    }
+}
+
+
+void objective::writeMeanValue() const
+{
+    if (Pstream::master())
+    {
+        // Write mean value if necessary
+        if (computeMeanFields_)
+        {
+            // File is opened only upon invocation of the write function
+            // in order to avoid various instantiations of the same objective
+            // opening the same file
+            if (meanValueFilePtr_.empty())
+            {
+                setMeanValueFilePtr();
+            }
+
+            meanValueFilePtr_()
+                << mesh_.time().value() << tab << JMean_ << endl;
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.H b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.H
new file mode 100644
index 0000000000000000000000000000000000000000..80d19b34c0968609bdf698cf5d8809fcddbff3d8
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.H
@@ -0,0 +1,365 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::objective
+
+Description
+    Abstract base class for objective functions. No point in making this
+    runTime selectable since its children will have different constructors.
+
+SourceFiles
+    objective.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef objective_H
+#define objective_H
+
+#include "autoPtr.H"
+#include "runTimeSelectionTables.H"
+#include "OFstream.H"
+#include "boundaryFieldsFwd.H"
+#include "solverControl.H"
+#include "objectiveFwd.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                          Class objective Declaration
+\*---------------------------------------------------------------------------*/
+
+class objective
+{
+protected:
+
+    // Protected data
+
+        const fvMesh& mesh_;
+        dictionary dict_;
+        const word adjointSolverName_;
+        const word primalSolverName_;
+        const word objectiveName_;
+        bool computeMeanFields_;
+
+        // Objective function value and weight
+        scalar J_;
+        scalar JMean_;  //average value
+        scalar weight_;
+
+        // Contribution to field sensitivity derivatives
+        // Topology optimisation
+        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+        autoPtr<volScalarField> dJdbPtr_;
+
+        // Contribution to surface sensitivity derivatives
+        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+        //- Term from material derivative
+        autoPtr<boundaryVectorField> bdJdbPtr_;
+
+        //- Term multiplying delta(n dS)/delta b
+        autoPtr<boundaryVectorField> bdSdbMultPtr_;
+
+        //- Term multiplying delta(n)/delta b
+        autoPtr<boundaryVectorField> bdndbMultPtr_;
+
+        //- Term multiplying delta(x)/delta b at the boundary
+        autoPtr<boundaryVectorField> bdxdbMultPtr_;
+
+        //- Term multiplying delta(x)/delta b at the boundary
+        //- for objectives that directly depend on x, e.g. moment
+        //- Needed in both FI and SI computations
+        autoPtr<boundaryVectorField> bdxdbDirectMultPtr_;
+
+        //- Contribution located in specific parts of a patch.
+        //- Mainly intended for patch boundary edges contributions, e.g.
+        //- NURBS surfaces G1 continuity
+        autoPtr<vectorField3> bEdgeContribution_;
+
+        //- For use with discrete-like sensitivities
+        autoPtr<boundaryTensorField> bdJdStressPtr_;
+
+        // Contribution to volume-based sensitivities from volume-based
+        // objective functions
+        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+        //- Multiplier of d(Volume)/db
+        autoPtr<volScalarField> divDxDbMultPtr_;
+
+        //- Emerging from volume objectives that include spatial derivatives
+        autoPtr<volTensorField> gradDxDbMultPtr_;
+
+        //- Output file variables
+        fileName objFunctionFolder_;
+
+        //- File to keep the objective values after the end of the primal solver
+        mutable autoPtr<OFstream> objFunctionFilePtr_;
+
+        //- File to keep the objective values at each iteration of the primal
+        //- solver
+        mutable autoPtr<OFstream> instantValueFilePtr_;
+
+        //- File to keep the average objective values after the end of the
+        //- primal solver
+        mutable autoPtr<OFstream> meanValueFilePtr_;
+
+
+    // Protected Member Functions
+
+        //- Return objective dictionary
+        const dictionary& dict() const;
+
+        //- Set the output file ptr
+        void setObjectiveFilePtr() const;
+
+        //- Set the output file ptr for the instantaneous value
+        void setInstantValueFilePtr() const;
+
+        //- Set the output file ptr for the mean value
+        void setMeanValueFilePtr() const;
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        objective(const objective&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const objective&) = delete;
+
+        //- Make objective Function Folder
+        void makeFolder();
+
+
+public:
+
+    //- Runtime type information
+    TypeName("objective");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeNewSelectionTable
+        (
+            autoPtr,
+            objective,
+            objective,
+            (
+                const fvMesh& mesh,
+                const dictionary& dict,
+                const word& adjointSolverName,
+                const word& primalSolverName
+            ),
+            (mesh, dict, adjointSolverName, primalSolverName)
+        );
+
+
+    // Constructors
+
+        //- Construct from components
+        objective
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            const word& adjointSolverName,
+            const word& primalSolverName
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<objective> New
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            const word& objectiveType,
+            const word& adjointSolverName,
+            const word& primalSolverName
+        );
+
+
+    //- Destructor
+    virtual ~objective() = default;
+
+
+    // Member Functions
+
+        virtual bool readDict(const dictionary& dict);
+
+        //- Return the objective function value
+        virtual scalar J() = 0;
+
+        //- Accumulate contribution for the mean objective value
+        void accumulateJMean(solverControl& solverControl);
+
+        //- Return the objective function weight
+        scalar weight() const;
+
+        //- Contribution to field sensitivities
+        const volScalarField& dJdb();
+
+        //- Contribution to surface sensitivities for a specific patch
+        const fvPatchVectorField& boundarydJdb(const label);
+
+        //- Multiplier of delta(n dS)/delta b
+        const fvPatchVectorField& dSdbMultiplier(const label);
+
+        //- Multiplier of delta(n dS)/delta b
+        const fvPatchVectorField& dndbMultiplier(const label);
+
+        //- Multiplier of delta(x)/delta b
+        const fvPatchVectorField& dxdbMultiplier(const label);
+
+        //- Multiplier of delta(x)/delta b
+        const fvPatchVectorField& dxdbDirectMultiplier(const label);
+
+        //- Multiplier located at patch boundary edges
+        const vectorField& boundaryEdgeMultiplier
+        (
+            const label patchI,
+            const label edgeI
+        );
+
+        //- Objective partial deriv wrt stress tensor
+        const fvPatchTensorField& boundarydJdStress(const label);
+
+        //- Contribution to surface sensitivities for all patches
+        const boundaryVectorField& boundarydJdb();
+
+        //- Multiplier of delta(n dS)/delta b for all patches
+        const boundaryVectorField& dSdbMultiplier();
+
+        //- Multiplier of delta(n dS)/delta b for all patches
+        const boundaryVectorField& dndbMultiplier();
+
+        //- Multiplier of delta(x)/delta b for all patches
+        const boundaryVectorField& dxdbMultiplier();
+
+        //- Multiplier of delta(x)/delta b for all patches
+        const boundaryVectorField& dxdbDirectMultiplier();
+
+        //- Multiplier located at patch boundary edges
+        const vectorField3& boundaryEdgeMultiplier();
+
+        //- Objective partial deriv wrt stress tensor
+        const boundaryTensorField& boundarydJdStress();
+
+        //- Multiplier of grad( delta(x)/delta b) for volume-based sensitivities
+        const volScalarField& divDxDbMultiplier();
+
+        //- Multiplier of grad( delta(x)/delta b) for volume-based sensitivities
+        const volTensorField& gradDxDbMultiplier();
+
+        //- Update objective function derivatives
+        virtual void update() = 0;
+
+        //- Update normalization factors, for objectives in
+        //- which the factor is not known a priori
+        virtual void updateNormalizationFactor();
+
+        //- Update objective function derivative term
+        virtual void update_boundarydJdb()
+        {}
+
+        //- Update d (normal dS) / db multiplier. Surface-based sensitivity term
+        virtual void update_dSdbMultiplier()
+        {}
+
+        //- Update d (normal) / db multiplier. Surface-based sensitivity term
+        virtual void update_dndbMultiplier()
+        {}
+
+        //- Update d (x) / db multiplier. Surface-based sensitivity term
+        virtual void update_dxdbMultiplier()
+        {}
+
+        //- Update d (x) / db multiplier. Surface and volume-based sensitivity
+        //- term
+        virtual void update_dxdbDirectMultiplier()
+        {}
+
+        //- Update boundary edge contributions
+        virtual void update_boundaryEdgeContribution()
+        {}
+
+        //- Update dJ/dStress field
+        virtual void update_dJdStressMultiplier()
+        {}
+
+        //- Update div( dx/db multiplier). Volume-based sensitivity term
+        virtual void update_divDxDbMultiplier()
+        {}
+
+        //- Update grad( dx/db multiplier). Volume-based sensitivity term
+        virtual void update_gradDxDbMultiplier()
+        {}
+
+        //- Write objective function history
+        virtual void write() const;
+
+        //- Write objective function history at each primal solver iteration
+        virtual void writeInstantaneousValue() const;
+
+        //- Write mean objective function history
+        virtual void writeMeanValue() const;
+
+        // Inline functions for checking whether pointers are set or not
+        inline const word& objectiveName() const;
+        inline bool hasdJdb();
+        inline bool hasBoundarydJdb();
+        inline bool hasdSdbMult();
+        inline bool hasdndbMult();
+        inline bool hasdxdbMult();
+        inline bool hasdxdbDirectMult();
+        inline bool hasBoundaryEdgeContribution();
+        inline bool hasBoundarydJdStress();
+        inline bool hasDivDxDbMult();
+        inline bool hasGradDxDbMult();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "objectiveI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objectiveFwd.H b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objectiveFwd.H
new file mode 100644
index 0000000000000000000000000000000000000000..92c396c05fb41c06102ac5871300748075764528
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objectiveFwd.H
@@ -0,0 +1,45 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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/>.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef objectiveFwd_H
+#define objectiveFwd_H
+
+#include "fieldTypes.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    typedef Field<Field<vectorField>> vectorField3;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objectiveI.H b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objectiveI.H
new file mode 100644
index 0000000000000000000000000000000000000000..7fbfb789eaededfb24001e8cfc346dc490f20ebf
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objectiveI.H
@@ -0,0 +1,98 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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/>.
+
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+inline const Foam::word& Foam::objective::objectiveName() const
+{
+    return objectiveName_;
+}
+
+
+inline bool Foam::objective::hasdJdb()
+{
+    return dJdbPtr_.valid();
+}
+
+
+inline bool Foam::objective::hasBoundarydJdb()
+{
+    return bdJdbPtr_.valid();
+}
+
+
+inline bool Foam::objective::hasdSdbMult()
+{
+    return bdSdbMultPtr_.valid();
+}
+
+
+inline bool Foam::objective::hasdndbMult()
+{
+    return bdndbMultPtr_.valid();
+}
+
+
+inline bool Foam::objective::hasdxdbMult()
+{
+    return bdxdbMultPtr_.valid();
+}
+
+
+inline bool Foam::objective::hasdxdbDirectMult()
+{
+    return bdxdbDirectMultPtr_.valid();
+}
+
+
+inline bool Foam::objective::hasBoundaryEdgeContribution()
+{
+    return bEdgeContribution_.valid();
+}
+
+
+inline bool Foam::objective::hasDivDxDbMult()
+{
+    return divDxDbMultPtr_.valid();
+}
+
+
+inline bool Foam::objective::hasGradDxDbMult()
+{
+    return gradDxDbMultPtr_.valid();
+}
+
+
+inline bool Foam::objective::hasBoundarydJdStress()
+{
+    return bdJdStressPtr_.valid();
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointEikonalSolver/adjointEikonalSolverIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointEikonalSolver/adjointEikonalSolverIncompressible.C
new file mode 100644
index 0000000000000000000000000000000000000000..f70e0f4d6d6503e848bed1a0d1fb9ed7e8479fb0
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointEikonalSolver/adjointEikonalSolverIncompressible.C
@@ -0,0 +1,300 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointEikonalSolverIncompressible.H"
+#include "wallFvPatch.H"
+#include "patchDistMethod.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(adjointEikonalSolver, 0);
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+wordList adjointEikonalSolver::patchTypes() const
+{
+    wordList daTypes
+    (
+        mesh_.boundary().size(),
+        fixedValueFvPatchScalarField::typeName
+    );
+
+    for (const label patchi : wallPatchIDs_)
+    {
+        daTypes[patchi] = zeroGradientFvPatchScalarField::typeName;
+    }
+
+    return daTypes;
+}
+
+
+void adjointEikonalSolver::read()
+{
+    nEikonalIters_ = dict_.lookupOrDefault<label>("iters", 1000);
+    tolerance_ = dict_.lookupOrDefault<scalar>("tolerance", 1e-6);
+    epsilon_ = dict_.lookupOrDefault<scalar>("epsilon", 0.1);
+}
+
+
+tmp<surfaceScalarField> adjointEikonalSolver::computeYPhi()
+{
+    // Primal distance field
+    const volScalarField& d = RASModelVars_().d();
+
+    volVectorField ny
+    (
+        IOobject
+        (
+            "ny",
+            mesh_.time().timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE,
+            false
+        ),
+        mesh_,
+        dimensionedVector(dimless, Zero),
+        patchDistMethod::patchTypes<vector>(mesh_, wallPatchIDs_)
+    );
+
+    const fvPatchList& patches = mesh_.boundary();
+    volVectorField::Boundary& nybf = ny.boundaryFieldRef();
+
+    for (const label patchi : wallPatchIDs_)
+    {
+        nybf[patchi] == -patches[patchi].nf();
+    }
+
+    ny = fvc::grad(d);
+
+    surfaceVectorField nf(fvc::interpolate(ny));
+
+    return tmp<surfaceScalarField>::New("yPhi", mesh_.Sf() & nf);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointEikonalSolver::adjointEikonalSolver
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    const autoPtr<incompressible::RASModelVariables>& RASModelVars,
+    autoPtr<Foam::incompressibleAdjoint::adjointRASModel>& adjointTurbulence,
+    const labelList& sensitivityPatchIDs
+)
+:
+    mesh_(mesh),
+    dict_(dict.subOrEmptyDict("adjointEikonalSolver")),
+    RASModelVars_(RASModelVars),
+    adjointTurbulence_(adjointTurbulence),
+    sensitivityPatchIDs_(sensitivityPatchIDs),
+    nEikonalIters_(-1),
+    tolerance_(-1),
+    epsilon_(Zero),
+    wallPatchIDs_(mesh_.boundaryMesh().findPatchIDs<wallPolyPatch>()),
+    da_
+    (
+        IOobject
+        (
+            "da",
+            mesh_.time().timeName(),
+            mesh_,
+            IOobject::READ_IF_PRESENT,
+            IOobject::AUTO_WRITE
+        ),
+        mesh_,
+        dimensionedScalar(sqr(dimLength)/pow3(dimTime), Zero),
+        patchTypes()
+    ),
+    distanceSensPtr_(createZeroBoundaryPtr<vector>(mesh_))
+{
+    read();
+};
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool adjointEikonalSolver::readDict(const dictionary& dict)
+{
+    dict_ = dict.subOrEmptyDict("adjointEikonalSolver");
+
+    return true;
+}
+
+
+void adjointEikonalSolver::solve()
+{
+    read();
+
+    // Primal distance field
+    const volScalarField& d = RASModelVars_().d();
+
+    // Populate the source term. Not dependent from da, so only
+    // need to update it once per optimisation cycle
+    tmp<volScalarField> tsource = adjointTurbulence_->distanceSensitivities();
+    const volScalarField& source = tsource();
+
+    // Convecting flux
+    tmp<surfaceScalarField> tyPhi = computeYPhi();
+    const surfaceScalarField& yPhi = tyPhi();
+
+    // Iterate the adjoint to the eikonal equation
+    for (label iter = 0; iter < nEikonalIters_; ++iter)
+    {
+        read();
+
+        Info<< "Adjoint Eikonal Iteration : " << iter << endl;
+
+        fvScalarMatrix daEqn
+        (
+            2*fvm::div(-yPhi, da_)
+          + fvm::SuSp(-epsilon_*fvc::laplacian(d), da_)
+          - epsilon_*fvm::laplacian(d, da_)
+          + source
+        );
+
+        daEqn.relax();
+        scalar residual = daEqn.solve().initialResidual();
+        Info<< "Max da " << gMax(mag(da_)()) << endl;
+
+        Info<< "ExecutionTime = " << mesh_.time().elapsedCpuTime() << " s"
+            << "  ClockTime = " << mesh_.time().elapsedClockTime() << " s"
+            << nl << endl;
+
+        // Check convergence
+        if (residual < tolerance_)
+        {
+            Info<< "\n***Reached adjoint eikonal convergence limit, iteration "
+                << iter << "***\n\n";
+            break;
+        }
+    }
+    da_.write();
+}
+
+
+boundaryVectorField& adjointEikonalSolver::distanceSensitivities()
+{
+    Info<< "Calculating distance sensitivities " << endl;
+
+    boundaryVectorField& distanceSens = distanceSensPtr_();
+
+    const volScalarField& d = RASModelVars_().d();
+    for (const label patchi : sensitivityPatchIDs_)
+    {
+        vectorField nf(mesh_.boundary()[patchi].nf());
+
+        // No surface area included. Will be done by the actual sensitivity tool
+        distanceSens[patchi] =
+           -2.*da_.boundaryField()[patchi]
+           *d.boundaryField()[patchi].snGrad()
+           *d.boundaryField()[patchi].snGrad()*nf;
+    }
+    return distanceSens;
+}
+
+
+tmp<volTensorField> adjointEikonalSolver::getFISensitivityTerm()  const
+{
+    Info<< "Calculating distance sensitivities " << endl;
+
+    const volScalarField& d = RASModelVars_().d();
+    const volVectorField gradD(fvc::grad(d));
+
+    volVectorField gradDDa
+    (
+        IOobject
+        (
+            "gradDDa",
+            mesh_.time().timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::AUTO_WRITE
+        ),
+        mesh_,
+        dimensionedVector(d.dimensions()*da_.dimensions()/dimLength, Zero),
+        patchDistMethod::patchTypes<vector>(mesh_, wallPatchIDs_)
+    );
+    gradDDa = fvc::grad(d*da_);
+
+    tmp<volTensorField> tdistanceSens
+    (
+        new volTensorField
+        (
+            IOobject
+            (
+                "distanceSensFI",
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE
+            ),
+            mesh_,
+            dimensionedTensor(da_.dimensions(), Zero)
+        )
+    );
+    volTensorField& distanceSens = tdistanceSens.ref();
+
+    distanceSens =
+        - 2.*da_*gradD*gradD
+        - epsilon_*gradD*gradDDa
+        + epsilon_*da_*d*fvc::grad(gradD);
+
+    return tdistanceSens;
+}
+
+
+const volScalarField& adjointEikonalSolver::da()
+{
+    return da_;
+}
+
+
+tmp<volVectorField> adjointEikonalSolver::gradEikonal()
+{
+    const volScalarField& d = RASModelVars_().d();
+    volVectorField gradD(fvc::grad(d));
+    return tmp<volVectorField>::New("gradEikonal", 2*gradD & fvc::grad(gradD));
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointEikonalSolver/adjointEikonalSolverIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointEikonalSolver/adjointEikonalSolverIncompressible.H
new file mode 100644
index 0000000000000000000000000000000000000000..2e9a24539c394e83ce5ff0ffd556e64cf86735de
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointEikonalSolver/adjointEikonalSolverIncompressible.H
@@ -0,0 +1,259 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::adjointEikonalSolver
+
+Description
+    Solver of the adjoint to the eikonal PDE
+
+    Reference:
+    \verbatim
+        For the development of the adjoint eikonal PDE and its boundary
+        conditions
+
+            Papoutsis-Kiachagias, E. M., & Giannakoglou, K. C. (2014).
+            Continuous Adjoint Methods for Turbulent Flows, Applied to Shape
+            and Topology Optimization: Industrial Applications.
+            Archives of Computational Methods in Engineering, 23(2), 255-299.
+            http://doi.org/10.1007/s11831-014-9141-9
+    \endverbatim
+
+    To be as consistent as possible, it is recommended to use the
+    advectionDiffusion wallDist method in fvSchemes, instead of the more widely
+    used meshWave
+
+    Example of the adjointEikonalSolver specification in optimisationDict:
+    \verbatim
+        optimisation
+        {
+            sensitivities
+            {
+                includeDistance true;
+                adjointEikonalSolver
+                {
+                    // epsilon should be the same as the one used
+                    // in fvSchemes/wallDist/advectionDiffusionCoeffs
+                    epsilon   0.1;
+                    iters     1000;
+                    tolerance 1e-6;
+                }
+            }
+        }
+    \endverbatim
+
+    Example of the entries in fvSchemes:
+    \verbatim
+        divSchemes
+        {
+            .
+            .
+            // avoid bounded schemes since yPhi is not conservative
+            div(-yPhi,da) Gauss linearUpwind grad(da);
+            .
+            .
+        }
+        laplacianSchemes
+        {
+            .
+            .
+            laplacian(yWall,da) Gauss linear corrected;
+            .
+            .
+        }
+    \endverbatim
+
+    Also, the solver specification and a relaxation factor for da are required
+    in fvSolution
+
+    \verbatim
+        da
+        {
+            solver          PBiCGStab;
+            preconditioner  DILU;
+            tolerance       1e-9;
+            relTol          0.1;
+        }
+
+        relaxationFactors
+        {
+            equations
+            {
+                .
+                .
+                da           0.5;
+                .
+                .
+            }
+        }
+    \endverbatim
+
+See also
+    Foam::patchDistMethod::advectionDiffusion
+    Foam::wallDist
+
+
+SourceFiles
+    adjointEikonalSolver.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointEikonalSolverIncompressible_H
+#define adjointEikonalSolverIncompressible_H
+
+#include "IOdictionary.H"
+#include "adjointRASModel.H"
+#include "createZeroField.H"
+#include "boundaryFieldsFwd.H"
+#include "RASModelVariables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+/*---------------------------------------------------------------------------*\
+                    Class adjointEikonalSolver Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointEikonalSolver
+{
+private:
+
+    // Private Member Functions
+
+        //- No copy construct
+        adjointEikonalSolver(const adjointEikonalSolver&) = delete;
+
+        //- No copy assignment
+        void operator=(const adjointEikonalSolver&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        const fvMesh& mesh_;
+
+        dictionary dict_;
+
+        const autoPtr<incompressible::RASModelVariables>& RASModelVars_;
+
+        autoPtr<Foam::incompressibleAdjoint::adjointRASModel>&
+            adjointTurbulence_;
+
+        const labelList& sensitivityPatchIDs_;
+
+        label nEikonalIters_;
+
+        scalar tolerance_;
+
+        scalar epsilon_;
+
+        labelHashSet wallPatchIDs_;
+
+        volScalarField da_;
+
+        //- Wall face sens w.r.t. (x,y.z)
+        autoPtr<boundaryVectorField> distanceSensPtr_;
+
+
+    // Protected functions
+
+        //- Return the boundary condition types for da
+        wordList patchTypes() const;
+
+        //- Compute convecting velocity
+        tmp<surfaceScalarField> computeYPhi();
+
+        //- Read options each time a new solution is found
+        void read();
+
+
+
+public:
+
+    //- Runtime type information
+    TypeName("adjointEikonalSolver");
+
+
+    // Constructors
+
+        //- Construct from components
+        adjointEikonalSolver
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            const autoPtr<incompressible::RASModelVariables>& RASModelVars,
+            autoPtr<Foam::incompressibleAdjoint::adjointRASModel>&
+                  adjointTurbulence,
+            const labelList& sensitivityPatchIDs
+        );
+
+    // Destructor
+
+       virtual ~adjointEikonalSolver() = default;
+
+
+    // Member Functions
+
+       //- Read dict if changed
+       virtual bool readDict(const dictionary& dict);
+
+       //- Calculate the adjoint distance field
+       void solve();
+
+       //- Return the sensitivity term depending on da
+       boundaryVectorField& distanceSensitivities();
+
+       //- Return the volume-based sensitivity term depending on da
+       tmp<volTensorField> getFISensitivityTerm() const;
+
+       //-  Return the adjoint distance field
+       const volScalarField& da();
+
+       //- Return the distance field
+       const volScalarField& d();
+
+       //- Return the gradient of the eikonal equation
+       tmp<volVectorField> gradEikonal();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.C
new file mode 100644
index 0000000000000000000000000000000000000000..4116a3a2f26bee4c224a007eadae5e2d4d5f5148
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.C
@@ -0,0 +1,174 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointMeshMovementSolverIncompressible.H"
+#include "subCycleTime.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(adjointMeshMovementSolver, 0);
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+void adjointMeshMovementSolver::read()
+{
+    nLaplaceIters_ = dict_.lookupOrDefault<label>("iters", 1000);
+    tolerance_ = dict_.lookupOrDefault<scalar>("tolerance", 1e-6);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointMeshMovementSolver::adjointMeshMovementSolver
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    Foam::incompressible::adjointSensitivity& adjointSensitivity,
+    const labelList& sensitivityPatchIDs,
+    const autoPtr<adjointEikonalSolver>& adjointEikonalSolverPtr
+)
+:
+    mesh_(mesh),
+    dict_(dict.subOrEmptyDict("adjointMeshMovementSolver")),
+    adjointSensitivity_(adjointSensitivity),
+    sensitivityPatchIDs_(sensitivityPatchIDs),
+    nLaplaceIters_(-1),
+    tolerance_(-1),
+    ma_
+    (
+        variablesSet::autoCreateMeshMovementField
+        (
+            mesh,
+            "ma",
+            dimensionSet(pow3(dimLength/dimTime))
+        )
+    ),
+    meshMovementSensPtr_(createZeroBoundaryPtr<vector>(mesh_)),
+    adjointEikonalSolverPtr_(adjointEikonalSolverPtr)
+{
+    read();
+};
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool adjointMeshMovementSolver::readDict(const dictionary& dict)
+{
+    dict_ = dict.subOrEmptyDict("adjointMeshMovementSolver");
+
+    return true;
+}
+
+
+void adjointMeshMovementSolver::solve()
+{
+    read();
+
+    // Compute source term
+    tmp<volVectorField> tsource
+    (
+        adjointSensitivity_.adjointMeshMovementSource()
+    );
+    volVectorField& source = tsource.ref();
+
+    if (adjointEikonalSolverPtr_.valid())
+    {
+        source -=
+            fvc::div(adjointEikonalSolverPtr_().getFISensitivityTerm()().T());
+    }
+
+    // Iterate the adjoint to the eikonal equation
+    for (label iter = 0; iter < nLaplaceIters_; iter++)
+    {
+        Info<< "Adjoint Mesh Movement Iteration: " << iter << endl;
+
+        fvVectorMatrix maEqn
+        (
+            fvm::laplacian(ma_)
+          + source
+        );
+
+        maEqn.boundaryManipulate(ma_.boundaryFieldRef());
+
+        //scalar residual = max(maEqn.solve().initialResidual());
+        scalar residual = mag(maEqn.solve().initialResidual());
+
+        Info<< "Max ma " << gMax(mag(ma_)()) << endl;
+
+        Info<< "ExecutionTime = " << mesh_.time().elapsedCpuTime() << " s"
+            << "  ClockTime = " << mesh_.time().elapsedClockTime() << " s"
+            << nl << endl;
+
+        // Check convergence
+        if (residual < tolerance_)
+        {
+            Info<< "\n***Reached adjoint mesh movement convergence limit, "
+                   "iteration " << iter << "***\n\n";
+            break;
+        }
+    }
+    ma_.write();
+}
+
+
+boundaryVectorField& adjointMeshMovementSolver::meshMovementSensitivities()
+{
+    Info<< "Calculating mesh movement sensitivities " << endl;
+
+    boundaryVectorField& meshMovementSens = meshMovementSensPtr_();
+
+    for (const label patchi : sensitivityPatchIDs_)
+    {
+        // No surface area included. Will be done by the actual sensitivity tool
+        meshMovementSens[patchi] = -ma_.boundaryField()[patchi].snGrad();
+    }
+
+    return meshMovementSens;
+}
+
+
+const volVectorField& adjointMeshMovementSolver::ma()
+{
+    return ma_;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.H
new file mode 100644
index 0000000000000000000000000000000000000000..809de884c6047029adc4cabba9761b8fadace7c8
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.H
@@ -0,0 +1,148 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::adjointMeshMovementSolver
+
+Description
+    Solver of the adjoint to the Laplace grid displacement equation
+
+    Reference:
+    \verbatim
+        Kavvadias, I., Papoutsis-Kiachagias, E., & Giannakoglou, K. (2015).
+        On the proper treatment of grid sensitivities in continuous adjoint
+        methods for shape optimization.
+        Journal of Computational Physics, 301, 1–18.
+        http://doi.org/10.1016/j.jcp.2015.08.012
+    \endverbatim
+
+SourceFiles
+    adjointMeshMovementSolver.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointMeshMovementSolverIncompressible_H
+#define adjointMeshMovementSolverIncompressible_H
+
+#include "adjointSensitivityIncompressible.H"
+#include "adjointEikonalSolverIncompressible.H"
+#include "createZeroField.H"
+#include "boundaryFieldsFwd.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+/*---------------------------------------------------------------------------*\
+                  Class adjointMeshMovementSolver Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointMeshMovementSolver
+{
+protected:
+
+    // Protected data
+
+        const fvMesh& mesh_;
+        dictionary dict_;
+        Foam::incompressible::adjointSensitivity& adjointSensitivity_;
+        const labelList& sensitivityPatchIDs_;
+        label nLaplaceIters_;
+        scalar tolerance_;
+        volVectorField ma_;
+
+        //- Wall face sens w.r.t.(x, y.z) //wall face sens w.r.t. (x,y.z)
+        autoPtr<boundaryVectorField> meshMovementSensPtr_;
+        const autoPtr<adjointEikonalSolver>& adjointEikonalSolverPtr_;
+
+        //- Read options each time a new solution is found
+        void read();
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        adjointMeshMovementSolver(const adjointMeshMovementSolver&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const adjointMeshMovementSolver&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("adjointMeshMovementSolver");
+
+
+    // Constructors
+
+        //- Construct from components
+        adjointMeshMovementSolver
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            Foam::incompressible::adjointSensitivity& adjointSensitivity,
+            const labelList& sensitivityPatchIDs,
+            const autoPtr<adjointEikonalSolver>& adjointEikonalSolverPtr
+        );
+
+    //- Destructor
+    virtual ~adjointMeshMovementSolver() = default;
+
+
+    // Member Functions
+
+       //- Read dict if changed
+       virtual bool readDict(const dictionary& dict);
+
+       //- Calculate the adjoint distance field
+       void solve();
+
+       //- Return the sensitivity term depending on da
+       boundaryVectorField& meshMovementSensitivities();
+
+       //- Return the adjoint distance field
+       const volVectorField& ma();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointSensitivity/adjointSensitivityIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointSensitivity/adjointSensitivityIncompressible.C
new file mode 100644
index 0000000000000000000000000000000000000000..b7476fa83201607d212dec99ec9f32672fa47e29
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointSensitivity/adjointSensitivityIncompressible.C
@@ -0,0 +1,341 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "runTimeSelectionTables.H"
+#include "adjointSensitivityIncompressible.H"
+#include "boundaryAdjointContribution.H"
+#include "incompressibleAdjointSolver.H"
+#include "wallFvPatch.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(adjointSensitivity, 0);
+defineRunTimeSelectionTable(adjointSensitivity, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointSensitivity::adjointSensitivity
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    incompressibleVars& primalVars,
+    incompressibleAdjointVars& adjointVars,
+    objectiveManager& objectiveManager,
+    fv::optionAdjointList& fvOptionsAdjoint
+)
+:
+    sensitivity(mesh, dict, objectiveManager.adjointSolverName()),
+    primalVars_(primalVars),
+    adjointVars_(adjointVars),
+    objectiveManager_(objectiveManager),
+    fvOptionsAdjoint_(fvOptionsAdjoint)
+{}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+autoPtr<adjointSensitivity> adjointSensitivity::New
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    incompressibleVars& primalVars,
+    incompressibleAdjointVars& adjointVars,
+    objectiveManager& objectiveManager,
+    fv::optionAdjointList& fvOptionsAdjoint
+)
+{
+    const word sensitivityType(dict.get<word>("type"));
+
+    Info<< "adjointSensitivity type : " << sensitivityType << endl;
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(sensitivityType);
+
+    if (!cstrIter.found())
+    {
+        FatalIOErrorInFunction(dict)
+            << "Unknown adjointSensitivity type " << sensitivityType
+            << nl << nl
+            << "Valid adjointSensitivity types are :" << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalIOError);
+    }
+
+    return autoPtr<adjointSensitivity>
+    (
+        cstrIter()
+        (
+            mesh,
+            dict,
+            primalVars,
+            adjointVars,
+            objectiveManager,
+            fvOptionsAdjoint
+        )
+    );
+}
+
+
+// * * * * * * * * * * * * * * *  Member Functions   * * * * * * * * * * * * //
+
+void adjointSensitivity::write(const word& baseName)
+{
+    sensitivity::write(baseName);
+}
+
+
+tmp<volTensorField> adjointSensitivity::computeGradDxDbMultiplier()
+{
+    // Term depending on the adjoint turbulence model
+    autoPtr<incompressibleAdjoint::adjointRASModel>& adjointRAS
+    (
+        adjointVars_.adjointTurbulence()
+    );
+    tmp<volTensorField> tturbulenceTerm(adjointRAS->FISensitivityTerm());
+    volTensorField& turbulenceTerm = tturbulenceTerm.ref();
+
+    // nu effective
+    tmp<volScalarField> tnuEff(adjointRAS->nuEff());
+    const volScalarField& nuEff = tnuEff();
+
+    tmp<volTensorField> tflowTerm
+    (
+        new volTensorField
+        (
+            IOobject
+            (
+               "flowTerm",
+               mesh_.time().timeName(),
+               mesh_,
+               IOobject::NO_READ,
+               IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedTensor(sqr(dimLength)/pow3(dimTime), Zero)
+        )
+    );
+    volTensorField& flowTerm = tflowTerm.ref();
+
+    const volScalarField& p = primalVars_.p();
+    const volVectorField& U = primalVars_.U();
+    const volScalarField& pa = adjointVars_.pa();
+    const volVectorField& Ua = adjointVars_.Ua();
+    volTensorField gradU(fvc::grad(U));
+    volTensorField gradUa(fvc::grad(Ua));
+
+    // Explicitly correct the boundary gradient to get rid of
+    // the tangential component
+    forAll(mesh_.boundary(), patchI)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        if (isA<wallFvPatch>(patch))
+        {
+            tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
+            const vectorField& nf = tnf();
+            gradU.boundaryFieldRef()[patchI] =
+                nf*U.boundaryField()[patchI].snGrad();
+            //gradUa.boundaryField()[patchI] =
+            //    nf*Ua.boundaryField()[patchI].snGrad();
+        }
+    }
+
+    volTensorField stress(nuEff*(gradU + T(gradU)));
+    autoPtr<volVectorField> stressXPtr
+    (
+        createZeroFieldPtr<vector>(mesh_, "stressX", stress.dimensions())
+    );
+    autoPtr<volVectorField> stressYPtr
+    (
+        createZeroFieldPtr<vector>(mesh_, "stressY", stress.dimensions())
+    );
+    autoPtr<volVectorField> stressZPtr
+    (
+        createZeroFieldPtr<vector>(mesh_, "stressZ", stress.dimensions())
+    );
+
+    stressXPtr().replace(0, stress.component(0));
+    stressXPtr().replace(1, stress.component(1));
+    stressXPtr().replace(2, stress.component(2));
+
+    stressYPtr().replace(0, stress.component(3));
+    stressYPtr().replace(1, stress.component(4));
+    stressYPtr().replace(2, stress.component(5));
+
+    stressZPtr().replace(0, stress.component(6));
+    stressZPtr().replace(1, stress.component(7));
+    stressZPtr().replace(2, stress.component(8));
+
+    volTensorField gradStressX(fvc::grad(stressXPtr()));
+    volTensorField gradStressY(fvc::grad(stressYPtr()));
+    volTensorField gradStressZ(fvc::grad(stressZPtr()));
+
+    // Contribution from objective functions and constraints
+    volTensorField objectiveContributions
+    (
+        IOobject
+        (
+            "objectiveContributions",
+            mesh_.time().timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        mesh_,
+        dimensionedTensor(sqr(dimLength)/pow3(dimTime), Zero)
+    );
+    PtrList<objective>& functions(objectiveManager_.getObjectiveFunctions());
+    forAll(functions, funcI)
+    {
+        objectiveContributions +=
+            functions[funcI].weight()
+           *functions[funcI].gradDxDbMultiplier();
+    }
+
+    // Note:
+    // term4 (Ua & grad(stress)) is numerically tricky.  Its div leads to third
+    // order spatial derivs in E-SI based computations Applying the product
+    // derivative rule (putting Ua inside the grad) gives better results in
+    // NACA0012, SA, WF.  However, the original formulation should be kept at
+    // the boundary in order to respect the Ua boundary conditions (necessary
+    // for E-SI to give the same sens as FI).  A mixed approach is hence
+    // followed
+    volTensorField term4
+    (
+      - nuEff*(gradUa & (gradU + T(gradU)))
+      + fvc::grad(nuEff * Ua & (gradU + T(gradU)))
+    );
+
+    forAll(mesh_.boundary(), pI)
+    {
+        if (!isA<coupledFvPatch>(mesh_.boundary()[pI]))
+        {
+            term4.boundaryFieldRef()[pI] =
+                Ua.component(0)().boundaryField()[pI]
+               *gradStressX.boundaryField()[pI]
+              + Ua.component(1)().boundaryField()[pI]
+               *gradStressY.boundaryField()[pI]
+              + Ua.component(2)().boundaryField()[pI]
+               *gradStressZ.boundaryField()[pI];
+        }
+    }
+
+    const autoPtr<ATCModel>& ATCModel =
+        mesh_.lookupObject<incompressibleAdjointSolver>
+        (
+            objectiveManager_.adjointSolverName()
+        ).getATCModel();
+
+    // Compute dxdb multiplier
+    flowTerm =
+        // Term 1, ATC
+        ATCModel->getFISensitivityTerm()
+        // Term 2
+      - fvc::grad(p) * Ua
+        // Term 3
+      - nuEff*(gradU & (gradUa + T(gradUa)))
+        // Term 4
+      + term4
+        // Term 5
+      + (pa * gradU)
+        // Term 6, from the adjoint turbulence model
+      + turbulenceTerm.T()
+        // Term 7, term from objective functions
+      + objectiveContributions;
+
+    // Correct boundary conditions for the flow term.
+    // Needed since the div of this term is often used
+    forAll(mesh_.boundary(), pI)
+    {
+        const fvPatch& patch = mesh_.boundary()[pI];
+        bool isSensPatch(false);
+        forAll(sensitivityPatchIDs_, pJ)
+        {
+            label patchJ = sensitivityPatchIDs_[pJ];
+            if (patchJ == pI)
+            {
+                isSensPatch = true;
+                break;
+            }
+        }
+
+        if (!isSensPatch && !isA<coupledFvPatch>(patch))
+        {
+            flowTerm.boundaryFieldRef()[pI] =
+                tensorField(patch.size(), tensor::zero);
+        }
+    }
+
+    flowTerm.correctBoundaryConditions();
+
+    return (tflowTerm);
+}
+
+
+tmp<volVectorField> adjointSensitivity::adjointMeshMovementSource()
+{
+    tmp<volTensorField> tgradDxDbMult = computeGradDxDbMultiplier();
+    volTensorField& gradDxDbMult = tgradDxDbMult.ref();
+
+    tmp<volVectorField> tadjointMeshMovementSource
+    (
+        new volVectorField
+        (
+            IOobject
+            (
+               "adjointMeshMovementSource",
+               mesh_.time().timeName(),
+               mesh_,
+               IOobject::NO_READ,
+               IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedVector(gradDxDbMult.dimensions()/dimLength, Zero)
+        )
+    );
+
+    volVectorField& source = tadjointMeshMovementSource.ref();
+
+    source -= fvc::div(gradDxDbMult.T());
+
+    return (tadjointMeshMovementSource);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointSensitivity/adjointSensitivityIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointSensitivity/adjointSensitivityIncompressible.H
new file mode 100644
index 0000000000000000000000000000000000000000..4db487498601e2ccb03d3126b35259ce2b8a4955
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointSensitivity/adjointSensitivityIncompressible.H
@@ -0,0 +1,195 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::adjointSensitivity
+
+Description
+    Abstract base class for adjoint-based sensitivities in incompressible flows
+
+    Reference:
+    \verbatim
+        For the FI and ESI formulations
+            Kavvadias, I., Papoutsis-Kiachagias, E., & Giannakoglou, K. (2015).
+            On the proper treatment of grid sensitivities in continuous adjoint
+            methods for shape optimization.
+            Journal of Computational Physics, 301, 1–18.
+            http://doi.org/10.1016/j.jcp.2015.08.012
+
+        For the SI formulation
+            Papoutsis-Kiachagias, E. M., & Giannakoglou, K. C. (2014).
+            Continuous Adjoint Methods for Turbulent Flows, Applied to Shape
+            and Topology Optimization: Industrial Applications.
+            Archives of Computational Methods in Engineering, 23(2), 255–299.
+            http://doi.org/10.1007/s11831-014-9141-9
+    \endverbatim
+
+SourceFiles
+    adjointSensitivity.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointSensitivityIncompressible_H
+#define adjointSensitivityIncompressible_H
+
+#include "sensitivity.H"
+#include "incompressibleVars.H"
+#include "incompressibleAdjointVars.H"
+#include "fvOptionAdjointList.H"
+#include "wallFvPatch.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+/*---------------------------------------------------------------------------*\
+                     Class adjointSensitivity Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointSensitivity
+:
+    public sensitivity
+{
+protected:
+
+    // Protected data
+
+        incompressibleVars& primalVars_;
+        incompressibleAdjointVars& adjointVars_;
+        objectiveManager& objectiveManager_;
+        fv::optionAdjointList& fvOptionsAdjoint_;
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        adjointSensitivity(const adjointSensitivity&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const adjointSensitivity&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("adjointSensitivity");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            adjointSensitivity,
+            dictionary,
+            (
+                const fvMesh& mesh,
+                const dictionary& dict,
+                incompressibleVars& primalVars,
+                incompressibleAdjointVars& adjointVars,
+                objectiveManager& objectiveManager,
+                fv::optionAdjointList& fvOptionsAdjoint
+            ),
+            (
+                mesh,
+                dict,
+                primalVars,
+                adjointVars,
+                objectiveManager,
+                fvOptionsAdjoint
+            )
+        );
+
+
+    // Constructors
+
+        //- Construct from components
+        adjointSensitivity
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            incompressibleVars& primalVars,
+            incompressibleAdjointVars& adjointVars,
+            objectiveManager& objectiveManager,
+            fv::optionAdjointList& fvOptionsAdjoint
+        );
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<adjointSensitivity> New
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            incompressibleVars& primalVars,
+            incompressibleAdjointVars& adjointVars,
+            objectiveManager& objectiveManager,
+            fv::optionAdjointList& fvOptionsAdjoint
+        );
+
+
+    //- Destructor
+    virtual ~adjointSensitivity() = default;
+
+
+    // Member Functions
+
+       //- Calculates and returns sensitivity fields.
+       //  Used with optimisation libraries
+       virtual const scalarField& calculateSensitivities() = 0;
+
+       //- Write sensitivity fields.
+       //  If valid, copies boundaryFields to volFields and writes them.
+       //  Virtual to be reimplemented by control points-based methods
+       //  (Bezier, RBF) which do not need to write fields
+       virtual void write(const word& baseName = word::null);
+
+       //- Compute the volTensorField multiplying grad(dxdb) for
+       //- the volume-based approach to compute shape sensitivity derivatives
+       tmp<volTensorField> computeGradDxDbMultiplier();
+
+       //- Compute source term for adjoint mesh movement equation
+       tmp<volVectorField> adjointMeshMovementSource();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityMultiple/sensitivityMultipleIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityMultiple/sensitivityMultipleIncompressible.C
new file mode 100644
index 0000000000000000000000000000000000000000..ea5dfe604d0a41262105988f46c75e051dbf5506
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityMultiple/sensitivityMultipleIncompressible.C
@@ -0,0 +1,142 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "sensitivityMultipleIncompressible.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(sensitivityMultiple, 0);
+addToRunTimeSelectionTable
+(
+    adjointSensitivity,
+    sensitivityMultiple,
+    dictionary
+);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+sensitivityMultiple::sensitivityMultiple
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    incompressibleVars& primalVars,
+    incompressibleAdjointVars& adjointVars,
+    objectiveManager& objectiveManager,
+    fv::optionAdjointList& fvOptionsAdjoint
+)
+:
+    adjointSensitivity
+    (
+        mesh,
+        dict,
+        primalVars,
+        adjointVars,
+        objectiveManager,
+        fvOptionsAdjoint
+    ),
+    sensTypes_(dict.subDict("sensTypes").toc()),
+    sens_(sensTypes_.size()),
+    derivatives_(0)
+{
+    forAll(sensTypes_, sI)
+    {
+        sens_.set
+        (
+            sI,
+            adjointSensitivity::New
+            (
+                mesh,
+                dict.subDict("sensTypes").subDict(sensTypes_[sI]),
+                primalVars,
+                adjointVars,
+                objectiveManager,
+                fvOptionsAdjoint
+            )
+        );
+    }
+};
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool sensitivityMultiple::readDict(const dictionary& dict)
+{
+    if (sensitivity::readDict(dict))
+    {
+        forAll(sens_, sI)
+        {
+            sens_[sI].readDict
+            (
+                dict.subDict("sensTypes").subDict(sensTypes_[sI])
+            );
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+
+const scalarField& sensitivityMultiple::calculateSensitivities()
+{
+    forAll(sens_, sI)
+    {
+        Info<< "Computing sensitivities " << sensTypes_[sI] << endl;
+        sens_[sI].calculateSensitivities();
+    }
+    write(type());
+
+    return (derivatives_);
+}
+
+
+void sensitivityMultiple::write(const word& baseName)
+{
+    forAll(sens_, sI)
+    {
+        sens_[sI].write(sensTypes_[sI]);
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityMultiple/sensitivityMultipleIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityMultiple/sensitivityMultipleIncompressible.H
new file mode 100644
index 0000000000000000000000000000000000000000..5b95a4f728cd7d205b13c307ae241013a2301800
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityMultiple/sensitivityMultipleIncompressible.H
@@ -0,0 +1,128 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::sensitivityMultiple
+
+Description
+    Calculation of adjoint based sensitivities of multiple types
+
+SourceFiles
+    sensitivityMultiple.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef sensitivityMultipleIncompressible_H
+#define sensitivityMultipleIncompressible_H
+
+#include "adjointSensitivityIncompressible.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+/*---------------------------------------------------------------------------*\
+                     Class sensitivityMultiple Declaration
+\*---------------------------------------------------------------------------*/
+
+class sensitivityMultiple
+:
+    public adjointSensitivity
+{
+protected:
+
+    // Protected data
+
+        wordList sensTypes_;
+
+        PtrList<adjointSensitivity> sens_;
+
+        scalarField derivatives_;
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        sensitivityMultiple(const sensitivityMultiple&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const sensitivityMultiple&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("multiple");
+
+
+    // Constructors
+
+        //- Construct from components
+        sensitivityMultiple
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            incompressibleVars& primalVars,
+            incompressibleAdjointVars& adjointVars,
+            objectiveManager& objectiveManager,
+            fv::optionAdjointList& fvOptionsAdjoint
+        );
+
+
+    //- Destructor
+    virtual ~sensitivityMultiple() = default;
+
+
+    // Member Functions
+
+       //- Read dict if changed
+       virtual bool readDict(const dictionary& dict);
+
+       //- Calculates sensitivities at wall surface points
+       const scalarField& calculateSensitivities();
+
+       //- Write sensitivities to file
+       virtual void write(const word& baseName = word::null);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressible.C
new file mode 100644
index 0000000000000000000000000000000000000000..5fca573e46dc8b9573a9c4d8742566487b2bb401
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressible.C
@@ -0,0 +1,712 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "sensitivitySurfaceIncompressible.H"
+#include "PrimitivePatchInterpolation.H"
+#include "syncTools.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(sensitivitySurface, 0);
+addToRunTimeSelectionTable
+(
+    adjointSensitivity,
+    sensitivitySurface,
+    dictionary
+);
+
+// * * * * * * * * * * * Private  Member Functions  * * * * * * * * * * * * * //
+
+void sensitivitySurface::read()
+{
+    includeSurfaceArea_ =
+        dict().lookupOrDefault<bool>("includeSurfaceArea", true);
+    includePressureTerm_ =
+        dict().lookupOrDefault<bool>("includePressure", true);
+    includeGradStressTerm_ =
+        dict().lookupOrDefault<bool>("includeGradStressTerm", true);
+    includeTransposeStresses_ =
+        dict().lookupOrDefault<bool>("includeTransposeStresses", true);
+    includeDivTerm_ = dict().lookupOrDefault<bool>("includeDivTerm", false);
+    includeDistance_ =
+        dict().lookupOrDefault<bool>
+        (
+            "includeDistance",
+            adjointVars_.adjointTurbulence().ref().includeDistance()
+        );
+    includeMeshMovement_ =
+        dict().lookupOrDefault<bool>("includeMeshMovement", true);
+    includeObjective_ =
+        dict().lookupOrDefault<bool>("includeObjectiveContribution", true);
+    writeGeometricInfo_ =
+        dict().lookupOrDefault<bool>("writeGeometricInfo", false);
+
+    // Allocate new solvers if necessary
+    if (includeDistance_ && eikonalSolver_.empty())
+    {
+        eikonalSolver_.reset
+        (
+            new adjointEikonalSolver
+            (
+                mesh_,
+                dict_,
+                primalVars_.RASModelVariables(),
+                adjointVars_.adjointTurbulence(),
+                sensitivityPatchIDs_
+            )
+        );
+    }
+    if (includeMeshMovement_ && meshMovementSolver_.empty())
+    {
+        meshMovementSolver_.reset
+        (
+            new adjointMeshMovementSolver
+            (
+                mesh_,
+                dict_,
+                *this,
+                sensitivityPatchIDs_,
+                eikonalSolver_
+            )
+        );
+    }
+}
+
+
+void sensitivitySurface::addGeometricSens()
+{
+    if (includeObjective_)
+    {
+        // Grab objective refs
+        PtrList<objective>& functions
+            (objectiveManager_.getObjectiveFunctions());
+        // Compute sens for all points in parameterized patches.
+        // Interfacing points will be accumulated later
+        autoPtr<pointBoundaryVectorField> pointSensdSdb
+        (
+            createZeroBoundaryPointFieldPtr<vector>(mesh_)
+        );
+        autoPtr<pointBoundaryVectorField> pointSensdndb
+        (
+            createZeroBoundaryPointFieldPtr<vector>(mesh_)
+        );
+        // Geometric (or "direct") sensitivities are better computed directly
+        // on the points
+        forAll(sensitivityPatchIDs_, pI)
+        {
+            const label patchI = sensitivityPatchIDs_[pI];
+            const fvPatch& patch = mesh_.boundary()[patchI];
+            vectorField nf(patch.nf());
+
+            // point sens result for patch
+            vectorField& patchdSdb = pointSensdSdb()[patchI];
+            vectorField& patchdndb = pointSensdndb()[patchI];
+
+            vectorField dSdbMultiplierTot(patch.size(), vector::zero);
+            vectorField dndbMultiplierTot(patch.size(), vector::zero);
+            forAll(functions, funcI)
+            {
+                dSdbMultiplierTot +=
+                    functions[funcI].weight()
+                   *functions[funcI].dSdbMultiplier(patchI);
+                dndbMultiplierTot +=
+                    functions[funcI].weight()
+                   *functions[funcI].dndbMultiplier(patchI);
+            }
+            // Correspondance of local point addressing to global point
+            // addressing
+            const labelList& meshPoints = patch.patch().meshPoints();
+            //  List with mesh faces. Global addressing
+            const faceList& faces = mesh_.faces();
+            //  Each local patch point belongs to these local patch faces
+            //  (local numbering)
+            const labelListList& patchPointFaces = patch.patch().pointFaces();
+            //  index of first face in patch
+            const label patchStartIndex = patch.start();
+            //  geometry differentiation engine
+            deltaBoundary dBoundary(mesh_);
+            //  Loop over patch points.
+            //  Collect contributions from each boundary face this point
+            //  belongs to
+            forAll(meshPoints, ppI)
+            {
+                const labelList& pointFaces = patchPointFaces[ppI];
+                forAll(pointFaces, pfI)
+                {
+                    label localFaceIndex = pointFaces[pfI];
+                    label globalFaceIndex = patchStartIndex + localFaceIndex;
+                    const face& faceI = faces[globalFaceIndex];
+                    // Point coordinates. All indices in global numbering
+                    pointField p(faceI.points(mesh_.points()));
+                    tensorField p_d(faceI.size(), tensor::zero);
+                    forAll(faceI, facePointI)
+                    {
+                        if (faceI[facePointI] == meshPoints[ppI])
+                        {
+                            p_d[facePointI] = tensor::I;
+                        }
+                    }
+                    tensorField deltaNormals =
+                        dBoundary.makeFaceCentresAndAreas_d(p, p_d);
+
+                    // Element [1] is the variation in the (dimensional) normal
+                    const tensor& deltaSf = deltaNormals[1];
+                    patchdSdb[ppI] +=
+                        dSdbMultiplierTot[localFaceIndex] & deltaSf;
+
+                    // Element [2] is the variation in the unit normal
+                    const tensor& deltaNf = deltaNormals[2];
+                    patchdndb[ppI]   +=
+                        dndbMultiplierTot[localFaceIndex] & deltaNf;
+                }
+            }
+        }
+        // Do parallel communications to avoid wrong values at processor
+        // boundaries
+        vectorField dSdbGlobal(mesh_.nPoints(), vector::zero);
+        vectorField dndbGlobal(mesh_.nPoints(), vector::zero);
+        forAll(sensitivityPatchIDs_, pI)
+        {
+            const label patchI = sensitivityPatchIDs_[pI];
+            const labelList& meshPoints =
+                mesh_.boundaryMesh()[patchI].meshPoints();
+            forAll(meshPoints, ppI)
+            {
+                const label globaPointI = meshPoints[ppI];
+                dSdbGlobal[globaPointI] += pointSensdSdb()[patchI][ppI];
+                dndbGlobal[globaPointI] += pointSensdndb()[patchI][ppI];
+            }
+        }
+        // Accumulate over processors
+        syncTools::syncPointList
+        (
+            mesh_, dSdbGlobal, plusEqOp<vector>(), vector::zero
+        );
+        syncTools::syncPointList
+        (
+            mesh_, dndbGlobal, plusEqOp<vector>(), vector::zero
+        );
+        // Transfer back to local fields and map to faces
+        forAll(sensitivityPatchIDs_, pI)
+        {
+            const label patchI = sensitivityPatchIDs_[pI];
+            const fvPatch& patch = mesh_.boundary()[patchI];
+            const labelList& meshPoints = patch.patch().meshPoints();
+            const scalarField& magSf = patch.magSf();
+            pointSensdSdb()[patchI].map(dSdbGlobal, meshPoints);
+            pointSensdndb()[patchI].map(dndbGlobal, meshPoints);
+            // Map dSf/dx and dnf/dx term from points to faces.  Ideally, all
+            // sensitivities should be computed at points rather than faces.
+            PrimitivePatchInterpolation<polyPatch> patchInter(patch.patch());
+            vectorField dSdbFace
+            (
+                patchInter.pointToFaceInterpolate(pointSensdSdb()[patchI])
+            );
+            // dSdb already contains the face area. Divide with it to make it
+            // compatible with the rest of the terms
+            dSdbFace /= magSf;
+
+            tmp<vectorField> tdndbFace =
+                patchInter.pointToFaceInterpolate(pointSensdndb()[patchI]);
+            const vectorField& dndbFace = tdndbFace();
+
+            // Add to sensitivity fields
+            wallFaceSensVecPtr_()[patchI] += dSdbFace + dndbFace;
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+sensitivitySurface::sensitivitySurface
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    incompressibleVars& primalVars,
+    incompressibleAdjointVars& adjointVars,
+    objectiveManager& objectiveManager,
+    fv::optionAdjointList& fvOptionsAdjoint
+)
+:
+    adjointSensitivity
+    (
+        mesh,
+        dict,
+        primalVars,
+        adjointVars,
+        objectiveManager,
+        fvOptionsAdjoint
+    ),
+    derivatives_(0),
+    includeSurfaceArea_(false),
+    includePressureTerm_(false),
+    includeGradStressTerm_(false),
+    includeTransposeStresses_(false),
+    includeDivTerm_(false),
+    includeDistance_(false),
+    includeMeshMovement_(false),
+    includeObjective_(false),
+    writeGeometricInfo_(false),
+    eikonalSolver_(nullptr),
+    meshMovementSolver_(nullptr),
+
+    nfOnPatchPtr_(nullptr),
+    SfOnPatchPtr_(nullptr),
+    CfOnPatchPtr_(nullptr)
+{
+    read();
+
+    // Allocate boundary field pointer
+    wallFaceSensVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+    wallFaceSensNormalPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
+    wallFaceSensNormalVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
+
+    // Allocate fields to contain geometric info
+    if (writeGeometricInfo_)
+    {
+        nfOnPatchPtr_.reset
+        (
+            new volVectorField
+            (
+                IOobject
+                (
+                    "nfOnPatch",
+                    mesh.time().timeName(),
+                    mesh,
+                    IOobject::NO_READ,
+                    IOobject::AUTO_WRITE
+                ),
+                mesh,
+                vector::zero
+            )
+        );
+
+        SfOnPatchPtr_.reset
+        (
+            new volVectorField
+            (
+                IOobject
+                (
+                    "SfOnPatch",
+                    mesh.time().timeName(),
+                    mesh,
+                    IOobject::NO_READ,
+                    IOobject::AUTO_WRITE
+                ),
+                mesh,
+                vector::zero
+            )
+        );
+
+        CfOnPatchPtr_.reset
+        (
+            new volVectorField
+            (
+                IOobject
+                (
+                    "CfOnPatch",
+                    mesh.time().timeName(),
+                    mesh,
+                    IOobject::NO_READ,
+                    IOobject::AUTO_WRITE
+                ),
+                mesh,
+                vector::zero
+            )
+        );
+    }
+
+    // Allocate appropriate space for the sensitivity field
+    computeDerivativesSize();
+};
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool sensitivitySurface::readDict(const dictionary& dict)
+{
+    if (sensitivity::readDict(dict))
+    {
+        if (eikonalSolver_.valid())
+        {
+            eikonalSolver_().readDict(dict);
+        }
+
+        if (meshMovementSolver_.valid())
+        {
+            meshMovementSolver_().readDict(dict);
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+
+void sensitivitySurface::computeDerivativesSize()
+{
+    label nFaces(0);
+    forAll(sensitivityPatchIDs_, pI)
+    {
+        const label patchI = sensitivityPatchIDs_[pI];
+        nFaces += mesh_.boundary()[patchI].size();
+    }
+    derivatives_.setSize(nFaces);
+}
+
+
+const scalarField& sensitivitySurface::calculateSensitivities()
+{
+    // Grab references
+    const volScalarField& p = primalVars_.p();
+    const volVectorField& U = primalVars_.U();
+
+    const volScalarField& pa = adjointVars_.pa();
+    const volVectorField& Ua = adjointVars_.Ua();
+    autoPtr<incompressibleAdjoint::adjointRASModel>& adjointTurbulence =
+        adjointVars_.adjointTurbulence();
+
+    // Restore to zero
+    derivatives_ = Zero;
+
+    // Update geometric fields for use by external users
+    if (writeGeometricInfo_)
+    {
+        forAll(sensitivityPatchIDs_, pI)
+        {
+            const label patchI = sensitivityPatchIDs_[pI];
+            const fvPatch& patch = mesh_.boundary()[patchI];
+            tmp<vectorField> tnf = patch.nf();
+            const vectorField& nf = tnf();
+            const vectorField& Sf = patch.Sf();
+            const vectorField& Cf = patch.Cf();
+
+            nfOnPatchPtr_().boundaryFieldRef()[patchI] = nf;
+            SfOnPatchPtr_().boundaryFieldRef()[patchI] = Sf;
+            CfOnPatchPtr_().boundaryFieldRef()[patchI] = Cf;
+        }
+    }
+
+    Info<< "    Calculating auxilary quantities " << endl;
+    // Fields needed to calculate adjoint sensitivities
+    const autoPtr<incompressible::RASModelVariables>&
+       turbVars = primalVars_.RASModelVariables();
+    const singlePhaseTransportModel& lamTransp = primalVars_.laminarTransport();
+    volScalarField nuEff(lamTransp.nu() + turbVars->nutRef());
+    volTensorField gradUa(fvc::grad(Ua));
+    volTensorField gradU(fvc::grad(U));
+
+    // Explicitly correct the boundary gradient to get rid of the tangential
+    // component
+    forAll(mesh_.boundary(), patchI)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        if (isA<wallFvPatch>(patch))
+        {
+            tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
+            const vectorField& nf = tnf();
+            gradU.boundaryFieldRef()[patchI] =
+                nf*U.boundaryField()[patchI].snGrad();
+        }
+    }
+
+    // Auxiliary terms
+    volVectorField gradp(fvc::grad(p));
+    volTensorField stress(nuEff*(gradU + T(gradU)));
+    autoPtr<volVectorField> stressXPtr
+    (
+        createZeroFieldPtr<vector>(mesh_, "stressX", stress.dimensions())
+    );
+    autoPtr<volVectorField> stressYPtr
+    (
+        createZeroFieldPtr<vector>(mesh_, "stressY", stress.dimensions())
+    );
+    autoPtr<volVectorField> stressZPtr
+    (
+        createZeroFieldPtr<vector>(mesh_, "stressZ", stress.dimensions())
+    );
+
+    stressXPtr().replace(0, stress.component(0));
+    stressXPtr().replace(1, stress.component(1));
+    stressXPtr().replace(2, stress.component(2));
+
+    stressYPtr().replace(0, stress.component(3));
+    stressYPtr().replace(1, stress.component(4));
+    stressYPtr().replace(2, stress.component(5));
+
+    stressZPtr().replace(0, stress.component(6));
+    stressZPtr().replace(1, stress.component(7));
+    stressZPtr().replace(2, stress.component(8));
+
+    volTensorField gradStressX(fvc::grad(stressXPtr()));
+    volTensorField gradStressY(fvc::grad(stressYPtr()));
+    volTensorField gradStressZ(fvc::grad(stressZPtr()));
+
+    // Solve extra equations if necessary
+    autoPtr<boundaryVectorField> distanceSensPtr(nullptr);
+    if (includeDistance_)
+    {
+        eikonalSolver_->solve();
+        distanceSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
+        const boundaryVectorField& sens =
+            eikonalSolver_->distanceSensitivities();
+        for (const label patchI : sensitivityPatchIDs_)
+        {
+            distanceSensPtr()[patchI] = sens[patchI];
+        }
+    }
+
+    autoPtr<boundaryVectorField> meshMovementSensPtr(nullptr);
+    if (includeMeshMovement_)
+    {
+        meshMovementSolver_->solve();
+        meshMovementSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
+        const boundaryVectorField& sens =
+            meshMovementSolver_->meshMovementSensitivities();
+        for (const label patchI : sensitivityPatchIDs_)
+        {
+            meshMovementSensPtr()[patchI] = sens[patchI];
+        }
+    }
+
+    // Terms from the adjoint turbulence model
+    const boundaryVectorField& adjointTMsensitivities =
+        adjointTurbulence->wallShapeSensitivities();
+
+    Info<< "    Calculating adjoint sensitivity. " << endl;
+
+    // Sensitivities do not include locale surface area by default.
+    // Part of the sensitivities that multiplies dxFace/db
+    for (const label patchI : sensitivityPatchIDs_)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        tmp<vectorField> tnf = patch.nf();
+        const vectorField& nf = tnf();
+
+        // Includes spurious tangential gradU part. Deprecated
+        /*
+        vectorField stressAndPressureTerm =
+              (
+                - (
+                       Ua.boundaryField()[patchI].snGrad()
+                    + (gradUa.boundaryField()[patchI] & nf)
+                  ) * nuEff.boundaryField()[patchI]
+                + pa.boundaryField()[patchI] *nf
+              ) & gradU.boundaryField()[patchI].T();
+        */
+
+        // Adjoint stress term
+        vectorField stressTerm
+        (
+          - (
+                Ua.boundaryField()[patchI].snGrad()
+              & U.boundaryField()[patchI].snGrad()
+            )
+          * nuEff.boundaryField()[patchI]
+          * nf
+        );
+
+
+        if (includeTransposeStresses_)
+        {
+            stressTerm -=
+                nuEff.boundaryField()[patchI]
+              * (
+                    // Note: in case of laminar or low-Re flows,
+                    // includes a spurious tangential gradUa component
+                    // (gradUa.boundaryField()[patchI] & nf)
+                    ((Ua.boundaryField()[patchI].snGrad() &nf)*nf)
+                    & U.boundaryField()[patchI].snGrad()
+                )
+              * nf;
+        }
+
+        if (includeDivTerm_)
+        {
+            stressTerm +=
+                scalar(1./3.)*nuEff.boundaryField()[patchI]
+              * (
+                    ((Ua.boundaryField()[patchI].snGrad() &nf)*nf)
+                    & U.boundaryField()[patchI].snGrad()
+                )
+              * nf;
+        }
+
+        vectorField gradStressTerm(patch.size(), vector::zero);
+        if (includeGradStressTerm_)
+        {
+            // Terms corresponding to contributions from converting delta to
+            // thetas are added through the corresponding adjoint boundary
+            // conditions instead of grabing contributions from the objective
+            // function.  Useful to have a unified formulation for low- and
+            // high-re meshes
+            const fvPatchVectorField& Uab = Ua.boundaryField()[patchI];
+            gradStressTerm = - ((Uab & nf)*gradp.boundaryField()[patchI]);
+            gradStressTerm +=
+            (
+                Uab.component(0) * gradStressX.boundaryField()[patchI]
+              + Uab.component(1) * gradStressY.boundaryField()[patchI]
+              + Uab.component(2) * gradStressZ.boundaryField()[patchI]
+            ) & nf;
+        }
+
+        // Adjoint pressure terms
+        vectorField pressureTerm(patch.size(), vector::zero);
+        if (includePressureTerm_)
+        {
+            pressureTerm =
+            (
+                (nf*pa.boundaryField()[patchI])
+                & U.boundaryField()[patchI].snGrad()
+            )* nf;
+        }
+
+        // Distance related terms
+        vectorField distanceTerm(pressureTerm.size(), vector::zero);
+        if (includeDistance_)
+        {
+            distanceTerm = distanceSensPtr()[patchI];
+        }
+
+        // Mesh movement related terms
+        vectorField meshMovementTerm(pressureTerm.size(), vector::zero);
+        if (includeMeshMovement_)
+        {
+            meshMovementTerm = meshMovementSensPtr()[patchI];
+        }
+
+        PtrList<objective>& functions
+            (objectiveManager_.getObjectiveFunctions());
+
+        // Term from objectives including x directly (e.g. moments)
+        vectorField dxdbMultiplierTot(pressureTerm.size(), vector::zero);
+        if (includeObjective_)
+        {
+            forAll(functions, funcI)
+            {
+                dxdbMultiplierTot +=
+                    functions[funcI].weight()
+                  * (
+                        functions[funcI].dxdbDirectMultiplier(patchI)
+                    );
+            }
+        }
+
+        // Fill in sensitivity fields
+        wallFaceSensVecPtr_()[patchI] =
+            stressTerm
+          + gradStressTerm
+          + pressureTerm
+          + distanceTerm
+          + meshMovementTerm
+          + adjointTMsensitivities[patchI]
+          + dxdbMultiplierTot;
+    }
+
+    // Add the sensitivity part corresponding to changes of the normal vector
+    // Computed at points and mapped to faces
+    addGeometricSens();
+
+    // Project to normal face vector
+    label nPassedFaces(0);
+    for (const label patchI : sensitivityPatchIDs_)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        tmp<vectorField> tnf(patch.nf());
+        const vectorField& nf = tnf();
+        const scalarField& magSf = patch.magSf();
+
+        if (includeSurfaceArea_)
+        {
+            wallFaceSensVecPtr_()[patchI] *= magSf;
+        }
+
+        wallFaceSensNormalPtr_()[patchI] = wallFaceSensVecPtr_()[patchI] & nf;
+        wallFaceSensNormalVecPtr_()[patchI] =
+            wallFaceSensNormalPtr_()[patchI] * nf;
+
+        forAll(patch, fI)
+        {
+            derivatives_[nPassedFaces + fI]
+                = wallFaceSensNormalPtr_()[patchI][fI];
+        }
+        nPassedFaces += patch.size();
+    }
+
+    // Write sens fields
+    write(type());
+
+    return (derivatives_);
+}
+
+
+autoPtr<adjointEikonalSolver>& sensitivitySurface::getAdjointEikonalSolver()
+{
+    return eikonalSolver_;
+}
+
+
+void sensitivitySurface::write(const word& baseName)
+{
+    // Determine suffix for fields holding the sens
+    if (includeMeshMovement_)
+    {
+        surfaceFieldSuffix_ = word("ESI");
+    }
+    else
+    {
+        surfaceFieldSuffix_ = word("SI");
+    }
+    adjointSensitivity::write();
+
+    if (writeGeometricInfo_)
+    {
+        nfOnPatchPtr_().write();
+        SfOnPatchPtr_().write();
+        CfOnPatchPtr_().write();
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+} // End namespace incompressible
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressible.H
new file mode 100644
index 0000000000000000000000000000000000000000..074b94436774eb6d602fc6ce4f28c1dce75eae64
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressible.H
@@ -0,0 +1,179 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::sensitivitySurface
+
+Description
+    Calculation of adjoint based sensitivities at wall faces
+
+SourceFiles
+    sensitivitySurface.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef sensitivitySurfaceIncompressible_H
+#define sensitivitySurfaceIncompressible_H
+
+#include "adjointSensitivityIncompressible.H"
+#include "adjointEikonalSolverIncompressible.H"
+#include "adjointMeshMovementSolverIncompressible.H"
+#include "deltaBoundary.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+/*---------------------------------------------------------------------------*\
+                     Class sensitivitySurface Declaration
+\*---------------------------------------------------------------------------*/
+
+class sensitivitySurface
+:
+    public adjointSensitivity
+{
+protected:
+
+    // Protected data
+
+        //- Scalar normal sens
+        scalarField derivatives_;
+
+        //- Include surface area in sens computation
+        bool includeSurfaceArea_;
+
+        //- Include the adjoint pressure term in sens computation
+        bool includePressureTerm_;
+
+        //- Include the term containing the grad of the stress at the boundary
+        bool includeGradStressTerm_;
+
+        //- Include the transpose part of the adjoint stresses
+        bool includeTransposeStresses_;
+
+        //- Include the term from the deviatoric part of the stresses
+        bool includeDivTerm_;
+
+        //- Include distance variation in sens computation
+        bool includeDistance_;
+
+        //- Include mesh movement variation in sens computation
+        bool includeMeshMovement_;
+
+        //- Include terms directly emerging from the objective function
+        bool includeObjective_;
+
+        //- Write geometric info for use by external programs
+        bool writeGeometricInfo_;
+
+        autoPtr<adjointEikonalSolver> eikonalSolver_;
+
+        autoPtr<adjointMeshMovementSolver> meshMovementSolver_;
+
+        // Export face normal and face centre for use by external users
+        autoPtr<volVectorField> nfOnPatchPtr_;
+        autoPtr<volVectorField> SfOnPatchPtr_;
+        autoPtr<volVectorField> CfOnPatchPtr_;
+
+
+    // Protected Member Functions
+
+        //- Read controls and update solver pointers if necessary
+        void read();
+
+        //- Add sensitivities from dSd/db and dnf/db computed at points and
+        //- mapped to faces
+        void addGeometricSens();
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        sensitivitySurface(const sensitivitySurface&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const sensitivitySurface&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("surface");
+
+
+    // Constructors
+
+        //- Construct from components
+        sensitivitySurface
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            incompressibleVars& primalVars,
+            incompressibleAdjointVars& adjointVars,
+            objectiveManager& objectiveManager,
+            fv::optionAdjointList& fvOptionsAdjoint
+        );
+
+
+    //- Destructor
+    virtual ~sensitivitySurface() = default;
+
+
+    // Member Functions
+
+       //- Read dict if changed
+       virtual bool readDict(const dictionary& dict);
+
+       //- Compute the number of faces on sensitivityPatchIDs_
+       void computeDerivativesSize();
+
+       //- Calculates sensitivities at wall surface points
+       const scalarField& calculateSensitivities();
+
+       //- Get adjoint eikonal solver
+       autoPtr<adjointEikonalSolver>& getAdjointEikonalSolver();
+
+       virtual void write(const word& baseName = word::null);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.C
new file mode 100644
index 0000000000000000000000000000000000000000..c19fc830a046d5dd98e1507081f1a9ad01f39a5b
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.C
@@ -0,0 +1,674 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "sensitivitySurfacePointsIncompressible.H"
+#include "addToRunTimeSelectionTable.H"
+#include "syncTools.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(sensitivitySurfacePoints, 0);
+addToRunTimeSelectionTable
+(
+    adjointSensitivity,
+    sensitivitySurfacePoints,
+    dictionary
+);
+
+// * * * * * * * * * * * Private  Member Functions  * * * * * * * * * * * * * //
+
+void sensitivitySurfacePoints::read()
+{
+    includeSurfaceArea_ =
+        dict().lookupOrDefault<bool>("includeSurfaceArea", false);
+    includePressureTerm_ =
+        dict().lookupOrDefault<bool>("includePressure", true);
+    includeGradStressTerm_ =
+        dict().lookupOrDefault<bool>("includeGradStressTerm", true);
+    includeTransposeStresses_ =
+        dict().lookupOrDefault<bool>("includeTransposeStresses", true);
+    includeDivTerm_ =
+        dict().lookupOrDefault<bool>("includeDivTerm", false);
+    includeDistance_ =
+        dict().lookupOrDefault<bool>
+        (
+            "includeDistance",
+            adjointVars_.adjointTurbulence().ref().includeDistance()
+        );
+    includeMeshMovement_ =
+        dict().lookupOrDefault<bool>("includeMeshMovement", true);
+    includeObjective_ =
+        dict().lookupOrDefault<bool>("includeObjectiveContribution", true);
+
+    // Allocate new solvers if necessary
+    if (includeDistance_ && eikonalSolver_.empty())
+    {
+        eikonalSolver_.reset
+        (
+            new adjointEikonalSolver
+            (
+                mesh_,
+                dict(),
+                primalVars_.RASModelVariables(),
+                adjointVars_.adjointTurbulence(),
+                sensitivityPatchIDs_
+            )
+        );
+    }
+
+    if (includeMeshMovement_ && meshMovementSolver_.empty())
+    {
+        meshMovementSolver_.reset
+        (
+            new adjointMeshMovementSolver
+            (
+                mesh_,
+                dict(),
+                *this,
+                sensitivityPatchIDs_,
+                eikonalSolver_
+            )
+        );
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+sensitivitySurfacePoints::sensitivitySurfacePoints
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    incompressibleVars& primalVars,
+    incompressibleAdjointVars& adjointVars,
+    objectiveManager& objectiveManager,
+    fv::optionAdjointList& fvOptionsAdjoint
+)
+:
+    adjointSensitivity
+    (
+        mesh,
+        dict,
+        primalVars,
+        adjointVars,
+        objectiveManager,
+        fvOptionsAdjoint
+    ),
+    derivatives_(0),
+    includeSurfaceArea_(false),
+    includePressureTerm_(false),
+    includeGradStressTerm_(false),
+    includeTransposeStresses_(false),
+    includeDivTerm_(false),
+    includeDistance_(false),
+    includeMeshMovement_(false),
+    includeObjective_(false),
+    eikonalSolver_(nullptr),
+    meshMovementSolver_(nullptr)
+{
+    read();
+
+    // Allocate boundary field pointer
+    wallPointSensVecPtr_.reset(createZeroBoundaryPointFieldPtr<vector>(mesh_));
+    wallPointSensNormalPtr_.reset
+    (
+        createZeroBoundaryPointFieldPtr<scalar>(mesh_)
+    );
+    wallPointSensNormalVecPtr_.reset
+    (
+        createZeroBoundaryPointFieldPtr<vector>(mesh_)
+    );
+
+    // Allocate appropriate space for sensitivities
+    label nTotalPoints(0);
+    for (const label patchI : sensitivityPatchIDs_)
+    {
+        label nPoints = mesh_.boundaryMesh()[patchI].nPoints();
+        nTotalPoints += returnReduce(nPoints, sumOp<label>());
+    }
+
+    // Derivatives for all (x,y,z) components of the displacement are kept
+    derivatives_ = scalarField(3*nTotalPoints, Zero);
+};
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool sensitivitySurfacePoints::readDict(const dictionary& dict)
+{
+    if (sensitivity::readDict(dict))
+    {
+        if (eikonalSolver_.valid())
+        {
+            eikonalSolver_().readDict(dict);
+        }
+
+        if (meshMovementSolver_.valid())
+        {
+            meshMovementSolver_().readDict(dict);
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+
+const scalarField& sensitivitySurfacePoints::calculateSensitivities()
+{
+    // Grab references
+    const volScalarField& p = primalVars_.p();
+    const volVectorField& U = primalVars_.U();
+
+    const volScalarField& pa = adjointVars_.pa();
+    const volVectorField& Ua = adjointVars_.Ua();
+    autoPtr<incompressibleAdjoint::adjointRASModel>& adjointTurbulence =
+        adjointVars_.adjointTurbulence();
+
+    // Restore to zero
+    derivatives_ = Zero;
+    forAll(mesh_.boundary(), patchI)
+    {
+        wallPointSensVecPtr_()[patchI] = vector::zero;
+        wallPointSensNormalPtr_()[patchI] = Zero;
+        wallPointSensNormalVecPtr_()[patchI] = vector::zero;
+    }
+
+    Info<< "    Calculating auxilary quantities " << endl;
+
+    // Fields needed to calculate adjoint sensitivities
+    volScalarField nuEff(adjointTurbulence->nuEff());
+    volTensorField gradUa(fvc::grad(Ua));
+    volTensorField gradU(fvc::grad(U));
+
+    // Explicitly correct the boundary gradient to get rid of the
+    // tangential component
+    forAll(mesh_.boundary(), patchI)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        if (isA<wallFvPatch>(patch))
+        {
+            tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
+            const vectorField& nf = tnf();
+            gradU.boundaryFieldRef()[patchI] =
+                nf*U.boundaryField()[patchI].snGrad();
+        }
+    }
+
+    // Auxiliary terms
+    volVectorField gradp(fvc::grad(p));
+    volTensorField stress(nuEff*(gradU + T(gradU)));
+    autoPtr<volVectorField> stressXPtr
+    (
+        createZeroFieldPtr<vector>(mesh_, "stressX", stress.dimensions())
+    );
+    autoPtr<volVectorField> stressYPtr
+    (
+        createZeroFieldPtr<vector>(mesh_, "stressY", stress.dimensions())
+    );
+    autoPtr<volVectorField> stressZPtr
+    (
+        createZeroFieldPtr<vector>(mesh_, "stressZ", stress.dimensions())
+    );
+
+    stressXPtr().replace(0, stress.component(0));
+    stressXPtr().replace(1, stress.component(1));
+    stressXPtr().replace(2, stress.component(2));
+
+    stressYPtr().replace(0, stress.component(3));
+    stressYPtr().replace(1, stress.component(4));
+    stressYPtr().replace(2, stress.component(5));
+
+    stressZPtr().replace(0, stress.component(6));
+    stressZPtr().replace(1, stress.component(7));
+    stressZPtr().replace(2, stress.component(8));
+
+    volTensorField gradStressX(fvc::grad(stressXPtr()));
+    volTensorField gradStressY(fvc::grad(stressYPtr()));
+    volTensorField gradStressZ(fvc::grad(stressZPtr()));
+
+    // solve extra equations if necessary
+    autoPtr<boundaryVectorField> distanceSensPtr(nullptr);
+    if (includeDistance_)
+    {
+        eikonalSolver_->solve();
+        distanceSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
+        const boundaryVectorField& sens =
+            eikonalSolver_->distanceSensitivities();
+        for (const label patchI : sensitivityPatchIDs_)
+        {
+            distanceSensPtr()[patchI] = sens[patchI];
+        }
+    }
+
+    autoPtr<boundaryVectorField> meshMovementSensPtr(nullptr);
+    if (includeMeshMovement_)
+    {
+        meshMovementSolver_->solve();
+        meshMovementSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
+        const boundaryVectorField& sens =
+            meshMovementSolver_->meshMovementSensitivities();
+        for (const label patchI : sensitivityPatchIDs_)
+        {
+            meshMovementSensPtr()[patchI] = sens[patchI];
+        }
+    }
+
+    // Terms from the adjoint turbulence model
+    const boundaryVectorField& adjointTMsensitivities =
+        adjointTurbulence->wallShapeSensitivities();
+
+    // Objective references
+    PtrList<objective>& functions(objectiveManager_.getObjectiveFunctions());
+
+    Info<< "    Calculating adjoint sensitivity. " << endl;
+
+    // The face-based part of the sensitivities, i.e. terms that multiply
+    // dxFace/dxPoint. Sensitivities DO include locale surface area, to get
+    // the correct weighting from the contributions of various faces.
+    // Normalized at the end.
+    autoPtr<boundaryVectorField> wallFaceSens
+    (
+        createZeroBoundaryPtr<vector>(mesh_)
+    );
+
+    for (const label patchI : sensitivityPatchIDs_)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        tmp<vectorField> tnf = patch.nf();
+        const vectorField& nf = tnf();
+        const scalarField& magSf = patch.magSf();
+
+        // Adjoint stress term
+        // vectorField stressTerm
+        //     (
+        //        -(nf & DUa.boundaryField()[patchI])
+        //        *nuEff.boundaryField()[patchI]
+        //       & gradU.boundaryField()[patchI].T();
+        //     )
+
+        vectorField stressTerm
+        (
+          - (
+                Ua.boundaryField()[patchI].snGrad()
+              & U.boundaryField()[patchI].snGrad()
+            )
+          * nuEff.boundaryField()[patchI]
+          * nf
+        );
+
+        vectorField gradStressTerm(patch.size(), vector::zero);
+        if (includeGradStressTerm_)
+        {
+            // Terms corresponding to contributions from converting delta to
+            // thetas are added through the corresponding adjoint boundary
+            // conditions instead of grabing contributions from the objective
+            // function. Useful to have a unified formulation for low- and
+            // high-re meshes
+            const fvPatchVectorField& Uab = Ua.boundaryField()[patchI];
+            gradStressTerm = (-((Uab & nf)*gradp.boundaryField()[patchI]));
+            gradStressTerm +=
+            (
+                Uab.component(0)*gradStressX.boundaryField()[patchI]
+              + Uab.component(1)*gradStressY.boundaryField()[patchI]
+              + Uab.component(2)*gradStressZ.boundaryField()[patchI]
+            ) & nf;
+        }
+
+        if (includeTransposeStresses_)
+        {
+            stressTerm -=
+                nuEff.boundaryField()[patchI]
+               *(
+                    // Note: in case of laminar or low-Re flows,
+                    // includes a spurious tangential gradUa component
+                    // (gradUa.boundaryField()[patchI] & nf)
+                    ((Ua.boundaryField()[patchI].snGrad() &nf)*nf)
+                  & U.boundaryField()[patchI].snGrad()
+                )
+              * nf;
+        }
+
+        if (includeDivTerm_)
+        {
+            stressTerm +=
+                scalar(1./3.)*nuEff.boundaryField()[patchI]
+              * (
+                    ((Ua.boundaryField()[patchI].snGrad() &nf)*nf)
+                  & U.boundaryField()[patchI].snGrad()
+                )
+               *nf;
+        }
+
+        // Adjoint pressure terms
+        vectorField pressureTerm(patch.size(), vector::zero);
+        if (includePressureTerm_)
+        {
+            pressureTerm =
+            (
+                (nf * pa.boundaryField()[patchI])
+              & U.boundaryField()[patchI].snGrad()
+            )
+           *nf;
+        }
+
+        // Distance related terms
+        vectorField distanceTerm(pressureTerm.size(), vector::zero);
+        if (includeDistance_)
+        {
+            distanceTerm = distanceSensPtr()[patchI];
+        }
+
+        // Mesh movement related terms
+        vectorField meshMovementTerm(pressureTerm.size(), vector::zero);
+        if (includeMeshMovement_)
+        {
+            meshMovementTerm = meshMovementSensPtr()[patchI];
+        }
+
+
+        vectorField dxdbMultiplierTot
+        (
+            mesh_.boundary()[patchI].size(), vector::zero
+        );
+        if (includeObjective_)
+        {
+            // Term from objectives multiplying dxdb
+            forAll(functions, funcI)
+            {
+                dxdbMultiplierTot +=
+                    functions[funcI].weight()
+                  * functions[funcI].dxdbDirectMultiplier(patchI);
+            }
+        }
+
+        // Fill in dxFace/dxPoint multiplier.
+        // Missing geometric contributions which are directly computed on the
+        // points
+        wallFaceSens()[patchI] =
+            stressTerm
+          + gradStressTerm
+          + pressureTerm
+          + distanceTerm
+          + meshMovementTerm
+          + adjointTMsensitivities[patchI]
+          + dxdbMultiplierTot;
+        wallFaceSens()[patchI] *= magSf;
+    }
+
+    // polyPatch::pointNormals will give the wrong result for points
+    // belonging to multiple patches or patch-processorPatch intersections.
+    // Keeping a mesh-wide field to allow easy reduction using syncTools.
+    // A bit expensive? Better way?
+    vectorField pointNormals(mesh_.nPoints(), vector::zero);
+    scalarField pointMagSf(mesh_.nPoints(), Zero);
+
+    // Geometric (or "direct") sensitivities are better computed directly on
+    // the points. Compute them and add the ones that depend on dxFace/dxPoint
+    for (const label patchI : sensitivityPatchIDs_)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        const scalarField& magSf = patch.magSf();
+        vectorField nf(patch.nf());
+
+        // Point sens result for patch
+        vectorField& pointPatchSens = wallPointSensVecPtr_()[patchI];
+
+        // Face sens for patch
+        const vectorField& facePatchSens = wallFaceSens()[patchI];
+
+        vectorField dSdbMultiplierTot(patch.size(), vector::zero);
+        vectorField dndbMultiplierTot(patch.size(), vector::zero);
+        forAll(functions, funcI)
+        {
+            dSdbMultiplierTot +=
+                functions[funcI].weight() //includes surface by itself
+               *functions[funcI].dSdbMultiplier(patchI);
+            dndbMultiplierTot +=
+                functions[funcI].weight()
+               *functions[funcI].dndbMultiplier(patchI)
+               *magSf;
+        }
+
+        // Correspondance of local point addressing to global point addressing
+        const labelList& meshPoints = patch.patch().meshPoints();
+
+        // List with mesh faces. Global addressing
+        const faceList& faces = mesh_.faces();
+
+        // Each local patch point belongs to these local patch faces
+        // (local numbering)
+        const labelListList& patchPointFaces = patch.patch().pointFaces();
+
+        // Index of first face in patch
+        const label patchStartIndex = patch.start();
+
+        // Geometry differentiation engine
+        deltaBoundary dBoundary(mesh_);
+
+        // Loop over patch points.
+        // Collect contributions from each boundary face this point belongs to
+        forAll(meshPoints, ppI)
+        {
+            const labelList& pointFaces = patchPointFaces[ppI];
+            forAll(pointFaces, pfI)
+            {
+                label localFaceIndex = pointFaces[pfI];
+                label globalFaceIndex = patchStartIndex + localFaceIndex;
+                const face& faceI = faces[globalFaceIndex];
+
+                // Point coordinates. All indices in global numbering
+                pointField p(faceI.points(mesh_.points()));
+                tensorField p_d(faceI.size(), tensor::zero);
+                forAll(faceI, facePointI)
+                {
+                    if (faceI[facePointI] == meshPoints[ppI])
+                    {
+                        p_d[facePointI] = tensor::I;
+                    }
+                }
+                tensorField deltaNormals =
+                    dBoundary.makeFaceCentresAndAreas_d(p, p_d);
+
+                // Element [0] is the variation in the face center
+                // (dxFace/dxPoint)
+                const tensor& deltaCf = deltaNormals[0];
+                pointPatchSens[ppI] += facePatchSens[localFaceIndex] & deltaCf;
+
+                // Term multiplying d(Sf)/d(point displacement) and
+                // d(nf)/d(point displacement)
+                //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                if (includeObjective_)
+                {
+                    // Element [1] is the variation in the (dimensional) normal
+                    const tensor& deltaSf = deltaNormals[1];
+                    pointPatchSens[ppI] +=
+                        dSdbMultiplierTot[localFaceIndex] & deltaSf;
+
+                    // Element [2] is the variation in the unit normal
+                    const tensor& deltaNf = deltaNormals[2];
+                    pointPatchSens[ppI] +=
+                        dndbMultiplierTot[localFaceIndex] & deltaNf;
+                }
+
+                // Accumulate information for point normals
+                pointNormals[meshPoints[ppI]] += nf[localFaceIndex];
+                pointMagSf[meshPoints[ppI]] += magSf[localFaceIndex];
+            }
+        }
+    }
+
+    // Do parallel communications to avoid wrong values at processor boundaries
+    // - global field for accumulation
+    vectorField pointSensGlobal(mesh_.nPoints(), vector::zero);
+    for (const label patchI : sensitivityPatchIDs_)
+    {
+        const labelList& meshPoints = mesh_.boundaryMesh()[patchI].meshPoints();
+        forAll(meshPoints, ppI)
+        {
+            const label globaPointI = meshPoints[ppI];
+            pointSensGlobal[globaPointI] +=
+                wallPointSensVecPtr_()[patchI][ppI];
+        }
+    }
+
+    // Accumulate dJ/dx_i, pointNormals and pointFaces number
+    syncTools::syncPointList
+    (
+        mesh_,
+        pointSensGlobal,
+        plusEqOp<vector>(),
+        vector::zero
+    );
+    syncTools::syncPointList
+    (
+        mesh_,
+        pointNormals,
+        plusEqOp<vector>(),
+        vector::zero
+    );
+    syncTools::syncPointList
+    (
+        mesh_,
+        pointMagSf,
+        plusEqOp<scalar>(),
+        scalar(0)
+    );
+
+    // Transfer back to local fields
+    for (const label patchI : sensitivityPatchIDs_)
+    {
+        const labelList& meshPoints =
+            mesh_.boundaryMesh()[patchI].meshPoints();
+        wallPointSensVecPtr_()[patchI].map(pointSensGlobal, meshPoints);
+    }
+
+    // Compute normal sens and append to return field
+    label nPassedDVs(0);
+    for (const label patchI : sensitivityPatchIDs_)
+    {
+        const polyPatch& patch = mesh_.boundaryMesh()[patchI];
+        List<scalarField> procPatchSens(Pstream::nProcs());
+        //if (patch.size()>0)
+        {
+            const labelList& meshPoints = patch.meshPoints();
+
+            // avoid storing unit point normals in the global list since we
+            // might divide multiple times with the number of faces belonging
+            // to the point. Instead do the division locally, per patch use
+            vectorField patchPointNormals(pointNormals, meshPoints);
+            patchPointNormals /= mag(patchPointNormals) + VSMALL;
+            if (!includeSurfaceArea_)
+            {
+                wallPointSensVecPtr_()[patchI] /=
+                    scalarField(pointMagSf, meshPoints);
+            }
+            wallPointSensNormalPtr_()[patchI] =
+                wallPointSensVecPtr_()[patchI]
+              & patchPointNormals;
+            wallPointSensNormalVecPtr_()[patchI] =
+                wallPointSensNormalPtr_()[patchI]
+               *patchPointNormals;
+
+            // 1. Gather sens from all processors for this patch and communicate
+            // them back. Potentially large memory overhead but the rest of the
+            // code structure assumes that all procs know all sensitivity
+            // derivatives
+            //
+            // 2. Transfer vectorial sensitivities to scalarField.
+            // Needed since the normal point vector is wrongly computed at patch
+            // boundaries and cannot be used to reconstruct a vectorial movement
+            // from just its normal component
+            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+            procPatchSens[Pstream::myProcNo()].setSize
+            (
+                3*wallPointSensNormalVecPtr_()[patchI].size()
+            );
+            scalarField& patchScalarSens = procPatchSens[Pstream::myProcNo()];
+            forAll(wallPointSensNormalVecPtr_()[patchI], ptI)
+            {
+                patchScalarSens[3*ptI] =
+                    wallPointSensNormalVecPtr_()[patchI][ptI].x();
+                patchScalarSens[3*ptI + 1] =
+                    wallPointSensNormalVecPtr_()[patchI][ptI].y();
+                patchScalarSens[3*ptI + 2] =
+                    wallPointSensNormalVecPtr_()[patchI][ptI].z();
+            }
+            Pstream::gatherList(procPatchSens);
+            Pstream::scatterList(procPatchSens);
+
+            forAll(procPatchSens, procI)
+            {
+                const scalarField& procSens = procPatchSens[procI];
+                forAll(procSens, dvI)
+                {
+                    derivatives_[nPassedDVs + dvI] = procSens[dvI];
+                }
+                nPassedDVs += procSens.size();
+            }
+        }
+    }
+
+    // Write sens fields
+    write(type());
+
+    return (derivatives_);
+}
+
+
+void sensitivitySurfacePoints::write(const word& baseName)
+{
+    //determine suffix for fields holding the sens
+    if (includeMeshMovement_)
+    {
+        surfaceFieldSuffix_ = "ESI";
+    }
+    else
+    {
+        surfaceFieldSuffix_ = "SI";
+    }
+    adjointSensitivity::write();
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+} // End namespace incompressible
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.H
new file mode 100644
index 0000000000000000000000000000000000000000..404b0f59a208599d7ce00566bce9288e825cb62c
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.H
@@ -0,0 +1,161 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::sensitivitySurfacePoints
+
+Description
+    Calculation of adjoint based sensitivities at wall points
+
+SourceFiles
+    sensitivitySurfacePoints.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef sensitivitySurfacePointsIncompressible_H
+#define sensitivitySurfacePointsIncompressible_H
+
+#include "adjointSensitivityIncompressible.H"
+#include "adjointEikonalSolverIncompressible.H"
+#include "adjointMeshMovementSolverIncompressible.H"
+#include "deltaBoundary.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+/*---------------------------------------------------------------------------*\
+                  Class sensitivitySurfacePoints Declaration
+\*---------------------------------------------------------------------------*/
+
+class sensitivitySurfacePoints
+:
+    public adjointSensitivity
+{
+protected:
+
+    // Protected data
+
+        //- Scalar normal sens
+        scalarField derivatives_;
+
+        //- Include surface area in sens computation
+        bool includeSurfaceArea_;
+
+        //- Include the adjoint pressure term in sens computation
+        bool includePressureTerm_;
+
+        //- Include the term containing the grad of the stress at the boundary
+        bool includeGradStressTerm_;
+
+        //- Include the transpose part of the adjoint stresses
+        bool includeTransposeStresses_;
+
+        //- Include the term from the deviatoric part of the stresses
+        bool includeDivTerm_;
+
+        //- Include distance variation in sens computation
+        bool includeDistance_;
+
+        //- Include mesh movement variation in sens computation
+        bool includeMeshMovement_;
+
+        //- Include terms directly emerging from the objective function
+        bool includeObjective_;
+
+        autoPtr<adjointEikonalSolver> eikonalSolver_;
+
+        autoPtr<adjointMeshMovementSolver> meshMovementSolver_;
+
+
+    // Protected Member Functions
+
+        //- Read controls and update solver pointers if necessary
+        void read();
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        sensitivitySurfacePoints(const sensitivitySurfacePoints&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const sensitivitySurfacePoints&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("surfacePoints");
+
+
+    // Constructors
+
+        //- Construct from components
+        sensitivitySurfacePoints
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            incompressibleVars& primalVars,
+            incompressibleAdjointVars& adjointVars,
+            objectiveManager& objectiveManager,
+            fv::optionAdjointList& fvOptionsAdjoint
+        );
+
+
+    //- Destructor
+    virtual ~sensitivitySurfacePoints() = default;
+
+
+    // Member Functions
+
+       //- Read dict if changed
+       virtual bool readDict(const dictionary& dict);
+
+       //- Calculates sensitivities at wall surface points
+       const scalarField& calculateSensitivities();
+
+       virtual void write(const word& baseName = word::null);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.C
new file mode 100644
index 0000000000000000000000000000000000000000..61e398eb953f1032e9e7150e2185120c30914b18
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.C
@@ -0,0 +1,358 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "runTimeSelectionTables.H"
+#include "sensitivity.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(sensitivity, 0);
+}
+
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+void Foam::sensitivity::writeFaceBasedSens() const
+{
+    const word suffix(adjointSolverName_ + surfaceFieldSuffix_);
+
+    // Wall face sensitivity projected to normal
+    if (wallFaceSensNormalPtr_.valid())
+    {
+        constructAndWriteSensitivityField<scalar>
+        (
+            wallFaceSensNormalPtr_,
+            "faceSensNormal" + suffix
+        );
+    }
+
+    if (writeAllSurfaceFiles_)
+    {
+        // Wall face sensitivity vectors
+        if (wallFaceSensVecPtr_.valid())
+        {
+            constructAndWriteSensitivityField<vector>
+            (
+                wallFaceSensVecPtr_,
+                "faceSensVec" + suffix
+            );
+        }
+
+        // Normal sens as vectors
+        if (wallFaceSensNormalVecPtr_.valid())
+        {
+            constructAndWriteSensitivityField<vector>
+            (
+                wallFaceSensNormalVecPtr_,
+                "faceSensNormalVec" + suffix
+            );
+        }
+    }
+}
+
+
+void Foam::sensitivity::writePointBasedSens() const
+{
+    const word suffix(adjointSolverName_ + surfaceFieldSuffix_);
+
+    // Wall point sensitivity projected to normal
+    if (wallPointSensNormalPtr_.valid())
+    {
+        constructAndWriteSensitivtyPointField<scalar>
+        (
+            wallPointSensNormalPtr_,
+            "pointSensNormal" + suffix
+        );
+    }
+
+    // Write point-based sensitivities, if present
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    if (writeAllSurfaceFiles_)
+    {
+        // Wall point sensitivity vectors
+        if (wallPointSensVecPtr_.valid())
+        {
+            constructAndWriteSensitivtyPointField<vector>
+            (
+                wallPointSensVecPtr_,
+                "pointSensVec" + suffix
+            );
+        }
+
+        // Normal point as vectors
+        if (wallPointSensNormalVecPtr_.valid())
+        {
+            constructAndWriteSensitivtyPointField<vector>
+            (
+                wallPointSensNormalVecPtr_,
+                "pointSensNormalVec" + suffix
+            );
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::sensitivity::sensitivity
+(
+    const fvMesh& mesh,
+    const dictionary& dict,
+    const word& adjointSolverName
+)
+:
+    mesh_(mesh),
+    dict_(dict),
+    sensitivityPatchIDs_(0),
+    adjointSolverName_(adjointSolverName),
+    surfaceFieldSuffix_(word::null),
+    writeAllSurfaceFiles_
+    (
+        dict.lookupOrDefault<bool>
+        (
+            "writeAllSurfaceFiles",
+            false
+        )
+    ),
+
+    wallFaceSensVecPtr_(nullptr),
+    wallFaceSensNormalPtr_(nullptr),
+    wallFaceSensNormalVecPtr_(nullptr),
+
+    wallPointSensVecPtr_(nullptr),
+    wallPointSensNormalPtr_(nullptr),
+    wallPointSensNormalVecPtr_(nullptr),
+
+    fieldSensPtr_(nullptr)
+{
+    labelHashSet patches
+    (
+        mesh_.boundaryMesh().patchSet(dict.get<wordRes>("patches"))
+    );
+
+    if (patches.empty())
+    {
+        WarningInFunction
+            << "There is no patch on which to compute sensitivities. "
+            << "Check optimisationDict" << nl
+            << endl;
+    }
+    sensitivityPatchIDs_ = patches.toc();
+};
+
+
+// * * * * * * * * * * * * * * *  Member Functions   * * * * * * * * * * * * //
+
+const Foam::dictionary& Foam::sensitivity::dict() const
+{
+    return dict_;
+}
+
+
+bool Foam::sensitivity::readDict(const dictionary& dict)
+{
+    dict_ = dict;
+
+    return true;
+}
+
+
+const Foam::labelList& Foam::sensitivity::sensitivityPatchIDs() const
+{
+    return sensitivityPatchIDs_;
+}
+
+
+void Foam::sensitivity::setSensitivityPatchIDs(const labelList& sensPatchIDs)
+{
+    sensitivityPatchIDs_ = sensPatchIDs;
+}
+
+
+void Foam::sensitivity::computeDerivativesSize()
+{
+    // Does nothing
+}
+
+
+void Foam::sensitivity::write(const word& baseName)
+{
+    writeFaceBasedSens();
+
+    writePointBasedSens();
+
+    if (fieldSensPtr_.valid())
+    {
+        fieldSensPtr_().write();
+    }
+}
+
+
+Foam::tmp<Foam::volVectorField> Foam::sensitivity::getWallFaceSensVec()
+{
+    if (wallFaceSensVecPtr_.valid())
+    {
+        return
+            constructVolSensitivtyField<vector>
+            (
+                wallFaceSensVecPtr_,
+                "faceSensVec" + adjointSolverName_
+            );
+    }
+    else
+    {
+        WarningInFunction
+            << " no faceSensVec boundary field. Returning zero" << endl;
+
+        return
+            tmp<volVectorField>
+            (
+                createZeroFieldPtr<vector>
+                (
+                    mesh_,
+                    "faceSensVec" + adjointSolverName_,
+                    dimless
+                ).ptr()
+            );
+    }
+}
+
+
+Foam::tmp<Foam::volScalarField> Foam::sensitivity::getWallFaceSensNormal()
+{
+    if (wallFaceSensNormalPtr_.valid())
+    {
+        return
+            constructVolSensitivtyField<scalar>
+            (
+                wallFaceSensNormalPtr_,
+                "faceSensNormal" + adjointSolverName_
+            );
+    }
+    else
+    {
+        WarningInFunction
+            << " no wallFaceSensNormal boundary field. Returning zero" << endl;
+
+        return
+            tmp<volScalarField>
+            (
+                createZeroFieldPtr<scalar>
+                (
+                    mesh_,
+                    "faceSensNormal" + adjointSolverName_, dimless
+                ).ptr()
+            );
+    }
+}
+
+
+Foam::tmp<Foam::volVectorField> Foam::sensitivity::getWallFaceSensNormalVec()
+{
+    if (wallFaceSensNormalVecPtr_.valid())
+    {
+        return
+            constructVolSensitivtyField<vector>
+            (
+                wallFaceSensNormalVecPtr_,
+                "faceSensNormalVec" + adjointSolverName_
+            );
+    }
+    else
+    {
+        WarningInFunction
+            << " no wallFaceSensNormalVec boundary field. Returning zero"
+            << endl;
+
+        return
+            tmp<volVectorField>
+            (
+                createZeroFieldPtr<vector>
+                (
+                    mesh_,
+                    "faceSensNormalVec" + adjointSolverName_,
+                    dimless
+                ).ptr()
+            );
+    }
+}
+
+
+Foam::tmp<Foam::pointVectorField> Foam::sensitivity::getWallPointSensVec()
+{
+    tmp<volVectorField> tWallFaceSensVec = getWallFaceSensVec();
+    volPointInterpolation volPointInter(mesh_);
+
+    return (volPointInter.interpolate(tWallFaceSensVec));
+}
+
+
+Foam::tmp<Foam::pointScalarField> Foam::sensitivity::getWallPointSensNormal()
+{
+    tmp<volScalarField> tWallFaceSensNormal = getWallFaceSensNormal();
+    volPointInterpolation volPointInter(mesh_);
+
+    return (volPointInter.interpolate(tWallFaceSensNormal));
+}
+
+
+Foam::tmp<Foam::pointVectorField>
+Foam::sensitivity::getWallPointSensNormalVec()
+{
+    tmp<volVectorField> tWallFaceSensNormalVec = getWallFaceSensNormalVec();
+    volPointInterpolation volPointInter(mesh_);
+
+    return (volPointInter.interpolate(tWallFaceSensNormalVec));
+}
+
+
+const Foam::boundaryVectorField&
+Foam::sensitivity::getWallFaceSensVecBoundary() const
+{
+    return wallFaceSensVecPtr_();
+}
+
+
+const Foam::boundaryScalarField&
+Foam::sensitivity::getWallFaceSensNormalBoundary() const
+{
+    return wallFaceSensNormalPtr_();
+}
+
+
+const Foam::boundaryVectorField&
+Foam::sensitivity::getWallFaceSensNormalVecBoundary() const
+{
+    return wallFaceSensNormalVecPtr_();
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.H
new file mode 100644
index 0000000000000000000000000000000000000000..ee9dae70b4b097ce91925e19bfac1e521bec5935
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.H
@@ -0,0 +1,258 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::sensitivity
+
+Description
+    Abstract base class for adjoint sensitivities
+
+SourceFiles
+    sensitivity.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef sensitivity_H
+#define sensitivity_H
+
+#include "volFields.H"
+#include "surfaceFields.H"
+#include "dictionary.H"
+#include "volPointInterpolation.H"
+
+#include "pointMesh.H"
+#include "pointPatchField.H"
+#include "pointPatchFieldsFwd.H"
+#include "fixedValuePointPatchField.H"
+#include "boundaryFieldsFwd.H"
+#include "createZeroField.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                         Class sensitivity Declaration
+\*---------------------------------------------------------------------------*/
+
+class sensitivity
+{
+protected:
+
+    // Protected data
+
+        const fvMesh& mesh_;
+        dictionary dict_;
+
+        // Cleaner option to go for a labelHashSet. Kept this way for
+        // compatibility
+        labelList sensitivityPatchIDs_;
+        word adjointSolverName_;
+        word surfaceFieldSuffix_;
+        bool writeAllSurfaceFiles_;
+
+        // autoPtrs for fields holding sensitivities.
+        // Not all of them are required for each case
+
+        // Boundary sensitivities at faces. Shape opt & flow control
+        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+        //- Wall face sens w.r.t. (x,y.z)
+        autoPtr<boundaryVectorField> wallFaceSensVecPtr_;
+
+        //- Wall face sens projected to normal
+        autoPtr<boundaryScalarField> wallFaceSensNormalPtr_;
+
+        //- Normal sens as vectors
+        autoPtr<boundaryVectorField> wallFaceSensNormalVecPtr_;
+
+        // Boundary sensitivities at points. Shape opt
+        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+        //- Wall point sens w.r.t. (x,y.z)
+        autoPtr<pointBoundaryVectorField> wallPointSensVecPtr_;
+
+        //- Wall point sens projected to normal
+        autoPtr<pointBoundaryScalarField> wallPointSensNormalPtr_;
+
+        //- Normal sens as vectors
+        autoPtr<pointBoundaryVectorField> wallPointSensNormalVecPtr_;
+
+        //field sensitivities. Topology optimisation
+        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        autoPtr<volScalarField> fieldSensPtr_;
+
+
+    // Protected Member Functions
+
+        //- Constructs volField based on boundaryField and writes it
+        template<class Type>
+        void constructAndWriteSensitivityField
+        (
+            const autoPtr
+            <
+                typename GeometricField<Type, fvPatchField, volMesh>::Boundary
+            >& sensFieldPtr,
+            const word& name
+        ) const;
+
+        //- Constructs pointField based on boundaryField and writes it
+        template<class Type>
+        void constructAndWriteSensitivtyPointField
+        (
+            const autoPtr<List<Field<Type>>>& sensFieldPtr,
+            const word& name
+        ) const;
+
+        //- Constructs volField based on boundaryField and writes it
+        template<class Type>
+        tmp<GeometricField<Type, fvPatchField, volMesh>>
+        constructVolSensitivtyField
+        (
+            const autoPtr
+            <
+                typename GeometricField<Type, fvPatchField, volMesh>::Boundary
+            >& sensFieldPtr,
+            const word& name
+        ) const;
+
+        //- Write face-based sensitivities, if present
+        void writeFaceBasedSens() const;
+
+        //- Write point-based sensitivities, if present
+        void writePointBasedSens() const;
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        sensitivity(const sensitivity&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const sensitivity&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("sensitivity");
+
+    // Constructors
+
+        //- Construct from components
+        sensitivity
+        (
+            const fvMesh& mesh,
+            const dictionary& dict,
+            const word& adjointSolverName
+        );
+
+    //- Destructor
+    virtual ~sensitivity() = default;
+
+
+    // Member Functions
+
+        //- Return the construction dictionary
+        const dictionary& dict() const;
+
+        //- Read dictionary if changed
+        virtual bool readDict(const dictionary& dict);
+
+        //- Get patch IDs on which sensitivities are computed
+        const labelList& sensitivityPatchIDs() const;
+
+        //- Overwrite sensitivityPatchIDs
+        void setSensitivityPatchIDs(const labelList& sensPatchIDs);
+
+        //- Compute design variables number. Does nothing in the base
+        //  Used to get the correct design variables number when
+        //  setSensitivityPatchIDs are not set in the constructor
+        virtual void computeDerivativesSize();
+
+        //- Calculates and returns sensitivity fields.
+        //  Used with optimisation libraries
+        virtual const scalarField& calculateSensitivities() = 0;
+
+        //- Write sensitivity fields.
+        //  If valid, copies boundaryFields to volFields and writes them.
+        //  Virtual to be reimplemented by control points-based methods
+        //  (Bezier, RBF) which do not need to write fields
+        virtual void write(const word& baseName = word::null);
+
+        //- Get wall face sensitivity vectors field
+        tmp<volVectorField> getWallFaceSensVec();
+
+        //- Get wall face sensitivity projected to normal field
+        tmp<volScalarField> getWallFaceSensNormal();
+
+        //- Get wall face normal sens as vectors field
+        tmp<volVectorField> getWallFaceSensNormalVec();
+
+        //- Get wall point sensitivity vectors field
+        //  Uses volPointInterpolation
+        tmp<pointVectorField> getWallPointSensVec();
+
+        //- Get wall point sensitivity projected to normal field
+        //  Uses volPointInterpolation
+        tmp<pointScalarField> getWallPointSensNormal();
+
+        //- Get wall point sens as vectors field
+        //  Uses volPointInterpolation
+        tmp<pointVectorField> getWallPointSensNormalVec();
+
+        //- Get wall face sensitivity vectors field
+        virtual const boundaryVectorField& getWallFaceSensVecBoundary() const;
+
+        //- Get wall face sensitivity projected to normal field
+        virtual const boundaryScalarField&
+            getWallFaceSensNormalBoundary() const;
+
+        //- Get wall face normal sens as vectors field
+        virtual const boundaryVectorField&
+            getWallFaceSensNormalVecBoundary() const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "sensitivityTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivityTemplates.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivityTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..2b070b2ebbe1cc79bca7a789c163efab1e2941f4
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivityTemplates.C
@@ -0,0 +1,157 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "sensitivity.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+template<class Type>
+void sensitivity::constructAndWriteSensitivityField
+(
+    const autoPtr
+    <
+        typename GeometricField<Type, fvPatchField, volMesh>::Boundary
+    >& sensFieldPtr,
+    const word& name
+) const
+{
+    GeometricField<Type, fvPatchField, volMesh> volSensField
+    (
+        IOobject
+        (
+            name,
+            mesh_.time().timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        mesh_,
+        dimensioned<Type>(dimless, Zero)
+    );
+
+    forAll(sensitivityPatchIDs_, pI)
+    {
+        const label patchI = sensitivityPatchIDs_[pI];
+        volSensField.boundaryFieldRef()[patchI] = sensFieldPtr()[patchI];
+    }
+
+    volSensField.write();
+}
+
+
+template<class Type>
+void sensitivity::constructAndWriteSensitivtyPointField
+(
+    const autoPtr<List<Field<Type>>>& sensFieldPtr,
+    const word& name
+) const
+{
+    GeometricField<Type, pointPatchField, pointMesh> pointSensField
+    (
+        IOobject
+        (
+            name,
+            mesh_.time().timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        pointMesh::New(mesh_),
+        dimensioned<Type>(dimless, Zero)
+        // fixedValuePointPatchField<Type>::typeName
+    );
+
+    forAll(sensitivityPatchIDs_, pI)
+    {
+        const label patchI = sensitivityPatchIDs_[pI];
+
+        //pointSensField.boundaryFieldRef()[patchI] == sensFieldPtr()[patchI];
+        pointSensField.boundaryField()[patchI].setInInternalField
+        (
+            pointSensField.primitiveFieldRef(),
+            sensFieldPtr()[patchI]
+        );
+    }
+
+    pointSensField.write();
+}
+
+
+template<class Type>
+tmp<GeometricField<Type, fvPatchField, volMesh>>
+sensitivity::constructVolSensitivtyField
+(
+    const autoPtr
+    <
+        typename GeometricField<Type, fvPatchField, volMesh>::Boundary
+    >& sensFieldPtr,
+    const word& name
+) const
+{
+        tmp<GeometricField<Type, fvPatchField, volMesh>> tVolSensField
+        (
+            new GeometricField<Type, fvPatchField, volMesh>
+            (
+                IOobject
+                (
+                    name,
+                    mesh_.time().timeName(),
+                    mesh_,
+                    IOobject::NO_READ,
+                    IOobject::NO_WRITE
+                ),
+                mesh_,
+                pTraits<Type>::zero
+            )
+        );
+        GeometricField<Type, fvPatchField, volMesh>& volSensField =
+            tVolSensField.ref();
+
+        typename GeometricField<Type, fvPatchField, volMesh>::Boundary&
+            volSensFieldbf = volSensField.boundaryFieldRef();
+
+        forAll(sensitivityPatchIDs_, pI)
+        {
+            const label patchI = sensitivityPatchIDs_[pI];
+            volSensFieldbf[patchI] = sensFieldPtr()[patchI];
+        }
+
+        return tVolSensField;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.C
new file mode 100644
index 0000000000000000000000000000000000000000..e992c64f5fd33003b9856fccb1c992a7ac15a1ff
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.C
@@ -0,0 +1,215 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "lineSearch.H"
+#include "Time.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(lineSearch, 0);
+defineRunTimeSelectionTable(lineSearch, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+lineSearch::lineSearch(const dictionary& dict, const Time& time)
+:
+    dict_(dict),
+    lineSearchDict_
+    (
+        IOobject
+        (
+            "lineSearch",
+            time.timeName(),
+            "uniform",
+            time,
+            IOobject::READ_IF_PRESENT,
+            IOobject::NO_WRITE,
+            false
+        )
+    ),
+    directionalDeriv_(Zero),
+    direction_(0),
+    oldMeritValue_(Zero),
+    newMeritValue_(Zero),
+    prevMeritDeriv_
+    (
+        lineSearchDict_.lookupOrDefault<scalar>("prevMeritDeriv", Zero)
+    ),
+    initialStep_(dict.lookupOrDefault<scalar>("initialStep", 1)),
+    minStep_(dict.lookupOrDefault<scalar>("minStep", 0.3)),
+    step_(Zero),
+    iter_(lineSearchDict_.lookupOrDefault<label>("iter", 0)),
+    maxIters_(dict.lookupOrDefault<scalar>("maxIters", 10)),
+    extrapolateInitialStep_
+    (
+        dict.lookupOrDefault<bool>
+        (
+            "extrapolateInitialStep",
+            false
+        )
+    ),
+    stepUpdate_(stepUpdate::New(dict))
+{}
+
+
+// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
+
+autoPtr<lineSearch> lineSearch::New
+(
+    const dictionary& dict,
+    const Time& time
+)
+{
+    autoPtr<lineSearch> lineSrch(nullptr);
+
+    const word modelType =
+        dict.lookupOrDefault<word>("lineSearchType", "none");
+
+    Info<< "lineSearch type : " << modelType << endl;
+
+    if (modelType != "none")
+    {
+        auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
+
+        if (!cstrIter.found())
+        {
+            FatalErrorInFunction
+                << "Unknown lineSearch type " << modelType
+                << nl << nl
+                << "Valid lineSearch types are :" << nl
+                << dictionaryConstructorTablePtr_->sortedToc()
+                << exit(FatalError);
+        }
+
+        lineSrch.reset((cstrIter()(dict, time)).ptr());
+    }
+    else
+    {
+        Info<< "No line search method specified. "
+            << "Proceeding with constant step" << endl;
+    }
+
+    return lineSrch;
+}
+
+
+// * * * * * * * * * * * * * * *  Member Functions   * * * * * * * * * * * * //
+
+void lineSearch::setDeriv(const scalar deriv)
+{
+    directionalDeriv_ = deriv;
+    stepUpdate_->setDeriv(deriv);
+}
+
+
+void lineSearch::setDirection(const scalarField& direction)
+{
+    direction_ = direction;
+}
+
+
+void lineSearch::setNewMeritValue(const scalar value)
+{
+    newMeritValue_ = value;
+    stepUpdate_->setNewMeritValue(value);
+}
+
+
+void lineSearch::setOldMeritValue(const scalar value)
+{
+    oldMeritValue_ = value;
+    stepUpdate_->setOldMeritValue(value);
+}
+
+
+void lineSearch::reset()
+{
+    if (extrapolateInitialStep_ && iter_ != 0)
+    {
+        // step_ = 2*(oldMeritValue_-prevMeritValue_)/directionalDeriv_;
+        // Interpolate in order to get same improvement with the previous
+        // optimisation cycle
+        step_ = max(min(step_*prevMeritDeriv_/directionalDeriv_, 1.), minStep_);
+        Info<< "\n------- Computing initial step-------" << endl;
+        Info<< "old dphi(0) "  << prevMeritDeriv_ << endl;
+        Info<< "dphi(0) "      << directionalDeriv_ << endl;
+        Info<< "Setting initial step value " << step_ << endl << endl;
+    }
+    else
+    {
+        step_ = initialStep_;
+    }
+}
+
+
+label lineSearch::maxIters() const
+{
+    return maxIters_;
+}
+
+
+scalar lineSearch::step() const
+{
+    return step_;
+}
+
+
+void lineSearch::updateStep(const scalar newStep)
+{
+    step_ = newStep;
+}
+
+
+lineSearch& lineSearch::operator++()
+{
+    iter_++;
+    prevMeritDeriv_ = directionalDeriv_;
+    lineSearchDict_.add<scalar>("prevMeritDeriv_", prevMeritDeriv_, true);
+    lineSearchDict_.add<label>("iter", iter_, true);
+    lineSearchDict_.regIOobject::write();
+
+    return *this;
+}
+
+
+lineSearch& lineSearch::operator++(int)
+{
+    return operator++();
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.H
new file mode 100644
index 0000000000000000000000000000000000000000..3d3c703d94bdf3abf08f9491b36562a3b1ce6069
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.H
@@ -0,0 +1,188 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::lineSearch
+
+Description
+    Abstract base class for optimisation methods
+
+SourceFiles
+    lineSearch.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef lineSearch_H
+#define lineSearch_H
+
+#include "runTimeSelectionTables.H"
+#include "IOdictionary.H"
+#include "scalarField.H"
+#include "stepUpdate.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                         Class lineSearch Declaration
+\*---------------------------------------------------------------------------*/
+
+class lineSearch
+{
+protected:
+
+    // Protected data
+
+        const dictionary dict_;
+        IOdictionary lineSearchDict_;
+        scalar directionalDeriv_;
+        scalarField direction_;
+
+        //- Old merit value from this opt cycle
+        scalar oldMeritValue_;
+
+        //- New merit value from this opt cycle
+        scalar newMeritValue_;
+
+        //- Merit directional deriv from the previous opt cycle
+        scalar prevMeritDeriv_;
+        scalar initialStep_;
+        scalar minStep_;
+        scalar step_;
+        label iter_;
+        label maxIters_;
+        bool extrapolateInitialStep_;
+        autoPtr<stepUpdate> stepUpdate_;
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        lineSearch(const lineSearch&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const lineSearch&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("lineSearch");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            lineSearch,
+            dictionary,
+            (
+                const dictionary& dict,
+                const Time& time
+            ),
+            (dict, time)
+        );
+
+
+    // Constructors
+
+        //- Construct from components
+        lineSearch(const dictionary& dict, const Time& time);
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<lineSearch> New
+        (
+            const dictionary& dict,
+            const Time& time
+        );
+
+
+    //- Destructor
+    virtual ~lineSearch() = default;
+
+
+    // Member Functions
+
+       //- Set objective derivative
+       virtual void setDeriv(const scalar deriv);
+
+       //- Set direction
+       void setDirection(const scalarField& direction);
+
+       //- Set new objective value
+       void setNewMeritValue(const scalar value);
+
+       //- Set old objective value
+       void setOldMeritValue(const scalar value);
+
+       //- Reset step to initial value
+       virtual void reset();
+
+       //- Get max number of iterations
+       label maxIters() const;
+
+       //- Get current step
+       scalar step() const;
+
+       //- Return the correction of the design variables
+       virtual bool converged() = 0;
+
+       //- Update the line search step based on the specific line search
+       //- strategy, e.g. bisection, quadratic fit, etc.
+       virtual void updateStep() = 0;
+
+       //- Update the step using the supplied value
+       virtual void updateStep(const scalar newStep);
+
+
+    // Member operators
+
+       //- Increment iteration number and store merit value corresponding to
+       //- the previous optimisation cycle
+       virtual lineSearch& operator++();
+
+       //- Postfix increment. Necessary for compilation
+       virtual lineSearch& operator++(int);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/stepUpdate/stepUpdate/stepUpdate.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/stepUpdate/stepUpdate/stepUpdate.C
new file mode 100644
index 0000000000000000000000000000000000000000..9995531007fa273989d5ef6a3f5a1c41231746c3
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/stepUpdate/stepUpdate/stepUpdate.C
@@ -0,0 +1,104 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "stepUpdate.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(stepUpdate, 0);
+defineRunTimeSelectionTable(stepUpdate, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+stepUpdate::stepUpdate(const dictionary& dict)
+:
+    dict_(dict)
+{}
+
+
+// * * * * * * * * * * * * * * * * Selectors  * * * * * * * * * * * * * * //
+
+autoPtr<stepUpdate> stepUpdate::New(const dictionary& dict)
+{
+    const word modelType =
+        dict.lookupOrDefault<word>("stepUpdateType", "bisection");
+
+    Info<< "stepUpdate type : " << modelType << endl;
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown stepUpdate type " << modelType
+            << nl << nl
+            << "Valid stepUpdate types are : " << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return autoPtr<stepUpdate>(cstrIter()(dict));
+}
+
+
+// * * * * * * * * * * * * * * *  Member Functions   * * * * * * * * * * * * //
+
+void stepUpdate::setDeriv(const scalar deriv)
+{
+    // Does nothing in base
+}
+
+
+void stepUpdate::setNewMeritValue(const scalar value)
+{
+    // Does nothing in base
+}
+
+
+void stepUpdate::setOldMeritValue(const scalar value)
+{
+    // Does nothing in base
+}
+
+
+void stepUpdate::setInitialStep(const scalar value)
+{
+    // Does nothing in base
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/stepUpdate/stepUpdate/stepUpdate.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/stepUpdate/stepUpdate/stepUpdate.H
new file mode 100644
index 0000000000000000000000000000000000000000..32c17350bf7f6958e1f3af387a8cfacf438f675e
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/stepUpdate/stepUpdate/stepUpdate.H
@@ -0,0 +1,137 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::stepUpdate
+
+Description
+    Abstract base class for optimisation methods
+
+SourceFiles
+    stepUpdate.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef stepUpdate_H
+#define stepUpdate_H
+
+#include "runTimeSelectionTables.H"
+#include "dictionary.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                         Class stepUpdate Declaration
+\*---------------------------------------------------------------------------*/
+
+class stepUpdate
+{
+protected:
+
+    // Protected data
+
+        const dictionary dict_;
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        stepUpdate(const stepUpdate&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const stepUpdate&);
+
+
+public:
+
+    //- Runtime type information
+    TypeName("stepUpdate");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            stepUpdate,
+            dictionary,
+            (
+                const dictionary& dict
+            ),
+            (dict)
+        );
+
+
+    // Constructors
+
+        //- Construct from components
+        stepUpdate(const dictionary& dict);
+
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<stepUpdate> New(const dictionary& dict);
+
+
+    //- Destructor
+    virtual ~stepUpdate() = default;
+
+
+    // Member Functions
+
+       //- Update the line search step
+       virtual void updateStep(scalar& step) = 0;
+
+       //- Set objective derivative
+       virtual void setDeriv(const scalar deriv);
+
+       //- Set new objective value
+       virtual void setNewMeritValue(const scalar value);
+
+       //- Set old objective value
+       virtual void setOldMeritValue(const scalar value);
+
+       //- Set old objective value
+       virtual void setInitialStep(const scalar value);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.C
new file mode 100644
index 0000000000000000000000000000000000000000..cd67276f14de7bbcf9791c1e0eaabcbffe4450a8
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.C
@@ -0,0 +1,268 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "optimisationManager.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(optimisationManager, 0);
+    defineRunTimeSelectionTable(optimisationManager, dictionary);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::optimisationManager::optimisationManager(fvMesh& mesh)
+:
+    IOdictionary
+    (
+        IOobject
+        (
+            "optimisationDict",
+            mesh.time().system(),
+            mesh,
+            IOobject::MUST_READ_IF_MODIFIED,
+            IOobject::NO_WRITE,
+            true
+        )
+    ),
+    mesh_(mesh),
+    time_(const_cast<Time&>(mesh.time())),
+    primalSolvers_(),
+    adjointSolverManagers_(),
+    managerType_(get<word>("optimisationManager")),
+    optType_(nullptr)
+{
+    const dictionary& primalSolversDict = subDict("primalSolvers");
+    const wordList& primalSolverNames = primalSolversDict.toc();
+
+    // Construct primal solvers
+    primalSolvers_.setSize(primalSolverNames.size());
+    forAll(primalSolvers_, solveri)
+    {
+        primalSolvers_.set
+        (
+            solveri,
+            primalSolver::New
+            (
+                mesh,
+                managerType_,
+                primalSolversDict.subDict(primalSolverNames[solveri])
+            )
+        );
+    }
+
+    // Construct adjointSolverManagers
+    const dictionary& adjointManagersDict = subDict("adjointManagers");
+    const wordList& adjointManagerNames = adjointManagersDict.toc();
+    adjointSolverManagers_.setSize(adjointManagerNames.size());
+
+    label nAdjointSolvers(0);
+    forAll(adjointSolverManagers_, manageri)
+    {
+        adjointSolverManagers_.set
+        (
+            manageri,
+            new adjointSolverManager
+            (
+                mesh,
+                managerType_,
+                adjointManagersDict.subDict(adjointManagerNames[manageri])
+            )
+        );
+        nAdjointSolvers += adjointSolverManagers_[manageri].nAdjointSolvers();
+    }
+
+    // Sanity checks on the naming convention
+    if (primalSolvers_.size() > 1)
+    {
+        for (const primalSolver& solveri : primalSolvers_)
+        {
+            if (!solveri.useSolverNameForFields())
+            {
+                FatalErrorInFunction
+                    << "Multiple primal solvers are present but "
+                    << "useSolverNameForFields is set to false in "
+                    << "primal solver " << solveri.solverName() << nl
+                    << "This is considered fatal."
+                    << exit(FatalError);
+            }
+        }
+    }
+
+    if (nAdjointSolvers > 1)
+    {
+        for (const adjointSolverManager& amI : adjointSolverManagers_)
+        {
+            const PtrList<adjointSolver>& adjointSolvers = amI.adjointSolvers();
+            for (const adjointSolver& asI : adjointSolvers)
+            {
+                if (!asI.useSolverNameForFields())
+                {
+                    FatalErrorInFunction
+                        << "Multiple adjoint solvers are present but "
+                        << "useSolverNameForFields is set to false in "
+                        << "adjoint solver " << asI.solverName() << nl
+                        << "This is considered fatal."
+                        << exit(FatalError);
+                }
+            }
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Selectors  * * * * * * * * * * * * * * //
+
+Foam::autoPtr<Foam::optimisationManager> Foam::optimisationManager::New
+(
+    fvMesh& mesh
+)
+{
+    word modelType;
+    {
+        IOdictionary dict
+        (
+            IOobject
+            (
+                "optimisationDict",
+                mesh.time().system(),
+                mesh,
+                IOobject::MUST_READ_IF_MODIFIED,
+                IOobject::NO_WRITE,
+                false // do not register
+            )
+        );
+
+        modelType = dict.get<word>("optimisationManager");
+    }
+
+    Info<< "optimisationManager type : " << modelType << endl;
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown optimisationManager type " << modelType << nl << nl
+            << "Valid optimisationManager types are :" << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return autoPtr<optimisationManager>(cstrIter()(mesh));
+}
+
+
+// * * * * * * * * * * * * * * *  Member Functions   * * * * * * * * * * * * //
+
+bool Foam::optimisationManager::read()
+{
+    if (regIOobject::read())
+    {
+        // Note: Only changing existing solvers - not adding any new
+        const dictionary& primalSolversDict = subDict("primalSolvers");
+        for (primalSolver& sol : primalSolvers_)
+        {
+            sol.readDict(primalSolversDict.subDict(sol.solverName()));
+        }
+
+        const dictionary& adjointManagersDict = subDict("adjointManagers");
+        for (adjointSolverManager& man : adjointSolverManagers_)
+        {
+            man.readDict(adjointManagersDict.subDict(man.managerName()));
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+
+Foam::PtrList<Foam::primalSolver>& Foam::optimisationManager::primalSolvers()
+{
+    return primalSolvers_;
+}
+
+
+Foam::PtrList<Foam::adjointSolverManager>&
+Foam::optimisationManager::adjointSolverManagers()
+{
+    return adjointSolverManagers_;
+}
+
+
+void Foam::optimisationManager::solvePrimalEquations()
+{
+    // Solve all primal equations
+    forAll(primalSolvers_, psI)
+    {
+        primalSolvers_[psI].solve();
+    }
+}
+
+
+void Foam::optimisationManager::solveAdjointEquations()
+{
+    // Solve all adjoint solver equations
+    forAll(adjointSolverManagers_, amI)
+    {
+        adjointSolverManagers_[amI].solveAdjointEquations();
+    }
+}
+
+
+void Foam::optimisationManager::computeSensitivities()
+{
+    // Compute senstivities from all adjoint solvers
+    forAll(adjointSolverManagers_, amI)
+    {
+        adjointSolverManagers_[amI].computeAllSensitivities();
+    }
+}
+
+
+void Foam::optimisationManager::updatePrimalBasedQuantities()
+{
+    forAll(adjointSolverManagers_, amI)
+    {
+        PtrList<adjointSolver>& adjointSolvers =
+            adjointSolverManagers_[amI].adjointSolvers();
+
+        forAll(adjointSolvers, asI)
+        {
+            adjointSolvers[asI].updatePrimalBasedQuantities();
+        }
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.H
new file mode 100644
index 0000000000000000000000000000000000000000..5dbd146d81cc8220575d515e7c2b9b54f3ccd290
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.H
@@ -0,0 +1,171 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::optimisationManager
+
+Description
+    Abstract base class for optimisation methods
+
+SourceFiles
+    optimisationManager.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef optimisationManager_H
+#define optimisationManager_H
+
+#include "runTimeSelectionTables.H"
+#include "IOdictionary.H"
+#include "optimisationTypeIncompressible.H"
+#include "primalSolver.H"
+#include "adjointSolverManager.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                     Class optimisationManager Declaration
+\*---------------------------------------------------------------------------*/
+
+class optimisationManager
+:
+    public IOdictionary
+{
+protected:
+
+    // Protected data
+
+        fvMesh& mesh_;
+        Time& time_;
+        PtrList<primalSolver> primalSolvers_;
+        PtrList<adjointSolverManager> adjointSolverManagers_;
+        const word managerType_;
+        autoPtr<incompressible::optimisationType> optType_;
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        optimisationManager(const optimisationManager&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const optimisationManager&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("optimisationManager");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            optimisationManager,
+            dictionary,
+            (
+                fvMesh& mesh
+            ),
+            (mesh)
+        );
+
+
+    // Constructors
+
+        //- Construct from components
+        optimisationManager(fvMesh& mesh);
+
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<optimisationManager> New(fvMesh& mesh);
+
+
+    //- Destructor
+    virtual ~optimisationManager() = default;
+
+
+    // Member Functions
+
+        virtual PtrList<primalSolver>& primalSolvers();
+
+        virtual PtrList<adjointSolverManager>& adjointSolverManagers();
+
+        virtual bool read();
+
+        //- Prefix increment,
+        virtual optimisationManager& operator++() = 0;
+
+        //- Postfix increment, this is identical to the prefix increment
+        virtual optimisationManager& operator++(int) = 0;
+
+        //- Return true if end of optimisation run.
+        //  Also, updates the design variables if needed
+        virtual bool checkEndOfLoopAndUpdate() = 0;
+
+        //- Return true if end of optimisation run
+        virtual bool end() = 0;
+
+        //- Whether to update the design variables
+        virtual bool update() = 0;
+
+        //- Update design variables.
+        //  Might employ a line search to find a correction satisfying the step
+        //  convergence criteria
+        virtual void updateDesignVariables() = 0;
+
+        //- Solve all primal equations
+        virtual void solvePrimalEquations();
+
+        //- Solve all adjoint equations
+        virtual void solveAdjointEquations();
+
+        //- Compute all adjoint sensitivities
+        virtual void computeSensitivities();
+
+        //- Solve all primal equations
+        virtual void updatePrimalBasedQuantities();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/singleRun/singleRun.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/singleRun/singleRun.C
new file mode 100644
index 0000000000000000000000000000000000000000..e7c34958c3ae2b9902d8540cd9d6cb20503fc3fd
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/singleRun/singleRun.C
@@ -0,0 +1,91 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "singleRun.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(singleRun, 0);
+    addToRunTimeSelectionTable(optimisationManager, singleRun, dictionary);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::singleRun::singleRun(fvMesh& mesh)
+:
+    optimisationManager(mesh),
+    cycles_(Zero)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::optimisationManager& Foam::singleRun::operator++()
+{
+    cycles_++;
+    return *this;
+}
+
+
+Foam::optimisationManager& Foam::singleRun::operator++(int)
+{
+    return operator++();
+}
+
+
+bool Foam::singleRun::checkEndOfLoopAndUpdate()
+{
+    return end();
+}
+
+
+bool Foam::singleRun::end()
+{
+    // Force execution of a single loop
+    return cycles_ > 1;
+}
+
+
+bool Foam::singleRun::update()
+{
+    // No update in singleRun cases
+    return false;
+}
+
+
+void Foam::singleRun::updateDesignVariables()
+{
+    // No update in singleRun cases
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/singleRun/singleRun.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/singleRun/singleRun.H
new file mode 100644
index 0000000000000000000000000000000000000000..8c0037cb284a184a4415fcc4908cab18f6b15e9e
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/singleRun/singleRun.H
@@ -0,0 +1,123 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::singleRun
+
+Description
+    Update design variables using steepest descent
+
+SourceFiles
+    singleRun.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef singleRun_H
+#define singleRun_H
+
+#include "optimisationManager.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                          Class singleRun Declaration
+\*---------------------------------------------------------------------------*/
+
+class singleRun
+:
+    public optimisationManager
+{
+protected:
+
+    // Protected data
+    label cycles_;
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        singleRun(const singleRun&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const singleRun&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("singleRun");
+
+
+    // Constructors
+
+        //- Construct from components
+        singleRun(fvMesh& mesh);
+
+
+    //- Destructor
+    virtual ~singleRun() = default;
+
+
+    // Member Functions
+
+        //- Prefix increment
+        virtual optimisationManager& operator++();
+
+        //- Postfix increment, this is identical to the prefix increment
+        virtual optimisationManager& operator++(int);
+
+        //- Return true if end of optimisation run.
+        //  Also, updates the design variables if needed
+        virtual bool checkEndOfLoopAndUpdate();
+
+        //- Return true if end of optimisation run
+        virtual bool end();
+
+        //- Whether to update the design variables
+        virtual bool update();
+
+        //- Update design variables.
+        //  Might employ a line search to find a correction satisfying the step
+        //  convergence criteria
+        virtual void updateDesignVariables();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/optimisationType/optimisationTypeIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/optimisationType/optimisationTypeIncompressible.C
new file mode 100644
index 0000000000000000000000000000000000000000..eebfc21d5581b20d0f143c1605f71373203aac53
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/optimisationType/optimisationTypeIncompressible.C
@@ -0,0 +1,284 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "optimisationTypeIncompressible.H"
+#include "constrainedOptimisationMethod.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(optimisationType, 0);
+defineRunTimeSelectionTable(optimisationType, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+optimisationType::optimisationType
+(
+    fvMesh& mesh,
+    const dictionary& dict,
+    PtrList<adjointSolverManager>& adjointSolverManagers
+)
+:
+    mesh_(mesh),
+    dict_(dict),
+    adjointSolvManagers_(adjointSolverManagers),
+    updateMethod_
+    (
+        updateMethod::New(mesh_, dict_.subDict("updateMethod"))
+    ),
+    sourcePtr_(nullptr),
+    lineSearch_(lineSearch::New(dict_.subDict("updateMethod"), mesh.time()))
+{
+    // Figure out number of adjoint solvers corresponding to constraints.
+    // Looks in all operating poitns
+    label nConstraints(0);
+    for (const adjointSolverManager& adjManagerI : adjointSolvManagers_)
+    {
+        nConstraints += adjManagerI.nConstraints();
+    }
+
+    // Sanity checks for combinations of number of constraints and
+    // optimisation methods
+    if
+    (
+        nConstraints
+     && !isA<constrainedOptimisationMethod>(updateMethod_())
+    )
+    {
+        // Has constraints but is not a constraint optimisation method
+        auto cstTablePtr
+        (
+            constrainedOptimisationMethod::dictionaryConstructorTablePtr_
+        );
+        FatalErrorInFunction
+            << "Found " << nConstraints << " adjoint solvers corresponding to "
+            << "constraints but the optimisation method used "
+            << "(" << updateMethod_().type() << ") "
+            << "is not a constrainedOptimisationMethod. " << nl
+            << "Available constrainedOptimisationMethods are :" << nl
+            << cstTablePtr->sortedToc()
+            << exit(FatalError);
+    }
+    else if
+    (
+        !nConstraints
+     && isA<constrainedOptimisationMethod>(updateMethod_())
+    )
+    {
+        // Does not have constraints but is a constrained optimisation method
+        WarningInFunction
+            << "Did not find any adjoint solvers corresponding to "
+            << "constraints but the optimisation method used "
+            << "(" << updateMethod_().type() << ") "
+            << "is a constrainedOptimisationMethod. " << nl << nl
+            << "This can cause some constraintOptimisationMethods to misbehave."
+            << nl << nl
+            << "Either the isConstraint bool is not set in one of the adjoint "
+            << "solvers or you should consider using an updateMethod "
+            << "that is not a constrainedOptimisationMethod"
+            << nl << endl;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+autoPtr<optimisationType> optimisationType::New
+(
+    fvMesh& mesh,
+    const dictionary& dict,
+    PtrList<adjointSolverManager>& adjointSolverManagers
+)
+{
+    const word modelType(dict.subDict("optimisationType").get<word>("type"));
+
+    Info<< "optimisationType type : " << modelType << endl;
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown optimisationType type " << modelType << nl << nl
+            << "Valid optimisationType types are :" << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return autoPtr<optimisationType>
+    (
+        cstrIter()(mesh, dict, adjointSolverManagers)
+    );
+}
+
+
+// * * * * * * * * * * * * * * *  Member Functions   * * * * * * * * * * * * //
+
+tmp<scalarField> optimisationType::computeDirection()
+{
+    // Sum contributions
+    scalarField objectiveSens;
+    PtrList<scalarField> constraintSens;
+    scalar objectiveValue(Zero);
+    scalarField constraintValues;
+
+    for (adjointSolverManager& adjSolvManager : adjointSolvManagers_)
+    {
+        const scalar opWeight = adjSolvManager.operatingPointWeight();
+
+        // Allocate objective sens size if necessary
+        tmp<scalarField> tadjointSolverManagerSens =
+            adjSolvManager.aggregateSensitivities();
+
+        if (objectiveSens.empty())
+        {
+            objectiveSens.setSize(tadjointSolverManagerSens().size(), Zero);
+        }
+
+        objectiveSens += opWeight*tadjointSolverManagerSens();
+        objectiveValue += opWeight*adjSolvManager.objectiveValue();
+
+        // Allocate constraint sens size if necessary
+        PtrList<scalarField> adjointSolverManagerConstSens =
+            adjSolvManager.constraintSensitivities();
+
+        tmp<scalarField> cValues = adjSolvManager.constraintValues();
+
+        if (constraintSens.empty())
+        {
+            constraintSens.setSize(adjointSolverManagerConstSens.size());
+            forAll(constraintSens, cI)
+            {
+                constraintSens.set
+                (
+                    cI,
+                    new scalarField
+                    (
+                        adjointSolverManagerConstSens[cI].size(),
+                        Zero
+                    )
+                );
+                constraintValues.setSize(cValues().size());
+                constraintValues = Zero;
+            }
+        }
+
+        forAll(constraintSens, cI)
+        {
+            constraintSens[cI] += opWeight*adjointSolverManagerConstSens[cI];
+        }
+        constraintValues += opWeight*cValues();
+    }
+
+    // Based on the sensitivities, return design variables correction
+    updateMethod_->setObjectiveDeriv(objectiveSens);
+    updateMethod_->setConstraintDeriv(constraintSens);
+    updateMethod_->setObjectiveValue(objectiveValue);
+    updateMethod_->setConstraintValues(constraintValues);
+    tmp<scalarField> tcorrection
+    (
+        new scalarField(objectiveSens.size(), Zero)
+    );
+    scalarField& correction = tcorrection.ref();
+    correction = updateMethod_->returnCorrection();
+
+    return tcorrection;
+}
+
+
+scalar optimisationType::computeMeritFunction()
+{
+    // Compute new objective and constraint values and update the ones
+    // in updateMethod
+    scalar objectiveValue(Zero);
+    scalarField constraintValues;
+
+    for (adjointSolverManager& adjSolvManager : adjointSolvManagers_)
+    {
+        const scalar opWeight = adjSolvManager.operatingPointWeight();
+
+        objectiveValue += opWeight*adjSolvManager.objectiveValue();
+        tmp<scalarField> cValues = adjSolvManager.constraintValues();
+
+        if (constraintValues.empty())
+        {
+            constraintValues.setSize(cValues().size(), Zero);
+        }
+        constraintValues += opWeight*cValues();
+    }
+    updateMethod_->setObjectiveValue(objectiveValue);
+    updateMethod_->setConstraintValues(constraintValues);
+
+    return updateMethod_->computeMeritFunction();
+}
+
+
+scalar optimisationType::meritFunctionDirectionalDerivative()
+{
+    return updateMethod_->meritFunctionDirectionalDerivative();
+}
+
+
+void optimisationType::updateOldCorrection(const scalarField& oldCorrection)
+{
+    updateMethod_->updateOldCorrection(oldCorrection);
+}
+
+
+void optimisationType::write()
+{
+    updateMethod_->write();
+}
+
+
+const autoPtr<volScalarField>& optimisationType::sourcePtr()
+{
+    return sourcePtr_;
+}
+
+
+autoPtr<lineSearch>& optimisationType::getLineSearch()
+{
+    return lineSearch_;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/optimisationType/optimisationTypeIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/optimisationType/optimisationTypeIncompressible.H
new file mode 100644
index 0000000000000000000000000000000000000000..71a7a969374612e71aa4a4fd011768a55a4fcd15
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/optimisationType/optimisationTypeIncompressible.H
@@ -0,0 +1,179 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::optimisationType
+
+Description
+    Abstract base class for optimisation methods
+
+SourceFiles
+    optimisationType.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef optimisationTypeIncompressible_H
+#define optimisationTypeIncompressible_H
+
+#include "adjointSolverManager.H"
+#include "updateMethod.H"
+#include "lineSearch.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace incompressible
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class optimisationType Declaration
+\*---------------------------------------------------------------------------*/
+
+class optimisationType
+{
+protected:
+
+    // Protected data
+
+        fvMesh& mesh_;
+        const dictionary dict_;
+        PtrList<adjointSolverManager>& adjointSolvManagers_;
+        autoPtr<updateMethod> updateMethod_;
+        autoPtr<volScalarField> sourcePtr_;
+        autoPtr<lineSearch> lineSearch_;
+
+        virtual void computeEta(scalarField& correction)=0;
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        optimisationType(const optimisationType&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const optimisationType&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("optimisationType");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            optimisationType,
+            dictionary,
+            (
+                fvMesh& mesh,
+                const dictionary& dict,
+                PtrList<adjointSolverManager>& adjointSolverManagers
+            ),
+            (mesh, dict, adjointSolverManagers)
+        );
+
+
+
+    // Constructors
+
+        //- Construct from components
+        optimisationType
+        (
+            fvMesh& mesh,
+            const dictionary& dict,
+            PtrList<adjointSolverManager>& adjointSolverManagers
+        );
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<optimisationType> New
+        (
+            fvMesh& mesh,
+            const dictionary& dict,
+            PtrList<adjointSolverManager>& adjointSolverManagers
+        );
+
+
+    // Destructor
+
+        virtual ~optimisationType() = default;
+
+        //- Update design variables
+        virtual void update() = 0;
+
+        //- Update design variables based on a given correction
+        virtual void update(scalarField& correction) = 0;
+
+        //- Store design variables, as the starting point for line search
+        virtual void storeDesignVariables() = 0;
+
+        //- Reset to starting point of line search
+        virtual void resetDesignVariables() = 0;
+
+        //- Compute update direction
+        virtual tmp<scalarField> computeDirection();
+
+        //- Compute the merit function of the optimisation problem.
+        //  Could be different than the objective function in case of
+        //  constraint optimisation
+        virtual scalar computeMeritFunction();
+
+        //- Derivative of the merit function
+        virtual scalar meritFunctionDirectionalDerivative();
+
+        //- Update old correction. Needed for quasi-Newton Methods
+        virtual void updateOldCorrection(const scalarField&);
+
+        //- Write useful quantities to files
+        virtual void write();
+
+        //- Get source term
+        const autoPtr<volScalarField>& sourcePtr();
+
+        //- Get a reference to the line search object
+        autoPtr<lineSearch>& getLineSearch();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.C
new file mode 100644
index 0000000000000000000000000000000000000000..7fb082d471999ae6cf8dfc2758a419cebced7670
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.C
@@ -0,0 +1,52 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "constrainedOptimisationMethod.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(constrainedOptimisationMethod, 0);
+    defineRunTimeSelectionTable(constrainedOptimisationMethod, dictionary);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::constrainedOptimisationMethod::constrainedOptimisationMethod
+(
+    const fvMesh& mesh,
+    const dictionary& dict
+)
+:
+    updateMethod(mesh, dict)
+{}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.H
new file mode 100644
index 0000000000000000000000000000000000000000..94bc81de4dbc0c7cd35c5f5a52b0a199ea7d5fcd
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.H
@@ -0,0 +1,124 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::constrainedOptimisationMethod
+
+Description
+    Abstract base class for optimisation methods supporting constraints.
+    Does not add functionality to updateMethod but act as a means
+    to categorize constrained optimisation methods for performing sanity checks
+
+SourceFiles
+    constrainedOptimisationMethod.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef constrainedOptimisationMethod_H
+#define constrainedOptimisationMethod_H
+
+#include "updateMethod.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                Class constrainedOptimisationMethod Declaration
+\*---------------------------------------------------------------------------*/
+
+class constrainedOptimisationMethod
+:
+    public updateMethod
+{
+private:
+
+    // Private Member Functions
+
+        //- No copy construct
+        constrainedOptimisationMethod
+        (
+            const constrainedOptimisationMethod&
+        ) = delete;
+
+        //- No copy assignment
+        void operator=(const constrainedOptimisationMethod&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("constrainedOptimisationMethod");
+
+    // Declare table with available constrainedOptimisation methods.
+    // Not used for run-time selection, just for keeping track of the
+    // available methods
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            constrainedOptimisationMethod,
+            dictionary,
+            (
+                const fvMesh& mesh,
+                const dictionary& dict
+            ),
+            (mesh, dict)
+        );
+
+
+    // Constructors
+
+        //- Construct from components
+        constrainedOptimisationMethod
+        (
+            const fvMesh& mesh,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~constrainedOptimisationMethod() = default;
+
+
+    // Member Functions
+
+       //- Return the correction of the design variables
+       virtual void computeCorrection()=0;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.C
new file mode 100644
index 0000000000000000000000000000000000000000..b9c5e3275f9c8363d71e8173438426cdb5bc89c3
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.C
@@ -0,0 +1,370 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "updateMethod.H"
+#include "OFstream.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(updateMethod, 0);
+    defineRunTimeSelectionTable(updateMethod, dictionary);
+}
+
+
+// * * * * * * * * * *  Protected  Member Functions  * * * * * * * * * * * * //
+
+const Foam::scalarField Foam::updateMethod::leftMult
+(
+    const scalarField& s,
+    const SquareMatrix<scalar>& m
+)
+{
+    if (s.size() != m.n())
+    {
+        FatalErrorInFunction
+            << "scalar derivative and HessianInv matrix do not have the "
+            << "same dimension"
+            << abort(FatalError);
+    }
+
+    scalarField res(s.size(), Zero);
+    forAll(s, i)
+    {
+        forAll(s, j)
+        {
+            res[i] += s[j]*m[j][i];
+        }
+    }
+
+    return (res);
+}
+
+
+const Foam::scalarField Foam::updateMethod::rightMult
+(
+    const SquareMatrix<scalar>& m,
+    const scalarField& s
+)
+{
+    if (s.size() != m.n())
+    {
+        FatalErrorInFunction
+            << "scalar derivative and HessianInv matrix do not have the "
+            << "same dimension"
+            << abort(FatalError);
+    }
+
+    scalarField res(s.size(), Zero);
+    forAll(s, i)
+    {
+        forAll(s, j)
+        {
+            res[i] += m[i][j]*s[j];
+        }
+    }
+
+    return (res);
+}
+
+
+Foam::SquareMatrix<Foam::scalar> Foam::updateMethod::outerProd
+(
+    const scalarField& a,
+    const scalarField& b
+)
+{
+    if (a.size() != b.size())
+    {
+        FatalErrorInFunction
+            << "operands of outerProduct do not have the same dimension"
+            << abort(FatalError);
+    }
+
+    SquareMatrix<scalar> res(a.size(), Zero);
+    forAll(a, i)
+    {
+        forAll(a, j)
+        {
+            res[i][j]  = a[i]*b[j];
+        }
+    }
+
+    return (res);
+}
+
+
+Foam::SquareMatrix<Foam::scalar>
+Foam::updateMethod::inv(SquareMatrix<scalar> A)
+{
+    label n(A.n());
+    SquareMatrix<scalar> invA(n, Zero);
+
+    //- LU decomposition of A
+    labelList pivotIndices(n, Zero);
+    LUDecompose(A, pivotIndices);
+    DebugInfo
+        << "LU decomposed A " << A << endl;
+
+    // Compute inverse of A by successive back-substitutions.
+    for (label j = 0; j < n; j++)
+    {
+        scalarField rhs(n, 0.);
+        rhs[j] = 1.;
+        LUBacksubstitute(A, pivotIndices, rhs);
+        // After LUBacksubstitute, rhs contains the j-th column of the inverse
+        for (label i = 0; i < n; i++)
+        {
+            invA[i][j] = rhs[i];
+        }
+    }
+
+
+    /*
+    // Alternative using SVD. Slower and less accurate
+    tempscalarRectangularMatrix Atemp(n, n, 0);
+    for (label i = 0; i < n; i++)
+    {
+        for (label j = 0; j < n; j++)
+        {
+            Atemp[i][j] = A[i][j];
+        }
+    }
+    scalarRectangularMatrix invTemp = SVDinv(Atemp);
+    scalarSquareMatrix invA(n, n, 0);
+    for (label i = 0; i < n; i++)
+    {
+        for (label j = 0; j < n; j++)
+        {
+            invA[i][j] = invTemp[i][j];
+        }
+    }
+    */
+
+    return invA;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::updateMethod::updateMethod
+(
+    const fvMesh& mesh,
+    const dictionary& dict
+)
+:
+    mesh_(mesh),
+    dict_(dict),
+    optMethodIODict_
+    (
+        IOobject
+        (
+            "updateMethodDict",
+            mesh_.time().timeName(),
+            "uniform",
+            mesh_,
+            IOobject::READ_IF_PRESENT,
+            IOobject::NO_WRITE
+        )
+    ),
+    objectiveDerivatives_(0),
+    constraintDerivatives_(0),
+    objectiveValue_(0),
+    cValues_(0),
+    correction_(0),
+    cumulativeCorrection_(0),
+    eta_(1),
+    initialEtaSet_(false),
+    correctionFolder_("correction")
+{
+    // Create folder to store corrections
+    if (Pstream::master())
+    {
+        mkDir(mesh_.time().globalPath()/"optimisation"/correctionFolder_);
+    }
+
+    // Set initial eta, if present. It might be set either in the
+    // optimisationDict or in the specific dictionary dedicated to the
+    // updateMethod
+    if (dict.readIfPresent("eta", eta_))
+    {
+        initialEtaSet_ = true;
+    }
+    else if (optMethodIODict_.readIfPresent("eta", eta_))
+    {
+        initialEtaSet_ = true;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Selectors  * * * * * * * * * * * * * * //
+
+Foam::autoPtr<Foam::updateMethod> Foam::updateMethod::New
+(
+    const fvMesh& mesh,
+    const dictionary& dict
+)
+{
+    const word modelType(dict.get<word>("method"));
+
+    Info<< "updateMethod type : " << modelType << endl;
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown updateMethod type " << modelType
+            << nl << nl
+            << "Valid updateMethod types are :" << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return autoPtr<updateMethod>(cstrIter()(mesh, dict));
+}
+
+
+// * * * * * * * * * * * * * * *  Member Functions   * * * * * * * * * * * * //
+
+void Foam::updateMethod::setObjectiveDeriv(const scalarField& derivs)
+{
+    objectiveDerivatives_ = derivs;
+}
+
+
+void Foam::updateMethod::setConstraintDeriv
+(
+    const PtrList<scalarField>& derivs
+)
+{
+    constraintDerivatives_ = derivs;
+}
+
+
+void Foam::updateMethod::setObjectiveValue(const scalar value)
+{
+    objectiveValue_ = value;
+}
+
+
+void Foam::updateMethod::setConstraintValues(const scalarField& values)
+{
+    cValues_ = values;
+}
+
+
+void Foam::updateMethod::setStep(const scalar eta)
+{
+    eta_ = eta;
+}
+
+
+Foam::scalarField& Foam::updateMethod::returnCorrection()
+{
+    computeCorrection();
+    return correction_;
+}
+
+
+void Foam::updateMethod::writeCorrection()
+{
+    if (Pstream::master())
+    {
+        // Allocate cumulativeCorrection if necessary
+        if (cumulativeCorrection_.empty())
+        {
+            cumulativeCorrection_.setSize(correction_.size(), Zero);
+        }
+        // Accumulate correction
+        cumulativeCorrection_ += correction_;
+
+        fileName correctionFile
+        (
+            correctionFolder_/"correction"+mesh_.time().timeName()
+        );
+        fileName cumulativeCorrectionFile
+        (
+            correctionFolder_/"cumulativeCorrection"+mesh_.time().timeName()
+        );
+
+        OFstream corFile(correctionFile.c_str());
+        OFstream cumulCorFile(cumulativeCorrectionFile.c_str());
+        forAll(correction_, cI)
+        {
+            corFile
+                << cI << " " << correction_[cI] << endl;
+            cumulCorFile
+                << cI << " " << cumulativeCorrection_[cI] << endl;
+        }
+    }
+}
+
+
+Foam::scalar Foam::updateMethod::computeMeritFunction()
+{
+    return objectiveValue_;
+}
+
+
+Foam::scalar Foam::updateMethod::meritFunctionDirectionalDerivative()
+{
+    return sum(objectiveDerivatives_*correction_);
+}
+
+
+bool& Foam::updateMethod::initialEtaSet()
+{
+    return initialEtaSet_;
+}
+
+
+void Foam::updateMethod::updateOldCorrection
+(
+    const scalarField& oldCorrection
+)
+{
+    correction_ = oldCorrection;
+}
+
+
+void Foam::updateMethod::write()
+{
+    // Insert eta if set
+    if (initialEtaSet_)
+    {
+        optMethodIODict_.add<scalar>("eta", eta_, true);
+    }
+
+    // Write IOdictionary
+    optMethodIODict_.regIOobject::write();
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.H
new file mode 100644
index 0000000000000000000000000000000000000000..2888f6b41bfc2d7c8af35ec3f804cec9de1d839c
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.H
@@ -0,0 +1,236 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::updateMethod
+
+Description
+    Abstract base class for optimisation methods
+
+SourceFiles
+    updateMethod.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef updateMethod_H
+#define updateMethod_H
+
+#include "runTimeSelectionTables.H"
+#include "IOdictionary.H"
+#include "fvMesh.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class updateMethod Declaration
+\*---------------------------------------------------------------------------*/
+
+class updateMethod
+{
+protected:
+
+    // Protected data
+
+        const fvMesh& mesh_;
+
+        const dictionary dict_;
+
+        //- Used to output values useful for continuation runs
+        IOdictionary optMethodIODict_;
+
+        //- Derivatives of the objective functions
+        scalarField objectiveDerivatives_;
+
+        //- Derivatives of the constraints
+        PtrList<scalarField> constraintDerivatives_;
+
+        //- Objective value
+        scalar objectiveValue_;
+
+        //- Constraint values
+        scalarField cValues_;
+
+        //- Design variables correction
+        scalarField correction_;
+
+        //- Cumulative design variables correction throughout the optimisation
+        //- loop
+        scalarField cumulativeCorrection_;
+
+        //- Step multiplying the correction
+        scalar eta_;
+
+        //- Is initially set?
+        bool initialEtaSet_;
+
+        //- Folder storing the corrections to file
+        //  For some optimisation methods with a very high number of
+        //  design variables (e.g. topology), it doesn't make much sense
+        //  to write all updates in the updateMethodDict. Hence, a
+        //  separate file is used to write the corrections, in case they are
+        //  needed for post-processing
+        word correctionFolder_;
+
+        // scalar -- matrix multiplications
+        const scalarField leftMult
+        (
+            const scalarField&,
+            const SquareMatrix<scalar>&
+        );
+
+        const scalarField rightMult
+        (
+            const SquareMatrix<scalar>&,
+            const scalarField&
+        );
+
+        SquareMatrix<scalar> outerProd
+        (
+            const scalarField&,
+            const scalarField&
+        );
+
+        SquareMatrix<scalar> inv(SquareMatrix<scalar> A);
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        updateMethod(const updateMethod&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const updateMethod&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("updateMethod");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            updateMethod,
+            dictionary,
+            (
+                const fvMesh& mesh,
+                const dictionary& dict
+            ),
+            (mesh, dict)
+        );
+
+
+    // Constructors
+
+        //- Construct from components
+        updateMethod
+        (
+            const fvMesh& mesh,
+            const dictionary& dict
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<updateMethod> New
+        (
+            const fvMesh& mesh,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~updateMethod() = default;
+
+
+    // Member Functions
+
+       //- Set objective derivative
+       void setObjectiveDeriv(const scalarField& derivs);
+
+       //- Set constraints derivative
+       void setConstraintDeriv(const PtrList<scalarField>& derivs);
+
+       //- Set constraints derivative
+       void setObjectiveValue(const scalar value);
+
+       //- Set constraints derivative
+       void setConstraintValues(const scalarField& values);
+
+       //- Set step for optimisation methods
+       void setStep(const scalar eta);
+
+       //- Return the correction of the design variables
+       virtual void computeCorrection()=0;
+
+       //- Return the correction of the design variables
+       //const scalarField& returnCorrection() const;
+
+       //- Return the correction of the design variables
+       scalarField& returnCorrection();
+
+       void writeCorrection();
+
+       //- Compute merit function. Could be different than the objective
+       //- in the presence of constraints
+       virtual scalar computeMeritFunction();
+
+       //- Directional derivative of the merit function, in the direction of
+       //- the correction. Could be different than the objective directional
+       //- derivative in the presence of constraints
+       virtual scalar meritFunctionDirectionalDerivative();
+
+       //- Return whether initial eta was set
+       bool& initialEtaSet();
+
+       //- Update old correction. useful for quasi-newton methods coupled with
+       //- line search
+       virtual void updateOldCorrection(const scalarField& oldCorrection);
+
+       //- Write usefull quantities to files
+       virtual void write();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.C b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.C
new file mode 100644
index 0000000000000000000000000000000000000000..3685d0d881e4168340db7491e2754bcf891589b2
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.C
@@ -0,0 +1,301 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointSolverManager.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(adjointSolverManager, 0);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::adjointSolverManager::adjointSolverManager
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict
+)
+:
+    regIOobject
+    (
+        IOobject
+        (
+            "adjointSolverManager" + dict.dictName(),
+            mesh.time().system(),
+            mesh,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE,
+            true //register object
+        )
+    ),
+    mesh_(mesh),
+    dict_(dict),
+    managerName_(dict.dictName()),
+    primalSolverName_(dict.get<word>("primalSolver")),
+    adjointSolvers_(0),
+    objectiveSolverIDs_(0),
+    constraintSolverIDs_(0),
+    operatingPointWeight_
+    (
+        dict.lookupOrDefault<scalar>("operatingPointWeight", 1)
+    )
+{
+    const dictionary& adjointSolversDict = dict.subDict("adjointSolvers");
+
+    const wordList adjSolverNames = adjointSolversDict.toc();
+    adjointSolvers_.setSize(adjSolverNames.size());
+    objectiveSolverIDs_.setSize(adjSolverNames.size());
+    constraintSolverIDs_.setSize(adjSolverNames.size());
+    label nObjectives(0);
+    label nConstraints(0);
+    forAll(adjSolverNames, namei)
+    {
+        adjointSolvers_.set
+        (
+            namei,
+            adjointSolver::New
+            (
+                mesh_,
+                managerType,
+                adjointSolversDict.subDict(adjSolverNames[namei]),
+                primalSolverName_
+            )
+        );
+
+        if (adjointSolvers_[namei].isConstraint())
+        {
+            constraintSolverIDs_[nConstraints++] = namei;
+        }
+        else
+        {
+            objectiveSolverIDs_[nObjectives++] = namei;
+        }
+    }
+    objectiveSolverIDs_.setSize(nObjectives);
+    constraintSolverIDs_.setSize(nConstraints);
+
+    Info<< "Found " << nConstraints
+        << " adjoint solvers acting as constraints" << endl;
+
+    // Having more than one non-aggregated objectives per operating point
+    // is needlessly expensive. Issue a warning
+    if (objectiveSolverIDs_.size() > 1)
+    {
+        WarningInFunction
+            << "Number of adjoint solvers corresponding to objectives "
+            << "is greater than 1 (" << objectiveSolverIDs_.size() << ")" << nl
+            << "Consider aggregating your objectives to one" << endl;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::adjointSolverManager::readDict(const dictionary& dict)
+{
+    dict_ = dict;
+
+    const dictionary& adjointSolversDict = dict.subDict("adjointSolvers");
+
+    // Note: only updating existing solvers
+    for (adjointSolver& solver : adjointSolvers_)
+    {
+        solver.readDict(adjointSolversDict.subDict(solver.name()));
+    }
+
+    return true;
+}
+
+
+const Foam::word& Foam::adjointSolverManager::managerName() const
+{
+    return managerName_;
+}
+
+
+const Foam::dictionary& Foam::adjointSolverManager::dict() const
+{
+    return dict_;
+}
+
+
+const Foam::PtrList<Foam::adjointSolver>&
+Foam::adjointSolverManager::adjointSolvers() const
+{
+    return adjointSolvers_;
+}
+
+
+Foam::PtrList<Foam::adjointSolver>&
+Foam::adjointSolverManager::adjointSolvers()
+{
+    return adjointSolvers_;
+}
+
+
+Foam::scalar Foam::adjointSolverManager::operatingPointWeight() const
+{
+    return operatingPointWeight_;
+}
+
+
+Foam::label Foam::adjointSolverManager::nConstraints() const
+{
+    return constraintSolverIDs_.size();
+}
+
+
+Foam::label Foam::adjointSolverManager::nObjectives() const
+{
+    return objectiveSolverIDs_.size();
+}
+
+
+Foam::label Foam::adjointSolverManager::nAdjointSolvers() const
+{
+    return nConstraints() + nObjectives();
+}
+
+
+void Foam::adjointSolverManager::solveAdjointEquations()
+{
+    for (adjointSolver& solver : adjointSolvers_)
+    {
+        objectiveManager& objManager = solver.getObjectiveManager();
+
+        // Update objective function related quantities
+        objManager.updateAndWrite();
+
+        // Solve the adjoint equations taking into consideration the weighted
+        // contribution of possibly multiple objectives
+        solver.solve();
+    }
+}
+
+
+Foam::tmp<Foam::scalarField>
+Foam::adjointSolverManager::aggregateSensitivities()
+{
+    tmp<scalarField> tsens(new scalarField(0));
+    scalarField& sens = tsens.ref();
+
+    // Sum sensitivities from all objectives expect the constraints
+    for (const label solveri : objectiveSolverIDs_)
+    {
+        // Sum contributions
+        const scalarField& solverSens =
+            adjointSolvers_[solveri].getObjectiveSensitivities();
+
+        if (sens.empty())
+        {
+            sens = scalarField(solverSens.size(), Zero);
+        }
+        sens += solverSens;
+    }
+
+    return tsens;
+}
+
+
+Foam::PtrList<Foam::scalarField>
+Foam::adjointSolverManager::constraintSensitivities()
+{
+    PtrList<scalarField> constraintSens(constraintSolverIDs_.size());
+    forAll(constraintSens, cI)
+    {
+        label consI = constraintSolverIDs_[cI];
+        constraintSens.set
+        (
+            cI,
+            new scalarField(adjointSolvers_[consI].getObjectiveSensitivities())
+        );
+    }
+
+    return constraintSens;
+}
+
+
+void Foam::adjointSolverManager::computeAllSensitivities()
+{
+    for (adjointSolver& adjSolver : adjointSolvers_)
+    {
+        adjSolver.clearSensitivities();
+        adjSolver.computeObjectiveSensitivities();
+    }
+}
+
+
+Foam::scalar Foam::adjointSolverManager::objectiveValue()
+{
+    scalar objValue(Zero);
+    for (const label solveri : objectiveSolverIDs_)
+    {
+        objectiveManager& objManager =
+            adjointSolvers_[objectiveSolverIDs_[solveri]].getObjectiveManager();
+        objValue += objManager.print();
+    }
+
+    return objValue;
+}
+
+
+Foam::tmp<Foam::scalarField> Foam::adjointSolverManager::constraintValues()
+{
+    tmp<scalarField> tconstraintValues
+    (
+        new scalarField(constraintSolverIDs_.size(), Zero)
+    );
+    scalarField& constraintValues = tconstraintValues.ref();
+    forAll(constraintValues, cI)
+    {
+        objectiveManager& objManager =
+            adjointSolvers_[constraintSolverIDs_[cI]].getObjectiveManager();
+        constraintValues[cI] = objManager.print();
+    }
+
+    return tconstraintValues;
+}
+
+
+void Foam::adjointSolverManager::updatePrimalBasedQuantities(const word& name)
+{
+    if (primalSolverName_ == name)
+    {
+        for (adjointSolver& solver : adjointSolvers_)
+        {
+            solver.updatePrimalBasedQuantities();
+        }
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.H b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.H
new file mode 100644
index 0000000000000000000000000000000000000000..b1fc9901334086e6928fa2c7e19722e15800521e
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.H
@@ -0,0 +1,187 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointSolverManager
+
+Description
+    Class for managing adjoint solvers, which may be more than one per
+    operating point
+
+SourceFiles
+    adjointSolverManager.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointSolverManager_H
+#define adjointSolverManager_H
+
+#include "adjointSolver.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                     Class adjointSolverManager Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointSolverManager
+:
+    public regIOobject
+{
+private:
+
+    // Private Member Functions
+
+        //- No  copy construct
+        adjointSolverManager(const adjointSolverManager&) = delete;
+
+        //- No copy assignment
+        void operator=(const adjointSolverManager&) = delete;
+
+
+protected:
+
+    // Protected Data
+
+        fvMesh& mesh_;
+
+        dictionary dict_;
+
+        const word managerName_;
+
+        const word primalSolverName_;
+
+        PtrList<adjointSolver> adjointSolvers_;
+
+        labelList objectiveSolverIDs_;
+
+        labelList constraintSolverIDs_;
+
+        scalar operatingPointWeight_;
+
+
+public:
+
+    TypeName("adjointSolverManager");
+
+
+    // Constructors
+
+        //- Construct from components
+        adjointSolverManager
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~adjointSolverManager() = default;
+
+
+    // Member Functions
+
+        virtual bool readDict(const dictionary& dict);
+
+
+        // Access
+
+            //- Const access to the manager name
+            const word& managerName() const;
+
+            //- Const access to the construction dictionary
+            const dictionary& dict() const;
+
+            //- Const access to adjoint solvers
+            const PtrList<adjointSolver>& adjointSolvers() const;
+
+            //- Non-const access to adjoint solvers
+            PtrList<adjointSolver>& adjointSolvers();
+
+            //- Const access to adjoint solvers
+            scalar operatingPointWeight() const;
+
+            //- Number of adjoint solvers corresponding to contraints
+            label nConstraints() const;
+
+            //- Number of adjoint solvers corresponding to objectives
+            label nObjectives() const;
+
+            //- Total number of adjoint solvers
+            label nAdjointSolvers() const;
+
+
+        // Evolution
+
+            //- Update objective function-related values and solve adjoint
+            //- equations
+            virtual void solveAdjointEquations();
+
+            //- Aggregate sensitivities from various adjoint solvers
+            virtual tmp<scalarField> aggregateSensitivities();
+
+            //- Get constraint sensitivities. One scalarField per constraint
+            virtual PtrList<scalarField> constraintSensitivities();
+
+            //- Compute sensitivities for all adjoint solvers
+            //- (both objective- and constraint-related ones)
+            //- Clears previous sensitivity fields
+            void computeAllSensitivities();
+
+            //- Get objective value
+            scalar objectiveValue();
+
+            //- Get constraint values
+            virtual tmp<scalarField> constraintValues();
+
+            //- Update fields related to primal solution.
+            //  For instance, primal fields of adjoint turbulence models
+            void updatePrimalBasedQuantities(const word& name);
+
+
+        // IO
+
+            virtual bool writeData(Ostream&) const
+            {
+                return true;
+            }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.C b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.C
new file mode 100644
index 0000000000000000000000000000000000000000..faab8a9e345c43e5b1d2fa72518beca910f9c47b
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.C
@@ -0,0 +1,152 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointSolver.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(adjointSolver, 0);
+    defineRunTimeSelectionTable(adjointSolver, adjointSolver);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::adjointSolver::adjointSolver
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict,
+    const word& primalSolverName
+)
+:
+    solver(mesh, managerType, dict),
+    primalSolverName_(primalSolverName),
+    objectiveManagerPtr_
+    (
+        objectiveManager::New
+        (
+            mesh,
+            dict.subDict("objectives"),
+            solverName_,
+            primalSolverName
+        )
+    ),
+    sensitivities_(nullptr),
+    computeSensitivities_
+    (
+        dict.lookupOrDefault<bool>("computeSensitivities", true)
+    ),
+    isConstraint_(dict.lookupOrDefault<bool>("isConstraint", false))
+{
+    // Update objective-related quantities to get correct derivatives
+    // in case of continuation
+    objectiveManagerPtr_().update();
+}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+Foam::autoPtr<Foam::adjointSolver> Foam::adjointSolver::New
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict,
+    const word& primalSolverName
+)
+{
+    const word adjointSolverType(dict.get<word>("type"));
+    auto cstrIter = adjointSolverConstructorTablePtr_->cfind(adjointSolverType);
+
+    if (!cstrIter.found())
+    {
+        FatalIOErrorInFunction(dict)
+            << "Unknown adjointSolver type " << adjointSolverType << nl << nl
+            << "Valid adjointSolver types are :" << nl
+            << adjointSolverConstructorTablePtr_->sortedToc()
+            << exit(FatalIOError);
+    }
+
+    return autoPtr<adjointSolver>
+    (
+        cstrIter()(mesh, managerType, dict, primalSolverName)
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::adjointSolver::readDict(const dictionary& dict)
+{
+    if (solver::readDict(dict))
+    {
+        computeSensitivities_ =
+            dict.lookupOrDefault<bool>("computeSensitivities", true);
+
+        objectiveManagerPtr_->readDict(dict.subDict("objectives"));
+
+        return true;
+    }
+
+    return false;
+}
+
+
+const Foam::objectiveManager& Foam::adjointSolver::getObjectiveManager() const
+{
+    return objectiveManagerPtr_();
+}
+
+
+Foam::objectiveManager& Foam::adjointSolver::getObjectiveManager()
+{
+    return objectiveManagerPtr_();
+}
+
+
+bool Foam::adjointSolver::isConstraint()
+{
+    return isConstraint_;
+}
+
+
+void Foam::adjointSolver::clearSensitivities()
+{
+    sensitivities_.clear();
+}
+
+
+void Foam::adjointSolver::updatePrimalBasedQuantities()
+{
+    // Does nothing in base
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.H b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.H
new file mode 100644
index 0000000000000000000000000000000000000000..c5a9e550211c2d1c1f9d7b1c83c8f54caa8a55cc
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.H
@@ -0,0 +1,195 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointSolver
+
+Description
+    Base class for adjoint solvers
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointSolver_H
+#define adjointSolver_H
+
+#include "fvMesh.H"
+#include "Time.H"
+#include "IOdictionary.H"
+#include "solver.H"
+#include "objectiveManager.H"
+#include "sensitivity.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class adjointSolver Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointSolver
+:
+    public solver
+{
+private:
+
+    // Private Member Functions
+
+        //- No copy construct
+        adjointSolver(const adjointSolver&) = delete;
+
+        //- No copy assignment
+        void operator=(const adjointSolver&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        //- Name of primal solver
+        const word primalSolverName_;
+
+        //- Object to manage objective functions
+        autoPtr<objectiveManager> objectiveManagerPtr_;
+
+        //- Sensitivities field
+        tmp<scalarField> sensitivities_;
+
+        //- Are sensitivities computed
+        bool computeSensitivities_;
+
+        //- Is the adjoint solver used to tackle a constraint
+        bool isConstraint_;
+
+
+public:
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("adjointSolver");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeNewSelectionTable
+        (
+            autoPtr,
+            adjointSolver,
+            adjointSolver,
+            (
+                fvMesh& mesh,
+                const word& managerType,
+                const dictionary& dict,
+                const word& primalSolverName
+            ),
+            (mesh, managerType, dict, primalSolverName)
+        );
+
+
+    // Constructors
+
+        //- Construct from mesh, dictionary, and primal solver name
+        adjointSolver
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict,
+            const word& primalSolverName
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<adjointSolver> New
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict,
+            const word& primalSolverName
+        );
+
+
+    //- Destructor
+    virtual ~adjointSolver() = default;
+
+
+    // Member Functions
+
+        // Access
+
+            virtual bool readDict(const dictionary& dict);
+
+            //- Return the primal solver name
+            const word& primalSolverName() const
+            {
+                return primalSolverName_;
+            }
+
+            //- Return a const reference to the objective manager
+            const objectiveManager& getObjectiveManager() const;
+
+            //- Return a reference to the objective manager
+            objectiveManager& getObjectiveManager();
+
+
+        // Evolution
+
+            //- Compute sensitivities of the underlaying objectives
+            virtual void computeObjectiveSensitivities() = 0;
+
+            //- Is the solving referring to a constraint
+            virtual bool isConstraint();
+
+            //- Grab a reference to the computed sensitivities
+            virtual const scalarField& getObjectiveSensitivities() = 0;
+
+            //- Clears the sensitivity field known by the adjoint solver
+            virtual void clearSensitivities();
+
+            //- Return the base sensitivity object
+            virtual sensitivity& getSensitivityBase() = 0;
+
+            //- Update primal based quantities, e.g. the primal fields
+            //- in adjoint turbulence models
+            //  Does nothing in the base
+            virtual void updatePrimalBasedQuantities();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C
new file mode 100644
index 0000000000000000000000000000000000000000..da4adf5b79f24df7ed3b7431392f120ae6da0c83
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C
@@ -0,0 +1,381 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointSimple.H"
+#include "findRefCell.H"
+#include "constrainHbyA.H"
+#include "adjustPhi.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(adjointSimple, 0);
+    addToRunTimeSelectionTable
+    (
+        incompressibleAdjointSolver,
+        adjointSimple,
+        dictionary
+    );
+}
+
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+void Foam::adjointSimple::addExtraSchemes()
+{
+    if (getAdjointVars().useSolverNameForFields())
+    {
+        WarningInFunction
+            << "useSolverNameForFields is set to true for adjointSolver "
+            << solverName() << nl << tab
+            << "Appending variable names with the solver name" << nl << tab
+            << "Please adjust the necessary entries in fvSchemes and fvSolution"
+            << nl << endl;
+    }
+}
+
+
+void Foam::adjointSimple::continuityErrors()
+{
+    const surfaceScalarField& phia = getAdjointVars().phiaInst();
+    volScalarField contErr(fvc::div(phia));
+
+    scalar sumLocalContErr = mesh_.time().deltaTValue()*
+        mag(contErr)().weightedAverage(mesh_.V()).value();
+
+    scalar globalContErr = mesh_.time().deltaTValue()*
+        contErr.weightedAverage(mesh_.V()).value();
+    cumulativeContErr_ += globalContErr;
+
+    Info<< "time step continuity errors : sum local = " << sumLocalContErr
+        << ", global = " << globalContErr
+        << ", cumulative = " << cumulativeContErr_
+        << endl;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::adjointSimple::adjointSimple
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict,
+    const word& primalSolverName
+)
+:
+    incompressibleAdjointSolver(mesh, managerType, dict, primalSolverName),
+    solverControl_(SIMPLEControl::New(mesh, managerType, *this)),
+    cumulativeContErr_(Zero),
+    adjointSensitivity_(nullptr)
+{
+    adjointVars_.reset
+    (
+        new incompressibleAdjointVars
+        (
+            mesh,
+            solverControl_(),
+            objectiveManagerPtr_(),
+            primalVars_
+        )
+    ),
+    ATCModel_.reset
+    (
+        ATCModel::New
+        (
+            mesh,
+            primalVars_,
+            getAdjointVars(),
+            dict.subDict("ATCModel")
+        ).ptr()
+    );
+
+    addExtraSchemes();
+    setRefCell
+    (
+        getAdjointVars().paInst(),
+        solverControl_().dict(),
+        solverControl_().pRefCell(),
+        solverControl_().pRefValue()
+    );
+
+    if (computeSensitivities_)
+    {
+        const IOdictionary& optDict =
+            mesh.lookupObject<IOdictionary>("optimisationDict");
+
+        adjointSensitivity_.reset
+        (
+            incompressible::adjointSensitivity::New
+            (
+                mesh,
+                optDict.subDict("optimisation").subDict("sensitivities"),
+                primalVars_,
+                getAdjointVars(),
+                objectiveManagerPtr_(),
+                fvOptionsAdjoint_
+            ).ptr()
+        );
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::adjointSimple::readDict(const dictionary& dict)
+{
+    if (incompressibleAdjointSolver::readDict(dict))
+    {
+        if (adjointSensitivity_.valid())
+        {
+            const IOdictionary& optDict =
+                mesh_.lookupObject<IOdictionary>("optimisationDict");
+
+            adjointSensitivity_().readDict
+            (
+                optDict.subDict("optimisation").subDict("sensitivities")
+            );
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+
+void Foam::adjointSimple::solveIter()
+{
+    const Time& time = mesh_.time();
+    Info<< "Time = " << time.timeName() << "\n" << endl;
+
+    // Grab primal references
+    const surfaceScalarField& phi = primalVars_.phi();
+    // Grab adjoint references
+    incompressibleAdjointVars& adjointVars = getAdjointVars();
+    volScalarField& pa = adjointVars.paInst();
+    volVectorField& Ua = adjointVars.UaInst();
+    surfaceScalarField& phia = adjointVars.phiaInst();
+    autoPtr<incompressibleAdjoint::adjointRASModel>& adjointTurbulence =
+        adjointVars.adjointTurbulence();
+    const label&  paRefCell  = solverControl_().pRefCell();
+    const scalar& paRefValue = solverControl_().pRefValue();
+
+    // Momentum predictor
+    //~~~~~~~~~~~~~~~~~~~
+
+    tmp<fvVectorMatrix> tUaEqn
+    (
+        fvm::div(-phi, Ua)
+      + adjointTurbulence->divDevReff(Ua)
+      + adjointTurbulence->adjointMeanFlowSource()
+      ==
+        fvOptionsAdjoint_(Ua)
+    );
+    fvVectorMatrix& UaEqn = tUaEqn.ref();
+
+    // Add sources from boundary conditions
+    UaEqn.boundaryManipulate(Ua.boundaryFieldRef());
+
+    // Add sources from volume-based objectives
+    objectiveManagerPtr_().addUaEqnSource(UaEqn);
+
+    // Add ATC term
+    ATCModel_->addATC(UaEqn);
+
+    // Add source from optimisationType (e.g. topology)
+    addOptimisationTypeSource(UaEqn);
+
+    UaEqn.relax();
+
+    fvOptionsAdjoint_.constrain(UaEqn);
+
+    if (solverControl_().momentumPredictor())
+    {
+        Foam::solve(UaEqn == -fvc::grad(pa));
+
+        fvOptionsAdjoint_.correct(Ua);
+    }
+
+    // Pressure Eq
+    //~~~~~~~~~~~~
+    {
+        volScalarField rAUa(1.0/UaEqn.A());
+        // 190402: Vag: to be updated.
+        // Probably a constrainHabyA by class is needed?
+        volVectorField HabyA(constrainHbyA(rAUa*UaEqn.H(), Ua, pa));
+        surfaceScalarField phiaHbyA("phiaHbyA", fvc::flux(HabyA));
+        adjustPhi(phiaHbyA, Ua, pa);
+
+        tmp<volScalarField> rAtUa(rAUa);
+
+        if (solverControl_().consistent())
+        {
+            rAtUa = 1.0/(1.0/rAUa - UaEqn.H1());
+            phiaHbyA +=
+                fvc::interpolate(rAtUa() - rAUa)*fvc::snGrad(pa)*mesh_.magSf();
+            HabyA -= (rAUa - rAtUa())*fvc::grad(pa);
+        }
+
+        tUaEqn.clear();
+
+        // Update the pressure BCs to ensure flux consistency
+        // constrainPressure(p, U, phiHbyA, rAtU(), MRF_);
+
+        // Non-orthogonal pressure corrector loop
+        while (solverControl_().correctNonOrthogonal())
+        {
+            fvScalarMatrix paEqn
+            (
+                fvm::laplacian(rAtUa(), pa) == fvc::div(phiaHbyA)
+            );
+
+            paEqn.boundaryManipulate(pa.boundaryFieldRef());
+
+            paEqn.setReference(paRefCell, paRefValue);
+
+            paEqn.solve();
+
+            if (solverControl_().finalNonOrthogonalIter())
+            {
+                phia = phiaHbyA - paEqn.flux();
+            }
+        }
+
+        continuityErrors();
+
+        // Explicitly relax pressure for adjoint momentum corrector
+        pa.relax();
+
+        // Momentum corrector
+        Ua = HabyA - rAtUa()*fvc::grad(pa);
+        Ua.correctBoundaryConditions();
+        fvOptionsAdjoint_.correct(Ua);
+        pa.correctBoundaryConditions();
+    }
+
+    adjointTurbulence->correct();
+
+    if (solverControl_().printMaxMags())
+    {
+        dimensionedScalar maxUa = max(mag(Ua));
+        dimensionedScalar maxpa = max(mag(pa));
+        Info<< "Max mag of adjoint velocity = " << maxUa.value() << endl;
+        Info<< "Max mag of adjoint pressure = " << maxpa.value() << endl;
+    }
+
+    solverControl_().write();
+
+    // Average fields if necessary
+    adjointVars.computeMeanFields();
+
+    // Print execution time
+    time.printExecutionTime(Info);
+}
+
+
+void Foam::adjointSimple::solve()
+{
+    if (active_)
+    {
+        // Reset mean fields before solving
+        getAdjointVars().resetMeanFields();
+
+        // Iterate
+        while (solverControl_().loop())
+        {
+            solveIter();
+        }
+    }
+}
+
+
+bool Foam::adjointSimple::loop()
+{
+    return solverControl_().loop();
+}
+
+
+void Foam::adjointSimple::computeObjectiveSensitivities()
+{
+    if (computeSensitivities_)
+    {
+        sensitivities_.reset
+        (
+            new scalarField(adjointSensitivity_().calculateSensitivities())
+        );
+    }
+    else
+    {
+        sensitivities_.reset(new scalarField(0));
+    }
+}
+
+
+const Foam::scalarField& Foam::adjointSimple::getObjectiveSensitivities()
+{
+    if (!sensitivities_.valid())
+    {
+        computeObjectiveSensitivities();
+    }
+
+    return sensitivities_();
+}
+
+
+Foam::sensitivity& Foam::adjointSimple::getSensitivityBase()
+{
+    if (adjointSensitivity_.valid())
+    {
+        return adjointSensitivity_();
+    }
+    else
+    {
+        FatalErrorInFunction
+            << "Sensitivity object not allocated \n"
+            << "Turn computeSensitivities on in "
+            << solverName_
+            << nl << nl
+            << exit(FatalError);
+
+        return adjointSensitivity_();
+    }
+}
+
+
+bool Foam::adjointSimple::writeData(Ostream& os) const
+{
+    os.writeEntry("averageIter", solverControl_().averageIter());
+
+    return true;
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.H b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.H
new file mode 100644
index 0000000000000000000000000000000000000000..4322ed8c0c65a54d07d10aa04287765fed399b67
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.H
@@ -0,0 +1,171 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointSimple
+
+Description
+    Solution of the adjoint PDEs for incompressible, steady-state flows
+
+    Reference:
+    \verbatim
+        For the development of the adjoint PDEs
+
+            Papoutsis-Kiachagias, E. M., & Giannakoglou, K. C. (2014).
+            Continuous Adjoint Methods for Turbulent Flows, Applied to Shape
+            and Topology Optimization: Industrial Applications.
+            Archives of Computational Methods in Engineering, 23(2), 255-299.
+            http://doi.org/10.1007/s11831-014-9141-9
+    \endverbatim
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointSimple_H
+#define adjointSimple_H
+
+#include "incompressibleAdjointSolver.H"
+#include "SIMPLEControl.H"
+#include "incompressibleVars.H"
+#include "incompressibleAdjointVars.H"
+#include "adjointSensitivityIncompressible.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class adjointSimple Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointSimple
+:
+    public incompressibleAdjointSolver
+{
+
+private:
+
+    // Private Member Functions
+
+        //- No copy construct
+        adjointSimple(const adjointSimple&) = delete;
+
+        //- No copy assignment
+        void operator=(const adjointSimple&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        //- Solver control
+        autoPtr<SIMPLEControl> solverControl_;
+
+        //- Cumulative continuity error
+        scalar cumulativeContErr_;
+
+        //- Sensitivity Derivatives engine
+        autoPtr<incompressible::adjointSensitivity> adjointSensitivity_;
+
+
+    // Protected Member Functions
+
+        //- In case variable names are different than the base ones,
+        //- add extra schemes and relaxation factors to the appropriate dicts
+        //  Note: 160813: Changes in the baseline solution and fvSchemes classes
+        //  have to be made in order to add schemes in the dict at run time.
+        //  Not supported for now
+        void addExtraSchemes();
+
+        //- Compute continuity errors
+        void continuityErrors();
+
+
+public:
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("adjointSimple");
+
+
+    // Constructors
+
+        //- Construct from mesh and dictionary
+        adjointSimple
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict,
+            const word& primalSolverName
+        );
+
+
+    //- Destructor
+    virtual ~adjointSimple() = default;
+
+
+    // Member Functions
+
+        //- Read dict if updated
+        virtual bool readDict(const dictionary& dict);
+
+
+        // Evolution
+
+            //- Execute one iteration of the solution algorithm
+            virtual void solveIter();
+
+            //- Main control loop
+            virtual void solve();
+
+            //- Looper (advances iters, time step)
+            virtual bool loop();
+
+            //- Compute sensitivities of the underlaying objectives
+            virtual void computeObjectiveSensitivities();
+
+            //- Grab a reference to the computed sensitivities
+            virtual const scalarField& getObjectiveSensitivities();
+
+            //- Return the base sensitivity object
+            virtual sensitivity& getSensitivityBase();
+
+            //- Write average iteration
+            virtual bool writeData(Ostream& os) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.C b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.C
new file mode 100644
index 0000000000000000000000000000000000000000..4a203611d3133fdc51284ab1443a33538f5f5ec9
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.C
@@ -0,0 +1,175 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "incompressibleAdjointSolver.H"
+#include "incompressiblePrimalSolver.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(incompressibleAdjointSolver, 0);
+    defineRunTimeSelectionTable(incompressibleAdjointSolver, dictionary);
+    addToRunTimeSelectionTable
+    (
+        adjointSolver,
+        incompressibleAdjointSolver,
+        adjointSolver
+    );
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::incompressibleAdjointSolver::incompressibleAdjointSolver
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict,
+    const word& primalSolverName
+)
+:
+    adjointSolver(mesh, managerType, dict, primalSolverName),
+    primalVars_
+    (
+        mesh.lookupObjectRef<incompressiblePrimalSolver>(primalSolverName).
+            getVars()
+    ),
+    adjointVars_(nullptr),
+    ATCModel_(nullptr),
+    fvOptionsAdjoint_
+    (
+        mesh_,
+        dict.subOrEmptyDict("fvOptions")
+    )
+{}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+Foam::autoPtr<Foam::incompressibleAdjointSolver>
+Foam::incompressibleAdjointSolver::New
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict,
+    const word& primalSolverName
+)
+{
+    const word solverType(dict.get<word>("solver"));
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(solverType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown incompressibleAdjointSolver type "
+            << solverType << nl << nl
+            << "Valid incompressibleAdjointSolver types are :" << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return
+        autoPtr<incompressibleAdjointSolver>
+        (
+            cstrIter()(mesh, managerType, dict, primalSolverName)
+        );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::incompressibleAdjointSolver::readDict(const dictionary& dict)
+{
+    if (adjointSolver::readDict(dict))
+    {
+        fvOptionsAdjoint_.read(dict.subOrEmptyDict("fvOptions"));
+
+        return true;
+    }
+
+    return false;
+}
+
+bool Foam::incompressibleAdjointSolver::useSolverNameForFields() const
+{
+    return getAdjointVars().useSolverNameForFields();
+}
+
+
+const Foam::incompressibleVars&
+Foam::incompressibleAdjointSolver::getPrimalVars() const
+{
+    return primalVars_;
+}
+
+
+
+const Foam::incompressibleAdjointVars&
+Foam::incompressibleAdjointSolver::getAdjointVars() const
+{
+    return adjointVars_();
+}
+
+
+Foam::incompressibleAdjointVars&
+Foam::incompressibleAdjointSolver::getAdjointVars()
+{
+    return adjointVars_.ref();
+}
+
+
+
+const Foam::autoPtr<Foam::ATCModel>&
+Foam::incompressibleAdjointSolver::getATCModel() const
+{
+    return ATCModel_;
+}
+
+
+Foam::autoPtr<Foam::ATCModel>& Foam::incompressibleAdjointSolver::getATCModel()
+{
+    return ATCModel_;
+}
+
+
+Foam::fv::optionAdjointList&
+Foam::incompressibleAdjointSolver::getFvOptionsAdjoint()
+{
+    return fvOptionsAdjoint_;
+}
+
+
+void Foam::incompressibleAdjointSolver::updatePrimalBasedQuantities()
+{
+    getAdjointVars().adjointTurbulence()->setChangedPrimalSolution();
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.H b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.H
new file mode 100644
index 0000000000000000000000000000000000000000..0b33408dad8897d540919de1664a24bf5d10a74e
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.H
@@ -0,0 +1,216 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressibleAdjointSolver
+
+Description
+    Base class for incompressibleAdjoint solvers
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef incompressibleAdjointSolver_H
+#define incompressibleAdjointSolver_H
+
+#include "adjointSolver.H"
+#include "incompressibleVars.H"
+#include "incompressibleAdjointVars.H"
+#include "ATCModel.H"
+#include "fvOptionAdjointList.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                 Class incompressibleAdjointSolver Declaration
+\*---------------------------------------------------------------------------*/
+
+class incompressibleAdjointSolver
+:
+    public adjointSolver
+{
+private:
+
+    // Private Member Functions
+
+        //- No copy construct
+        incompressibleAdjointSolver
+        (
+            const incompressibleAdjointSolver&
+        ) = delete;
+
+        //- No copy assignment
+        void operator=(const incompressibleAdjointSolver&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        //- Primal variable set
+        incompressibleVars& primalVars_;
+
+        //- Adjoint variable set
+        //- Needs to be allocated in each derived class since it requires
+        //- a solverControl variable which is specifically allocated there
+        //  (e.g. SIMPLEControl for simple)
+        autoPtr<incompressibleAdjointVars> adjointVars_;
+
+        //- Adjoint Transpose Convection options
+        autoPtr<ATCModel> ATCModel_;
+
+        //- optionList for source terms addition
+        fv::optionAdjointList fvOptionsAdjoint_;
+
+
+public:
+
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("incompressible");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            incompressibleAdjointSolver,
+            dictionary,
+            (
+                fvMesh& mesh,
+                const word& managerType,
+                const dictionary& dict,
+                const word& primalSolverName
+            ),
+            (mesh, managerType, dict, primalSolverName)
+        );
+
+
+    // Constructors
+
+        //- Construct from mesh and dictionary
+        incompressibleAdjointSolver
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict,
+            const word& primalSolverName
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected incompressible adjoint solver
+        static autoPtr<incompressibleAdjointSolver> New
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict,
+            const word& primalSolverName
+        );
+
+
+    //- Destructor
+    virtual ~incompressibleAdjointSolver() = default;
+
+
+    // Member Functions
+
+        //- Read dict if updated
+        virtual bool readDict(const dictionary& dict);
+
+        //- Should solver name be appended to fields
+        bool useSolverNameForFields() const;
+
+
+        // Access
+
+            //- Access to the incompressible primal variables set
+            const incompressibleVars& getPrimalVars() const;
+
+            //- Access to the incompressible adjoint variables set
+            virtual const incompressibleAdjointVars& getAdjointVars() const;
+
+            //- Access to the incompressible adjoint variables set
+            virtual incompressibleAdjointVars& getAdjointVars();
+
+            //- Access to the ATC model
+            const autoPtr<ATCModel>& getATCModel() const;
+
+            //- Access to the ATC model
+            autoPtr<ATCModel>& getATCModel();
+
+            //- Access to fvOptionsAdjointList
+            fv::optionAdjointList& getFvOptionsAdjoint();
+
+
+        // Evolution
+
+            //- Update primal based quantities, e.g. the primal fields
+            //- in adjoint turbulence models
+            virtual void updatePrimalBasedQuantities();
+
+
+        // IO
+
+            //- In case of multi-point runs with turbulent flows,
+            //- output dummy turbulence fields with the base names, to allow
+            //- continuation
+            virtual bool write(const bool valid = true) const
+            {
+                if (mesh_.time().writeTime())
+                {
+                    return primalVars_.write();
+                }
+
+                return false;
+            }
+
+            //- In case of multi-point runs with turbulent flows,
+            //- output dummy turbulence fields with the base names, to allow
+            //- continuation
+            virtual bool writeNow() const
+            {
+                return primalVars_.write();
+            }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.C b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.C
new file mode 100644
index 0000000000000000000000000000000000000000..d6b4a31a3b49e11eb6fba7da51865ec5e9584d64
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.C
@@ -0,0 +1,118 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "RASTurbulenceModel.H"
+#include "findRefCell.H"
+#include "Time.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(RASTurbulenceModel, 0);
+    addToRunTimeSelectionTable
+    (
+        incompressiblePrimalSolver,
+        RASTurbulenceModel,
+        dictionary
+    );
+}
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::RASTurbulenceModel::RASTurbulenceModel
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict
+)
+:
+    incompressiblePrimalSolver(mesh, managerType, dict),
+    solverControl_(SIMPLEControl::New(mesh, managerType, *this))
+{
+    vars_.reset(new incompressibleVars(mesh, solverControl_()));
+    setRefCell
+    (
+        vars_().pInst(),
+        solverControl_().dict(),
+        solverControl_().pRefCell(),
+        solverControl_().pRefValue()
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::RASTurbulenceModel::solveIter()
+{
+    const Time& time = mesh_.time();
+    Info<< "Time = " << time.timeName() << "\n" << endl;
+
+    // Grab references
+    autoPtr<incompressible::turbulenceModel>& turbulence = vars_().turbulence();
+    turbulence->correct();
+
+    solverControl_().write();
+
+    // Average fields if necessary
+    vars_().computeMeanFields();
+
+    time.printExecutionTime(Info);
+}
+
+
+void Foam::RASTurbulenceModel::solve()
+{
+    // Iterate
+    if (active_)
+    {
+        // Reset initial and mean fields before solving
+        while (solverControl_().loop())
+        {
+            solveIter();
+        }
+    }
+}
+
+
+bool Foam::RASTurbulenceModel::loop()
+{
+    return solverControl_().loop();
+}
+
+
+bool Foam::RASTurbulenceModel::writeData(Ostream& os) const
+{
+    os.writeEntry("averageIter", solverControl_().averageIter());
+
+    return true;
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.H b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.H
new file mode 100644
index 0000000000000000000000000000000000000000..7b826f71ceaa02913bcda146a1899a0f57b72e07
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.H
@@ -0,0 +1,125 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::RASTurbulenceModel
+
+Description
+    Solves for a RAS turbulence model, with constant U and phi values
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef RASTurbulenceModel_H
+#define RASTurbulenceModel_H
+
+#include "incompressiblePrimalSolver.H"
+#include "SIMPLEControl.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class RASTurbulenceModel Declaration
+\*---------------------------------------------------------------------------*/
+
+class RASTurbulenceModel
+:
+    public incompressiblePrimalSolver
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        RASTurbulenceModel(const RASTurbulenceModel&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const RASTurbulenceModel&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        //- Solver control
+        autoPtr<SIMPLEControl> solverControl_;
+
+
+public:
+
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("RASTurbulenceModel");
+
+
+    // Constructors
+
+        //- Construct from mesh and dictionary
+        RASTurbulenceModel
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~RASTurbulenceModel() = default;
+
+
+    // Member Functions
+
+        // Evolution
+
+            //- Execute one iteration of the solution algorithm
+            virtual void solveIter();
+
+            //- Main control loop
+            virtual void solve();
+
+            //- Looper (advances iters, time step)
+            virtual bool loop();
+
+            //- Read average iteration
+            virtual bool writeData(Ostream& os) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.C b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.C
new file mode 100644
index 0000000000000000000000000000000000000000..0c85173b914efe637754097e02d70bdb41900e81
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.C
@@ -0,0 +1,243 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "incompressiblePrimalSolver.H"
+#include "adjustPhi.H"
+#include "adjointSolver.H"
+#include "addToRunTimeSelectionTable.H"
+
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(incompressiblePrimalSolver, 0);
+    defineRunTimeSelectionTable(incompressiblePrimalSolver, dictionary);
+    addToRunTimeSelectionTable
+    (
+        primalSolver,
+        incompressiblePrimalSolver,
+        primalSolver
+    );
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::incompressiblePrimalSolver::incompressiblePrimalSolver
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict
+)
+:
+    primalSolver(mesh, managerType, dict),
+    vars_(nullptr),
+    phiReconstructionTol_
+    (
+        dict.subOrEmptyDict("fieldReconstruction").
+            lookupOrDefault<scalar>("tolerance", scalar(5.e-5))
+    ),
+    phiReconstructionIters_
+    (
+        dict.subOrEmptyDict("fieldReconstruction").
+            lookupOrDefault<label>("iters", label(10))
+    ),
+    fvOptions_
+    (
+        mesh_,
+        dict.subOrEmptyDict("fvOptions")
+    )
+{}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+Foam::autoPtr<Foam::incompressiblePrimalSolver>
+Foam::incompressiblePrimalSolver::New
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict
+)
+{
+    const word solverType(dict.get<word>("solver"));
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(solverType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown incompressiblePrimalSolver type " << solverType
+            << nl << nl
+            << "Valid incompressiblePrimalSolver types are :" << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return
+        autoPtr<incompressiblePrimalSolver>
+        (
+            cstrIter()(mesh, managerType, dict)
+        );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::incompressiblePrimalSolver::readDict(const dictionary& dict)
+{
+    if (primalSolver::readDict(dict))
+    {
+        fvOptions_.read(dict.subOrEmptyDict("fvOptions"));
+
+        return true;
+    }
+
+    return false;
+}
+
+
+Foam::List<Foam::objective*>
+Foam::incompressiblePrimalSolver::getObjectiveFunctions() const
+{
+    DynamicList<objective*> objectives(10);
+
+    auto adjointSolvers = mesh_.lookupClass<adjointSolver>();
+
+    for (adjointSolver* adjointPtr : adjointSolvers)
+    {
+        adjointSolver& adjoint = *adjointPtr;
+
+        if (adjoint.active() && adjoint.primalSolverName() == solverName_)
+        {
+            PtrList<objective>& managerObjectives =
+                adjoint.getObjectiveManager().getObjectiveFunctions();
+
+            for (objective& obj : managerObjectives)
+            {
+                objectives.append(&obj);
+            }
+        }
+    }
+
+    return objectives;
+}
+
+
+bool Foam::incompressiblePrimalSolver::useSolverNameForFields() const
+{
+    return vars_().useSolverNameForFields();
+}
+
+
+const Foam::incompressibleVars&
+Foam::incompressiblePrimalSolver::getVars() const
+{
+    return vars_();
+}
+
+
+Foam::incompressibleVars&
+Foam::incompressiblePrimalSolver::getVars()
+{
+    return vars_.ref();
+}
+
+
+void Foam::incompressiblePrimalSolver::correctBoundaryConditions()
+{
+    incompressibleVars& vars = vars_();
+    // Update boundary conditions for all primal volFields,
+    // including averaged ones, if present
+    vars.correctBoundaryConditions();
+
+    // phi cannot be updated through correctBoundayrConditions.
+    // Re-compute based on the Rhie-Chow interpolation scheme.
+    // This is a non-linear process
+    // (phi depends on UEqn().A() which depends on phi)
+    // so iterations are required
+
+    volScalarField& p = vars.p();
+    volVectorField& U = vars.U();
+    surfaceScalarField& phi = vars.phi();
+    autoPtr<incompressible::turbulenceModel>& turbulence = vars.turbulence();
+
+    scalar contError(GREAT), diff(GREAT);
+    for (label iter = 0; iter < phiReconstructionIters_; ++iter)
+    {
+        Info<< "phi correction iteration " << iter << endl;
+
+        // Form momentum equations to grab A
+        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        tmp<fvVectorMatrix> tUEqn
+        (
+            fvm::div(phi, U)
+          + turbulence->divDevReff(U)
+          ==
+            fvOptions_(U)
+        );
+        fvVectorMatrix& UEqn = tUEqn.ref();
+        UEqn.relax();
+        fvOptions_.constrain(UEqn);
+
+        // Pressure equation will give the Rhie-Chow correction
+        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        volScalarField rAU(1.0/UEqn.A());
+        volVectorField HbyA("HbyA", U);
+        HbyA = rAU*UEqn.H();
+        tUEqn.clear();
+
+        surfaceScalarField phiHbyA("phiHbyA", fvc::flux(HbyA));
+        adjustPhi(phiHbyA, U, p);
+
+        //fvOptions_.makeRelative(phiHbyA);
+
+        fvScalarMatrix pEqn
+        (
+            fvm::laplacian(rAU, p) == fvc::div(phiHbyA)
+        );
+        phi = phiHbyA - pEqn.flux();
+
+        // Check convergence
+        // ~~~~~~~~~~~~~~~~~
+        scalar contErrorNew =
+            mesh_.time().deltaTValue()*
+            mag(fvc::div(phi)())().weightedAverage(mesh_.V()).value();
+
+        Info<< "sum local = " << contErrorNew << endl;
+        diff = mag(contErrorNew - contError)/contError;
+        contError = contErrorNew;
+
+        if (diff < phiReconstructionTol_) break;
+
+        Info<< endl;
+     }
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.H b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.H
new file mode 100644
index 0000000000000000000000000000000000000000..831a2039aa0fdf586bb9e70b7f4a5feed2276368
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.H
@@ -0,0 +1,200 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressiblePrimalSolver
+
+Description
+    Base class for primal incompressible solvers
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef incompressiblePrimalSolver_H
+#define incompressiblePrimalSolver_H
+
+#include "primalSolver.H"
+#include "incompressibleVars.H"
+#include "fvOptionList.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+class objective;
+
+/*---------------------------------------------------------------------------*\
+                  Class incompressiblePrimalSolver Declaration
+\*---------------------------------------------------------------------------*/
+
+class incompressiblePrimalSolver
+:
+    public primalSolver
+{
+private:
+
+    // Privare Member Functions
+
+        //- No copy construct
+        incompressiblePrimalSolver(const incompressiblePrimalSolver&) = delete;
+
+        //- No copy assignment
+        void operator=(const incompressiblePrimalSolver&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        //- Set with incompressible variables
+        //- Needs to be allocated in each derived class since it requires
+        //- a solverControl variable which is specifically allocated there
+        //  (e.g. SIMPLEControl for simple)
+        autoPtr<incompressibleVars> vars_;
+
+        //- Convergence criterion for reconstructing phi from U and p
+        scalar phiReconstructionTol_;
+
+        //- Max iterations  for reconstructing phi from U and p
+        label phiReconstructionIters_;
+
+        //- optionList for source terms addition
+        fv::optionList fvOptions_;
+
+
+public:
+
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("incompressible");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            incompressiblePrimalSolver,
+            dictionary,
+            (
+                fvMesh& mesh,
+                const word& managerType,
+                const dictionary& dict
+            ),
+            (mesh, managerType, dict)
+        );
+
+
+    // Constructors
+
+        //- Construct from mesh and dictionary
+        incompressiblePrimalSolver
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected incompressible primal solver
+        static autoPtr<incompressiblePrimalSolver> New
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~incompressiblePrimalSolver() = default;
+
+
+    // Member Functions
+
+        //- Read dict if updated
+        virtual bool readDict(const dictionary& dict);
+
+        //- Should solver name be appended to fields
+        bool useSolverNameForFields() const;
+
+
+        // Access
+
+            //- Return the list of objectives assodicated with this solver
+            List<objective*> getObjectiveFunctions() const;
+
+            //- Access to the incompressible variables set
+            const incompressibleVars& getVars() const;
+
+            //- Access to the incompressible variables set
+            incompressibleVars& getVars();
+
+
+        // Evolution
+
+            //- Update boundary conditions
+            virtual void correctBoundaryConditions();
+
+
+        // IO
+
+            //- In case of multi-point runs with turbulent flows,
+            //- output dummy turbulence fields with the base names, to allow
+            //- continuation
+            virtual bool write(const bool valid = true) const
+            {
+                if (mesh_.time().writeTime())
+                {
+                    return vars_().write();
+                }
+
+                return false;
+            }
+
+            //- In case of multi-point runs with turbulent flows,
+            //- output dummy turbulence fields with the base names, to allow
+            //- continuation
+            virtual bool writeNow() const
+            {
+                return vars_().write();
+            }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.C b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.C
new file mode 100644
index 0000000000000000000000000000000000000000..9f4889fd9c993b522d4059e5577f9bbd7142e82f
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.C
@@ -0,0 +1,285 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "simple.H"
+#include "findRefCell.H"
+#include "constrainHbyA.H"
+#include "constrainPressure.H"
+#include "adjustPhi.H"
+#include "Time.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(simple, 0);
+    addToRunTimeSelectionTable(incompressiblePrimalSolver, simple, dictionary);
+}
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+void Foam::simple::addExtraSchemes()
+{
+    if (vars_().useSolverNameForFields())
+    {
+        WarningInFunction
+            << "useSolverNameForFields is set to true for primalSolver "
+            << solverName() << nl << tab
+            << "Appending variable names with the solver name" << nl << tab
+            << "Please adjust the necessary entries in fvSchemes and fvSolution"
+            << nl << endl;
+    }
+}
+
+
+void Foam::simple::continuityErrors()
+{
+    surfaceScalarField& phi = vars_().phiInst();
+    volScalarField contErr(fvc::div(phi));
+
+    scalar sumLocalContErr = mesh_.time().deltaTValue()*
+        mag(contErr)().weightedAverage(mesh_.V()).value();
+
+    scalar globalContErr = mesh_.time().deltaTValue()*
+        contErr.weightedAverage(mesh_.V()).value();
+    cumulativeContErr_ += globalContErr;
+
+    Info<< "time step continuity errors : sum local = " << sumLocalContErr
+        << ", global = " << globalContErr
+        << ", cumulative = " << cumulativeContErr_
+        << endl;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::simple::simple
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict
+)
+:
+    incompressiblePrimalSolver(mesh, managerType, dict),
+    solverControl_(SIMPLEControl::New(mesh, managerType, *this)),
+    MRF_(mesh),
+    cumulativeContErr_(Zero),
+    objectives_(0)
+{
+    vars_.reset(new incompressibleVars(mesh, solverControl_()));
+    addExtraSchemes();
+    setRefCell
+    (
+        vars_().pInst(),
+        solverControl_().dict(),
+        solverControl_().pRefCell(),
+        solverControl_().pRefValue()
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::simple::readDict(const dictionary& dict)
+{
+    if (incompressiblePrimalSolver::readDict(dict))
+    {
+        return true;
+    }
+
+    return false;
+}
+
+void Foam::simple::solveIter()
+{
+    const Time& time = mesh_.time();
+    Info<< "Time = " << time.timeName() << "\n" << endl;
+
+    // Grab references
+    incompressibleVars& vars = vars_();
+    volScalarField& p = vars.pInst();
+    volVectorField& U = vars.UInst();
+    surfaceScalarField& phi = vars.phiInst();
+    autoPtr<incompressible::turbulenceModel>& turbulence = vars.turbulence();
+    label&  pRefCell  = solverControl_().pRefCell();
+    scalar& pRefValue = solverControl_().pRefValue();
+
+    // Momentum predictor
+    //~~~~~~~~~~~~~~~~~~~
+
+    MRF_.correctBoundaryVelocity(U);
+
+    tmp<fvVectorMatrix> tUEqn
+    (
+        fvm::div(phi, U)
+      + MRF_.DDt(U)
+      + turbulence->divDevReff(U)
+      ==
+        fvOptions_(U)
+    );
+    fvVectorMatrix& UEqn = tUEqn.ref();
+
+    addOptimisationTypeSource(UEqn);
+
+    UEqn.relax();
+
+    fvOptions_.constrain(UEqn);
+
+    if (solverControl_().momentumPredictor())
+    {
+        Foam::solve(UEqn == -fvc::grad(p));
+
+        fvOptions_.correct(U);
+    }
+
+    // Pressure Eq
+    //~~~~~~~~~~~~
+    {
+        volScalarField rAU(1.0/UEqn.A());
+        volVectorField HbyA(constrainHbyA(rAU*UEqn.H(), U, p));
+        surfaceScalarField phiHbyA("phiHbyA", fvc::flux(HbyA));
+        MRF_.makeRelative(phiHbyA);
+        adjustPhi(phiHbyA, U, p);
+
+        tmp<volScalarField> rAtU(rAU);
+
+        if (solverControl_().consistent())
+        {
+            rAtU = 1.0/(1.0/rAU - UEqn.H1());
+            phiHbyA +=
+                fvc::interpolate(rAtU() - rAU)*fvc::snGrad(p)*mesh_.magSf();
+            HbyA -= (rAU - rAtU())*fvc::grad(p);
+        }
+
+        tUEqn.clear();
+
+        // Update the pressure BCs to ensure flux consistency
+        constrainPressure(p, U, phiHbyA, rAtU(), MRF_);
+
+        // Non-orthogonal pressure corrector loop
+        while (solverControl_().correctNonOrthogonal())
+        {
+            fvScalarMatrix pEqn
+            (
+                fvm::laplacian(rAtU(), p) == fvc::div(phiHbyA)
+            );
+
+            pEqn.setReference(pRefCell, pRefValue);
+
+            pEqn.solve();
+
+            if (solverControl_().finalNonOrthogonalIter())
+            {
+                phi = phiHbyA - pEqn.flux();
+            }
+        }
+
+        continuityErrors();
+
+        // Explicitly relax pressure for momentum corrector
+        p.relax();
+
+        // Momentum corrector
+        U = HbyA - rAtU()*fvc::grad(p);
+        U.correctBoundaryConditions();
+        fvOptions_.correct(U);
+    }
+
+    vars_().laminarTransport().correct();
+    turbulence->correct();
+
+    solverControl_().write();
+
+    // Print objective values to screen and compute mean value
+    Info<< endl;
+    for (objective* obj : objectives_)
+    {
+        Info<< obj->objectiveName() << " : " << obj->J() << endl;
+        obj->accumulateJMean(solverControl_());
+        obj->writeInstantaneousValue();
+    }
+
+    // Average fields if necessary
+    vars.computeMeanFields();
+
+    // Print execution time
+    time.printExecutionTime(Info);
+}
+
+
+void Foam::simple::solve()
+{
+    // Iterate
+    if (active_)
+    {
+        // Get the objectives for this solver
+        if (objectives_.empty())
+        {
+            objectives_ = getObjectiveFunctions();
+        }
+
+        // Reset initial and mean fields before solving
+        restoreInitValues();
+        vars_().resetMeanFields();
+
+        // Validate turbulence model fields
+        vars_().turbulence()->validate();
+
+        while (solverControl_().loop())
+        {
+            solveIter();
+        }
+
+        // Safety
+        objectives_.clear();
+    }
+}
+
+
+bool Foam::simple::loop()
+{
+    return solverControl_().loop();
+}
+
+
+void Foam::simple::restoreInitValues()
+{
+    vars_().restoreInitValues();
+}
+
+
+bool Foam::simple::writeData(Ostream& os) const
+{
+    os.writeEntry("averageIter", solverControl_().averageIter());
+
+    return true;
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.H b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.H
new file mode 100644
index 0000000000000000000000000000000000000000..8d92a9d60b3e1ed424841915246673bfc7ab0102
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.H
@@ -0,0 +1,148 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::simple
+
+Description
+    Base class for solution control classes
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef simple_H
+#define simple_H
+
+#include "incompressiblePrimalSolver.H"
+#include "SIMPLEControl.H"
+#include "IOMRFZoneList.H"
+#include "objective.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class simple Declaration
+\*---------------------------------------------------------------------------*/
+
+class simple
+:
+    public incompressiblePrimalSolver
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        simple(const simple&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const simple&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        //- Solver control
+        autoPtr<SIMPLEControl> solverControl_;
+
+        //- MRF zones
+        IOMRFZoneList MRF_;
+
+        //- Cumulative continuity error
+        scalar cumulativeContErr_;
+
+        //- List of objectives related to this primal solver
+        List<objective*> objectives_;
+
+        //- In case variable names are different than the base ones,
+        //- add extra schemes and relaxation factors to the appropriate dicts
+        //  Note: Not supported for now
+        void addExtraSchemes();
+
+        //- Compute continuity errors
+        void continuityErrors();
+
+
+public:
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("simple");
+
+
+    // Constructors
+
+        //- Construct from mesh and dictionary
+        simple
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~simple() = default;
+
+
+    // Member Functions
+
+        virtual bool readDict(const dictionary& dict);
+
+        // Evolution
+
+            //- Execute one iteration of the solution algorithm
+            virtual void solveIter();
+
+            //- Main control loop
+            virtual void solve();
+
+            //- Looper (advances iters, time step)
+            virtual bool loop();
+
+            //- Restore initial field values if necessary
+            virtual void restoreInitValues();
+
+            //- Write average iteration
+            virtual bool writeData(Ostream& os) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.C b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.C
new file mode 100644
index 0000000000000000000000000000000000000000..3c8d89c8b944b104fd09154d0f82a7a102fce185
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.C
@@ -0,0 +1,101 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "primalSolver.H"
+#include "addToRunTimeSelectionTable.H"
+
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(primalSolver, 0);
+    defineRunTimeSelectionTable(primalSolver, primalSolver);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::primalSolver::primalSolver
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict
+)
+:
+    solver(mesh, managerType, dict)
+{}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+Foam::autoPtr<Foam::primalSolver> Foam::primalSolver::New
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict
+)
+{
+    const word primalSolverType(dict.get<word>("type"));
+
+    auto cstrIter = primalSolverConstructorTablePtr_->cfind(primalSolverType);
+
+    if (!cstrIter.found())
+    {
+        FatalIOErrorInFunction(dict)
+            << "Unknown primalSolver type " << primalSolverType
+            << nl << nl
+            << "Valid primalSolver types are :" << nl
+            << primalSolverConstructorTablePtr_->sortedToc()
+            << exit(FatalIOError);
+    }
+
+    return autoPtr<primalSolver>(cstrIter()(mesh, managerType, dict));
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::primalSolver::readDict(const dictionary& dict)
+{
+    if (solver::readDict(dict))
+    {
+        return true;
+    }
+
+    return false;
+}
+
+
+void Foam::primalSolver::correctBoundaryConditions()
+{
+    // Do nothing
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.H b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.H
new file mode 100644
index 0000000000000000000000000000000000000000..fea80835aa722042f887c564211902340255b333
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.H
@@ -0,0 +1,138 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::primalSolver
+
+Description
+    Base class for primal solvers
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef primalSolver_H
+#define primalSolver_H
+
+#include "fvMesh.H"
+#include "solver.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                            Class primalSolver Declaration
+\*---------------------------------------------------------------------------*/
+
+class primalSolver
+:
+    public solver
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        primalSolver(const primalSolver&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const primalSolver&) = delete;
+
+
+public:
+
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("primalSolver");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeNewSelectionTable
+        (
+            autoPtr,
+            primalSolver,
+            primalSolver,
+            (
+                fvMesh& mesh,
+                const word& managerType,
+                const dictionary& dict
+            ),
+            (mesh, managerType, dict)
+        );
+
+
+    // Constructors
+
+        //- Construct from mesh and dictionary
+        primalSolver
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected primal solver
+        static autoPtr<primalSolver> New
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~primalSolver() = default;
+
+
+    // Member Functions
+
+        virtual bool readDict(const dictionary& dict);
+
+
+        // Evolution
+
+            //- update boundary conditions
+            virtual void correctBoundaryConditions();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.C b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.C
new file mode 100644
index 0000000000000000000000000000000000000000..2861b6bb3ec65f5a2b491b5aa74dd6551e01d097
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.C
@@ -0,0 +1,131 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "solver.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(solver, 0);
+}
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::solver::solver
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const dictionary& dict
+)
+:
+    localIOdictionary
+    (
+        IOobject
+        (
+            dict.dictName(),
+            mesh.time().timeName(),
+            fileName("uniform")/fileName("solvers"),
+            mesh,
+            IOobject::READ_IF_PRESENT,
+            IOobject::AUTO_WRITE
+        ),
+        word::null // avoid type checking since dictionary is read using the
+                   // derived type name and type() will result in "solver" here
+    ),
+    mesh_(mesh),
+    managerType_(managerType),
+    dict_(dict),
+    solverName_(dict.dictName()),
+    active_(dict.lookupOrDefault<bool>("active", true)),
+    optTypeSource_(nullptr)
+{}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::solver::~solver()
+{
+    optTypeSource_ = 0;
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::solver::readDict(const dictionary& dict)
+{
+    dict_ = dict;
+
+    // Note: Slightly dangerous to change active_ while the solver is
+    // running. At the very least, this should trigger writing before stoping.
+    // Additional problems if we have an adjontSolver corresponding to a
+    // constraint. To be revisited
+    //active_ = dict.lookupOrDefault<bool>("active", true);
+
+    return true;
+}
+
+
+const Foam::word& Foam::solver::solverName() const
+{
+    return solverName_;
+}
+
+
+bool Foam::solver::active()
+{
+    return active_;
+}
+
+
+const Foam::dictionary& Foam::solver::dict() const
+{
+    return dict_;
+}
+
+
+void Foam::solver::restoreInitValues()
+{
+    // Does nothing in the base class
+}
+
+
+void Foam::solver::updateOptTypeSource
+(
+    const autoPtr<volScalarField>& optSourcePtr
+)
+{
+    if (optSourcePtr.valid())
+    {
+        const volScalarField& optSource = optSourcePtr();
+        optTypeSource_ = &optSource;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.H b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.H
new file mode 100644
index 0000000000000000000000000000000000000000..d44b59729f173ebb2dbb1b8e7e7be73ea27a761d
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.H
@@ -0,0 +1,206 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::solver
+
+Description
+    Base class for solution control classes
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef solver_H
+#define solver_H
+
+#include "fvMesh.H"
+#include "fvMatrix.H"
+#include "localIOdictionary.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+/*---------------------------------------------------------------------------*\
+                            Class solver Declaration
+\*---------------------------------------------------------------------------*/
+
+class solver
+:
+    public localIOdictionary
+{
+private:
+
+    // Private Member Functions
+
+        //- No copy construct
+        solver(const solver&) = delete;
+
+        //- No copy assignment
+        void operator=(const solver&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        //- Reference to the mesh database
+        fvMesh& mesh_;
+
+        //- The optimisation type
+        const word managerType_;
+
+        //- Dictionary holding the solver info
+        dictionary dict_;
+
+        //- Solver name
+        const word solverName_;
+
+        //- Solve equations?
+        bool active_;
+
+        //- Pointer to a source term coming from the optimisationType
+        //- (e.g. porosity from topologyOptimisation)
+        //  Will never allocate new memory, so no need to be deleted
+        //  in the destructor
+        const volScalarField* optTypeSource_;
+
+
+public:
+
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("solver");
+
+
+    // Constructors
+
+        //- Construct from mesh and dictionary
+        solver
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~solver();
+
+
+    // Member Functions
+
+        virtual bool readDict(const dictionary& dict);
+
+        // Access
+
+            //- Return the solver name
+            const word& solverName() const;
+
+            //- Use solver name as a suffix to the involved fields
+            virtual bool useSolverNameForFields() const = 0;
+
+            //- Return state of solver
+            virtual bool active();
+
+            //- Return the solver dictionary
+            virtual const dictionary& dict() const;
+
+
+        // Evolution
+
+            //- Execute one iteration of the solution algorithm
+            virtual void solveIter() = 0;
+
+            //- Main control loop
+            virtual void solve() = 0;
+
+            //- Looper (advances iters, time step)
+            virtual bool loop() = 0;
+
+            //- Restore initial field values if necessary
+            virtual void restoreInitValues();
+
+            //- Update source term related to optimisationType
+            void updateOptTypeSource
+            (
+                const autoPtr<volScalarField>& optSourcePtr
+            );
+
+            //- Main control loop.
+            //  Gets a list of function pointers to be called at the end of
+            //  each solver iteration
+            template<class Type>
+            void solveWithArgs
+            (
+                Type& type,
+                List<void (Type::*)()>& funcs
+            );
+
+            //- Add source from optimisationType to underlaying equation
+            template<class Type>
+            void addOptimisationTypeSource(fvMatrix<Type>& matrix) const;
+
+
+        // IO
+
+            //- Required by regIOobject
+            virtual bool writeData(Ostream&) const
+            {
+                return true;
+            }
+
+            //- Workaround for turbulent fields on multi-point runs
+            virtual bool write(const bool valid = true) const
+            {
+                return false;
+            }
+
+            //- Workaround for turbulent fields on multi-point runs
+            virtual bool writeNow() const
+            {
+                return false;
+            }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+#   include "solverTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solverTemplates.C b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solverTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..29335d298274122243090fbb40d4834d785642b4
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solverTemplates.C
@@ -0,0 +1,74 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "fvmSup.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+void Foam::solver::solveWithArgs
+(
+    Type& type,
+    List<void (Type::*)()>& funcs
+)
+{
+    // Iterate
+    if (active_)
+    {
+        restoreInitValues();
+        while(loop())
+        {
+            solveIter();
+            forAll(funcs, fI)
+            {
+                (type.*funcs[fI])();
+            }
+        }
+
+        mesh_.time().printExecutionTime(Info);
+    }
+}
+
+
+template<class Type>
+void Foam::solver::addOptimisationTypeSource
+(
+    fvMatrix<Type>& matrix
+) const
+{
+    // If source has been allocated, add source * variable
+    if (optTypeSource_)
+    {
+        const GeometricField<Type, fvPatchField, volMesh>& psi = matrix.psi();
+
+        matrix += fvm::Sp(*optTypeSource_, psi);
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.C b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.C
new file mode 100644
index 0000000000000000000000000000000000000000..f43578594e178f8b21f9bbf119f460857d9d7690
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.C
@@ -0,0 +1,123 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "SIMPLEControl.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(SIMPLEControl, 0);
+    defineRunTimeSelectionTable(SIMPLEControl, dictionary);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::SIMPLEControl::SIMPLEControl
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const solver& solver
+)
+:
+    solverControl(solver),
+    simpleControl(mesh, "SIMPLE", false),
+    managerType_(managerType),
+    nIters_(Zero),
+    pRefCell_(Zero),
+    pRefValue_(Zero)
+{
+    read();
+}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+Foam::autoPtr<Foam::SIMPLEControl> Foam::SIMPLEControl::New
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const solver& solver
+)
+{
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(managerType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown control type " << managerType << nl << nl
+            << "Valid control types are :" << endl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return autoPtr<SIMPLEControl>(cstrIter()(mesh, managerType, solver));
+}
+
+
+bool Foam::SIMPLEControl::read()
+{
+    simpleControl::read();
+    solverControl::read();
+    readIters();
+
+    if (average_ && averageStartIter_ > nIters_)
+    {
+        WarningInFunction
+            << "Average start iteration is larger than nIter in solver "
+            << solver_.solverName() << nl
+            << tab << "Disabling averaging ..." << nl
+            << endl;
+        average_ = false;
+    }
+
+    return true;
+}
+
+
+void Foam::SIMPLEControl::readIters()
+{
+    nIters_ = dict().get<label>("nIters");
+}
+
+
+void Foam::SIMPLEControl::checkMeanSolution() const
+{
+    if (average_ && iter_ < averageStartIter_)
+    {
+        WarningInFunction
+            << "Solver " << solver_.solverName()
+            << " converged before averaging started" << nl << tab
+            << "Using instantaneous fields ..." << nl
+            << endl;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.H b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.H
new file mode 100644
index 0000000000000000000000000000000000000000..291b7e3334e92d154a4d02b19a76a9ac4fabab09
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.H
@@ -0,0 +1,176 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::SIMPLEControl
+
+Description
+    SIMPLE control class to supply convergence information/checks for
+    the SIMPLE loop.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef SIMPLEControl_H
+#define SIMPLEControl_H
+
+#include "solverControl.H"
+#include "simpleControl.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class SIMPLEControl Declaration
+\*---------------------------------------------------------------------------*/
+
+class SIMPLEControl
+:
+    public solverControl,
+    public simpleControl
+{
+
+protected:
+
+    // Protected Data
+
+        //- Optimisation type
+        const word& managerType_;
+
+        //- Number of SIMPLE iterations
+        label nIters_;
+
+        //- Pressure reference cell
+        label  pRefCell_;
+        //
+        //- Pressure reference value
+        scalar pRefValue_;
+
+
+private:
+
+        //- No copy construct
+        SIMPLEControl(const SIMPLEControl&) = delete;
+
+        //- No copy assignment
+        void operator=(const SIMPLEControl&) = delete;
+
+
+public:
+
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("SIMPLEControl");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            SIMPLEControl,
+            dictionary,
+            (
+                fvMesh& mesh,
+                const word& managerType,
+                const solver& solver
+            ),
+            (mesh, managerType, solver)
+        );
+
+
+    // Constructors
+
+        //- Construct from mesh
+        SIMPLEControl
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const solver& solver
+        );
+
+
+    //- Destructor
+    virtual ~SIMPLEControl() = default;
+
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<SIMPLEControl> New
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const solver& solver
+        );
+
+
+    // Member Functions
+
+        virtual bool read();
+
+        virtual void readIters();
+
+        void checkMeanSolution() const;
+
+        // Access
+
+            //- Return the solution dictionary
+            inline virtual const dictionary dict() const;
+
+            //- Return pressure reference cell
+            inline label& pRefCell();
+
+            //- Return pressure reference value
+            inline scalar& pRefValue();
+
+        // Solution control
+
+            //- Whether to call time.write() or not
+            virtual bool write(const bool valid = true) const = 0;
+
+        // Evolution
+
+            //- Loop
+            virtual bool loop() = 0;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+#include "SIMPLEControlI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControlI.H b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControlI.H
new file mode 100644
index 0000000000000000000000000000000000000000..c009130f81407f30d04271627864c05d721b1229
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControlI.H
@@ -0,0 +1,50 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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/>.
+
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+inline const Foam::dictionary Foam::SIMPLEControl::dict() const
+{
+    return solutionDict();
+}
+
+
+inline Foam::label& Foam::SIMPLEControl::pRefCell()
+{
+    return pRefCell_;
+}
+
+
+inline Foam::scalar& Foam::SIMPLEControl::pRefValue()
+{
+    return pRefValue_;
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/singleRun/SIMPLEControlSingleRun.C b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/singleRun/SIMPLEControlSingleRun.C
new file mode 100644
index 0000000000000000000000000000000000000000..2847b275f61b071bf06189cd5894746dacf8ae63
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/singleRun/SIMPLEControlSingleRun.C
@@ -0,0 +1,179 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "SIMPLEControlSingleRun.H"
+#include "addToRunTimeSelectionTable.H"
+#include "Time.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(SIMPLEControlSingleRun, 0);
+    addToRunTimeSelectionTable
+    (
+        SIMPLEControl,
+        SIMPLEControlSingleRun,
+        dictionary
+    );
+}
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+bool Foam::SIMPLEControlSingleRun::read()
+{
+    return SIMPLEControl::read();
+}
+
+
+void Foam::SIMPLEControlSingleRun::readIters()
+{
+    label nItersOld = nIters_;
+    nIters_ = dict().get<label>("nIters");
+
+    if (nIters_ != nItersOld || iter_ == 0)
+    {
+        Time& runTime = const_cast<Time&>(mesh_.time());
+        if (iter_ == 0)
+        {
+            startTime_ = runTime.value();
+        }
+        Info<< "Setting endTime to " << startTime_ + nIters_ << endl;
+        runTime.setEndTime(startTime_ + nIters_);
+        endTime_ = runTime.endTime().value();
+    }
+}
+
+
+void Foam::SIMPLEControlSingleRun::checkEndTime(bool& isRunning)
+{
+    // If controlDict is modified during run-time, time.endTime() is reset
+    // to what is read from controlDict and overwrites the one set through
+    // nIters. Silently reset
+    Time& time = const_cast<Time&>(mesh_.time());
+
+    if (time.endTime().value() != endTime_)
+    {
+        time.setEndTime(startTime_ + nIters_);
+        endTime_ = time.endTime().value();
+        isRunning =
+            time.value() < (time.endTime().value() - 0.5*time.deltaTValue());
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::SIMPLEControlSingleRun::SIMPLEControlSingleRun
+(
+    fvMesh& mesh,
+    const word& managerType,
+    const solver& solver
+)
+:
+    SIMPLEControl(mesh, managerType, solver),
+    startTime_(Zero),
+    endTime_(Zero)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool Foam::SIMPLEControlSingleRun::write(const bool valid) const
+{
+    Time& time = const_cast<Time&>(mesh_.time());
+    time.write();
+    solver_.write();
+
+    return true;
+}
+
+
+void Foam::SIMPLEControlSingleRun::writeNow()
+{
+    Time& time = const_cast<Time&>(mesh_.time());
+    // Avoid writing fields if already in an outputTime iter
+    // since results will be written by the solver class either way
+    if (!time.writeTime())
+    {
+        time.writeNow();
+        solver_.writeNow();
+    }
+}
+
+
+bool Foam::SIMPLEControlSingleRun::loop()
+{
+    solutionControl::setFirstIterFlag(true, true);
+
+    this->read();
+    ++iter_;
+
+    Time& runTime = const_cast<Time&>(mesh_.time());
+
+    if (initialised_ && criteriaSatisfied())
+    {
+        Info<< nl
+            << solver_.solverName()
+            << " solution converged in "
+            << runTime.timeName() << " iterations" << nl << endl;
+
+        // write fields (including dummy turbulence fields in multi-point runs)
+        writeNow();
+
+        // Check whether mean fields have not been computed due to an
+        // unexpectedly early convergence
+        checkMeanSolution();
+
+        return false;
+    }
+    else
+    {
+        initialised_ = true;
+        storePrevIterFields();
+    }
+
+    bool isRunning = runTime.loop();
+    checkEndTime(isRunning);
+
+    if (!isRunning)
+    {
+        Info<< nl
+            << solver_.solverName()
+            << " solution reached max. number of iterations "
+            << nIters_ << nl << endl;
+
+        // Write fields (including dummy turbulence fields in multi-point runs)
+        writeNow();
+    }
+
+    return isRunning;
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/singleRun/SIMPLEControlSingleRun.H b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/singleRun/SIMPLEControlSingleRun.H
new file mode 100644
index 0000000000000000000000000000000000000000..9fa5e896fdd188c921aee1acfa35721ec6dfe5eb
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/singleRun/SIMPLEControlSingleRun.H
@@ -0,0 +1,137 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::SIMPLEControlSingleRun
+
+Description
+    SIMPLE control class for single runs (i.e. not optimisation).
+    Time acts as in simpleFoam, with all solver control read through
+    optimisationDict
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef SIMPLEControlSingleRun_H
+#define SIMPLEControlSingleRun_H
+
+#include "SIMPLEControl.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                    Class SIMPLEControlSingleRun Declaration
+\*---------------------------------------------------------------------------*/
+
+class SIMPLEControlSingleRun
+:
+    public SIMPLEControl
+{
+protected:
+
+    // Protected Data
+
+        //- Start time
+        scalar startTime_;
+
+        //- End time
+        scalar endTime_;
+
+
+    // Protected Member Functions
+
+        //- Read controls from optimisationDict
+        virtual bool read();
+
+        //- Set end time if number of iters has changed
+        virtual void readIters();
+
+        //- Check whether endTime has been overwritten by a run-time
+        //- modification of controlDict
+        void checkEndTime(bool& isRunning);
+
+
+private:
+
+        //- No copy construct
+        SIMPLEControlSingleRun(const SIMPLEControlSingleRun&) = delete;
+
+        //- No copy assignment
+        void operator=(const SIMPLEControlSingleRun&) = delete;
+
+
+public:
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("singleRun");
+
+
+    // Constructors
+
+        //- Construct from mesh
+        SIMPLEControlSingleRun
+        (
+            fvMesh& mesh,
+            const word& managerType,
+            const solver& solver
+        );
+
+
+    //- Destructor
+    virtual ~SIMPLEControlSingleRun() = default;
+
+
+    // Member Functions
+
+        // Solution control
+
+            //- Whether to call time.write() or not
+            virtual bool write(const bool valid = true) const;
+
+            //- Write fields, even if it is not a writeTime
+            void writeNow();
+
+        // Evolution
+
+            //- Loop
+            virtual bool loop();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControl.C b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControl.C
new file mode 100644
index 0000000000000000000000000000000000000000..bcd76ae967149c6084465a9ebc611668de59791a
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControl.C
@@ -0,0 +1,77 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "solverControl.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(solverControl, 0);
+}
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+bool Foam::solverControl::read()
+{
+    // Read basic entries
+    printMaxMags_ = solutionDict().lookupOrDefault<bool>("printMaxMags", false);
+
+    // Manage averaging
+    dictionary averagingDict = solutionDict().subOrEmptyDict("averaging");
+    averageStartIter_ = averagingDict.lookupOrDefault<label>("startIter", -1);
+
+    return true;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::solverControl::solverControl(const solver& solver)
+:
+    solver_(solver),
+    printMaxMags_(true),
+    iter_(0),
+    averageIter_(solver.lookupOrDefault<label>("averageIter", 0)),
+    averageStartIter_(-1),
+    // Non run-time modifiable options read in the constructor only
+    storeInitValues_
+    (
+        solverDict().lookupOrDefault<bool>("storeInitValues", false)
+    ),
+    average_
+    (
+        solutionDict().subOrEmptyDict("averaging").
+            lookupOrDefault<bool>("average", false)
+    )
+{
+    read();
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControl.H b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControl.H
new file mode 100644
index 0000000000000000000000000000000000000000..252fa3065dd43bf7fb545e535fc746917c21ddd9
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControl.H
@@ -0,0 +1,177 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::solverControl
+
+Description
+    Base class for solver control classes
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef solverControl_H
+#define solverControl_H
+
+#include "fvMesh.H"
+#include "solver.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class solverControl Declaration
+\*---------------------------------------------------------------------------*/
+
+class solverControl
+{
+protected:
+
+    // Protected data
+
+        //- Reference to the underlaying solver
+        const solver& solver_;
+
+        // Solution controls
+
+            //- Whether to print the max magnitude during each solver iteration
+            //  Useful for adjoint solvers
+            bool printMaxMags_;
+
+
+        // Evolution
+
+            //- Current iteration index
+            label iter_;
+
+            //- Current averaging iteration index
+            label averageIter_;
+
+            //- Averaging start index
+            label averageStartIter_;
+
+            // Non run-time modifiable entries
+
+                //- Whether to re-initialize the solution based on the initial
+                //- time step. Makes sense only for optimisation or FD runs
+                bool storeInitValues_;
+
+                //- Do averaging
+                bool average_;
+
+
+    // Protected Member Functions
+
+        //- Read controls from optimisationDict
+        virtual bool read();
+
+
+private:
+
+        //- No copy construct
+        solverControl(const solverControl&) = delete;
+
+        //- No copy assignment
+        void operator=(const solverControl&) = delete;
+
+
+public:
+
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("solverControl");
+
+
+    // Constructors
+
+        //- Construct from solver
+        solverControl(const solver& solver);
+
+
+    //- Destructor
+    virtual ~solverControl() = default;
+
+
+    // Member Functions
+
+        //- Read controls from optimisationDict
+
+            //- Return the solver dictionary
+            inline virtual const dictionary solverDict() const;
+
+            //- Return the solutionControls dictionary
+            inline virtual const dictionary solutionDict() const;
+
+            //- Print max mags of solver fields
+            inline bool printMaxMags() const;
+
+
+        // Solution control
+
+            //- Re-initialize
+            inline bool storeInitValues() const;
+
+            //- Return iteration index
+            inline label iter() const;
+
+            //- Return average iteration index reference
+            inline label& averageIter();
+
+            //- Return const average iteration index reference
+            inline label averageIter() const;
+
+            //- Return iteration index
+            inline label averageStartIter() const;
+
+            //- Whether or not to add fields of the current iteration to the
+            //- average fields
+            inline bool doAverageIter() const;
+
+            //- Use averaged fields?
+            //- For solving the adjoint equations or computing sensitivities
+            //- based on averaged fields
+            inline bool useAveragedFields() const;
+
+            //- Whether averaging is enabled or not
+            inline bool average() const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+#include "solverControlI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControlI.H b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControlI.H
new file mode 100644
index 0000000000000000000000000000000000000000..bc9d4e024d3cc3601a76d92f7f51d8bcd7d8a29e
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControlI.H
@@ -0,0 +1,112 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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/>.
+
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+inline const Foam::dictionary Foam::solverControl::solverDict() const
+{
+    return solver_.dict();
+}
+
+
+inline const Foam::dictionary Foam::solverControl::solutionDict() const
+{
+    return solverDict().subDict("solutionControls");
+}
+
+
+inline bool Foam::solverControl::printMaxMags() const
+{
+    return printMaxMags_;
+}
+
+
+inline bool Foam::solverControl::storeInitValues() const
+{
+    return storeInitValues_;
+}
+
+
+inline Foam::label Foam::solverControl::iter() const
+{
+    return iter_;
+}
+
+
+inline Foam::label& Foam::solverControl::averageIter()
+{
+    return averageIter_;
+}
+
+
+inline Foam::label Foam::solverControl::averageIter() const
+{
+    return averageIter_;
+}
+
+
+inline Foam::label Foam::solverControl::averageStartIter() const
+{
+    return averageStartIter_;
+}
+
+
+inline bool Foam::solverControl::doAverageIter() const
+{
+    if (average_ && iter_ >= averageStartIter_)
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+
+inline bool Foam::solverControl::useAveragedFields() const
+{
+    if (average_ && averageIter_)
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+
+inline bool Foam::solverControl::average() const
+{
+    return average_;
+}
+
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressible/incompressibleVars.C b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressible/incompressibleVars.C
new file mode 100644
index 0000000000000000000000000000000000000000..6ffc059abca8b3139dd893503e75ec2e278db9f1
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressible/incompressibleVars.C
@@ -0,0 +1,529 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "incompressibleVars.H"
+#include "createZeroField.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(incompressibleVars, 0);
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+void incompressibleVars::setFields()
+{
+    setField(pPtr_, mesh_, "p", solverName_, useSolverNameForFields_);
+    setField(UPtr_, mesh_, "U", solverName_, useSolverNameForFields_);
+    setFluxField
+    (
+        phiPtr_,
+        mesh_,
+        UInst(),
+        "phi",
+        solverName_,
+        useSolverNameForFields_
+    );
+
+    mesh_.setFluxRequired(pPtr_->name());
+
+    // if required, correct boundary conditions of mean flow fields here in
+    // order to have the correct bcs for e.g. turbulence models that follow.
+    // NOTE: phi correction depends on the solver (includes for instance
+    // Rhie-Chow interpolation).  This needs to be implemented within
+    // incompressiblePrimalSolver
+    if (correctBoundaryConditions_)
+    {
+        correctNonTurbulentBoundaryConditions();
+    }
+
+    laminarTransportPtr_.reset
+    (
+        new singlePhaseTransportModel(UInst(), phiInst())
+    );
+    turbulence_.reset
+    (
+        incompressible::turbulenceModel::New
+        (
+            UInst(),
+            phiInst(),
+            laminarTransport()
+        ).ptr()
+    );
+    RASModelVariables_.reset
+    (
+        incompressible::RASModelVariables::New
+        (
+            mesh_,
+            solverControl_
+        ).ptr()
+    );
+    renameTurbulenceFields();
+    if (correctBoundaryConditions_)
+    {
+        correctTurbulentBoundaryConditions();
+    }
+}
+
+
+void incompressibleVars::setInitFields()
+{
+    // Store init fields
+    // only mean flow here since turbulent quantities
+    // are allocated automatically in RASModelVariables
+    if (solverControl_.storeInitValues())
+    {
+        pInitPtr_.reset(new volScalarField(pInst().name() + "Init", pInst()));
+        UInitPtr_.reset(new volVectorField(UInst().name() + "Init", UInst()));
+        phiInitPtr_.reset
+        (
+            new surfaceScalarField(phiInst().name() + "Init", phiInst())
+        );
+    }
+}
+
+
+void incompressibleVars::setMeanFields()
+{
+    // Allocate mean fields
+    // only mean flow here since turbulent quantities
+    // are allocated automatically in RASModelVariables
+    if (solverControl_.average())
+    {
+        Info<< "Allocating Mean Primal Fields" << endl;
+        pMeanPtr_.reset
+        (
+            new volScalarField
+            (
+                IOobject
+                (
+                    pInst().name()+"Mean",
+                    mesh_.time().timeName(),
+                    mesh_,
+                    IOobject::READ_IF_PRESENT,
+                    IOobject::AUTO_WRITE
+                ),
+                pInst()
+            )
+        );
+        UMeanPtr_.reset
+        (
+            new volVectorField
+            (
+                IOobject
+                (
+                    UInst().name()+"Mean",
+                    mesh_.time().timeName(),
+                    mesh_,
+                    IOobject::READ_IF_PRESENT,
+                    IOobject::AUTO_WRITE
+                ),
+                UInst()
+            )
+        );
+        phiMeanPtr_.reset
+        (
+            new surfaceScalarField
+            (
+                IOobject
+                (
+                    phiInst().name()+"Mean",
+                    mesh_.time().timeName(),
+                    mesh_,
+                    IOobject::READ_IF_PRESENT,
+                    IOobject::AUTO_WRITE
+                ),
+                phiInst()
+            )
+        );
+
+        // Correct boundary conditions if necessary
+        if (correctBoundaryConditions_)
+        {
+            pMeanPtr_().correctBoundaryConditions();
+            UMeanPtr_().correctBoundaryConditions();
+        }
+    }
+}
+
+
+void incompressibleVars::renameTurbulenceFields()
+{
+    //  Turbulence model always reads fields with the prescribed name
+    //  If a custom name is supplied, check whether this field exists,
+    //  copy it to the field known by the turbulence model
+    //  and re-name the latter
+    if (useSolverNameForFields_)
+    {
+        incompressible::RASModelVariables& rasVars = RASModelVariables_();
+        if (rasVars.hasTMVar1())
+        {
+            renameTurbulenceField(rasVars.TMVar1Inst(), solverName_);
+        }
+        if (rasVars.hasTMVar2())
+        {
+            renameTurbulenceField(rasVars.TMVar2Inst(), solverName_);
+        }
+        if (rasVars.hasNut())
+        {
+            renameTurbulenceField(rasVars.nutRefInst(), solverName_);
+        }
+    }
+}
+
+
+void incompressibleVars::correctNonTurbulentBoundaryConditions()
+{
+    Info<< "Correcting (U,p) boundary conditions " << endl;
+    pInst().correctBoundaryConditions();
+    UInst().correctBoundaryConditions();
+    if (solverControl_.average())
+    {
+        pMeanPtr_().correctBoundaryConditions();
+        UMeanPtr_().correctBoundaryConditions();
+    }
+}
+
+
+void incompressibleVars::correctTurbulentBoundaryConditions()
+{
+    // If required, correct boundary conditions of turbulent fields.
+    // Includes the correction of boundary conditions for averaged fields,
+    // if any
+    Info<< "Correcting boundary conditions of turbulent fields" << endl;
+    RASModelVariables_().correctBoundaryConditions(turbulence_());
+}
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+incompressibleVars::incompressibleVars
+(
+    fvMesh& mesh,
+    solverControl& SolverControl
+)
+:
+    variablesSet(mesh, SolverControl.solverDict()),
+    solverControl_(SolverControl),
+    pPtr_(nullptr),
+    UPtr_(nullptr),
+    phiPtr_(nullptr),
+    laminarTransportPtr_(nullptr),
+    turbulence_(nullptr),
+    RASModelVariables_(nullptr),
+
+    pInitPtr_(nullptr),
+    UInitPtr_(nullptr),
+    phiInitPtr_(nullptr),
+
+    pMeanPtr_(nullptr),
+    UMeanPtr_(nullptr),
+    phiMeanPtr_(nullptr),
+
+    correctBoundaryConditions_
+    (
+        SolverControl.solverDict().subOrEmptyDict("fieldReconstruction").
+            lookupOrDefault<bool>("reconstruct", false)
+    )
+{
+    setFields();
+    setInitFields();
+    setMeanFields();
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+const volScalarField& incompressibleVars::p() const
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return pMeanPtr_();
+    }
+    else
+    {
+        return pPtr_();
+    }
+}
+
+
+volScalarField& incompressibleVars::p()
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return pMeanPtr_();
+    }
+    else
+    {
+        return pPtr_();
+    }
+}
+
+
+const volVectorField& incompressibleVars::U() const
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return UMeanPtr_();
+    }
+    else
+    {
+        return UPtr_();
+    }
+}
+
+
+volVectorField& incompressibleVars::U()
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return UMeanPtr_();
+    }
+    else
+    {
+        return UPtr_();
+    }
+}
+
+
+const surfaceScalarField& incompressibleVars::phi() const
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return phiMeanPtr_();
+    }
+    else
+    {
+        return phiPtr_();
+    }
+}
+
+surfaceScalarField& incompressibleVars::phi()
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return phiMeanPtr_();
+    }
+    else
+    {
+        return phiPtr_();
+    }
+}
+
+
+const volScalarField& incompressibleVars::pInst() const
+{
+    return pPtr_();
+}
+
+
+volScalarField& incompressibleVars::pInst()
+{
+    return pPtr_();
+}
+
+
+const volVectorField& incompressibleVars::UInst() const
+{
+    return UPtr_();
+}
+
+
+volVectorField& incompressibleVars::UInst()
+{
+    return UPtr_();
+}
+
+
+const surfaceScalarField& incompressibleVars::phiInst() const
+{
+    return phiPtr_();
+}
+
+
+surfaceScalarField& incompressibleVars::phiInst()
+{
+    return phiPtr_();
+}
+
+
+const singlePhaseTransportModel& incompressibleVars::laminarTransport() const
+{
+    return laminarTransportPtr_();
+}
+
+
+singlePhaseTransportModel& incompressibleVars::laminarTransport()
+{
+    return laminarTransportPtr_();
+}
+
+
+const autoPtr<incompressible::turbulenceModel>&
+incompressibleVars::turbulence() const
+{
+    return turbulence_;
+}
+
+
+autoPtr<incompressible::turbulenceModel>& incompressibleVars::turbulence()
+{
+    return turbulence_;
+}
+
+
+const autoPtr<incompressible::RASModelVariables>&
+incompressibleVars::RASModelVariables() const
+{
+    return RASModelVariables_;
+}
+
+
+autoPtr<incompressible::RASModelVariables>&
+incompressibleVars::RASModelVariables()
+{
+    return RASModelVariables_;
+}
+
+
+void incompressibleVars::restoreInitValues()
+{
+    if (solverControl_.storeInitValues())
+    {
+        Info<< "Restoring field values to initial ones" << endl;
+        pInst() == pInitPtr_();
+        UInst() == UInitPtr_();
+        phiInst() == phiInitPtr_();
+        RASModelVariables_().restoreInitValues();
+    }
+}
+
+
+void incompressibleVars::resetMeanFields()
+{
+    if (solverControl_.average())
+    {
+        Info<< "Reseting mean fields to zero" << endl;
+
+        // Reset fields to zero
+        pMeanPtr_() == dimensionedScalar(pInst().dimensions(), Zero);
+        UMeanPtr_() == dimensionedVector(UInst().dimensions(), Zero);
+        phiMeanPtr_() == dimensionedScalar(phiInst().dimensions(), Zero);
+        RASModelVariables_().resetMeanFields();
+
+        // Reset averaging iteration index to 0
+        solverControl_.averageIter() = 0;
+    }
+}
+
+
+void incompressibleVars::computeMeanFields()
+{
+    if (solverControl_.doAverageIter())
+    {
+        Info<< "Averaging fields" << endl;
+        label& iAverageIter = solverControl_.averageIter();
+        scalar avIter(iAverageIter);
+        scalar oneOverItP1 = 1./(avIter + 1);
+        scalar mult = avIter*oneOverItP1;
+        pMeanPtr_() == pMeanPtr_()*mult + pInst()*oneOverItP1;
+        UMeanPtr_() == UMeanPtr_()*mult + UInst()*oneOverItP1;
+        phiMeanPtr_() == phiMeanPtr_()*mult + phiInst()*oneOverItP1;
+        RASModelVariables_().computeMeanFields();
+        ++iAverageIter;
+    }
+}
+
+
+void incompressibleVars::correctBoundaryConditions()
+{
+    correctNonTurbulentBoundaryConditions();
+    RASModelVariables_().correctBoundaryConditions(turbulence_());
+}
+
+
+bool incompressibleVars::storeInitValues() const
+{
+    return solverControl_.storeInitValues();
+}
+
+
+bool incompressibleVars::computeMeanFields() const
+{
+    return solverControl_.average();
+}
+
+
+bool incompressibleVars::write() const
+{
+    // Write dummy fields, for continuation only
+    if (useSolverNameForFields_)
+    {
+        if (RASModelVariables_().hasTMVar1())
+        {
+            createZeroFieldPtr<scalar>
+            (
+                mesh_,
+                RASModelVariables_().TMVar1BaseName(),
+                RASModelVariables_().TMVar1Inst().dimensions()
+            )().write();
+        }
+        if (RASModelVariables_().hasTMVar2())
+        {
+            createZeroFieldPtr<scalar>
+            (
+                mesh_,
+                RASModelVariables_().TMVar2BaseName(),
+                RASModelVariables_().TMVar2Inst().dimensions()
+            )().write();
+        }
+        if (RASModelVariables_().hasNut())
+        {
+            createZeroFieldPtr<scalar>
+            (
+                mesh_,
+                RASModelVariables_().nutBaseName(),
+                RASModelVariables_().nutRefInst().dimensions()
+            )().write();
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressible/incompressibleVars.H b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressible/incompressibleVars.H
new file mode 100644
index 0000000000000000000000000000000000000000..e22543a3395ff3e294be2ad745120abba7780664
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressible/incompressibleVars.H
@@ -0,0 +1,248 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressibleVars
+
+Description
+    Base class for solution control classes
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef incompressibleVars_H
+#define incompressibleVars_H
+
+#include "variablesSet.H"
+#include "fvMesh.H"
+#include "singlePhaseTransportModel.H"
+#include "turbulentTransportModel.H"
+#include "RASModelVariables.H"
+#include "solverControl.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class incompressibleVars Declaration
+\*---------------------------------------------------------------------------*/
+
+class incompressibleVars
+:
+    public variablesSet
+{
+protected:
+
+    // Protected data
+
+        //- Reference to the solverControl of the solver allocating the fields
+        solverControl& solverControl_;
+
+        //- Fields involved in the solution of the incompressible NS equations
+        autoPtr<volScalarField> pPtr_;
+        autoPtr<volVectorField> UPtr_;
+        autoPtr<surfaceScalarField> phiPtr_;
+        autoPtr<singlePhaseTransportModel> laminarTransportPtr_;
+        autoPtr<incompressible::turbulenceModel>turbulence_;
+        autoPtr<incompressible::RASModelVariables> RASModelVariables_;
+        //autoPtr<volScalarField> TPtr_;
+
+        //- Keep a copy of the initial field values if necessary
+        autoPtr<volScalarField> pInitPtr_;
+        autoPtr<volVectorField> UInitPtr_;
+        autoPtr<surfaceScalarField> phiInitPtr_;
+
+        //- Manage mean fields. Turbulent mean fields are managed
+        //- in RASModelVariables
+        autoPtr<volScalarField> pMeanPtr_;
+        autoPtr<volVectorField> UMeanPtr_;
+        autoPtr<surfaceScalarField>phiMeanPtr_;
+
+        //- Update boundary conditions upon construction.
+        //  Useful for cases in which information has been lost on boundary
+        //  (e.g. averaging, redistribution)
+        bool correctBoundaryConditions_;
+
+        //- Read fields and set turbulence
+        void setFields();
+
+        //- Set initial fields if necessary
+        void setInitFields();
+
+        //- Set mean fields if necessary
+        void setMeanFields();
+
+        //- Rename turbulence fields if necessary
+        void renameTurbulenceFields();
+
+        //- Update boundary conditions of mean-flow
+        void correctNonTurbulentBoundaryConditions();
+
+        //- Update boundary conditions of turbulent fields
+        void correctTurbulentBoundaryConditions();
+
+        //- Disallow default bitwise copy construct
+        incompressibleVars(const incompressibleVars&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const incompressibleVars&);
+
+
+public:
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("incompressibleVars");
+
+
+    // Constructors
+
+        //- Construct from mesh
+        incompressibleVars
+        (
+            fvMesh& mesh,
+            solverControl& SolverControl
+        );
+
+
+    //- Destructor
+    virtual ~incompressibleVars() = default;
+
+
+    // Member Functions
+
+        // Access
+
+            // Access to fields that will be later used for the solution of
+            // the adjoint equations. Might be averaged or not, depending on
+            // the corresponding switch
+            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                //- Return const reference to pressure
+                const volScalarField& p() const;
+
+                //- Return reference to pressure
+                volScalarField& p();
+
+                //- Return const reference to velocity
+                const volVectorField& U() const;
+
+                //- Return reference to velocity
+                volVectorField& U();
+
+                //- Return const reference to volume flux
+                const surfaceScalarField& phi() const;
+
+                //- Return reference to volume flux
+                surfaceScalarField& phi();
+
+
+            // Access to instantaneous fields. Solvers should use these fields
+            // to execute a solver iteration
+            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                //- Return const reference to pressure
+                const volScalarField& pInst() const;
+
+                //- Return reference to pressure
+                volScalarField& pInst();
+
+                //- Return const reference to velocity
+                const volVectorField& UInst() const;
+
+                //- Return reference to velocity
+                volVectorField& UInst();
+
+                //- Return const reference to volume flux
+                const surfaceScalarField& phiInst() const;
+
+                //- Return reference to volume flux
+                surfaceScalarField& phiInst();
+
+
+            //- Return const reference to transport model
+            const singlePhaseTransportModel& laminarTransport() const;
+
+            //- Return reference to transport model
+            singlePhaseTransportModel& laminarTransport();
+
+            //- Return const reference to the turbulence model
+            const autoPtr<incompressible::turbulenceModel>& turbulence() const;
+
+            //- Return  reference to the turbulence model
+            autoPtr<incompressible::turbulenceModel>& turbulence();
+
+            //- Return const reference to the turbulence model variables
+            const autoPtr<incompressible::RASModelVariables>&
+                RASModelVariables() const;
+
+            //- Return reference to the turbulence model variables
+            autoPtr<incompressible::RASModelVariables>& RASModelVariables();
+
+            //- Restore field values to the initial ones
+            void restoreInitValues();
+
+            //- Reset mean fields to zero
+            void resetMeanFields();
+
+            //- Compute mean fields on the fly
+            void computeMeanFields();
+
+            //- correct boundaryconditions for all volFields
+            void correctBoundaryConditions();
+
+            //- Return storeInitValues bool
+            bool storeInitValues() const;
+
+            //- Return computeMeanFields bool
+            bool computeMeanFields() const;
+
+            /*
+            //- Return const reference to the temperature
+            const volScalarField& T() const;
+
+            //- Return reference to the temperature
+            volScalarField& T();
+            */
+
+            //- Write dummy turbulent fields to allow for continuation in
+            //- multi-point, turbulent runs
+            bool write() const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.C b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.C
new file mode 100644
index 0000000000000000000000000000000000000000..ab54f709e775776847868d2749c9fdf004f7f371
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.C
@@ -0,0 +1,122 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "incompressibleAdjointVars.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(incompressibleAdjointVars, 0);
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+incompressibleAdjointVars::incompressibleAdjointVars
+(
+    fvMesh& mesh,
+    solverControl& SolverControl,
+    objectiveManager& objManager,
+    incompressibleVars& primalVars
+)
+:
+    incompressibleAdjointMeanFlowVars(mesh, SolverControl, primalVars),
+    objectiveManager_(objManager),
+
+    adjointTurbulence_
+    (
+        incompressibleAdjoint::adjointRASModel::New
+        (
+            primalVars_,
+            *this,
+            objManager
+        )
+    )
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+const autoPtr<incompressibleAdjoint::adjointRASModel>&
+incompressibleAdjointVars::adjointTurbulence() const
+{
+    return adjointTurbulence_;
+}
+
+
+autoPtr<incompressibleAdjoint::adjointRASModel>&
+incompressibleAdjointVars::adjointTurbulence()
+{
+    return adjointTurbulence_;
+}
+
+
+void incompressibleAdjointVars::resetMeanFields()
+{
+    if (solverControl_.average())
+    {
+        Info<< "Reseting adjoint mean fields to zero" << endl;
+
+        // Reset fields to zero
+        paMeanPtr_() == dimensionedScalar(paPtr_().dimensions(), Zero);
+        UaMeanPtr_() == dimensionedVector(UaPtr_().dimensions(), Zero);
+        phiaMeanPtr_() == dimensionedScalar(phiaPtr_().dimensions(), Zero);
+        adjointTurbulence_().resetMeanFields();
+
+        // Reset averaging iteration index to 0
+        solverControl_.averageIter() = 0;
+    }
+}
+
+
+void incompressibleAdjointVars::computeMeanFields()
+{
+    if (solverControl_.doAverageIter())
+    {
+        Info<< "Averaging adjoint fields" << endl;
+        label& iAverageIter = solverControl_.averageIter();
+        scalar avIter(iAverageIter);
+        scalar oneOverItP1 = 1./(avIter+1);
+        scalar mult = avIter*oneOverItP1;
+        paMeanPtr_() == paMeanPtr_()  *mult + paPtr_()  *oneOverItP1;
+        UaMeanPtr_() == UaMeanPtr_()  *mult + UaPtr_()  *oneOverItP1;
+        phiaMeanPtr_() == phiaMeanPtr_()*mult + phiaPtr_()*oneOverItP1;
+        adjointTurbulence_().computeMeanFields();
+        ++iAverageIter;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.H b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.H
new file mode 100644
index 0000000000000000000000000000000000000000..b4bad6c8823e493d6ea81416f18bfe33e4e05ff6
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.H
@@ -0,0 +1,129 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressibleAdjointVars
+
+Description
+    Class including all adjoint fields for incompressible flows
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef incompressibleAdjointVars_H
+#define incompressibleAdjointVars_H
+
+#include "incompressibleAdjointMeanFlowVars.H"
+#include "objectiveManager.H"
+#include "adjointRASModel.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                  Class incompressibleAdjointVars Declaration
+\*---------------------------------------------------------------------------*/
+
+class incompressibleAdjointVars
+:
+    public incompressibleAdjointMeanFlowVars
+{
+protected:
+
+    // Protected data
+
+        //- Reference to the objectiveManager
+        objectiveManager& objectiveManager_;
+
+        //- Adjoint to the turbulence model
+        autoPtr<incompressibleAdjoint::adjointRASModel> adjointTurbulence_;
+
+
+    // Protected Member Functions
+
+        //- Disallow default bitwise copy construct
+        incompressibleAdjointVars(const incompressibleAdjointVars&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const incompressibleAdjointVars&);
+
+
+public:
+
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("incompressibleAdjointVars");
+
+
+    // Constructors
+
+        //- Construct from mesh
+        incompressibleAdjointVars
+        (
+            fvMesh& mesh,
+            solverControl& SolverControl,
+            objectiveManager& objManager,
+            incompressibleVars& primalVars
+        );
+
+
+    //- Destructor
+    virtual ~incompressibleAdjointVars(){};
+
+
+    // Member Functions
+
+        // Access
+
+            //- Return const reference to the adjointRASModel
+            const autoPtr<incompressibleAdjoint::adjointRASModel>&
+                adjointTurbulence() const;
+
+            //- Return non-const reference to the adjointRASModel
+            autoPtr<incompressibleAdjoint::adjointRASModel>&
+                adjointTurbulence();
+
+            //- Reset mean fields to zero
+            void resetMeanFields();
+
+            //- Compute mean fields on the fly
+            void computeMeanFields();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.C b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.C
new file mode 100644
index 0000000000000000000000000000000000000000..f64820e4fb6738c1e90508087a36244e201103aa
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.C
@@ -0,0 +1,271 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "incompressibleAdjointMeanFlowVars.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(incompressibleAdjointMeanFlowVars, 0);
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+void incompressibleAdjointMeanFlowVars::setFields()
+{
+    setField(paPtr_, mesh_, "pa", solverName_, useSolverNameForFields_);
+    setField(UaPtr_, mesh_, "Ua", solverName_, useSolverNameForFields_);
+    setFluxField
+    (
+        phiaPtr_,
+        mesh_,
+        UaInst(),
+        "phia",
+        solverName_,
+        useSolverNameForFields_
+    );
+
+    mesh_.setFluxRequired(paPtr_->name());
+}
+
+void incompressibleAdjointMeanFlowVars::setMeanFields()
+{
+    // Allocate mean fields
+    // Only mean flow here since turbulent quantities
+    // are allocated automatically in RASModelVariables
+    if (solverControl_.average())
+    {
+        Info<< "Allocating Mean Adjoint Fields" << endl;
+        paMeanPtr_.reset
+        (
+            new volScalarField
+            (
+                IOobject
+                (
+                    paInst().name() + "Mean",
+                    mesh_.time().timeName(),
+                    mesh_,
+                    IOobject::READ_IF_PRESENT,
+                    IOobject::AUTO_WRITE
+                ),
+                paInst()
+            )
+        );
+        UaMeanPtr_.reset
+        (
+            new volVectorField
+            (
+                IOobject
+                (
+                    UaInst().name() + "Mean",
+                    mesh_.time().timeName(),
+                    mesh_,
+                    IOobject::READ_IF_PRESENT,
+                    IOobject::AUTO_WRITE
+                ),
+                UaInst()
+            )
+        );
+        phiaMeanPtr_.reset
+        (
+            new surfaceScalarField
+            (
+                IOobject
+                (
+                    phiaInst().name() + "Mean",
+                    mesh_.time().timeName(),
+                    mesh_,
+                    IOobject::READ_IF_PRESENT,
+                    IOobject::AUTO_WRITE
+                ),
+                phiaInst()
+            )
+        );
+    }
+}
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+incompressibleAdjointMeanFlowVars::incompressibleAdjointMeanFlowVars
+(
+    fvMesh& mesh,
+    solverControl& SolverControl,
+    incompressibleVars& primalVars
+)
+:
+    variablesSet(mesh, SolverControl.solverDict()),
+    solverControl_(SolverControl),
+    primalVars_(primalVars),
+    paPtr_(nullptr),
+    UaPtr_(nullptr),
+    phiaPtr_(nullptr),
+    paMeanPtr_(nullptr),
+    UaMeanPtr_(nullptr),
+    phiaMeanPtr_(nullptr)
+{
+    setFields();
+    setMeanFields();
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+const volScalarField& incompressibleAdjointMeanFlowVars::pa() const
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return paMeanPtr_();
+    }
+    else
+    {
+        return paPtr_();
+    }
+}
+
+
+volScalarField& incompressibleAdjointMeanFlowVars::pa()
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return paMeanPtr_();
+    }
+    else
+    {
+        return paPtr_();
+    }
+}
+
+
+const volVectorField& incompressibleAdjointMeanFlowVars::Ua() const
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return UaMeanPtr_();
+    }
+    else
+    {
+        return UaPtr_();
+    }
+}
+
+
+volVectorField& incompressibleAdjointMeanFlowVars::Ua()
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return UaMeanPtr_();
+    }
+    else
+    {
+        return UaPtr_();
+    }
+}
+
+
+const surfaceScalarField& incompressibleAdjointMeanFlowVars::phia() const
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return phiaMeanPtr_();
+    }
+    else
+    {
+        return phiaPtr_();
+    }
+}
+
+
+surfaceScalarField& incompressibleAdjointMeanFlowVars::phia()
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return phiaMeanPtr_();
+    }
+    else
+    {
+        return phiaPtr_();
+    }
+}
+
+
+const volScalarField& incompressibleAdjointMeanFlowVars::paInst() const
+{
+    return paPtr_();
+}
+
+
+volScalarField& incompressibleAdjointMeanFlowVars::paInst()
+{
+    return paPtr_();
+}
+
+
+const volVectorField& incompressibleAdjointMeanFlowVars::UaInst() const
+{
+    return UaPtr_();
+}
+
+
+volVectorField& incompressibleAdjointMeanFlowVars::UaInst()
+{
+    return UaPtr_();
+}
+
+
+const surfaceScalarField& incompressibleAdjointMeanFlowVars::phiaInst() const
+{
+    return phiaPtr_();
+}
+
+
+surfaceScalarField& incompressibleAdjointMeanFlowVars::phiaInst()
+{
+    return phiaPtr_();
+}
+
+
+bool incompressibleAdjointMeanFlowVars::computeMeanFields() const
+{
+    return solverControl_.average();
+}
+
+
+const solverControl& incompressibleAdjointMeanFlowVars::getSolverControl() const
+{
+    return solverControl_;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.H b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.H
new file mode 100644
index 0000000000000000000000000000000000000000..a99fec87dea18fa1a139b364ffcab032e51f2d96
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.H
@@ -0,0 +1,190 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressibleAdjointMeanFlowVars
+
+Description
+    Manages the adjoint mean flow fields and their mean values
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef incompressibleAdjointMeanFlowVars_H
+#define incompressibleAdjointMeanFlowVars_H
+
+#include "variablesSet.H"
+#include "incompressibleVars.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+              Class incompressibleAdjointMeanFlowVars Declaration
+\*---------------------------------------------------------------------------*/
+
+class incompressibleAdjointMeanFlowVars
+:
+    public variablesSet
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        incompressibleAdjointMeanFlowVars
+        (
+            const incompressibleAdjointMeanFlowVars&
+        );
+
+        //- Disallow default bitwise assignment
+        void operator=(const incompressibleAdjointMeanFlowVars&);
+
+
+protected:
+
+    // Protected data
+
+        //- Reference to the solverControl of the solver allocating the fields
+        solverControl& solverControl_;
+
+        //- Reference to primal variables
+        incompressibleVars& primalVars_;
+
+        //- Fields involved in the solution of the incompressible adjoint NS
+        //- equations
+        autoPtr<volScalarField> paPtr_;
+        autoPtr<volVectorField> UaPtr_;
+        autoPtr<surfaceScalarField> phiaPtr_;
+
+        //- Mean Adjoint Fields. Actual averaging is done in the
+        //- incompressibleAdjointVars class to take care of the mean adjoint
+        //- turbulence variables
+        autoPtr<volScalarField> paMeanPtr_;
+        autoPtr<volVectorField> UaMeanPtr_;
+        autoPtr<surfaceScalarField> phiaMeanPtr_;
+
+        // Protected Member Functions
+
+            //- Read fields and set turbulence
+            void setFields();
+
+            //- Read mean fields, if necessary
+            void setMeanFields();
+
+
+public:
+
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("incompressibleAdjointMeanFlowVars");
+
+
+    // Constructors
+
+        //- Construct from mesh
+        incompressibleAdjointMeanFlowVars
+        (
+            fvMesh& mesh,
+            solverControl& SolverControl,
+            incompressibleVars& primalVars
+        );
+
+
+    //- Destructor
+    virtual ~incompressibleAdjointMeanFlowVars() = default;
+
+
+    // Member Functions
+
+
+        // Access
+
+            // Access to adjoint fields. Might be averaged or not depending on
+            // the correspondign switch. Averaged fields are used to compute
+            // an "average" sensitivity field
+
+                //- Return const reference to pressure
+                const volScalarField& pa() const;
+
+                //- Return reference to pressure
+                volScalarField& pa();
+
+                //- Return const reference to velocity
+                const volVectorField& Ua() const;
+
+                //- Return reference to velocity
+                volVectorField& Ua();
+
+                //- Return const reference to volume flux
+                const surfaceScalarField& phia() const;
+
+                //- Return reference to volume flux
+                surfaceScalarField& phia();
+
+
+            // Access to instantaneous fields. Solvers and adjoint boundary
+            // conditions should use these fields to execute a solver iteration
+
+                //- Return const reference to pressure
+                const volScalarField& paInst() const;
+
+                //- Return reference to pressure
+                volScalarField& paInst();
+
+                //- Return const reference to velocity
+                const volVectorField& UaInst() const;
+
+                //- Return reference to velocity
+                volVectorField& UaInst();
+
+                //- Return const reference to volume flux
+                const surfaceScalarField& phiaInst() const;
+
+                //- Return reference to volume flux
+                surfaceScalarField& phiaInst();
+
+            //- Return computeMeanFields bool
+            bool computeMeanFields() const;
+
+            //- Return const reference to solverControl
+            const solverControl& getSolverControl() const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/variablesSet/variablesSet.C b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/variablesSet/variablesSet.C
new file mode 100644
index 0000000000000000000000000000000000000000..65a627d246a7152d82a848a518f87b987fe363b0
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/variablesSet/variablesSet.C
@@ -0,0 +1,192 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "variablesSet.H"
+#include "surfaceFields.H"
+#include "fixedValueFvPatchFields.H"
+#include "linear.H"
+
+#include "wallFvPatch.H"
+#include "emptyFvPatch.H"
+#include "emptyFvPatchField.H"
+#include "processorFvPatch.H"
+#include "processorFvPatchField.H"
+#include "cyclicFvPatch.H"
+#include "cyclicFvPatchField.H"
+#include "cyclicAMIFvPatch.H"
+#include "cyclicAMIFvPatchField.H"
+#include "symmetryFvPatch.H"
+#include "symmetryFvPatchField.H"
+#include "symmetryPlaneFvPatch.H"
+#include "symmetryPlaneFvPatchField.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(variablesSet, 0);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+variablesSet::variablesSet
+(
+    fvMesh& mesh,
+    const dictionary& dict
+)
+:
+    mesh_(mesh),
+    solverName_(dict.dictName()),
+    useSolverNameForFields_
+    (
+        dict.lookupOrDefault<bool>("useSolverNameForFields", false)
+    )
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+const word& variablesSet::solverName() const
+{
+    return solverName_;
+}
+
+
+bool variablesSet::useSolverNameForFields() const
+{
+    return useSolverNameForFields_;
+}
+
+
+void variablesSet::setFluxField
+(
+    autoPtr<surfaceScalarField>& fieldPtr,
+    const fvMesh& mesh,
+    const volVectorField& velocity,
+    const word& baseName,
+    const word& solverName,
+    const bool useSolverNameForFields
+)
+{
+    // Try to read in field with custom or base name
+    bool fieldFound
+    (
+        readFieldOK
+        (
+            fieldPtr,
+            mesh,
+            baseName,
+            solverName,
+            useSolverNameForFields
+        )
+    );
+
+    // No base or custom field found.
+    // Construct field based on linear interpolation
+    if (!fieldFound)
+    {
+        word phiName(baseName);
+        if (useSolverNameForFields)
+        {
+            phiName += solverName;
+        }
+        IOobject header
+        (
+            phiName,
+            mesh.time().timeName(),
+            mesh,
+            IOobject::READ_IF_PRESENT,
+            IOobject::AUTO_WRITE
+        );
+        fieldPtr.reset
+        (
+            new surfaceScalarField
+            (
+                header,
+                linearInterpolate(velocity) & mesh.Sf()
+            )
+        );
+    }
+}
+
+
+tmp<surfaceScalarField> variablesSet::allocateFluxField
+(
+    const fvMesh& mesh,
+    const volVectorField& velocity,
+    const word& baseName,
+    const word& solverName,
+    const bool useSolverNameForFields
+)
+{
+    autoPtr<surfaceScalarField> fieldPtr(nullptr);
+    setFluxField
+    (
+        fieldPtr,
+        mesh,
+        velocity,
+        baseName,
+        solverName,
+        useSolverNameForFields
+    );
+
+    return tmp<surfaceScalarField>(fieldPtr.ptr());
+}
+
+
+tmp<volVectorField> variablesSet::autoCreateMeshMovementField
+(
+    const fvMesh& mesh,
+    const word& fieldName,
+    const dimensionSet& dims
+)
+{
+    return tmp<volVectorField>::New
+    (
+        IOobject
+        (
+            fieldName,
+            mesh.time().timeName(),
+            mesh,
+            IOobject::READ_IF_PRESENT,
+            IOobject::NO_WRITE
+        ),
+        mesh,
+        dimensionedVector(dims, Zero),
+        fixedValueFvPatchVectorField::typeName
+    );
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/variablesSet/variablesSet.H b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/variablesSet/variablesSet.H
new file mode 100644
index 0000000000000000000000000000000000000000..bb66c87298f3c7e9964fafc9ffc15b3db1ab1309
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/variablesSet/variablesSet.H
@@ -0,0 +1,212 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::variablesSet
+
+Description
+    Base class for creating a set of variables
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef variablesSet_H
+#define variablesSet_H
+
+#include "fvMesh.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class variablesSet Declaration
+\*---------------------------------------------------------------------------*/
+
+class variablesSet
+{
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        variablesSet(const variablesSet&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const variablesSet&) = delete;
+
+        //- Add the solverName to every patch entry read from the boundaryField
+        //- of the IOobject and allocate the corresponding GeometricField.
+        //- Used to pass the adjoint solver name to the adjoint boundary
+        //- conditions.
+        //  Returns naked pointer but used only to feed autoPtrs and tmps,
+        //  so memory handling shouldn't be an issue
+        template<class Type, template<class> class PatchField, class GeoMesh>
+        static GeometricField<Type, PatchField, GeoMesh>* allocateNamedField
+        (
+            const fvMesh& mesh,
+            const IOobject& io,
+            const word& solverName
+        );
+
+        //- Read field with base or custom field name
+        template<class Type, template<class> class PatchField, class GeoMesh>
+        static bool readFieldOK
+        (
+            autoPtr<GeometricField<Type, PatchField, GeoMesh>>& fieldPtr,
+            const fvMesh& mesh,
+            const word& baseName,
+            const word& solverName,
+            const bool useSolverNameForFields
+        );
+
+
+protected:
+
+    // Protected data
+
+        //- Reference to the mesh database
+        fvMesh& mesh_;
+
+        //- Solver name owning the variables set
+        word solverName_;
+
+        //- Append the solver name to the variables names?
+        bool useSolverNameForFields_;
+
+
+public:
+
+
+    // Static Data Members
+
+        //- Run-time type information
+        TypeName("variablesSet");
+
+
+    // Constructors
+
+        //- Construct from mesh and solver name
+        variablesSet
+        (
+            fvMesh& mesh,
+            const dictionary& dict
+        );
+
+
+    //- Destructor
+    virtual ~variablesSet() = default;
+
+
+    // Member Functions
+
+        // Access
+
+            //- Return solver name
+            const word& solverName() const;
+
+            //- Append solver name to fields?
+            bool useSolverNameForFields() const;
+
+        // Set functions. Static in order to be used by other classes as well
+
+            //- Read vol fields
+            template<class Type>
+            static void setField
+            (
+                autoPtr<GeometricField<Type, fvPatchField, volMesh>>& fieldPtr,
+                const fvMesh& mesh,
+                const word& baseName,
+                const word& solverName,
+                const bool useSolverNameForFields
+            );
+
+            template<class Type>
+            tmp<GeometricField<Type, fvPatchField, volMesh>> allocateField
+            (
+                const fvMesh& mesh,
+                const word& baseName,
+                const word& solverName,
+                const bool useSolverNameForFields
+            );
+
+            //- Turbulence model always reads fields with the prescribed name
+            //- If a custom name is supplied, check whether this field exists,
+            //- copy it to the field known by the turbulence model
+            //- and re-name the latter
+            template<class Type>
+            void renameTurbulenceField
+            (
+                GeometricField<Type, fvPatchField, volMesh>& baseField,
+                const word& solverName
+            );
+
+            //- Set flux field
+            static void setFluxField
+            (
+                autoPtr<surfaceScalarField>& fieldPtr,
+                const fvMesh& mesh,
+                const volVectorField& velocity,
+                const word& baseName,
+                const word& solverName,
+                const bool useSolverNameForFields
+            );
+
+            tmp<surfaceScalarField> allocateFluxField
+            (
+                const fvMesh& mesh,
+                const volVectorField& velocity,
+                const word& baseName,
+                const word& solverName,
+                const bool useSolverNameForFields
+            );
+
+            //- Auto create variable for mesh movement
+            static tmp<volVectorField> autoCreateMeshMovementField
+            (
+                const fvMesh& mesh,
+                const word& name,
+                const dimensionSet& dims
+            );
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "variablesSetTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/variablesSet/variablesSetTemplates.C b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/variablesSet/variablesSetTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..bc3fb50d51761f723181a18d7dd7d2fa46440442
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/variablesSet/variablesSetTemplates.C
@@ -0,0 +1,292 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "localIOdictionary.H"
+#include "FieldField.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+template<class Type, template<class> class PatchField, class GeoMesh>
+GeometricField<Type, PatchField, GeoMesh>* variablesSet::allocateNamedField
+(
+    const fvMesh& mesh,
+    const IOobject& io,
+    const word& solverName
+)
+{
+    typedef GeometricField<Type, PatchField, GeoMesh> fieldType;
+
+    // Read-in boundary conditions from given IOobject
+    localIOdictionary dict
+    (
+        IOobject
+        (
+            io.name(),
+            io.instance(),
+            io.local(),
+            io.db(),
+            IOobject::MUST_READ,
+            IOobject::NO_WRITE,
+            false
+        ),
+        fieldType::typeName
+    );
+    dictionary& bField(dict.subDict("boundaryField"));
+
+    // Add solverName to all patch entries.
+    // Reduntant if not adjoint fields, but overhead should be small
+    for (entry& dEntry : bField)
+    {
+        if (dEntry.isDict())
+        {
+            dEntry.dict().add<word>("solverName", solverName, true);
+        }
+    }
+    DebugInfo
+        << bField << endl;
+
+    return (new fieldType(io, mesh, dict));
+}
+
+
+template<class Type, template<class> class PatchField, class GeoMesh>
+bool variablesSet::readFieldOK
+(
+    autoPtr<GeometricField<Type, PatchField, GeoMesh>>& fieldPtr,
+    const fvMesh& mesh,
+    const word& baseName,
+    const word& solverName,
+    const bool useSolverNameForFields
+)
+{
+    typedef GeometricField<Type, PatchField, GeoMesh> fieldType;
+
+    word customName = baseName + solverName;
+    IOobject headerCustomName
+    (
+        customName,
+        mesh.time().timeName(),
+        mesh,
+        IOobject::MUST_READ,
+        IOobject::AUTO_WRITE
+    );
+
+    IOobject headerBaseName
+    (
+        baseName,
+        mesh.time().timeName(),
+        mesh,
+        IOobject::MUST_READ,
+        IOobject::AUTO_WRITE
+    );
+
+    bool fieldFound(false);
+
+    // Read field with full name (i.e. baseName plus solverName) if present
+    if
+    (
+        headerCustomName.typeHeaderOk<fieldType>(false)
+     && useSolverNameForFields
+    )
+    {
+        fieldPtr.reset
+        (
+            allocateNamedField<Type, PatchField, GeoMesh>
+            (
+                mesh,
+                headerCustomName,
+                solverName
+            )
+        );
+        fieldFound = true;
+    }
+    // else, see whether the base field exists
+    else if (headerBaseName.typeHeaderOk<fieldType>(false))
+    {
+        fieldPtr.reset
+        (
+            allocateNamedField<Type, PatchField, GeoMesh>
+            (
+                mesh,
+                headerBaseName,
+                solverName
+            )
+        );
+
+        // Rename field if necessary
+        if (useSolverNameForFields)
+        {
+            Info<< "Field " << customName << " not found" << endl;
+            Info<< "Reading base field " << baseName << " and renaming ... "
+                << endl;
+            fieldPtr.ref().rename(customName);
+        }
+        fieldFound = true;
+    }
+
+    return fieldFound;
+}
+
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+template<class Type>
+void variablesSet::setField
+(
+    autoPtr<GeometricField<Type, fvPatchField, volMesh>>& fieldPtr,
+    const fvMesh& mesh,
+    const word& baseName,
+    const word& solverName,
+    const bool useSolverNameForFields
+)
+{
+    // Try to read in field with custom or base name
+    bool fieldFound
+    (
+        readFieldOK
+        (
+            fieldPtr,
+            mesh,
+            baseName,
+            solverName,
+            useSolverNameForFields
+        )
+    );
+
+    // No base or custom field found. This is fatal
+    if (!fieldFound)
+    {
+        FatalErrorInFunction
+            << "Could not read field with custom ("
+            << word(baseName + solverName) << ") "
+            << "or base (" << baseName << ") name"
+            << exit(FatalError);
+    }
+}
+
+
+template<class Type>
+tmp<GeometricField<Type, fvPatchField, volMesh>> variablesSet::allocateField
+(
+    const fvMesh& mesh,
+    const word& baseName,
+    const word& solverName,
+    const bool useSolverNameForFields
+)
+{
+    typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
+
+    autoPtr<VolFieldType> fieldPtr(nullptr);
+    setField(fieldPtr, mesh, baseName, solverName, useSolverNameForFields);
+
+    return tmp<VolFieldType>(fieldPtr.ptr());
+}
+
+
+template<class Type>
+void variablesSet::renameTurbulenceField
+(
+    GeometricField<Type, fvPatchField, volMesh>& baseField,
+    const word& solverName
+)
+{
+    // typedefs
+    typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
+    typedef typename VolFieldType::Boundary Boundary;
+
+    // Name of custom field, to be potentially read in
+    const word baseName = baseField.name();
+    const word customName = baseName + solverName;
+    const fvMesh& mesh = baseField.mesh();
+
+    // Renaming of the base field
+    baseField.rename(customName);
+
+    // Create field with baseName and write it, to enable continuation
+    // Note: gives problems for multi-point runs since we end up with
+    // multiple db entries with the same name (one from here and one from
+    // the solver that will construct a turbulenceModel).
+    // Handled through solver.write() for now
+    /*
+    if (!mesh.foundObject<VolFieldType>(baseName))
+    {
+        autoPtr<VolFieldType> baseCopy(new VolFieldType(baseField));
+        baseCopy().IOobject::writeOpt() = baseField.writeOpt();
+        baseCopy().rename(baseName);
+        regIOobject::store(baseCopy);
+    }
+    */
+
+    // Check whether a field with the custom name exists, read it in and
+    // set supplied base field to that
+    IOobject headerCustomName
+    (
+        customName,
+        mesh.time().timeName(),
+        mesh,
+        IOobject::MUST_READ,
+        IOobject::AUTO_WRITE,
+        false // do not register temp field to avoid db collisions
+    );
+
+    if (headerCustomName.typeHeaderOk<VolFieldType>(true))
+    {
+        Info<< "Reading custom turbulence field " << customName
+            << " and replacing " << baseName << nl << endl;
+        VolFieldType customField(headerCustomName, mesh);
+
+        // Copy internalfield
+        baseField.primitiveFieldRef() = customField.primitiveField();
+
+        // We might apply different boundary conditions per operating point
+        // We need to read them from the custom files and substitute the ones
+        // known by the turbulence model field
+        Boundary& baseBoundary = baseField.boundaryFieldRef();
+        Boundary& customBoundary = customField.boundaryFieldRef();
+        forAll(baseBoundary, patchI)
+        {
+            baseBoundary.set
+            (
+                patchI,
+                customBoundary[patchI].clone(baseField.ref())
+            );
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointLaminar/adjointLaminar.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointLaminar/adjointLaminar.C
new file mode 100644
index 0000000000000000000000000000000000000000..124b71f978154c01cd8b553a184722fdfafc5caf
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointLaminar/adjointLaminar.C
@@ -0,0 +1,195 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointLaminar.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressibleAdjoint
+{
+namespace adjointRASModels
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(adjointLaminar, 0);
+addToRunTimeSelectionTable(adjointRASModel, adjointLaminar, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointLaminar::adjointLaminar
+(
+    incompressibleVars& primalVars,
+    incompressibleAdjointMeanFlowVars& adjointVars,
+    objectiveManager& objManager,
+    const word& adjointTurbulenceModelName,
+    const word& modelName
+)
+:
+    adjointRASModel
+    (
+        modelName,
+        primalVars,
+        adjointVars,
+        objManager,
+        adjointTurbulenceModelName
+    )
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+tmp<volSymmTensorField> adjointLaminar::devReff() const
+{
+    const volVectorField& Ua = adjointVars_.Ua();
+    return tmp<volSymmTensorField>
+    (
+        new volSymmTensorField
+        (
+            IOobject
+            (
+                "devRhoReff",
+                runTime_.timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+           -nu()*dev(twoSymm(fvc::grad(Ua)))
+        )
+    );
+}
+
+
+tmp<fvVectorMatrix> adjointLaminar::divDevReff(volVectorField& U) const
+{
+    return
+    (
+      - fvm::laplacian(nuEff(), U)
+      - fvc::div(nuEff()*dev(T(fvc::grad(U))))
+    );
+}
+
+
+tmp<volVectorField> adjointLaminar::adjointMeanFlowSource()
+{
+    return tmp<volVectorField>::New
+        (
+            IOobject
+            (
+                "adjointMeanFlowSource",
+                runTime_.timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedVector
+            (
+                dimensionSet(0, 1, -2, 0, 0),
+                Zero
+            )
+        );
+}
+
+
+bool adjointLaminar::read()
+{
+    return adjointRASModel::read();
+}
+
+
+void adjointLaminar::correct()
+{
+    adjointTurbulenceModel::correct();
+}
+
+
+const boundaryVectorField& adjointLaminar::adjointMomentumBCSource() const
+{
+    // zero contribution
+    return adjMomentumBCSourcePtr_();
+}
+
+
+const boundaryVectorField& adjointLaminar::wallShapeSensitivities()
+{
+    return wallShapeSensitivitiesPtr_();
+}
+
+
+const boundaryVectorField& adjointLaminar::wallFloCoSensitivities()
+{
+    return wallFloCoSensitivitiesPtr_();
+}
+
+
+tmp<volScalarField> adjointLaminar::distanceSensitivities()
+{
+    return tmp<volScalarField>::New
+        (
+            IOobject
+            (
+                "adjointEikonalSource" + type(),
+                runTime_.timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedScalar(dimLength/pow3(dimTime), Zero)
+       );
+}
+
+
+tmp<volTensorField> adjointLaminar::FISensitivityTerm()
+{
+    return tmp<volTensorField>::New
+        (
+            IOobject
+            (
+                "volumeSensTerm" + type(),
+                runTime_.timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedTensor(dimensionSet(0, 2, -3, 0, 0), Zero)
+       );
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace adjointRASModels
+} // End namespace incompressibleAdjoint
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointLaminar/adjointLaminar.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointLaminar/adjointLaminar.H
new file mode 100644
index 0000000000000000000000000000000000000000..c339e107864a22f8d83847e78f042a780629f0c1
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointLaminar/adjointLaminar.H
@@ -0,0 +1,142 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressibleAdjoint::adjointRASModels::adjointLaminar
+
+Description
+    Dummy turbulence model for a laminar incompressible flow. Can also
+    be used when the "frozen turbulence" assumption is employed.
+
+SourceFiles
+    adjointLaminar.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointRasLaminar_H
+#define adjointRasLaminar_H
+
+#include "adjointRASModel.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressibleAdjoint
+{
+namespace adjointRASModels
+{
+
+/*---------------------------------------------------------------------------*\
+                        Class adjointLaminar Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointLaminar
+:
+    public adjointRASModel
+{
+private:
+
+    // Private Member Functions
+
+        //- No copy construct
+        adjointLaminar(const adjointLaminar&) = delete;
+
+        //- No copy assignment
+        void operator=(const adjointLaminar&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("adjointLaminar");
+
+
+    // Constructors
+
+        //- Construct from components
+        adjointLaminar
+        (
+            incompressibleVars& primalVars,
+            incompressibleAdjointMeanFlowVars& adjointVars,
+            objectiveManager& objManager,
+            const word& adjointTurbulenceModelName
+                = adjointTurbulenceModel::typeName,
+            const word& modelName = typeName
+        );
+
+
+    //- Destructor
+    virtual ~adjointLaminar() = default;
+
+
+    // Member Functions
+
+        //- Return the effective stress tensor, i.e. the adjointLaminar stress
+        virtual tmp<volSymmTensorField> devReff() const;
+
+        //- Return the diffusion term for the momentum equation
+        virtual tmp<fvVectorMatrix> divDevReff(volVectorField& U) const;
+
+        //- Source terms to the adjoint momentum equation due to the
+        //- differentiation of the turbulence model
+        virtual tmp<volVectorField> adjointMeanFlowSource();
+
+        //- Returns zero field
+        virtual const boundaryVectorField& adjointMomentumBCSource() const;
+
+        //- Returns zero field
+        virtual const boundaryVectorField& wallShapeSensitivities();
+
+        //- Returns zero field
+        virtual const boundaryVectorField& wallFloCoSensitivities();
+
+        //- Returns zero field
+        virtual tmp<volScalarField> distanceSensitivities();
+
+        //- Returns zero field
+        virtual tmp<volTensorField> FISensitivityTerm();
+
+        //- Correct the primal viscosity field. Redundant?
+        virtual void correct();
+
+        //- Read adjointRASProperties dictionary
+        virtual bool read();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace adjointRASModels
+} // End namespace incompressibleAdjoint
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.C
new file mode 100644
index 0000000000000000000000000000000000000000..6e8dab5d259d14a0eaa0ad00357e78a223fd42f4
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.C
@@ -0,0 +1,474 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointRASModel.H"
+#include "wallFvPatch.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressibleAdjoint
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(adjointRASModel, 0);
+defineRunTimeSelectionTable(adjointRASModel, dictionary);
+addToRunTimeSelectionTable
+(
+    adjointTurbulenceModel,
+    adjointRASModel,
+    adjointTurbulenceModel
+);
+
+
+// * * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * //
+
+void adjointRASModel::printCoeffs()
+{
+    if (printCoeffs_)
+    {
+        Info<< type() << "Coeffs" << coeffDict_ << endl;
+    }
+}
+
+
+void adjointRASModel::setMeanFields()
+{
+    const solverControl& solControl = adjointVars_.getSolverControl();
+    if (solControl.average())
+    {
+        if (adjointTMVariable1Ptr_.valid())
+        {
+            adjointTMVariable1MeanPtr_.reset
+            (
+                new volScalarField
+                (
+                    IOobject
+                    (
+                        getAdjointTMVariable1Inst().name() + "Mean",
+                        mesh_.time().timeName(),
+                        mesh_,
+                        IOobject::READ_IF_PRESENT,
+                        IOobject::AUTO_WRITE
+                    ),
+                    getAdjointTMVariable1Inst()
+                )
+            );
+        }
+
+        if (adjointTMVariable2Ptr_.valid())
+        {
+            adjointTMVariable2MeanPtr_.reset
+            (
+                new volScalarField
+                (
+                    IOobject
+                    (
+                        getAdjointTMVariable2Inst().name() + "Mean",
+                        mesh_.time().timeName(),
+                        mesh_,
+                        IOobject::READ_IF_PRESENT,
+                        IOobject::AUTO_WRITE
+                    ),
+                    getAdjointTMVariable2Inst()
+                )
+            );
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointRASModel::adjointRASModel
+(
+    const word& type,
+    incompressibleVars& primalVars,
+    incompressibleAdjointMeanFlowVars& adjointVars,
+    objectiveManager& objManager,
+    const word& adjointTurbulenceModelName
+)
+:
+    adjointTurbulenceModel
+    (
+        primalVars,
+        adjointVars,
+        objManager,
+        adjointTurbulenceModelName
+    ),
+    IOdictionary
+    (
+        IOobject
+        (
+            "adjointRASProperties",
+            primalVars.U().time().constant(),
+            primalVars.U().db(),
+            IOobject::MUST_READ_IF_MODIFIED,
+            IOobject::NO_WRITE
+        )
+    ),
+
+    objectiveManager_(objManager),
+
+    adjointTurbulence_(get<word>("adjointTurbulence")),
+    printCoeffs_(lookupOrDefault<Switch>("printCoeffs", false)),
+    coeffDict_(subOrEmptyDict(type + "Coeffs")),
+
+    y_(mesh_),
+
+    adjointTMVariable1Ptr_(nullptr),
+    adjointTMVariable2Ptr_(nullptr),
+    adjointTMVariable1MeanPtr_(nullptr),
+    adjointTMVariable2MeanPtr_(nullptr),
+    adjMomentumBCSourcePtr_( createZeroBoundaryPtr<vector>(mesh_) ),
+    wallShapeSensitivitiesPtr_( createZeroBoundaryPtr<vector>(mesh_) ),
+    wallFloCoSensitivitiesPtr_( createZeroBoundaryPtr<vector>(mesh_) ),
+    includeDistance_(false),
+    changedPrimalSolution_(true)
+{}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+autoPtr<adjointRASModel> adjointRASModel::New
+(
+    incompressibleVars& primalVars,
+    incompressibleAdjointMeanFlowVars& adjointVars,
+    objectiveManager& objManager,
+    const word& adjointTurbulenceModelName
+)
+{
+    // Get model name, but do not register the dictionary
+    // otherwise it is registered in the database twice
+    const word modelType
+    (
+        IOdictionary
+        (
+            IOobject
+            (
+                "adjointRASProperties",
+                primalVars.U().time().constant(),
+                primalVars.U().db(),
+                IOobject::MUST_READ_IF_MODIFIED,
+                IOobject::NO_WRITE,
+                false
+            )
+        ).get<word>("adjointRASModel")
+    );
+
+    Info<< "Selecting adjointRAS turbulence model " << modelType << endl;
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown adjointRASModel type "
+            << modelType << nl << nl
+            << "Valid adjointRASModel types:" << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return autoPtr<adjointRASModel>
+    (
+        cstrIter()
+        (
+            primalVars,
+            adjointVars,
+            objManager,
+            adjointTurbulenceModelName
+        )
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void adjointRASModel::correct()
+{
+    adjointTurbulenceModel::correct();
+
+    if (adjointTurbulence_ && mesh_.changing())
+    {
+        y_.correct();
+    }
+}
+
+
+bool adjointRASModel::read()
+{
+    //if (regIOobject::read())
+
+    // Bit of trickery : we are both IOdictionary ('adjointRASProperties') and
+    // an regIOobject from the adjointTurbulenceModel level. Problem is to
+    // distinguish between the two - we only want to reread the IOdictionary.
+
+    bool ok = IOdictionary::readData
+    (
+        IOdictionary::readStream
+        (
+            IOdictionary::type()
+        )
+    );
+    IOdictionary::close();
+
+    if (ok)
+    {
+        readEntry("adjointTurbulence", adjointTurbulence_);
+
+        if (const dictionary* dictPtr = findDict(type() + "Coeffs"))
+        {
+            coeffDict_ <<= *dictPtr;
+        }
+
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+
+volScalarField& adjointRASModel::getAdjointTMVariable1Inst()
+{
+    if (adjointTMVariable1Ptr_.empty())
+    {
+        // if pointer is not set, set it to a zero field
+        adjointTMVariable1Ptr_.reset
+        (
+            new volScalarField
+            (
+                IOobject
+                (
+                    "adjointTMVariable1" + type(),
+                    mesh_.time().timeName(),
+                    mesh_,
+                    IOobject::NO_READ,
+                    IOobject::NO_WRITE
+                ),
+                mesh_,
+                dimensionedScalar(dimless, Zero)
+            )
+        );
+    }
+
+    return adjointTMVariable1Ptr_();
+}
+
+
+volScalarField& adjointRASModel::getAdjointTMVariable2Inst()
+{
+    if (adjointTMVariable2Ptr_.empty())
+    {
+        // if pointer is not set, set it to a zero field
+        adjointTMVariable2Ptr_.reset
+        (
+            new volScalarField
+            (
+                IOobject
+                (
+                   "adjointTMVariable2" + type(),
+                   mesh_.time().timeName(),
+                   mesh_,
+                   IOobject::NO_READ,
+                   IOobject::NO_WRITE
+                ),
+                mesh_,
+                dimensionedScalar(dimless, Zero)
+            )
+        );
+    }
+
+    return adjointTMVariable2Ptr_();
+}
+
+
+volScalarField& adjointRASModel::getAdjointTMVariable1()
+{
+    if (adjointVars_.getSolverControl().useAveragedFields())
+    {
+        return adjointTMVariable1MeanPtr_();
+    }
+    else
+    {
+        return getAdjointTMVariable1Inst();
+    }
+}
+
+
+
+volScalarField& adjointRASModel::getAdjointTMVariable2()
+{
+    if (adjointVars_.getSolverControl().useAveragedFields())
+    {
+        return adjointTMVariable2MeanPtr_();
+    }
+    else
+    {
+        return getAdjointTMVariable2Inst();
+    }
+}
+
+
+autoPtr<volScalarField>& adjointRASModel::getAdjointTMVariable1InstPtr()
+{
+    return adjointTMVariable1Ptr_;
+}
+
+
+autoPtr<volScalarField>& adjointRASModel::getAdjointTMVariable2InstPtr()
+{
+    return adjointTMVariable2Ptr_;
+}
+
+
+tmp<volScalarField> adjointRASModel::nutJacobianTMVar1() const
+{
+    return
+        tmp<volScalarField>::New
+        (
+            IOobject
+            (
+                "nutJacobianTMVar1"+type(),
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedScalar
+            (
+               nut().dimensions()/adjointTMVariable1Ptr_().dimensions(),
+               Zero
+            )
+        );
+}
+
+
+tmp<volScalarField> adjointRASModel::nutJacobianTMVar2() const
+{
+    return
+        tmp<volScalarField>::New
+        (
+            IOobject
+            (
+                "nutJacobianTMVar2"+type(),
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedScalar
+            (
+                nut().dimensions()/adjointTMVariable2Ptr_().dimensions(),
+                Zero
+            )
+        );
+}
+
+
+tmp<scalarField> adjointRASModel::diffusionCoeffVar1(label patchI) const
+{
+    return tmp<scalarField>::New(mesh_.boundary()[patchI].size(), Zero);
+}
+
+
+tmp<scalarField> adjointRASModel::diffusionCoeffVar2(label patchI) const
+{
+    return tmp<scalarField>::New(mesh_.boundary()[patchI].size(), Zero);
+}
+
+
+void adjointRASModel::setChangedPrimalSolution()
+{
+    changedPrimalSolution_ = true;
+}
+
+
+void adjointRASModel::resetMeanFields()
+{
+    const solverControl& solControl = adjointVars_.getSolverControl();
+    if (solControl.average())
+    {
+        if (adjointTMVariable1MeanPtr_.valid())
+        {
+            adjointTMVariable1MeanPtr_() ==
+                dimensionedScalar(adjointTMVariable1Ptr_().dimensions(), Zero);
+        }
+        if (adjointTMVariable2MeanPtr_.valid())
+        {
+            adjointTMVariable2MeanPtr_() ==
+                dimensionedScalar(adjointTMVariable2Ptr_().dimensions(), Zero);
+        }
+    }
+}
+
+
+void adjointRASModel::computeMeanFields()
+{
+    const solverControl& solControl = adjointVars_.getSolverControl();
+    if (solControl.doAverageIter())
+    {
+        const label iAverageIter = solControl.averageIter();
+        scalar avIter(iAverageIter);
+        scalar oneOverItP1 = 1./(avIter+1);
+        scalar mult = avIter*oneOverItP1;
+        if (adjointTMVariable1MeanPtr_.valid())
+        {
+            adjointTMVariable1MeanPtr_() ==
+                adjointTMVariable1Ptr_()*mult
+              + getAdjointTMVariable1Inst()*oneOverItP1;
+        }
+        if (adjointTMVariable2MeanPtr_.valid())
+        {
+            adjointTMVariable2MeanPtr_() ==
+                adjointTMVariable2Ptr_()*mult
+              + getAdjointTMVariable2Inst()*oneOverItP1;
+        }
+    }
+}
+
+
+bool adjointRASModel::includeDistance() const
+{
+    return includeDistance_;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.H
new file mode 100644
index 0000000000000000000000000000000000000000..6fd893f76bb0ff82a7d85fac6b8410c35b7d8d4e
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.H
@@ -0,0 +1,323 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::adjointRASModels
+
+Description
+    Namespace for incompressible adjointRAS turbulence models.
+
+Class
+    Foam::incompressibleAdjoint::adjointRASModel
+
+Description
+    Abstract base class for incompressible turbulence models.
+
+SourceFiles
+    adjointRASModel.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointRASModel_H
+#define adjointRASModel_H
+
+#include "adjointTurbulenceModel.H"
+#include "volFields.H"
+#include "surfaceFields.H"
+#include "nearWallDist.H"
+#include "fvm.H"
+#include "fvc.H"
+#include "fvMatrices.H"
+#include "incompressible/transportModel/transportModel.H"
+#include "IOdictionary.H"
+#include "Switch.H"
+#include "bound.H"
+#include "autoPtr.H"
+#include "runTimeSelectionTables.H"
+#include "objectiveManager.H"
+#include "boundaryFieldsFwd.H"
+#include "createZeroField.H"
+#include "solverControl.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressibleAdjoint
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class adjointRASModel Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointRASModel
+:
+    public adjointTurbulenceModel,
+    public IOdictionary
+{
+private:
+
+    // Private Member Functions
+
+        //- No copy construct
+        adjointRASModel(const adjointRASModel&) = delete;
+
+        //- No copy assignment
+        void operator=(const adjointRASModel&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        //- Reference to the objectiveManager
+        objectiveManager& objectiveManager_;
+
+        //- Turbulence on/off flag
+        Switch adjointTurbulence_;
+
+        //- Flag to print the model coeffs at run-time
+        Switch printCoeffs_;
+
+        //- Model coefficients dictionary
+        dictionary coeffDict_;
+
+        //- Near wall distance boundary field
+        nearWallDist y_;
+
+        //- Adjoint turbulence model variable 1
+        autoPtr<volScalarField> adjointTMVariable1Ptr_;
+
+        //- Adjoint turbulence model variable 2
+        autoPtr<volScalarField> adjointTMVariable2Ptr_;
+
+        //- Adjoint turbulence model variable 1, mean value
+        autoPtr<volScalarField> adjointTMVariable1MeanPtr_;
+
+        //- Adjoint turbulence model variable 2, mean value
+        autoPtr<volScalarField> adjointTMVariable2MeanPtr_;
+
+        //- Source to the adjoint momentum BC emerging
+        //- from differentiating the turbulence model
+        autoPtr<boundaryVectorField> adjMomentumBCSourcePtr_;
+
+        //- Wall sensitivity term for shape optimisation
+        autoPtr<boundaryVectorField> wallShapeSensitivitiesPtr_;
+
+        //- Wall sensitivity term for flow control optimisation
+        autoPtr<boundaryVectorField> wallFloCoSensitivitiesPtr_;
+
+        //- Does the turbulence model include distances and should the
+        //- adjoint to the distance field be computed
+        bool includeDistance_;
+
+        //- Has the primal solution changed?
+        bool changedPrimalSolution_;
+
+
+    // Protected Member Functions
+
+        //- Print model coefficients
+        virtual void printCoeffs();
+
+        //- Set mean fields
+        void setMeanFields();
+
+
+public:
+
+    //- Runtime type information
+    TypeName("adjointRASModel");
+
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            adjointRASModel,
+            dictionary,
+            (
+                incompressibleVars& primalVars,
+                incompressibleAdjointMeanFlowVars& adjointVars,
+                objectiveManager& objManager,
+                const word& adjointTurbulenceModelName
+            ),
+            (
+                primalVars,
+                adjointVars,
+                objManager,
+                adjointTurbulenceModelName
+            )
+        );
+
+
+    // Constructors
+
+        //- Construct from components
+        adjointRASModel
+        (
+            const word& type,
+            incompressibleVars& primalVars,
+            incompressibleAdjointMeanFlowVars& adjointVars,
+            objectiveManager& objManager,
+            const word& adjointTurbulenceModelName =
+                adjointTurbulenceModel::typeName
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected adjointRAS model
+        static autoPtr<adjointRASModel> New
+        (
+            incompressibleVars& primalVars,
+            incompressibleAdjointMeanFlowVars& adjointVars,
+            objectiveManager& objManager,
+            const word& adjointTurbulenceModelName =
+                adjointTurbulenceModel::typeName
+        );
+
+
+    //- Destructor
+    virtual ~adjointRASModel() = default;
+
+
+    // Member Functions
+
+        //- Return the near wall distances
+        const nearWallDist& y() const
+        {
+            return y_;
+        }
+
+        //- Const access to the coefficients dictionary
+        const dictionary& coeffDict() const
+        {
+            return coeffDict_;
+        }
+
+        //- Return non-constant reference to adjoint turbulence model variable 1
+        //  Will allocate and return a zero field in case it does not exist
+        volScalarField& getAdjointTMVariable1Inst();
+
+        //- Return non-constant reference to adjoint turbulence model variable 2
+        //  Will allocate and return a zero field in case it does not exist
+        volScalarField& getAdjointTMVariable2Inst();
+
+        //- Return non-constant reference to adjoint turbulence model variable 1
+        //  Will return the mean value if present,
+        //  otherwise the instantaneous value
+        volScalarField& getAdjointTMVariable1();
+
+        //- Return non-constant reference to adjoint turbulence model variable 2
+        //  Will return the mean value if present,
+        //  otherwise the instantaneous value
+        volScalarField& getAdjointTMVariable2();
+
+        //- Return non-constant autoPtr to adjoint turbulence model variable 1
+        autoPtr<volScalarField>& getAdjointTMVariable1InstPtr();
+
+        //- Return non-constant autoPtr to adjoint turbulence model variable 2
+        autoPtr<volScalarField>& getAdjointTMVariable2InstPtr();
+
+        //- Return the effective stress tensor including the laminar stress
+        virtual tmp<volSymmTensorField> devReff() const = 0;
+
+        //- Return the diffusion term for the momentum equation
+        virtual tmp<fvVectorMatrix> divDevReff(volVectorField& U) const = 0;
+
+        //- Source terms to the adjoint momentum equation due to
+        //- the differentiation of the turbulence model
+        virtual tmp<volVectorField> adjointMeanFlowSource() = 0;
+
+        //- Jacobian of nut wrt the first turbulence model variable
+        //  Needed for objective functions that depend on nut. Defaults to zero
+        virtual tmp<volScalarField> nutJacobianTMVar1() const;
+
+        //- Jacobian of nut wrt the second turbulence model variable
+        //  Needed for objective functions that depend on nut. Defaults to zero
+        virtual tmp<volScalarField> nutJacobianTMVar2() const;
+
+        //- Diffusion coefficient of the first primal and adjoint turbulence
+        //- model equation. Needed for some adjoint BCs. Defaults to zero
+        virtual tmp<scalarField> diffusionCoeffVar1(label patchI) const;
+
+        //- Diffusion coefficient of the second primal and adjoint turbulence
+        //- model equation. Needed for some adjoint BCs. Defaults to zero
+        virtual tmp<scalarField> diffusionCoeffVar2(label patchI) const;
+
+        //- Source for the outlet adjoint momentum BC coming from
+        //- differentiating the turbulence model
+        virtual const boundaryVectorField& adjointMomentumBCSource() const = 0;
+
+        //- Sensitivity terms for shape optimisation, emerging from
+        //  the turbulence model differentiation.
+        //  Misses dxdb, to be added by the classes assembling the sensitivities
+        virtual const boundaryVectorField& wallShapeSensitivities() = 0;
+
+        //- Sensitivity terms for flow control, emerging from the
+        //  turbulence model differentiation
+        virtual const boundaryVectorField& wallFloCoSensitivities() = 0;
+
+        //- Sensitivity terms resulting from the differentiation of the
+        //- distance field. Misses dxdb, to be added by the classes
+        //- assembling the sensitivities
+        virtual tmp<volScalarField> distanceSensitivities() = 0;
+
+        //- Term contributing to the computation of FI-based sensitivities
+        //  Misses grad(dxdb), to be added by the assembling the sensitivities
+        virtual tmp<volTensorField> FISensitivityTerm() = 0;
+
+        //- Solve the adjoint turbulence equations
+        virtual void correct();
+
+        //- Read adjointRASProperties dictionary
+        virtual bool read();
+
+        //- Set flag of changed primal solution to true
+        void setChangedPrimalSolution();
+
+        //- Reset mean fields to zero
+        void resetMeanFields();
+
+        //- Average adjoint fields on the fly
+        void computeMeanFields();
+
+        //- Should the adjoint to the eikonal equation be computed
+        bool includeDistance() const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.C
new file mode 100644
index 0000000000000000000000000000000000000000..3d52196b603060b8d93dd1753aa4fe9a0184d8ae
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.C
@@ -0,0 +1,1103 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointSpalartAllmaras.H"
+#include "addToRunTimeSelectionTable.H"
+#include "wallDist.H"
+#include "wallFvPatch.H"
+#include "nutUSpaldingWallFunctionFvPatchScalarField.H"
+#include "boundaryAdjointContribution.H"
+#include "coupledFvPatch.H"
+#include "ATCModel.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressibleAdjoint
+{
+namespace adjointRASModels
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(adjointSpalartAllmaras, 0);
+addToRunTimeSelectionTable
+(
+    adjointRASModel,
+    adjointSpalartAllmaras,
+    dictionary
+);
+
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+// * * * * * * * * * * * * Primal Spalart - Allmaras * * * * * * * * * * * * //
+
+tmp<volScalarField> adjointSpalartAllmaras::chi() const
+{
+    return nuTilda()/nu();
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::fv1(const volScalarField& chi) const
+{
+    const volScalarField chi3(pow3(chi));
+    return chi3/(chi3 + pow3(Cv1_));
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::fv2
+(
+    const volScalarField& chi,
+    const volScalarField& fv1
+) const
+{
+    return 1.0 - chi/(1.0 + chi*fv1);
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::Stilda
+(
+    const volScalarField& chi,
+    const volScalarField& fv1
+) const
+{
+    volScalarField Omega(::sqrt(2.0)*mag(skew(gradU_)));
+
+    return
+    (
+        max
+        (
+            Omega
+          + fv2(chi, fv1)*nuTilda()/sqr(kappa_*y_),
+            Cs_*Omega
+        )
+    );
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::r
+(
+    const volScalarField& Stilda
+) const
+{
+    tmp<volScalarField> tr
+    (
+        new volScalarField
+        (
+            min
+            (
+                nuTilda()/(max(Stilda, minStilda_)*sqr(kappa_*y_)),
+                scalar(10)
+            )
+        )
+    );
+    tr.ref().boundaryFieldRef() == Zero;
+
+    return tr;
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::fw
+(
+    const volScalarField& Stilda
+) const
+{
+    const volScalarField g(r_ + Cw2_*(pow6(r_) - r_));
+
+    return g*pow((1.0 + pow6(Cw3_))/(pow6(g) + pow6(Cw3_)), 1.0/6.0);
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::DnuTildaEff() const
+{
+    return tmp<volScalarField>
+    (
+        new volScalarField("DnuTildaEff", (nuTilda() + this->nu())/sigmaNut_)
+    );
+}
+
+
+const volScalarField& adjointSpalartAllmaras::nuTilda() const
+{
+    return primalVars_.RASModelVariables()().TMVar1();
+}
+
+
+const volScalarField& adjointSpalartAllmaras::nut() const
+{
+    return primalVars_.RASModelVariables()().nutRef();
+}
+
+
+// * * * * * * * * * * *  Adjoint Spalart - Allmaras * * * * * * * * * * * * //
+
+tmp<volScalarField> adjointSpalartAllmaras::dFv1_dChi
+(
+    const volScalarField& chi
+) const
+{
+    volScalarField chi3(pow3(chi));
+
+    return 3.0*pow3(Cv1_)*sqr(chi/(chi3+pow3(Cv1_)));
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dFv2_dChi
+(
+    const volScalarField& chi,
+    const volScalarField& fv1,
+    const volScalarField& dFv1dChi
+) const
+{
+    return (chi*chi*dFv1dChi - 1.)/sqr(1. + chi*fv1);
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dStilda_dOmega
+(
+    const volScalarField& Omega,
+    const volScalarField& fv2
+) const
+{
+    volScalarField fieldSwitch
+    (
+        Omega + fv2*nuTilda()/sqr(kappa_*y_) - Cs_*Omega
+    );
+
+    return pos(fieldSwitch) + neg(fieldSwitch)*Cs_;
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dStilda_dNuTilda
+(
+    const volScalarField& Omega,
+    const volScalarField& fv2,
+    const volScalarField& dFv2dChi
+) const
+{
+    volScalarField invDenom(1./sqr(kappa_*y_));
+    volScalarField fieldSwitch(Omega + fv2*nuTilda()*invDenom - Cs_*Omega);
+
+    return pos(fieldSwitch)*(dFv2dChi*nuTilda()*invDenom/nu() + fv2*invDenom);
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dStilda_dDelta
+(
+    const volScalarField& Omega,
+    const volScalarField& fv2
+) const
+{
+    volScalarField aux(fv2*nuTilda()/sqr(kappa_*y_));
+    volScalarField fieldSwitch(Omega + aux - Cs_*Omega);
+
+    return - 2.*pos(fieldSwitch)*aux/y_;
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dr_dNuTilda
+(
+    const volScalarField& Stilda
+) const
+{
+    tmp<volScalarField> tdrdNutilda
+    (
+        1./(max(Stilda, minStilda_)*sqr(kappa_*y_))
+        *(scalar(10) - r_)/(scalar(10) - r_ + SMALL)
+    );
+    tdrdNutilda.ref().boundaryFieldRef() == Zero;
+
+    return tdrdNutilda;
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dr_dStilda
+(
+    const volScalarField& Stilda
+) const
+{
+    tmp<volScalarField> tdrdStilda
+    (
+        - nuTilda()/sqr(max(Stilda, minStilda_)*kappa_*y_)
+        *(scalar(10) - r_)/(scalar(10) - r_ + SMALL)
+    );
+    tdrdStilda.ref().boundaryFieldRef() == Zero;
+
+    return tdrdStilda;
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dr_dDelta
+(
+    const volScalarField& Stilda
+) const
+{
+    tmp<volScalarField> tdrdDelta
+    (
+        -2.*nuTilda()/(max(Stilda, minStilda_)*sqr(kappa_*y_)*y_)
+        *(scalar(10) - r_)/(scalar(10) - r_ + SMALL)
+    );
+    tdrdDelta.ref().boundaryFieldRef() == Zero;
+
+    return tdrdDelta;
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dfw_dr
+(
+    const volScalarField& Stilda
+) const
+{
+    volScalarField g(r_ + Cw2_*(pow6(r_) - r_));
+
+    dimensionedScalar pow6Cw3 = pow6(Cw3_);
+    volScalarField pow6g(pow6(g));
+
+    return  pow6Cw3/(pow6g + pow6Cw3)
+           *pow((1.0 + pow6Cw3)/(pow6g + pow6Cw3), 1.0/6.0)
+           *(1.0 + Cw2_*(6.0*pow5(r_) - 1.0));
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dfw_dNuTilda
+(
+    const volScalarField& Stilda,
+    const volScalarField& dfwdr,
+    const volScalarField& dStildadNuTilda
+) const
+{
+    volScalarField invDenom(1./sqr(kappa_*y_));
+
+    return
+        dfwdr*(dr_dNuTilda(Stilda) + dr_dStilda(Stilda)*dStildadNuTilda);
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dfw_dOmega
+(
+    const volScalarField& Stilda,
+    const volScalarField& dfwdr,
+    const volScalarField& dStildadOmega
+) const
+{
+    return dfwdr*dr_dStilda(Stilda)*dStildadOmega;
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dfw_dDelta
+(
+    const volScalarField& Stilda,
+    const volScalarField& dfwdr,
+    const volScalarField& dStildadDelta
+) const
+{
+    return dfwdr*(dr_dDelta(Stilda) + dr_dStilda(Stilda)*dStildadDelta);
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dD_dNuTilda
+(
+    const volScalarField& fw,
+    const volScalarField& dfwdNuTilda
+) const
+{
+    return Cw1_*(nuTilda()*dfwdNuTilda + fw)/sqr(y_);
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dP_dNuTilda
+(
+    const volScalarField& dStildadNuTilda
+) const
+{
+    return - Cb1_*dStildadNuTilda;
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::dnut_dNuTilda
+(
+    const volScalarField& fv1,
+    const volScalarField& dFv1dChi
+) const
+{
+    return dFv1dChi*nuTilda()/nu() + fv1;
+}
+
+
+tmp<volVectorField> adjointSpalartAllmaras::conservativeMomentumSource()
+{
+    // Store boundary field of the conservative part,
+    // for use in adjoint outlet boundary conditions
+    forAll(mesh_.boundary(), pI)
+    {
+        const fvPatch& patch = mesh_.boundary()[pI];
+        if(!isA<coupledFvPatch>(patch))
+        {
+            vectorField nf(patch.nf());
+            adjMomentumBCSourcePtr_()[pI] =
+                (nf & momentumSourceMult_.boundaryField()[pI])
+               *nuaTilda().boundaryField()[pI];
+        }
+    }
+
+    return fvc::div(momentumSourceMult_*nuaTilda());
+}
+
+
+void adjointSpalartAllmaras::updatePrimalRelatedFields()
+{
+    if (changedPrimalSolution_)
+    {
+        Info<< "Updating primal-based fields of the adjoint turbulence "
+            << "model ..." << endl;
+
+        // Grab references
+        const volVectorField& U = primalVars_.U();
+
+        // Update gradient fields
+        gradU_ = mask_*fvc::grad(U, "gradUStilda");
+        gradNuTilda_ = fvc::grad(nuTilda());
+
+        const volScalarField Omega(::sqrt(2.0)*mag(skew(gradU_)));
+
+        // Primal SA fields
+        volScalarField chi(this->chi());
+        volScalarField fv1(this->fv1(chi));
+        volScalarField fv2(this->fv2(chi, fv1));
+        Stilda_ = Stilda(chi, fv1);
+        r_ = r(Stilda_);
+        fw_ = this->fw(Stilda_);
+
+        // Derivatives of primal fields wrt to nuTilda
+        volScalarField dFv1_dChi(this->dFv1_dChi(chi));
+        volScalarField dFv2_dChi(this->dFv2_dChi(chi, fv1, dFv1_dChi));
+        volScalarField dStilda_dNuTilda
+            (this->dStilda_dNuTilda(Omega, fv2, dFv2_dChi));
+        volScalarField dfw_dr(this->dfw_dr(Stilda_));
+        volScalarField dfw_dNuTilda
+            (this->dfw_dNuTilda(Stilda_, dfw_dr, dStilda_dNuTilda));
+
+        // Fields to be used in the nuaTilda equation
+        symmAdjointProductionU_ =
+            symm(mask_*fvc::grad(U, "adjointProductionU"));
+
+        productionDestructionSource_ =
+            nuTilda()
+           *(
+                dD_dNuTilda(fw_, dfw_dNuTilda)
+              + dP_dNuTilda(dStilda_dNuTilda)
+            );
+
+        Cdnut_ = dnut_dNuTilda(fv1, dFv1_dChi);
+
+        // Constant multiplier in the adjoint momentum source term
+        volScalarField dStilda_dOmega(this->dStilda_dOmega(Omega, fv2));
+        volScalarField dfw_dOmega
+            (this->dfw_dOmega(Stilda_, dfw_dr, dStilda_dOmega));
+
+        momentumSourceMult_ =
+            2.*skew(gradU_)
+           /(Omega + dimensionedScalar("SMALL", Omega.dimensions(), SMALL))
+           *(
+              - Cb1_*nuTilda()*dStilda_dOmega
+              + Cw1_*sqr(nuTilda()/y_)*dfw_dOmega
+            );
+
+        // Set changedPrimalSolution_ to false to avoid recomputing these
+        // fields unless the primal has changed
+        changedPrimalSolution_ = false;
+    }
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::allocateMask()
+{
+    tmp<volScalarField> mask;
+    if (limitAdjointProduction_)
+    {
+        mask = ATCModel::createLimiter(mesh_, coeffDict_);
+    }
+    else
+    {
+        mask = tmp<volScalarField>
+        (
+            new volScalarField
+            (
+                IOobject
+                (
+                   "unitMask",
+                   mesh_.time().timeName(),
+                   mesh_,
+                   IOobject::NO_READ,
+                   IOobject::NO_WRITE
+                ),
+                mesh_,
+                dimensionedScalar("unit", dimless, scalar(1))
+            )
+        );
+    }
+
+    return mask;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointSpalartAllmaras::adjointSpalartAllmaras
+(
+    incompressibleVars& primalVars,
+    incompressibleAdjointMeanFlowVars& adjointVars,
+    objectiveManager& objManager,
+    const word& adjointTurbulenceModelName,
+    const word& modelName
+)
+:
+    adjointRASModel
+    (
+        modelName,
+        primalVars,
+        adjointVars,
+        objManager,
+        adjointTurbulenceModelName
+    ),
+
+    sigmaNut_
+    (
+        dimensioned<scalar>::lookupOrAddToDict
+        (
+            "sigmaNut",
+            this->coeffDict_,
+            0.66666
+        )
+    ),
+    kappa_
+    (
+        dimensioned<scalar>::lookupOrAddToDict
+        (
+            "kappa",
+            this->coeffDict_,
+            0.41
+        )
+    ),
+
+    Cb1_
+    (
+        dimensioned<scalar>::lookupOrAddToDict
+        (
+            "Cb1",
+            this->coeffDict_,
+            0.1355
+        )
+    ),
+    Cb2_
+    (
+        dimensioned<scalar>::lookupOrAddToDict
+        (
+            "Cb2",
+            this->coeffDict_,
+            0.622
+        )
+    ),
+    Cw1_(Cb1_/sqr(kappa_) + (1.0 + Cb2_)/sigmaNut_),
+    Cw2_
+    (
+        dimensioned<scalar>::lookupOrAddToDict
+        (
+            "Cw2",
+            this->coeffDict_,
+            0.3
+        )
+    ),
+    Cw3_
+    (
+        dimensioned<scalar>::lookupOrAddToDict
+        (
+            "Cw3",
+            this->coeffDict_,
+            2.0
+        )
+    ),
+    Cv1_
+    (
+        dimensioned<scalar>::lookupOrAddToDict
+        (
+            "Cv1",
+            this->coeffDict_,
+            7.1
+        )
+    ),
+    Cs_
+    (
+        dimensioned<scalar>::lookupOrAddToDict
+        (
+            "Cs",
+            this->coeffDict_,
+            0.3
+        )
+    ),
+
+    limitAdjointProduction_
+    (
+        coeffDict_.lookupOrDefault<bool>("limitAdjointProduction",true)
+    ),
+
+    y_(primalVars_.RASModelVariables()().d()),
+
+    mask_(allocateMask()),
+
+    symmAdjointProductionU_
+    (
+        IOobject
+        (
+            "symmAdjointProductionU",
+            runTime_.timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        mesh_,
+        dimensionedSymmTensor(dimless/dimTime, Zero)
+    ),
+
+    productionDestructionSource_
+    (
+        IOobject
+        (
+            "productionDestructionSource",
+            runTime_.timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        mesh_,
+        dimensionedScalar(dimless/dimTime, Zero)
+    ),
+
+    Stilda_
+    (
+        IOobject
+        (
+            "Stilda",
+            runTime_.timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        mesh_,
+        dimensionedScalar(dimless/dimTime, Zero)
+    ),
+
+    r_
+    (
+        IOobject
+        (
+            "r",
+            runTime_.timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        mesh_,
+        dimensionedScalar(dimless, Zero)
+    ),
+
+    fw_
+    (
+        IOobject
+        (
+            "fw",
+            runTime_.timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        mesh_,
+        dimensionedScalar(dimless, Zero)
+    ),
+
+    Cdnut_
+    (
+        IOobject
+        (
+            "Cdnut",
+            runTime_.timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        mesh_,
+        dimensionedScalar(dimless, Zero)
+    ),
+
+    momentumSourceMult_
+    (
+        IOobject
+        (
+            "momentumSourceMult",
+            runTime_.timeName(),
+            mesh_,
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        ),
+        mesh_,
+        dimensionedTensor(sqr(dimLength)/dimTime, Zero)
+    ),
+
+    gradU_(fvc::grad(primalVars.U())),
+    gradNuTilda_(fvc::grad(nuTilda())),
+    minStilda_("SMALL", Stilda_.dimensions(), SMALL)
+{
+    // Read nuaTilda field and reset pointer to the first
+    // adjoint turbulence model variable
+    variablesSet::setField
+    (
+        adjointTMVariable1Ptr_,
+        mesh_,
+        "nuaTilda",
+        adjointVars.solverName(),
+        adjointVars.useSolverNameForFields()
+    );
+
+    setMeanFields();
+
+    // Set the includeDistance to true, to allow for the automatic solution
+    // of the adjoint eikonal equation when computing sensitivities
+    includeDistance_ = true;
+
+    // Update the primal related fields here so that functions computing
+    // sensitivities have the updated fields in case of continuation
+    updatePrimalRelatedFields();
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+tmp<volSymmTensorField> adjointSpalartAllmaras::devReff() const
+{
+    const volVectorField& Ua = adjointVars_.UaInst();
+    return tmp<volSymmTensorField>::New
+        (
+            IOobject
+            (
+                "devRhoReff",
+                runTime_.timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+           -nuEff()*dev(twoSymm(fvc::grad(Ua)))
+        );
+}
+
+
+tmp<fvVectorMatrix> adjointSpalartAllmaras::divDevReff(volVectorField& Ua) const
+{
+    tmp<volScalarField> tnuEff(nuEff());
+    const volScalarField& nuEff = tnuEff();
+
+    return
+    (
+      - fvm::laplacian(nuEff, Ua)
+      - fvc::div(nuEff*dev(fvc::grad(Ua)().T()))
+    );
+}
+
+
+tmp<volVectorField> adjointSpalartAllmaras::adjointMeanFlowSource()
+{
+    // cm formulation
+    //return (- nuTilda()*fvc::grad(nuaTilda() - conservativeMomentumSource());
+
+    // ncm formulation
+    return (nuaTilda()*gradNuTilda_ - conservativeMomentumSource());
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::nutJacobianTMVar1() const
+{
+    volScalarField chi(this->chi());
+    volScalarField fv1(this->fv1(chi));
+    volScalarField dFv1_dChi(this->dFv1_dChi(chi));
+
+    return dnut_dNuTilda(fv1, dFv1_dChi);
+}
+
+
+tmp<scalarField> adjointSpalartAllmaras::diffusionCoeffVar1(label patchI) const
+{
+    tmp<scalarField> tdiffCoeff
+    (
+        new scalarField(mesh_.boundary()[patchI].size(), Zero)
+    );
+
+    scalarField& diffCoeff = tdiffCoeff.ref();
+
+    diffCoeff =
+        (nuTilda().boundaryField()[patchI] + nu()().boundaryField()[patchI])
+        /sigmaNut_.value();
+
+    return tdiffCoeff;
+}
+
+
+const boundaryVectorField&
+adjointSpalartAllmaras::adjointMomentumBCSource() const
+{
+    // Computed in conservativeMomentumSource
+    return adjMomentumBCSourcePtr_();
+}
+
+
+const boundaryVectorField& adjointSpalartAllmaras::wallShapeSensitivities()
+{
+    boundaryVectorField& wallShapeSens = wallShapeSensitivitiesPtr_();
+
+    forAll(mesh_.boundary(), patchI)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+
+        tmp<vectorField> tnf(patch.nf());
+        const vectorField& nf = tnf();
+        if (isA<wallFvPatch>(patch) && patch.size() != 0)
+        {
+            wallShapeSens[patchI] =
+              - nuaTilda().boundaryField()[patchI].snGrad()
+              * diffusionCoeffVar1(patchI)()
+              * nuTilda().boundaryField()[patchI].snGrad() * nf;
+        }
+    }
+
+    return wallShapeSens;
+}
+
+
+const boundaryVectorField& adjointSpalartAllmaras::wallFloCoSensitivities()
+{
+    boundaryVectorField& wallFloCoSens = wallFloCoSensitivitiesPtr_();
+
+    forAll(mesh_.boundary(), patchI)
+    {
+        tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
+        const vectorField& nf = tnf();
+
+        wallFloCoSens[patchI] =
+            nuaTilda().boundaryField()[patchI]
+          * nuTilda().boundaryField()[patchI] * nf;
+    }
+
+    return wallFloCoSens;
+}
+
+
+tmp<volScalarField> adjointSpalartAllmaras::distanceSensitivities()
+{
+    const volVectorField& U = primalVars_.U();
+    const volVectorField& Ua = adjointVars_.Ua();
+
+    // Primal SA fields
+    volScalarField chi(this->chi());
+    volScalarField fv1(this->fv1(chi));
+    volScalarField fv2(this->fv2(chi, fv1));
+    volScalarField Omega(::sqrt(2.0)*mag(gradU_));
+
+    // Derivatives of primal fields wrt to nuTilda
+    volScalarField dFv1_dChi(this->dFv1_dChi(chi));
+    volScalarField dFv2_dChi(this->dFv2_dChi(chi, fv1, dFv1_dChi));
+    volScalarField dStilda_dDelta(this->dStilda_dDelta(Omega, fv2));
+    volScalarField dfw_dr(this->dfw_dr(Stilda_));
+    volScalarField dfw_dDelta
+        (this->dfw_dDelta(Stilda_, dfw_dr, dStilda_dDelta));
+
+
+    tmp<volScalarField> tadjointEikonalSource
+    (
+        new volScalarField
+        (
+            "adjointEikonalSource" + type(),
+            (
+                - Cb1_*nuTilda()*dStilda_dDelta
+                + Cw1_*sqr(nuTilda()/y_)*(dfw_dDelta - 2.*fw_/y_)
+            )*nuaTilda()
+        )
+    );
+    volScalarField& adjointEikonalSource = tadjointEikonalSource.ref();
+
+    // if wall functions are used, add appropriate source terms
+    typedef nutUSpaldingWallFunctionFvPatchScalarField
+        SAwallFunctionPatchField;
+
+    const volScalarField::Boundary& nutBoundary = nut().boundaryField();
+    const scalarField& V = mesh_.V().field();
+
+    tmp<volScalarField> tnuEff = nuEff();
+    const volScalarField& nuEff = tnuEff();
+
+    forAll(nutBoundary, patchi)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchi];
+        if
+        (
+            isA<SAwallFunctionPatchField>(nutBoundary[patchi])
+         && patch.size() != 0
+        )
+        {
+            const scalar kappa_(0.41);
+            const scalar E_(9.8);
+            const tmp<vectorField> tnf(patch.nf());
+            const vectorField& nf = tnf();
+            const scalarField& magSf = patch.magSf();
+
+            const fvPatchVectorField& Up = U.boundaryField()[patchi];
+            const fvPatchVectorField& Uap = Ua.boundaryField()[patchi];
+            const vectorField Uc(Up.patchInternalField());
+            const vectorField Uc_t(Uc - (Uc & nf)*nf);
+
+            // By convention, tf has the direction of the tangent
+            // PRIMAL velocity at the first cell off the wall
+            const vectorField tf(Uc_t/mag(Uc_t));
+
+            const scalarField nuw(nuEff.boundaryField()[patchi]);
+            const scalarField nu(this->nu()().boundaryField()[patchi]);
+            const fvPatchScalarField& yC = y()[patchi];
+
+            const scalarField magGradU(mag(Up.snGrad()));
+
+            // Note: What happens in separation?? sign change needed
+            const scalarField vtau(sqrt(nuw*magGradU));
+
+            // Note: mag for positive uPlus
+            const scalarField uPlus(mag(Uc)/vtau);
+
+            const scalarField yPlus(yC*vtau/nu);
+            const scalarField kUu(min(kappa_*uPlus, scalar(50)));
+            const scalarField auxA
+                ((kappa_/E_)*(exp(kUu) - 1 - kUu - 0.5*kUu*kUu));
+            const scalarField Cwf_d(sqr(vtau)/nu/(yPlus+uPlus*(1 + auxA)));
+
+            // Tangential components are according to tf
+            autoPtr<boundaryAdjointContribution> boundaryContrPtr
+            (
+                boundaryAdjointContribution::New
+                (
+                    "objectiveManager" + objectiveManager_.adjointSolverName(),
+                    objectiveManager_.adjointSolverName(),
+                    "incompressible",
+                    patch
+                )
+            );
+            tmp<vectorField> tsource(boundaryContrPtr->normalVelocitySource());
+
+            const scalarField rt(tsource() & tf);
+            const scalarField Uap_t(Uap & tf);
+
+            const labelList& faceCells = patch.faceCells();
+            forAll(faceCells, faceI)
+            {
+                label cellI = faceCells[faceI];
+                adjointEikonalSource[cellI] -=
+                    2.*( rt[faceI] + Uap_t[faceI] )
+                  * vtau[faceI]*Cwf_d[faceI]*magSf[faceI]
+                  / V[cellI]; // Divide with cell volume since the term
+                              // will be used as a source term in the
+                              // adjoint eikonal equation
+            }
+        }
+    }
+
+    return tadjointEikonalSource;
+}
+
+
+tmp<volTensorField> adjointSpalartAllmaras::FISensitivityTerm()
+{
+    const volVectorField& U  = primalVars_.U();
+
+    volTensorField gradU(fvc::grad(U));
+    volVectorField gradNuTilda(fvc::grad(nuTilda()));
+    volVectorField gradNuaTilda(fvc::grad(nuaTilda()));
+
+    // Explicitly correct the boundary gradient to get rid of
+    // the tangential component
+    forAll(mesh_.boundary(), patchI)
+    {
+        const fvPatch& patch = mesh_.boundary()[patchI];
+        if (isA<wallFvPatch>(patch))
+        {
+            tmp<vectorField> tnf(patch.nf());
+            const vectorField& nf = tnf();
+            // gradU:: can cause problems in zeroGradient patches for U
+            // and zero fixedValue for nuTilda.
+            // S becomes 0 and is used as a denominator in G
+            //gradU.boundaryField()[patchI] =
+            //  nf * U_.boundaryField()[patchI].snGrad();
+            gradNuTilda.boundaryFieldRef()[patchI]  =
+                nf * nuTilda().boundaryField()[patchI].snGrad();
+            gradNuaTilda.boundaryFieldRef()[patchI] =
+                nf * nuaTilda().boundaryField()[patchI].snGrad();
+        }
+    }
+
+    // delta vorticity
+    volScalarField Omega(::sqrt(2.0)*mag(skew(gradU)));
+    volTensorField deltaOmega
+    (
+        (
+           (gradU & gradU)().T() //jk
+         - (gradU & gradU.T())   //symmetric
+        )
+       /(Omega + dimensionedScalar("SMALL", Omega.dimensions(), SMALL))
+    );
+
+    volScalarField chi(this->chi());
+    volScalarField fv1(this->fv1(chi));
+    volScalarField fv2(this->fv2(chi, fv1));
+
+    volScalarField dfw_dr(this->dfw_dr(Stilda_));
+    volScalarField dStilda_dOmega(this->dStilda_dOmega(Omega, fv2));
+    volScalarField dfw_dOmega
+        (this->dfw_dOmega(Stilda_, dfw_dr, dStilda_dOmega));
+
+    // Assemply of the return field
+    tmp<volTensorField> tvolSensTerm
+    (
+        new volTensorField
+        (
+            "volSensTerm",
+            // jk, cm formulation for the TM model convection
+            - (nuaTilda() * (U * gradNuTilda))
+            // jk, symmetric in theory
+            + nuaTilda()*fvc::grad(DnuTildaEff() * gradNuTilda)().T()
+            // jk
+            - DnuTildaEff() * (gradNuaTilda * gradNuTilda)
+            // symmetric
+            + 2.*nuaTilda()*Cb2_/sigmaNut_ * (gradNuTilda * gradNuTilda)
+            + (
+                - Cb1_*nuTilda()*dStilda_dOmega
+                + Cw1_*sqr(nuTilda()/y_)*dfw_dOmega
+              )
+            * nuaTilda() * deltaOmega // jk
+         )
+    );
+
+    return tvolSensTerm;
+}
+
+
+void adjointSpalartAllmaras::correct()
+{
+    if (!adjointTurbulence_)
+    {
+        return;
+    }
+
+    adjointTurbulenceModel::correct();
+
+    updatePrimalRelatedFields();
+
+    const surfaceScalarField& phi = primalVars_.phi();
+    const volVectorField& Ua = adjointVars_.UaInst();
+
+    volScalarField gradNua(gradNuTilda_ & fvc::grad(nuaTilda()));
+    volScalarField gradUaR
+    (
+        2.0*fvc::grad(Ua,"adjointProductionUa") && symmAdjointProductionU_
+    );
+
+    dimensionedScalar oneOverSigmaNut = 1./sigmaNut_;
+
+    nuaTilda().storePrevIter();
+
+    tmp<fvScalarMatrix> nuaTildaEqn
+    (
+        fvm::ddt(nuaTilda())
+      + fvm::div(-phi, nuaTilda())
+      - fvm::laplacian(DnuTildaEff(), nuaTilda())
+        // Note: Susp
+      + fvm::SuSp(productionDestructionSource_, nuaTilda())
+      + fvc::laplacian(2.0*Cb2_*oneOverSigmaNut*nuaTilda(), nuTilda())
+      + gradNua*oneOverSigmaNut
+     ==
+        // always a negative contribution to the lhs. No Sp used!
+        Cb1_*Stilda_*nuaTilda()
+        //always a positive contribution to the lhs. no need for SuSp
+      - fvm::Sp(Cw1_*fw_*nuTilda()/sqr(y_), nuaTilda())
+      - Cdnut_*gradUaR
+    );
+
+    // Add sources from the objective functions
+    objectiveManager_.addTMEqn1Source(nuaTildaEqn.ref());
+
+    nuaTildaEqn.ref().relax();
+    solve(nuaTildaEqn);
+    nuaTilda().correctBoundaryConditions();
+    nuaTilda().relax();
+
+    if (adjointVars_.getSolverControl().printMaxMags())
+    {
+        scalar maxDeltaNuaTilda =
+            gMax(mag(nuaTilda() - nuaTilda().prevIter())());
+        dimensionedScalar maxNuaTilda = max(mag(nuaTilda()));
+        Info<< "Max mag of nuaTilda = " << maxNuaTilda.value() << endl;
+        Info<< "Max mag of delta nuaTilda = " << maxDeltaNuaTilda << endl;
+    }
+}
+
+
+bool adjointSpalartAllmaras::read()
+{
+    if (adjointRASModel::read())
+    {
+        sigmaNut_.readIfPresent(this->coeffDict());
+        kappa_.readIfPresent(this->coeffDict());
+
+        Cb1_.readIfPresent(this->coeffDict());
+        Cb2_.readIfPresent(this->coeffDict());
+        Cw1_ = Cb1_/sqr(kappa_) + (1.0 + Cb2_)/sigmaNut_;
+        Cw2_.readIfPresent(this->coeffDict());
+        Cw3_.readIfPresent(this->coeffDict());
+        Cv1_.readIfPresent(this->coeffDict());
+        Cs_.readIfPresent(this->coeffDict());
+
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace adjointRASModels
+} // End namespace incompressibleAdjoint
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.H
new file mode 100644
index 0000000000000000000000000000000000000000..919cbeb378fcfaf244e34f1fc4b8f8f0e024e3a2
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.H
@@ -0,0 +1,356 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressibleAdjoint::adjointRASModels::adjointSpalartAllmaras
+
+Description
+    Continuous adjoint to the Spalart-Allmaras one-eqn mixing-length model for
+    incompressible flows.
+
+    Reference:
+    \verbatim
+        For the adjoint to the Spalart-Allmaras PDE
+
+            Zymaris, A., Papadimitriou, D., Giannakoglou, K., &
+            Othmer, C. (2009).
+            Continuous adjoint approach to the Spalart-Allmaras turbulence
+            model for incompressible flows.
+            Computers & Fluids, 38(8), 1528-538.
+            http://doi.org/10.1016/j.compfluid.2008.12.006
+
+        For the FI sensitivity terms
+
+            Papoutsis-Kiachagias, E. M., Asouti, V. G., Giannakoglou, K. C.,
+            Gkagkas, K., Shimokawa, S., & Itakura, E. (2018).
+            Multi-point aerodynamic shape optimization of cars based on
+            continuous adjoint.
+            Structural and Multidisciplinary Optimization, 59(2), 675-694.
+            http://doi.org/10.1007/s00158-018-2091-3
+
+    \endverbatim
+
+    Both of the above-mentioned papers develop the adjoint to the
+    Spalart-Allmaras PDE that includes the fv3 term.  The current
+    implementation corresponds to the Spalart-Allmaras PDE as programmed within
+    OpenFOAM and is, thus, slightly different than the one developed in the
+    cited papers
+
+SourceFiles
+    adjointSpalartAllmaras.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointSpalartAllmaras_H
+#define adjointSpalartAllmaras_H
+
+#include "adjointRASModel.H"
+#include "wallDist.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressibleAdjoint
+{
+namespace adjointRASModels
+{
+
+/*---------------------------------------------------------------------------*\
+                    Class adjointSpalartAllmaras Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointSpalartAllmaras
+:
+    public adjointRASModel
+{
+    // Private Member Functions
+
+        //- No copy construct
+        adjointSpalartAllmaras(const adjointSpalartAllmaras&) = delete;
+
+        //- No copy assignment
+        void operator=(const adjointSpalartAllmaras&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        // Model coefficients
+
+            dimensionedScalar sigmaNut_;
+            dimensionedScalar kappa_;
+
+            dimensionedScalar Cb1_;
+            dimensionedScalar Cb2_;
+            dimensionedScalar Cw1_;
+            dimensionedScalar Cw2_;
+            dimensionedScalar Cw3_;
+            dimensionedScalar Cv1_;
+            dimensionedScalar Cs_;
+
+            //- Whether to limit the adjoint production term to enhance
+            //- stability
+            bool limitAdjointProduction_;
+
+
+        // Fields
+
+            //- Wall distance
+            //  Note: reference to the distance known by the primal model
+            const volScalarField& y_;
+
+            //- Field for masking (convergence enhancement)
+            volScalarField mask_;
+
+            // Fields that depend only on primal fields and are very expensive
+            // to compute in each iteration.
+            // Store and update them when the primal solution has been updated
+            volSymmTensorField symmAdjointProductionU_;
+            volScalarField productionDestructionSource_;
+            volScalarField Stilda_;
+            volScalarField r_;
+            volScalarField fw_;
+            volScalarField Cdnut_;
+            volTensorField momentumSourceMult_;
+            volTensorField gradU_;
+            volVectorField gradNuTilda_;
+
+            // Useful quantities for bounding
+            dimensionedScalar minStilda_;
+
+
+    // Protected Member Functions
+
+        // Primal Spalart - Allmaras
+
+            tmp<volScalarField> chi() const;
+
+            tmp<volScalarField> fv1(const volScalarField& chi) const;
+
+            tmp<volScalarField> fv2
+            (
+                const volScalarField& chi,
+                const volScalarField& fv1
+            ) const;
+
+            tmp<volScalarField> Stilda
+            (
+                const volScalarField& chi,
+                const volScalarField& fv1
+            ) const;
+
+            tmp<volScalarField> r(const volScalarField& Stilda) const;
+
+            tmp<volScalarField> fw(const volScalarField& Stilda) const;
+
+            tmp<volScalarField> DnuTildaEff() const;
+
+            //- References to the primal turbulence model variables
+            const volScalarField& nuTilda() const;
+
+            const volScalarField& nut() const;
+
+
+        // Adjoint Spalart - Allmaras
+
+            // Differentiation of the primal Spalart - Allmaras terms
+
+                tmp<volScalarField> dFv1_dChi
+                (
+                    const volScalarField& chi
+                ) const;
+
+                tmp<volScalarField> dFv2_dChi
+                (
+                    const volScalarField& chi,
+                    const volScalarField& fv1,
+                    const volScalarField& dFv1dChi
+                ) const;
+
+                tmp<volScalarField> dStilda_dOmega
+                (
+                    const volScalarField& Omega,
+                    const volScalarField& fv2
+                ) const;
+
+                tmp<volScalarField> dStilda_dNuTilda
+                (
+                    const volScalarField& Omega,
+                    const volScalarField& fv2,
+                    const volScalarField& dFv2dChi
+                ) const;
+
+                tmp<volScalarField> dStilda_dDelta
+                (
+                    const volScalarField& Omega,
+                    const volScalarField& fv2
+                ) const;
+
+                tmp<volScalarField> dr_dNuTilda
+                (
+                    const volScalarField& Stilda
+                ) const;
+
+                tmp<volScalarField> dr_dStilda
+                (
+                    const volScalarField& Stilda
+                ) const;
+
+                tmp<volScalarField> dr_dDelta
+                (
+                    const volScalarField& Stilda
+                ) const;
+
+                tmp<volScalarField> dfw_dr
+                (
+                    const volScalarField& Stilda
+                ) const;
+
+                tmp<volScalarField> dfw_dNuTilda
+                (
+                    const volScalarField& Stilda,
+                    const volScalarField& dfwdr,
+                    const volScalarField& dStildadNuTilda
+                ) const;
+
+                tmp<volScalarField> dfw_dOmega
+                (
+                    const volScalarField& Stilda,
+                    const volScalarField& dfwdr,
+                    const volScalarField& dStildadOmega
+                ) const;
+
+                tmp<volScalarField> dfw_dDelta
+                (
+                    const volScalarField& Stilda,
+                    const volScalarField& dfwdr,
+                    const volScalarField& dStildadDelta
+                ) const;
+
+                tmp<volScalarField> dD_dNuTilda
+                (
+                    const volScalarField& fw,
+                    const volScalarField& dfwdNuTilda
+                ) const;
+
+                tmp<volScalarField> dP_dNuTilda
+                (
+                    const volScalarField& dStildadNuTilda
+                ) const;
+
+                tmp<volScalarField> dnut_dNuTilda
+                (
+                    const volScalarField& fv1,
+                    const volScalarField& dFv1dChi
+                ) const;
+
+
+            //- Conservative source term for the adjoint momentum equations
+            //  Sets also the adjointMomentumBCSource
+            tmp<volVectorField> conservativeMomentumSource();
+
+            //- Access to the adjoint Spalart - Allmaras field
+            inline volScalarField& nuaTilda()
+            {
+                return adjointTMVariable1Ptr_();
+            };
+
+            //- Update the constant primal-related fields
+            void updatePrimalRelatedFields();
+
+            //- Allocate the mask field
+            tmp<volScalarField> allocateMask();
+
+
+public:
+
+    //- Runtime type information
+    TypeName("adjointSpalartAllmaras");
+
+
+    // Constructors
+
+        //- Construct from components
+        adjointSpalartAllmaras
+        (
+            incompressibleVars& primalVars,
+            incompressibleAdjointMeanFlowVars& adjointVars,
+            objectiveManager& objManager,
+            const word& adjointTurbulenceModelName
+                = adjointTurbulenceModel::typeName,
+            const word& modelName = typeName
+        );
+
+
+    //- Destructor
+    virtual ~adjointSpalartAllmaras() = default;
+
+
+    // Member Functions
+
+        virtual tmp<volSymmTensorField> devReff() const;
+
+        virtual tmp<fvVectorMatrix> divDevReff(volVectorField& U) const;
+
+        virtual tmp<volVectorField> adjointMeanFlowSource();
+
+        virtual tmp<volScalarField> nutJacobianTMVar1() const;
+
+        virtual tmp<scalarField> diffusionCoeffVar1(label patchI) const;
+
+        virtual const boundaryVectorField& adjointMomentumBCSource() const;
+
+        virtual const boundaryVectorField& wallShapeSensitivities();
+
+        virtual const boundaryVectorField& wallFloCoSensitivities();
+
+        virtual tmp<volScalarField> distanceSensitivities();
+
+        virtual tmp<volTensorField> FISensitivityTerm();
+
+        //- Solve the adjoint turbulence equations
+        virtual void correct();
+
+        //- Read adjointRASProperties dictionary
+        virtual bool read();
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace adjointRASModels
+} // End namespace incompressibleAdjoint
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointFarFieldNuaTilda/adjointFarFieldNuaTildaFvPatchScalarField.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointFarFieldNuaTilda/adjointFarFieldNuaTildaFvPatchScalarField.C
new file mode 100644
index 0000000000000000000000000000000000000000..3ab49c26bd9fcc9c7e5a9121de7ffc7e976d4342
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointFarFieldNuaTilda/adjointFarFieldNuaTildaFvPatchScalarField.C
@@ -0,0 +1,179 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointFarFieldNuaTildaFvPatchScalarField.H"
+#include "addToRunTimeSelectionTable.H"
+#include "fvPatchFieldMapper.H"
+#include "volFields.H"
+#include "surfaceFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointFarFieldNuaTildaFvPatchScalarField::
+adjointFarFieldNuaTildaFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(p, iF),
+    adjointBoundaryCondition(p, iF, word::null)
+{}
+
+
+adjointFarFieldNuaTildaFvPatchScalarField::
+adjointFarFieldNuaTildaFvPatchScalarField
+(
+    const adjointFarFieldNuaTildaFvPatchScalarField& ptf,
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchScalarField(ptf, p, iF, mapper),
+    adjointBoundaryCondition(p, iF, ptf.adjointSolverName_)
+{}
+
+
+adjointFarFieldNuaTildaFvPatchScalarField::
+adjointFarFieldNuaTildaFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchScalarField(p, iF),
+    adjointBoundaryCondition(p, iF, dict.get<word>("solverName"))
+{
+    fvPatchField<scalar>::operator=
+    (
+        scalarField("value", dict, p.size())
+    );
+}
+
+
+adjointFarFieldNuaTildaFvPatchScalarField::
+adjointFarFieldNuaTildaFvPatchScalarField
+(
+    const adjointFarFieldNuaTildaFvPatchScalarField& tppsf,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(tppsf, iF),
+    adjointBoundaryCondition(tppsf)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void adjointFarFieldNuaTildaFvPatchScalarField::updateCoeffs()
+{
+    if (updated())
+    {
+        return;
+    }
+    vectorField nf(patch().nf());
+
+    const fvPatchField<vector>& Ub = boundaryContrPtr_->Ub();
+    tmp<scalarField> tnuEff(boundaryContrPtr_->TMVariable1Diffusion());
+    const scalarField& nuEff = tnuEff();
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+
+    // Patch-adjacent nuaTilda nuaTildaNei
+    tmp<scalarField> tnuaTildaNei(patchInternalField());
+    const scalarField& nuaTildaNei = tnuaTildaNei();
+
+    // Patch deltas
+    const scalarField& delta = patch().deltaCoeffs();
+
+    operator==
+    (
+        pos(phip)
+       *(
+            (nuEff*delta*nuaTildaNei)
+           /((Ub & nf) + nuEff*delta)
+        )
+    );
+
+    fixedValueFvPatchScalarField::updateCoeffs();
+}
+
+
+tmp<Field<scalar>> adjointFarFieldNuaTildaFvPatchScalarField::
+valueInternalCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+
+    // For fixedValue nuTilda patches
+    return tmp<Field<scalar>>::New(neg(phip)*pTraits<scalar>::one);
+}
+
+
+tmp<Field<scalar>> adjointFarFieldNuaTildaFvPatchScalarField::
+valueBoundaryCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    const fvsPatchField<scalar>& phip = boundaryContrPtr_->phib();
+
+    // For zeroGradient nuTilda patches
+    return tmp<Field<scalar>>::New(pos(phip)*(*this));
+}
+
+
+void adjointFarFieldNuaTildaFvPatchScalarField::write(Ostream& os) const
+{
+    fvPatchScalarField::write(os);
+    writeEntry("value", os);
+    os.writeEntry("solverName", adjointSolverName_);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+makePatchTypeField
+(
+    fvPatchScalarField,
+    adjointFarFieldNuaTildaFvPatchScalarField
+);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointFarFieldNuaTilda/adjointFarFieldNuaTildaFvPatchScalarField.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointFarFieldNuaTilda/adjointFarFieldNuaTildaFvPatchScalarField.H
new file mode 100644
index 0000000000000000000000000000000000000000..71dbb054648f1ab5a84ac805d93d47c5845eee39
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointFarFieldNuaTilda/adjointFarFieldNuaTildaFvPatchScalarField.H
@@ -0,0 +1,154 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointFarFieldNuaTildaFvPatchScalarField
+
+Description
+
+SourceFiles
+    adjointFarFieldNuaTildaFvPatchScalarField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointFarFieldNuaTildaFvPatchScalarField_H
+#define adjointFarFieldNuaTildaFvPatchScalarField_H
+
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                Class adjointFarFieldNuaTildaFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointFarFieldNuaTildaFvPatchScalarField
+:
+    public fixedValueFvPatchScalarField,
+    public adjointBoundaryCondition
+{
+public:
+
+    //- Runtime type information
+    TypeName("adjointFarFieldNuaTilda");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointFarFieldNuaTildaFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointFarFieldNuaTildaFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given adjointFarFieldNuaTildaFvPatchScalarField
+        //- onto a new patch
+        adjointFarFieldNuaTildaFvPatchScalarField
+        (
+            const adjointFarFieldNuaTildaFvPatchScalarField&,
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchScalarField> clone() const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointFarFieldNuaTildaFvPatchScalarField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointFarFieldNuaTildaFvPatchScalarField
+        (
+            const adjointFarFieldNuaTildaFvPatchScalarField&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchScalarField> clone
+        (
+            const DimensionedField<scalar, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointFarFieldNuaTildaFvPatchScalarField(*this, iF)
+            );
+        }
+
+
+    // Member functions
+
+        // Evaluation functions
+
+            //- Update the coefficients associated with the patch field
+            virtual void updateCoeffs();
+
+            //- Return the matrix diagonal coefficients corresponding to the
+            //- evaluation of the value of this patchField with given weights
+            virtual tmp<Field<scalar>> valueInternalCoeffs
+            (
+                const tmp<scalarField>&
+            ) const;
+
+            //- Return the matrix source coefficients corresponding to the
+            //- evaluation of the value of this patchField with given weights
+            virtual tmp<Field<scalar>> valueBoundaryCoeffs
+            (
+                const tmp<scalarField>&
+            ) const;
+
+        //- Write
+        virtual void write(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointInletNuaTilda/adjointInletNuaTildaFvPatchScalarField.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointInletNuaTilda/adjointInletNuaTildaFvPatchScalarField.C
new file mode 100644
index 0000000000000000000000000000000000000000..cbb41a18b0dbbd1a60e697c9c263590d19c3ddb8
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointInletNuaTilda/adjointInletNuaTildaFvPatchScalarField.C
@@ -0,0 +1,135 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointInletNuaTildaFvPatchScalarField.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointInletNuaTildaFvPatchScalarField::adjointInletNuaTildaFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(p, iF),
+    adjointBoundaryCondition(p, iF, word::null)
+{}
+
+
+adjointInletNuaTildaFvPatchScalarField::adjointInletNuaTildaFvPatchScalarField
+(
+    const adjointInletNuaTildaFvPatchScalarField& ptf,
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchScalarField(ptf, p, iF, mapper),
+    adjointBoundaryCondition(p, iF, ptf.adjointSolverName_)
+{}
+
+
+adjointInletNuaTildaFvPatchScalarField::adjointInletNuaTildaFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchScalarField(p, iF, dict),
+    adjointBoundaryCondition(p, iF, dict.get<word>("solverName"))
+{}
+
+
+adjointInletNuaTildaFvPatchScalarField::adjointInletNuaTildaFvPatchScalarField
+(
+    const adjointInletNuaTildaFvPatchScalarField& ptf,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(ptf, iF),
+    adjointBoundaryCondition(ptf)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void adjointInletNuaTildaFvPatchScalarField::updateCoeffs()
+{
+    if (updated())
+    {
+        return;
+    }
+
+    operator==(Zero);
+
+    fixedValueFvPatchScalarField::updateCoeffs();
+}
+
+
+tmp<Field<scalar>> adjointInletNuaTildaFvPatchScalarField::valueInternalCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    return tmp<Field<scalar>>::New(this->size(), pTraits<scalar>::one);
+}
+
+
+tmp<Field<scalar>> adjointInletNuaTildaFvPatchScalarField::valueBoundaryCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    return tmp<Field<scalar>>::New(this->size(), pTraits<scalar>::zero);
+}
+
+
+void adjointInletNuaTildaFvPatchScalarField::write(Ostream& os) const
+{
+    fvPatchScalarField::write(os);
+    writeEntry("value", os);
+    os.writeEntry("solverName", adjointSolverName_);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+makePatchTypeField(fvPatchScalarField, adjointInletNuaTildaFvPatchScalarField);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointInletNuaTilda/adjointInletNuaTildaFvPatchScalarField.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointInletNuaTilda/adjointInletNuaTildaFvPatchScalarField.H
new file mode 100644
index 0000000000000000000000000000000000000000..08f705f74b6f702f7dceca2b9a0c86f56b7bd0ec
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointInletNuaTilda/adjointInletNuaTildaFvPatchScalarField.H
@@ -0,0 +1,156 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointInletNuaTildaFvPatchScalarField
+
+Description
+    Inlet boundary for adjoint nuaTilda.
+
+SourceFiles
+    adjointInletNuaTildaFvPatchScalarField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointInletNuaTildaFvPatchScalarField_H
+#define adjointInletNuaTildaFvPatchScalarField_H
+
+#include "fvPatchFields.H"
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                 Class adjointInletNuaTildaFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointInletNuaTildaFvPatchScalarField
+:
+    public fixedValueFvPatchScalarField,
+    public adjointBoundaryCondition
+{
+
+public:
+
+    //- Runtime type information
+    TypeName("adjointInletNuaTilda");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointInletNuaTildaFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointInletNuaTildaFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given adjointInletNuaTildaFvPatchScalarField
+        //  onto a new patch
+        adjointInletNuaTildaFvPatchScalarField
+        (
+            const adjointInletNuaTildaFvPatchScalarField&,
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchScalarField> clone() const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointInletNuaTildaFvPatchScalarField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointInletNuaTildaFvPatchScalarField
+        (
+            const adjointInletNuaTildaFvPatchScalarField&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchScalarField> clone
+        (
+            const DimensionedField<scalar, volMesh>& iF
+        ) const
+        {
+            Info<< "manager name " << managerName_ << endl;
+            return tmp<fvPatchScalarField>
+            (
+                new adjointInletNuaTildaFvPatchScalarField(*this, iF)
+            );
+        }
+
+
+    // Member functions
+
+        //- Update the coefficients associated with the patch field
+        virtual void updateCoeffs();
+
+        //- Return the matrix diagonal coefficients corresponding to the
+        //- evaluation of the value of this patchField with given weights
+        virtual tmp<Field<scalar>> valueInternalCoeffs
+        (
+            const tmp<scalarField>&
+        ) const;
+
+        //- Return the matrix source coefficients corresponding to the
+        //- evaluation of the value of this patchField with given weights
+        virtual tmp<Field<scalar>> valueBoundaryCoeffs
+        (
+            const tmp<scalarField>&
+        ) const;
+
+        //- Write
+        virtual void write(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletFlux/adjointOutletFluxFvPatchScalarField.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletFlux/adjointOutletFluxFvPatchScalarField.C
new file mode 100644
index 0000000000000000000000000000000000000000..8d61edcd2203983d501467e50c5941f7b7dc22db
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletFlux/adjointOutletFluxFvPatchScalarField.C
@@ -0,0 +1,150 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointOutletFluxFvPatchScalarField.H"
+#include "addToRunTimeSelectionTable.H"
+#include "fvPatchFieldMapper.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointOutletFluxFvPatchScalarField::adjointOutletFluxFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(p, iF)
+{}
+
+
+adjointOutletFluxFvPatchScalarField::adjointOutletFluxFvPatchScalarField
+(
+    const adjointOutletFluxFvPatchScalarField& ptf,
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchScalarField(ptf, p, iF, mapper)
+{}
+
+
+adjointOutletFluxFvPatchScalarField::adjointOutletFluxFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchScalarField(p, iF)
+{
+    fvPatchField<scalar>::operator=
+    (
+        scalarField("value", dict, p.size())
+    );
+}
+
+
+adjointOutletFluxFvPatchScalarField::adjointOutletFluxFvPatchScalarField
+(
+    const adjointOutletFluxFvPatchScalarField& tppsf,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(tppsf, iF)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void adjointOutletFluxFvPatchScalarField::updateCoeffs()
+{
+    if (updated())
+    {
+        return;
+    }
+
+    operator==(scalarField(patch().size(), Zero));
+
+    fixedValueFvPatchScalarField::updateCoeffs();
+}
+
+
+tmp<Field<scalar>> adjointOutletFluxFvPatchScalarField::valueInternalCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    return tmp<Field<scalar>>::New(this->size(), pTraits<scalar>::zero);
+}
+
+
+tmp<Field<scalar>> adjointOutletFluxFvPatchScalarField::valueBoundaryCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    return tmp<Field<scalar>>::New(this->size(), pTraits<scalar>::zero);
+}
+
+
+tmp<Field<scalar>>
+adjointOutletFluxFvPatchScalarField::gradientBoundaryCoeffs() const
+{
+    return tmp<Field<scalar>>::New(this->size(), pTraits<scalar>::zero);
+}
+
+
+tmp<Field<scalar>>
+adjointOutletFluxFvPatchScalarField::gradientInternalCoeffs() const
+{
+    return tmp<Field<scalar>>::New(this->size(), pTraits<scalar>::zero);
+}
+
+
+void adjointOutletFluxFvPatchScalarField::write(Ostream& os) const
+{
+    fvPatchScalarField::write(os);
+    writeEntry("value", os);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+makePatchTypeField(fvPatchScalarField, adjointOutletFluxFvPatchScalarField);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletFlux/adjointOutletFluxFvPatchScalarField.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletFlux/adjointOutletFluxFvPatchScalarField.H
new file mode 100644
index 0000000000000000000000000000000000000000..32a7280027d2c943fc28a131719d510fa0a87714
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletFlux/adjointOutletFluxFvPatchScalarField.H
@@ -0,0 +1,162 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointOutletFluxFvPatchScalarField
+
+Description
+
+SourceFiles
+    adjointOutletFluxFvPatchScalarField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointOutletFluxFvPatchScalarField_H
+#define adjointOutletFluxFvPatchScalarField_H
+
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                   Class adjointOutletFluxFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointOutletFluxFvPatchScalarField
+:
+    public fixedValueFvPatchScalarField
+{
+public:
+
+    //- Runtime type information
+    TypeName("adjointOutletFlux");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointOutletFluxFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointOutletFluxFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given adjointOutletFluxFvPatchScalarField
+        //- onto a new patch
+        adjointOutletFluxFvPatchScalarField
+        (
+            const adjointOutletFluxFvPatchScalarField&,
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchScalarField> clone() const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointOutletFluxFvPatchScalarField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointOutletFluxFvPatchScalarField
+        (
+            const adjointOutletFluxFvPatchScalarField&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchScalarField> clone
+        (
+            const DimensionedField<scalar, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointOutletFluxFvPatchScalarField(*this, iF)
+            );
+        }
+
+
+    // Member functions
+
+        // Evaluation functions
+
+            //- Update the coefficients associated with the patch field
+            virtual void updateCoeffs();
+
+            //- Return the matrix diagonal coefficients corresponding to the
+            //- evaluation of the value of this patchField with given weights
+            virtual tmp<Field<scalar>> valueInternalCoeffs
+            (
+                const tmp<scalarField>&
+            ) const;
+
+            //- Return the matrix source coefficients corresponding to the
+            //- evaluation of the value of this patchField with given weights
+            virtual tmp<Field<scalar>> valueBoundaryCoeffs
+            (
+                const tmp<scalarField>&
+
+            ) const;
+
+            //- Return the matrix source coefficients corresponding to the
+            //- evaluation of the gradient of this patchField
+            virtual tmp<Field<scalar>> gradientBoundaryCoeffs() const;
+
+            //- Return the matrix diagonal coefficients corresponding to the
+            //- evaluation of the gradient of this patchField
+            virtual tmp<Field<scalar>> gradientInternalCoeffs() const;
+
+        //- Write
+        virtual void write(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTilda/adjointOutletNuaTildaFvPatchScalarField.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTilda/adjointOutletNuaTildaFvPatchScalarField.C
new file mode 100644
index 0000000000000000000000000000000000000000..6147bd91a8d06037226c667dbe61a0b5436f0232
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTilda/adjointOutletNuaTildaFvPatchScalarField.C
@@ -0,0 +1,139 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointOutletNuaTildaFvPatchScalarField.H"
+#include "addToRunTimeSelectionTable.H"
+#include "fvPatchFieldMapper.H"
+#include "volFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointOutletNuaTildaFvPatchScalarField::adjointOutletNuaTildaFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(p, iF),
+    adjointBoundaryCondition(p, iF, word::null)
+{}
+
+
+adjointOutletNuaTildaFvPatchScalarField::adjointOutletNuaTildaFvPatchScalarField
+(
+    const adjointOutletNuaTildaFvPatchScalarField& ptf,
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchScalarField(ptf, p, iF, mapper),
+    adjointBoundaryCondition(p, iF, ptf.adjointSolverName_)
+{}
+
+
+adjointOutletNuaTildaFvPatchScalarField::adjointOutletNuaTildaFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchScalarField(p, iF),
+    adjointBoundaryCondition(p, iF, dict.get<word>("solverName"))
+{
+    fvPatchField<scalar>::operator=
+    (
+        scalarField("value", dict, p.size())
+    );
+}
+
+
+adjointOutletNuaTildaFvPatchScalarField::adjointOutletNuaTildaFvPatchScalarField
+(
+    const adjointOutletNuaTildaFvPatchScalarField& tppsf,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(tppsf, iF),
+    adjointBoundaryCondition(tppsf)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void adjointOutletNuaTildaFvPatchScalarField::updateCoeffs()
+{
+    if (updated())
+    {
+        return;
+    }
+    vectorField nf(patch().nf());
+
+    const fvPatchField<vector>& Ub = boundaryContrPtr_->Ub();
+    tmp<scalarField> tnuEff(boundaryContrPtr_->TMVariable1Diffusion());
+    const scalarField& nuEff = tnuEff();
+
+    // Patch-adjacent nuaTilda nuaTildaNei
+    tmp<scalarField> tnuaTildaNei(patchInternalField());
+    const scalarField& nuaTildaNei = tnuaTildaNei();
+
+    const scalarField& delta = patch().deltaCoeffs();
+
+    operator==
+    (
+        (nuEff*delta*nuaTildaNei)
+       /((Ub & nf) + nuEff*delta)
+    );
+
+    fixedValueFvPatchScalarField::updateCoeffs();
+}
+
+
+void adjointOutletNuaTildaFvPatchScalarField::write(Ostream& os) const
+{
+    fvPatchScalarField::write(os);
+    writeEntry("value", os);
+    os.writeEntry("solverName", adjointSolverName_);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+makePatchTypeField(fvPatchScalarField, adjointOutletNuaTildaFvPatchScalarField);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTilda/adjointOutletNuaTildaFvPatchScalarField.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTilda/adjointOutletNuaTildaFvPatchScalarField.H
new file mode 100644
index 0000000000000000000000000000000000000000..04b775e7f40532d4d943db669310efc87b454bce
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTilda/adjointOutletNuaTildaFvPatchScalarField.H
@@ -0,0 +1,138 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointOutletNuaTildaFvPatchScalarField
+
+Description
+
+SourceFiles
+    adjointOutletNuaTildaFvPatchScalarField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointOutletNuaTildaFvPatchScalarField_H
+#define adjointOutletNuaTildaFvPatchScalarField_H
+
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                 Class adjointOutletNuaTildaFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointOutletNuaTildaFvPatchScalarField
+:
+    public fixedValueFvPatchScalarField,
+    public adjointBoundaryCondition
+{
+public:
+
+    //- Runtime type information
+    TypeName("adjointOutletNuaTilda");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointOutletNuaTildaFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointOutletNuaTildaFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given adjointOutletNuaTildaFvPatchScalarField
+        //- onto a new patch
+        adjointOutletNuaTildaFvPatchScalarField
+        (
+            const adjointOutletNuaTildaFvPatchScalarField&,
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchScalarField> clone() const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointOutletNuaTildaFvPatchScalarField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointOutletNuaTildaFvPatchScalarField
+        (
+            const adjointOutletNuaTildaFvPatchScalarField&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchScalarField> clone
+        (
+            const DimensionedField<scalar, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointOutletNuaTildaFvPatchScalarField(*this, iF)
+            );
+        }
+
+
+    // Member functions
+
+        //- Update the coefficients associated with the patch field
+        virtual void updateCoeffs();
+
+        //- Write
+        virtual void write(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTildaFlux/adjointOutletNuaTildaFluxFvPatchScalarField.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTildaFlux/adjointOutletNuaTildaFluxFvPatchScalarField.C
new file mode 100644
index 0000000000000000000000000000000000000000..17a6d0868251da18aa69a299b5ece97c41091bf2
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTildaFlux/adjointOutletNuaTildaFluxFvPatchScalarField.C
@@ -0,0 +1,166 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointOutletNuaTildaFluxFvPatchScalarField.H"
+#include "addToRunTimeSelectionTable.H"
+#include "fvPatchFieldMapper.H"
+#include "volFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointOutletNuaTildaFluxFvPatchScalarField::
+adjointOutletNuaTildaFluxFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(p, iF),
+    adjointBoundaryCondition(p, iF, word::null)
+{}
+
+
+adjointOutletNuaTildaFluxFvPatchScalarField::
+adjointOutletNuaTildaFluxFvPatchScalarField
+(
+    const adjointOutletNuaTildaFluxFvPatchScalarField& ptf,
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const fvPatchFieldMapper& mapper
+)
+:
+    fixedValueFvPatchScalarField(ptf, p, iF, mapper),
+    adjointBoundaryCondition(p, iF, ptf.adjointSolverName_)
+{}
+
+
+adjointOutletNuaTildaFluxFvPatchScalarField::
+adjointOutletNuaTildaFluxFvPatchScalarField
+(
+    const fvPatch& p,
+    const DimensionedField<scalar, volMesh>& iF,
+    const dictionary& dict
+)
+:
+    fixedValueFvPatchScalarField(p, iF),
+    adjointBoundaryCondition(p, iF, dict.get<word>("solverName"))
+{
+    fvPatchField<scalar>::operator=
+    (
+        scalarField("value", dict, p.size())
+    );
+}
+
+
+adjointOutletNuaTildaFluxFvPatchScalarField::
+adjointOutletNuaTildaFluxFvPatchScalarField
+(
+    const adjointOutletNuaTildaFluxFvPatchScalarField& tppsf,
+    const DimensionedField<scalar, volMesh>& iF
+)
+:
+    fixedValueFvPatchScalarField(tppsf, iF),
+    adjointBoundaryCondition(tppsf)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void adjointOutletNuaTildaFluxFvPatchScalarField::updateCoeffs()
+{
+    if (updated())
+    {
+        return;
+    }
+
+    operator == (scalarField(patch().size(), Zero));
+
+    fixedValueFvPatchScalarField::updateCoeffs();
+}
+
+
+tmp<Field<scalar>>
+adjointOutletNuaTildaFluxFvPatchScalarField::valueInternalCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    return tmp<Field<scalar>>::New(this->size(), pTraits<scalar>::zero);
+}
+
+
+tmp<Field<scalar>>
+adjointOutletNuaTildaFluxFvPatchScalarField::valueBoundaryCoeffs
+(
+    const tmp<scalarField>&
+) const
+{
+    return tmp<Field<scalar>>::New(this->size(), pTraits<scalar>::zero);
+}
+
+
+tmp<Field<scalar>>
+adjointOutletNuaTildaFluxFvPatchScalarField::gradientBoundaryCoeffs() const
+{
+    return tmp<Field<scalar>>::New(this->size(), pTraits<scalar>::zero);
+}
+
+
+tmp<Field<scalar>>
+adjointOutletNuaTildaFluxFvPatchScalarField::gradientInternalCoeffs() const
+{
+    return tmp<Field<scalar>>::New(this->size(), pTraits<scalar>::zero);
+}
+
+
+void adjointOutletNuaTildaFluxFvPatchScalarField::write(Ostream& os) const
+{
+    fvPatchScalarField::write(os);
+    writeEntry("value", os);
+    os.writeEntry("solverName", adjointSolverName_);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+makePatchTypeField
+(
+    fvPatchScalarField,
+    adjointOutletNuaTildaFluxFvPatchScalarField
+);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTildaFlux/adjointOutletNuaTildaFluxFvPatchScalarField.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTildaFlux/adjointOutletNuaTildaFluxFvPatchScalarField.H
new file mode 100644
index 0000000000000000000000000000000000000000..29bc40c24593f8b72cd6030ab17f9e18af5c336c
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/derivedFvPatchFields/adjointOutletNuaTildaFlux/adjointOutletNuaTildaFluxFvPatchScalarField.H
@@ -0,0 +1,164 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::adjointOutletNuaTildaFluxFvPatchScalarField
+
+Description
+
+SourceFiles
+    adjointOutletNuaTildaFluxFvPatchScalarField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointOutletNuaTildaFluxFvPatchScalarField_H
+#define adjointOutletNuaTildaFluxFvPatchScalarField_H
+
+#include "fixedValueFvPatchFields.H"
+#include "adjointBoundaryCondition.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+               Class adjointOutletNuaTildaFluxFvPatch Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointOutletNuaTildaFluxFvPatchScalarField
+:
+    public fixedValueFvPatchScalarField,
+    public adjointBoundaryCondition
+{
+
+public:
+
+    //- Runtime type information
+    TypeName("adjointOutletNuaTildaFlux");
+
+
+    // Constructors
+
+        //- Construct from patch and internal field
+        adjointOutletNuaTildaFluxFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct from patch, internal field and dictionary
+        adjointOutletNuaTildaFluxFvPatchScalarField
+        (
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const dictionary&
+        );
+
+        //- Construct by mapping given
+        //- adjointOutletNuaTildaFluxFvPatchScalarField onto a new patch
+        adjointOutletNuaTildaFluxFvPatchScalarField
+        (
+            const adjointOutletNuaTildaFluxFvPatchScalarField&,
+            const fvPatch&,
+            const DimensionedField<scalar, volMesh>&,
+            const fvPatchFieldMapper&
+        );
+
+        //- Construct and return a clone
+        virtual tmp<fvPatchScalarField> clone() const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointOutletNuaTildaFluxFvPatchScalarField(*this)
+            );
+        }
+
+        //- Construct as copy setting internal field reference
+        adjointOutletNuaTildaFluxFvPatchScalarField
+        (
+            const adjointOutletNuaTildaFluxFvPatchScalarField&,
+            const DimensionedField<scalar, volMesh>&
+        );
+
+        //- Construct and return a clone setting internal field reference
+        virtual tmp<fvPatchScalarField> clone
+        (
+            const DimensionedField<scalar, volMesh>& iF
+        ) const
+        {
+            return tmp<fvPatchScalarField>
+            (
+                new adjointOutletNuaTildaFluxFvPatchScalarField(*this, iF)
+            );
+        }
+
+
+    // Member functions
+
+        // Evaluation functions
+
+            //- Update the coefficients associated with the patch field
+            virtual void updateCoeffs();
+
+            //- Return the matrix diagonal coefficients corresponding to the
+            //- evaluation of the value of this patchField with given weights
+            virtual tmp<Field<scalar>> valueInternalCoeffs
+            (
+                const tmp<scalarField>&
+            ) const;
+
+            //- Return the matrix source coefficients corresponding to the
+            //- evaluation of the value of this patchField with given weights
+            virtual tmp<Field<scalar>> valueBoundaryCoeffs
+            (
+                const tmp<scalarField>&
+
+            ) const;
+
+            //- Return the matrix source coefficients corresponding to the
+            //- evaluation of the gradient of this patchField
+            virtual tmp<Field<scalar>> gradientBoundaryCoeffs() const;
+
+            //- Return the matrix diagonal coefficients corresponding to the
+            //- evaluation of the gradient of this patchField
+            virtual tmp<Field<scalar>> gradientInternalCoeffs() const;
+
+        //- Write
+        virtual void write(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointTurbulenceModel/adjointTurbulenceModel.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointTurbulenceModel/adjointTurbulenceModel.C
new file mode 100644
index 0000000000000000000000000000000000000000..9f085054a2c596ac17d9ea93a2b1580229067025
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointTurbulenceModel/adjointTurbulenceModel.C
@@ -0,0 +1,141 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "adjointTurbulenceModel.H"
+#include "volFields.H"
+#include "surfaceFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressibleAdjoint
+{
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(adjointTurbulenceModel, 0);
+defineRunTimeSelectionTable(adjointTurbulenceModel, adjointTurbulenceModel);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+adjointTurbulenceModel::adjointTurbulenceModel
+(
+    incompressibleVars& primalVars,
+    incompressibleAdjointMeanFlowVars& adjointVars,
+    objectiveManager& objManager,
+    const word& adjointTurbulenceModelName
+)
+:
+    regIOobject
+    (
+        IOobject
+        (
+            adjointTurbulenceModelName,
+            primalVars.U().time().constant(),
+            primalVars.U().db(),
+            IOobject::NO_READ,
+            IOobject::NO_WRITE
+        )
+    ),
+    primalVars_(primalVars),
+    adjointVars_(adjointVars),
+    runTime_(primalVars.U().time()),
+    mesh_(primalVars.U().mesh())
+{}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+autoPtr<adjointTurbulenceModel> adjointTurbulenceModel::New
+(
+    incompressibleVars& primalVars,
+    incompressibleAdjointMeanFlowVars& adjointVars,
+    objectiveManager& objManager,
+    const word& adjointTurbulenceModelName
+)
+{
+    // Get model name, but do not register the dictionary
+    // otherwise it is registered in the database twice
+    const word modelType
+    (
+        IOdictionary
+        (
+            IOobject
+            (
+                "turbulenceProperties",
+                primalVars.U().time().constant(),
+                primalVars.U().db(),
+                IOobject::MUST_READ_IF_MODIFIED,
+                IOobject::NO_WRITE,
+                false
+            )
+        ).get<word>("simulationType")
+    );
+
+    Info<< "Selecting turbulence model type " << modelType << endl;
+
+    auto cstrIter =
+        adjointTurbulenceModelConstructorTablePtr_->cfind(modelType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << modelType << nl << nl
+            << "Valid adjointTurbulenceModel types:" << endl
+            << adjointTurbulenceModelConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return autoPtr<adjointTurbulenceModel>
+    (
+        cstrIter()
+        (
+            primalVars,
+            adjointVars,
+            objManager,
+            adjointTurbulenceModelName
+        )
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void adjointTurbulenceModel::correct()
+{
+    primalVars_.laminarTransport().correct();
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressibleAdjoint
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointTurbulenceModel/adjointTurbulenceModel.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointTurbulenceModel/adjointTurbulenceModel.H
new file mode 100644
index 0000000000000000000000000000000000000000..7a743ab03cccac29fc323ff8962e6d6219451b84
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointTurbulenceModel/adjointTurbulenceModel.H
@@ -0,0 +1,218 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressibleAdjoint
+
+Description
+    Namespace for incompressible adjoint turbulence models.
+
+Class
+    Foam::incompressibleAdjoint::adjointTurbulenceModel
+
+Description
+    Abstract base class for incompressible adjoint turbulence models
+    (RAS, LES and laminar).
+
+SourceFiles
+    adjointTurbulenceModel.C
+    newTurbulenceModel.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef adjointTurbulenceModel_H
+#define adjointTurbulenceModel_H
+
+#include "incompressibleVars.H"
+#include "incompressibleAdjointMeanFlowVars.H"
+#include "objectiveManager.H"
+#include "Time.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward declarations
+class fvMesh;
+
+namespace incompressibleAdjoint
+{
+
+/*---------------------------------------------------------------------------*\
+                    Class adjointTurbulenceModel Declaration
+\*---------------------------------------------------------------------------*/
+
+class adjointTurbulenceModel
+:
+    public regIOobject
+{
+private:
+
+    // Private Member Functions
+
+        //- No copy construct
+        adjointTurbulenceModel(const adjointTurbulenceModel&) = delete;
+
+        //- No copy assignment
+        void operator=(const adjointTurbulenceModel&) = delete;
+
+
+protected:
+
+    // Protected data
+
+        incompressibleVars& primalVars_;
+        incompressibleAdjointMeanFlowVars& adjointVars_;
+        const Time& runTime_;
+        const fvMesh& mesh_;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("adjointTurbulenceModel");
+
+
+    // Declare run-time New selection table
+
+        declareRunTimeNewSelectionTable
+        (
+            autoPtr,
+            adjointTurbulenceModel,
+            adjointTurbulenceModel,
+            (
+                incompressibleVars& primalVars,
+                incompressibleAdjointMeanFlowVars& adjointVars,
+                objectiveManager& objManager,
+                const word& adjointTurbulenceModelName
+            ),
+            (
+                primalVars,
+                adjointVars,
+                objManager,
+                adjointTurbulenceModelName
+            )
+        );
+
+
+    // Constructors
+
+        //- Construct from components
+        adjointTurbulenceModel
+        (
+            incompressibleVars& primalVars,
+            incompressibleAdjointMeanFlowVars& adjointVars,
+            objectiveManager& objManager,
+            const word& adjointTurbulenceModelName = typeName
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<adjointTurbulenceModel> New
+        (
+            incompressibleVars& primalVars,
+            incompressibleAdjointMeanFlowVars& adjointVars,
+            objectiveManager& objManager,
+            const word& adjointTurbulenceModelName = typeName
+        );
+
+
+    //- Destructor
+    virtual ~adjointTurbulenceModel() = default;
+
+
+    // Member Functions
+
+        //- Return the laminar viscosity
+        inline tmp<volScalarField> nu() const
+        {
+            return primalVars_.laminarTransport().nu();
+        }
+
+        //- Return the turbulence viscosity
+        virtual const volScalarField& nut() const
+        {
+            return primalVars_.RASModelVariables()().nutRef();
+        }
+
+        //- Return the effective viscosity
+        virtual tmp<volScalarField> nuEff() const
+        {
+            // Go through RASModelVariables::nutRef in order to obtain
+            // the mean field, if present
+            const singlePhaseTransportModel& lamTrans =
+                primalVars_.laminarTransport();
+            const autoPtr<incompressible::RASModelVariables>&
+                turbVars = primalVars_.RASModelVariables();
+
+            return
+                tmp<volScalarField>::New
+                (
+                    "nuEff",
+                    lamTrans.nu()() + turbVars().nutRef()
+                );
+            //return primalVars_.turbulence()().nuEff();
+        }
+
+        //- Return the effective stress tensor including the laminar stress
+        virtual tmp<volSymmTensorField> devReff() const = 0;
+
+        //- Return the diffusion term for the momentum equation
+        virtual tmp<fvVectorMatrix> divDevReff(volVectorField& U) const = 0;
+
+        //- Source term added to the adjoint mean flow due to the
+        //  differentiation of the turbulence model
+        virtual tmp<volVectorField> adjointMeanFlowSource() = 0;
+
+        //- Solve the adjoint turbulence equations
+        virtual void correct() = 0;
+
+        //- Read adjointLESProperties or adjointRASProperties dictionary
+        virtual bool read() = 0;
+
+        //- Default dummy write function
+        virtual bool writeData(Ostream&) const
+        {
+            return true;
+        }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressibleAdjoint
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/LaunderSharmaKE/LaunderSharmaKE.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/LaunderSharmaKE/LaunderSharmaKE.C
new file mode 100644
index 0000000000000000000000000000000000000000..a7684b9060def3c557f5766ce778158078afd73b
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/LaunderSharmaKE/LaunderSharmaKE.C
@@ -0,0 +1,87 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "LaunderSharmaKE.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressible
+{
+namespace RASVariables
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(LaunderSharmaKE, 0);
+addToRunTimeSelectionTable(RASModelVariables, LaunderSharmaKE, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+LaunderSharmaKE::LaunderSharmaKE
+(
+    const fvMesh& mesh,
+    const solverControl& SolverControl
+)
+:
+    RASModelVariables(mesh, SolverControl)
+{
+    hasTMVar1_ = true;
+    TMVar1Ptr_ = mesh_.getObjectPtr<volScalarField>("k");
+    TMVar1BaseName_ = "k";
+
+    hasTMVar2_ = true;
+    TMVar2Ptr_ = mesh_.getObjectPtr<volScalarField>("epsilon");
+    TMVar2BaseName_ = "epsilon";
+
+    hasNut_ = true;
+    nutPtr_ = mesh_.getObjectPtr<volScalarField>("nut");
+
+    allocateInitValues();
+    allocateMeanFields();
+}
+
+
+LaunderSharmaKE::~LaunderSharmaKE()
+{
+    // nullify pointer
+    TMVar1Ptr_ = nullptr;
+    TMVar2Ptr_ = nullptr;
+    nutPtr_ = nullptr;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace RASVariables
+} // End namespace incompressible
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/LaunderSharmaKE/LaunderSharmaKE.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/LaunderSharmaKE/LaunderSharmaKE.H
new file mode 100644
index 0000000000000000000000000000000000000000..c738d0038fb6d6e6803fb78f37fec800c92ad0ee
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/LaunderSharmaKE/LaunderSharmaKE.H
@@ -0,0 +1,92 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::RASVariables::LaunderSharmaKE
+
+Description
+
+SourceFiles
+    LaunderSharmaKE.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef LaunderSharmaKE_H
+#define LaunderSharmaKE_H
+
+#include "RASModelVariables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressible
+{
+namespace RASVariables
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class LaunderSharmaKE Declaration
+\*---------------------------------------------------------------------------*/
+
+class LaunderSharmaKE
+:
+    public RASModelVariables
+{
+
+public:
+
+    //- Runtime type information
+    TypeName("LaunderSharmaKE");
+
+
+    // Constructors
+
+        //- Construct from components
+        LaunderSharmaKE
+        (
+            const fvMesh& mesh,
+            const solverControl& SolverControl
+        );
+
+
+    //- Destructor
+    virtual ~LaunderSharmaKE();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace RASVariables
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.C
new file mode 100644
index 0000000000000000000000000000000000000000..1757edf3426f7e7b87a506a6ea5c4e923e8a5861
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.C
@@ -0,0 +1,583 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "RASModelVariables.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressible
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(RASModelVariables, 0);
+defineRunTimeSelectionTable(RASModelVariables, dictionary);
+
+// * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
+
+void RASModelVariables::allocateInitValues()
+{
+    if (solverControl_.storeInitValues())
+    {
+        Info<< "Storing initial values of turbulence variables" << endl;
+        if (hasTMVar1_)
+        {
+            TMVar1InitPtr_.reset
+            (
+                new volScalarField
+                (
+                    TMVar1Inst().name()+"Init",TMVar1Inst()
+                )
+            );
+        }
+
+        if (hasTMVar2_)
+        {
+            TMVar2InitPtr_.reset
+            (
+                new volScalarField
+                (
+                    TMVar2Inst().name()+"Init",TMVar2Inst()
+                )
+            );
+        }
+
+        if (hasNut_)
+        {
+            nutInitPtr_.reset
+            (
+                new volScalarField
+                (
+                    nutRefInst().name()+"Init",nutRefInst()
+                )
+            );
+        }
+    }
+}
+
+
+void RASModelVariables::allocateMeanFields()
+{
+    if (solverControl_.average())
+    {
+        Info<< "Allocating mean values of turbulence variables" << endl;
+        if (hasTMVar1_)
+        {
+            TMVar1MeanPtr_.reset
+            (
+                new volScalarField
+                (
+                    IOobject
+                    (
+                        TMVar1Inst().name()+"Mean",
+                        mesh_.time().timeName(),
+                        mesh_,
+                        IOobject::READ_IF_PRESENT,
+                        IOobject::AUTO_WRITE
+                    ),
+                    TMVar1Inst()
+                )
+            );
+        }
+        if (hasTMVar2_)
+        {
+            TMVar2MeanPtr_.reset
+            (
+                new volScalarField
+                (
+                    IOobject
+                    (
+                        TMVar2Inst().name()+"Mean",
+                        mesh_.time().timeName(),
+                        mesh_,
+                        IOobject::READ_IF_PRESENT,
+                        IOobject::AUTO_WRITE
+                    ),
+                    TMVar2Inst()
+                )
+            );
+        }
+
+        if (hasNut_)
+        {
+            nutMeanPtr_.reset
+            (
+                new volScalarField
+                (
+                    IOobject
+                    (
+                        nutRefInst().name()+"Mean",
+                        mesh_.time().timeName(),
+                        mesh_,
+                        IOobject::READ_IF_PRESENT,
+                        IOobject::AUTO_WRITE
+                    ),
+                    nutRefInst()
+                )
+            );
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+RASModelVariables::RASModelVariables
+(
+    const fvMesh& mesh,
+    const solverControl& SolverControl
+)
+:
+    mesh_(mesh),
+    solverControl_(SolverControl),
+    hasTMVar1_(false),
+    hasTMVar2_(false),
+    hasNut_(false),
+    hasDist_(false),
+    TMVar1Ptr_(nullptr),
+    TMVar2Ptr_(nullptr),
+    nutPtr_(nullptr),
+    dPtr_(nullptr),
+    TMVar1BaseName_(word::null),
+    TMVar2BaseName_(word::null),
+    nutBaseName_("nut"),
+    TMVar1InitPtr_(nullptr),
+    TMVar2InitPtr_(nullptr),
+    nutInitPtr_(nullptr),
+    TMVar1MeanPtr_(nullptr),
+    TMVar2MeanPtr_(nullptr),
+    nutMeanPtr_(nullptr)
+{}
+
+
+// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
+
+autoPtr<RASModelVariables> RASModelVariables::New
+(
+    const fvMesh& mesh,
+    const solverControl& SolverControl
+)
+{
+    // Get model name, but do not register the dictionary
+    // otherwise it is registered in the database twice
+    const word modelType
+    (
+        IOdictionary
+        (
+            IOobject
+            (
+                turbulenceModel::propertiesName,
+                mesh.time().constant(),
+                mesh,
+                IOobject::MUST_READ_IF_MODIFIED,
+                IOobject::NO_WRITE,
+                false
+            )
+        ).subOrEmptyDict("RAS").lookupOrDefault<word>("RASModel", "laminar")
+    );
+
+    Info<< "Creating references for RASModel variables : " << modelType << endl;
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
+
+    if (!cstrIter.found())
+    {
+        FatalErrorInFunction
+            << "Unknown RASModelVariables type " << modelType << nl << nl
+            << "Valid RASModelVariables types are :" << nl
+            << dictionaryConstructorTablePtr_->sortedToc()
+            << exit(FatalError);
+    }
+
+    return autoPtr<RASModelVariables>(cstrIter()(mesh, SolverControl));
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+bool RASModelVariables::hasTMVar1() const
+{
+    return hasTMVar1_;
+}
+
+
+bool RASModelVariables::hasTMVar2() const
+{
+    return hasTMVar2_;
+}
+
+
+bool RASModelVariables::hasNut() const
+{
+    return hasNut_;
+}
+
+
+bool RASModelVariables::hasDist() const
+{
+    return hasDist_;
+}
+
+
+const word& RASModelVariables::TMVar1BaseName() const
+{
+    return TMVar1BaseName_;
+}
+
+
+const word& RASModelVariables::TMVar2BaseName() const
+{
+    return TMVar2BaseName_;
+}
+
+
+const word& RASModelVariables::nutBaseName() const
+{
+    return nutBaseName_;
+}
+
+
+const volScalarField& RASModelVariables::TMVar1() const
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return TMVar1MeanPtr_();
+    }
+    else
+    {
+        return *TMVar1Ptr_;
+    }
+}
+
+
+volScalarField& RASModelVariables::TMVar1()
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return TMVar1MeanPtr_();
+    }
+    else
+    {
+        return *TMVar1Ptr_;
+    }
+}
+
+
+const volScalarField& RASModelVariables::TMVar2() const
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return TMVar2MeanPtr_();
+    }
+    else
+    {
+        return *TMVar2Ptr_;
+    }
+}
+
+volScalarField& RASModelVariables::TMVar2()
+{
+    if (solverControl_.useAveragedFields())
+    {
+        return TMVar2MeanPtr_();
+    }
+    else
+    {
+        return *TMVar2Ptr_;
+    }
+}
+
+const volScalarField& RASModelVariables::nutRef() const
+{
+    if (solverControl_.useAveragedFields() && hasNut_)
+    {
+        return nutMeanPtr_();
+    }
+    else
+    {
+        return *nutPtr_;
+    }
+}
+
+
+volScalarField& RASModelVariables::nutRef()
+{
+    if (solverControl_.useAveragedFields() && hasNut_)
+    {
+        return  nutMeanPtr_();
+    }
+    else
+    {
+        return *nutPtr_;
+    }
+}
+
+
+const volScalarField& RASModelVariables::d() const
+{
+    return *dPtr_;
+}
+
+
+volScalarField& RASModelVariables::d()
+{
+    return *dPtr_;
+}
+
+
+const volScalarField& RASModelVariables::TMVar1Inst() const
+{
+    return *TMVar1Ptr_;
+}
+
+
+volScalarField& RASModelVariables::TMVar1Inst()
+{
+    return *TMVar1Ptr_;
+}
+
+
+const volScalarField& RASModelVariables::TMVar2Inst() const
+{
+    return *TMVar2Ptr_;
+}
+
+
+volScalarField& RASModelVariables::TMVar2Inst()
+{
+    return *TMVar2Ptr_;
+}
+
+
+const volScalarField& RASModelVariables::nutRefInst() const
+{
+    return *nutPtr_;
+}
+
+
+volScalarField& RASModelVariables::nutRefInst()
+{
+    return *nutPtr_;
+}
+
+
+tmp<volScalarField> RASModelVariables::nutJacobianVar1
+(
+    const singlePhaseTransportModel& laminarTransport
+) const
+{
+    WarningInFunction
+        << "jutJacobianVar1 not implemented for the current turbulence model."
+        << "Returning zero field" << endl;
+
+    tmp<volScalarField> nutJacobian
+    (
+        new volScalarField
+        (
+            IOobject
+            (
+                "nutJacobianVar1",
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedScalar(dimless, Zero)
+        )
+    );
+    return nutJacobian;
+}
+
+
+tmp<volScalarField> RASModelVariables::nutJacobianVar2
+(
+    const singlePhaseTransportModel& laminarTransport
+) const
+{
+    WarningInFunction
+        << "nutJacobianVar2 not implemented for the current turbulence model."
+        << "Returning zero field" << endl;
+
+    tmp<volScalarField> nutJacobian
+    (
+        new volScalarField
+        (
+            IOobject
+            (
+                "nutJacobianVar2",
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedScalar(dimless, Zero)
+        )
+    );
+    return nutJacobian;
+}
+
+void RASModelVariables::restoreInitValues()
+{
+    if (solverControl_.storeInitValues())
+    {
+        if (hasTMVar1_)
+        {
+            TMVar1Inst() == TMVar1InitPtr_();
+        }
+        if (hasTMVar2_)
+        {
+            TMVar2Inst() == TMVar2InitPtr_();
+        }
+        if (hasNut_)
+        {
+            nutRefInst() == nutInitPtr_();
+        }
+    }
+}
+
+
+void RASModelVariables::resetMeanFields()
+{
+    if (solverControl_.average())
+    {
+        Info<< "Reseting mean turbulent fields to zero" << endl;
+
+        // Reset fields to zero
+        if (hasTMVar1_)
+        {
+            TMVar1MeanPtr_() ==
+                dimensionedScalar(TMVar1Inst().dimensions(), Zero);
+        }
+        if (hasTMVar2_)
+        {
+            TMVar2MeanPtr_() ==
+                dimensionedScalar(TMVar2Inst().dimensions(), Zero);
+        }
+        if (hasNut_)
+        {
+            nutMeanPtr_() == dimensionedScalar(nutRefInst().dimensions(), Zero);
+        }
+    }
+}
+
+
+void RASModelVariables::computeMeanFields()
+{
+    if (solverControl_.doAverageIter())
+    {
+        const label iAverageIter = solverControl_.averageIter();
+        scalar avIter(iAverageIter);
+        scalar oneOverItP1 = 1./(avIter + 1);
+        scalar mult = avIter*oneOverItP1;
+        if (hasTMVar1_)
+        {
+            TMVar1MeanPtr_() ==
+                TMVar1MeanPtr_()*mult + TMVar1Inst()*oneOverItP1;
+        }
+        if (hasTMVar2_)
+        {
+            TMVar2MeanPtr_() ==
+                TMVar2MeanPtr_()*mult + TMVar2Inst()*oneOverItP1;
+        }
+        if (hasNut_)
+        {
+            nutMeanPtr_() == nutMeanPtr_()*mult + nutRefInst()*oneOverItP1;
+        }
+    }
+}
+
+
+tmp<volSymmTensorField> RASModelVariables::devReff
+(
+    const singlePhaseTransportModel& laminarTransport,
+    const volVectorField& U
+) const
+{
+    return tmp<volSymmTensorField>
+    (
+        new volSymmTensorField
+        (
+            IOobject
+            (
+                "devRhoReff",
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+           -(laminarTransport.nu() + nutRef())*dev(twoSymm(fvc::grad(U)))
+        )
+    );
+}
+
+
+void RASModelVariables::correctBoundaryConditions
+(
+    const incompressible::turbulenceModel& turbulence
+)
+{
+    if (hasTMVar1())
+    {
+        TMVar1Ptr_->correctBoundaryConditions();
+        if (solverControl_.average())
+        {
+            TMVar1MeanPtr_().correctBoundaryConditions();
+        }
+    }
+
+    if (hasTMVar2())
+    {
+        TMVar2Ptr_->correctBoundaryConditions();
+        if (solverControl_.average())
+        {
+            TMVar2MeanPtr_().correctBoundaryConditions();
+        }
+    }
+
+    if (hasNut())
+    {
+        nutPtr_->correctBoundaryConditions();
+        if (solverControl_.average())
+        {
+            nutMeanPtr_().correctBoundaryConditions();
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.H
new file mode 100644
index 0000000000000000000000000000000000000000..5bc2ff05c38d1854b1fe8d9484a8c4e2f677dc14
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.H
@@ -0,0 +1,240 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::RASModelVariables
+
+Description
+    Abstract base class for objective functions. No point in making this
+    runTime selectable since its childs will have different constructors.
+
+SourceFiles
+    RASModelVariables.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef RASModelVariables_H
+#define RASModelVariables_H
+
+#include "solverControl.H"
+#include "singlePhaseTransportModel.H"
+#include "turbulentTransportModel.H"
+#include "runTimeSelectionTables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressible
+{
+
+/*---------------------------------------------------------------------------*\
+                      Class RASModelVariables Declaration
+\*---------------------------------------------------------------------------*/
+
+class RASModelVariables
+{
+
+protected:
+
+    // Protected data
+
+        const fvMesh& mesh_;
+        const solverControl& solverControl_;
+
+        // autoPtrs delete the memory on destruction
+        // Can cause memory mishandling issues in this case
+        // Use regular ptrs instead
+        bool hasTMVar1_;
+        bool hasTMVar2_;
+        bool hasNut_;
+        bool hasDist_;
+        volScalarField* TMVar1Ptr_;
+        volScalarField* TMVar2Ptr_;
+        volScalarField* nutPtr_;
+        volScalarField* dPtr_;
+
+        // Base names of the turbulent fields
+        word TMVar1BaseName_;
+        word TMVar2BaseName_;
+        word nutBaseName_;
+
+        // conditionally store initial values
+        // For finite differences and optimisation runs
+        autoPtr<volScalarField> TMVar1InitPtr_;
+        autoPtr<volScalarField> TMVar2InitPtr_;
+        autoPtr<volScalarField> nutInitPtr_;
+
+        // conditionally store mean values
+        autoPtr<volScalarField> TMVar1MeanPtr_;
+        autoPtr<volScalarField> TMVar2MeanPtr_;
+        autoPtr<volScalarField> nutMeanPtr_;
+
+
+    // Protected functions
+
+        void allocateInitValues();
+        void allocateMeanFields();
+
+
+private:
+
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct
+        RASModelVariables(const RASModelVariables&) = delete;
+
+        //- Disallow default bitwise assignment
+        void operator=(const RASModelVariables&) = delete;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("RASModelVariables");
+
+    // Declare run-time constructor selection table
+
+        declareRunTimeSelectionTable
+        (
+            autoPtr,
+            RASModelVariables,
+            dictionary,
+            (
+                const fvMesh& mesh,
+                const solverControl& SolverControl
+            ),
+            (mesh, SolverControl)
+        );
+
+
+    // Constructors
+
+        //- Construct from components
+        RASModelVariables
+        (
+            const fvMesh& mesh,
+            const solverControl& SolverControl
+        );
+
+
+    // Selectors
+
+        //- Return a reference to the selected turbulence model
+        static autoPtr<RASModelVariables> New
+        (
+            const fvMesh& mesh,
+            const solverControl& SolverControl
+        );
+
+
+    // Destructor
+
+        // Destructor does nothing on base since depending on the case new
+        // fields might be allocated
+        // MUST be overloaded in inherited classes
+        virtual ~RASModelVariables() = default;
+
+
+    // Member Functions
+
+
+        //- Bools to idenify which turbulent fields are present
+        bool hasTMVar1() const;
+        bool hasTMVar2() const;
+        bool hasNut() const;
+        bool hasDist() const;
+
+        //- Turbulence field names
+        const word& TMVar1BaseName() const;
+        const word& TMVar2BaseName() const;
+        const word& nutBaseName() const;
+
+        //- Return references to turbulence fields
+        //  will return the mean field if it exists, otherwise the
+        //  instantaneous one
+        const volScalarField& TMVar1() const;
+              volScalarField& TMVar1();
+        const volScalarField& TMVar2() const;
+              volScalarField& TMVar2();
+        const volScalarField& nutRef() const;
+              volScalarField& nutRef();
+        const volScalarField& d() const;
+              volScalarField& d();
+
+        //- return references to instantaneous turbulence fields
+        const volScalarField& TMVar1Inst() const;
+              volScalarField& TMVar1Inst();
+        const volScalarField& TMVar2Inst() const;
+              volScalarField& TMVar2Inst();
+        const volScalarField& nutRefInst() const;
+              volScalarField& nutRefInst();
+
+        //- Return nut Jacobian wrt the TM vars
+        virtual tmp<volScalarField> nutJacobianVar1
+        (
+            const singlePhaseTransportModel& laminarTransport
+        ) const;
+        virtual tmp<volScalarField> nutJacobianVar2
+        (
+            const singlePhaseTransportModel& laminarTransport
+        ) const;
+
+        //- Restore turbulent fields to their initial values
+        void restoreInitValues();
+
+        //- Reset mean fields to zero
+        void resetMeanFields();
+
+        //- Compute mean fields on the fly
+        void computeMeanFields();
+
+        //- Return stress tensor based on the mean flow variables
+        tmp<volSymmTensorField> devReff
+        (
+            const singlePhaseTransportModel& laminarTransport,
+            const volVectorField& U
+        ) const;
+
+        //- correct bounday conditions of turbulent fields
+        virtual void correctBoundaryConditions
+        (
+            const incompressible::turbulenceModel& turbulence
+        );
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.C
new file mode 100644
index 0000000000000000000000000000000000000000..fdd8db848e33fbf819867ce4b772cb8cfa379c62
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.C
@@ -0,0 +1,143 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "SpalartAllmaras.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressible
+{
+namespace RASVariables
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(SpalartAllmaras, 0);
+addToRunTimeSelectionTable(RASModelVariables, SpalartAllmaras, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+SpalartAllmaras::SpalartAllmaras
+(
+    const fvMesh& mesh,
+    const solverControl& SolverControl
+)
+:
+    RASModelVariables(mesh, SolverControl)
+{
+    hasTMVar1_ = true;
+    TMVar1Ptr_ = mesh_.getObjectPtr<volScalarField>("nuTilda");
+    TMVar1BaseName_ = "nuTilda";
+
+    TMVar2Ptr_ =
+        new volScalarField
+        (
+            IOobject
+            (
+                "dummySpalartAllmarasVar2",
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh,
+            dimensionedScalar(dimless, Zero)
+        );
+
+    hasNut_ = true;
+    nutPtr_ = mesh_.getObjectPtr<volScalarField>("nut");
+
+    hasDist_ = true;
+    dPtr_ = mesh_.getObjectPtr<volScalarField>("yWall");
+
+    allocateInitValues();
+    allocateMeanFields();
+}
+
+
+SpalartAllmaras::~SpalartAllmaras ()
+{
+    // nullify pointer
+    TMVar1Ptr_ = nullptr;
+    nutPtr_ = nullptr;
+    dPtr_ = nullptr;
+
+    // nullify pointer and delete allocated field
+    delete TMVar2Ptr_;
+    TMVar2Ptr_ = nullptr;
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+tmp<volScalarField> SpalartAllmaras::nutJacobianVar1
+(
+    const singlePhaseTransportModel& laminarTransport
+) const
+{
+    tmp<volScalarField> tnutJacobian
+    (
+        new volScalarField
+        (
+            IOobject
+            (
+                "nutJacobianVar1",
+                mesh_.time().timeName(),
+                mesh_,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh_,
+            dimensionedScalar(dimless, Zero)
+        )
+    );
+    volScalarField& nutJacobian = tnutJacobian.ref();
+
+    const volScalarField& nu = laminarTransport.nu();
+    const volScalarField& nuTilda = TMVar1();
+    volScalarField chi(nuTilda/nu);
+    volScalarField chi3(pow3(chi));
+    scalar Cv13 = pow3(7.1);
+    volScalarField fv1(chi3/(chi3 + Cv13));
+    volScalarField fv1ByChi2Sqr(sqr(chi/(chi3 + Cv13)));
+    volScalarField Cdfv1(3.0*Cv13*fv1ByChi2Sqr);
+    nutJacobian = Cdfv1*chi + fv1;
+
+    return tnutJacobian;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace RASVariables
+} // End namespace incompressible
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.H
new file mode 100644
index 0000000000000000000000000000000000000000..08b1a8b327e25b77b708a7e010ab7db21f8e9ec5
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.H
@@ -0,0 +1,99 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::RASVariables::SpalartAllmaras
+
+Description
+
+SourceFiles
+    SpalartAllmaras.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef SpalartAllmaras_H
+#define SpalartAllmaras_H
+
+#include "RASModelVariables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressible
+{
+namespace RASVariables
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class SpalartAllmaras Declaration
+\*---------------------------------------------------------------------------*/
+
+class SpalartAllmaras
+:
+    public RASModelVariables
+{
+
+public:
+
+    //- Runtime type information
+    TypeName("SpalartAllmaras");
+
+
+    // Constructors
+
+        //- Construct from components
+        SpalartAllmaras
+        (
+            const fvMesh& mesh,
+            const solverControl& SolverControl
+        );
+
+
+    //- Destructor
+    virtual ~SpalartAllmaras();
+
+    // Member Functions
+        //- return nut Jacobian wrt the TM vars
+        virtual tmp<volScalarField> nutJacobianVar1
+        (
+            const singlePhaseTransportModel& laminarTransport
+        ) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace RASVariables
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.C
new file mode 100644
index 0000000000000000000000000000000000000000..de81825f556f9814cdce0b596425400d3c495f02
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.C
@@ -0,0 +1,87 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "kEpsilon.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressible
+{
+namespace RASVariables
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(kEpsilon, 0);
+addToRunTimeSelectionTable(RASModelVariables, kEpsilon, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+kEpsilon::kEpsilon
+(
+    const fvMesh& mesh,
+    const solverControl& SolverControl
+)
+:
+    RASModelVariables(mesh, SolverControl)
+{
+    hasTMVar1_ = true;
+    TMVar1Ptr_ = mesh_.getObjectPtr<volScalarField>("k");
+    TMVar1BaseName_ = "k";
+
+    hasTMVar2_ = true;
+    TMVar2Ptr_ = mesh_.getObjectPtr<volScalarField>("epsilon");
+    TMVar2BaseName_ = "epsilon";
+
+    hasNut_ = true;
+    nutPtr_ = mesh_.getObjectPtr<volScalarField>("nut");
+
+    allocateInitValues();
+    allocateMeanFields();
+}
+
+
+kEpsilon::~kEpsilon()
+{
+    // nullify pointer
+    TMVar1Ptr_ = nullptr;
+    TMVar2Ptr_ = nullptr;
+    nutPtr_    = nullptr;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace RASVariables
+} // End namespace incompressible
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.H
new file mode 100644
index 0000000000000000000000000000000000000000..2d54ba2879ee6c9682b6c538464c3673f07a2d0a
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.H
@@ -0,0 +1,92 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::RASVariables::kEpsilon
+
+Description
+
+SourceFiles
+    kEpsilon.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef kEpsilon_H
+#define kEpsilon_H
+
+#include "RASModelVariables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressible
+{
+namespace RASVariables
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class kEpsilon Declaration
+\*---------------------------------------------------------------------------*/
+
+class kEpsilon
+:
+    public RASModelVariables
+{
+
+public:
+
+    //- Runtime type information
+    TypeName("kEpsilon");
+
+
+    // Constructors
+
+        //- Construct from components
+        kEpsilon
+        (
+            const fvMesh& mesh,
+            const solverControl& SolverControl
+        );
+
+
+    //- Destructor
+    virtual ~kEpsilon();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace RASVariables
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.C
new file mode 100644
index 0000000000000000000000000000000000000000..70f7084121794b35d0c9d1064fa267d6b0158c7f
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.C
@@ -0,0 +1,102 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "kOmegaSST.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressible
+{
+namespace RASVariables
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(kOmegaSST, 0);
+addToRunTimeSelectionTable(RASModelVariables, kOmegaSST, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+kOmegaSST::kOmegaSST
+(
+    const fvMesh& mesh,
+    const solverControl& SolverControl
+)
+:
+    RASModelVariables(mesh, SolverControl)
+{
+    hasTMVar1_ = true;
+    TMVar1Ptr_ = mesh_.getObjectPtr<volScalarField>("k");
+    TMVar1BaseName_ = "k";
+
+    hasTMVar2_ = true;
+    TMVar2Ptr_ = mesh_.getObjectPtr<volScalarField>("omega");
+    TMVar2BaseName_ = "omega";
+
+    hasNut_ = true;
+    nutPtr_ = mesh_.getObjectPtr<volScalarField>("nut");
+
+    allocateInitValues();
+    allocateMeanFields();
+}
+
+
+kOmegaSST::~kOmegaSST()
+{
+    // nullify pointers
+    TMVar1Ptr_ = nullptr;
+    TMVar2Ptr_ = nullptr;
+    nutPtr_    = nullptr;
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void kOmegaSST::correctBoundaryConditions
+(
+    const incompressible::turbulenceModel& turbulence
+)
+{
+    // The presence of G is required to update the boundary value of omega
+    const volVectorField& U(turbulence.U());
+    const volScalarField S2(2*magSqr(symm(fvc::grad(U))));
+    volScalarField G(turbulence.GName(), nutRef() * S2);
+    RASModelVariables::correctBoundaryConditions(turbulence);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace RASVariables
+} // End namespace incompressible
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.H
new file mode 100644
index 0000000000000000000000000000000000000000..8eee8da85406e63b989d9b581f083fb83a3f087d
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.H
@@ -0,0 +1,101 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::RASVariables::kOmegaSST
+
+Description
+
+SourceFiles
+    kOmegaSST.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef kOmegaSST_H
+#define kOmegaSST_H
+
+#include "RASModelVariables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressible
+{
+namespace RASVariables
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class kOmegaSST Declaration
+\*---------------------------------------------------------------------------*/
+
+class kOmegaSST
+:
+    public RASModelVariables
+{
+
+public:
+
+    //- Runtime type information
+    TypeName("kOmegaSST");
+
+
+    // Constructors
+
+        //- Construct from components
+        kOmegaSST
+        (
+            const fvMesh& mesh,
+            const solverControl& SolverControl
+        );
+
+
+    //- Destructor
+    virtual ~kOmegaSST();
+
+
+    // Member Functions
+
+        //- Correct boundary conditions of turbulent fields
+        virtual void correctBoundaryConditions
+        (
+            const incompressible::turbulenceModel& turbulence
+        );
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace RASVariables
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/laminar/laminar.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/laminar/laminar.C
new file mode 100644
index 0000000000000000000000000000000000000000..f7ac1b06456f885b874dc19356e3b0601b108556
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/laminar/laminar.C
@@ -0,0 +1,124 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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 "laminar.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressible
+{
+namespace RASVariables
+{
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+defineTypeNameAndDebug(laminar, 0);
+addToRunTimeSelectionTable(RASModelVariables, laminar, dictionary);
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+laminar::laminar
+(
+    const fvMesh& mesh,
+    const solverControl& SolverControl
+)
+:
+    RASModelVariables(mesh, SolverControl)
+{
+    TMVar1Ptr_ =
+        new volScalarField
+        (
+            IOobject
+            (
+                "dummylaminarVar1",
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh,
+            dimensionedScalar(dimless, Zero)
+        );
+
+    TMVar2Ptr_ =
+        new volScalarField
+        (
+            IOobject
+            (
+                "dummylaminarVar2",
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh,
+            dimensionedScalar(dimless, Zero)
+        );
+
+    nutPtr_ =
+        new volScalarField
+        (
+            IOobject
+            (
+                "dummylaminarNut",
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::NO_WRITE
+            ),
+            mesh,
+            dimensionedScalar(sqr(dimLength)/dimTime, Zero)
+        );
+        allocateInitValues();
+}
+
+
+laminar::~laminar()
+{
+    // nullify pointer and delete allocated fields
+    delete TMVar1Ptr_;
+    TMVar1Ptr_ = nullptr;
+
+    delete TMVar2Ptr_;
+    TMVar2Ptr_ = nullptr;
+
+    delete nutPtr_;
+    nutPtr_ = nullptr;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace RASVariables
+} // End namespace incompressible
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/laminar/laminar.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/laminar/laminar.H
new file mode 100644
index 0000000000000000000000000000000000000000..68db1cd91b0f98d4bcfbe746f157e842aaed2bd4
--- /dev/null
+++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/laminar/laminar.H
@@ -0,0 +1,92 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2019 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+                            | Copyright (C) 2007-2019 PCOpt/NTUA
+                            | Copyright (C) 2013-2019 FOSS GP
+-------------------------------------------------------------------------------
+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::incompressible::RASVariables::laminar
+
+Description
+
+SourceFiles
+    laminar.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef laminar_H
+#define laminar_H
+
+#include "RASModelVariables.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace incompressible
+{
+namespace RASVariables
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class laminar Declaration
+\*---------------------------------------------------------------------------*/
+
+class laminar
+:
+    public RASModelVariables
+{
+
+public:
+
+    //- Runtime type information
+    TypeName("laminar");
+
+
+    // Constructors
+
+        //- Construct from components
+        laminar
+        (
+            const fvMesh& mesh,
+            const solverControl& SolverControl
+        );
+
+
+    //- Destructor
+    virtual ~laminar();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace RASVariables
+} // End namespace incompressible
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/U b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/U
new file mode 100644
index 0000000000000000000000000000000000000000..cf35cc3f279d7d7f0a57b35d08d7a9bda501cff8
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/U
@@ -0,0 +1,52 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      U;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include        "include/initialConditions"
+
+dimensions      [0 1 -1 0 0 0 0];
+
+internalField   uniform $flowVelocity;
+
+boundaryField
+{
+    #includeEtc "caseDicts/setConstraintTypes"
+
+    #include "include/fixedInlet"
+
+    outlet
+    {
+        type            inletOutlet;
+        inletValue      uniform (0 0 0);
+        value           $internalField;
+    }
+
+    lowerWall
+    {
+        type            fixedValue;
+        value           $internalField;
+    }
+
+    motorBikeGroup
+    {
+        type            noSlip;
+    }
+
+    #include "include/frontBackUpperPatches"
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/Ua b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/Ua
new file mode 100644
index 0000000000000000000000000000000000000000..493c743f80c00b19b104d9aedd5fc07aefe3bab1
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/Ua
@@ -0,0 +1,56 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      Ua;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include        "include/initialConditions"
+
+dimensions      [0 1 -1 0 0 0 0];
+
+internalField   uniform (0 0 0);
+
+boundaryField
+{
+    #includeEtc "caseDicts/setConstraintTypes"
+
+    inlet
+    {
+        type            adjointInletVelocity;
+        value           $internalField;
+    }
+
+    outlet
+    {
+        type            adjointOutletVelocity;
+        inletValue      uniform (0 0 0);
+        value           $internalField;
+    }
+
+    lowerWall
+    {
+        type            adjointWallVelocity;
+        value           $internalField;
+    }
+
+    motorBikeGroup
+    {
+          $lowerWall
+    }
+
+    #include "include/frontBackUpperPatches"
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/include/fixedInlet b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/include/fixedInlet
new file mode 100644
index 0000000000000000000000000000000000000000..2e5346afa2cd7fb21757823fc955d5268f67ea44
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/include/fixedInlet
@@ -0,0 +1,15 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+
+inlet
+{
+    type  fixedValue;
+    value $internalField;
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/include/frontBackUpperPatches b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/include/frontBackUpperPatches
new file mode 100644
index 0000000000000000000000000000000000000000..d09be8ab014b12100638b1c15e8ce6f029db36c9
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/include/frontBackUpperPatches
@@ -0,0 +1,19 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+
+upperWall
+{
+    type slip;
+}
+
+frontAndBack
+{
+    type slip;
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/include/initialConditions b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/include/initialConditions
new file mode 100644
index 0000000000000000000000000000000000000000..9bc753bdd2ecb5d58e5ffecc5cac2f1c642f6fbf
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/include/initialConditions
@@ -0,0 +1,13 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+
+flowVelocity         (20 0 0);
+pressure             0;
+nuTilda              1.5e-04;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/nuTilda b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/nuTilda
new file mode 100644
index 0000000000000000000000000000000000000000..d6594e4381bc8952490f4e742a84d63046a6fdd5
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/nuTilda
@@ -0,0 +1,54 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nuTilda;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include        "include/initialConditions"
+
+dimensions      [0 2 -1 0 0 0 0];
+
+internalField   uniform $nuTilda;
+
+boundaryField
+{
+    #includeEtc "caseDicts/setConstraintTypes"
+
+    //- Define inlet conditions
+    #include "include/fixedInlet"
+
+    outlet
+    {
+        type            inletOutlet;
+        inletValue      $internalField;
+        value           $internalField;
+    }
+
+    lowerWall
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+
+    motorBikeGroup
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+
+    #include "include/frontBackUpperPatches"
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/nuaTilda b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/nuaTilda
new file mode 100644
index 0000000000000000000000000000000000000000..7bdade62d456e8da84eea840cb7020528d8f7c4e
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/nuaTilda
@@ -0,0 +1,54 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nuTilda;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [0 0 -1 0 0 0 0];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    #includeEtc "caseDicts/setConstraintTypes"
+
+    inlet
+    {
+        type            adjointInletNuaTilda;
+        value           uniform 0;
+    }
+
+    outlet
+    {
+        type            adjointOutletNuaTilda;
+        value           uniform 0;
+    }
+
+    lowerWall
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+
+    motorBikeGroup
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+
+    #include "include/frontBackUpperPatches"
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/nut b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/nut
new file mode 100644
index 0000000000000000000000000000000000000000..8cfb22c2ab10d5e16110bf5f2cc6f1d0f844e8a7
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/nut
@@ -0,0 +1,64 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nut;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [0 2 -1 0 0 0 0];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    #includeEtc "caseDicts/setConstraintTypes"
+
+    frontAndBack
+    {
+        type            calculated;
+        value           uniform 0;
+    }
+
+    inlet
+    {
+        type            calculated;
+        value           uniform 0;
+    }
+
+    outlet
+    {
+        type            calculated;
+        value           uniform 0;
+    }
+
+    lowerWall
+    {
+        type            nutUSpaldingWallFunction;
+        value           uniform 0;
+    }
+
+    upperWall
+    {
+        type            calculated;
+        value           uniform 0;
+    }
+
+    motorBikeGroup
+    {
+        type            nutUSpaldingWallFunction;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/p b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/p
new file mode 100644
index 0000000000000000000000000000000000000000..775ca225ab24cec5974fb06955a466a608a6ec53
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/p
@@ -0,0 +1,51 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    object      p;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include        "include/initialConditions"
+
+dimensions      [0 2 -2 0 0 0 0];
+
+internalField   uniform $pressure;
+
+boundaryField
+{
+    #includeEtc "caseDicts/setConstraintTypes"
+
+    inlet
+    {
+        type            zeroGradient;
+    }
+
+    outlet
+    {
+        type            fixedValue;
+        value           $internalField;
+    }
+
+    lowerWall
+    {
+        type            zeroGradient;
+    }
+
+    motorBikeGroup
+    {
+        type            zeroGradient;
+    }
+
+    #include "include/frontBackUpperPatches"
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/pa b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/pa
new file mode 100644
index 0000000000000000000000000000000000000000..a4496d334a25d353d223bad18821a2e2088289f1
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/0.orig/pa
@@ -0,0 +1,51 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    object      pa;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include        "include/initialConditions"
+
+dimensions      [0 2 -2 0 0 0 0];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    #includeEtc "caseDicts/setConstraintTypes"
+
+    inlet
+    {
+        type            zeroGradient;
+    }
+
+    outlet
+    {
+        type            adjointFarFieldPressure;
+        value           $internalField;
+    }
+
+    lowerWall
+    {
+        type            zeroGradient;
+    }
+
+    motorBikeGroup
+    {
+        type            zeroGradient;
+    }
+
+    #include "include/frontBackUpperPatches"
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/Allclean b/tutorials/incompressible/adjointOptimisationFoam/motorBike/Allclean
new file mode 100755
index 0000000000000000000000000000000000000000..a0bb1b4d393264805bc967260a37c840225fc70e
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/Allclean
@@ -0,0 +1,12 @@
+#!/bin/sh
+cd ${0%/*} || exit 1                        # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/CleanFunctions  # Tutorial clean functions
+
+cleanCase0
+
+# Remove surface and features
+rm -f constant/triSurface/motorBike.obj.gz > /dev/null 2>&1
+rm -f constant/triSurface/motorBike.eMesh  > /dev/null 2>&1
+rm -rf constant/extendedFeatureEdgeMesh    > /dev/null 2>&1
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/Allrun b/tutorials/incompressible/adjointOptimisationFoam/motorBike/Allrun
new file mode 100755
index 0000000000000000000000000000000000000000..03610ff0df920bd13625a58ae52f4e94f7a36c83
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/Allrun
@@ -0,0 +1,43 @@
+#!/bin/sh
+cd ${0%/*} || exit 1                        # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/RunFunctions    # Tutorial run functions
+
+# Alternative decomposeParDict name:
+decompDict="-decomposeParDict system/decomposeParDict.20"
+## Standard decomposeParDict name:
+# unset decompDict
+
+# copy motorbike surface from resources directory
+\cp $FOAM_TUTORIALS/resources/geometry/motorBike.obj.gz constant/triSurface/
+runApplication surfaceFeatureExtract
+
+runApplication blockMesh
+
+runApplication $decompDict decomposePar
+
+# Using distributedTriSurfaceMesh?
+if foamDictionary -entry geometry -value system/snappyHexMeshDict | \
+   grep -q distributedTriSurfaceMesh
+then
+    echo "surfaceRedistributePar does not need to be run anymore"
+    echo " - distributedTriSurfaceMesh will do on-the-fly redistribution"
+fi
+
+runParallel $decompDict snappyHexMesh -overwrite
+
+#- For non-parallel running: - set the initial fields
+# restore0Dir
+
+#- For parallel running: set the initial fields
+restore0Dir -processor
+
+runParallel $decompDict patchSummary
+runParallel $decompDict potentialFoam
+runParallel $decompDict checkMesh -writeFields '(nonOrthoAngle)' -constant
+
+runParallel $decompDict $(getApplication)
+
+runApplication reconstructParMesh -constant
+runApplication reconstructPar -latestTime
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/README b/tutorials/incompressible/adjointOptimisationFoam/motorBike/README
new file mode 100644
index 0000000000000000000000000000000000000000..dc20c303c8ad71b56729ba09a119dab7387ebe07
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/README
@@ -0,0 +1,9 @@
+1) When we expect a high oscillation of the flow residuals and, especially,
+of the objective value, it is recommended to use averaging (see corresponding
+dict in the primal solver setup). Even with this engineering trick, optimisation
+in cases involving practically unsteady of highly oscillating flows, using
+steady-state adjoint solutions should be used with caution.
+
+2) The adjoint equations, with the current setup, have an almost monotonic
+convergence. Hence, no averaging is needed since the last time-step will be the
+more converged one.
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/constant/adjointRASProperties b/tutorials/incompressible/adjointOptimisationFoam/motorBike/constant/adjointRASProperties
new file mode 100644
index 0000000000000000000000000000000000000000..1f97c4e2802b5a8a523ffcc406e885757c7a3ce3
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/constant/adjointRASProperties
@@ -0,0 +1,31 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      RASProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+adjointRASModel   adjointSpalartAllmaras;
+
+adjointSpalartAllmarasCoeffs
+{
+    nSmooth           0;
+    zeroATCPatchTypes (wall patch);
+    maskType          pointCells;
+}
+
+adjointTurbulence on;
+
+printCoeffs       off;
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/constant/transportProperties b/tutorials/incompressible/adjointOptimisationFoam/motorBike/constant/transportProperties
new file mode 100644
index 0000000000000000000000000000000000000000..171f00e1151bb426d915d4736527e406d90a0387
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/constant/transportProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      transportProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+transportModel  Newtonian;
+
+nu              1.5e-05;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/constant/triSurface/README b/tutorials/incompressible/adjointOptimisationFoam/motorBike/constant/triSurface/README
new file mode 100644
index 0000000000000000000000000000000000000000..de3f29cc01268a637d915dc6d9b8fb98400e9906
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/constant/triSurface/README
@@ -0,0 +1,4 @@
+Directory to house tri-surfaces
+
+The Allrun script copies the surface from the $FOAM_TUTORIALS/resources/geometry
+directory
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/constant/turbulenceProperties b/tutorials/incompressible/adjointOptimisationFoam/motorBike/constant/turbulenceProperties
new file mode 100644
index 0000000000000000000000000000000000000000..91c7c930b688a1a628b8ec01740ca0059fd2a88a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/constant/turbulenceProperties
@@ -0,0 +1,28 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      turbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+simulationType RAS;
+
+RAS
+{
+    RASModel            SpalartAllmaras;
+
+    turbulence          on;
+
+    printCoeffs         on;
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/blockMeshDict b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/blockMeshDict
new file mode 100644
index 0000000000000000000000000000000000000000..16836626e506bc94a4aaf1b29302bd0f44a55bc0
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/blockMeshDict
@@ -0,0 +1,86 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      blockMeshDict;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+scale   1;
+
+vertices
+(
+    (-5 -4 0)
+    (15 -4 0)
+    (15  4 0)
+    (-5  4 0)
+    (-5 -4 8)
+    (15 -4 8)
+    (15  4 8)
+    (-5  4 8)
+);
+
+blocks
+(
+    hex (0 1 2 3 4 5 6 7) (20 8 8) simpleGrading (1 1 1)
+);
+
+edges
+(
+);
+
+boundary
+(
+    frontAndBack
+    {
+        type patch;
+        faces
+        (
+            (3 7 6 2)
+            (1 5 4 0)
+        );
+    }
+    inlet
+    {
+        type patch;
+        faces
+        (
+            (0 4 7 3)
+        );
+    }
+    outlet
+    {
+        type patch;
+        faces
+        (
+            (2 6 5 1)
+        );
+    }
+    lowerWall
+    {
+        type wall;
+        faces
+        (
+            (0 3 2 1)
+        );
+    }
+    upperWall
+    {
+        type patch;
+        faces
+        (
+            (4 5 6 7)
+        );
+    }
+);
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/controlDict b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/controlDict
new file mode 100644
index 0000000000000000000000000000000000000000..7eeca23a259200bd402291492082b95d62c810f0
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/controlDict
@@ -0,0 +1,48 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      controlDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+application     adjointOptimisationFoam;
+
+startFrom       latestTime;
+
+startTime       0;
+
+stopAt          endTime;
+
+endTime         2000;
+
+deltaT          1;
+
+writeControl    timeStep;
+
+writeInterval   1000;
+
+purgeWrite      1;
+
+writeFormat     binary;
+
+writePrecision  6;
+
+writeCompression off;
+
+timeFormat      general;
+
+timePrecision   6;
+
+runTimeModifiable true;
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/decomposeParDict.20 b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/decomposeParDict.20
new file mode 100644
index 0000000000000000000000000000000000000000..0f8da85a11210b21976daba6b534cf5e6be73153
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/decomposeParDict.20
@@ -0,0 +1,27 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      decomposeParDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+numberOfSubdomains 20;
+
+method          hierarchical;
+// method          ptscotch;
+
+coeffs
+{
+    n           (5 2 2);
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/fvSchemes b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/fvSchemes
new file mode 100644
index 0000000000000000000000000000000000000000..8b8c8aedd573b36b13dc020c520372c21b4f0e2a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/fvSchemes
@@ -0,0 +1,72 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSchemes;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ddtSchemes
+{
+    default         steadyState;
+}
+
+gradSchemes
+{
+    default         Gauss linear;
+    grad(U)         cellLimited Gauss linear 1;
+    grad(nuTilda)   cellLimited Gauss linear 1;
+    gradDConv       cellLimited Gauss linear 1;
+    gradDaConv      cellLimited Gauss linear 1;
+    gradUATC        cellLimited Gauss linear 1;
+}
+
+divSchemes
+{
+    default                 Gauss linear;
+    div(phi,U)              bounded Gauss linearUpwindV grad(U);
+    div(phi,nuTilda)        bounded Gauss upwind;
+    div(yPhi,yWall)                 Gauss linearUpwind gradDConv;
+
+    div(-phiMean,Ua)        bounded Gauss upwind;
+    div(-phiMean,nuaTilda)  bounded Gauss upwind;
+    div(-yPhi,da)                   Gauss upwind;
+}
+
+laplacianSchemes
+{
+    default         Gauss linear limited 0.333;
+}
+
+interpolationSchemes
+{
+    default         linear;
+}
+
+snGradSchemes
+{
+    default         limited 0.333;
+}
+
+wallDist
+{
+    method advectionDiffusion;
+    advectionDiffusionCoeffs
+    {
+        method    meshWave;
+        tolerance 1.e-5;
+        maxIter   1000;
+        epsilon   0.1;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/fvSolution b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/fvSolution
new file mode 100644
index 0000000000000000000000000000000000000000..a9ffdcc4833cd7ebdfe380678054307ffe4451e9
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/fvSolution
@@ -0,0 +1,78 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSolution;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+solvers
+{
+    "p|pa"
+    {
+        solver          GAMG;
+        smoother        GaussSeidel;
+        tolerance       1e-7;
+        relTol          0.01;
+    }
+
+    ma
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+
+    Phi
+    {
+        $p;
+    }
+
+    "U|Ua|nuTilda|nuaTilda|yWall|da"
+    {
+        solver          smoothSolver;
+        smoother        GaussSeidel;
+        tolerance       1e-8;
+        relTol          0.1;
+        nSweeps         1;
+    }
+}
+
+potentialFlow
+{
+    nNonOrthogonalCorrectors 10;
+}
+
+relaxationFactors
+{
+    fields
+    {
+        "p.*"    0.3;
+        "pa.*"   0.7;
+    }
+    equations
+    {
+        U         0.7;
+        Ua        0.3;
+        nuTilda   0.7;
+        nuaTilda  0.02;
+        yWall     0.7;
+        da        0.5;
+    }
+}
+
+cache
+{
+    grad(U);
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/meshQualityDict b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/meshQualityDict
new file mode 100644
index 0000000000000000000000000000000000000000..fb33ff9fec97a8f88c719616bef884bf28ca5827
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/meshQualityDict
@@ -0,0 +1,24 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      meshQualityDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Include defaults parameters from master dictionary
+#includeEtc "caseDicts/meshQualityDict"
+
+//- minFaceWeight (0 -> 0.5)
+minFaceWeight 0.02;
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/optimisationDict
new file mode 100644
index 0000000000000000000000000000000000000000..c5bfcd1c9eca1d75a7351d3e3aad5be361746214
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/optimisationDict
@@ -0,0 +1,123 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      optimisationDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+optimisationManager singleRun;
+
+primalSolvers
+{
+    op1
+    {
+        active                 true;
+        type                   incompressible;
+        solver                 simple;
+
+        solutionControls
+        {
+            consistent yes;
+            nIters 1000;
+            residualControl
+            {
+                "p.*"       1.e-5;
+                "U.*"       1.e-5;
+            }
+            averaging
+            {
+                average     true;
+                startIter   500;
+            }
+        }
+    }
+}
+
+adjointManagers
+{
+    adjManager1
+    {
+        primalSolver             op1;
+        adjointSolvers
+        {
+            adjS1
+            {
+                // choose adjoint solver
+                //----------------------
+                active                 true;
+                type                   incompressible;
+                solver                 adjointSimple;
+
+                // manage objectives
+                //------------------
+                objectives
+                {
+                    type incompressible;
+                    objectiveNames
+                    {
+                        drag
+                        {
+                            weight     1.;
+                            type       force;
+                            patches    ("motorBike.*");
+                            direction  (1 0 0);
+                            Aref       0.75;
+                            rhoInf     1;
+                            UInf       20;
+                        }
+                    }
+                }
+                // ATC treatment
+                //--------------
+                ATCModel
+                {
+                    ATCModel          standard;
+                    extraConvection   0;
+                    nSmooth           0;
+                    zeroATCPatchTypes (wall patch);
+                    maskType          pointCells;
+                }
+                // solution control
+                //------------------
+                solutionControls
+                {
+                    consistent yes;
+                    nIters 1000;
+                    residualControl
+                    {
+                        "pa.*"       1.e-5;
+                        "Ua.*"       1.e-5;
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+optimisation
+{
+    sensitivities
+    {
+        type               surfacePoints;
+        patches            (motorBikeGroup);
+        includeSurfaceArea false;
+        adjointEikonalSolver
+        {
+            tolerance 1.e-5;
+            iters     1000;
+            epsilon   0.1;
+        }
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/snappyHexMeshDict b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/snappyHexMeshDict
new file mode 100644
index 0000000000000000000000000000000000000000..ea41f243933b522037e1544ae6e0321d0645e400
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/snappyHexMeshDict
@@ -0,0 +1,326 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      snappyHexMeshDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Which of the steps to run
+castellatedMesh true;
+snap            true;
+addLayers       true;
+
+
+// Geometry. Definition of all surfaces. All surfaces are of class
+// searchableSurface.
+// Surfaces are used
+// - to specify refinement for any mesh cell intersecting it
+// - to specify refinement for any mesh cell inside/outside/near
+// - to 'snap' the mesh boundary to the surface
+geometry
+{
+    motorBike.obj
+    {
+        type triSurfaceMesh;
+        name motorBike;
+    }
+
+    refinementBox
+    {
+        type box;
+        min  (-1.0 -0.7 0.0);
+        max  ( 8.0  0.7 2.5);
+    }
+}
+
+
+// Settings for the castellatedMesh generation.
+castellatedMeshControls
+{
+
+    // Refinement parameters
+    // ~~~~~~~~~~~~~~~~~~~~~
+
+    // If local number of cells is >= maxLocalCells on any processor
+    // switches from from refinement followed by balancing
+    // (current method) to (weighted) balancing before refinement.
+    maxLocalCells 100000;
+
+    // Overall cell limit (approximately). Refinement will stop immediately
+    // upon reaching this number so a refinement level might not complete.
+    // Note that this is the number of cells before removing the part which
+    // is not 'visible' from the keepPoint. The final number of cells might
+    // actually be a lot less.
+    maxGlobalCells 2000000;
+
+    // The surface refinement loop might spend lots of iterations refining just a
+    // few cells. This setting will cause refinement to stop if <= minimumRefine
+    // are selected for refinement. Note: it will at least do one iteration
+    // (unless the number of cells to refine is 0)
+    minRefinementCells 10;
+
+    // Allow a certain level of imbalance during refining
+    // (since balancing is quite expensive)
+    // Expressed as fraction of perfect balance (= overall number of cells /
+    // nProcs). 0=balance always.
+    maxLoadUnbalance 0.10;
+
+
+    // Number of buffer layers between different levels.
+    // 1 means normal 2:1 refinement restriction, larger means slower
+    // refinement.
+    nCellsBetweenLevels 3;
+
+
+
+    // Explicit feature edge refinement
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    // Specifies a level for any cell intersected by its edges.
+    // This is a featureEdgeMesh, read from constant/triSurface for now.
+    features
+    (
+        {
+            file "motorBike.eMesh";
+            level 7;
+        }
+    );
+
+
+
+    // Surface based refinement
+    // ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    // Specifies two levels for every surface. The first is the minimum level,
+    // every cell intersecting a surface gets refined up to the minimum level.
+    // The second level is the maximum level. Cells that 'see' multiple
+    // intersections where the intersections make an
+    // angle > resolveFeatureAngle get refined up to the maximum level.
+
+    refinementSurfaces
+    {
+        motorBike
+        {
+            // Surface-wise min and max refinement level
+            level (7 7);
+
+            // Optional specification of patch type (default is wall). No
+            // constraint types (cyclic, symmetry) etc. are allowed.
+            patchInfo
+            {
+                type wall;
+                inGroups (motorBikeGroup);
+            }
+        }
+    }
+
+    // Resolve sharp angles
+    resolveFeatureAngle 30;
+
+
+    // Region-wise refinement
+    // ~~~~~~~~~~~~~~~~~~~~~~
+
+    // Specifies refinement level for cells in relation to a surface. One of
+    // three modes
+    // - distance. 'levels' specifies per distance to the surface the
+    //   wanted refinement level. The distances need to be specified in
+    //   descending order.
+    // - inside. 'levels' is only one entry and only the level is used. All
+    //   cells inside the surface get refined up to the level. The surface
+    //   needs to be closed for this to be possible.
+    // - outside. Same but cells outside.
+
+    refinementRegions
+    {
+        refinementBox
+        {
+            mode inside;
+            levels ((1E15 4));
+        }
+    }
+
+
+    // Mesh selection
+    // ~~~~~~~~~~~~~~
+
+    // After refinement patches get added for all refinementSurfaces and
+    // all cells intersecting the surfaces get put into these patches. The
+    // section reachable from the locationInMesh is kept.
+    // NOTE: This point should never be on a face, always inside a cell, even
+    // after refinement.
+    locationInMesh (3.0001 3.0001 0.43);
+
+
+    // Whether any faceZones (as specified in the refinementSurfaces)
+    // are only on the boundary of corresponding cellZones or also allow
+    // free-standing zone faces. Not used if there are no faceZones.
+    allowFreeStandingZoneFaces true;
+}
+
+
+
+// Settings for the snapping.
+snapControls
+{
+    //- Number of patch smoothing iterations before finding correspondence
+    //  to surface
+    nSmoothPatch 3;
+
+    //- Relative distance for points to be attracted by surface feature point
+    //  or edge. True distance is this factor times local
+    //  maximum edge length.
+    tolerance 2.0;
+
+    //- Number of mesh displacement relaxation iterations.
+    nSolveIter 30;
+
+    //- Maximum number of snapping relaxation iterations. Should stop
+    //  before upon reaching a correct mesh.
+    nRelaxIter 5;
+
+    // Feature snapping
+
+        //- Number of feature edge snapping iterations.
+        //  Leave out altogether to disable.
+        nFeatureSnapIter 10;
+
+        //- Detect (geometric only) features by sampling the surface
+        //  (default=false).
+        implicitFeatureSnap false;
+
+        //- Use castellatedMeshControls::features (default = true)
+        explicitFeatureSnap true;
+
+        //- Detect points on multiple surfaces (only for explicitFeatureSnap)
+        multiRegionFeatureSnap false;
+}
+
+
+
+// Settings for the layer addition.
+addLayersControls
+{
+    // Are the thickness parameters below relative to the undistorted
+    // size of the refined cell outside layer (true) or absolute sizes (false).
+    relativeSizes true;
+
+    // Per final patch (so not geometry!) the layer information
+    layers
+    {
+        "(lowerWall|motorBike).*"
+        {
+            nSurfaceLayers 1;
+        }
+    }
+
+    // Expansion factor for layer mesh
+    expansionRatio 1.0;
+
+    // Wanted thickness of final added cell layer. If multiple layers
+    // is the thickness of the layer furthest away from the wall.
+    // Relative to undistorted size of cell outside layer.
+    // See relativeSizes parameter.
+    finalLayerThickness 0.3;
+
+    // Minimum thickness of cell layer. If for any reason layer
+    // cannot be above minThickness do not add layer.
+    // Relative to undistorted size of cell outside layer.
+    minThickness 0.1;
+
+    // If points get not extruded do nGrow layers of connected faces that are
+    // also not grown. This helps convergence of the layer addition process
+    // close to features.
+    // Note: changed(corrected) w.r.t 1.7.x! (didn't do anything in 1.7.x)
+    nGrow 0;
+
+    // Advanced settings
+
+    // When not to extrude surface. 0 is flat surface, 90 is when two faces
+    // are perpendicular
+    featureAngle 60;
+
+    // At non-patched sides allow mesh to slip if extrusion direction makes
+    // angle larger than slipFeatureAngle.
+    slipFeatureAngle 30;
+
+    // Maximum number of snapping relaxation iterations. Should stop
+    // before upon reaching a correct mesh.
+    nRelaxIter 3;
+
+    // Number of smoothing iterations of surface normals
+    nSmoothSurfaceNormals 1;
+
+    // Number of smoothing iterations of interior mesh movement direction
+    nSmoothNormals 3;
+
+    // Smooth layer thickness over surface patches
+    nSmoothThickness 10;
+
+    // Stop layer growth on highly warped cells
+    maxFaceThicknessRatio 0.5;
+
+    // Reduce layer growth where ratio thickness to medial
+    // distance is large
+    maxThicknessToMedialRatio 0.3;
+
+    // Angle used to pick up medial axis points
+    // Note: changed(corrected) w.r.t 1.7.x! 90 degrees corresponds to 130
+    // in 1.7.x.
+    minMedialAxisAngle 90;
+
+
+    // Create buffer region for new layer terminations
+    nBufferCellsNoExtrude 0;
+
+
+    // Overall max number of layer addition iterations. The mesher will exit
+    // if it reaches this number of iterations; possibly with an illegal
+    // mesh.
+    nLayerIter 50;
+}
+
+
+
+// Generic mesh quality settings. At any undoable phase these determine
+// where to undo.
+meshQualityControls
+{
+    #include "meshQualityDict"
+
+
+    // Advanced
+
+    //- Number of error distribution iterations
+    nSmoothScale 4;
+    //- Amount to scale back displacement at error points
+    errorReduction 0.75;
+}
+
+
+// Advanced
+
+// Write flags
+writeFlags
+(
+    scalarLevels
+    layerSets
+    layerFields     // write volScalarField for layer coverage
+);
+
+
+// Merge tolerance. Is fraction of overall bounding box of initial mesh.
+// Note: the write tolerance needs to be higher than this.
+mergeTolerance 1e-6;
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/surfaceFeatureExtractDict b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/surfaceFeatureExtractDict
new file mode 100644
index 0000000000000000000000000000000000000000..14878b7b999e6c2f6b9ef7ef94dc97cceb695427
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/motorBike/system/surfaceFeatureExtractDict
@@ -0,0 +1,45 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      surfaceFeatureExtractDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+motorBike.obj
+{
+    // How to obtain raw features (extractFromFile || extractFromSurface)
+    extractionMethod    extractFromSurface;
+
+    // Mark edges whose adjacent surface normals are at an angle less
+    // than includedAngle as features
+    // - 0  : selects no edges
+    // - 180: selects all edges
+    includedAngle       150;
+
+    subsetFeatures
+    {
+        // Keep nonManifold edges (edges with >2 connected faces)
+        nonManifoldEdges       no;
+
+        // Keep open edges (edges with 1 connected face)
+        openEdges       yes;
+    }
+
+
+    // Write options
+
+    // Write features to obj format for postprocessing
+    writeObj            yes;
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/0/U b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/0/U
new file mode 100644
index 0000000000000000000000000000000000000000..1efd524707a474bf79d29ef339c3c1ff7f7a97e6
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/0/U
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      U;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 5.996344962 0.20939698 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    pressure
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    inlet
+    {
+        type            freestream;
+        freestreamValue uniform ( 5.996344962 0.20939698 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/0/Ua b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/0/Ua
new file mode 100644
index 0000000000000000000000000000000000000000..4b051627e21873de58e613b1d89a205858718367
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/0/Ua
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      Ua;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 0 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    pressure
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    inlet
+    {
+        type            adjointFarFieldVelocity;
+        value           uniform ( 0 0 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/0/p b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/0/p
new file mode 100644
index 0000000000000000000000000000000000000000..f5f1bff84bda9596ef6b7cbf92eeb3bc800ab62a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/0/p
@@ -0,0 +1,45 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      p;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            zeroGradient;
+    }
+    pressure
+    {
+        type            zeroGradient;
+    }
+    inlet
+    {
+        type            outletInlet;
+        outletValue     uniform 0;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/0/pa b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/0/pa
new file mode 100644
index 0000000000000000000000000000000000000000..62aab96355507f0538c59596550650093eebd30e
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/0/pa
@@ -0,0 +1,44 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      pa;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            zeroGradient;
+    }
+    pressure
+    {
+        type            zeroGradient;
+    }
+    inlet
+    {
+        type            adjointFarFieldPressure;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/Allclean b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/Allclean
new file mode 100755
index 0000000000000000000000000000000000000000..289939fbe9f20ab28316b31fe66c0c23743b7d8a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/Allclean
@@ -0,0 +1,7 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/CleanFunctions  # Tutorial clean functions
+
+cleanCase
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/Allrun b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/Allrun
new file mode 100755
index 0000000000000000000000000000000000000000..ce49e97d662a01541794ce9102920478efb327be
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/Allrun
@@ -0,0 +1,11 @@
+#!/bin/sh
+cd ${0%/*} || exit 1                        # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/RunFunctions    # Tutorial run functions
+
+resourcesDir=$FOAM_TUTORIALS/incompressible/adjointOptimisationFoam/resources
+
+\cp -r $resourcesDir/meshes/naca0012/polyMesh constant
+runApplication decomposePar
+runParallel $(getApplication)
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/constant/adjointRASProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/constant/adjointRASProperties
new file mode 100644
index 0000000000000000000000000000000000000000..48724552a35189947602192d0ed61d67ad4aa44c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/constant/adjointRASProperties
@@ -0,0 +1,24 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      RASProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+adjointRASModel   adjointLaminar;
+
+adjointTurbulence on;
+
+printCoeffs       off;
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/constant/transportProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/constant/transportProperties
new file mode 100644
index 0000000000000000000000000000000000000000..9020a89270c3333a6e8f50af90e518f8d5f91ed7
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/constant/transportProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      transportProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+transportModel  Newtonian;
+
+nu              nu [ 0 2 -1 0 0 0 0 ] 6.e-03;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/constant/turbulenceProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/constant/turbulenceProperties
new file mode 100644
index 0000000000000000000000000000000000000000..2458cef5935e9832af85e09d41736be3e34b363e
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/constant/turbulenceProperties
@@ -0,0 +1,19 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      turbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+simulationType  laminar;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/controlDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/controlDict
new file mode 100644
index 0000000000000000000000000000000000000000..174e9185e2ca2a7f054755c65146a7be2a31cf11
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/controlDict
@@ -0,0 +1,47 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      controlDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+application     adjointOptimisationFoam;
+
+startFrom       latestTime;
+
+startTime       0;
+
+stopAt          endTime;
+
+endTime         6000;
+
+deltaT          1;
+
+writeControl    timeStep;
+
+writeInterval   1000;
+
+purgeWrite      1;
+
+writeFormat     ascii;
+
+writePrecision  16;
+
+writeCompression true;
+
+timeFormat      general;
+
+timePrecision   6;
+
+runTimeModifiable yes;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/decomposeParDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/decomposeParDict
new file mode 100644
index 0000000000000000000000000000000000000000..6d7021f19d5121a9aab584ca76b5c76e3425cd92
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/decomposeParDict
@@ -0,0 +1,26 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      decomposeParDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+numberOfSubdomains 4;
+
+method          hierarchical;
+
+coeffs
+{
+    n               (2 2 1);
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/fvSchemes b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/fvSchemes
new file mode 100644
index 0000000000000000000000000000000000000000..f09f81fb1527b5b0d7a9ae6c2d2c6a9eb20252a0
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/fvSchemes
@@ -0,0 +1,51 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSchemes;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ddtSchemes
+{
+    default         steadyState;
+}
+
+gradSchemes
+{
+    default          Gauss linear;
+    gradUConv        cellLimited Gauss linear 0.5;
+}
+
+divSchemes
+{
+    default                 Gauss linear;
+    div(phi,U)      bounded Gauss linearUpwind gradUConv;
+    div(-phi,Ua)    bounded Gauss linearUpwind gradUaConv;
+}
+
+laplacianSchemes
+{
+    default         Gauss linear corrected;
+}
+
+interpolationSchemes
+{
+    default         linear;
+}
+
+snGradSchemes
+{
+    default         corrected;
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/fvSolution b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/fvSolution
new file mode 100644
index 0000000000000000000000000000000000000000..472ba3b769180bfe125cabc9f608a98de4b695be
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/fvSolution
@@ -0,0 +1,61 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSolution;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+SIMPLE
+{
+    nNonOrthogonalCorrectors 0;
+}
+
+solvers
+{
+    "p.*|pa.*"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "m|ma"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "U.*|Ua.*"
+    {
+        solver           PBiCGStab;
+        preconditioner   DILU;
+        tolerance        1e-9;
+        relTol           0.1;
+    }
+}
+
+relaxationFactors
+{
+    fields
+    {
+        "p.*"    0.3;
+        "pa.*"   0.3;
+    }
+    equations
+    {
+        "U.*"    0.7;
+        "Ua.*"   0.7;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/optimisationDict
new file mode 100644
index 0000000000000000000000000000000000000000..3c95d2489903cae33a0420311054050b1f9ed336
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/drag/system/optimisationDict
@@ -0,0 +1,105 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      optimisationDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+optimisationManager    singleRun;
+
+primalSolvers
+{
+    op1
+    {
+        active                 true;
+        type                   incompressible;
+        solver                 simple;
+        solutionControls
+        {
+            nIters 3000;
+            residualControl
+            {
+                "p.*"       1.e-7;
+                "U.*"       1.e-7;
+            }
+        }
+    }
+}
+
+adjointManagers
+{
+    adjManager1
+    {
+        primalSolver             op1;
+        adjointSolvers
+        {
+            adjS1
+            {
+                // choose adjoint solver
+                //----------------------
+                active                 true;
+                type                   incompressible;
+                solver                 adjointSimple;
+
+                // manage objectives
+                //------------------
+                objectives
+                {
+                    type               incompressible;
+                    objectiveNames
+                    {
+                        drag
+                        {
+                            weight          1.;
+                            type            force;
+                            patches         (pressure suction);
+                            direction       (0.9993908270189999 0.034899496703 0);
+                            Aref            2.;
+                            rhoInf          1.225;
+                            UInf            1;
+                        }
+                    }
+                }
+
+                // ATC treatment
+                //--------------
+                ATCModel
+                {
+                    ATCModel        standard;
+                }
+
+                // solution control
+                //------------------
+                solutionControls
+                {
+                    nIters 3000;
+                    residualControl
+                    {
+                        "pa.*"       1.e-7;
+                        "Ua.*"       1.e-7;
+                    }
+                }
+            }
+        }
+    }
+}
+
+optimisation
+{
+    sensitivities
+    {
+        type            surfacePoints;
+        patches         (pressure suction);
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/0/U b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/0/U
new file mode 100644
index 0000000000000000000000000000000000000000..1efd524707a474bf79d29ef339c3c1ff7f7a97e6
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/0/U
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      U;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 5.996344962 0.20939698 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    pressure
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    inlet
+    {
+        type            freestream;
+        freestreamValue uniform ( 5.996344962 0.20939698 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/0/Ua b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/0/Ua
new file mode 100644
index 0000000000000000000000000000000000000000..4b051627e21873de58e613b1d89a205858718367
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/0/Ua
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      Ua;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 0 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    pressure
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    inlet
+    {
+        type            adjointFarFieldVelocity;
+        value           uniform ( 0 0 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/0/p b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/0/p
new file mode 100644
index 0000000000000000000000000000000000000000..f5f1bff84bda9596ef6b7cbf92eeb3bc800ab62a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/0/p
@@ -0,0 +1,45 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      p;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            zeroGradient;
+    }
+    pressure
+    {
+        type            zeroGradient;
+    }
+    inlet
+    {
+        type            outletInlet;
+        outletValue     uniform 0;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/0/pa b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/0/pa
new file mode 100644
index 0000000000000000000000000000000000000000..62aab96355507f0538c59596550650093eebd30e
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/0/pa
@@ -0,0 +1,44 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      pa;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            zeroGradient;
+    }
+    pressure
+    {
+        type            zeroGradient;
+    }
+    inlet
+    {
+        type            adjointFarFieldPressure;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/Allclean b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/Allclean
new file mode 100755
index 0000000000000000000000000000000000000000..289939fbe9f20ab28316b31fe66c0c23743b7d8a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/Allclean
@@ -0,0 +1,7 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/CleanFunctions  # Tutorial clean functions
+
+cleanCase
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/Allrun b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/Allrun
new file mode 100755
index 0000000000000000000000000000000000000000..ce49e97d662a01541794ce9102920478efb327be
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/Allrun
@@ -0,0 +1,11 @@
+#!/bin/sh
+cd ${0%/*} || exit 1                        # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/RunFunctions    # Tutorial run functions
+
+resourcesDir=$FOAM_TUTORIALS/incompressible/adjointOptimisationFoam/resources
+
+\cp -r $resourcesDir/meshes/naca0012/polyMesh constant
+runApplication decomposePar
+runParallel $(getApplication)
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/constant/adjointRASProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/constant/adjointRASProperties
new file mode 100644
index 0000000000000000000000000000000000000000..48724552a35189947602192d0ed61d67ad4aa44c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/constant/adjointRASProperties
@@ -0,0 +1,24 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      RASProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+adjointRASModel   adjointLaminar;
+
+adjointTurbulence on;
+
+printCoeffs       off;
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/constant/transportProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/constant/transportProperties
new file mode 100644
index 0000000000000000000000000000000000000000..9020a89270c3333a6e8f50af90e518f8d5f91ed7
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/constant/transportProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      transportProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+transportModel  Newtonian;
+
+nu              nu [ 0 2 -1 0 0 0 0 ] 6.e-03;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/constant/turbulenceProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/constant/turbulenceProperties
new file mode 100644
index 0000000000000000000000000000000000000000..2458cef5935e9832af85e09d41736be3e34b363e
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/constant/turbulenceProperties
@@ -0,0 +1,19 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      turbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+simulationType  laminar;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/controlDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/controlDict
new file mode 100644
index 0000000000000000000000000000000000000000..174e9185e2ca2a7f054755c65146a7be2a31cf11
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/controlDict
@@ -0,0 +1,47 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      controlDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+application     adjointOptimisationFoam;
+
+startFrom       latestTime;
+
+startTime       0;
+
+stopAt          endTime;
+
+endTime         6000;
+
+deltaT          1;
+
+writeControl    timeStep;
+
+writeInterval   1000;
+
+purgeWrite      1;
+
+writeFormat     ascii;
+
+writePrecision  16;
+
+writeCompression true;
+
+timeFormat      general;
+
+timePrecision   6;
+
+runTimeModifiable yes;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/decomposeParDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/decomposeParDict
new file mode 100644
index 0000000000000000000000000000000000000000..6d7021f19d5121a9aab584ca76b5c76e3425cd92
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/decomposeParDict
@@ -0,0 +1,26 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      decomposeParDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+numberOfSubdomains 4;
+
+method          hierarchical;
+
+coeffs
+{
+    n               (2 2 1);
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/fvSchemes b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/fvSchemes
new file mode 100644
index 0000000000000000000000000000000000000000..f09f81fb1527b5b0d7a9ae6c2d2c6a9eb20252a0
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/fvSchemes
@@ -0,0 +1,51 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSchemes;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ddtSchemes
+{
+    default         steadyState;
+}
+
+gradSchemes
+{
+    default          Gauss linear;
+    gradUConv        cellLimited Gauss linear 0.5;
+}
+
+divSchemes
+{
+    default                 Gauss linear;
+    div(phi,U)      bounded Gauss linearUpwind gradUConv;
+    div(-phi,Ua)    bounded Gauss linearUpwind gradUaConv;
+}
+
+laplacianSchemes
+{
+    default         Gauss linear corrected;
+}
+
+interpolationSchemes
+{
+    default         linear;
+}
+
+snGradSchemes
+{
+    default         corrected;
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/fvSolution b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/fvSolution
new file mode 100644
index 0000000000000000000000000000000000000000..472ba3b769180bfe125cabc9f608a98de4b695be
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/fvSolution
@@ -0,0 +1,61 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSolution;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+SIMPLE
+{
+    nNonOrthogonalCorrectors 0;
+}
+
+solvers
+{
+    "p.*|pa.*"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "m|ma"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "U.*|Ua.*"
+    {
+        solver           PBiCGStab;
+        preconditioner   DILU;
+        tolerance        1e-9;
+        relTol           0.1;
+    }
+}
+
+relaxationFactors
+{
+    fields
+    {
+        "p.*"    0.3;
+        "pa.*"   0.3;
+    }
+    equations
+    {
+        "U.*"    0.7;
+        "Ua.*"   0.7;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/optimisationDict
new file mode 100644
index 0000000000000000000000000000000000000000..b01b7552334aaf1e0cf037fdcc15a5e23b335d6c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/lift/system/optimisationDict
@@ -0,0 +1,105 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      optimisationDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+optimisationManager    singleRun;
+
+primalSolvers
+{
+    op1
+    {
+        active                 true;
+        type                   incompressible;
+        solver                 simple;
+        solutionControls
+        {
+            nIters 3000;
+            residualControl
+            {
+                "p.*"       1.e-7;
+                "U.*"       1.e-7;
+            }
+        }
+    }
+}
+
+adjointManagers
+{
+    adjManager1
+    {
+        primalSolver             op1;
+        adjointSolvers
+        {
+            adjS1
+            {
+                // choose adjoint solver
+                //----------------------
+                active                 true;
+                type                   incompressible;
+                solver                 adjointSimple;
+
+                // manage objectives
+                //------------------
+                objectives
+                {
+                    type               incompressible;
+                    objectiveNames
+                    {
+                        lift
+                        {
+                            weight          1.;
+                            type            force;
+                            patches         (pressure suction);
+                            direction       (0.034899496703 -0.9993908270189999 0);
+                            Aref            2.;
+                            rhoInf          1.225;
+                            UInf            1;
+                        }
+                    }
+                }
+
+                // ATC treatment
+                //--------------
+                ATCModel
+                {
+                    ATCModel        standard;
+                }
+
+                // solution control
+                //------------------
+                solutionControls
+                {
+                    nIters 3000;
+                    residualControl
+                    {
+                        "pa.*"       1.e-7;
+                        "Ua.*"       1.e-7;
+                    }
+                }
+            }
+        }
+    }
+}
+
+optimisation
+{
+    sensitivities
+    {
+        type            surfacePoints;
+        patches         (pressure suction);
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/0/U b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/0/U
new file mode 100644
index 0000000000000000000000000000000000000000..1efd524707a474bf79d29ef339c3c1ff7f7a97e6
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/0/U
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      U;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 5.996344962 0.20939698 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    pressure
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    inlet
+    {
+        type            freestream;
+        freestreamValue uniform ( 5.996344962 0.20939698 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/0/Ua b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/0/Ua
new file mode 100644
index 0000000000000000000000000000000000000000..4b051627e21873de58e613b1d89a205858718367
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/0/Ua
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      Ua;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 0 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    pressure
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    inlet
+    {
+        type            adjointFarFieldVelocity;
+        value           uniform ( 0 0 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/0/p b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/0/p
new file mode 100644
index 0000000000000000000000000000000000000000..f5f1bff84bda9596ef6b7cbf92eeb3bc800ab62a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/0/p
@@ -0,0 +1,45 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      p;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            zeroGradient;
+    }
+    pressure
+    {
+        type            zeroGradient;
+    }
+    inlet
+    {
+        type            outletInlet;
+        outletValue     uniform 0;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/0/pa b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/0/pa
new file mode 100644
index 0000000000000000000000000000000000000000..62aab96355507f0538c59596550650093eebd30e
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/0/pa
@@ -0,0 +1,44 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      pa;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            zeroGradient;
+    }
+    pressure
+    {
+        type            zeroGradient;
+    }
+    inlet
+    {
+        type            adjointFarFieldPressure;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/Allclean b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/Allclean
new file mode 100755
index 0000000000000000000000000000000000000000..289939fbe9f20ab28316b31fe66c0c23743b7d8a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/Allclean
@@ -0,0 +1,7 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/CleanFunctions  # Tutorial clean functions
+
+cleanCase
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/Allrun b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/Allrun
new file mode 100755
index 0000000000000000000000000000000000000000..ce49e97d662a01541794ce9102920478efb327be
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/Allrun
@@ -0,0 +1,11 @@
+#!/bin/sh
+cd ${0%/*} || exit 1                        # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/RunFunctions    # Tutorial run functions
+
+resourcesDir=$FOAM_TUTORIALS/incompressible/adjointOptimisationFoam/resources
+
+\cp -r $resourcesDir/meshes/naca0012/polyMesh constant
+runApplication decomposePar
+runParallel $(getApplication)
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/constant/adjointRASProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/constant/adjointRASProperties
new file mode 100644
index 0000000000000000000000000000000000000000..c283c94cf3c573f97fc18efc21baa33649f1bfb6
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/constant/adjointRASProperties
@@ -0,0 +1,22 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      RASProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+adjointRASModel   adjointLaminar;
+
+adjointTurbulence on;
+
+printCoeffs       off;
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/constant/transportProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/constant/transportProperties
new file mode 100644
index 0000000000000000000000000000000000000000..9020a89270c3333a6e8f50af90e518f8d5f91ed7
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/constant/transportProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      transportProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+transportModel  Newtonian;
+
+nu              nu [ 0 2 -1 0 0 0 0 ] 6.e-03;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/constant/turbulenceProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/constant/turbulenceProperties
new file mode 100644
index 0000000000000000000000000000000000000000..2458cef5935e9832af85e09d41736be3e34b363e
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/constant/turbulenceProperties
@@ -0,0 +1,19 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      turbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+simulationType  laminar;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/controlDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/controlDict
new file mode 100644
index 0000000000000000000000000000000000000000..174e9185e2ca2a7f054755c65146a7be2a31cf11
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/controlDict
@@ -0,0 +1,47 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      controlDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+application     adjointOptimisationFoam;
+
+startFrom       latestTime;
+
+startTime       0;
+
+stopAt          endTime;
+
+endTime         6000;
+
+deltaT          1;
+
+writeControl    timeStep;
+
+writeInterval   1000;
+
+purgeWrite      1;
+
+writeFormat     ascii;
+
+writePrecision  16;
+
+writeCompression true;
+
+timeFormat      general;
+
+timePrecision   6;
+
+runTimeModifiable yes;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/decomposeParDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/decomposeParDict
new file mode 100644
index 0000000000000000000000000000000000000000..6d7021f19d5121a9aab584ca76b5c76e3425cd92
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/decomposeParDict
@@ -0,0 +1,26 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      decomposeParDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+numberOfSubdomains 4;
+
+method          hierarchical;
+
+coeffs
+{
+    n               (2 2 1);
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/fvSchemes b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/fvSchemes
new file mode 100644
index 0000000000000000000000000000000000000000..f09f81fb1527b5b0d7a9ae6c2d2c6a9eb20252a0
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/fvSchemes
@@ -0,0 +1,51 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSchemes;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ddtSchemes
+{
+    default         steadyState;
+}
+
+gradSchemes
+{
+    default          Gauss linear;
+    gradUConv        cellLimited Gauss linear 0.5;
+}
+
+divSchemes
+{
+    default                 Gauss linear;
+    div(phi,U)      bounded Gauss linearUpwind gradUConv;
+    div(-phi,Ua)    bounded Gauss linearUpwind gradUaConv;
+}
+
+laplacianSchemes
+{
+    default         Gauss linear corrected;
+}
+
+interpolationSchemes
+{
+    default         linear;
+}
+
+snGradSchemes
+{
+    default         corrected;
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/fvSolution b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/fvSolution
new file mode 100644
index 0000000000000000000000000000000000000000..472ba3b769180bfe125cabc9f608a98de4b695be
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/fvSolution
@@ -0,0 +1,61 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSolution;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+SIMPLE
+{
+    nNonOrthogonalCorrectors 0;
+}
+
+solvers
+{
+    "p.*|pa.*"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "m|ma"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "U.*|Ua.*"
+    {
+        solver           PBiCGStab;
+        preconditioner   DILU;
+        tolerance        1e-9;
+        relTol           0.1;
+    }
+}
+
+relaxationFactors
+{
+    fields
+    {
+        "p.*"    0.3;
+        "pa.*"   0.3;
+    }
+    equations
+    {
+        "U.*"    0.7;
+        "Ua.*"   0.7;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/optimisationDict
new file mode 100644
index 0000000000000000000000000000000000000000..ca906d6a5729f9bd83184eba912349cda54a078e
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/laminar/moment/system/optimisationDict
@@ -0,0 +1,107 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      optimisationDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+optimisationManager    singleRun;
+
+primalSolvers
+{
+    op1
+    {
+        active                 true;
+        type                   incompressible;
+        solver                 simple;
+        solutionControls
+        {
+            nIters 3000;
+            residualControl
+            {
+                "p.*"       1.e-7;
+                "U.*"       1.e-7;
+            }
+        }
+    }
+}
+
+adjointManagers
+{
+    adjManager1
+    {
+        primalSolver             op1;
+        adjointSolvers
+        {
+            adjS1
+            {
+                // choose adjoint solver
+                //----------------------
+                active                 true;
+                type                   incompressible;
+                solver                 adjointSimple;
+
+                // manage objectives
+                //------------------
+                objectives
+                {
+                    type               incompressible;
+                    objectiveNames
+                    {
+                        moment
+                        {
+                            weight          1.;
+                            type            moment;
+                            patches         (pressure suction);
+                            direction       (0 0 1);
+                            rotationCenter  (0 0 0);
+                            Aref            2.;
+                            lRef            1.;
+                            rhoInf          1.225;
+                            UInf            1;
+                        }
+                    }
+                }
+
+                // ATC treatment
+                //--------------
+                ATCModel
+                {
+                    ATCModel        standard;
+                }
+
+                // solution control
+                //------------------
+                solutionControls
+                {
+                    nIters 3000;
+                    residualControl
+                    {
+                        "pa.*"       1.e-7;
+                        "Ua.*"       1.e-7;
+                    }
+                }
+            }
+        }
+    }
+}
+
+optimisation
+{
+    sensitivities
+    {
+        type            surfacePoints;
+        patches         (pressure suction);
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/U b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/U
new file mode 100644
index 0000000000000000000000000000000000000000..27b025761536e4a994c1b98cc16ef043d746d9c4
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/U
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      U;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 59.96344962 2.0939698 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    pressure
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    inlet
+    {
+        type            freestream;
+        freestreamValue uniform ( 59.96344962 2.0939698 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/Ua b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/Ua
new file mode 100644
index 0000000000000000000000000000000000000000..4b051627e21873de58e613b1d89a205858718367
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/Ua
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      Ua;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 0 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    pressure
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    inlet
+    {
+        type            adjointFarFieldVelocity;
+        value           uniform ( 0 0 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/nuTilda b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/nuTilda
new file mode 100644
index 0000000000000000000000000000000000000000..50ea7fccb7edac13842d022597796dfa4821a7af
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/nuTilda
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nuTilda;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -1 0 0 0 0 ];
+
+internalField   uniform 2.5e-4;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    pressure
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    inlet
+    {
+        type            inletOutlet;
+        inletValue      uniform 2.5e-04;
+        value           uniform 2.5e-04;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/nuaTilda b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/nuaTilda
new file mode 100644
index 0000000000000000000000000000000000000000..2458c7dbdd356355f130d5344a8c11b57b39b640
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/nuaTilda
@@ -0,0 +1,45 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nuaTilda;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 0 -1 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    pressure
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    inlet
+    {
+        type            adjointFarFieldNuaTilda;
+        value           uniform 0;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/nut b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/nut
new file mode 100644
index 0000000000000000000000000000000000000000..628f3611d429df99cfb16a560f1bd9954441b2f8
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/nut
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nut;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -1 0 0 0 0 ];
+
+internalField   uniform 2.5e-4;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            nutUSpaldingWallFunction;
+        value           uniform 0;
+    }
+    pressure
+    {
+        type            nutUSpaldingWallFunction;
+        value           uniform 0;
+    }
+    inlet
+    {
+        type            calculated;
+        value           uniform 2.5e-4;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/p b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/p
new file mode 100644
index 0000000000000000000000000000000000000000..f5f1bff84bda9596ef6b7cbf92eeb3bc800ab62a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/p
@@ -0,0 +1,45 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      p;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            zeroGradient;
+    }
+    pressure
+    {
+        type            zeroGradient;
+    }
+    inlet
+    {
+        type            outletInlet;
+        outletValue     uniform 0;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/pa b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/pa
new file mode 100644
index 0000000000000000000000000000000000000000..62aab96355507f0538c59596550650093eebd30e
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/0/pa
@@ -0,0 +1,44 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      pa;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            zeroGradient;
+    }
+    pressure
+    {
+        type            zeroGradient;
+    }
+    inlet
+    {
+        type            adjointFarFieldPressure;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/Allclean b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/Allclean
new file mode 100755
index 0000000000000000000000000000000000000000..289939fbe9f20ab28316b31fe66c0c23743b7d8a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/Allclean
@@ -0,0 +1,7 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/CleanFunctions  # Tutorial clean functions
+
+cleanCase
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/Allrun b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/Allrun
new file mode 100755
index 0000000000000000000000000000000000000000..ce49e97d662a01541794ce9102920478efb327be
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/Allrun
@@ -0,0 +1,11 @@
+#!/bin/sh
+cd ${0%/*} || exit 1                        # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/RunFunctions    # Tutorial run functions
+
+resourcesDir=$FOAM_TUTORIALS/incompressible/adjointOptimisationFoam/resources
+
+\cp -r $resourcesDir/meshes/naca0012/polyMesh constant
+runApplication decomposePar
+runParallel $(getApplication)
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/constant/adjointRASProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/constant/adjointRASProperties
new file mode 100644
index 0000000000000000000000000000000000000000..4124d750a542b600d92c47a29beba732f3f0b42e
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/constant/adjointRASProperties
@@ -0,0 +1,28 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      adjointTurbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+adjointRASModel adjointSpalartAllmaras;
+
+adjointSpalartAllmarasCoeffs
+{
+    nSmooth           0;
+    zeroATCPatchTypes ();
+    maskType          faceCells;
+}
+
+adjointTurbulence on;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/constant/transportProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/constant/transportProperties
new file mode 100644
index 0000000000000000000000000000000000000000..4c22e29201884a797fe4167dab797910488ad78c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/constant/transportProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      transportProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+transportModel  Newtonian;
+
+nu              nu [ 0 2 -1 0 0 0 0 ] 1.e-05;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/constant/turbulenceProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/constant/turbulenceProperties
new file mode 100644
index 0000000000000000000000000000000000000000..6d738810e991241d66d4fe93ddee68390d559833
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/constant/turbulenceProperties
@@ -0,0 +1,28 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      turbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+simulationType RAS;
+
+RAS
+{
+    RASModel            SpalartAllmaras;
+
+    turbulence          on;
+
+    printCoeffs         on;
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/controlDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/controlDict
new file mode 100644
index 0000000000000000000000000000000000000000..174e9185e2ca2a7f054755c65146a7be2a31cf11
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/controlDict
@@ -0,0 +1,47 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      controlDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+application     adjointOptimisationFoam;
+
+startFrom       latestTime;
+
+startTime       0;
+
+stopAt          endTime;
+
+endTime         6000;
+
+deltaT          1;
+
+writeControl    timeStep;
+
+writeInterval   1000;
+
+purgeWrite      1;
+
+writeFormat     ascii;
+
+writePrecision  16;
+
+writeCompression true;
+
+timeFormat      general;
+
+timePrecision   6;
+
+runTimeModifiable yes;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/decomposeParDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/decomposeParDict
new file mode 100644
index 0000000000000000000000000000000000000000..6d7021f19d5121a9aab584ca76b5c76e3425cd92
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/decomposeParDict
@@ -0,0 +1,26 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      decomposeParDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+numberOfSubdomains 4;
+
+method          hierarchical;
+
+coeffs
+{
+    n               (2 2 1);
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/fvSchemes b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/fvSchemes
new file mode 100644
index 0000000000000000000000000000000000000000..93cf109729bec836b2bd44a204f290a092f43650
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/fvSchemes
@@ -0,0 +1,74 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSchemes;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ddtSchemes
+{
+    default         steadyState;
+}
+
+gradSchemes
+{
+    default          Gauss linear;
+    gradUConv        cellLimited Gauss linear 1;
+    gradNuTildaConv  cellLimited Gauss linear 1;
+    gradDConv        cellLimited Gauss linear 1;
+
+    gradUaConv       cellLimited Gauss linear 1;
+    gradNuaTildaConv cellLimited Gauss linear 1;
+  //gradUATC         cellLimited Gauss linear 1;
+}
+
+divSchemes
+{
+    default            Gauss linear;
+    div(phi,U)         bounded Gauss linearUpwind gradUConv;
+    div(-phi,Ua)       bounded Gauss linearUpwind gradUaConv;
+    div(yPhi,yWall)            Gauss linearUpwind gradDConv;
+
+    div(phi,nuTilda)   bounded Gauss linearUpwind gradNuTildaConv;
+    div(-phi,nuaTilda) bounded Gauss linearUpwind gradNuaTildaConv;
+    div(-yPhi,da)              Gauss linearUpwind gradDaConv;
+}
+
+laplacianSchemes
+{
+    default         Gauss linear corrected;
+}
+
+interpolationSchemes
+{
+    default         linear;
+}
+
+snGradSchemes
+{
+    default         corrected;
+}
+
+wallDist
+{
+    method advectionDiffusion;
+    advectionDiffusionCoeffs
+    {
+        method    meshWave;
+        tolerance 5.e-6;
+        maxIter   1000;
+        epsilon   0.1;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/fvSolution b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/fvSolution
new file mode 100644
index 0000000000000000000000000000000000000000..450efa5c1f3e4db5f72d7457d6212f243a887b73
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/fvSolution
@@ -0,0 +1,65 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSolution;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+SIMPLE
+{
+    nNonOrthogonalCorrectors 0;
+}
+
+solvers
+{
+    "p.*|pa.*"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "m|ma"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "U.*|Ua.*|nuTilda.*|nuaTilda.*|yWall|da"
+    {
+        solver           PBiCGStab;
+        preconditioner   DILU;
+        tolerance        1e-9;
+        relTol           0.1;
+    }
+}
+
+relaxationFactors
+{
+    fields
+    {
+        "p.*"        0.3;
+        "pa.*"       0.3;
+    }
+    equations
+    {
+        "U.*"        0.7;
+        "Ua.*"       0.7;
+        "nuTilda.*"  0.7;
+        "nuaTilda.*" 0.7;
+        "yWall.*"    0.5;
+        "da.*"       0.7;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/optimisationDict
new file mode 100644
index 0000000000000000000000000000000000000000..f0b69ec378edd7808ea8dcad692bf8c9df85a165
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftFullSetup/system/optimisationDict
@@ -0,0 +1,131 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      optimisationDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+optimisationManager     singleRun;
+
+primalSolvers
+{
+    op1
+    {
+        active                 true;
+        type                   incompressible;
+        solver                 simple;
+        useSolverNameForFields false;
+        solutionControls
+        {
+            nIters 3000;
+            residualControl
+            {
+                "p.*"       1.e-6;
+                "U.*"       1.e-6;
+                "nuTilda.*" 1.e-6;
+            }
+        }
+    }
+}
+
+adjointManagers
+{
+    adjManager1
+    {
+        primalSolver             op1;
+        operatingPointWeight     1;
+        adjointSolvers
+        {
+            adjS1
+            {
+                // choose adjoint solver
+                //----------------------
+                active                 true;
+                type                   incompressible;
+                solver                 adjointSimple;
+                useSolverNameForFields false;
+                computeSensitivities   true;
+
+                // manage objectives
+                //------------------
+                objectives
+                {
+                    type                incompressible;
+                    objectiveNames
+                    {
+                        lift
+                        {
+                            weight          1.;
+                            type            force;
+                            patches         (pressure suction);
+                            direction       (0.034899496703 -0.9993908270189999 0);
+                            Aref            2.;
+                            rhoInf          1.225;
+                            UInf            1;
+                        }
+                    }
+                }
+
+                // ATC treatment
+                //--------------
+                ATCModel
+                {
+                    ATCModel          standard;
+                    extraConvection   0;
+                    nSmooth           0;
+                    zeroATCPatchTypes ();
+                    maskType          faceCells;
+                }
+
+                // solution control
+                //------------------
+                solutionControls
+                {
+                    nIters 3000;
+                    residualControl
+                    {
+                        "pa.*"       1.e-6;
+                        "Ua.*"       1.e-6;
+                        "nuaTilda.*" 1.e-6;
+                    }
+                }
+            }
+        }
+    }
+}
+
+optimisation
+{
+    sensitivities
+    {
+        type              surfacePoints;
+        patches           (pressure suction);
+        includeSurfaceArea  false;
+        includeDistance     true;
+        includeMeshMovement true;
+        includeObjectiveContribution true;
+        writeAllSurfaceFiles         true;
+        adjointMeshMovementSolver
+        {
+            iters     1000;
+            tolerance 1.e-6;
+        }
+        adjointEikonalSolver
+        {
+            iters     1000;
+            tolerance 1.e-6;
+            epsilon   0.1;
+        }
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/U b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/U
new file mode 100644
index 0000000000000000000000000000000000000000..27b025761536e4a994c1b98cc16ef043d746d9c4
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/U
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      U;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 59.96344962 2.0939698 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    pressure
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    inlet
+    {
+        type            freestream;
+        freestreamValue uniform ( 59.96344962 2.0939698 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/Ua b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/Ua
new file mode 100644
index 0000000000000000000000000000000000000000..4b051627e21873de58e613b1d89a205858718367
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/Ua
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      Ua;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 0 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    pressure
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    inlet
+    {
+        type            adjointFarFieldVelocity;
+        value           uniform ( 0 0 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/nuTilda b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/nuTilda
new file mode 100644
index 0000000000000000000000000000000000000000..50ea7fccb7edac13842d022597796dfa4821a7af
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/nuTilda
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nuTilda;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -1 0 0 0 0 ];
+
+internalField   uniform 2.5e-4;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    pressure
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    inlet
+    {
+        type            inletOutlet;
+        inletValue      uniform 2.5e-04;
+        value           uniform 2.5e-04;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/nuaTilda b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/nuaTilda
new file mode 100644
index 0000000000000000000000000000000000000000..2458c7dbdd356355f130d5344a8c11b57b39b640
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/nuaTilda
@@ -0,0 +1,45 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nuaTilda;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 0 -1 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    pressure
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    inlet
+    {
+        type            adjointFarFieldNuaTilda;
+        value           uniform 0;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/nut b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/nut
new file mode 100644
index 0000000000000000000000000000000000000000..628f3611d429df99cfb16a560f1bd9954441b2f8
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/nut
@@ -0,0 +1,46 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nut;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -1 0 0 0 0 ];
+
+internalField   uniform 2.5e-4;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            nutUSpaldingWallFunction;
+        value           uniform 0;
+    }
+    pressure
+    {
+        type            nutUSpaldingWallFunction;
+        value           uniform 0;
+    }
+    inlet
+    {
+        type            calculated;
+        value           uniform 2.5e-4;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/p b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/p
new file mode 100644
index 0000000000000000000000000000000000000000..f5f1bff84bda9596ef6b7cbf92eeb3bc800ab62a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/p
@@ -0,0 +1,45 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      p;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            zeroGradient;
+    }
+    pressure
+    {
+        type            zeroGradient;
+    }
+    inlet
+    {
+        type            outletInlet;
+        outletValue     uniform 0;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/pa b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/pa
new file mode 100644
index 0000000000000000000000000000000000000000..62aab96355507f0538c59596550650093eebd30e
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/0/pa
@@ -0,0 +1,44 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      pa;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    suction
+    {
+        type            zeroGradient;
+    }
+    pressure
+    {
+        type            zeroGradient;
+    }
+    inlet
+    {
+        type            adjointFarFieldPressure;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/Allclean b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/Allclean
new file mode 100755
index 0000000000000000000000000000000000000000..289939fbe9f20ab28316b31fe66c0c23743b7d8a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/Allclean
@@ -0,0 +1,7 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/CleanFunctions  # Tutorial clean functions
+
+cleanCase
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/Allrun b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/Allrun
new file mode 100755
index 0000000000000000000000000000000000000000..ce49e97d662a01541794ce9102920478efb327be
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/Allrun
@@ -0,0 +1,11 @@
+#!/bin/sh
+cd ${0%/*} || exit 1                        # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/RunFunctions    # Tutorial run functions
+
+resourcesDir=$FOAM_TUTORIALS/incompressible/adjointOptimisationFoam/resources
+
+\cp -r $resourcesDir/meshes/naca0012/polyMesh constant
+runApplication decomposePar
+runParallel $(getApplication)
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/constant/adjointRASProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/constant/adjointRASProperties
new file mode 100644
index 0000000000000000000000000000000000000000..d81bdb5ad8084041dcf3c88b0f0830896c21a5cb
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/constant/adjointRASProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      adjointTurbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+adjointRASModel adjointSpalartAllmaras;
+
+adjointTurbulence on;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/constant/transportProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/constant/transportProperties
new file mode 100644
index 0000000000000000000000000000000000000000..4c22e29201884a797fe4167dab797910488ad78c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/constant/transportProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      transportProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+transportModel  Newtonian;
+
+nu              nu [ 0 2 -1 0 0 0 0 ] 1.e-05;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/constant/turbulenceProperties b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/constant/turbulenceProperties
new file mode 100644
index 0000000000000000000000000000000000000000..6d738810e991241d66d4fe93ddee68390d559833
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/constant/turbulenceProperties
@@ -0,0 +1,28 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      turbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+simulationType RAS;
+
+RAS
+{
+    RASModel            SpalartAllmaras;
+
+    turbulence          on;
+
+    printCoeffs         on;
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/controlDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/controlDict
new file mode 100644
index 0000000000000000000000000000000000000000..174e9185e2ca2a7f054755c65146a7be2a31cf11
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/controlDict
@@ -0,0 +1,47 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      controlDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+application     adjointOptimisationFoam;
+
+startFrom       latestTime;
+
+startTime       0;
+
+stopAt          endTime;
+
+endTime         6000;
+
+deltaT          1;
+
+writeControl    timeStep;
+
+writeInterval   1000;
+
+purgeWrite      1;
+
+writeFormat     ascii;
+
+writePrecision  16;
+
+writeCompression true;
+
+timeFormat      general;
+
+timePrecision   6;
+
+runTimeModifiable yes;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/decomposeParDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/decomposeParDict
new file mode 100644
index 0000000000000000000000000000000000000000..6d7021f19d5121a9aab584ca76b5c76e3425cd92
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/decomposeParDict
@@ -0,0 +1,26 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      decomposeParDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+numberOfSubdomains 4;
+
+method          hierarchical;
+
+coeffs
+{
+    n               (2 2 1);
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/fvSchemes b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/fvSchemes
new file mode 100644
index 0000000000000000000000000000000000000000..93cf109729bec836b2bd44a204f290a092f43650
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/fvSchemes
@@ -0,0 +1,74 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSchemes;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ddtSchemes
+{
+    default         steadyState;
+}
+
+gradSchemes
+{
+    default          Gauss linear;
+    gradUConv        cellLimited Gauss linear 1;
+    gradNuTildaConv  cellLimited Gauss linear 1;
+    gradDConv        cellLimited Gauss linear 1;
+
+    gradUaConv       cellLimited Gauss linear 1;
+    gradNuaTildaConv cellLimited Gauss linear 1;
+  //gradUATC         cellLimited Gauss linear 1;
+}
+
+divSchemes
+{
+    default            Gauss linear;
+    div(phi,U)         bounded Gauss linearUpwind gradUConv;
+    div(-phi,Ua)       bounded Gauss linearUpwind gradUaConv;
+    div(yPhi,yWall)            Gauss linearUpwind gradDConv;
+
+    div(phi,nuTilda)   bounded Gauss linearUpwind gradNuTildaConv;
+    div(-phi,nuaTilda) bounded Gauss linearUpwind gradNuaTildaConv;
+    div(-yPhi,da)              Gauss linearUpwind gradDaConv;
+}
+
+laplacianSchemes
+{
+    default         Gauss linear corrected;
+}
+
+interpolationSchemes
+{
+    default         linear;
+}
+
+snGradSchemes
+{
+    default         corrected;
+}
+
+wallDist
+{
+    method advectionDiffusion;
+    advectionDiffusionCoeffs
+    {
+        method    meshWave;
+        tolerance 5.e-6;
+        maxIter   1000;
+        epsilon   0.1;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/fvSolution b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/fvSolution
new file mode 100644
index 0000000000000000000000000000000000000000..450efa5c1f3e4db5f72d7457d6212f243a887b73
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/fvSolution
@@ -0,0 +1,65 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSolution;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+SIMPLE
+{
+    nNonOrthogonalCorrectors 0;
+}
+
+solvers
+{
+    "p.*|pa.*"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "m|ma"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "U.*|Ua.*|nuTilda.*|nuaTilda.*|yWall|da"
+    {
+        solver           PBiCGStab;
+        preconditioner   DILU;
+        tolerance        1e-9;
+        relTol           0.1;
+    }
+}
+
+relaxationFactors
+{
+    fields
+    {
+        "p.*"        0.3;
+        "pa.*"       0.3;
+    }
+    equations
+    {
+        "U.*"        0.7;
+        "Ua.*"       0.7;
+        "nuTilda.*"  0.7;
+        "nuaTilda.*" 0.7;
+        "yWall.*"    0.5;
+        "da.*"       0.7;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/optimisationDict
new file mode 100644
index 0000000000000000000000000000000000000000..37e9ba02a57367c3827df7a9cb6360d496b3a811
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/naca0012/turbulent/liftMinimumSetup/system/optimisationDict
@@ -0,0 +1,107 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      optimisationDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+optimisationManager     singleRun;
+
+primalSolvers
+{
+    op1
+    {
+        active                 true;
+        type                   incompressible;
+        solver                 simple;
+        solutionControls
+        {
+            nIters 3000;
+            residualControl
+            {
+                "p.*"       1.e-6;
+                "U.*"       1.e-6;
+                "nuTilda.*" 1.e-6;
+            }
+        }
+    }
+}
+
+adjointManagers
+{
+    adjManager1
+    {
+        primalSolver             op1;
+        adjointSolvers
+        {
+            adjS1
+            {
+                // choose adjoint solver
+                //----------------------
+                active                 true;
+                type                   incompressible;
+                solver                 adjointSimple;
+
+                // manage objectives
+                //------------------
+                objectives
+                {
+                    type                incompressible;
+                    objectiveNames
+                    {
+                        lift
+                        {
+                            weight          1.;
+                            type            force;
+                            patches         (pressure suction);
+                            direction       (0.034899496703 -0.9993908270189999 0);
+                            Aref            2.;
+                            rhoInf          1.225;
+                            UInf            1;
+                        }
+                    }
+                }
+
+                // ATC treatment
+                //--------------
+                ATCModel
+                {
+                    ATCModel          standard;
+                }
+
+                // solution control
+                //------------------
+                solutionControls
+                {
+                    nIters 3000;
+                    residualControl
+                    {
+                        "pa.*"       1.e-6;
+                        "Ua.*"       1.e-6;
+                        "nuaTilda.*" 1.e-6;
+                    }
+                }
+            }
+        }
+    }
+}
+
+optimisation
+{
+    sensitivities
+    {
+        type              surfacePoints;
+        patches           (pressure suction);
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/boundary.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/boundary.gz
new file mode 100644
index 0000000000000000000000000000000000000000..efd8a381811439a4ddbb27323c2a32fdf0af48b2
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/boundary.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/faces.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/faces.gz
new file mode 100644
index 0000000000000000000000000000000000000000..5740adf1cf3090b3efb3443ec7dfda8fde0175e3
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/faces.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/neighbour.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/neighbour.gz
new file mode 100644
index 0000000000000000000000000000000000000000..e8cb117cfdc8aa439abd2447f136a325cf1c8b28
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/neighbour.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/owner.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/owner.gz
new file mode 100644
index 0000000000000000000000000000000000000000..c90410a35ad5e9ae5996e34c512f2f10fedd618e
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/owner.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/points.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/points.gz
new file mode 100644
index 0000000000000000000000000000000000000000..70e17d6b60119e929cd755678345fcb498943d06
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/naca0012/polyMesh/points.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/boundary.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/boundary.gz
new file mode 100644
index 0000000000000000000000000000000000000000..bd3a9aa3cf6f539df10ce2b4652ea3333e156a1f
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/boundary.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/faces.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/faces.gz
new file mode 100644
index 0000000000000000000000000000000000000000..33a847f04e4788e8e15e724bc3fee8a1bf470d99
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/faces.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/neighbour.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/neighbour.gz
new file mode 100644
index 0000000000000000000000000000000000000000..59dd2075e3b663319e99a3a4bc36d1af701c8a8c
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/neighbour.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/owner.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/owner.gz
new file mode 100644
index 0000000000000000000000000000000000000000..3372e6e3693f0078d46c1c1ea84765d54eae6565
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/owner.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/points.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/points.gz
new file mode 100644
index 0000000000000000000000000000000000000000..4177ef3e35ae9722f8a57d824e352bc9c7ce4ee1
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/meshes/sbend/polyMesh/points.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_0.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_0.gz
new file mode 100644
index 0000000000000000000000000000000000000000..056af352e0c2b5717d58092a3009f8aed69d969a
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_0.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_1.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_1.gz
new file mode 100644
index 0000000000000000000000000000000000000000..3f064eab6c83b84e373668ff31ebb8326af1c91d
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_1.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_10.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_10.gz
new file mode 100644
index 0000000000000000000000000000000000000000..fd000ce78752865f23af8317fcf57bd83f3d1c31
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_10.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_11.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_11.gz
new file mode 100644
index 0000000000000000000000000000000000000000..cc7da4710f47e557b1ecb67bde1134e961ac0d59
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_11.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_12.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_12.gz
new file mode 100644
index 0000000000000000000000000000000000000000..752a90ec0c5919966dbfc32d62c619a81a33427a
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_12.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_13.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_13.gz
new file mode 100644
index 0000000000000000000000000000000000000000..fb175399dd5c18a9c066beb9b0dd4f742c142b0a
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_13.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_14.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_14.gz
new file mode 100644
index 0000000000000000000000000000000000000000..30f4e0077cc1f2bb481a480c2fc9094649c30ec5
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_14.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_15.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_15.gz
new file mode 100644
index 0000000000000000000000000000000000000000..9efd45f88b8a8b96a3a3197e586a5c66d166dc00
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_15.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_2.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_2.gz
new file mode 100644
index 0000000000000000000000000000000000000000..ba62092a6b2a69346d959eb0b4382a0a11afca87
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_2.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_3.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_3.gz
new file mode 100644
index 0000000000000000000000000000000000000000..256adf01a0b601f57cac7189ffdca44c8108d462
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_3.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_4.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_4.gz
new file mode 100644
index 0000000000000000000000000000000000000000..34a50fb9efbe4a1dedd51fbb37dc63a7e5392d63
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_4.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_5.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_5.gz
new file mode 100644
index 0000000000000000000000000000000000000000..1cd510e747380a04fb44f9c134b5a8614535e71a
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_5.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_6.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_6.gz
new file mode 100644
index 0000000000000000000000000000000000000000..03ffa5a5a67d8e7d2735e9f3b40865cc57c49229
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_6.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_7.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_7.gz
new file mode 100644
index 0000000000000000000000000000000000000000..493a10bb33799a08ffeee75c496e5ee2be42e5a8
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_7.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_8.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_8.gz
new file mode 100644
index 0000000000000000000000000000000000000000..b8b2c2265c544420364af12006446729f97ead97
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_8.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_9.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_9.gz
new file mode 100644
index 0000000000000000000000000000000000000000..300c9cb035f708d08220eb10efa35e29c99eacd7
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/naca0012/dxidXj_9.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_0.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_0.gz
new file mode 100644
index 0000000000000000000000000000000000000000..714e9e1f7bdd23a3646ba25d67e84c39126d1f66
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_0.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_1.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_1.gz
new file mode 100644
index 0000000000000000000000000000000000000000..5f28a46692be21cffc13044ef720a61f2cc88ced
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_1.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_10.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_10.gz
new file mode 100644
index 0000000000000000000000000000000000000000..6395bea8ba4f7f9e72956c321419d698451d70cb
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_10.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_11.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_11.gz
new file mode 100644
index 0000000000000000000000000000000000000000..37d77a1d63e9a58e1f10982658ef0d06546891a4
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_11.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_12.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_12.gz
new file mode 100644
index 0000000000000000000000000000000000000000..430dc9c690d2965d2c0ac01313d4b91dabb2a1af
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_12.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_13.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_13.gz
new file mode 100644
index 0000000000000000000000000000000000000000..17e7571568fadd0fa2d691277fbb72fc9c4cdb10
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_13.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_14.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_14.gz
new file mode 100644
index 0000000000000000000000000000000000000000..8208bf6f2e2b8bb8abcea5b69667b4878904d21d
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_14.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_15.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_15.gz
new file mode 100644
index 0000000000000000000000000000000000000000..cdf2a6deffe709f5eb01b44dcce1c25b25405d9a
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_15.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_16.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_16.gz
new file mode 100644
index 0000000000000000000000000000000000000000..b3d801c8de12bd1c71272364a47c17b276f2fbd3
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_16.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_17.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_17.gz
new file mode 100644
index 0000000000000000000000000000000000000000..b057939c4aa042aa7f5d0341e548063bc2f348fc
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_17.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_18.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_18.gz
new file mode 100644
index 0000000000000000000000000000000000000000..ab9a18ed743d7788297184f1de2f5563fcf1ca20
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_18.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_19.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_19.gz
new file mode 100644
index 0000000000000000000000000000000000000000..feab06780a1bde2a1165c179602e46fa6da66fde
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_19.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_2.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_2.gz
new file mode 100644
index 0000000000000000000000000000000000000000..61629961a5540ae4ac4b8f9658737583f31099d3
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_2.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_20.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_20.gz
new file mode 100644
index 0000000000000000000000000000000000000000..127ec7b69002860fa51ea0ad7cd0f04682013aec
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_20.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_21.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_21.gz
new file mode 100644
index 0000000000000000000000000000000000000000..376004399f7562eecf699ae62f7ef44260ea8bc4
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_21.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_22.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_22.gz
new file mode 100644
index 0000000000000000000000000000000000000000..c413330821ff876a8bc5b23e25fb085a90aa7a4a
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_22.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_23.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_23.gz
new file mode 100644
index 0000000000000000000000000000000000000000..5780090af98268c28f77d738e3082329dc152022
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_23.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_3.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_3.gz
new file mode 100644
index 0000000000000000000000000000000000000000..75db335283f2e210417c614957002cde3848ac3f
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_3.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_4.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_4.gz
new file mode 100644
index 0000000000000000000000000000000000000000..a374107c44714ca3ac99072031ba20ea6f79fcf8
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_4.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_5.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_5.gz
new file mode 100644
index 0000000000000000000000000000000000000000..132598e525cc5614a631c5cc62117bab5c6bb3fa
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_5.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_6.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_6.gz
new file mode 100644
index 0000000000000000000000000000000000000000..8f6bfa469b64431970aab787f53f3b5a49099318
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_6.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_7.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_7.gz
new file mode 100644
index 0000000000000000000000000000000000000000..930e141115e4e7177037008768ef74e651db1640
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_7.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_8.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_8.gz
new file mode 100644
index 0000000000000000000000000000000000000000..5c6c8b672c5e4798c6eb93f51bbe87d3fcf0c21a
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_8.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_9.gz b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_9.gz
new file mode 100644
index 0000000000000000000000000000000000000000..494448c87484acac227647071983d214f3269414
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/resources/param/sbend/dxidXj_9.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/U b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/U
new file mode 100644
index 0000000000000000000000000000000000000000..86855f366d3118269f4cd0c1cbb673c1d59a4916
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/U
@@ -0,0 +1,55 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      U;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 0.039473 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    lower
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    upper
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    Inlet
+    {
+        type            fixedValue;
+        value           uniform ( 0.039473 0 0 );
+    }
+    Outlet
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/Ua b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/Ua
new file mode 100644
index 0000000000000000000000000000000000000000..1ffd585d52957272754116db8bbfb64dc7dbd2d8
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/Ua
@@ -0,0 +1,56 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      Ua;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 0 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    upper
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    Inlet
+    {
+        type            adjointInletVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    Outlet
+    {
+        type            adjointOutletVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    lower
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_0.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_0.gz
new file mode 100644
index 0000000000000000000000000000000000000000..714e9e1f7bdd23a3646ba25d67e84c39126d1f66
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_0.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_1.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_1.gz
new file mode 100644
index 0000000000000000000000000000000000000000..5f28a46692be21cffc13044ef720a61f2cc88ced
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_1.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_10.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_10.gz
new file mode 100644
index 0000000000000000000000000000000000000000..6395bea8ba4f7f9e72956c321419d698451d70cb
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_10.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_11.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_11.gz
new file mode 100644
index 0000000000000000000000000000000000000000..37d77a1d63e9a58e1f10982658ef0d06546891a4
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_11.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_12.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_12.gz
new file mode 100644
index 0000000000000000000000000000000000000000..430dc9c690d2965d2c0ac01313d4b91dabb2a1af
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_12.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_13.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_13.gz
new file mode 100644
index 0000000000000000000000000000000000000000..17e7571568fadd0fa2d691277fbb72fc9c4cdb10
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_13.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_14.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_14.gz
new file mode 100644
index 0000000000000000000000000000000000000000..8208bf6f2e2b8bb8abcea5b69667b4878904d21d
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_14.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_15.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_15.gz
new file mode 100644
index 0000000000000000000000000000000000000000..cdf2a6deffe709f5eb01b44dcce1c25b25405d9a
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_15.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_16.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_16.gz
new file mode 100644
index 0000000000000000000000000000000000000000..b3d801c8de12bd1c71272364a47c17b276f2fbd3
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_16.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_17.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_17.gz
new file mode 100644
index 0000000000000000000000000000000000000000..b057939c4aa042aa7f5d0341e548063bc2f348fc
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_17.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_18.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_18.gz
new file mode 100644
index 0000000000000000000000000000000000000000..ab9a18ed743d7788297184f1de2f5563fcf1ca20
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_18.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_19.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_19.gz
new file mode 100644
index 0000000000000000000000000000000000000000..feab06780a1bde2a1165c179602e46fa6da66fde
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_19.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_2.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_2.gz
new file mode 100644
index 0000000000000000000000000000000000000000..61629961a5540ae4ac4b8f9658737583f31099d3
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_2.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_20.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_20.gz
new file mode 100644
index 0000000000000000000000000000000000000000..127ec7b69002860fa51ea0ad7cd0f04682013aec
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_20.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_21.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_21.gz
new file mode 100644
index 0000000000000000000000000000000000000000..376004399f7562eecf699ae62f7ef44260ea8bc4
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_21.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_22.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_22.gz
new file mode 100644
index 0000000000000000000000000000000000000000..c413330821ff876a8bc5b23e25fb085a90aa7a4a
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_22.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_23.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_23.gz
new file mode 100644
index 0000000000000000000000000000000000000000..5780090af98268c28f77d738e3082329dc152022
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_23.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_3.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_3.gz
new file mode 100644
index 0000000000000000000000000000000000000000..75db335283f2e210417c614957002cde3848ac3f
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_3.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_4.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_4.gz
new file mode 100644
index 0000000000000000000000000000000000000000..a374107c44714ca3ac99072031ba20ea6f79fcf8
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_4.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_5.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_5.gz
new file mode 100644
index 0000000000000000000000000000000000000000..132598e525cc5614a631c5cc62117bab5c6bb3fa
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_5.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_6.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_6.gz
new file mode 100644
index 0000000000000000000000000000000000000000..8f6bfa469b64431970aab787f53f3b5a49099318
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_6.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_7.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_7.gz
new file mode 100644
index 0000000000000000000000000000000000000000..930e141115e4e7177037008768ef74e651db1640
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_7.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_8.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_8.gz
new file mode 100644
index 0000000000000000000000000000000000000000..5c6c8b672c5e4798c6eb93f51bbe87d3fcf0c21a
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_8.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_9.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_9.gz
new file mode 100644
index 0000000000000000000000000000000000000000..494448c87484acac227647071983d214f3269414
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/dxidXj_9.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/ma b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/ma
new file mode 100644
index 0000000000000000000000000000000000000000..f888305e34231d9da10353a9bc212d55ed771f02
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/ma
@@ -0,0 +1,57 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  plus                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      ma;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [0 3 -3 0 0 0 0];
+
+
+internalField   uniform (0 0 0);
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            fixedValue;
+        value           uniform (0 0 0);
+    }
+    upper
+    {
+        type            fixedValue;
+        value           uniform (0 0 0);
+    }
+    Inlet
+    {
+        type            fixedValue;
+        value           uniform (0 0 0);
+    }
+    Outlet
+    {
+        type            fixedValue;
+        value           uniform (0 0 0);
+    }
+    lower
+    {
+        type            fixedValue;
+        value           uniform (0 0 0);
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/p b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/p
new file mode 100644
index 0000000000000000000000000000000000000000..774f2a81b26ae15fe41a0eea1fb9c586a5b10fc1
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/p
@@ -0,0 +1,52 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      p;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    lower
+    {
+        type            zeroGradient;
+    }
+    upper
+    {
+        type            zeroGradient;
+    }
+    sideWall
+    {
+        type            zeroGradient;
+    }
+    Inlet
+    {
+        type            zeroGradient;
+    }
+    Outlet
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/pa b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/pa
new file mode 100644
index 0000000000000000000000000000000000000000..70eee3cc03a4d1408be7875bc0344254e3878283
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/0/pa
@@ -0,0 +1,52 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      pa;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            zeroGradient;
+    }
+    upper
+    {
+        type            zeroGradient;
+    }
+    Inlet
+    {
+        type            zeroGradient;
+    }
+    Outlet
+    {
+        type            adjointOutletPressure;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/Allclean b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/Allclean
new file mode 100755
index 0000000000000000000000000000000000000000..289939fbe9f20ab28316b31fe66c0c23743b7d8a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/Allclean
@@ -0,0 +1,7 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/CleanFunctions  # Tutorial clean functions
+
+cleanCase
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/Allrun b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/Allrun
new file mode 100755
index 0000000000000000000000000000000000000000..8a7f639223c626eb83112e83e0c0a975a617921b
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/Allrun
@@ -0,0 +1,12 @@
+#!/bin/sh
+cd ${0%/*} || exit 1                        # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/RunFunctions    # Tutorial run functions
+
+resourcesDir=$FOAM_TUTORIALS/incompressible/adjointOptimisationFoam/resources
+
+\cp $resourcesDir/param/sbend/* 0
+\cp -r $resourcesDir/meshes/sbend/polyMesh constant
+runApplication decomposePar
+runParallel $(getApplication)
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/constant/adjointRASProperties b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/constant/adjointRASProperties
new file mode 100644
index 0000000000000000000000000000000000000000..48724552a35189947602192d0ed61d67ad4aa44c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/constant/adjointRASProperties
@@ -0,0 +1,24 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      RASProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+adjointRASModel   adjointLaminar;
+
+adjointTurbulence on;
+
+printCoeffs       off;
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/constant/dynamicMeshDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/constant/dynamicMeshDict
new file mode 100644
index 0000000000000000000000000000000000000000..31227cf2572d2a3c1dad723fed2c2575c82f71c4
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/constant/dynamicMeshDict
@@ -0,0 +1,49 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      dynamicMeshDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+solver volumetricBSplinesMotionSolver;
+
+volumetricBSplinesMotionSolverCoeffs
+{
+    controlBoxes (duct);
+    duct
+    {
+        name    duct;
+        type    cartesian;
+        nCPsU   9;
+        nCPsV   5;
+        nCPsW   3;
+        degreeU 3;
+        degreeV 3;
+        degreeW 2;
+
+        controlPointsDefinition axisAligned;
+        lowerCpBounds           (-1.1 -0.21 -0.05);
+        upperCpBounds           ( 1.1  0.39  0.15);
+
+        confineX1movement false;
+        confineX2movement false;
+        confineX3movement true;
+        confineBoundaryControlPoints false;
+
+        boundUMinCPs ( (true true true) (true true true) );
+        boundUMaxCPs ( (true true true) (true true true) );
+        boundWMinCPs ( (true true true) );
+        boundWMaxCPs ( (true true true) );
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/constant/transportProperties b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/constant/transportProperties
new file mode 100644
index 0000000000000000000000000000000000000000..cef0dd60051abf98461bee3fafc3626128f2ef1c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/constant/transportProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      transportProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+transportModel  Newtonian;
+
+nu              nu [0 2 -1 0 0 0 0] 1.5e-05;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/constant/turbulenceProperties b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/constant/turbulenceProperties
new file mode 100644
index 0000000000000000000000000000000000000000..4c6fb923e0c9017f03269be5058c8e2e4b2a1b95
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/constant/turbulenceProperties
@@ -0,0 +1,19 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      turbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+simulationType laminar;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/controlDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/controlDict
new file mode 100644
index 0000000000000000000000000000000000000000..174e9185e2ca2a7f054755c65146a7be2a31cf11
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/controlDict
@@ -0,0 +1,47 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      controlDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+application     adjointOptimisationFoam;
+
+startFrom       latestTime;
+
+startTime       0;
+
+stopAt          endTime;
+
+endTime         6000;
+
+deltaT          1;
+
+writeControl    timeStep;
+
+writeInterval   1000;
+
+purgeWrite      1;
+
+writeFormat     ascii;
+
+writePrecision  16;
+
+writeCompression true;
+
+timeFormat      general;
+
+timePrecision   6;
+
+runTimeModifiable yes;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/decomposeParDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/decomposeParDict
new file mode 100644
index 0000000000000000000000000000000000000000..77b43da11676790f1a062276cfe4f4bfff25f5aa
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/decomposeParDict
@@ -0,0 +1,26 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      decomposeParDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+numberOfSubdomains 4;
+
+method          hierarchical;
+
+coeffs
+{
+    n               (4 1 1);
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/fvSchemes b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/fvSchemes
new file mode 100644
index 0000000000000000000000000000000000000000..40e98efdb1fbb7b3b74fa1585ecc104b6b8fef88
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/fvSchemes
@@ -0,0 +1,55 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSchemes;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ddtSchemes
+{
+    default         steadyState;
+}
+
+gradSchemes
+{
+    default         Gauss linear;
+}
+
+divSchemes
+{
+    default         Gauss linear;
+
+    div(phi,U)      bounded Gauss linearUpwind gradUConv;
+    div(-phi,Ua)    bounded Gauss linearUpwind gradUaConv;
+
+    div((nuEff*dev(grad(U).T()))) Gauss linear;
+    div((nuEff*dev(grad(Ua).T()))) Gauss linear;
+}
+
+laplacianSchemes
+{
+    default         Gauss linear corrected;
+
+}
+
+interpolationSchemes
+{
+    default         linear;
+}
+
+snGradSchemes
+{
+    default         corrected;
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/fvSolution b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/fvSolution
new file mode 100644
index 0000000000000000000000000000000000000000..ce225da8136cc05e1357ee7735be0c456e32f4f3
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/fvSolution
@@ -0,0 +1,61 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSolution;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+SIMPLE
+{
+    nNonOrthogonalCorrectors 0;
+}
+
+solvers
+{
+    "p|pa"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "m|ma"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "U|Ua"
+    {
+        solver           PBiCGStab;
+        preconditioner   DILU;
+        tolerance        1e-9;
+        relTol           0.1;
+    };
+}
+
+relaxationFactors
+{
+    fields
+    {
+        p               0.5;
+        pa              0.5;
+    }
+    equations
+    {
+        U               0.7;
+        Ua              0.7;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/optimisationDict
new file mode 100644
index 0000000000000000000000000000000000000000..f2886862cc00f67a750de4d1015bfba0a0989402
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/laminar/system/optimisationDict
@@ -0,0 +1,101 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      optimisationDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+optimisationManager     singleRun;
+
+primalSolvers
+{
+    p1
+    {
+        active                 true;
+        type                   incompressible;
+        solver                 simple;
+        solutionControls
+        {
+            nIters 3000;
+            residualControl
+            {
+                "p.*"       1.e-7;
+                "U.*"       1.e-7;
+            }
+        }
+    }
+}
+
+adjointManagers
+{
+    am1
+    {
+        primalSolver             p1;
+        adjointSolvers
+        {
+            as1
+            {
+                // choose adjoint solver
+                //----------------------
+                active                 true;
+                type                   incompressible;
+                solver                 adjointSimple;
+
+                // manage objectives
+                //------------------
+                objectives
+                {
+                    type                incompressible;
+                    objectiveNames
+                    {
+                        losses
+                        {
+                            weight          1;
+                            type            PtLosses;
+                            patches         (Inlet Outlet);
+                        }
+                    }
+                }
+
+                // ATC treatment
+                //--------------
+                ATCModel
+                {
+                    ATCModel        standard;
+                }
+
+                // solution control
+                //------------------
+                solutionControls
+                {
+                    nIters 3000;
+                    residualControl
+                    {
+                        "pa.*"       1.e-7;
+                        "Ua.*"       1.e-7;
+                    }
+                }
+            }
+        }
+    }
+}
+
+optimisation
+{
+    sensitivities
+    {
+        type            surfacePoints;
+        patches         (lower upper);
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/U b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/U
new file mode 100644
index 0000000000000000000000000000000000000000..0e771a04208cbe3bdc64bde50b801f2e46c398a3
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/U
@@ -0,0 +1,55 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      U;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 3.95 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    lower
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    upper
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    Inlet
+    {
+        type            fixedValue;
+        value           uniform ( 3.95 0 0 );
+    }
+    Outlet
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/Ua b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/Ua
new file mode 100644
index 0000000000000000000000000000000000000000..1ffd585d52957272754116db8bbfb64dc7dbd2d8
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/Ua
@@ -0,0 +1,56 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      Ua;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 0 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    upper
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    Inlet
+    {
+        type            adjointInletVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    Outlet
+    {
+        type            adjointOutletVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    lower
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/nuTilda b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/nuTilda
new file mode 100644
index 0000000000000000000000000000000000000000..3d0b12a41fdd3bee435dc9c99d038adf464044b3
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/nuTilda
@@ -0,0 +1,55 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nuTilda;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -1 0 0 0 0 ];
+
+internalField   uniform 4.5e-05;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    upper
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    Inlet
+    {
+        type            fixedValue;
+        value           uniform 4.5e-05;
+    }
+    Outlet
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/nuaTilda b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/nuaTilda
new file mode 100644
index 0000000000000000000000000000000000000000..a3192e89dba6b054a074b62a2bdc15e559e5837c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/nuaTilda
@@ -0,0 +1,60 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nuaTilda;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 0 -1 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    upper
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    Inlet
+    {
+        type            adjointInletNuaTilda;
+        value           uniform 0;
+    }
+    Outlet
+    {
+        type            adjointOutletNuaTilda;
+        value           uniform 0;
+    }
+    defaultFaces
+    {
+        type            empty;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/nut b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/nut
new file mode 100644
index 0000000000000000000000000000000000000000..db4acaef62315c271b9926df62353ccd1ebb90f6
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/nut
@@ -0,0 +1,55 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nut;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -1 0 0 0 0 ];
+
+internalField   uniform 3.15e-06;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            nutUSpaldingWallFunction;
+        value           uniform 0;
+    }
+    upper
+    {
+        type            nutUSpaldingWallFunction;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            nutUSpaldingWallFunction;
+        value           uniform 0;
+    }
+    Inlet
+    {
+        type            fixedValue;
+        value           uniform 3.15e-06;
+    }
+    Outlet
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/p b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/p
new file mode 100644
index 0000000000000000000000000000000000000000..774f2a81b26ae15fe41a0eea1fb9c586a5b10fc1
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/p
@@ -0,0 +1,52 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      p;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    lower
+    {
+        type            zeroGradient;
+    }
+    upper
+    {
+        type            zeroGradient;
+    }
+    sideWall
+    {
+        type            zeroGradient;
+    }
+    Inlet
+    {
+        type            zeroGradient;
+    }
+    Outlet
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/pa b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/pa
new file mode 100644
index 0000000000000000000000000000000000000000..70eee3cc03a4d1408be7875bc0344254e3878283
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/0/pa
@@ -0,0 +1,52 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      pa;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            zeroGradient;
+    }
+    upper
+    {
+        type            zeroGradient;
+    }
+    Inlet
+    {
+        type            zeroGradient;
+    }
+    Outlet
+    {
+        type            adjointOutletPressure;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/Allclean b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/Allclean
new file mode 100755
index 0000000000000000000000000000000000000000..289939fbe9f20ab28316b31fe66c0c23743b7d8a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/Allclean
@@ -0,0 +1,7 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/CleanFunctions  # Tutorial clean functions
+
+cleanCase
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/Allrun b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/Allrun
new file mode 100755
index 0000000000000000000000000000000000000000..23b181cb454a5e592f01f84e73003e2fac51a738
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/Allrun
@@ -0,0 +1,13 @@
+#------------------------------------------------------------------------------
+#!/bin/sh
+cd ${0%/*} || exit 1                        # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/RunFunctions    # Tutorial run functions
+
+resourcesDir=$FOAM_TUTORIALS/incompressible/adjointOptimisationFoam/resources
+
+#\cp $resourcesDir/param/sbend/* 0
+\cp -r $resourcesDir/meshes/sbend/polyMesh constant
+runApplication decomposePar
+runParallel $(getApplication)
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/constant/adjointRASProperties b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/constant/adjointRASProperties
new file mode 100644
index 0000000000000000000000000000000000000000..d81bdb5ad8084041dcf3c88b0f0830896c21a5cb
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/constant/adjointRASProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      adjointTurbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+adjointRASModel adjointSpalartAllmaras;
+
+adjointTurbulence on;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/constant/dynamicMeshDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/constant/dynamicMeshDict
new file mode 100644
index 0000000000000000000000000000000000000000..31227cf2572d2a3c1dad723fed2c2575c82f71c4
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/constant/dynamicMeshDict
@@ -0,0 +1,49 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      dynamicMeshDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+solver volumetricBSplinesMotionSolver;
+
+volumetricBSplinesMotionSolverCoeffs
+{
+    controlBoxes (duct);
+    duct
+    {
+        name    duct;
+        type    cartesian;
+        nCPsU   9;
+        nCPsV   5;
+        nCPsW   3;
+        degreeU 3;
+        degreeV 3;
+        degreeW 2;
+
+        controlPointsDefinition axisAligned;
+        lowerCpBounds           (-1.1 -0.21 -0.05);
+        upperCpBounds           ( 1.1  0.39  0.15);
+
+        confineX1movement false;
+        confineX2movement false;
+        confineX3movement true;
+        confineBoundaryControlPoints false;
+
+        boundUMinCPs ( (true true true) (true true true) );
+        boundUMaxCPs ( (true true true) (true true true) );
+        boundWMinCPs ( (true true true) );
+        boundWMaxCPs ( (true true true) );
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/constant/transportProperties b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/constant/transportProperties
new file mode 100644
index 0000000000000000000000000000000000000000..cef0dd60051abf98461bee3fafc3626128f2ef1c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/constant/transportProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      transportProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+transportModel  Newtonian;
+
+nu              nu [0 2 -1 0 0 0 0] 1.5e-05;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/constant/turbulenceProperties b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/constant/turbulenceProperties
new file mode 100644
index 0000000000000000000000000000000000000000..6d738810e991241d66d4fe93ddee68390d559833
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/constant/turbulenceProperties
@@ -0,0 +1,28 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      turbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+simulationType RAS;
+
+RAS
+{
+    RASModel            SpalartAllmaras;
+
+    turbulence          on;
+
+    printCoeffs         on;
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/controlDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/controlDict
new file mode 100644
index 0000000000000000000000000000000000000000..174e9185e2ca2a7f054755c65146a7be2a31cf11
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/controlDict
@@ -0,0 +1,47 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      controlDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+application     adjointOptimisationFoam;
+
+startFrom       latestTime;
+
+startTime       0;
+
+stopAt          endTime;
+
+endTime         6000;
+
+deltaT          1;
+
+writeControl    timeStep;
+
+writeInterval   1000;
+
+purgeWrite      1;
+
+writeFormat     ascii;
+
+writePrecision  16;
+
+writeCompression true;
+
+timeFormat      general;
+
+timePrecision   6;
+
+runTimeModifiable yes;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/decomposeParDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/decomposeParDict
new file mode 100644
index 0000000000000000000000000000000000000000..77b43da11676790f1a062276cfe4f4bfff25f5aa
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/decomposeParDict
@@ -0,0 +1,26 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      decomposeParDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+numberOfSubdomains 4;
+
+method          hierarchical;
+
+coeffs
+{
+    n               (4 1 1);
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/fvSchemes b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/fvSchemes
new file mode 100644
index 0000000000000000000000000000000000000000..f1fccf1d6ea751c91ee10b9e6b567c92fe8b8746
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/fvSchemes
@@ -0,0 +1,71 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSchemes;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ddtSchemes
+{
+    default         steadyState;
+}
+
+gradSchemes
+{
+    default         Gauss linear;
+    gradDConv       cellLimited Gauss linear 1;
+}
+
+divSchemes
+{
+    default            Gauss linear;
+
+    div(phi,U)         bounded Gauss linearUpwind gradUConv;
+    div(phi,nuTilda)   bounded Gauss linearUpwind gradNuTildaConv;
+    div(yPhi,yWall)            Gauss linearUpwind gradDConv;
+    div(-phi,Ua)       bounded Gauss linearUpwind gradUaConv;
+    div(-phi,nuaTilda) bounded Gauss linearUpwind gradNuaTildaConv;
+    div(-yPhi,da)              Gauss linearUpwind gradDaConv;
+
+    div((nuEff*dev(grad(U).T()))) Gauss linear;
+    div((nuEff*dev(grad(Ua).T()))) Gauss linear;
+}
+
+laplacianSchemes
+{
+    default         Gauss linear corrected;
+
+}
+
+interpolationSchemes
+{
+    default         linear;
+}
+
+snGradSchemes
+{
+    default         corrected;
+}
+
+wallDist
+{
+    method advectionDiffusion;
+    advectionDiffusionCoeffs
+    {
+        method    meshWave;
+        tolerance 1.e-6;
+        maxIter   1000;
+        epsilon   0.1;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/fvSolution b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/fvSolution
new file mode 100644
index 0000000000000000000000000000000000000000..187302c97b6258eff52259c03f96287a5807cf07
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/fvSolution
@@ -0,0 +1,65 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSolution;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+SIMPLE
+{
+    nNonOrthogonalCorrectors 0;
+}
+
+solvers
+{
+    "p|pa"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "m|ma"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "U|Ua|nuTilda|nuaTilda|yWall|da"
+    {
+        solver           PBiCGStab;
+        preconditioner   DILU;
+        tolerance        1e-9;
+        relTol           0.1;
+    };
+}
+
+relaxationFactors
+{
+    fields
+    {
+        p               0.5;
+        pa              0.5;
+    }
+    equations
+    {
+        U               0.7;
+        Ua              0.7;
+        nuTilda         0.7;
+        nuaTilda        0.7;
+        yWall           0.7;
+        da              0.7;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/optimisationDict
new file mode 100644
index 0000000000000000000000000000000000000000..f2886862cc00f67a750de4d1015bfba0a0989402
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/highRe/system/optimisationDict
@@ -0,0 +1,101 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      optimisationDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+optimisationManager     singleRun;
+
+primalSolvers
+{
+    p1
+    {
+        active                 true;
+        type                   incompressible;
+        solver                 simple;
+        solutionControls
+        {
+            nIters 3000;
+            residualControl
+            {
+                "p.*"       1.e-7;
+                "U.*"       1.e-7;
+            }
+        }
+    }
+}
+
+adjointManagers
+{
+    am1
+    {
+        primalSolver             p1;
+        adjointSolvers
+        {
+            as1
+            {
+                // choose adjoint solver
+                //----------------------
+                active                 true;
+                type                   incompressible;
+                solver                 adjointSimple;
+
+                // manage objectives
+                //------------------
+                objectives
+                {
+                    type                incompressible;
+                    objectiveNames
+                    {
+                        losses
+                        {
+                            weight          1;
+                            type            PtLosses;
+                            patches         (Inlet Outlet);
+                        }
+                    }
+                }
+
+                // ATC treatment
+                //--------------
+                ATCModel
+                {
+                    ATCModel        standard;
+                }
+
+                // solution control
+                //------------------
+                solutionControls
+                {
+                    nIters 3000;
+                    residualControl
+                    {
+                        "pa.*"       1.e-7;
+                        "Ua.*"       1.e-7;
+                    }
+                }
+            }
+        }
+    }
+}
+
+optimisation
+{
+    sensitivities
+    {
+        type            surfacePoints;
+        patches         (lower upper);
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/U b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/U
new file mode 100644
index 0000000000000000000000000000000000000000..696f097a7d50ba5e6d86449530b1656787374421
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/U
@@ -0,0 +1,55 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      U;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 0.3 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    lower
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    upper
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    Inlet
+    {
+        type            fixedValue;
+        value           uniform ( 0.3 0 0 );
+    }
+    Outlet
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/Ua b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/Ua
new file mode 100644
index 0000000000000000000000000000000000000000..1ffd585d52957272754116db8bbfb64dc7dbd2d8
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/Ua
@@ -0,0 +1,56 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      Ua;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 0 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    upper
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    Inlet
+    {
+        type            adjointInletVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    Outlet
+    {
+        type            adjointOutletVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    lower
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/Up2 b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/Up2
new file mode 100644
index 0000000000000000000000000000000000000000..77ca2daf66f45cf781a2e4a1f341af3175f9438f
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/Up2
@@ -0,0 +1,55 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      U;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 4.95 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    lower
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    upper
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    Inlet
+    {
+        type            fixedValue;
+        value           uniform ( 4.95 0 0 );
+    }
+    Outlet
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/nuTilda b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/nuTilda
new file mode 100644
index 0000000000000000000000000000000000000000..3d0b12a41fdd3bee435dc9c99d038adf464044b3
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/nuTilda
@@ -0,0 +1,55 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nuTilda;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -1 0 0 0 0 ];
+
+internalField   uniform 4.5e-05;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    upper
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    Inlet
+    {
+        type            fixedValue;
+        value           uniform 4.5e-05;
+    }
+    Outlet
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/nuaTilda b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/nuaTilda
new file mode 100644
index 0000000000000000000000000000000000000000..a3192e89dba6b054a074b62a2bdc15e559e5837c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/nuaTilda
@@ -0,0 +1,60 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nuaTilda;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 0 -1 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    upper
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    Inlet
+    {
+        type            adjointInletNuaTilda;
+        value           uniform 0;
+    }
+    Outlet
+    {
+        type            adjointOutletNuaTilda;
+        value           uniform 0;
+    }
+    defaultFaces
+    {
+        type            empty;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/nut b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/nut
new file mode 100644
index 0000000000000000000000000000000000000000..777caf4b6c6da2e44de61f51287a63d2cb24b582
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/nut
@@ -0,0 +1,55 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nut;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -1 0 0 0 0 ];
+
+internalField   uniform 3.15e-06;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            nutLowReWallFunction;
+        value           uniform 0;
+    }
+    upper
+    {
+        type            nutLowReWallFunction;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            nutLowReWallFunction;
+        value           uniform 0;
+    }
+    Inlet
+    {
+        type            fixedValue;
+        value           uniform 3.15e-06;
+    }
+    Outlet
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/p b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/p
new file mode 100644
index 0000000000000000000000000000000000000000..774f2a81b26ae15fe41a0eea1fb9c586a5b10fc1
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/p
@@ -0,0 +1,52 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      p;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    lower
+    {
+        type            zeroGradient;
+    }
+    upper
+    {
+        type            zeroGradient;
+    }
+    sideWall
+    {
+        type            zeroGradient;
+    }
+    Inlet
+    {
+        type            zeroGradient;
+    }
+    Outlet
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/pa b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/pa
new file mode 100644
index 0000000000000000000000000000000000000000..70eee3cc03a4d1408be7875bc0344254e3878283
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/0/pa
@@ -0,0 +1,52 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      pa;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            zeroGradient;
+    }
+    upper
+    {
+        type            zeroGradient;
+    }
+    Inlet
+    {
+        type            zeroGradient;
+    }
+    Outlet
+    {
+        type            adjointOutletPressure;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/Allclean b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/Allclean
new file mode 100755
index 0000000000000000000000000000000000000000..ce71d454d9f3253a106fdbd6c1be792d72e1cf7b
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/Allclean
@@ -0,0 +1,13 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # Run from this directory
+
+# Clean time directories and processors
+rm -rf *[1-9]* processor*
+
+# Clean all optimisation outputs
+rm -rf optimisation constant/controlPoints
+
+# Clean logs
+rm -f log.* 2>/dev/null
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/Allrun b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/Allrun
new file mode 100755
index 0000000000000000000000000000000000000000..23b181cb454a5e592f01f84e73003e2fac51a738
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/Allrun
@@ -0,0 +1,13 @@
+#------------------------------------------------------------------------------
+#!/bin/sh
+cd ${0%/*} || exit 1                        # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/RunFunctions    # Tutorial run functions
+
+resourcesDir=$FOAM_TUTORIALS/incompressible/adjointOptimisationFoam/resources
+
+#\cp $resourcesDir/param/sbend/* 0
+\cp -r $resourcesDir/meshes/sbend/polyMesh constant
+runApplication decomposePar
+runParallel $(getApplication)
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/adjointRASProperties b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/adjointRASProperties
new file mode 100644
index 0000000000000000000000000000000000000000..d81bdb5ad8084041dcf3c88b0f0830896c21a5cb
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/adjointRASProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      adjointTurbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+adjointRASModel adjointSpalartAllmaras;
+
+adjointTurbulence on;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/dynamicMeshDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/dynamicMeshDict
new file mode 100644
index 0000000000000000000000000000000000000000..31227cf2572d2a3c1dad723fed2c2575c82f71c4
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/dynamicMeshDict
@@ -0,0 +1,49 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      dynamicMeshDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+solver volumetricBSplinesMotionSolver;
+
+volumetricBSplinesMotionSolverCoeffs
+{
+    controlBoxes (duct);
+    duct
+    {
+        name    duct;
+        type    cartesian;
+        nCPsU   9;
+        nCPsV   5;
+        nCPsW   3;
+        degreeU 3;
+        degreeV 3;
+        degreeW 2;
+
+        controlPointsDefinition axisAligned;
+        lowerCpBounds           (-1.1 -0.21 -0.05);
+        upperCpBounds           ( 1.1  0.39  0.15);
+
+        confineX1movement false;
+        confineX2movement false;
+        confineX3movement true;
+        confineBoundaryControlPoints false;
+
+        boundUMinCPs ( (true true true) (true true true) );
+        boundUMaxCPs ( (true true true) (true true true) );
+        boundWMinCPs ( (true true true) );
+        boundWMaxCPs ( (true true true) );
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/boundary.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/boundary.gz
new file mode 100644
index 0000000000000000000000000000000000000000..bd3a9aa3cf6f539df10ce2b4652ea3333e156a1f
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/boundary.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/faces.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/faces.gz
new file mode 100644
index 0000000000000000000000000000000000000000..33a847f04e4788e8e15e724bc3fee8a1bf470d99
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/faces.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/neighbour.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/neighbour.gz
new file mode 100644
index 0000000000000000000000000000000000000000..59dd2075e3b663319e99a3a4bc36d1af701c8a8c
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/neighbour.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/owner.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/owner.gz
new file mode 100644
index 0000000000000000000000000000000000000000..3372e6e3693f0078d46c1c1ea84765d54eae6565
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/owner.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/points.gz b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/points.gz
new file mode 100644
index 0000000000000000000000000000000000000000..4177ef3e35ae9722f8a57d824e352bc9c7ce4ee1
Binary files /dev/null and b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/polyMesh/points.gz differ
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/transportProperties b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/transportProperties
new file mode 100644
index 0000000000000000000000000000000000000000..cef0dd60051abf98461bee3fafc3626128f2ef1c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/transportProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      transportProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+transportModel  Newtonian;
+
+nu              nu [0 2 -1 0 0 0 0] 1.5e-05;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/turbulenceProperties b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/turbulenceProperties
new file mode 100644
index 0000000000000000000000000000000000000000..6d738810e991241d66d4fe93ddee68390d559833
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/constant/turbulenceProperties
@@ -0,0 +1,28 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      turbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+simulationType RAS;
+
+RAS
+{
+    RASModel            SpalartAllmaras;
+
+    turbulence          on;
+
+    printCoeffs         on;
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/controlDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/controlDict
new file mode 100644
index 0000000000000000000000000000000000000000..d3c688c299ecc80bb548004a3d1b32fae6cf118a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/controlDict
@@ -0,0 +1,47 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      controlDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+application       adjointOptimisationFoam;
+
+startFrom         latestTime;
+
+startTime         0;
+
+stopAt            endTime;
+
+endTime           1000;
+
+deltaT            1;
+
+writeControl      timeStep;
+
+writeInterval     1000;
+
+purgeWrite        0;
+
+writeFormat       ascii;
+
+writePrecision    16;
+
+writeCompression  true;
+
+timeFormat        general;
+
+timePrecision     6;
+
+runTimeModifiable yes;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/decomposeParDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/decomposeParDict
new file mode 100644
index 0000000000000000000000000000000000000000..77b43da11676790f1a062276cfe4f4bfff25f5aa
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/decomposeParDict
@@ -0,0 +1,26 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      decomposeParDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+numberOfSubdomains 4;
+
+method          hierarchical;
+
+coeffs
+{
+    n               (4 1 1);
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/fvSchemes b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/fvSchemes
new file mode 100644
index 0000000000000000000000000000000000000000..2d4fa3751c799671a5721487328ca2ef2ddc5ed1
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/fvSchemes
@@ -0,0 +1,75 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSchemes;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ddtSchemes
+{
+    default         steadyState;
+}
+
+gradSchemes
+{
+    default         Gauss linear;
+    gradDConv       cellLimited Gauss linear 1;
+}
+
+divSchemes
+{
+    default            Gauss linear;
+
+    div(phip1,Up1)         bounded Gauss linearUpwind gradUConv;
+    div(phip1,nuTildap1)   bounded Gauss linearUpwind gradNuTildaConv;
+    div(phip2,Up2)         bounded Gauss linearUpwind gradUConv;
+    div(phip2,nuTildap2)   bounded Gauss linearUpwind gradNuTildaConv;
+
+    div(yPhi,yWall)                Gauss linearUpwind gradDConv;
+
+    div(-phip1,Uaas1)       bounded Gauss linearUpwind gradUaConv;
+    div(-phip1,nuaTildaas1) bounded Gauss linearUpwind gradNuaTildaConv;
+    div(-phip2,Uaas2)       bounded Gauss linearUpwind gradUaConv;
+    div(-phip2,nuaTildaas2) bounded Gauss linearUpwind gradNuaTildaConv;
+
+    div(-yPhi,da)              Gauss linearUpwind gradDaConv;
+}
+
+laplacianSchemes
+{
+    default         Gauss linear corrected;
+
+}
+
+interpolationSchemes
+{
+    default         linear;
+}
+
+snGradSchemes
+{
+    default         corrected;
+}
+
+wallDist
+{
+    method advectionDiffusion;
+    advectionDiffusionCoeffs
+    {
+        method    meshWave;
+        tolerance 1.e-6;
+        maxIter   1000;
+        epsilon   0.1;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/fvSolution b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/fvSolution
new file mode 100644
index 0000000000000000000000000000000000000000..741ebe3295829a69fc43c8c2a3a4fb42112069ca
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/fvSolution
@@ -0,0 +1,65 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSolution;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+SIMPLE
+{
+    nNonOrthogonalCorrectors 0;
+}
+
+solvers
+{
+    "p.*|pa.*"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "m.*|ma.*"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "U.*|Ua.*|nuTilda.*|nuaTilda.*|yWall|da"
+    {
+        solver           PBiCGStab;
+        preconditioner   DILU;
+        tolerance        1e-9;
+        relTol           0.1;
+    };
+}
+
+relaxationFactors
+{
+    fields
+    {
+       "p.*"            0.5;
+       "pa.*"           0.5;
+    }
+    equations
+    {
+        "U.*"           0.7;
+        "Ua.*"          0.7;
+        "nuTilda.*"     0.7;
+        "nuaTilda.*"    0.7;
+        yWall           0.7;
+        da              0.7;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/optimisationDict
new file mode 100644
index 0000000000000000000000000000000000000000..5e38709fefe8872f14703783c9c046a40acc629a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/multiPoint/system/optimisationDict
@@ -0,0 +1,177 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      optimisationDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+optimisationManager     singleRun;
+
+primalSolvers
+{
+    p1
+    {
+        active                 true;
+        type                   incompressible;
+        solver                 simple;
+        useSolverNameForFields true;
+
+        solutionControls
+        {
+            nIters 3000;
+            residualControl
+            {
+                "p.*"       1.e-7;
+                "U.*"       1.e-7;
+                "nuTilda.*" 1.e-7;
+            }
+        }
+    }
+    p2
+    {
+        active                 true;
+        type                   incompressible;
+        solver                 simple;
+        useSolverNameForFields true;
+
+        solutionControls
+        {
+            nIters 3000;
+            residualControl
+            {
+                "p.*"       1.e-7;
+                "U.*"       1.e-7;
+                "nuTilda.*" 1.e-7;
+            }
+        }
+    }
+}
+
+adjointManagers
+{
+    am1
+    {
+        primalSolver             p1;
+        operatingPointWeight     1;
+        adjointSolvers
+        {
+            as1
+            {
+                // choose adjoint solver
+                //----------------------
+                active                 true;
+                type                   incompressible;
+                solver                 adjointSimple;
+                useSolverNameForFields true;
+
+                // manage objectives
+                //------------------
+                objectives
+                {
+                    type                incompressible;
+                    objectiveNames
+                    {
+                        losses
+                        {
+                            weight          1;
+                            type            PtLosses;
+                            patches         (Inlet Outlet);
+                        }
+                    }
+                }
+
+                // ATC treatment
+                //--------------
+                ATCModel
+                {
+                    ATCModel        standard;
+                }
+
+                // solution control
+                //------------------
+                solutionControls
+                {
+                    nIters 3000;
+                    residualControl
+                    {
+                        "pa.*"       1.e-7;
+                        "Ua.*"       1.e-7;
+                        "nuaTilda.*" 1.e-7;
+                    }
+                }
+            }
+        }
+    }
+    am2
+    {
+        primalSolver             p2;
+        operatingPointWeight     300;
+        adjointSolvers
+        {
+            as2
+            {
+                // choose adjoint solver
+                //----------------------
+                active                 true;
+                type                   incompressible;
+                solver                 adjointSimple;
+                useSolverNameForFields true;
+
+                // manage objectives
+                //------------------
+                objectives
+                {
+                    type                incompressible;
+                    objectiveNames
+                    {
+                        losses
+                        {
+                            weight              1;
+                            type                PtLosses;
+                        }
+                    }
+                }
+
+                // ATC treatment
+                //--------------
+                ATCModel
+                {
+                    ATCModel        standard;
+                }
+
+                // solution control
+                //------------------
+                solutionControls
+                {
+                    nIters 3000;
+                    residualControl
+                    {
+                        "pa.*"       1.e-7;
+                        "Ua.*"       1.e-7;
+                        "nuaTilda.*" 1.e-7;
+                    }
+                }
+            }
+        }
+    }
+}
+
+optimisation
+{
+    sensitivities
+    {
+        type                surfacePoints;
+        patches             (lower upper);
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/U b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/U
new file mode 100644
index 0000000000000000000000000000000000000000..0e771a04208cbe3bdc64bde50b801f2e46c398a3
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/U
@@ -0,0 +1,55 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      U;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 3.95 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    lower
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    upper
+    {
+        type            fixedValue;
+        value           uniform ( 0 0 0 );
+    }
+    Inlet
+    {
+        type            fixedValue;
+        value           uniform ( 3.95 0 0 );
+    }
+    Outlet
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/Ua b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/Ua
new file mode 100644
index 0000000000000000000000000000000000000000..1ffd585d52957272754116db8bbfb64dc7dbd2d8
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/Ua
@@ -0,0 +1,56 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volVectorField;
+    location    "0";
+    object      Ua;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 1 -1 0 0 0 0 ];
+
+internalField   uniform ( 0 0 0 );
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    upper
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    Inlet
+    {
+        type            adjointInletVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    Outlet
+    {
+        type            adjointOutletVelocity;
+        value           uniform ( 0 0 0 );
+    }
+    lower
+    {
+        type            adjointWallVelocity;
+        value           uniform ( 0 0 0 );
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/nuTilda b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/nuTilda
new file mode 100644
index 0000000000000000000000000000000000000000..3d0b12a41fdd3bee435dc9c99d038adf464044b3
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/nuTilda
@@ -0,0 +1,55 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nuTilda;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -1 0 0 0 0 ];
+
+internalField   uniform 4.5e-05;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    upper
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    Inlet
+    {
+        type            fixedValue;
+        value           uniform 4.5e-05;
+    }
+    Outlet
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/nuaTilda b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/nuaTilda
new file mode 100644
index 0000000000000000000000000000000000000000..a3192e89dba6b054a074b62a2bdc15e559e5837c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/nuaTilda
@@ -0,0 +1,60 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nuaTilda;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 0 -1 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    upper
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+    Inlet
+    {
+        type            adjointInletNuaTilda;
+        value           uniform 0;
+    }
+    Outlet
+    {
+        type            adjointOutletNuaTilda;
+        value           uniform 0;
+    }
+    defaultFaces
+    {
+        type            empty;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/nut b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/nut
new file mode 100644
index 0000000000000000000000000000000000000000..777caf4b6c6da2e44de61f51287a63d2cb24b582
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/nut
@@ -0,0 +1,55 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      nut;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -1 0 0 0 0 ];
+
+internalField   uniform 3.15e-06;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            nutLowReWallFunction;
+        value           uniform 0;
+    }
+    upper
+    {
+        type            nutLowReWallFunction;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            nutLowReWallFunction;
+        value           uniform 0;
+    }
+    Inlet
+    {
+        type            fixedValue;
+        value           uniform 3.15e-06;
+    }
+    Outlet
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/p b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/p
new file mode 100644
index 0000000000000000000000000000000000000000..774f2a81b26ae15fe41a0eea1fb9c586a5b10fc1
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/p
@@ -0,0 +1,52 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      p;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    lower
+    {
+        type            zeroGradient;
+    }
+    upper
+    {
+        type            zeroGradient;
+    }
+    sideWall
+    {
+        type            zeroGradient;
+    }
+    Inlet
+    {
+        type            zeroGradient;
+    }
+    Outlet
+    {
+        type            fixedValue;
+        value           uniform 0;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/pa b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/pa
new file mode 100644
index 0000000000000000000000000000000000000000..70eee3cc03a4d1408be7875bc0344254e3878283
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/0/pa
@@ -0,0 +1,52 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1812                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       volScalarField;
+    location    "0";
+    object      pa;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+dimensions      [ 0 2 -2 0 0 0 0 ];
+
+internalField   uniform 0;
+
+boundaryField
+{
+    frontBack
+    {
+        type            empty;
+    }
+    sideWall
+    {
+        type            zeroGradient;
+    }
+    upper
+    {
+        type            zeroGradient;
+    }
+    Inlet
+    {
+        type            zeroGradient;
+    }
+    Outlet
+    {
+        type            adjointOutletPressure;
+        value           uniform 0;
+    }
+    lower
+    {
+        type            zeroGradient;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/Allclean b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/Allclean
new file mode 100755
index 0000000000000000000000000000000000000000..289939fbe9f20ab28316b31fe66c0c23743b7d8a
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/Allclean
@@ -0,0 +1,7 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/CleanFunctions  # Tutorial clean functions
+
+cleanCase
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/Allrun b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/Allrun
new file mode 100755
index 0000000000000000000000000000000000000000..23b181cb454a5e592f01f84e73003e2fac51a738
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/Allrun
@@ -0,0 +1,13 @@
+#------------------------------------------------------------------------------
+#!/bin/sh
+cd ${0%/*} || exit 1                        # Run from this directory
+. $WM_PROJECT_DIR/bin/tools/RunFunctions    # Tutorial run functions
+
+resourcesDir=$FOAM_TUTORIALS/incompressible/adjointOptimisationFoam/resources
+
+#\cp $resourcesDir/param/sbend/* 0
+\cp -r $resourcesDir/meshes/sbend/polyMesh constant
+runApplication decomposePar
+runParallel $(getApplication)
+
+#------------------------------------------------------------------------------
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/constant/adjointRASProperties b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/constant/adjointRASProperties
new file mode 100644
index 0000000000000000000000000000000000000000..d81bdb5ad8084041dcf3c88b0f0830896c21a5cb
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/constant/adjointRASProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      adjointTurbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+adjointRASModel adjointSpalartAllmaras;
+
+adjointTurbulence on;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/constant/dynamicMeshDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/constant/dynamicMeshDict
new file mode 100644
index 0000000000000000000000000000000000000000..31227cf2572d2a3c1dad723fed2c2575c82f71c4
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/constant/dynamicMeshDict
@@ -0,0 +1,49 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      dynamicMeshDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+solver volumetricBSplinesMotionSolver;
+
+volumetricBSplinesMotionSolverCoeffs
+{
+    controlBoxes (duct);
+    duct
+    {
+        name    duct;
+        type    cartesian;
+        nCPsU   9;
+        nCPsV   5;
+        nCPsW   3;
+        degreeU 3;
+        degreeV 3;
+        degreeW 2;
+
+        controlPointsDefinition axisAligned;
+        lowerCpBounds           (-1.1 -0.21 -0.05);
+        upperCpBounds           ( 1.1  0.39  0.15);
+
+        confineX1movement false;
+        confineX2movement false;
+        confineX3movement true;
+        confineBoundaryControlPoints false;
+
+        boundUMinCPs ( (true true true) (true true true) );
+        boundUMaxCPs ( (true true true) (true true true) );
+        boundWMinCPs ( (true true true) );
+        boundWMaxCPs ( (true true true) );
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/constant/transportProperties b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/constant/transportProperties
new file mode 100644
index 0000000000000000000000000000000000000000..cef0dd60051abf98461bee3fafc3626128f2ef1c
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/constant/transportProperties
@@ -0,0 +1,21 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      transportProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+transportModel  Newtonian;
+
+nu              nu [0 2 -1 0 0 0 0] 1.5e-05;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/constant/turbulenceProperties b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/constant/turbulenceProperties
new file mode 100644
index 0000000000000000000000000000000000000000..6d738810e991241d66d4fe93ddee68390d559833
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/constant/turbulenceProperties
@@ -0,0 +1,28 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      turbulenceProperties;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+simulationType RAS;
+
+RAS
+{
+    RASModel            SpalartAllmaras;
+
+    turbulence          on;
+
+    printCoeffs         on;
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/controlDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/controlDict
new file mode 100644
index 0000000000000000000000000000000000000000..174e9185e2ca2a7f054755c65146a7be2a31cf11
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/controlDict
@@ -0,0 +1,47 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      controlDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+application     adjointOptimisationFoam;
+
+startFrom       latestTime;
+
+startTime       0;
+
+stopAt          endTime;
+
+endTime         6000;
+
+deltaT          1;
+
+writeControl    timeStep;
+
+writeInterval   1000;
+
+purgeWrite      1;
+
+writeFormat     ascii;
+
+writePrecision  16;
+
+writeCompression true;
+
+timeFormat      general;
+
+timePrecision   6;
+
+runTimeModifiable yes;
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/decomposeParDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/decomposeParDict
new file mode 100644
index 0000000000000000000000000000000000000000..77b43da11676790f1a062276cfe4f4bfff25f5aa
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/decomposeParDict
@@ -0,0 +1,26 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      decomposeParDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+numberOfSubdomains 4;
+
+method          hierarchical;
+
+coeffs
+{
+    n               (4 1 1);
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/fvSchemes b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/fvSchemes
new file mode 100644
index 0000000000000000000000000000000000000000..f1fccf1d6ea751c91ee10b9e6b567c92fe8b8746
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/fvSchemes
@@ -0,0 +1,71 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSchemes;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+ddtSchemes
+{
+    default         steadyState;
+}
+
+gradSchemes
+{
+    default         Gauss linear;
+    gradDConv       cellLimited Gauss linear 1;
+}
+
+divSchemes
+{
+    default            Gauss linear;
+
+    div(phi,U)         bounded Gauss linearUpwind gradUConv;
+    div(phi,nuTilda)   bounded Gauss linearUpwind gradNuTildaConv;
+    div(yPhi,yWall)            Gauss linearUpwind gradDConv;
+    div(-phi,Ua)       bounded Gauss linearUpwind gradUaConv;
+    div(-phi,nuaTilda) bounded Gauss linearUpwind gradNuaTildaConv;
+    div(-yPhi,da)              Gauss linearUpwind gradDaConv;
+
+    div((nuEff*dev(grad(U).T()))) Gauss linear;
+    div((nuEff*dev(grad(Ua).T()))) Gauss linear;
+}
+
+laplacianSchemes
+{
+    default         Gauss linear corrected;
+
+}
+
+interpolationSchemes
+{
+    default         linear;
+}
+
+snGradSchemes
+{
+    default         corrected;
+}
+
+wallDist
+{
+    method advectionDiffusion;
+    advectionDiffusionCoeffs
+    {
+        method    meshWave;
+        tolerance 1.e-6;
+        maxIter   1000;
+        epsilon   0.1;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/fvSolution b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/fvSolution
new file mode 100644
index 0000000000000000000000000000000000000000..187302c97b6258eff52259c03f96287a5807cf07
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/fvSolution
@@ -0,0 +1,65 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      fvSolution;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+SIMPLE
+{
+    nNonOrthogonalCorrectors 0;
+}
+
+solvers
+{
+    "p|pa"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "m|ma"
+    {
+        solver           PCG;
+        preconditioner   DIC;
+        tolerance        1e-9;
+        relTol           0.01;
+    };
+    "U|Ua|nuTilda|nuaTilda|yWall|da"
+    {
+        solver           PBiCGStab;
+        preconditioner   DILU;
+        tolerance        1e-9;
+        relTol           0.1;
+    };
+}
+
+relaxationFactors
+{
+    fields
+    {
+        p               0.5;
+        pa              0.5;
+    }
+    equations
+    {
+        U               0.7;
+        Ua              0.7;
+        nuTilda         0.7;
+        nuaTilda        0.7;
+        yWall           0.7;
+        da              0.7;
+    }
+}
+
+// ************************************************************************* //
diff --git a/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/optimisationDict
new file mode 100644
index 0000000000000000000000000000000000000000..f2886862cc00f67a750de4d1015bfba0a0989402
--- /dev/null
+++ b/tutorials/incompressible/adjointOptimisationFoam/sbend/turbulent/lowRe/singlePoint/system/optimisationDict
@@ -0,0 +1,101 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  1812                                  |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      optimisationDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+optimisationManager     singleRun;
+
+primalSolvers
+{
+    p1
+    {
+        active                 true;
+        type                   incompressible;
+        solver                 simple;
+        solutionControls
+        {
+            nIters 3000;
+            residualControl
+            {
+                "p.*"       1.e-7;
+                "U.*"       1.e-7;
+            }
+        }
+    }
+}
+
+adjointManagers
+{
+    am1
+    {
+        primalSolver             p1;
+        adjointSolvers
+        {
+            as1
+            {
+                // choose adjoint solver
+                //----------------------
+                active                 true;
+                type                   incompressible;
+                solver                 adjointSimple;
+
+                // manage objectives
+                //------------------
+                objectives
+                {
+                    type                incompressible;
+                    objectiveNames
+                    {
+                        losses
+                        {
+                            weight          1;
+                            type            PtLosses;
+                            patches         (Inlet Outlet);
+                        }
+                    }
+                }
+
+                // ATC treatment
+                //--------------
+                ATCModel
+                {
+                    ATCModel        standard;
+                }
+
+                // solution control
+                //------------------
+                solutionControls
+                {
+                    nIters 3000;
+                    residualControl
+                    {
+                        "pa.*"       1.e-7;
+                        "Ua.*"       1.e-7;
+                    }
+                }
+            }
+        }
+    }
+}
+
+optimisation
+{
+    sensitivities
+    {
+        type            surfacePoints;
+        patches         (lower upper);
+    }
+}
+
+// ************************************************************************* //