levelSetDesignVariables.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) 2022-2023 PCOpt/NTUA
9  Copyright (C) 2022-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 
30 #include "wallDist.H"
33 
34 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38 
39 // * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * * //
40 
41 defineTypeNameAndDebug(levelSetDesignVariables, 1);
43 (
47 );
48 
49 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
50 
52 {
53  scalarField& vars = *this;
54  if (localIOdictionary::found("alpha"))
55  {
56  vars = (scalarField("alpha", *this, vars.size()));
57  }
58  else
59  {
60  // Initialise as the distance from the wall patches of the initial
61  // domain
62  const labelHashSet wallPatchIDs =
65  (
66  IOobject
67  (
68  "yLevelSet",
69  mesh_.time().timeName(),
70  mesh_,
73  ),
74  mesh_,
76  patchDistMethod::patchTypes<scalar>(mesh_, wallPatchIDs)
77  );
79  (
80  dict_.subDict("initialisation"),
81  mesh_,
82  wallPatchIDs
83  )->correct(y);
84  vars = y.primitiveField();
85 
86  if (debug)
87  {
89  }
90  }
91 }
92 
93 
95 {
97 
98  // Safety - set beta equal to zero next to the IO cells
99  for (const label IOcell : zones_.IOCells())
100  {
101  betaIf[IOcell] = Zero;
102  }
103 
104  const labelList& fixedZeroPorousZones = zones_.fixedZeroPorousZoneIDs();
105  const labelList& fixedPorousZones = zones_.fixedPorousZoneIDs();
106  const scalarList& fixedPorousValues = zones_.fixedPorousValues();
107 
108  // Apply fixed porosity
109  for (const label zoneID : fixedZeroPorousZones)
110  {
111  const labelList& zone = mesh_.cellZones()[zoneID];
112  for (const label cellI : zone)
113  {
114  betaIf[cellI] = Zero;
115  }
116  }
117 
118  // Apply fixed porosity
119  forAll(fixedPorousZones, zI)
120  {
121  const label zoneID = fixedPorousZones[zI];
122  const scalar value = fixedPorousValues[zI];
123  const labelList& zone = mesh_.cellZones()[zoneID];
124  for (const label cellI : zone)
125  {
126  betaIf[cellI] = value >= 0 ? 0 : 1;
127  }
128  }
129 
131 }
132 
133 
135 {
138  {
139  boolList isActiveVar(mesh_.nCells(), true);
140 
141  const labelList& fixedZeroPorousZones =
143  for (const label zoneID : fixedZeroPorousZones)
144  {
145  const labelList& zone = mesh_.cellZones()[zoneID];
146  for (const label cellI : zone)
147  {
148  isActiveVar[cellI] = false;
149  }
150  }
151 
152  const labelList& fixedPorousZones = zones_.fixedPorousZoneIDs();
153  for (const label zoneID : fixedPorousZones)
154  {
155  const labelList& zone = mesh_.cellZones()[zoneID];
156  for (const label cellI : zone)
157  {
158  isActiveVar[cellI] = false;
159  }
160  }
161 
162  if (!activeIO)
163  {
164  for (label cellI : zones_.IOCells())
165  {
166  isActiveVar[cellI] = false;
167  }
168  }
169 
170  label iVar(0);
171  forAll(isActiveVar, cI)
172  {
173  if (isActiveVar[cI])
174  {
175  activeDesignVariables_[iVar++] = cI;
176  }
177  }
179  }
180  else
181  {
182  const labelList& adjointPorousZoneIDs = zones_.adjointPorousZoneIDs();
183 
184  label iVar(0);
185  for (const label cellZoneID : adjointPorousZoneIDs)
186  {
187  const labelList& zone = mesh_.cellZones()[cellZoneID];
188 
189  for (const label cellI : zone)
190  {
191  activeDesignVariables_[iVar] = cellI;
192  iVar++;
193  }
194  }
196  }
197 }
198 
199 
201 {
202  // Compute the beta field by passing the distance field through
203  // a Heaviside function
206  beta = 1 - beta;
207  // Apply fixed values if necessary
209 
211 }
212 
213 
215 {
216  Info<< "Re-initilising the level-set distance field" << nl << endl;
217 
219  (
220  IOobject
221  (
222  "yLevelSet",
223  mesh_.time().timeName(),
224  mesh_,
227  ),
228  mesh_,
231  );
232  y.primitiveFieldRef() = aTilda_.primitiveFieldRef();
233  y.correctBoundaryConditions();
234 
235  changedFaces_.clear();
236  changedFaces_.setSize(mesh_.nFaces(), -1);
237 
238  changedFacesInfo_.clear();
239  changedFacesInfo_.setSize(mesh_.nFaces());
240 
241  writeFluidSolidInterface(aTilda_, 0, changedFaces_, changedFacesInfo_);
242 
243  List<wallPointData<label>> allFaceInfo(mesh_.nFaces());
244  allCellInfo_.clear();
245  allCellInfo_.setSize(mesh_.nCells());
246 
248  (
249  mesh_,
250  changedFaces_,
251  changedFacesInfo_,
252  allFaceInfo,
253  allCellInfo_,
254  mesh_.globalData().nTotalCells() + 1
255  );
256 
257  // Transfer the distance from cellInfo to the alphaTilda field
258  forAll(allCellInfo_, celli)
259  {
260  if (allCellInfo_[celli].valid(wave.data()))
261  {
262  signedDistances_[celli] =
263  sign(aTilda_[celli])*Foam::sqrt(allCellInfo_[celli].distSqr());
264  }
265  }
266  signedDistances_.correctBoundaryConditions();
267 }
268 
269 
270 // * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
271 
272 levelSetDesignVariables::levelSetDesignVariables
273 (
274  fvMesh& mesh,
275  const dictionary& dict
276 )
277 :
279  designVariables(mesh, dict, mesh.nCells()),
280  radius_
281  (regularisationRadius::New(mesh, dict.subDict("regularisation"), false)),
282  regularisation_
283  (regularisationPDE::New(mesh, dict.subDict("regularisation"), zones_)),
284  aTilda_
285  (
286  IOobject
287  (
288  "aTilda",
289  mesh_.time().timeName(),
290  mesh_,
291  IOobject::READ_IF_PRESENT,
292  IOobject::AUTO_WRITE
293  ),
294  mesh_,
297  ),
298  signedDistances_
299  (
300  IOobject
301  (
302  "signedDistances",
303  mesh_.time().timeName(),
304  mesh_,
305  IOobject::READ_IF_PRESENT,
306  IOobject::AUTO_WRITE
307  ),
308  mesh_,
311  ),
312  interpolation_
313  (
314  topOInterpolationFunction::New(mesh_, dict_.subDict("interpolation"))
315  ),
316  beta_
317  (
318  IOobject
319  (
320  "beta",
321  mesh_.time().timeName(),
322  mesh_,
323  IOobject::READ_IF_PRESENT,
324  IOobject::AUTO_WRITE
325  ),
326  mesh_,
328  ),
329  fixATildaValues_(dict.getOrDefault<bool>("fixATildaValues", true)),
330  writeAllDistanceFields_
331  (dict.getOrDefault<bool>("writeAllDistanceFields", false)),
332  changedFaces_(),
333  changedFacesInfo_(),
334  allCellInfo_()
335 {
336  // Read the alpha field if present, or set it based on the distance field
337  readField();
338 
339  // Read bounds of design variables if present.
340  // If not, use the maximum distance field in the fluid to set them.
341  scalar maxDist = gMax(*this);
342  scalar lowerBound =
343  localIOdictionary::getOrDefault<scalar>("lowerBound", -maxDist - SMALL);
344  scalar upperBound =
345  localIOdictionary::getOrDefault<scalar>("upperBound", maxDist + SMALL);
346  readBounds
347  (
348  autoPtr<scalar>(new scalar(lowerBound)),
349  autoPtr<scalar>(new scalar(upperBound))
350  );
351  DebugInfo
352  << "Using lower/upper bounds "
353  << lowerBounds_()[0] << "/" << upperBounds_()[0]
354  << endl;
355 
356  // Update the beta field based on the initial design vars
357  scalarField zeroUpdate(scalarField::size(), Zero);
358  update(zeroUpdate);
359 
360  // Determine which design variables are active
362 }
363 
364 
365 // * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
366 
368 (
369  fvMesh& mesh,
370  const dictionary& dict
371 )
372 {
374  (
376  );
377 }
378 
379 
380 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
383 {
384  return beta_;
385 }
386 
387 
389 {
391 
392  // Compute the regularised design variables
393  regularisation_->regularise
394  (
396  true, radius_(), upperBounds_()[0], fixATildaValues_
397  );
399 
401  {
402  writeDesignVars();
403  aTilda_.write();
404  }
405 
406  // Compute signed distances based on aTilda
408 
409  // Set beta based on the signed distances
410  updateBeta();
411 
413  {
415  beta_.write();
416  }
417 
418  // Though the mesh is kept constant, the distance from wall may change
419  // due to fvOptions depending on beta. Trick wallDist into updating it
420 
422 }
423 
424 
426 {
427  const scalar maxChange(gMax(mag(correction)));
428  Info<< "maxInitChange/maxChange \t"
429  << maxInitChange_() << "/" << maxChange << endl;
430  const scalar eta(maxInitChange_() / maxChange);
431  Info<< "Setting eta value to " << eta << endl;
432  correction *= eta;
433 
434  return eta;
435 }
436 
437 
439 {
440  return true;
441 }
442 
443 
445 (
446  adjointSensitivity& adjointSens
447 )
448 {
449  // Raw sensitivities field
450  const scalarField& fieldSens = adjointSens.fieldSensPtr()->primitiveField();
451 
452  // Return field
453  auto tobjectiveSens(tmp<scalarField>::New(fieldSens));
454  scalarField& objectiveSens = tobjectiveSens.ref();
455 
456  // Multiply with dBetadAtilda
457  objectiveSens *=
459 
460  // Solve the adjoint to the regularisation equation
462  regularise(aTilda_, objectiveSens, objectiveSens, false, radius_());
463 
464  objectiveSens *= mesh_.V();
465 
467  {
468  volScalarField sens
469  (
470  IOobject
471  (
472  "sens" + adjointSens.getAdjointSolver().solverName(),
473  mesh_.time().timeName(),
474  mesh_,
477  ),
478  mesh_,
480  );
481  sens.primitiveFieldRef() = objectiveSens;
482  sens.write();
483  }
484 
485  return tobjectiveSens;
486 }
487 
488 
490 {
492  {
494  (
495  IOobject
496  (
497  "alpha",
498  mesh_.time().timeName(),
499  mesh_,
502  ),
503  mesh_,
505  );
506  alpha.primitiveFieldRef() = *this;
507  alpha.correctBoundaryConditions();
508 
509  alpha.write();
510  }
511 }
512 
513 
514 bool levelSetDesignVariables::writeData(Ostream& os) const
515 {
516  // Lower and upper bound values might be computed based on the initial
517  // distance field. Write to file to enable continuation
518  os.writeEntry("lowerBound", lowerBounds_()[0]);
519  os.writeEntry("upperBound", upperBounds_()[0]);
520 
521  scalarField::writeEntry("alpha", os);
522 
523  return true;
524 }
525 
526 
527 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
528 
529 } // End namespace Foam
530 
531 // ************************************************************************* //
static const word & zeroGradientType() noexcept
The type name for zeroGradient patch fields.
Definition: fvPatchField.H:221
Base class for selecting the regulatisation radius.
labelList activeDesignVariables_
Which of the design variables will be updated.
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
dimensionedScalar sign(const dimensionedScalar &ds)
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
Return the correction form of the given matrix by subtracting the matrix multiplied by the current fi...
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
const word zeroGradientType
A zeroGradient patch field type.
const Internal::FieldType & primitiveField() const noexcept
Return a const-reference to the internal field values.
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.
autoPtr< regularisationPDE > regularisation_
Regularisation mechanism.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:56
virtual bool globalSum() const
Whether to use global sum when computing matrix-vector products in update methods.
volScalarField aTilda_
The regularised field.
void updateSignedDistances()
Make aTilda a signed distance field based on the zero iso-surface of the current aTilda field...
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
void applyFixedPorosityValues()
Apply fixed values in certain zones.
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
const scalarList & fixedPorousValues() const
Values of alpha for each fixed porous zone.
Definition: topOZones.H:177
Wave propagation of information through grid. Every iteration information goes through one layer of c...
Definition: FaceCellWave.H:206
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.
void writeEntry(const word &keyword, Ostream &os) const
Write the field as a dictionary entry.
Definition: Field.C:720
Template invariant parts for fvPatchField.
Definition: fvPatchField.H:77
Base class for selecting the regulatisation PDE.
autoPtr< regularisationRadius > radius_
The regularisation radius.
Ignore writing from objectRegistry::writeObject()
bool writeTime() const noexcept
True if this is a write interval.
Definition: TimeStateI.H:73
const dimensionSet dimless
Dimensionless.
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
virtual void update(scalarField &correction)
Update design variables based on a given correction.
const DimensionedField< scalar, volMesh > & V() const
Return cell volumes.
const adjointSolver & getAdjointSolver() const
Const access to adjoint solver.
volScalarField signedDistances_
The signed distances field.
const cellZone & IOCells() const
Cells next to IO boundaries.
Definition: topOZones.H:201
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:441
Macros for easy insertion into run-time selection tables.
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
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:72
word timeName
Definition: getTimeIndex.H:3
scalar y
static autoPtr< levelSetDesignVariables > New(fvMesh &mesh, const dictionary &dict)
Return a reference to the selected turbulence model.
void setSize(const label n)
Alias for resize()
Definition: List.H:320
dynamicFvMesh & mesh
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:609
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Foam::wallPolyPatch.
Definition: wallPolyPatch.H:46
const labelList & fixedZeroPorousZoneIDs() const
Cell zone IDs with fixed zero porosity values.
Definition: topOZones.H:185
autoPtr< topOInterpolationFunction > interpolation_
Function to transorm signed distances to the indicator field beta_.
virtual bool write(const bool writeOnProc=true) const
Write using setting from DB.
virtual const volScalarField & beta() const
Const reference to the beta field.
Signed distance field design variables for level-set based topology optimization (topO).
autoPtr< scalar > maxInitChange_
Maximum design variables&#39; change in the first optimisation cycle.
void readBounds(autoPtr< scalar > lowerBoundPtr=nullptr, autoPtr< scalar > upperBoundPtr=nullptr)
Read bounds for design variables, if present.
void readField()
Read the design variables field.
bool writeAllDistanceFields_
Write all fields related to the distance calculation (debugging)
#define DebugInfo
Report an information message using Foam::Info.
volScalarField beta_
The indicator field.
static word timeName(const scalar t, const int precision=precision_)
Return a time name for the given scalar time value formatted with the given precision.
Definition: Time.C:714
label size() const noexcept
The number of elements in the container.
Definition: UList.H:680
int debug
Static debugging option.
Type gMax(const FieldField< Field, Type > &f)
Info<< "Predicted p max-min : "<< max(p).value()<< " "<< min(p).value()<< endl;rho==max(psi *p+alphal *rhol0+((alphav *psiv+alphal *psil) - psi) *pSat, rhoMin);# 1 "/home/chef2/andy/OpenFOAM/release/v2406/OpenFOAM-v2406/applications/solvers/multiphase/cavitatingFoam/alphavPsi.H" 1{ alphav=clamp((rho - rholSat)/(rhovSat - rholSat), zero_one{});alphal=1.0 - alphav;Info<< "max-min alphav: "<< max(alphav).value()<< " "<< min(alphav).value()<< endl;psiModel-> correct()
Definition: pEqn.H:63
OBJstream os(runTime.globalPath()/outputName)
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
autoPtr< scalarField > lowerBounds_
Lower bounds of the design variables.
virtual tmp< scalarField > assembleSensitivities(adjointSensitivity &adjointSens)
Add contributions from the adjoint to the regularization PDE, the derivative of the interpolation fun...
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field values.
Abstract base class for defining design variables.
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:50
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
label nCells() const noexcept
Number of mesh cells.
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.
Automatically write from objectRegistry::writeObject()
autoPtr< scalarField > upperBounds_
Upper bounds of the design variables.
const labelList & adjointPorousZoneIDs() const
Cell zone IDs in which porosity is allowed to change.
Definition: topOZones.H:193
const cellZoneMesh & cellZones() const noexcept
Return cell zone mesh.
Definition: polyMesh.H:679
void correctBoundaryConditions()
Correct boundary field.
messageStream Info
Information stream (stdout output on master, null elsewhere)
void updateBeta()
Update the beta field.
void operator+=(const UList< scalar > &)
Definition: Field.C:799
virtual scalar computeEta(scalarField &correction)
Compute eta if not set in the first step.
List< label > labelList
A List of labels.
Definition: List.H:62
A class for managing temporary objects.
Definition: HashPtrTable.H:50
const dimensionedScalar alpha
Fine-structure constant: default SI units: [].
void setActiveDesignVariables(bool activeIO=false)
Determine which design variables are active.
Base class for all design variables related to topology optimisation (topO). Provides the lookup func...
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:180
static autoPtr< patchDistMethod > New(const dictionary &dict, const fvMesh &mesh, const labelHashSet &patchIDs, const word &defaultPatchDistMethod=word::null)
List< bool > boolList
A List of bools.
Definition: List.H:60
const labelList & fixedPorousZoneIDs() const
Cell zone IDs with fixed porosity values.
Definition: topOZones.H:169
List< wallPoints > allFaceInfo(mesh_.nFaces())
labelHashSet findPatchIDs() const
Find patch indices for a given polyPatch type.
bool fixATildaValues_
Fix aTilda values in fixed{Zero}PorousZones and IOcells.
const autoPtr< volScalarField > & fieldSensPtr() const
Get the fieldSensPtr.
Definition: sensitivity.H:152
virtual void writeDesignVars()
Write useful quantities to files.
virtual bool writeData(Ostream &) const
The writeData function required by the regIOobject write operation.
Namespace for OpenFOAM.
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127