volumetricBSplinesDesignVariables.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 
30 #include "pointVolInterpolation.H"
33 
34 // * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38  defineTypeNameAndDebug(volumetricBSplinesDesignVariables, 0);
40  (
41  shapeDesignVariables,
42  volumetricBSplinesDesignVariables,
44  );
45 }
46 
47 
48 // * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * //
49 
51 {
53 }
54 
55 
58 {
59  return volBSplinesBase_.getActiveDesignVariables();
60 }
61 
62 
64 {
65  // Active design variables pertaining to the CPs numbering
66  labelList activeVarsInCPs = volBSplinesBase_.getActiveDesignVariables();
67 
68  // Convert the aforementioned list to the numbering of the actual design
69  // variables
70  activeDesignVariables_ =
71  constraint_().computeActiveDesignVariables(activeVarsInCPs);
72 }
73 
74 
76 {
77  const scalarField& dvs = *this;
78 
79  // Convert design variables to CPs coordinates, stored in a scalarField
80  scalarField cpsScalar(constraint_().designVariablesToControlPoints(dvs));
81 
82  // Convert the scalarField to vectorFields and transfer to morphing boxes
83  PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef();
84  label varID(0);
85  for (NURBS3DVolume& boxI : boxes)
86  {
87  vectorField cps(boxI.getControlPoints().size(), Zero);
88  for (vector& cpI : cps)
89  {
90  cpI.x() = cpsScalar[varID++];
91  cpI.y() = cpsScalar[varID++];
92  cpI.z() = cpsScalar[varID++];
93  }
94  boxI.setControlPoints(cps);
95  }
96 }
97 
98 
100 {
101  // Store CP coordinates to a scalarField
102  scalarField cpsScalar(3*volBSplinesBase_.getTotalControlPointsNumber());
103  const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxes();
104  label varID(0);
105  for (const NURBS3DVolume& boxI : boxes)
106  {
107  const vectorField& cps = boxI.getControlPoints();
108  for (const vector& cpI : cps)
109  {
110  cpsScalar[varID++] = cpI.x();
111  cpsScalar[varID++] = cpI.y();
112  cpsScalar[varID++] = cpI.z();
113  }
114  }
115 
116  // Convert this scalarField to the design variables
118  (constraint_().controlPointsToDesignVariables(cpsScalar));
119 }
120 
121 
123 (
124  const vectorField& controlPoints
125 )
126 {
127  // Store CP coordinates to a scalarField
128  scalarField cpsScalar(3*volBSplinesBase_.getTotalControlPointsNumber());
129  const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxes();
130  label varID(0);
131  for (const NURBS3DVolume& boxI : boxes)
132  {
133  const label nCPs(boxI.getControlPoints().size());
134  for (label cpI = 0; cpI < nCPs; ++cpI)
135  {
136  cpsScalar[varID++] = controlPoints[cpI].x();
137  cpsScalar[varID++] = controlPoints[cpI].y();
138  cpsScalar[varID++] = controlPoints[cpI].z();
139  }
140  }
141 
142  // Convert this scalarField to the design variables
144  (constraint_().controlPointsToDesignVariables(cpsScalar));
145 }
146 
147 
149 (
150  autoPtr<scalar> lowerBoundPtr,
151  autoPtr<scalar> upperBoundPtr
152 )
153 {
154  designVariables::readBounds(lowerBoundPtr, upperBoundPtr);
155  readBounds(lowerBounds_, "lower", -1);
156  readBounds(upperBounds_, "upper", 1);
158  // Update bounds based on the constraints - WIP
159  constraint_().computeBounds(lowerBounds_, upperBounds_);
160 }
161 
162 
164 (
165  autoPtr<scalarField>& bounds,
166  const word& boundsName,
167  const label sign
168 )
169 {
170  // Read global bounds for the control points
171  if (dict_.found(boundsName + "CPBounds"))
172  {
173  bounds.reset(new scalarField(getVars().size()));
174 
175  vector CPBounds(dict_.get<vector>(boundsName + "CPBounds"));
176  const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef();
177  label varID(0);
178  for (const NURBS3DVolume& boxI : boxes)
179  {
180  const label nCPs(boxI.getControlPoints().size());
181  for (label iCP = 0; iCP < nCPs; ++iCP)
182  {
183  bounds()[varID++] = CPBounds.x();
184  bounds()[varID++] = CPBounds.y();
185  bounds()[varID++] = CPBounds.z();
186  }
187  }
188  }
189  // Read in bounds from the designVariables dictionary if present.
190  // If nonOverlappingCPs is used, the current CPs are used to determine the
191  // bounds of the CPs. If we continue from a previous solution, the current
192  // CPs are different from the initial ones and, hence, different bounds
193  // will be computed for the continuation run. Instead, read the bounds
194  // from the designVariables dict, if present
195  else if (localIOdictionary::found(boundsName + "Bounds"))
196  {
197  DebugInfo
198  << "Reading " << boundsName << "Bounds from dict " << endl;
199  bounds.reset
200  (new scalarField(boundsName + "Bounds", *this, getVars().size()));
201 
202  }
203  else if (nonOverlappingCPs_)
204  {
205  DebugInfo
206  << "Setting " << boundsName << "Bounds from nonOverlappingCPs"
207  << endl;
208  bounds.reset(new scalarField(getVars().size()));
209  const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef();
210  label varID(0);
211  for (const NURBS3DVolume& boxI : boxes)
212  {
213  const vectorField& cps = boxI.getControlPoints();
214  const Vector<label> nCPsDir = boxI.nCPsPerDirection();
215  vector dists(Zero);
216  for (label idir = 0; idir < 3; ++idir)
217  {
218  dists[idir] =
219  (max(cps.component(idir)) - min(cps.component(idir)))
220  /scalar(nCPsDir[idir] - 1);
221  }
222  const label nCPs(boxI.getControlPoints().size());
223  for (label iCP = 0; iCP < nCPs; ++iCP)
224  {
225  const vector& cp = cps[iCP];
226  bounds()[varID++] = cp.x() + sign*0.5*dists.x();
227  bounds()[varID++] = cp.y() + sign*0.5*dists.y();
228  bounds()[varID++] = cp.z() + sign*0.5*dists.z();
229  }
230  }
231  }
232 }
233 
234 
236 (
237  const scalarField& bounds,
238  const word& name
239 ) const
240 {
241  if (Pstream::master())
242  {
243  const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef();
244  label passed(0);
245  for (const NURBS3DVolume& boxI : boxes)
246  {
247  OFstream file
248  (
249  word("optimisation")/word("controlPoints")/boxI.name()
250  + name + mesh_.time().timeName() + ".csv"
251  );
252  // Write header
253  file<< "\"Points : 0\", \"Points : 1\", \"Points : 2\","
254  << "\"i\", \"j\", \"k\""<< endl;
255 
256  const vectorField& cps = boxI.getControlPoints();
257  const label nCPsU = boxI.basisU().nCPs();
258  const label nCPsV = boxI.basisV().nCPs();
259  forAll(cps, cpI)
260  {
261  const label k = cpI/label(nCPsU*nCPsV);
262  const label j = (cpI - k*nCPsU*nCPsV)/nCPsU;
263  const label i = (cpI - k*nCPsU*nCPsV - j*nCPsU);
264 
265  file<< bounds[3*cpI + passed] << ", "
266  << bounds[3*cpI + 1 + passed] << ", "
267  << bounds[3*cpI + 2 + passed] << ", "
268  << i << ", "
269  << j << ", "
270  << k << endl;
271  }
272  passed += 3*cps.size();
273  }
274  }
275 }
276 
277 
279 (
280  const vectorField& cpMovement
281 )
282 {
283  displacementMethod& dm = displMethodPtr_.ref();
284  // Are volumetric B-Splines also used to move the mesh ?
285  if (isA<displacementMethodvolumetricBSplinesMotionSolver>(dm))
286  {
287  // Communicate the control points movement to the displacement method
288  displMethodPtr_->setControlField(cpMovement);
289  }
290  else
291  {
292  // This will also update the control point positions
293  tmp<vectorField> tnewPoints =
294  volBSplinesBase_.computeBoundaryDisplacement
295  (
296  cpMovement,
297  parametertisedPatches_.toc()
298  );
299  const vectorField& newPoints = tnewPoints();
300 
302  (
303  IOobject
304  (
305  "dx",
306  mesh_.time().timeName(),
307  mesh_,
311  ),
312  pointMesh::New(mesh_),
314  );
315 
316  for (const label pI : parametertisedPatches_)
317  {
318  dx.boundaryField()[pI].setInInternalField
319  (
320  dx.primitiveFieldRef(),
321  vectorField(newPoints, mesh_.boundaryMesh()[pI].meshPoints())
322  );
323  }
324 
325  // Set boundary movement of motion solver
326  displMethodPtr_->setMotionField(dx);
327  }
328 }
329 
330 
331 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
332 
333 Foam::volumetricBSplinesDesignVariables::volumetricBSplinesDesignVariables
334 (
335  fvMesh& mesh,
336  const dictionary& dict
337 )
338 :
339  shapeDesignVariables(mesh, dict),
340  localIOdictionary
341  (
342  IOobject
343  (
344  "volumetricBSplinesDesignVariables",
345  mesh.time().timeName(),
346  fileName("uniform"),
347  mesh,
348  IOobject::READ_IF_PRESENT,
349  IOobject::AUTO_WRITE
350  ),
351  word::null
352  ),
353  volBSplinesBase_(const_cast<volBSplinesBase&>(volBSplinesBase::New(mesh))),
354  nonOverlappingCPs_(dict_.getOrDefault<bool>("nonOverlappingCPs", false)),
355  updateBounds_(dict_.getOrDefault<bool>("updateBounds", true)),
356  constraint_(morphingBoxConstraint::New(mesh, dict, *this))
357 {
358  // Read in design variables if present or initialise them
359  if (localIOdictionary::found("designVariables"))
360  {
362  (scalarField("designVariables", *this, scalarField::size()));
363  }
364  else if (constraint_().initialiseVars())
365  {
367  }
368 
369  // Set the active design variables
371 
372  // Read bounds for design variables, if present
373  readBounds();
374 }
375 
376 
377 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * //
378 
381 (
382  const scalarField& correction
383 )
384 {
385  auto tcpMovement
386  (
388  (
389  volBSplinesBase_.getTotalControlPointsNumber(),
390  Zero
391  )
392  );
393  vectorField& cpMovement = tcpMovement.ref();
394 
395  // Convert the correction pertaining to the design variables to a
396  // scalarField correction for the control points
397  const scalarField correctionCPs(constraint_().correctionCPs(correction));
398 
399  // scalarField to vectorField conversion
400  forAll(cpMovement, iCP)
401  {
402  cpMovement[iCP].x() = correctionCPs[3*iCP];
403  cpMovement[iCP].y() = correctionCPs[3*iCP + 1];
404  cpMovement[iCP].z() = correctionCPs[3*iCP + 2];
405  }
406  volBSplinesBase_.boundControlPointMovement(cpMovement);
407 
408  return tcpMovement;
409 }
410 
411 
413 {
414  // Get controlPoint movement from correction
415  tmp<vectorField> tcpMovement = controlPointMovement(correction);
416  const vectorField& cpMovement = tcpMovement();
417 
418  // Set the field driving the displacement method
419  setDisplacement(cpMovement);
420 
421  // Do the actual mesh movement
422  // Updates also the control point positions
423  moveMesh();
424 
425  // Update the design variables
427 }
428 
429 
431 {
433  designVariablesToControlPoints();
434 }
435 
436 
437 Foam::scalar
439 {
440  return constraint_().computeEta(correction, maxInitChange_());
441 }
442 
443 
445 {
446  return false;
447 }
448 
449 
452 (
453  adjointSensitivity& adjointSens
454 )
455 {
456  return
457  constraint_().postProcessSens
458  (
460  adjointSens.getAdjointSolver().solverName()
461  );
462 }
463 
466 {
467  constraint_().updateBounds(lowerBounds_, upperBounds_);
468 }
469 
470 
472 {
473  scalarField::writeEntry("designVariables", os);
474  if (lowerBounds_)
475  {
476  lowerBounds_().writeEntry("lowerBounds", os);
477  writeBounds(lowerBounds_(), "lowerBounds");
478  }
479  if (upperBounds_)
480  {
481  upperBounds_().writeEntry("upperBounds", os);
482  writeBounds(upperBounds_(), "upperBounds");
483  }
484  return constraint_().writeData(os);
485 }
486 
487 
489 (
490  const label varID
491 ) const
492 {
493  const displacementMethod& dm = displMethodPtr_();
494  if (isA<displacementMethodvolumetricBSplinesMotionSolver>(dm))
495  {
496  Vector<label> decomposed = volBSplinesBase_.decomposeDV(varID);
497  const label boxI = decomposed.x();
498  const label cpILocal = decomposed.y();
499  const label dir = decomposed.z();
500 
501  pointTensorField dxdb(volBSplinesBase_.boxRef(boxI).getDxDb(cpILocal));
502  return unzipCol(dxdb, dir);
503  }
504  return tmp<vectorField>::New(0);
505 }
506 
507 
509 (
510  const label patchI,
511  const label varID
512 ) const
513 {
514  Vector<label> decomposed = volBSplinesBase_.decomposeDV(varID);
515  const label boxI = decomposed.x();
516  const label cpILocal = decomposed.y();
517  const label dir = decomposed.z();
518 
520  (volBSplinesBase_.boxRef(boxI).patchDxDbFace(patchI, cpILocal));
521  return unzipCol(dxdb, dir);
522 }
523 
524 
526 (
527  const label patchI,
528  const label varID
529 ) const
530 {
531  Vector<label> decomposed = volBSplinesBase_.decomposeDV(varID);
532  const label boxI = decomposed.x();
533  const label cpILocal = decomposed.y();
534  const label dir = decomposed.z();
535 
536  tensorField dndb
537  (
538  volBSplinesBase_.boxRef(boxI).
539  dndbBasedSensitivities(patchI, cpILocal, false)
540  );
541  return unzipCol(dndb, dir);
542 }
543 
544 
546 (
547  const label patchI,
548  const label varID
549 ) const
550 {
551  Vector<label> decomposed = volBSplinesBase_.decomposeDV(varID);
552  const label boxI = decomposed.x();
553  const label cpILocal = decomposed.y();
554  const label dir = decomposed.z();
555 
556  tensorField dndb
557  (
558  volBSplinesBase_.boxRef(boxI).dndbBasedSensitivities(patchI, cpILocal)
559  );
560  return unzipCol(dndb, dir);
561 }
562 
563 
565 (
566  const label varID
567 ) const
568 {
569  Vector<label> decomposed = volBSplinesBase_.decomposeDV(varID);
570  const label boxI = decomposed.x();
571  const label cpILocal = decomposed.y();
572  const label dir = decomposed.z();
573  NURBS3DVolume& box = volBSplinesBase_.boxRef(boxI);
574  pointVolInterpolation volPointInter(pointMesh::New(mesh_), mesh_);
575  // WIP: we compute the entire dxdb tensor corresponding to the contol point
576  // and then extract the desired direction. This is quite expensive.
577  // Specific functions returning what we want should be implemented in
578  // NURBS3DVolume to reduce the cost
579  tmp<volTensorField> dxdb = volPointInter.interpolate(box.getDxDb(cpILocal));
580  auto tdxdbDir =
582  (
583  IOobject
584  (
585  "dxdbDir",
586  mesh_.time().timeName(),
587  mesh_,
590  ),
591  mesh_,
593  );
594  volVectorField& dxdbDir = tdxdbDir.ref();
595  unzipCol(dxdb(), vector::components(dir), dxdbDir);
596  return tdxdbDir;
597 }
598 
599 
600 // ************************************************************************* //
dimensionedScalar sign(const dimensionedScalar &ds)
void readBounds(autoPtr< scalar > lowerBoundPtr=nullptr, autoPtr< scalar > upperBoundPtr=nullptr)
Read bounds for design variables, if present.
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
autoPtr< morphingBoxConstraint > constraint_
Constraint imposed on the movement of the design variables.
virtual bool globalSum() const
Whether to use global sum when computing matrix-vector products in update methods.
virtual void evolveNumber()
For design variables with a dynamic character (i.e. changing.
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:130
Abstract base class for adjoint-based sensitivities.
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 resetDesignVariables()
Reset to starting point of line search.
virtual scalar computeEta(scalarField &correction)
Compute eta if not set in the first step.
static FOAM_NO_DANGLING_REFERENCE const pointMesh & New(const polyMesh &mesh, Args &&... args)
Get existing or create MeshObject registered with typeName.
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:518
bool cp(const fileName &src, const fileName &dst, const bool followLink=true)
Copy the source to the destination (recursively if necessary).
Definition: POSIX.C:1069
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.
volBSplinesBase & volBSplinesBase_
Reference to underlaying volumetric B-Splines morpher.
void designVariablesToControlPoints()
Set control points based on current design variables values.
virtual tmp< scalarField > assembleSensitivities(adjointSensitivity &adjointSens)
Add part of sensitivity derivatives related to geometry variations.
GeometricField< vector, pointPatchField, pointMesh > pointVectorField
void writeEntry(const word &keyword, Ostream &os) const
Write the field as a dictionary entry.
Definition: Field.C:754
const Cmpt & y() const noexcept
Access to the vector y component.
Definition: Vector.H:150
label k
Boltzmann constant.
Ignore writing from objectRegistry::writeObject()
const dimensionSet dimless
Dimensionless.
const adjointSolver & getAdjointSolver() const
Const access to adjoint solver.
NURBS3DVolume morpher. Includes support functions for gradient computations Base class providing supp...
Definition: NURBS3DVolume.H:69
Macros for easy insertion into run-time selection tables.
GeometricField< tensor, pointPatchField, pointMesh > pointTensorField
virtual tmp< scalarField > assembleSensitivities(adjointSensitivity &adjointSens)
Assemble the sensitivity derivatives, by also applying possible constraints.
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:400
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:36
virtual void update(scalarField &correction)
Update design variables based on a given correction.
word timeName
Definition: getTimeIndex.H:3
void writeBounds(const scalarField &bounds, const word &name) const
Write current bounds to file.
friend Ostream & operator(Ostream &, const Field< scalar > &)
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
virtual tmp< volVectorField > dCdb(const label varID) const
Get dCdb for given design variable.
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
void controlPointsToDesignVariables()
Set the design variables based on the current control points.
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:217
void readBounds(autoPtr< scalar > lowerBoundPtr=nullptr, autoPtr< scalar > upperBoundPtr=nullptr)
Read bounds for design variables, if present.
Vector< scalar > vector
Definition: vector.H:57
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
#define DebugInfo
Report an information message using Foam::Info.
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
label size() const noexcept
The number of elements in the container.
Definition: UList.H:707
const Cmpt & x() const noexcept
Access to the vector x component.
Definition: Vector.H:145
void setActiveDesignVariables()
Set IDs of active design variables.
defineTypeNameAndDebug(combustionModel, 0)
virtual tmp< vectorField > dxdbFace(const label patchI, const label varID) const
Get dxdb for given design variable and patch.
tmp< vectorField > controlPointMovement(const scalarField &correction)
Transform correction of design variables to control points movement.
void unzipCol(const FieldField< Field, SymmTensor< Cmpt >> &input, const direction idx, FieldField< Field, Vector< Cmpt >> &result)
Extract a symmTensor field field column (x,y,z) == (0,1,2)
virtual tmp< vectorField > dSdb(const label patchI, const label varID) const
Get dSdb for given design variable and patch.
label getTotalControlPointsNumber() const
Get cumulative number of control points from all boxes.
decomposeUsingBbs false
Use bounding boxes (default) or unique decomposition of triangles (i.e. do not duplicate triangles) ...
const Cmpt & z() const noexcept
Access to the vector z component.
Definition: Vector.H:155
void setDisplacement(const vectorField &cpMovement)
Set the field driving the displacement method.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers...
Definition: PtrList.H:56
const word & solverName() const
Return the solver name.
Definition: solverI.H:30
Nothing to be read.
virtual label sensSize() const
Size of the active control points.
Internal & ref(const bool updateAccessTime=true)
Same as internalFieldRef()
static bool master(label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1807
components
Component labeling enumeration.
Definition: Vector.H:83
Field< vector > vectorField
Specialisation of Field<T> for vector.
virtual void resetDesignVariables()
Reset to starting point of line search.
void operator+=(const UList< scalar > &)
Definition: Field.C:833
tmp< pointTensorField > getDxDb(const label cpI)
Get dxCartesiandb for a certain control point.
virtual tmp< vectorField > dxdbVol(const label varID) const
Get dxdb for all mesh points.
A class for managing temporary objects.
Definition: HashPtrTable.H:50
virtual bool writeData(Ostream &os) const
Write fields to support continuation.
virtual const labelList & activeSensitivities() const
Components of the active control points.
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:188
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
Do not request registration (bool: false)
virtual tmp< vectorField > dndb(const label patchI, const label varID) const
Get dndb for given design variable and patch.
Namespace for OpenFOAM.
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127