shapeDesignVariables.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-2023 PCOpt/NTUA
9  Copyright (C) 2013-2023 FOSS GP
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "shapeDesignVariables.H"
30 #include "cellQuality.H"
31 #include "createZeroField.H"
33 #include "volFieldsFwd.H"
34 #include "adjointEikonalSolver.H"
35 #include "IOmanip.H"
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41  defineTypeNameAndDebug(shapeDesignVariables, 0);
42  defineRunTimeSelectionTable(shapeDesignVariables, dictionary);
44  (
45  designVariables,
46  shapeDesignVariables,
48  );
49 }
50 
51 
52 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
53 
54 Foam::label Foam::shapeDesignVariables::sensSize() const
55 {
56  return size();
57 }
58 
59 
61 {
62  return activeDesignVariables_;
63 }
64 
65 
68 (
69  const label patchI,
70  const label varID
71 ) const
72 {
73  const dictionary dxdbDict = dict_.subOrEmptyDict("dxdbSolver");
74  const label iters = dxdbDict.getOrDefault<label>("iters", 1000);
75  const scalar tolerance =
76  dxdbDict.getOrDefault<scalar>("tolerance", 1.e-07);
78  (
80  (
82  (
83  mesh_,
84  "m",
86  )
87  )
88  );
89  volVectorField& m = tm.ref();
90 
91  // Solve for dxdb
92  //~~~~~~~~~~~~~~~~
93  m.boundaryFieldRef()[patchI] == dxdbFace(patchI, varID);
94 
95  // Iterate the direct differentiation of the grid displacement equation
96  for (label iter = 0; iter < iters; ++iter)
97  {
98  Info<< "Mesh Movement Propagation for varID" << varID
99  << ", Iteration : "<< iter << endl;
100 
101  fvVectorMatrix mEqn
102  (
103  fvm::laplacian(m)
104  );
105 
106  scalar residual = mag(mEqn.solve().initialResidual());
107 
108  DebugInfo
109  << "Max dxdb " << gMax(mag(m)()) << endl;
110 
111  mesh_.time().printExecutionTime(Info);
112 
113  // Check convergence
114  if (residual < tolerance)
115  {
116  Info<< "\n***Reached dxdb convergence limit, iteration " << iter
117  << "***\n\n";
118  break;
119  }
120  }
121 
122  return tm;
123 }
124 
125 
127 {
128  if (dxdbVolSens_.empty())
129  {
130  dxdbVolSens_.setSize(sensSize(), Zero);
131  dxdbSurfSens_.setSize(sensSize(), Zero);
132  dSdbSens_.setSize(sensSize(), Zero);
133  dndbSens_.setSize(sensSize(), Zero);
134  dxdbDirectSens_.setSize(sensSize(), Zero);
135  dVdbSens_.setSize(sensSize(), Zero);
136  distanceSens_.setSize(sensSize(), Zero);
137  optionsSens_.setSize(sensSize(), Zero);
138  bcSens_.setSize(sensSize(), Zero);
139  }
140 }
141 
142 
144 {
145  dxdbVolSens_ = Zero;
146  dxdbSurfSens_ = Zero;
147  dSdbSens_ = Zero;
148  dndbSens_ = Zero;
149  dxdbDirectSens_ = Zero;
150  dVdbSens_ = Zero;
151  distanceSens_ = Zero;
152  optionsSens_ = Zero;
153  bcSens_ = Zero;
154 }
155 
156 
157 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
158 
159 Foam::shapeDesignVariables::shapeDesignVariables
160 (
161  fvMesh& mesh,
162  const dictionary& dict
163 )
164 :
166  parametertisedPatches_
167  (
168  mesh_.boundaryMesh().patchSet(dict.get<wordRes>("patches"))
169  ),
170  displMethodPtr_
171  (
172  displacementMethod::New(mesh_, parametertisedPatches_.toc())
173  ),
174  pointsInit_(nullptr),
175  writeEachMesh_(dict.getOrDefault<bool>("writeEachMesh", true)),
176  dxdbVolSens_(),
177  dxdbSurfSens_(),
178  dSdbSens_(),
179  dndbSens_(),
180  dxdbDirectSens_(),
181  dVdbSens_(),
182  distanceSens_(),
183  optionsSens_(),
184  bcSens_(),
185  derivativesFolder_
186  (
187  word("optimisation")/word("derivatives")
188  /word(mesh.name() == polyMesh::defaultRegion ? word() : mesh.name())
189  )
190 {
192  {
194  << "None of the provided parameterised patches is valid"
195  << endl
196  << exit(FatalError);
197  }
199 }
200 
201 
202 // * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
203 
205 (
206  fvMesh& mesh,
207  const dictionary& dict
208 )
209 {
210  const word modelType(dict.get<word>("shapeType"));
211 
212  Info<< "shapeDesignVariables type : " << modelType << endl;
213 
214  auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
215 
216  if (!cstrIter.found())
217  {
219  (
220  "shapeType",
221  modelType,
222  *dictionaryConstructorTablePtr_
223  ) << exit(FatalError);
224  }
226  return autoPtr<shapeDesignVariables>(cstrIter()(mesh, dict));
227 }
228 
229 
230 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * //
231 
233 {
235  {
236  parametertisedPatches_ =
237  mesh_.boundaryMesh().patchSet(dict.get<wordRes>("patches"));
238  displMethodPtr_->setPatchIDs(parametertisedPatches_.toc());
239 
240  writeEachMesh_ =
241  dict.getOrDefault<bool>("writeEachMesh", true);
242 
243  return true;
244  }
245 
246  return false;
247 }
248 
249 
251 {
253 
254  if (!pointsInit_)
255  {
256  pointsInit_.reset(new pointField(mesh_.nPoints(), Zero));
257  }
258  pointsInit_() = mesh_.points();
259 }
260 
261 
263 {
265  mesh_.movePoints(pointsInit_());
266 }
267 
268 
270 {
271  // Move mesh
272  displMethodPtr_->update();
273 
274  if (writeEachMesh_)
275  {
276  Info<< " Writing new mesh points for mesh region "
277  << mesh_.name() << endl;
279  (
280  IOobject
281  (
282  "points",
283  mesh_.pointsInstance(),
284  mesh_.meshSubDir,
285  mesh_,
288  false
289  ),
290  mesh_.points()
291  );
292  points.write();
293  }
295  // Check mesh quality
296  mesh_.checkMesh(true);
297 }
298 
299 
301 (
302  adjointSensitivity& adjointSens
303 )
304 {
305  // Return field
306  tmp<scalarField> tsens(tmp<scalarField>::New(sensSize(), Zero));
307  scalarField& sens = tsens.ref();
308 
309  // Reset sensitivity components to zero
310  allocateSensFields();
311  zeroSensFields();
312 
313  // Grab multipliers from the adjoint sensitivities
314  const autoPtr<volTensorField>& gradDxDbMult = adjointSens.gradDxDbMult();
315  const autoPtr<scalarField>& divDxDbMult = adjointSens.divDxDbMult();
316  const autoPtr<boundaryVectorField>& dxdbMult = adjointSens.dxdbMult();
317  const autoPtr<boundaryVectorField>& dSdbMult = adjointSens.dSfdbMult();
318  const autoPtr<boundaryVectorField>& dndbMult = adjointSens.dnfdbMult();
319  const autoPtr<boundaryVectorField>& dxdbDirectMult =
320  adjointSens.dxdbDirectMult();
321  const autoPtr<boundaryVectorField>& bcDxDbmult = adjointSens.bcDxDbMult();
322  const autoPtr<vectorField>& optionsDxDbMult = adjointSens.optionsDxDbMult();
323  const volScalarField::Internal& V = mesh_.V();
324  autoPtr<adjointEikonalSolver>& eikonalSolver =
325  adjointSens.getAdjointEikonalSolver();
326 
327  autoPtr<volTensorField> distanceSens(nullptr);
328  if (adjointSens.includeDistance())
329  {
330  distanceSens.reset
331  (
332  new volTensorField(eikonalSolver->getFISensitivityTerm())
333  );
334  }
335 
336  // Loop over active design variables only
337  for (const label varI : activeSensitivities())
338  {
339  // FI approach, integrate terms including variations of the grid
340  // sensitivities
341  if (adjointSens.computeDxDbInternalField())
342  {
343  // Parameterization info
344  tmp<volVectorField> tvolDxDbI = dCdb(varI);
345  const volVectorField& volDxDbI = tvolDxDbI();
346  tmp<volTensorField> gradDxDb = fvc::grad(volDxDbI);
347 
348  // Contributions from the adjoint-related part
349  dxdbVolSens_[varI] = gSum((gradDxDbMult() && gradDxDb())*V);
350 
351  // Contributions from the distance related part
352  if (adjointSens.includeDistance())
353  {
354  distanceSens_[varI] = gSum((distanceSens() && gradDxDb)*V);
355  }
356  // Contributions from the multiplier of divDxDb
357  if (divDxDbMult)
358  {
359  dVdbSens_[varI] +=
360  gSum(divDxDbMult()*fvc::div(volDxDbI)().primitiveField()*V);
361  }
362 
363  // Contributions from fvOptions
364  optionsSens_[varI] +=
365  gSum((optionsDxDbMult() & volDxDbI.primitiveField())*V);
366  }
367 
368  // Contribution from boundary terms
369  // Most of them (with the expection of dxdbMult) exist in both the
370  // FI and E-SI approaches
371  for (const label patchI : parametertisedPatches_)
372  {
373  if (dSdbMult)
374  {
375  tmp<vectorField> pdSdb = dSdb(patchI, varI);
376  dSdbSens_[varI] += gSum(dSdbMult()[patchI] & pdSdb);
377  }
378 
379  if (dndbMult)
380  {
381  tmp<vectorField> pdndb = dndb(patchI, varI);
382  dndbSens_[varI] += gSum((dndbMult()[patchI] & pdndb));
383  }
384 
385  tmp<vectorField> pdxdb = dxdbFace(patchI, varI);
386  // Main contribution in the E-SI approach
387  if (dxdbMult)
388  {
389  dxdbSurfSens_[varI] += gSum(dxdbMult()[patchI] & pdxdb());
390  }
391  if (dxdbDirectMult)
392  {
393  dxdbDirectSens_[varI] +=
394  gSum((dxdbDirectMult()[patchI] & pdxdb()));
395  }
396  if (bcDxDbmult)
397  {
398  bcSens_[varI] += gSum((bcDxDbmult()[patchI] & pdxdb()));
399  }
400  }
401  }
402 
403  sens =
404  dxdbVolSens_ + dxdbSurfSens_ + dSdbSens_ + dndbSens_ + dxdbDirectSens_
405  + dVdbSens_ + distanceSens_ + optionsSens_ + bcSens_;
406 
407  writeSensitivities(sens, adjointSens);
408 
409  return tsens;
410 }
411 
412 
414 (
415  const scalarField& sens,
416  const adjointSensitivity& adjointSens
417 )
418 {
419  OFstream derivFile
420  (
421  derivativesFolder_/
422  type() + adjointSens.getAdjointSolver().solverName()
423  + adjointSens.getSuffix() + mesh_.time().timeName()
424  );
425  unsigned int widthDV = max(int(name(dxdbVolSens_.size()).size()), int(6));
426  unsigned int width = IOstream::defaultPrecision() + 7;
427  derivFile
428  << setw(widthDV) << "#varID" << " "
429  << setw(width) << "total"<< " "
430  << setw(width) << "dxdbVol" << " "
431  << setw(width) << "dxdbSurf" << " "
432  << setw(width) << "dSdb" << " "
433  << setw(width) << "dndb" << " "
434  << setw(width) << "dxdbDirect" << " "
435  << setw(width) << "dVdb" << " "
436  << setw(width) << "distance" << " "
437  << setw(width) << "options" << " "
438  << setw(width) << "dvdb" << endl;
439 
440  for (const label varI : activeSensitivities())
441  {
442  derivFile
443  << setw(widthDV) << varI << " "
444  << setw(width) << sens[varI] << " "
445  << setw(width) << dxdbVolSens_[varI] << " "
446  << setw(width) << dxdbSurfSens_[varI] << " "
447  << setw(width) << dSdbSens_[varI] << " "
448  << setw(width) << dndbSens_[varI] << " "
449  << setw(width) << dxdbDirectSens_[varI] << " "
450  << setw(width) << dVdbSens_[varI] << " "
451  << setw(width) << distanceSens_[varI] << " "
452  << setw(width) << optionsSens_[varI] << " "
453  << setw(width) << bcSens_[varI] << " "
454  << endl;
455  }
456 }
457 
458 
460 (
461  const label varID
462 ) const
463 {
464  // Deliberately returning a zero-sized field
465  return tmp<vectorField>::New(0);
466 }
467 
468 
470 (
471  const label patchI,
472  const label varID
473 ) const
474 {
476  return nullptr;
477 }
478 
479 
481 (
482  const label patchI,
483  const label varID
484 ) const
485 {
487  return nullptr;
488 }
489 
490 
492 (
493  const label patchI,
494  const label varID
495 ) const
496 {
498  return nullptr;
499 }
500 
501 
503 Foam::shapeDesignVariables::dCdb(const label varID) const
504 {
506  return nullptr;
507 }
508 
509 
510 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
virtual const labelList & activeSensitivities() const
Active variables for which to compute sensitivities.
dictionary dict
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh >> grad(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcGrad.C:47
virtual tmp< vectorField > dxdbFace(const label patchI, const label varID) const
Get dxdb for a given design variable and patch.
virtual void writeSensitivities(const scalarField &sens, const adjointSensitivity &adjointSens)
Write final sensitivity derivatives to files.
virtual void storeDesignVariables()
Store design variables, as the starting point for line search.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
virtual tmp< volVectorField > dCdb(const label varID) const
Get dCdb for a given design variable.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Forwards and collection of common volume field types.
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:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
Abstract base class for adjoint-based sensitivities.
void zeroSensFields()
Zero the fields assosiated with the computation of sensitivities.
T & ref() const
Return non-const reference to the contents of a non-null managed pointer.
Definition: tmpI.H:235
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
GeometricField< tensor, fvPatchField, volMesh > volTensorField
Definition: volFieldsFwd.H:86
tmp< GeometricField< Type, fvPatchField, volMesh > > div(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcDiv.C:42
virtual void resetDesignVariables()
Reset to starting point of line search.
Output to file stream, using an OSstream.
Definition: OFstream.H:49
virtual void moveMesh()
Move mesh based on displacementMethod.
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface...
Definition: boundaryMesh.H:58
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
static unsigned int defaultPrecision() noexcept
Return the default precision.
Definition: IOstream.H:423
virtual tmp< scalarField > assembleSensitivities(adjointSensitivity &adjointSens)
Add part of sensitivity derivatives related to geometry variations.
virtual label sensSize() const
Size of the sensitivity derivatives.
Ignore writing from objectRegistry::writeObject()
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T. FatalIOError if not found, or if the number of tokens is incorrect.
#define FatalErrorInLookup(lookupTag, lookupName, lookupTable)
Report an error message using Foam::FatalError.
Definition: error.H:605
const adjointSolver & getAdjointSolver() const
Const access to adjoint solver.
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:82
virtual bool computeDxDbInternalField() const
Should the parameterization compute the internalField of dxdb.
virtual tmp< volVectorField > solveMeshMovementEqn(const label patchI, const label varID) const
Compute dxdb at the mesh cell centers by solving a Laplace PDE.
Macros for easy insertion into run-time selection tables.
const autoPtr< scalarField > & divDxDbMult() const
virtual bool readDict(const dictionary &dict)
Read dictionary if changed.
static autoPtr< shapeDesignVariables > New(fvMesh &mesh, const dictionary &dict)
Construct and return the selected shapeDesignVariables.
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:37
const autoPtr< volTensorField > & gradDxDbMult() const
label size() const noexcept
The number of elements in table.
Definition: HashTable.H:342
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:799
Dimension set for the base types, which can be used to implement rigorous dimension checking for alge...
Definition: dimensionSet.H:105
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
dynamicFvMesh & mesh
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:614
Type gSum(const FieldField< Field, Type > &f)
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const pointField & points
A class for handling words, derived from Foam::string.
Definition: word.H:63
virtual tmp< vectorField > dndb(const label patchI, const label varID) const
Get dndb for a given design variable and patch.
tmp< volTensorField > getFISensitivityTerm() const
Return the volume-based sensitivity term depending on da.
const autoPtr< boundaryVectorField > & bcDxDbMult() const
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
A List of wordRe with additional matching capabilities.
Definition: wordRes.H:53
const autoPtr< boundaryVectorField > & dxdbMult() const
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
virtual void resetDesignVariables()
Reset to the starting point of line search.
Abstract base class for displacement methods, which are a set or wrapper classes allowing to change t...
const autoPtr< boundaryVectorField > & dnfdbMult() const
#define DebugInfo
Report an information message using Foam::Info.
Istream and Ostream manipulators taking arguments.
label size() const noexcept
The number of elements in the container.
Definition: UList.H:671
autoPtr< adjointEikonalSolver > & getAdjointEikonalSolver()
Return the adjoint eikonal solver.
defineRunTimeSelectionTable(reactionRateFlameArea, dictionary)
Type gMax(const FieldField< Field, Type > &f)
defineTypeNameAndDebug(combustionModel, 0)
dictionary subOrEmptyDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX, const bool mandatory=false) const
Find and return a sub-dictionary as a copy, otherwise return an empty dictionary. ...
Definition: dictionary.C:521
const word & getSuffix() const
Get suffix.
fileName derivativesFolder_
Name of the sensitivity derivatives folder.
virtual void storeDesignVariables()
Store design variables, as the starting point for line search.
virtual bool readDict(const dictionary &dict)
Read dictionary if changed.
const autoPtr< vectorField > & optionsDxDbMult() const
Abstract base class for defining design variables.
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:50
tmp< fvMatrix< Type > > laplacian(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvmLaplacian.C:41
const word & solverName() const
Return the solver name.
Definition: solverI.H:30
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
Definition: areaFieldsFwd.H:42
Nothing to be read.
loopControl iters(runTime, aMesh.solutionDict(), "solution")
virtual tmp< vectorField > dSdb(const label patchI, const label varID) const
Get dSdb for a given design variable and patch.
const autoPtr< boundaryVectorField > & dxdbDirectMult() const
Boundary & boundaryFieldRef(const bool updateAccessTime=true)
Return a reference to the boundary field.
messageStream Info
Information stream (stdout output on master, null elsewhere)
Internal & ref(const bool updateAccessTime=true)
Same as internalFieldRef()
void allocateSensFields()
Allocate the fields assosiated with the computation of sensitivities.
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
bool includeDistance() const
Should the adjoint eikonal PDE should be solved.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T, or return the given default value. FatalIOError if it is found and the number of...
A class for managing temporary objects.
Definition: HashPtrTable.H:50
const autoPtr< boundaryVectorField > & dSfdbMult() const
#define NotImplemented
Issue a FatalErrorIn for a function not currently implemented.
Definition: error.H:686
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:172
labelHashSet parametertisedPatches_
Patches to be moved by the design variables.
List< label > toc(const UList< bool > &bools)
Return the (sorted) values corresponding to &#39;true&#39; entries.
Definition: BitOps.C:158
A primitive field of type <T> with automated input and output.
virtual tmp< vectorField > dxdbVol(const label varID) const
Get dxdb for all mesh points.
static tmp< volVectorField > autoCreateMeshMovementField(const fvMesh &mesh, const word &name, const dimensionSet &dims)
Auto create variable for mesh movement.
Definition: variablesSet.C:166
Namespace for OpenFOAM.
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127