sensitivitySurfacePointsIncompressible.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-2020, 2022 PCOpt/NTUA
9  Copyright (C) 2013-2020, 2022 FOSS GP
10  Copyright (C) 2019-2022 OpenCFD Ltd.
11 -------------------------------------------------------------------------------
12 License
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 
33 #include "syncTools.H"
34 
35 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39 
40 namespace incompressible
41 {
42 
43 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
44 
45 defineTypeNameAndDebug(sensitivitySurfacePoints, 0);
47 (
51 );
52 
53 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
54 
56 {
58  dict().getOrDefault<bool>("includeSurfaceArea", false);
60  dict().getOrDefault<bool>("includePressure", true);
62  dict().getOrDefault<bool>("includeGradStressTerm", true);
64  dict().getOrDefault<bool>("includeTransposeStresses", true);
66  dict().getOrDefault<bool>("useSnGradInTranposeStresses", false);
68  dict().getOrDefault<bool>("includeDivTerm", false);
70  dict().getOrDefault<bool>
71  (
72  "includeDistance",
73  adjointVars_.adjointTurbulence().ref().includeDistance()
74  );
76  dict().getOrDefault<bool>("includeMeshMovement", true);
78  dict().getOrDefault<bool>("includeObjectiveContribution", true);
79 
80  // Allocate new solvers if necessary
82  {
83  eikonalSolver_.reset
84  (
86  (
87  mesh_,
88  dict(),
91  sensitivityPatchIDs_
92  )
93  );
94  }
95 
97  {
99  (
101  (
102  mesh_,
103  dict(),
104  *this,
105  sensitivityPatchIDs_,
107  )
108  );
109  }
110 }
111 
112 
114 {
115  // Solve extra equations if necessary
116  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117  autoPtr<boundaryVectorField> distanceSensPtr(nullptr);
118  if (includeDistance_)
119  {
120  eikonalSolver_->solve();
121  distanceSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
122  const boundaryVectorField& sens =
123  eikonalSolver_->distanceSensitivities();
124  for (const label patchI : sensitivityPatchIDs_)
125  {
126  distanceSensPtr()[patchI] = sens[patchI];
127  }
128  }
129 
130  autoPtr<boundaryVectorField> meshMovementSensPtr(nullptr);
132  {
133  meshMovementSolver_->solve();
134  meshMovementSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
135  const boundaryVectorField& sens =
136  meshMovementSolver_->meshMovementSensitivities();
137  for (const label patchI : sensitivityPatchIDs_)
138  {
139  meshMovementSensPtr()[patchI] = sens[patchI];
140  }
141  }
142 
143  // Add to other terms multiplying dxFace/dxPoints
144  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
145  for (const label patchI : sensitivityPatchIDs_)
146  {
147  const fvPatch& patch = mesh_.boundary()[patchI];
148  tmp<vectorField> tnf = patch.nf();
149  const scalarField& magSf = patch.magSf();
150  // Distance related terms
151  if (includeDistance_)
152  {
153  wallFaceSens_()[patchI] += distanceSensPtr()[patchI];
154  }
155 
156  // Mesh movement related terms
158  {
159  wallFaceSens_()[patchI] += meshMovementSensPtr()[patchI];
160  }
161 
162  // Add local face area
163  //~~~~~~~~~~~~~~~~~~~~
164  // Sensitivities DO include locale surface area, to get
165  // the correct weighting from the contributions of various faces.
166  // Normalized at the end.
167  // dSfdbMult already includes the local area. No need to re-multiply
168  wallFaceSens_()[patchI] *= magSf;
169  dnfdbMult_()[patchI] *= magSf;
170  }
171 }
172 
173 
175 {
176  // Geometric (or "direct") sensitivities are better computed directly on
177  // the points. Compute them and add the ones that depend on dxFace/dxPoint
178  for (const label patchI : sensitivityPatchIDs_)
179  {
180  const fvPatch& patch = mesh_.boundary()[patchI];
181  vectorField nf(patch.nf());
182 
183  // Point sens result for patch
184  vectorField& pointPatchSens = wallPointSensVecPtr_()[patchI];
185 
186  // Face sens for patch
187  const vectorField& facePatchSens = wallFaceSens_()[patchI];
188 
189  // Geometry variances
190  const vectorField& dSfdbMultPatch = dSfdbMult_()[patchI];
191  const vectorField& dnfdbMultPatch = dnfdbMult_()[patchI];
192 
193  // Correspondance of local point addressing to global point addressing
194  const labelList& meshPoints = patch.patch().meshPoints();
195 
196  // List with mesh faces. Global addressing
197  const faceList& faces = mesh_.faces();
198 
199  // Each local patch point belongs to these local patch faces
200  // (local numbering)
201  const labelListList& patchPointFaces = patch.patch().pointFaces();
202 
203  // Index of first face in patch
204  const label patchStartIndex = patch.start();
205 
206  // Geometry differentiation engine
207  deltaBoundary dBoundary(mesh_);
208 
209  // Loop over patch points.
210  // Collect contributions from each boundary face this point belongs to
211  forAll(meshPoints, ppI)
212  {
213  const labelList& pointFaces = patchPointFaces[ppI];
214  forAll(pointFaces, pfI)
215  {
216  label localFaceIndex = pointFaces[pfI];
217  label globalFaceIndex = patchStartIndex + localFaceIndex;
218  const face& faceI = faces[globalFaceIndex];
219 
220  // Point coordinates. All indices in global numbering
221  pointField p(faceI.points(mesh_.points()));
222  tensorField p_d(faceI.size(), Zero);
223  forAll(faceI, facePointI)
224  {
225  if (faceI[facePointI] == meshPoints[ppI])
226  {
227  p_d[facePointI] = tensor::I;
228  }
229  }
230  tensorField deltaNormals =
231  dBoundary.makeFaceCentresAndAreas_d(p, p_d);
232 
233  // Element [0] is the variation in the face center
234  // (dxFace/dxPoint)
235  const tensor& deltaCf = deltaNormals[0];
236  pointPatchSens[ppI] += facePatchSens[localFaceIndex] & deltaCf;
237 
238  // Term multiplying d(Sf)/d(point displacement) and
239  // d(nf)/d(point displacement)
240  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
241  if (includeObjective_)
242  {
243  // Element [1] is the variation in the (dimensional) normal
244  const tensor& deltaSf = deltaNormals[1];
245  pointPatchSens[ppI] +=
246  dSfdbMultPatch[localFaceIndex] & deltaSf;
247 
248  // Element [2] is the variation in the unit normal
249  const tensor& deltaNf = deltaNormals[2];
250  pointPatchSens[ppI] +=
251  dnfdbMultPatch[localFaceIndex] & deltaNf;
252  }
253  }
254  }
255  }
256 }
257 
258 
260 (
261  vectorField& pointNormals,
262  scalarField& pointMagSf
263 )
264 {
265  for (const label patchI : sensitivityPatchIDs_)
266  {
267  const fvPatch& patch = mesh_.boundary()[patchI];
268  const scalarField& magSf = patch.magSf();
269  vectorField nf(patch.nf());
270 
271  // Correspondance of local point addressing to global point addressing
272  const labelList& meshPoints = patch.patch().meshPoints();
273 
274  // Each local patch point belongs to these local patch faces
275  // (local numbering)
276  const labelListList& patchPointFaces = patch.patch().pointFaces();
277 
278  // Loop over patch points
279  forAll(meshPoints, ppI)
280  {
281  const labelList& pointFaces = patchPointFaces[ppI];
282  forAll(pointFaces, pfI)
283  {
284  const label localFaceIndex = pointFaces[pfI];
285 
286  // Accumulate information for point normals
287  pointNormals[meshPoints[ppI]] += nf[localFaceIndex];
288  pointMagSf[meshPoints[ppI]] += magSf[localFaceIndex];
289  }
290  }
291  }
292 
294  (
295  mesh_,
296  pointNormals,
297  plusEqOp<vector>(),
298  vector::zero
299  );
301  (
302  mesh_,
303  pointMagSf,
305  scalar(0)
306  );
307 }
308 
309 
311 {
312  word suffix(dict().getOrDefault<word>("suffix", word::null));
313  // Determine suffix for fields holding the sens
315  {
317  (
318  adjointVars_.solverName() + "ESI" + suffix
319  );
320  }
321  else
322  {
324  (
325  adjointVars_.solverName() + "SI" + suffix
326  );
327  }
328 }
329 
330 
331 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
332 
333 sensitivitySurfacePoints::sensitivitySurfacePoints
334 (
335  const fvMesh& mesh,
336  const dictionary& dict,
338 )
339 :
340  adjointSensitivity(mesh, dict, adjointSolver),
342  includeSurfaceArea_(false),
343  includePressureTerm_(false),
344  includeGradStressTerm_(false),
345  includeTransposeStresses_(false),
346  useSnGradInTranposeStresses_(false),
347  includeDivTerm_(false),
348  includeDistance_(false),
349  includeMeshMovement_(false),
350  includeObjective_(false),
351  eikonalSolver_(nullptr),
352  meshMovementSolver_(nullptr),
353  wallFaceSens_(createZeroBoundaryPtr<vector>(mesh_)),
354  dSfdbMult_(createZeroBoundaryPtr<vector>(mesh_)),
355  dnfdbMult_(createZeroBoundaryPtr<vector>(mesh_))
356 
357 {
358  read();
359 
360  // Allocate boundary field pointer
361  wallPointSensVecPtr_.reset(createZeroBoundaryPointFieldPtr<vector>(mesh_));
362  wallPointSensNormalPtr_.reset
363  (
364  createZeroBoundaryPointFieldPtr<scalar>(mesh_)
365  );
366  wallPointSensNormalVecPtr_.reset
367  (
368  createZeroBoundaryPointFieldPtr<vector>(mesh_)
369  );
370 
371  // Allocate appropriate space for sensitivities
372  label nTotalPoints(0);
373  for (const label patchI : sensitivityPatchIDs_)
374  {
375  nTotalPoints += mesh_.boundaryMesh()[patchI].nPoints();
376  }
377  reduce(nTotalPoints, sumOp<label>());
378 
379  // Derivatives for all (x,y,z) components of the displacement are kept
380  derivatives_ = scalarField(3*nTotalPoints, Zero);
381 }
382 
383 
384 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
385 
387 {
389  {
390  if (eikonalSolver_)
391  {
392  eikonalSolver_().readDict(dict);
393  }
394 
396  {
397  meshMovementSolver_().readDict(dict);
398  }
399 
400  return true;
401  }
402 
403  return false;
404 }
405 
406 
408 {
409  // Grab references
410  const volScalarField& p = primalVars_.p();
411  const volVectorField& U = primalVars_.U();
412 
413  const volScalarField& pa = adjointVars_.pa();
414  const volVectorField& Ua = adjointVars_.Ua();
417 
418  // Solve extra equations if necessary
419  if (includeDistance_)
420  {
421  eikonalSolver_->accumulateIntegrand(dt);
422  }
423 
425  {
426  meshMovementSolver_->accumulateIntegrand(dt);
427  }
428 
429  // Terms from the adjoint turbulence model
430  const boundaryVectorField& adjointTMsensitivities =
431  adjointTurbulence->wallShapeSensitivities();
432 
433  // Objective references
434  PtrList<objective>& functions(objectiveManager_.getObjectiveFunctions());
435 
436  DebugInfo
437  << " Calculating adjoint sensitivity. " << endl;
438 
439  tmp<volScalarField> tnuEff = adjointTurbulence->nuEff();
440  const volScalarField& nuEff = tnuEff.ref();
441 
442  // Deal with the stress part first since it's the most awkward in terms
443  // of memory managment
445  {
446  // Terms corresponding to contributions from converting delta
447  // to thetas are added through the corresponding adjoint
448  // boundary conditions instead of grabbing contributions from
449  // the objective function. Useful to have a unified
450  // formulation for low- and high-re meshes
451 
452  tmp<volVectorField> tgradp = fvc::grad(p);
453  const volVectorField& gradp = tgradp.ref();
454  for (const label patchI : sensitivityPatchIDs_)
455  {
456  const fvPatch& patch = mesh_.boundary()[patchI];
457  tmp<vectorField> tnf = patch.nf();
458  const fvPatchVectorField& Uab = Ua.boundaryField()[patchI];
459  wallFaceSens_()[patchI] -=
460  (Uab & tnf)*gradp.boundaryField()[patchI]*dt;
461  }
462  tgradp.clear();
463 
464  // We only need to modify the boundaryField of gradU locally.
465  // If grad(U) is cached then
466  // a. The .ref() call fails since the tmp is initialised from a
467  // const ref
468  // b. we would be changing grad(U) for all other places in the code
469  // that need it
470  // So, always allocate new memory and avoid registering the new field
471  tmp<volTensorField> tgradU =
472  volTensorField::New("gradULocal", fvc::grad(U));
473  volTensorField::Boundary& gradUbf = tgradU.ref().boundaryFieldRef();
474 
475  // Explicitly correct the boundary gradient to get rid of the
476  // tangential component
477  forAll(mesh_.boundary(), patchI)
478  {
479  const fvPatch& patch = mesh_.boundary()[patchI];
480  if (isA<wallFvPatch>(patch))
481  {
482  tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
483  gradUbf[patchI] = tnf*U.boundaryField()[patchI].snGrad();
484  }
485  }
486 
487  tmp<volSymmTensorField> tstress = nuEff*twoSymm(tgradU);
488  const volSymmTensorField& stress = tstress.cref();
489  autoPtr<volVectorField> ptemp
490  (Foam::createZeroFieldPtr<vector>(mesh_, "temp", sqr(dimVelocity)));
491  volVectorField& temp = ptemp.ref();
492  for (label idir = 0; idir < pTraits<vector>::nComponents; ++idir)
493  {
494  unzipRow(stress, idir, temp);
495  volTensorField gradStressDir(fvc::grad(temp));
496  for (const label patchI : sensitivityPatchIDs_)
497  {
498  const fvPatch& patch = mesh_.boundary()[patchI];
499  tmp<vectorField> tnf = patch.nf();
500  const fvPatchVectorField& Uab = Ua.boundaryField()[patchI];
501  wallFaceSens_()[patchI] +=
502  (
503  Uab.component(idir)
504  *(gradStressDir.boundaryField()[patchI] & tnf)
505  )*dt;
506  }
507  }
508  }
509 
510  // Transpose part of the adjoint stresses
511  // Dealt with separately to deallocate gradUa as soon as possible
513  {
514  tmp<volTensorField> tgradUa = fvc::grad(Ua);
515  const volTensorField::Boundary& gradUabf =
516  tgradUa.cref().boundaryField();
517  for (const label patchI : sensitivityPatchIDs_)
518  {
519  const fvPatch& patch = mesh_.boundary()[patchI];
520  tmp<vectorField> tnf = patch.nf();
521  const vectorField& nf = tnf();
522  vectorField gradUaNf
523  (
525  ? (Ua.boundaryField()[patchI].snGrad() & nf)*nf
526  : (gradUabf[patchI] & nf)
527  );
528  wallFaceSens_()[patchI] -=
529  nuEff.boundaryField()[patchI]
530  *(gradUaNf & U.boundaryField()[patchI].snGrad())*tnf;
531  }
532  }
533 
534  // The face-based part of the sensitivities, i.e. terms that multiply
535  // dxFace/dxPoint.
536  for (const label patchI : sensitivityPatchIDs_)
537  {
538  const fvPatch& patch = mesh_.boundary()[patchI];
539  tmp<vectorField> tnf = patch.nf();
540  const vectorField& nf = tnf();
541 
542  // Adjoint stress term
543  // vectorField stressTerm
544  // (
545  // -(nf & DUa.boundaryField()[patchI])
546  // *nuEff.boundaryField()[patchI]
547  // & gradU.boundaryField()[patchI].T();
548  // )
549 
550  vectorField stressTerm
551  (
552  - (
553  Ua.boundaryField()[patchI].snGrad()
554  & U.boundaryField()[patchI].snGrad()
555  )
556  * nuEff.boundaryField()[patchI]
557  * nf
558  );
559 
560  if (includeDivTerm_)
561  {
562  stressTerm +=
563  scalar(1./3.)*nuEff.boundaryField()[patchI]
564  * (
565  ((Ua.boundaryField()[patchI].snGrad() &nf)*nf)
566  & U.boundaryField()[patchI].snGrad()
567  )
568  *nf;
569  }
570 
571  // Adjoint pressure terms
572  vectorField pressureTerm(patch.size(), Zero);
574  {
575  pressureTerm =
576  (
577  (nf*pa.boundaryField()[patchI])
578  & U.boundaryField()[patchI].snGrad()
579  )
580  *nf;
581  }
582 
583  vectorField dxdbMultiplierTot(patch.size(), Zero);
584  if (includeObjective_)
585  {
586  // Term from objectives multiplying dxdb
587  forAll(functions, funcI)
588  {
589  const scalar wei = functions[funcI].weight();
590  // dt added in wallFaceSens_
591  dxdbMultiplierTot +=
592  wei*functions[funcI].dxdbDirectMultiplier(patchI);
593 
594  // Fill in multipliers of d(Sf)/db and d(nf)/db
595  dSfdbMult_()[patchI] +=
596  wei*dt*functions[funcI].dSdbMultiplier(patchI);
597  dnfdbMult_()[patchI] +=
598  wei*dt*functions[funcI].dndbMultiplier(patchI);
599  }
600  }
601 
602  // Fill in dxFace/dxPoint multiplier.
603  // Missing geometric contributions which are directly computed on the
604  // points
605  wallFaceSens_()[patchI] +=
606  (
607  stressTerm
608  + pressureTerm
609  + adjointTMsensitivities[patchI]
610  + dxdbMultiplierTot
611  )*dt;
612  }
614  // Add terms from physics other than the typical incompressible flow eqns
616  (wallFaceSens_(), sensitivityPatchIDs_, dt);
617 }
618 
619 
621 {
622  // Add remaining parts to term multiplying dxFace/dxPoints
623  // Solves for post-processing PDEs
625 
626  // Geometric (or "direct") sensitivities are better computed directly on
627  // the points. Compute them and add the ones that depend on dxFace/dxPoint
629 
630  // polyPatch::pointNormals will give the wrong result for points
631  // belonging to multiple patches or patch-processorPatch intersections.
632  // Keeping a mesh-wide field to allow easy reduction using syncTools.
633  // A bit expensive? Better way?
634  vectorField pointNormals(mesh_.nPoints(), Zero);
635  scalarField pointMagSf(mesh_.nPoints(), Zero);
636  constructGlobalPointNormalsAndAreas(pointNormals, pointMagSf);
637 
638  // Do parallel communications to avoid wrong values at processor boundaries
639  // Global field for accumulation
640  vectorField pointSensGlobal(mesh_.nPoints(), Zero);
641  for (const label patchI : sensitivityPatchIDs_)
642  {
643  const labelList& meshPoints = mesh_.boundaryMesh()[patchI].meshPoints();
644  forAll(meshPoints, ppI)
645  {
646  const label globaPointI = meshPoints[ppI];
647  pointSensGlobal[globaPointI] +=
648  wallPointSensVecPtr_()[patchI][ppI];
649  }
650  }
651 
652  // Accumulate dJ/dx_i
654  (
655  mesh_,
656  pointSensGlobal,
658  vector::zero
659  );
660 
661  // Transfer back to local fields
662  for (const label patchI : sensitivityPatchIDs_)
663  {
664  const labelList& meshPoints =
665  mesh_.boundaryMesh()[patchI].meshPoints();
666  wallPointSensVecPtr_()[patchI].map(pointSensGlobal, meshPoints);
667  }
668 
669  // Compute normal sens and append to return field
670  label nPassedDVs(0);
671  for (const label patchI : sensitivityPatchIDs_)
672  {
673  const polyPatch& patch = mesh_.boundaryMesh()[patchI];
674  List<scalarField> procPatchSens(Pstream::nProcs());
675  //if (patch.size()>0)
676  {
677  const labelList& meshPoints = patch.meshPoints();
678 
679  // Avoid storing unit point normals in the global list since we
680  // might divide multiple times with the number of faces belonging
681  // to the point. Instead do the division locally, per patch use
682  vectorField patchPointNormals(pointNormals, meshPoints);
683  patchPointNormals /= mag(patchPointNormals) + VSMALL;
684  if (!includeSurfaceArea_)
685  {
686  wallPointSensVecPtr_()[patchI] /=
687  scalarField(pointMagSf, meshPoints);
688  }
689  wallPointSensNormalPtr_()[patchI] =
690  wallPointSensVecPtr_()[patchI]
691  & patchPointNormals;
692  wallPointSensNormalVecPtr_()[patchI] =
693  wallPointSensNormalPtr_()[patchI]
694  *patchPointNormals;
695 
696  // 1. Gather sens from all processors for this patch and communicate
697  // them back. Potentially large memory overhead but the rest of the
698  // code structure assumes that all procs know all sensitivity
699  // derivatives
700  //
701  // 2. Transfer vectorial sensitivities to scalarField.
702  // Needed since the normal point vector is wrongly computed at patch
703  // boundaries and cannot be used to reconstruct a vectorial movement
704  // from just its normal component
705  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
706 
707  procPatchSens[Pstream::myProcNo()].setSize
708  (
709  3*wallPointSensNormalVecPtr_()[patchI].size()
710  );
711  scalarField& patchScalarSens = procPatchSens[Pstream::myProcNo()];
712  forAll(wallPointSensNormalVecPtr_()[patchI], ptI)
713  {
714  patchScalarSens[3*ptI] =
715  wallPointSensNormalVecPtr_()[patchI][ptI].x();
716  patchScalarSens[3*ptI + 1] =
717  wallPointSensNormalVecPtr_()[patchI][ptI].y();
718  patchScalarSens[3*ptI + 2] =
719  wallPointSensNormalVecPtr_()[patchI][ptI].z();
720  }
721  Pstream::allGatherList(procPatchSens);
722 
723  forAll(procPatchSens, procI)
724  {
725  const scalarField& procSens = procPatchSens[procI];
726  forAll(procSens, dvI)
727  {
728  derivatives_[nPassedDVs + dvI] = procSens[dvI];
729  }
730  nPassedDVs += procSens.size();
731  }
732  }
733  }
734 }
735 
736 
738 {
739  // Reset terms in post-processing PDEs
740  if (includeDistance_)
741  {
742  eikonalSolver_->reset();
743  }
745  {
746  meshMovementSolver_->reset();
747  }
748 
749  // Reset local fields to zero
750  wallFaceSens_() = vector::zero;
751  dSfdbMult_() = vector::zero;
752  dnfdbMult_() = vector::zero;
754  // Reset sensitivity fields
757 }
758 
759 
760 void sensitivitySurfacePoints::write(const word& baseName)
761 {
762  setSuffixName();
765 }
766 
767 
768 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
769 
770 } // End namespace Foam
771 } // End namespace incompressible
772 
773 // ************************************************************************* //
const fvMesh & mesh_
Definition: sensitivity.H:65
Solver of the adjoint to the Laplace grid displacement equation.
GeometricField< symmTensor, fvPatchField, volMesh > volSymmTensorField
Definition: volFieldsFwd.H:85
dictionary dict
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh >> grad(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcGrad.C:47
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
bool includeGradStressTerm_
Include the term containing the grad of the stress at the boundary.
void setSuffix(const word &suffix)
Set suffix.
virtual bool readDict(const dictionary &dict)
Read dictionary if changed.
Definition: sensitivity.C:56
defineTypeNameAndDebug(adjointEikonalSolver, 0)
fvPatchField< vector > fvPatchVectorField
virtual void accumulateIntegrand(const scalar dt)
Accumulate sensitivity integrands.
virtual void additionalSensitivityMapTerms(boundaryVectorField &sensitivityMap, const labelHashSet &patchIDs, const scalar dt)
Terms to be added to the sensitivity map, depending on the adjoint solver.
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:68
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
label nPoints() const noexcept
Number of mesh points.
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
autoPtr< boundaryVectorField > dSfdbMult_
Multipliers of d(Sf)/db and d(nf)/db.
PtrList< objective > & getObjectiveFunctions()
Return reference to objective functions.
GeometricField< tensor, fvPatchField, volMesh > volTensorField
Definition: volFieldsFwd.H:86
dimensionedSymmTensor sqr(const dimensionedVector &dv)
volVectorField::Boundary boundaryVectorField
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:70
virtual void write(const word &baseName=word::null)
Write sensitivity fields.
Differentiation of the mesh data structure.
Definition: deltaBoundary.H:54
void unzipRow(const FieldField< Field, SymmTensor< Cmpt >> &input, const direction idx, FieldField< Field, Vector< Cmpt >> &result)
Extract a symmTensor field field row (x,y,z) == (0,1,2)
vectorField makeFaceCentresAndAreas_d(const pointField &p, const pointField &p_d)
Given a face and the points to be moved in the normal direction, find faceArea, faceCentre and unitVe...
Definition: deltaBoundary.C:65
bool includeTransposeStresses_
Include the transpose part of the adjoint stresses.
Base class for adjoint solvers.
Definition: adjointSolver.H:51
GeometricBoundaryField< tensor, fvPatchField, volMesh > Boundary
Type of boundary fields.
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1029
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:82
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
addToRunTimeSelectionTable(adjointSensitivity, sensitivityBezier, dictionary)
Macros for easy insertion into run-time selection tables.
dimensionedSymmTensor twoSymm(const dimensionedSymmTensor &dt)
Base class for incompressibleAdjoint solvers.
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1073
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:414
void finalisePointSensitivities()
Converts face sensitivities to point sensitivities and adds the ones directly computed in points (i...
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:37
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:81
static void allGatherList(List< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses linear/tree communication. ...
const dictionary & dict() const
Return the construction dictionary.
Definition: sensitivity.C:50
pointField points(const UList< point > &pts) const
Return the points corresponding to this face.
Definition: faceI.H:80
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1020
dynamicFvMesh & mesh
bool includeDivTerm_
Include the term from the deviatoric part of the stresses.
const volScalarField & pa() const
Return const reference to pressure.
autoPtr< typename GeometricField< Type, fvPatchField, volMesh >::Boundary > createZeroBoundaryPtr(const fvMesh &mesh, bool printAllocation=false)
bool useSnGradInTranposeStresses_
Use snGrad in the transpose part of the adjoint stresses.
static const Identity< scalar > I
Definition: Identity.H:100
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:584
A class for handling words, derived from Foam::string.
Definition: word.H:63
Abstract base class for adjoint-based sensitivities in incompressible flows.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
const volVectorField & Ua() const
Return const reference to velocity.
const volScalarField & p() const
Return const reference to pressure.
static const word null
An empty word.
Definition: word.H:84
virtual void clearSensitivities()
Zero sensitivity fields and their constituents.
const autoPtr< incompressibleAdjoint::adjointRASModel > & adjointTurbulence() const
Return const reference to the adjointRASModel.
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1098
const word & solverName() const
Return solver name.
Definition: variablesSet.C:77
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
#define DebugInfo
Report an information message using Foam::Info.
const volVectorField & U() const
Return const reference to velocity.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
autoPtr< boundaryVectorField > wallFaceSens_
The face-based part of the sensitivities.
bool includeSurfaceArea_
Include surface area in sens computation.
void write()
Write sensitivity fields.
void finaliseFaceMultiplier()
Add terms related to post-processing PDEs (i.e. adjoint Eikonal, adjoint mesh movement) and add local...
const autoPtr< incompressible::RASModelVariables > & RASModelVariables() const
Return const reference to the turbulence model variables.
void read()
Read controls and update solver pointers if necessary.
bool includeDistance_
Include distance variation in sens computation.
bool includePressureTerm_
Include the adjoint pressure term in sens computation.
U
Definition: pEqn.H:72
virtual void write(const word &baseName=word::null)
Write sensitivity fields.
void clearSensitivities()
Zero sensitivity fields and their constituents.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:79
Calculation of adjoint based sensitivities at wall points.
bool includeObjective_
Include terms directly emerging from the objective function.
const std::string patch
OpenFOAM patch number as a std::string.
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
Reduce inplace (cf. MPI Allreduce) using specified communication schedule.
bool includeMeshMovement_
Include mesh movement variation in sens computation.
Internal & ref(const bool updateAccessTime=true)
Same as internalFieldRef()
const fvBoundaryMesh & boundary() const noexcept
Return reference to boundary mesh.
Definition: fvMesh.H:397
Field< vector > vectorField
Specialisation of Field<T> for vector.
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
virtual bool readDict(const dictionary &dict)
Read dict if changed.
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
void setSuffixName()
Set suffix name for sensitivity fields.
volScalarField & p
static tmp< GeometricField< tensor, fvPatchField, volMesh > > New(const word &name, const Mesh &mesh, const dimensionSet &dims, const word &patchFieldType=fvPatchField< tensor >::calculatedType())
Return tmp field from name, mesh, dimensions and patch type.
virtual void clearSensitivities()
Zero sensitivity fields and their constituents.
Tensor of scalars, i.e. Tensor<scalar>.
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
void constructGlobalPointNormalsAndAreas(vectorField &pointNormals, scalarField &pointMagSf)
Construct globally correct point normals and point areas.
Namespace for OpenFOAM.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:133
const dimensionSet dimVelocity