adjointSimple.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2007-2021 PCOpt/NTUA
9  Copyright (C) 2013-2021 FOSS GP
10  Copyright (C) 2019-2020 OpenCFD Ltd.
11 -------------------------------------------------------------------------------
12 License
13  This file is part of OpenFOAM.
14 
15  OpenFOAM is free software: you can redistribute it and/or modify it
16  under the terms of the GNU General Public License as published by
17  the Free Software Foundation, either version 3 of the License, or
18  (at your option) any later version.
19 
20  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
21  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23  for more details.
24 
25  You should have received a copy of the GNU General Public License
26  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
27 
28 \*---------------------------------------------------------------------------*/
29 
30 #include "adjointSimple.H"
31 #include "findRefCell.H"
32 #include "constrainHbyA.H"
33 #include "adjustPhi.H"
34 #include "fvOptions.H"
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41  defineTypeNameAndDebug(adjointSimple, 0);
43  (
44  incompressibleAdjointSolver,
45  adjointSimple,
47  );
48 }
49 
50 
51 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
52 
54 {
55  vars_.reset
56  (
58  (
59  mesh_,
63  )
64  );
65  return getAdjointVars();
66 }
67 
68 
70 {
71  if (adjointVars_.useSolverNameForFields())
72  {
74  << "useSolverNameForFields is set to true for adjointSolver "
75  << solverName() << nl << tab
76  << "Appending variable names with the solver name" << nl << tab
77  << "Please adjust the necessary entries in fvSchemes and fvSolution"
78  << nl << endl;
79  }
80 }
81 
82 
84 {
85  const surfaceScalarField& phia = adjointVars_.phiaInst();
87 
88  scalar sumLocalContErr = mesh_.time().deltaTValue()*
89  mag(contErr)().weightedAverage(mesh_.V()).value();
90 
91  scalar globalContErr = mesh_.time().deltaTValue()*
92  contErr.weightedAverage(mesh_.V()).value();
93  cumulativeContErr_ += globalContErr;
94 
95  Info<< "time step continuity errors : sum local = " << sumLocalContErr
96  << ", global = " << globalContErr
97  << ", cumulative = " << cumulativeContErr_
98  << endl;
99 }
100 
101 
102 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
103 
104 Foam::adjointSimple::adjointSimple
105 (
106  fvMesh& mesh,
107  const word& managerType,
108  const dictionary& dict,
109  const word& primalSolverName
110 )
111 :
112  incompressibleAdjointSolver(mesh, managerType, dict, primalSolverName),
113  solverControl_(SIMPLEControl::New(mesh, managerType, *this)),
114  adjointVars_(allocateVars()),
115  cumulativeContErr_(Zero),
116  adjointSensitivity_(nullptr)
117 {
118  ATCModel_.reset
119  (
121  (
122  mesh,
123  primalVars_,
124  adjointVars_,
125  dict.subDict("ATCModel")
126  ).ptr()
127  );
128 
129  addExtraSchemes();
130  setRefCell
131  (
133  solverControl_().dict(),
134  solverControl_().pRefCell(),
135  solverControl_().pRefValue()
136  );
137 
139  {
140  const IOdictionary& optDict =
141  mesh.lookupObject<IOdictionary>("optimisationDict");
142 
143  adjointSensitivity_.reset
144  (
146  (
147  mesh,
148  optDict.subDict("optimisation").subDict("sensitivities"),
149  *this
150  ).ptr()
151  );
152  // Read stored sensitivities, if they exist
153  // Need to know the size of the sensitivity field, retrieved after the
154  // allocation of the corresponding object
155  if (dictionary::found("sensitivities"))
156  {
159  (
160  "sensitivities",
161  *this,
162  adjointSensitivity_().getSensitivities().size()
163  );
164  }
165  }
166 }
167 
168 
169 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
170 
171 bool Foam::adjointSimple::readDict(const dictionary& dict)
172 {
174  {
175  if (adjointSensitivity_)
176  {
177  const IOdictionary& optDict =
178  mesh_.lookupObject<IOdictionary>("optimisationDict");
179 
180  adjointSensitivity_().readDict
181  (
182  optDict.subDict("optimisation").subDict("sensitivities")
183  );
184  }
185 
186  return true;
187  }
188 
189  return false;
190 }
191 
192 
194 {
195  preIter();
196  mainIter();
197  postIter();
198 }
199 
202 {
203  Info<< "Time = " << mesh_.time().timeName() << "\n" << endl;
204 }
205 
206 
208 {
209  addProfiling(adjointSimple, "adjointSimple::mainIter");
210  // Grab primal references
211  const surfaceScalarField& phi = primalVars_.phi();
212  // Grab adjoint references
213  volScalarField& pa = adjointVars_.paInst();
214  volVectorField& Ua = adjointVars_.UaInst();
215  surfaceScalarField& phia = adjointVars_.phiaInst();
217  adjointVars_.adjointTurbulence();
218  const label& paRefCell = solverControl_().pRefCell();
219  const scalar& paRefValue = solverControl_().pRefValue();
220  fv::options& fvOptions(fv::options::New(this->mesh_));
221 
222  // Momentum predictor
223  //~~~~~~~~~~~~~~~~~~~
224 
225  tmp<fvVectorMatrix> tUaEqn
226  (
227  fvm::div(-phi, Ua)
228  + adjointTurbulence->divDevReff(Ua)
229  + adjointTurbulence->adjointMeanFlowSource()
230  ==
231  fvOptions(Ua)
232  );
233  fvVectorMatrix& UaEqn = tUaEqn.ref();
234 
235  // Add sources from boundary conditions
236  UaEqn.boundaryManipulate(Ua.boundaryFieldRef());
237 
238  // Add sources from volume-based objectives
239  objectiveManagerPtr_().addUaEqnSource(UaEqn);
240 
241  // Add ATC term
242  ATCModel_->addATC(UaEqn);
243 
244  // Additional source terms (e.g. energy equation)
245  addMomentumSource(UaEqn);
246 
247  UaEqn.relax();
248 
249  fvOptions.constrain(UaEqn);
250 
251  if (solverControl_().momentumPredictor())
252  {
253  Foam::solve(UaEqn == -fvc::grad(pa));
254 
255  fvOptions.correct(Ua);
256  }
257 
258  // Pressure Eq
259  //~~~~~~~~~~~~
260  {
261  volScalarField rAUa(1.0/UaEqn.A());
262  // 190402: Vag: to be updated.
263  // Probably a constrainHabyA by class is needed?
264  volVectorField HabyA(constrainHbyA(rAUa*UaEqn.H(), Ua, pa));
265  surfaceScalarField phiaHbyA("phiaHbyA", fvc::flux(HabyA));
266  adjustPhi(phiaHbyA, Ua, pa);
267 
268  tmp<volScalarField> rAtUa(rAUa);
269 
270  if (solverControl_().consistent())
271  {
272  rAtUa = 1.0/(1.0/rAUa - UaEqn.H1());
273  phiaHbyA +=
274  fvc::interpolate(rAtUa() - rAUa)*fvc::snGrad(pa)*mesh_.magSf();
275  HabyA -= (rAUa - rAtUa())*fvc::grad(pa);
276  }
277 
278  tUaEqn.clear();
279 
280  // Update the pressure BCs to ensure flux consistency
281  // constrainPressure(p, U, phiHbyA, rAtU(), MRF_);
282 
283  // Non-orthogonal pressure corrector loop
284  while (solverControl_().correctNonOrthogonal())
285  {
287  (
288  fvm::laplacian(rAtUa(), pa) == fvc::div(phiaHbyA)
289  );
290 
292 
293  addPressureSource(paEqn);
294 
296  paEqn.setReference(paRefCell, paRefValue);
297 
298  paEqn.solve();
299 
300  if (solverControl_().finalNonOrthogonalIter())
301  {
302  phia = phiaHbyA - paEqn.flux();
303  }
304  }
305 
306  continuityErrors();
307 
308  // Explicitly relax pressure for adjoint momentum corrector
309  pa.relax();
310 
311  // Momentum corrector
312  Ua = HabyA - rAtUa()*fvc::grad(pa);
314  fvOptions.correct(Ua);
316  }
317 
318  adjointTurbulence->correct();
319 
320  if (solverControl_().printMaxMags())
321  {
322  dimensionedScalar maxUa = gMax(mag(Ua)());
323  dimensionedScalar maxpa = gMax(mag(pa)());
324  Info<< "Max mag of adjoint velocity = " << maxUa.value() << endl;
325  Info<< "Max mag of adjoint pressure = " << maxpa.value() << endl;
326  }
327 }
328 
329 
331 {
332  solverControl_().write();
333 
334  // Average fields if necessary
335  adjointVars_.computeMeanFields();
336 
337  // Print execution time
338  mesh_.time().printExecutionTime(Info);
339 }
340 
341 
343 {
344  addProfiling(adjointSimple, "adjointSimple::solve");
345  if (active_)
346  {
347  preLoop();
348  while (solverControl_().loop())
349  {
350  solveIter();
351  }
352  postLoop();
353  }
354 }
355 
358 {
359  return solverControl_().loop();
360 }
361 
362 
364 {
365  // Reset mean fields before solving
366  adjointVars_.resetMeanFields();
367 }
368 
369 
371 {
372  if (computeSensitivities_)
373  {
374  adjointSensitivity_->accumulateIntegrand(scalar(1));
375  const scalarField& sens = adjointSensitivity_->calculateSensitivities();
376  if (!sensitivities_)
377  {
378  sensitivities_.reset(new scalarField(sens.size(), Zero));
379  }
380  sensitivities_.ref() = sens;
381  }
382  else
383  {
384  sensitivities_.reset(new scalarField());
385  }
386 }
387 
388 
390 {
391  if (!sensitivities_)
392  {
393  computeObjectiveSensitivities();
394  }
395 
396  return sensitivities_();
397 }
398 
399 
401 {
402  if (computeSensitivities_)
403  {
404  adjointSensitivity_->clearSensitivities();
406  }
407 }
408 
409 
411 {
412  if (!adjointSensitivity_.valid())
413  {
415  << "Sensitivity object not allocated" << nl
416  << "Turn computeSensitivities on in "
417  << solverName_
418  << nl << nl
420  }
421 
422  return adjointSensitivity_();
423 }
424 
427 {
428  // Does nothing
429 }
430 
433 {
434  // Does nothing
435 }
436 
437 
439 {
441 
442  // Update objective function related quantities
443  objectiveManagerPtr_->updateAndWrite();
444 }
445 
446 
448 {
449  os.writeEntry("averageIter", solverControl_().averageIter());
451 }
452 
453 
454 // ************************************************************************* //
const bool momentumPredictor
virtual void mainIter()
The main SIMPLE iter.
bool computeSensitivities_
Are sensitivities computed.
Definition: adjointSolver.H:92
const Type & value() const noexcept
Return const reference to value.
dictionary dict
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh >> grad(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcGrad.C:47
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:118
fvMatrix< scalar > fvScalarMatrix
Definition: fvMatricesFwd.H:37
#define addProfiling(name, descr)
Define profiling trigger with specified name and description string.
const Type & lookupObject(const word &name, const bool recursive=false) const
Lookup and return const reference to the object of the given Type. Fatal if not found or the wrong ty...
const volScalarField & paInst() const
Return const reference to pressure.
SolverPerformance< Type > solve(faMatrix< Type > &, const dictionary &)
Solve returning the solution statistics given convergence tolerance.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
virtual void updatePrimalBasedQuantities()
Update primal based quantities related to the objective functions.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
virtual const incompressibleAdjointVars & getAdjointVars() const
Access to the incompressible adjoint variables set.
void addExtraSchemes()
In case variable names are different than the base ones, add extra schemes and relaxation factors to ...
Definition: adjointSimple.C:62
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
virtual tmp< fvVectorMatrix > divDevReff(volVectorField &U) const =0
Return the diffusion term for the momentum equation.
tmp< surfaceScalarField > flux(const volVectorField &vvf)
Return the face-flux field obtained from the given volVectorField.
void correct(GeometricField< Type, fvPatchField, volMesh > &field)
Apply correction to field.
virtual void preLoop()
Functions to be called before loop.
tmp< GeometricField< Type, fvPatchField, volMesh > > div(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcDiv.C:42
const fvMesh & mesh() const
Return the solver mesh.
Definition: solver.C:89
virtual bool readDict(const dictionary &dict)
Read dict if updated.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
void setReference(const label celli, const Type &value, const bool forceReference=false)
Set reference level for solution.
Definition: fvMatrix.C:1010
autoPtr< ATCModel > ATCModel_
Adjoint Transpose Convection options.
autoPtr< SIMPLEControl > solverControl_
Solver control.
Definition: adjointSimple.H:85
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
virtual void updatePrimalBasedQuantities()
Update primal based quantities, e.g. the primal fields in adjoint turbulence models.
scalar globalContErr
constexpr char tab
The tab &#39;\t&#39; character(0x09)
Definition: Ostream.H:48
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:312
autoPtr< variablesSet > vars_
Base variableSet pointer.
Definition: solver.H:92
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
Finite-volume options.
Definition: fvOptions.H:51
Abstract base class for adjoint sensitivities.
Definition: sensitivity.H:59
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:85
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:453
bool adjustPhi(surfaceScalarField &phi, const volVectorField &U, volScalarField &p)
Adjust the balance of fluxes to obey continuity.
Definition: adjustPhi.C:30
Find the reference cell nearest (in index) to the given cell but which is not on a cyclic...
Macros for easy insertion into run-time selection tables.
incompressibleAdjointVars & allocateVars()
Allocate incompressibleAdjointVars and return reference to be used for convenience in the rest of the...
Definition: adjointSimple.C:46
fv::options & fvOptions
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:100
virtual void clearSensitivities()
Clears the sensitivity field known by the adjoint solver.
Class including all adjoint fields for incompressible flows.
Base class for incompressibleAdjoint solvers.
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:50
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:84
volScalarField::Internal contErr((fvc::ddt(rho)+fvc::div(rhoPhi) -(fvOptions(alpha1, mixture.thermo1().rho())&rho1) -(fvOptions(alpha2, mixture.thermo2().rho())&rho2))())
virtual bool loop()
Looper (advances iters, time step)
virtual bool writeData(Ostream &os) const
Write the sensitivity derivatives.
dynamicFvMesh & mesh
virtual void correct()
Solve the adjoint turbulence equations.
incompressibleVars & primalVars_
Primal variable set.
incompressibleAdjointVars & adjointVars_
Reference to incompressibleAdjointVars.
Definition: adjointSimple.H:93
virtual void preIter()
Steps to be executed before each main SIMPLE iteration.
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
virtual bool readDict(const dictionary &dict)
Read dict if updated.
virtual sensitivity & getSensitivityBase()
Return the base sensitivity object.
static autoPtr< adjointSensitivity > New(const fvMesh &mesh, const dictionary &dict, incompressibleAdjointSolver &adjointSolver)
Return a reference to the selected turbulence model.
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:203
A special matrix type and solver, designed for finite volume solutions of scalar equations. Face addressing is used to make all matrix assembly and solution loops vectorise.
Definition: fvPatchField.H:64
tmp< volVectorField > constrainHbyA(const tmp< volVectorField > &tHbyA, const volVectorField &U, const volScalarField &p)
Definition: constrainHbyA.C:28
virtual const dictionary & dict() const
Return the solver dictionary.
Definition: solver.C:106
void continuityErrors()
Compute continuity errors.
Definition: adjointSimple.C:76
virtual void postIter()
Steps to be executed before each main SIMPLE iteration.
void constrain(fvMatrix< Type > &eqn)
Apply constraints to equation.
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:55
autoPtr< incompressible::adjointSensitivity > adjointSensitivity_
Sensitivity Derivatives engine.
SolverPerformance< Type > solve(const dictionary &)
Solve returning the solution statistics.
static autoPtr< ATCModel > New(const fvMesh &mesh, const incompressibleVars &primalVars, const incompressibleAdjointVars &adjointVars, const dictionary &dict)
Return a reference to the selected turbulence model.
Definition: ATCModel.C:122
tmp< fvMatrix< Type > > div(const surfaceScalarField &flux, const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvmDiv.C:41
Type gMax(const FieldField< Field, Type > &f)
OBJstream os(runTime.globalPath()/outputName)
virtual void solve()
Main control loop.
virtual const scalarField & getObjectiveSensitivities()
Grab a reference to the computed sensitivities.
defineTypeNameAndDebug(combustionModel, 0)
static tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > interpolate(const GeometricField< Type, fvPatchField, volMesh > &tvf, const surfaceScalarField &faceFlux, Istream &schemeData)
Interpolate field onto faces using scheme given by Istream.
addToRunTimeSelectionTable(decompositionMethod, kahipDecomp, dictionary)
virtual void addPressureSource(fvScalarMatrix &matrix)
Source terms for the continuity equation.
void relax(const scalar alpha)
Relax field (for steady-state solution).
#define WarningInFunction
Report a warning using Foam::Warning.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
tmp< fvMatrix< Type > > laplacian(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvmLaplacian.C:41
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:79
Solution of the adjoint PDEs for incompressible, steady-state flows.
Definition: adjointSimple.H:58
Boundary & boundaryFieldRef(const bool updateAccessTime=true)
Return a reference to the boundary field.
virtual bool writeData(Ostream &os) const
Write average iteration.
void correctBoundaryConditions()
Correct boundary field.
SIMPLE control class to supply convergence information/checks for the SIMPLE loop.
Definition: SIMPLEControl.H:46
For cases which do no have a pressure boundary adjust the balance of fluxes to obey continuity...
messageStream Info
Information stream (stdout output on master, null elsewhere)
fvScalarMatrix paEqn(fvm::d2dt2(pa) - sqr(c0) *fvc::laplacian(pa))
fvMesh & mesh_
Reference to the mesh database.
Definition: solver.H:56
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > flux() const
Return the face-flux field from the matrix.
Definition: fvMatrix.C:1451
void boundaryManipulate(typename GeometricField< Type, fvPatchField, volMesh >::Boundary &values)
Manipulate based on a boundary field.
Definition: fvMatrix.C:1265
dimensioned< Type > weightedAverage(const DimensionedField< scalar, GeoMesh > &weightField) const
Calculate and return weighted average.
virtual void solveIter()
Execute one iteration of the solution algorithm.
A class for managing temporary objects.
Definition: HashPtrTable.H:50
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
static options & New(const fvMesh &mesh)
Construct fvOptions and register to database if not present.
Definition: fvOptions.C:96
virtual void clearSensitivities()
Clears the sensitivity field known by the adjoint solver and zeros sensitivities constituents.
virtual tmp< volVectorField > adjointMeanFlowSource()=0
Source terms to the adjoint momentum equation due to the differentiation of the turbulence model...
bool setRefCell(const volScalarField &field, const volScalarField &fieldRef, const dictionary &dict, label &refCelli, scalar &refValue, const bool forceReference=false)
If the field fieldRef needs referencing find the reference cell nearest.
Definition: findRefCell.C:27
virtual void addMomentumSource(fvVectorMatrix &matrix)
Source terms for the momentum equations.
tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > snGrad(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvcSnGrad.C:40
autoPtr< objectiveManager > objectiveManagerPtr_
Object to manage objective functions.
Definition: adjointSolver.H:82
virtual void computeObjectiveSensitivities()
Compute sensitivities of the underlaying objectives.
scalar sumLocalContErr
Namespace for OpenFOAM.
tmp< scalarField > sensitivities_
Sensitivities field.
Definition: adjointSolver.H:87
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:157