From 4d67819a2c3f654498eca182d180d7cf1a43f44a Mon Sep 17 00:00:00 2001
From: Vaggelis Papoutsis <vaggelisp@gmail.com>
Date: Thu, 14 May 2020 18:06:27 +0300
Subject: [PATCH] ENH: changes related to when the objective value is written

- Objective now inherits from localIOdictionary and writes the mean
objective value under the uniform folder, each time mesh.write() is
called. This is crucial for getting the correct old merit function value
if the simulation is continued from a previous state and lineSearch is
used.
- Objectives are now computed and written even if the corresponding
adjoint solver is inactive. This, among others, is also essential for
getting the correct old merit function value in case of continuation.
- Writing of the objective function (and its mean, if present) history
has now moved to updatePrimalBasedQuantities, instead of the preLoop
part of the adjoint solvers. This was decided to get the objective
values to files, even if the adjoint solver is inactive. Arguably, an
even better place to write the objective functions would be the postLoop
part of the primal solvers, however this might cause multiple writes of
the objective value for the inner iterations of lineSearch, if one is
used.
---
 .../adjoint/objectives/objective/objective.C  | 56 ++++++++-----------
 .../adjoint/objectives/objective/objective.H  | 14 ++++-
 .../adjointSimple/adjointSimple.C             | 16 ++++--
 .../adjointSimple/adjointSimple.H             | 12 +++-
 .../incompressiblePrimalSolver.C              |  6 +-
 5 files changed, 60 insertions(+), 44 deletions(-)

diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.C b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.C
index 975813fdbc9..a8ee9c77e15 100644
--- a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.C
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.C
@@ -106,6 +106,22 @@ objective::objective
     const word& primalSolverName
 )
 :
+    localIOdictionary
+    (
+        IOobject
+        (
+            dict.dictName(),
+            mesh.time().timeName(),
+            fileName("uniform")/fileName("objectives")/adjointSolverName,
+            mesh,
+            IOobject::READ_IF_PRESENT,
+            IOobject::AUTO_WRITE
+        ),
+        // avoid type checking since dictionary is read using the
+        // derived type name and type() will result in "objective"
+        // here
+        word::null
+    ),
     mesh_(mesh),
     dict_(dict),
     adjointSolverName_(adjointSolverName),
@@ -115,7 +131,7 @@ objective::objective
     nullified_(false),
 
     J_(Zero),
-    JMean_(Zero),
+    JMean_(this->getOrDefault<scalar>("JMean", Zero)),
     weight_(Zero),
 
     integrationStartTimePtr_(nullptr),
@@ -158,21 +174,6 @@ objective::objective
             new scalar(dict.get<scalar>("integrationEndTime"))
         );
     }
-
-    // Read JMean from dictionary, if present
-    IOobject headObjectiveIODict
-    (
-        "objectiveDict" + objectiveName_,
-        mesh_.time().timeName(),
-        "uniform",
-        mesh_,
-        IOobject::READ_IF_PRESENT,
-        IOobject::NO_WRITE
-    );
-    if (headObjectiveIODict.typeHeaderOk<IOdictionary>(false))
-    {
-        JMean_ = IOdictionary(headObjectiveIODict).get<scalar>("JMean");
-    }
 }
 
 
@@ -660,22 +661,13 @@ void objective::writeMeanValue() const
                 << mesh_.time().value() << tab << JMean_ << endl;
         }
     }
-    // Write mean value under time/uniform, to allow for lineSearch to work
-    // appropriately in continuation runs, when field averaging is used
-    IOdictionary objectiveDict
-    (
-        IOobject
-        (
-            "objectiveDict" + objectiveName_,
-            mesh_.time().timeName(),
-            "uniform",
-            mesh_,
-            IOobject::NO_READ,
-            IOobject::NO_WRITE
-        )
-    );
-    objectiveDict.add<scalar>("JMean", JMean_);
-    objectiveDict.regIOobject::write();
+}
+
+
+bool objective::writeData(Ostream& os) const
+{
+    os.writeEntry("JMean", JMean_);
+    return os.good();
 }
 
 
diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.H b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.H
index 7b6a3aa3d49..7fc69c3f5f9 100644
--- a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.H
+++ b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.H
@@ -40,6 +40,7 @@ SourceFiles
 #ifndef objective_H
 #define objective_H
 
+#include "localIOdictionary.H"
 #include "autoPtr.H"
 #include "runTimeSelectionTables.H"
 #include "OFstream.H"
@@ -57,6 +58,8 @@ namespace Foam
 \*---------------------------------------------------------------------------*/
 
 class objective
+:
+    public localIOdictionary
 {
 protected:
 
@@ -70,9 +73,13 @@ protected:
         bool computeMeanFields_;
         bool nullified_;
 
-        // Objective function value and weight
+        //- Objective function value and weight
         scalar J_;
-        scalar JMean_;  //average value
+
+        //- Average objective value
+        scalar JMean_;
+
+        //- Objective weight
         scalar weight_;
 
         // Objective integration start and end times (for unsteady flows)
@@ -361,6 +368,9 @@ public:
         //- Write mean objective function history
         virtual void writeMeanValue() const;
 
+        //- Write averaged objective for continuation
+        virtual bool writeData(Ostream& os) const;
+
         // Inline functions for checking whether pointers are set or not
         inline const word& objectiveName() const;
         inline bool hasdJdb() const;
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C
index d59f6e93471..8b54effb8ac 100644
--- a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C
@@ -5,8 +5,8 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2007-2019 PCOpt/NTUA
-    Copyright (C) 2013-2019 FOSS GP
+    Copyright (C) 2007-2020 PCOpt/NTUA
+    Copyright (C) 2013-2020 FOSS GP
     Copyright (C) 2019 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
@@ -312,9 +312,6 @@ void Foam::adjointSimple::solve()
 {
     if (active_)
     {
-        // Update objective function related quantities
-        objectiveManagerPtr_->updateAndWrite();
-
         // Reset mean fields before solving
         adjointVars_.resetMeanFields();
 
@@ -389,6 +386,15 @@ Foam::sensitivity& Foam::adjointSimple::getSensitivityBase()
 }
 
 
+void Foam::adjointSimple::updatePrimalBasedQuantities()
+{
+    incompressibleAdjointSolver::updatePrimalBasedQuantities();
+
+    // Update objective function related quantities
+    objectiveManagerPtr_->updateAndWrite();
+}
+
+
 bool Foam::adjointSimple::writeData(Ostream& os) const
 {
     os.writeEntry("averageIter", solverControl_().averageIter());
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.H b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.H
index 14b348f632f..a5884247be4 100644
--- a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.H
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.H
@@ -5,8 +5,8 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2007-2019 PCOpt/NTUA
-    Copyright (C) 2013-2019 FOSS GP
+    Copyright (C) 2007-2020 PCOpt/NTUA
+    Copyright (C) 2013-2020 FOSS GP
     Copyright (C) 2019 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
@@ -168,6 +168,14 @@ public:
             //- Return the base sensitivity object
             virtual sensitivity& getSensitivityBase();
 
+            //- Update primal based quantities
+            //- related to the objective functions.
+            //  Also writes the objective function values to files.
+            //  Written here and not in the postLoop function of the primal
+            //  to make sure we don't pollute the objective files with
+            //  objectives of non-converged linearSearch iterations
+            virtual void updatePrimalBasedQuantities();
+
             //- Write average iteration
             virtual bool writeData(Ostream& os) const;
 };
diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.C b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.C
index bfc3a4bc11a..f1f50530e36 100644
--- a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.C
+++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.C
@@ -5,8 +5,8 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2007-2019 PCOpt/NTUA
-    Copyright (C) 2013-2019 FOSS GP
+    Copyright (C) 2007-2020 PCOpt/NTUA
+    Copyright (C) 2013-2020 FOSS GP
     Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
@@ -130,7 +130,7 @@ Foam::incompressiblePrimalSolver::getObjectiveFunctions() const
     {
         adjointSolver& adjoint = *adjointPtr;
 
-        if (adjoint.active() && adjoint.primalSolverName() == solverName_)
+        if (adjoint.primalSolverName() == solverName_)
         {
             PtrList<objective>& managerObjectives =
                 adjoint.getObjectiveManager().getObjectiveFunctions();
-- 
GitLab