topODesignVariables.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 "localIOdictionary.H"
30 #include "topODesignVariables.H"
31 #include "wallDist.H"
32 #include "wallFvPatch.H"
33 #include "cutFaceIso.H"
34 #include "cutCellIso.H"
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41  defineTypeNameAndDebug(topODesignVariables, 0);
43  (
44  designVariables,
45  topODesignVariables,
46  designVariables
47  );
48 }
49 
50 
51 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
52 
54 (
55  const scalarField& correction,
56  const label fluidID
57 )
58 {
59  DebugInfo
60  << "Updating design variables for field " << fluidID << endl;
61  const label n = mesh_.nCells();
62  SubField<scalar> localCorrection(correction, n, fluidID*n);
63  SubField<scalar> field(*this, n, fluidID*n);
64 
65  // Update porosity in adjoint porous cells
67  {
68  forAll(field, cellI)
69  {
70  field[cellI] +=
71  min
72  (
73  max
74  (
75  field[cellI] + localCorrection[cellI],
76  scalar(0)
77  ),
78  1.
79  )
80  - field[cellI];
81  }
82  }
83  else
84  {
85  for (label cellZoneID : zones_.adjointPorousZoneIDs())
86  {
87  const labelList& zoneCells = mesh_.cellZones()[cellZoneID];
88  for (label cellI : zoneCells)
89  {
90  field[cellI] +=
91  min
92  (
93  max
94  (
95  field[cellI] + localCorrection[cellI],
96  scalar(0)
97  ),
98  1.
99  )
100  - field[cellI];
101  }
102  }
103  }
104 }
105 
106 
108 {
109  SubField<scalar> alpha(*this, mesh_.nCells());
110  // Zero porosity in the cells next to IO
111  for (label cellI : zones_.IOCells())
112  {
113  alpha[cellI] = 0.;
114  }
115 
116  // Apply fixed porosity
117  forAll(zones_.fixedPorousZoneIDs(), zI)
118  {
119  const label cellZoneID = zones_.fixedPorousZoneIDs()[zI];
120  const labelList& zoneCells = mesh_.cellZones()[cellZoneID];
121  const scalar alphaValue(zones_.fixedPorousValues()[zI]);
122  for (label cellI : zoneCells)
123  {
124  alpha[cellI] = alphaValue;
125  }
126  }
127 
128  // Apply fixed zero porosity
129  for (label cellZoneID : zones_.fixedZeroPorousZoneIDs())
130  {
131  const labelList& zoneCells = mesh_.cellZones()[cellZoneID];
132  for (label cellI : zoneCells)
133  {
134  alpha[cellI] = 0.;
135  }
136  }
137 }
138 
139 
141 {
142  const scalar maxChange(gMax(mag(correction)));
143  Info<< "maxInitChange/maxChange \t"
144  << maxInitChange_() << "/" << maxChange << endl;
145  const scalar eta(maxInitChange_() / maxChange);
146  Info<< "Setting eta value to " << eta << endl;
147  correction *= eta;
148 
149  return eta;
150 }
151 
152 
154 (
155  const label fluidID,
156  const bool activeIO
157 )
158 {
159  const label offset(fluidID*mesh_.nCells());
160  label varI(activeDesignVariables_.size());
161  activeDesignVariables_.setSize(offset + mesh_.nCells(), -1);
162  // Set active design variables
163  // If specific porosity zones are prescribed, use them directly
164  if (!zones_.adjointPorousZoneIDs().empty())
165  {
166  for (label cellZoneID : zones_.adjointPorousZoneIDs())
167  {
168  for (const label var : mesh_.cellZones()[cellZoneID])
169  {
170  activeDesignVariables_[varI++] = var + offset;
171  }
172  }
173  }
174  // Else, pick up all cells in non-constant porosity zones
175  else
176  {
177  boolList isActiveDV(mesh_.nCells(), true);
178  // Exclude cells with fixed porosity
179  for (label cellZoneID : zones_.fixedPorousZoneIDs())
180  {
181  for (label cellI : mesh_.cellZones()[cellZoneID])
182  {
183  isActiveDV[cellI] = false;
184  }
185  }
186  for (label cellZoneID : zones_.fixedZeroPorousZoneIDs())
187  {
188  for (label cellI : mesh_.cellZones()[cellZoneID])
189  {
190  isActiveDV[cellI] = false;
191  }
192  }
193  if (!activeIO)
194  {
195  for (label cellI : zones_.IOCells())
196  {
197  isActiveDV[cellI] = false;
198  }
199  }
200 
201  // Set active design variables
202  forAll(isActiveDV, cellI)
203  {
204  if (isActiveDV[cellI])
205  {
206  activeDesignVariables_[varI++] = offset + cellI;
207  }
208  }
209  }
210  activeDesignVariables_.setSize(varI);
211 }
212 
213 
215 (
216  const word& name,
217  const label fluidID,
218  const bool setIOValues
219 )
220 {
221  const label offset(fluidID*mesh_.nCells());
223  {
224  SubField<scalar>(*this, mesh_.nCells(), offset) =
225  scalarField(name, *this, mesh_.nCells());
226  }
227  else
228  {
229  IOobject header
230  (
231  name,
232  mesh_.time().timeName(),
233  mesh_,
236  );
237  if (header.typeHeaderOk<volScalarField>())
238  {
239  Info<< "Setting design variables based on the alpha field "
240  << nl << endl;
241  volScalarField volField
242  (
243  header,
244  mesh_
245  );
246  const scalarField& field = volField.primitiveField();
247  forAll(field, cI)
248  {
249  scalarField::operator[](offset + cI) = field[cI];
250  }
251  }
252  }
253 }
254 
255 
257 {
258  // Set active design variables
259  setActiveDesignVariables();
260 
261  // Read in values from file, if present
262  readField("alpha", 0, true);
263 
264  if (regularisation_.growFromWalls())
265  {
266  scalarField& alpha = *this;
267  for (const fvPatch& patch : mesh_.boundary())
268  {
269  if (isA<wallFvPatch>(patch))
270  {
271  const labelList& faceCells = patch.faceCells();
272  forAll(faceCells, cI)
273  {
274  alpha[faceCells[cI]] = 1.;
275  }
276  }
277  }
278  }
279 
280  // Make sure alpha has fixed values where it should
281  scalarField dummyCorrection(mesh_.nCells(), Zero);
282  update(dummyCorrection);
283 
284  // Read bounds for design variables, if present
286 }
287 
288 
289 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
290 
291 Foam::topODesignVariables::topODesignVariables
292 (
293  fvMesh& mesh,
294  const dictionary& dict
295 )
296 :
297  topODesignVariables(mesh, dict, mesh.nCells())
298 {}
299 
300 
301 Foam::topODesignVariables::topODesignVariables
302 (
303  fvMesh& mesh,
304  const dictionary& dict,
305  const label size
306 )
307 :
309  designVariables(mesh, dict, size),
310  alpha_(SubField<scalar>(*this, mesh.nCells(), 0)),
311  regularisation_
312  (
313  mesh,
314  alpha_,
315  zones_,
316  dict_.subDict("regularisation")
317  ),
318  writeAllFields_
319  (
320  dict.getOrDefaultCompat<bool>
321  (
322  "writeAllFields", {{"writeAllAlphaFields", 2306}}, false
323  )
324  ),
325  addFvOptions_(dict.getOrDefault<bool>("addFvOptions", false))
326 {}
327 
328 
329 // * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
330 
332 (
333  fvMesh& mesh,
334  const dictionary& dict
335 )
336 {
338 }
339 
340 
341 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * //
342 
344 {
345  return regularisation_.beta();
346 }
347 
348 
350 (
351  const word& interpolationFieldName
352 ) const
353 {
354  return beta().primitiveField();
355 }
356 
357 
359 (
361  const topOInterpolationFunction& interpolationFunc,
362  const FieldField<Field, scalar>& fluidValues,
363  const scalarField& solidValues,
364  const label fieldi,
365  const word& interpolationFieldName
366 ) const
367 {
368  const scalarField& indicator = interpolationField(interpolationFieldName);
369  scalarField interpolant(indicator.size(), Zero);
370  interpolationFunc.interpolate(indicator, interpolant);
371 
372  // Interpolate field values
373  const scalar diff(solidValues[fieldi] - fluidValues[0][fieldi]);
374  field.primitiveFieldRef() = fluidValues[0][fieldi] + interpolant*diff;
375  field.correctBoundaryConditions();
376 }
377 
378 
380 (
381  scalarField& sens,
382  const topOInterpolationFunction& interpolationFunc,
383  const FieldField<Field, scalar>& fluidValues,
384  const scalarField& solidValues,
385  const label fieldi,
386  const word& designVariablesName,
387  const word& interpolationFieldName
388 ) const
389 {
390  const scalarField& indicator = interpolationField(interpolationFieldName);
391  sens *=
392  (solidValues[fieldi] - fluidValues[0][fieldi])
393  *interpolationFunc.derivative(indicator);
394 }
395 
396 
398 (
400  const topOInterpolationFunction& interpolationFunc
401 ) const
402 {
403  const scalarField& beta = this->beta().primitiveField();
404  scalarField interpolant(beta.size(), Zero);
405  interpolationFunc.interpolate(beta, interpolant);
406  field *= scalar(1) - interpolant;
407 }
408 
409 
411 (
412  scalarField& sens,
413  const topOInterpolationFunction& interpolationFunc,
414  const word& designVariablesName
415 ) const
416 {
417  const scalarField& beta = this->beta().primitiveField();
418  sens *= - interpolationFunc.derivative(beta);
419 }
420 
421 
423 (
424  const word& interpolationFieldName,
425  const topOInterpolationFunction& interpolationFunc
426 ) const
427 {
428  const scalarField& beta = this->beta().primitiveField();
430  interpolationFunc.interpolate(beta, tinterpolant.ref());
431  return tinterpolant;
432 }
433 
434 
436 (
437  const word& interpolationFieldName,
438  const topOInterpolationFunction& interpolationFunc
439 ) const
440 {
441  const scalarField& beta = this->beta().primitiveField();
442  return interpolationFunc.derivative(beta);
443 }
444 
445 
447 {
448  // Update alpha values
449  updateField(correction);
450 
451  // Fix alpha in zones
452  applyFixedValues();
453 
454  // Update the beta field
455  regularisation_.updateBeta();
456 
457  // Though the mesh is kept constant, the distance from wall may change
458  // if the method computing it includes fvOptions that depend on the
459  // indicator field.
460  // Trick wallDist into updating it
461 
463 
464 
465  // Write the 0.5 beta iso-line to files, as an indication of the
466  // fluid-solid interface
467  labelList changedFaces(mesh_.nFaces(), -1);
468  List<wallPointData<label>> changedFacesInfo(mesh_.nFaces());
469  writeFluidSolidInterface(-beta(), -0.5, changedFaces, changedFacesInfo);
470 }
471 
472 
474 {
475  return true;
476 }
477 
478 
480 (
481  adjointSensitivity& adjointSens
482 )
483 {
484  // Raw sensitivities field.
485  // Does not include the adjoint to the regularisation and projection steps
486  const scalarField& fieldSens = adjointSens.fieldSensPtr()->primitiveField();
487 
488  // Return field (complete sensitivities)
489  auto tobjectiveSens(tmp<scalarField>::New(fieldSens));
490  scalarField& objectiveSens = tobjectiveSens.ref();
491 
492  // Add part due to regularisation and projection
493  regularisation_.postProcessSens(objectiveSens);
494 
495  // Write final sensitivities field
496  if (writeAllFields_ && mesh_.time().writeTime())
497  {
498  volScalarField sens
499  (
500  IOobject
501  (
502  "topOSens" + adjointSens.getAdjointSolver().solverName(),
503  mesh_.time().timeName(),
504  mesh_,
507  ),
508  mesh_,
510  );
511  sens.primitiveFieldRef() = objectiveSens;
512  sens.write();
513  }
514 
515  return tobjectiveSens;
516 }
517 
518 
520 {
521  // Rest of the contrsuctor initialisation
522  initialize();
523 }
524 
525 
527 (
528  const PtrList<primalSolver>& primalSolvers,
530 )
531 {
532  // WIP
533  if (addFvOptions_)
534  {
535  for (const primalSolver& solver : primalSolvers)
536  {
538  }
539  for (const adjointSolverManager& manager : adjointSolverManagers)
540  {
541  const PtrList<adjointSolver>& adjointSolvers =
542  manager.adjointSolvers();
543  for (const adjointSolver& solver : adjointSolvers)
544  {
546  }
547  }
548  }
549 }
550 
551 
553 {
554  if (writeAllFields_ && mesh_.time().writeTime())
555  {
557  (
558  IOobject
559  (
560  "alpha",
561  mesh_.time().timeName(),
562  mesh_,
565  ),
566  mesh_,
568  );
569  alpha.primitiveFieldRef() = alpha_;
570 
571  alpha.write();
572  }
573 }
574 
575 
576 bool Foam::topODesignVariables::writeData(Ostream& os) const
577 {
578  const scalarField& alpha = alpha_;
579  alpha.writeEntry("alpha", os);
580 
581  return true;
582 }
583 
584 
585 // ************************************************************************* //
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
Return the correction form of the given matrix by subtracting the matrix multiplied by the current fi...
virtual tmp< scalarField > assembleSensitivities(adjointSensitivity &sens)
Assemble sensitivity derivatives, by combining the part related to the primal and adjoint solution wi...
scalar diff(const triad &A, const triad &B)
Return a quantity of the difference between two triads.
Definition: triad.C:373
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
virtual void interpolationSensitivities(scalarField &sens, const topOInterpolationFunction &interpolationFunc, const FieldField< Field, scalar > &fluidValues, const scalarField &solidValues, const label fieldi, const word &designVariablesName, const word &interpolationFieldName="beta") const
Post-processing sensitivities due to interpolations based on the indicator fields.
rDeltaTY field()
Base solver class.
Definition: solver.H:45
virtual tmp< scalarField > penaltySensitivities(const word &interpolationFieldName, const topOInterpolationFunction &interpolationFunc) const
Return the penalty term derivative.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
Abstract base class for adjoint-based sensitivities.
Base class for primal solvers.
Definition: primalSolver.H:46
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
virtual void interpolate(volScalarField &field, const topOInterpolationFunction &interpolationFunc, const FieldField< Field, scalar > &fluidValues, const scalarField &solidValues, const label fieldi, const word &interpolationFieldName="beta") const
Interpolate between the given field and solid values.
topOZones zones_
Cell zones useful for defining the constant and changing parts of the domain in topO.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:675
A class that holds the data needed to identify things (zones, patches) in a dynamic mesh...
Definition: DynamicID.H:48
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
Ignore writing from objectRegistry::writeObject()
const dimensionSet dimless
Dimensionless.
Design variables for porosity-based topology optimisation (topO) problems.
const adjointSolver & getAdjointSolver() const
Const access to adjoint solver.
virtual const volScalarField & beta() const
Get the indicator field.
Macros for easy insertion into run-time selection tables.
A field of fields is a PtrList of fields with reference counting.
Definition: FieldField.H:51
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:104
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
T & operator[](const label i)
Return element of UList.
Definition: UListI.H:362
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:72
virtual scalar computeEta(scalarField &correction)
Compute eta if not set in the first step.
virtual void addTopOFvOptions() const
Add topO fvOptions.
Definition: solver.C:102
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
void writeEntry(const word &keyword, Ostream &os) const
Write as a dictionary entry with keyword.
virtual const scalarField & interpolationField(const word &interpolationFieldName="beta") const
Return interpolant.
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
virtual void writeDesignVars()
Write porosity field to file.
virtual void nullifyInSolidSensitivities(scalarField &sens, const topOInterpolationFunction &interpolationFunc, const word &designVariablesName) const
Nullify given field in the solid domain.
static autoPtr< topODesignVariables > New(fvMesh &mesh, const dictionary &dict)
Construct and return the selected design variables.
virtual void setActiveDesignVariables(const label fluidID=0, const bool activeIO=false)
Set active design variables.
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
virtual tmp< scalarField > derivative(const scalarField &arg) const =0
Return of function with respect to the argument field.
#define DebugInfo
Report an information message using Foam::Info.
virtual void update(scalarField &correction)
Update design variables based on a given correction.
virtual bool writeData(Ostream &) const
The writeData function required by the regIOobject write operation.
Type gMax(const FieldField< Field, Type > &f)
OBJstream os(runTime.globalPath()/outputName)
mesh update()
defineTypeNameAndDebug(combustionModel, 0)
static bool try_movePoints(const fvMesh &mesh)
Trigger update of y-field for the "wallDist" MeshObject on the given mesh. A no-op if the wallDist is...
Definition: wallDist.C:152
DynamicID< cellZoneMesh > cellZoneID
Foam::cellZoneID.
Definition: ZoneIDs.H:38
void applyFixedValues()
Apply fixed values in certain zones.
virtual void nullifyInSolid(scalarField &field, const topOInterpolationFunction &interpolationFunc) const
Nullify given field in the solid domain.
virtual void setInitialValues()
Set initial values of the design variables.
virtual void updateField(const scalarField &correction, const label fluidID=0)
Update the design variables given their correction.
Abstract base class for defining design variables.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
label nCells() const noexcept
Number of mesh cells.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers...
Definition: List.H:55
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
Nothing to be read.
virtual tmp< scalarField > penalty(const word &interpolationFieldName, const topOInterpolationFunction &interpolationFunc) const
Return the Brinkman penalisation term.
Automatically write from objectRegistry::writeObject()
const labelList & adjointPorousZoneIDs() const
Cell zone IDs in which porosity is allowed to change.
Definition: topOZones.H:193
const std::string patch
OpenFOAM patch number as a std::string.
const dimensionSet dimTime(0, 0, 1, 0, 0, 0, 0)
Definition: dimensionSets.H:51
const cellZoneMesh & cellZones() const noexcept
Return cell zone mesh.
Definition: polyMesh.H:679
virtual void initialize()
Part of the constructor initialisation.
virtual void interpolate(const scalarField &arg, scalarField &res) const =0
Interpolate argument to result.
messageStream Info
Information stream (stdout output on master, null elsewhere)
dimensionedScalar beta("beta", dimless/dimTemperature, laminarTransport)
label n
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
virtual void addFvOptions(const PtrList< primalSolver > &primalSolver, const PtrList< adjointSolverManager > &adjointSolverManagers)
Automatically add fvOptions depending on the design variables to the primal and adjoint solvers...
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...
List< label > labelList
A List of labels.
Definition: List.H:62
A class for managing temporary objects.
Definition: HashPtrTable.H:50
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
const dimensionedScalar alpha
Fine-structure constant: default SI units: [].
Base class for all design variables related to topology optimisation (topO). Provides the lookup func...
PtrList< adjointSolverManager > & adjointSolverManagers
Definition: createFields.H:8
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:180
virtual bool globalSum() const
Whether to use global sum when computing matrix-vector products in update methods.
List< bool > boolList
A List of bools.
Definition: List.H:60
const autoPtr< volScalarField > & fieldSensPtr() const
Get the fieldSensPtr.
Definition: sensitivity.H:152
Namespace for OpenFOAM.
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
void readField(const word &name, const label fluidID=0, const bool setIOValues=false)
Read field with (path of) the design variables and store input in the design variables list with opti...
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127