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-------------------------------------------------------------------------------
12License
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
39namespace Foam
40{
43 (
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
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,
125 dict.subDict("ATCModel")
126 ).ptr()
127 );
128
131 (
136 );
137
139 {
140 const IOdictionary& optDict =
141 mesh.lookupObject<IOdictionary>("optimisationDict");
142
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
172{
173 if (incompressibleAdjointSolver::readDict(dict))
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
200
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();
221
222 // Momentum predictor
223 //~~~~~~~~~~~~~~~~~~~
224
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
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
356
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
419 << exit(FatalError);
420 }
421
422 return adjointSensitivity_();
423}
424
425
427{
428 // Does nothing
429}
430
431
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());
450 return adjointSolver::writeData(os);
451}
452
453
454// ************************************************************************* //
bool found
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
For cases which do no have a pressure boundary adjust the balance of fluxes to obey continuity....
fv::options & fvOptions
surfaceScalarField & phi
const scalar pRefValue
const label pRefCell
dimensioned< Type > weightedAverage(const DimensionedField< scalar, GeoMesh > &weightField) const
Calculate and return weighted average.
void relax(const scalar alpha)
Relax field (for steady-state solution).
Boundary & boundaryFieldRef(const bool updateAccessTime=true)
Return a reference to the boundary field.
void correctBoundaryConditions()
Correct boundary field.
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:57
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:239
SIMPLE control class to supply convergence information/checks for the SIMPLE loop.
Definition: SIMPLEControl.H:56
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
Solution of the adjoint PDEs for incompressible, steady-state flows.
Definition: adjointSimple.H:67
virtual void postIter()
Steps to be executed before each main SIMPLE iteration.
virtual void clearSensitivities()
autoPtr< SIMPLEControl > solverControl_
Solver control.
Definition: adjointSimple.H:85
virtual void preIter()
Steps to be executed before each main SIMPLE iteration.
virtual bool writeData(Ostream &os) const
Write average iteration.
autoPtr< incompressible::adjointSensitivity > adjointSensitivity_
Sensitivity Derivatives engine.
Definition: adjointSimple.H:96
virtual void addMomentumSource(fvVectorMatrix &matrix)
Source terms for the momentum equations.
virtual sensitivity & getSensitivityBase()
Return the base sensitivity object.
virtual bool readDict(const dictionary &dict)
Read dict if updated.
virtual const scalarField & getObjectiveSensitivities()
Grab a reference to the computed sensitivities.
incompressibleAdjointVars & allocateVars()
Definition: adjointSimple.C:53
virtual void mainIter()
The main SIMPLE iter.
virtual void updatePrimalBasedQuantities()
incompressibleAdjointVars & adjointVars_
Reference to incompressibleAdjointVars.
Definition: adjointSimple.H:90
virtual void preLoop()
Functions to be called before loop.
void continuityErrors()
Compute continuity errors.
Definition: adjointSimple.C:83
virtual void computeObjectiveSensitivities()
Compute sensitivities of the underlaying objectives.
virtual bool loop()
Looper (advances iters, time step)
virtual void solveIter()
Execute one iteration of the solution algorithm.
virtual void solve()
Main control loop.
virtual void addPressureSource(fvScalarMatrix &matrix)
Source terms for the continuity equation.
virtual void clearSensitivities()
Clears the sensitivity field known by the adjoint solver.
tmp< scalarField > sensitivities_
Sensitivities field.
Definition: adjointSolver.H:83
autoPtr< objectiveManager > objectiveManagerPtr_
Object to manage objective functions.
Definition: adjointSolver.H:80
bool computeSensitivities_
Are sensitivities computed.
Definition: adjointSolver.H:86
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:460
const Type & value() const
Return const reference to value.
A special matrix type and solver, designed for finite volume solutions of scalar equations....
Definition: fvMatrix.H:121
void relax(const scalar alpha)
Relax matrix (for steady-state solution).
Definition: fvMatrix.C:1092
tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > flux() const
Return the face-flux field from the matrix.
Definition: fvMatrix.C:1443
SolverPerformance< Type > solve(const dictionary &)
Solve returning the solution statistics.
tmp< volScalarField > A() const
Return the central coefficient.
Definition: fvMatrix.C:1303
tmp< volScalarField > H1() const
Return H(1)
Definition: fvMatrix.C:1394
void setReference(const label celli, const Type &value, const bool forceReference=false)
Set reference level for solution.
Definition: fvMatrix.C:1002
void boundaryManipulate(typename GeometricField< Type, fvPatchField, volMesh >::Boundary &values)
Manipulate based on a boundary field.
Definition: fvMatrix.C:1257
tmp< GeometricField< Type, fvPatchField, volMesh > > H() const
Return the H operation source.
Definition: fvMatrix.C:1332
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:91
void constrain(fvMatrix< Type > &eqn)
Apply constraints to equation.
void correct(GeometricField< Type, fvPatchField, volMesh > &field)
Apply correction to field.
Finite-volume options.
Definition: fvOptions.H:59
const volScalarField & paInst() const
Return const reference to pressure.
Base class for incompressibleAdjoint solvers.
autoPtr< ATCModel > ATCModel_
Adjoint Transpose Convection options.
virtual const incompressibleAdjointVars & getAdjointVars() const
Access to the incompressible adjoint variables set.
incompressibleVars & primalVars_
Primal variable set.
Class including all adjoint fields for incompressible flows.
const Type & lookupObject(const word &name, const bool recursive=false) const
Abstract base class for adjoint sensitivities.
Definition: sensitivity.H:64
autoPtr< variablesSet > vars_
Base variableSet pointer.
Definition: solver.H:82
virtual const dictionary & dict() const
Return the solver dictionary.
Definition: solver.C:113
const fvMesh & mesh() const
Return the solver mesh.
Definition: solver.C:96
fvMesh & mesh_
Reference to the mesh database.
Definition: solver.H:60
A class for managing temporary objects.
Definition: tmp.H:65
void clear() const noexcept
Definition: tmpI.H:287
T & ref() const
Definition: tmpI.H:227
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
volScalarField::Internal contErr((fvc::ddt(rho)+fvc::div(rhoPhi) -(fvOptions(alpha1, mixture.thermo1().rho())&rho1) -(fvOptions(alpha2, mixture.thermo2().rho())&rho2))())
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
Find the reference cell nearest (in index) to the given cell but which is not on a cyclic,...
#define WarningInFunction
Report a warning using Foam::Warning.
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.
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh > > grad(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcGrad.C:54
tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > snGrad(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvcSnGrad.C:47
tmp< GeometricField< Type, fvPatchField, volMesh > > div(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcDiv.C:49
tmp< surfaceScalarField > flux(const volVectorField &vvf)
Return the face-flux field obtained from the given volVectorField.
Definition: fvcFlux.C:34
tmp< fvMatrix< Type > > laplacian(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvmLaplacian.C:48
tmp< fvMatrix< Type > > div(const surfaceScalarField &flux, const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvmDiv.C:48
Namespace for OpenFOAM.
bool adjustPhi(surfaceScalarField &phi, const volVectorField &U, volScalarField &p)
Adjust the balance of fluxes to obey continuity.
Definition: adjustPhi.C:37
messageStream Info
Information stream (stdout output on master, null elsewhere)
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh > > &tdf1, const word &name, const dimensionSet &dimensions)
Global function forwards to reuseTmpDimensionedField::New.
error FatalError
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Type gMax(const FieldField< Field, Type > &f)
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:34
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
constexpr char tab
The tab '\t' character(0x09)
Definition: Ostream.H:52
SolverPerformance< Type > solve(faMatrix< Type > &, const dictionary &)
Solve returning the solution statistics given convergence tolerance.
fvScalarMatrix paEqn(fvm::d2dt2(pa) - sqr(c0) *fvc::laplacian(pa))
#define addProfiling(name, descr)
Define profiling trigger with specified name and description string.
const bool momentumPredictor
dictionary dict
scalar sumLocalContErr
scalar globalContErr