sensitivitySurfaceIncompressible.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-2021 PCOpt/NTUA
9  Copyright (C) 2013-2021 FOSS GP
10  Copyright (C) 2019-2020 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 
32 #include "syncTools.H"
34 #include "faMatrices.H"
35 #include "famSup.H"
36 #include "famLaplacian.H"
37 #include "volSurfaceMapping.H"
40 
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 
43 namespace Foam
44 {
45 
46 namespace incompressible
47 {
48 
49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
50 
51 defineTypeNameAndDebug(sensitivitySurface, 1);
53 (
54  adjointSensitivity,
55  sensitivitySurface,
56  dictionary
57 );
58 
59 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
60 
62 {
64  {
65  // Grab objective refs
66  PtrList<objective>& functions
68  // Compute sens for all points in parameterized patches.
69  // Interfacing points will be accumulated later
71  (
72  createZeroBoundaryPointFieldPtr<vector>(mesh_)
73  );
75  (
76  createZeroBoundaryPointFieldPtr<vector>(mesh_)
77  );
78  // Geometric (or "direct") sensitivities are better computed directly
79  // on the points
80  for (const label patchI : sensitivityPatchIDs_)
81  {
82  const fvPatch& patch = mesh_.boundary()[patchI];
83  const vectorField nf(patch.nf());
84 
85  // point sens result for patch
86  vectorField& patchdSdb = pointSensdSdb()[patchI];
87  vectorField& patchdndb = pointSensdndb()[patchI];
88 
89  vectorField dSdbMultiplierTot(patch.size(), Zero);
90  vectorField dndbMultiplierTot(patch.size(), Zero);
91  for (auto& fun : functions)
92  {
93  dSdbMultiplierTot += fun.weight()*fun.dSdbMultiplier(patchI);
94  dndbMultiplierTot += fun.weight()*fun.dndbMultiplier(patchI);
95  }
96  // Correspondence of local point addressing to global point
97  // addressing
98  const labelList& meshPoints = patch.patch().meshPoints();
99  // List with mesh faces. Global addressing
100  const faceList& faces = mesh_.faces();
101  // Each local patch point belongs to these local patch faces
102  // (local numbering)
103  const labelListList& patchPointFaces = patch.patch().pointFaces();
104  // index of first face in patch
105  const label patchStartIndex = patch.start();
106  // geometry differentiation engine
107  deltaBoundary dBoundary(mesh_);
108  // Loop over patch points.
109  // Collect contributions from each boundary face this point
110  // belongs to
111  forAll(meshPoints, ppI)
112  {
113  const labelList& pointFaces = patchPointFaces[ppI];
114  for (label localFaceIndex : pointFaces)
115  {
116  label globalFaceIndex = patchStartIndex + localFaceIndex;
117  const face& faceI = faces[globalFaceIndex];
118  // Point coordinates. All indices in global numbering
119  const pointField p(faceI.points(mesh_.points()));
120  tensorField p_d(faceI.size(), Zero);
121  forAll(faceI, facePointI)
122  {
123  if (faceI[facePointI] == meshPoints[ppI])
124  {
125  p_d[facePointI] = tensor::I;
126  }
127  }
128  const tensorField deltaNormals
129  (
130  dBoundary.makeFaceCentresAndAreas_d(p, p_d)
131  );
132 
133  // Element [1] is the variation in the (dimensional) normal
134  const tensor& deltaSf = deltaNormals[1];
135  patchdSdb[ppI] +=
136  dSdbMultiplierTot[localFaceIndex] & deltaSf;
137 
138  // Element [2] is the variation in the unit normal
139  const tensor& deltaNf = deltaNormals[2];
140  patchdndb[ppI] +=
141  dndbMultiplierTot[localFaceIndex] & deltaNf;
142  }
143  }
144  }
145  // Do parallel communications to avoid wrong values at processor
146  // boundaries
147  vectorField dSdbGlobal(mesh_.nPoints(), Zero);
148  vectorField dndbGlobal(mesh_.nPoints(), Zero);
149  for (const label patchI : sensitivityPatchIDs_)
150  {
151  const labelList& meshPoints =
152  mesh_.boundaryMesh()[patchI].meshPoints();
153  forAll(meshPoints, ppI)
154  {
155  const label globaPointI = meshPoints[ppI];
156  dSdbGlobal[globaPointI] += pointSensdSdb()[patchI][ppI];
157  dndbGlobal[globaPointI] += pointSensdndb()[patchI][ppI];
158  }
159  }
160  // Accumulate over processors
162  (
163  mesh_, dSdbGlobal, plusEqOp<vector>(), vector::zero
164  );
166  (
167  mesh_, dndbGlobal, plusEqOp<vector>(), vector::zero
168  );
169  // Transfer back to local fields and map to faces
170  for (const label patchI : sensitivityPatchIDs_)
171  {
172  const fvPatch& patch = mesh_.boundary()[patchI];
173  const labelList& meshPoints = patch.patch().meshPoints();
174  const scalarField& magSf = patch.magSf();
175  pointSensdSdb()[patchI].map(dSdbGlobal, meshPoints);
176  pointSensdndb()[patchI].map(dndbGlobal, meshPoints);
177  // Map dSf/dx and dnf/dx term from points to faces. Ideally, all
178  // sensitivities should be computed at points rather than faces.
179  PrimitivePatchInterpolation<polyPatch> patchInter(patch.patch());
180  vectorField dSdbFace
181  (
182  patchInter.pointToFaceInterpolate(pointSensdSdb()[patchI])
183  );
184  // dSdb already contains the face area. Divide with it to make it
185  // compatible with the rest of the terms
186  dSdbFace /= magSf;
187 
188  tmp<vectorField> tdndbFace =
189  patchInter.pointToFaceInterpolate(pointSensdndb()[patchI]);
190  const vectorField& dndbFace = tdndbFace();
191 
192  // Add to sensitivity fields
193  wallFaceSensVecPtr_()[patchI] += dSdbFace + dndbFace;
194  }
195  }
196 }
197 
198 
200 {
201  word suffix(dict().getOrDefault<word>("suffix", word::null));
202  // Determine suffix for fields holding the sens
204  {
206  (
207  adjointVars_.solverName() + "ESI" + suffix
208  );
209  }
210  else
211  {
213  (
214  adjointVars_.solverName() + "SI" + suffix
215  );
216  }
217 }
218 
219 
221 {
222  // Read in parameters
223  const label iters(dict().getOrDefault<label>("iters", 500));
224  const scalar tolerance(dict().getOrDefault<scalar>("tolerance", 1.e-06));
225  autoPtr<faMesh> aMeshPtr(nullptr);
226 
227  IOobject faceLabels
228  (
229  "faceLabels",
231  (
233  "faceLabels",
235  ),
237  mesh_,
240  );
241 
242  // If the faMesh already exists, read it
243  if (faceLabels.typeHeaderOk<labelIOList>(false))
244  {
245  Info<< "Reading the already constructed faMesh" << endl;
246  aMeshPtr.reset(new faMesh(mesh_));
247  }
248  else
249  {
250  // Dictionary used to construct the faMesh
251  dictionary faMeshDefinition;
252 
253  IOobject faMeshDefinitionDict
254  (
255  "faMeshDefinition",
256  mesh_.time().caseSystem(),
257  mesh_,
260  );
261 
262  // If the faMeshDefinitionDict exists, use it to construct the mesh
263  if (faMeshDefinitionDict.typeHeaderOk<IOdictionary>(false))
264  {
265  Info<< "Reading faMeshDefinition from system " << endl;
266  faMeshDefinition = IOdictionary(faMeshDefinitionDict);
267  }
268  // Otherwise, faMesh is generated from all patches on which we compute
269  // sensitivities
270  else
271  {
272  Info<< "Constructing faMeshDefinition from sensitivity patches"
273  << endl;
274  wordList polyMeshPatches(sensitivityPatchIDs_.size());
275  label i(0);
276  for (const label patchID : sensitivityPatchIDs_)
277  {
278  polyMeshPatches[i++] = mesh_.boundary()[patchID].name();
279  }
280  faMeshDefinition.add<wordList>("polyMeshPatches", polyMeshPatches);
281  (void)faMeshDefinition.subDictOrAdd("boundary");
282  }
283 
284  // Construct faMesh
285  aMeshPtr.reset(new faMesh(mesh_, faMeshDefinition));
286  }
287  faMesh& aMesh = aMeshPtr.ref();
288 
289  // Physical radius of the smoothing, provided either directly or computed
290  // based on the average 'length' of boundary faces
291  const scalar Rphysical
292  (dict().getOrDefault<scalar>("radius", computeRadius(aMesh)));
293  DebugInfo
294  << "Physical radius of the sensitivity smoothing "
295  << Rphysical << nl << endl;
296 
297  // Radius used as the diffusivity in the Helmholtz filter, computed as a
298  // function of the physical radius
299  const dimensionedScalar RpdeSqr
300  (
301  "RpdeSqr", dimArea, sqr(Rphysical/(2.*::sqrt(3.)))
302  );
303 
304  dimensionedScalar one("1", dimless, 1.);
305 
306  // Mapping engine
308 
309  // Source term in faMatrix needs to be an areaField
310  areaScalarField sens
311  (
312  IOobject
313  (
314  "sens",
315  mesh_.time().timeName(),
316  mesh_,
319  ),
320  aMesh,
323  );
324 
325  // Copy sensitivities to area field
326  sens.primitiveFieldRef() =
327  vsm.mapToSurface<scalar>(wallFaceSensNormalPtr_());
328 
329  // Initialisation of the smoothed sensitivities field based on the original
330  // sensitivities
331  areaScalarField smoothedSens("smoothedSens", sens);
332  for (label iter = 0; iter < iters; ++iter)
333  {
334  Info<< "Sensitivity smoothing iteration " << iter << endl;
335 
336  faScalarMatrix smoothEqn
337  (
338  fam::Sp(one, smoothedSens)
339  - fam::laplacian(RpdeSqr, smoothedSens)
340  ==
341  sens
342  );
343 
344  smoothEqn.relax();
345 
346  const scalar residual(mag(smoothEqn.solve().initialResidual()));
347 
348  DebugInfo
349  << "Max smoothSens " << gMax(mag(smoothedSens)()) << endl;
350 
351  // Print execution time
353 
354  // Check convergence
355  if (residual < tolerance)
356  {
357  Info<< "\n***Reached smoothing equation convergence limit, "
358  "iteration " << iter << "***\n\n";
359  break;
360  }
361  }
362 
363  // Field used to write the smoothed sensitivity field to file
364  volScalarField volSmoothedSens
365  (
366  IOobject
367  (
368  "smoothedSurfaceSens" + surfaceFieldSuffix_,
369  mesh_.time().timeName(),
370  mesh_,
373  ),
374  mesh_,
376  );
377 
378  // Transfer result back to volField and write
379  vsm.mapToVolume(smoothedSens, volSmoothedSens.boundaryFieldRef());
380  volSmoothedSens.write();
381 }
382 
383 
385 {
386  scalar averageArea(gAverage(aMesh.S().field()));
387  const Vector<label>& geometricD = mesh_.geometricD();
388  const boundBox& bounds = mesh_.bounds();
389  forAll(geometricD, iDir)
390  {
391  if (geometricD[iDir] == -1)
392  {
393  averageArea /= bounds.span()[iDir];
394  }
395  }
396  scalar mult = dict().getOrDefault<scalar>("meanRadiusMultiplier", 10);
397 
398  return mult*pow(averageArea, scalar(1)/scalar(mesh_.nGeometricD() - 1));
399 }
400 
401 
402 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
403 
404 sensitivitySurface::sensitivitySurface
405 (
406  const fvMesh& mesh,
407  const dictionary& dict,
408  incompressibleVars& primalVars,
409  incompressibleAdjointVars& adjointVars,
411 )
412 :
414  (
415  mesh,
416  dict,
417  primalVars,
418  adjointVars,
420  ),
422  includeSurfaceArea_(false),
423  includePressureTerm_(false),
424  includeGradStressTerm_(false),
425  includeTransposeStresses_(false),
426  useSnGradInTranposeStresses_(false),
427  includeDivTerm_(false),
428  includeDistance_(false),
429  includeMeshMovement_(false),
430  includeObjective_(false),
431  writeGeometricInfo_(false),
432  smoothSensitivities_(false),
433  eikonalSolver_(nullptr),
434  meshMovementSolver_(nullptr),
435 
436  nfOnPatchPtr_(nullptr),
437  SfOnPatchPtr_(nullptr),
438  CfOnPatchPtr_(nullptr)
439 {
440  read();
441  setSuffixName();
442 
443  // Allocate boundary field pointer
444  wallFaceSensVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
445  wallFaceSensNormalPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
446  wallFaceSensNormalVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
447 
448  // Allocate fields to contain geometric info
449  if (writeGeometricInfo_)
450  {
451  nfOnPatchPtr_.reset
452  (
453  new volVectorField
454  (
455  IOobject
456  (
457  "nfOnPatch",
458  mesh.time().timeName(),
459  mesh,
462  ),
463  mesh,
465  )
466  );
467 
468  SfOnPatchPtr_.reset
469  (
470  new volVectorField
471  (
472  IOobject
473  (
474  "SfOnPatch",
475  mesh.time().timeName(),
476  mesh,
479  ),
480  mesh,
482  )
483  );
484 
485  CfOnPatchPtr_.reset
486  (
487  new volVectorField
488  (
489  IOobject
490  (
491  "CfOnPatch",
492  mesh.time().timeName(),
493  mesh,
496  ),
497  mesh,
499  )
500  );
501  }
502 
503  // Allocate appropriate space for the sensitivity field
504  computeDerivativesSize();
505 }
506 
507 
508 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
509 
511 {
513  dict().getOrDefault<bool>("includeSurfaceArea", true);
515  dict().getOrDefault<bool>("includePressure", true);
517  dict().getOrDefault<bool>("includeGradStressTerm", true);
519  dict().getOrDefault<bool>("includeTransposeStresses", true);
521  dict().getOrDefault<bool>("useSnGradInTranposeStresses", false);
522  includeDivTerm_ = dict().getOrDefault<bool>("includeDivTerm", false);
524  dict().getOrDefault<bool>
525  (
526  "includeDistance",
527  adjointVars_.adjointTurbulence().ref().includeDistance()
528  );
530  dict().getOrDefault<bool>("includeMeshMovement", true);
532  dict().getOrDefault<bool>("includeObjectiveContribution", true);
534  dict().getOrDefault<bool>("writeGeometricInfo", false);
536  dict().getOrDefault<bool>("smoothSensitivities", false);
537 
538  // Allocate new solvers if necessary
540  {
541  eikonalSolver_.reset
542  (
544  (
545  mesh_,
546  dict_,
548  adjointVars_,
549  sensitivityPatchIDs_
550  )
551  );
552  }
554  {
555  meshMovementSolver_.reset
556  (
558  (
559  mesh_,
560  dict_,
561  *this,
562  sensitivityPatchIDs_,
564  )
565  );
566  }
567 }
568 
569 
571 {
573  {
574  if (eikonalSolver_)
575  {
576  eikonalSolver_().readDict(dict);
577  }
578 
580  {
581  meshMovementSolver_().readDict(dict);
582  }
583 
584  return true;
585  }
586 
587  return false;
588 }
589 
590 
592 {
593  label nFaces(0);
594  for (const label patchI : sensitivityPatchIDs_)
595  {
596  nFaces += mesh_.boundary()[patchI].size();
597  }
598  derivatives_.setSize(nFaces);
599 }
600 
601 
603 {
604  // Grab references
605  const volScalarField& p = primalVars_.p();
606  const volVectorField& U = primalVars_.U();
607 
608  const volScalarField& pa = adjointVars_.pa();
609  const volVectorField& Ua = adjointVars_.Ua();
612 
613  Info<< " Calculating auxiliary quantities " << endl;
614  // Fields needed to calculate adjoint sensitivities
616  turbVars = primalVars_.RASModelVariables();
618  volScalarField nuEff(lamTransp.nu() + turbVars->nutRef());
619  volTensorField gradUa(fvc::grad(Ua));
620  volTensorField gradU(fvc::grad(U));
621 
622  // Explicitly correct the boundary gradient to get rid of the tangential
623  // component
624  forAll(mesh_.boundary(), patchI)
625  {
626  const fvPatch& patch = mesh_.boundary()[patchI];
627  if (isA<wallFvPatch>(patch))
628  {
629  tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
630  const vectorField& nf = tnf();
631  gradU.boundaryFieldRef()[patchI] =
632  nf*U.boundaryField()[patchI].snGrad();
633  }
634  }
635 
636  // Auxiliary terms
637  volVectorField gradp(fvc::grad(p));
638  volTensorField stress(nuEff*(gradU + T(gradU)));
639  autoPtr<volVectorField> stressXPtr
640  (
641  createZeroFieldPtr<vector>(mesh_, "stressX", stress.dimensions())
642  );
643  autoPtr<volVectorField> stressYPtr
644  (
645  createZeroFieldPtr<vector>(mesh_, "stressY", stress.dimensions())
646  );
647  autoPtr<volVectorField> stressZPtr
648  (
649  createZeroFieldPtr<vector>(mesh_, "stressZ", stress.dimensions())
650  );
651 
652  stressXPtr().replace(0, stress.component(0));
653  stressXPtr().replace(1, stress.component(1));
654  stressXPtr().replace(2, stress.component(2));
655 
656  stressYPtr().replace(0, stress.component(3));
657  stressYPtr().replace(1, stress.component(4));
658  stressYPtr().replace(2, stress.component(5));
659 
660  stressZPtr().replace(0, stress.component(6));
661  stressZPtr().replace(1, stress.component(7));
662  stressZPtr().replace(2, stress.component(8));
663 
664  volTensorField gradStressX(fvc::grad(stressXPtr()));
665  volTensorField gradStressY(fvc::grad(stressYPtr()));
666  volTensorField gradStressZ(fvc::grad(stressZPtr()));
667 
668  // Accumulate source for additional post-processing PDEs, if necessary
669  if (includeDistance_)
670  {
671  eikonalSolver_->accumulateIntegrand(dt);
672  }
673 
675  {
676  meshMovementSolver_->accumulateIntegrand(dt);
677  }
678 
679  // Terms from the adjoint turbulence model
680  const boundaryVectorField& adjointTMsensitivities =
681  adjointTurbulence->wallShapeSensitivities();
682 
683  DebugInfo
684  << " Calculating adjoint sensitivity. " << endl;
685 
686  // Sensitivities do not include locale surface area by default.
687  // Part of the sensitivities that multiplies dxFace/db
688  for (const label patchI : sensitivityPatchIDs_)
689  {
690  const fvPatch& patch = mesh_.boundary()[patchI];
691  tmp<vectorField> tnf = patch.nf();
692  const vectorField& nf = tnf();
693 
694  // Includes spurious tangential gradU part. Deprecated
695  /*
696  vectorField stressAndPressureTerm =
697  (
698  - (
699  Ua.boundaryField()[patchI].snGrad()
700  + (gradUa.boundaryField()[patchI] & nf)
701  ) * nuEff.boundaryField()[patchI]
702  + pa.boundaryField()[patchI] *nf
703  ) & gradU.boundaryField()[patchI].T();
704  */
705 
706  // Adjoint stress term
707  vectorField stressTerm
708  (
709  - (
710  Ua.boundaryField()[patchI].snGrad()
711  & U.boundaryField()[patchI].snGrad()
712  )
713  * nuEff.boundaryField()[patchI]
714  * nf
715  );
716 
717 
719  {
720  vectorField gradUaNf
721  (
723  (Ua.boundaryField()[patchI].snGrad() & nf)*nf :
724  (gradUa.boundaryField()[patchI] & nf)
725  );
726 
727  stressTerm -=
728  nuEff.boundaryField()[patchI]
729  *(gradUaNf & U.boundaryField()[patchI].snGrad())
730  *nf;
731  }
732 
733  if (includeDivTerm_)
734  {
735  stressTerm +=
736  scalar(1./3.)*nuEff.boundaryField()[patchI]
737  * (
738  ((Ua.boundaryField()[patchI].snGrad() &nf)*nf)
739  & U.boundaryField()[patchI].snGrad()
740  )
741  * nf;
742  }
743 
744  vectorField gradStressTerm(patch.size(), Zero);
746  {
747  // Terms corresponding to contributions from converting delta to
748  // thetas are added through the corresponding adjoint boundary
749  // conditions instead of grabbing contributions from the objective
750  // function. Useful to have a unified formulation for low- and
751  // high-re meshes
752  const fvPatchVectorField& Uab = Ua.boundaryField()[patchI];
753  gradStressTerm = - ((Uab & nf)*gradp.boundaryField()[patchI]);
754  gradStressTerm +=
755  (
756  Uab.component(0) * gradStressX.boundaryField()[patchI]
757  + Uab.component(1) * gradStressY.boundaryField()[patchI]
758  + Uab.component(2) * gradStressZ.boundaryField()[patchI]
759  ) & nf;
760  }
761 
762  // Adjoint pressure terms
763  vectorField pressureTerm(patch.size(), Zero);
765  {
766  pressureTerm =
767  (
768  (nf*pa.boundaryField()[patchI])
769  & U.boundaryField()[patchI].snGrad()
770  )* nf;
771  }
772 
773  PtrList<objective>& functions
775 
776  // Term from objectives including x directly (e.g. moments)
777  vectorField dxdbMultiplierTot(pressureTerm.size(), Zero);
778  if (includeObjective_)
779  {
780  forAll(functions, funcI)
781  {
782  dxdbMultiplierTot +=
783  functions[funcI].weight()
784  * (
785  functions[funcI].dxdbDirectMultiplier(patchI)
786  );
787  }
788  }
789 
790  // Fill in sensitivity fields
791  wallFaceSensVecPtr_()[patchI] +=
792  (
793  stressTerm
794  + gradStressTerm
795  + pressureTerm
796  + adjointTMsensitivities[patchI]
797  + dxdbMultiplierTot
798  )*dt;
799  }
800 
801  // Add the sensitivity part corresponding to changes of the normal vector
802  // Computed at points and mapped to faces
804 }
805 
806 
808 {
809  // Update geometric fields for use by external users
811  {
812  for (const label patchI : sensitivityPatchIDs_)
813  {
814  const fvPatch& patch = mesh_.boundary()[patchI];
815  tmp<vectorField> tnf = patch.nf();
816  const vectorField& nf = tnf();
817  const vectorField& Sf = patch.Sf();
818  const vectorField& Cf = patch.Cf();
819 
820  nfOnPatchPtr_().boundaryFieldRef()[patchI] = nf;
821  SfOnPatchPtr_().boundaryFieldRef()[patchI] = Sf;
822  CfOnPatchPtr_().boundaryFieldRef()[patchI] = Cf;
823  }
824  }
825 
826  // Solve extra equations if necessary
827  // Solved using accumulated sources over time
828  autoPtr<boundaryVectorField> distanceSensPtr(nullptr);
829  if (includeDistance_)
830  {
831  eikonalSolver_->solve();
832  distanceSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
833  const boundaryVectorField& sens =
834  eikonalSolver_->distanceSensitivities();
835  for (const label patchI : sensitivityPatchIDs_)
836  {
837  distanceSensPtr()[patchI] = sens[patchI];
838  }
839  }
840 
841  autoPtr<boundaryVectorField> meshMovementSensPtr(nullptr);
843  {
844  meshMovementSolver_->solve();
845  meshMovementSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
846  const boundaryVectorField& sens =
847  meshMovementSolver_->meshMovementSensitivities();
848  for (const label patchI : sensitivityPatchIDs_)
849  {
850  meshMovementSensPtr()[patchI] = sens[patchI];
851  }
852  }
853 
854 
855  // Project to normal face vector
856  label nPassedFaces(0);
857  for (const label patchI : sensitivityPatchIDs_)
858  {
859  const fvPatch& patch = mesh_.boundary()[patchI];
860  tmp<vectorField> tnf(patch.nf());
861  const vectorField& nf = tnf();
862 
863  // Distance related terms
864  if (includeDistance_)
865  {
866  wallFaceSensVecPtr_()[patchI] += distanceSensPtr()[patchI];
867  }
868 
869  // Mesh movement related terms
871  {
872  wallFaceSensVecPtr_()[patchI] += meshMovementSensPtr()[patchI];
873  }
874 
876  {
877  wallFaceSensVecPtr_()[patchI] *= patch.magSf();
878  }
879 
880  wallFaceSensNormalPtr_()[patchI] = wallFaceSensVecPtr_()[patchI] & nf;
881  wallFaceSensNormalVecPtr_()[patchI] =
882  wallFaceSensNormalPtr_()[patchI] * nf;
883 
884  forAll(patch, fI)
885  {
886  derivatives_[nPassedFaces + fI]
887  = wallFaceSensNormalPtr_()[patchI][fI];
888  }
889  nPassedFaces += patch.size();
890  }
891 
892  // Smooth sensitivities if needed
894  {
896  }
897 }
898 
899 
901 {
902  // Reset terms in post-processing PDEs
903  if (includeDistance_)
904  {
905  eikonalSolver_->reset();
906  }
908  {
909  meshMovementSolver_->reset();
910  }
911  // Reset sensitivity fields
914 }
915 
916 
918 {
919  return eikonalSolver_;
920 }
921 
922 
923 void sensitivitySurface::write(const word& baseName)
924 {
925  setSuffixName();
928 
930  {
931  nfOnPatchPtr_().write();
932  SfOnPatchPtr_().write();
933  CfOnPatchPtr_().write();
934  }
935 }
936 
937 
938 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
939 
940 } // End namespace Foam
941 } // End namespace incompressible
942 
943 // ************************************************************************* //
Foam::fvPatchField< vector >
Foam::sensitivity::dict
const dictionary & dict() const
Return the construction dictionary.
Definition: sensitivity.C:57
Foam::IOobject::NO_WRITE
Definition: IOobject.H:195
Foam::incompressible::adjointSensitivity::derivatives_
scalarField derivatives_
Definition: adjointSensitivityIncompressible.H:83
Foam::zeroGradientFaPatchField
Author Zeljko Tukovic, FMENA Hrvoje Jasak, Wikki Ltd.
Definition: zeroGradientFaPatchField.H:55
Foam::IOdictionary
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:54
Foam::Tensor< scalar >
Foam::polyMesh::points
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1069
Foam::objectiveManager
class for managing incompressible objective functions.
Definition: objectiveManager.H:54
Foam::IOobject
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:169
Foam::incompressible::sensitivitySurface::assembleSensitivities
virtual void assembleSensitivities()
Assemble sensitivities.
Definition: sensitivitySurfaceIncompressible.C:807
Foam::GeometricField::component
tmp< GeometricField< cmptType, PatchField, GeoMesh > > component(const direction) const
Return a component of the field.
Foam::variablesSet::solverName
const word & solverName() const
Return solver name.
Definition: variablesSet.C:84
Foam::incompressible::sensitivitySurface::includePressureTerm_
bool includePressureTerm_
Include the adjoint pressure term in sens computation.
Definition: sensitivitySurfaceIncompressible.H:95
Foam::incompressible::sensitivitySurface::includeObjective_
bool includeObjective_
Include terms directly emerging from the objective function.
Definition: sensitivitySurfaceIncompressible.H:116
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::IOobject::AUTO_WRITE
Definition: IOobject.H:194
Foam::fvc::grad
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh >> grad(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcGrad.C:54
Foam::deltaBoundary
Differentiation of the mesh data structure.
Definition: deltaBoundary.H:58
Foam::faMatrix
A special matrix type and solver, designed for finite area solutions of scalar equations....
Definition: faMatricesFwd.H:43
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:65
Foam::Tensor::I
static const Tensor I
Definition: Tensor.H:85
Foam::incompressible::defineTypeNameAndDebug
defineTypeNameAndDebug(adjointEikonalSolver, 0)
PrimitivePatchInterpolation.H
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:61
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::polyMesh::nGeometricD
label nGeometricD() const
Return the number of valid geometric dimensions in the mesh.
Definition: polyMesh.C:869
Foam::fam::laplacian
tmp< faMatrix< Type > > laplacian(const GeometricField< Type, faPatchField, areaMesh > &vf)
Definition: famLaplacian.C:49
Foam::gAverage
Type gAverage(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:604
Foam::IOobject::typeHeaderOk
bool typeHeaderOk(const bool checkType=true, const bool search=true, const bool verbose=true)
Read header (uses typeFilePath to find file) and check its info.
Definition: IOobjectTemplates.C:39
Foam::polyMesh::dbDir
virtual const fileName & dbDir() const
Override the objectRegistry dbDir for a single-region case.
Definition: polyMesh.C:829
Foam::read
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:108
Foam::Time::timeName
static word timeName(const scalar t, const int precision=precision_)
Definition: Time.C:780
Foam::incompressible::sensitivitySurface::eikonalSolver_
autoPtr< adjointEikonalSolver > eikonalSolver_
Definition: sensitivitySurfaceIncompressible.H:125
faMatrices.H
Foam::TimePaths::caseSystem
fileName caseSystem() const
Definition: TimePathsI.H:119
Foam::one
A class representing the concept of 1 (one) that can be used to avoid manipulating objects known to b...
Definition: one.H:61
Foam::polyMesh::boundaryMesh
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:444
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::incompressible::sensitivitySurface::write
virtual void write(const word &baseName=word::null)
Write sensitivity maps.
Definition: sensitivitySurfaceIncompressible.C:923
Foam::singlePhaseTransportModel
A simple single-phase transport model based on viscosityModel.
Definition: singlePhaseTransportModel.H:57
Foam::incompressible::sensitivitySurface::smoothSensitivities
void smoothSensitivities()
Definition: sensitivitySurfaceIncompressible.C:220
Foam::incompressibleVars::p
const volScalarField & p() const
Return const reference to pressure.
Definition: incompressibleVars.C:305
famSup.H
Calculate the matrix for implicit and explicit sources.
Foam::polyMesh::geometricD
const Vector< label > & geometricD() const
Return the vector of geometric directions in mesh.
Definition: polyMesh.C:858
syncTools.H
Foam::dictionary::subDictOrAdd
dictionary & subDictOrAdd(const word &keyword, enum keyType::option matchOpt=keyType::REGEX)
Find and return a sub-dictionary for manipulation.
Definition: dictionary.C:500
Foam::incompressibleAdjointVars
Class including all adjoint fields for incompressible flows.
Definition: incompressibleAdjointVars.H:52
Foam::faMatrix::solve
SolverPerformance< Type > solve(const dictionary &)
Solve returning the solution statistics.
Definition: faMatrixSolve.C:55
Foam::syncTools::syncPointList
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
Definition: syncToolsTemplates.C:721
Foam::primitiveMesh::nPoints
label nPoints() const noexcept
Number of mesh points.
Definition: primitiveMeshI.H:37
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::incompressibleVars::RASModelVariables
const autoPtr< incompressible::RASModelVariables > & RASModelVariables() const
Return const reference to the turbulence model variables.
Definition: incompressibleVars.C:444
Foam::shapeSensitivitiesBase
Definition: shapeSensitivitiesBase.H:63
Foam::incompressible::sensitivitySurface::meshMovementSolver_
autoPtr< adjointMeshMovementSolver > meshMovementSolver_
Definition: sensitivitySurfaceIncompressible.H:127
vsm
volSurfaceMapping vsm(aMesh)
aMesh
faMesh aMesh(mesh)
Foam::incompressible::adjointEikonalSolver
Solver of the adjoint to the eikonal PDE.
Definition: adjointEikonalSolverIncompressible.H:146
Foam::boundBox::span
vector span() const
The bounding box span (from minimum to maximum)
Definition: boundBoxI.H:127
Foam::incompressible::sensitivitySurface::includeGradStressTerm_
bool includeGradStressTerm_
Include the term containing the grad of the stress at the boundary.
Definition: sensitivitySurfaceIncompressible.H:98
Foam::Time::printExecutionTime
Ostream & printExecutionTime(OSstream &os) const
Print the elapsed ExecutionTime (cpu-time), ClockTime.
Definition: TimeIO.C:618
Foam::fam::Sp
tmp< faMatrix< Type > > Sp(const areaScalarField &sp, const GeometricField< Type, faPatchField, areaMesh > &vf)
Definition: famSup.C:86
Foam::incompressible::addToRunTimeSelectionTable
addToRunTimeSelectionTable(adjointSensitivity, sensitivityBezier, dictionary)
Foam::shapeSensitivitiesBase::write
void write()
Write sensitivity fields.
Definition: shapeSensitivitiesBase.C:216
Foam::incompressible::adjointSensitivity
Abstract base class for adjoint-based sensitivities in incompressible flows.
Definition: adjointSensitivityIncompressible.H:75
Foam::incompressible::sensitivitySurface::includeDivTerm_
bool includeDivTerm_
Include the term from the deviatoric part of the stresses.
Definition: sensitivitySurfaceIncompressible.H:107
Foam::sensitivity::mesh_
const fvMesh & mesh_
Definition: sensitivity.H:69
Foam::dimArea
const dimensionSet dimArea(sqr(dimLength))
Definition: dimensionSets.H:59
Foam::Field< vector >
Foam::incompressible::sensitivitySurface::computeDerivativesSize
void computeDerivativesSize()
Compute the number of faces on sensitivityPatchIDs_.
Definition: sensitivitySurfaceIncompressible.C:591
Foam::sensitivity::readDict
virtual bool readDict(const dictionary &dict)
Read dictionary if changed.
Definition: sensitivity.C:63
Foam::Info
messageStream Info
Information stream (stdout output on master, null elsewhere)
Foam::incompressible::sensitivitySurface::computeRadius
scalar computeRadius(const faMesh &aMesh)
Definition: sensitivitySurfaceIncompressible.C:384
Foam::incompressible::sensitivitySurface::writeGeometricInfo_
bool writeGeometricInfo_
Write geometric info for use by external programs.
Definition: sensitivitySurfaceIncompressible.H:119
Foam::incompressible::sensitivitySurface::accumulateIntegrand
virtual void accumulateIntegrand(const scalar dt)
Accumulate sensitivity integrands.
Definition: sensitivitySurfaceIncompressible.C:602
fixedValueFaPatchFields.H
patchID
label patchID
Definition: boundaryProcessorFaPatchPoints.H:5
Foam::fvPatch
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:65
Foam::incompressibleVars::laminarTransport
const singlePhaseTransportModel & laminarTransport() const
Return const reference to transport model.
Definition: incompressibleVars.C:418
Foam::IOobject::READ_IF_PRESENT
Definition: IOobject.H:187
Foam::incompressible::sensitivitySurface::useSnGradInTranposeStresses_
bool useSnGradInTranposeStresses_
Use snGrad in the transpose part of the adjoint stresses.
Definition: sensitivitySurfaceIncompressible.H:104
Foam::T
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
Definition: FieldFieldFunctions.C:58
Foam::incompressibleAdjointMeanFlowVars::pa
const volScalarField & pa() const
Return const reference to pressure.
Definition: incompressibleAdjointMeanFlowVars.C:147
Foam::dimensionedScalar
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Definition: dimensionedScalarFwd.H:42
Foam::incompressible::sensitivitySurface::getAdjointEikonalSolver
autoPtr< adjointEikonalSolver > & getAdjointEikonalSolver()
Get adjoint eikonal solver.
Definition: sensitivitySurfaceIncompressible.C:917
Foam::incompressibleVars::U
const volVectorField & U() const
Return const reference to velocity.
Definition: incompressibleVars.C:331
Foam::PtrList
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition: List.H:59
Foam::incompressible::adjointSensitivity::clearSensitivities
virtual void clearSensitivities()
Zero sensitivity fields and their constituents.
Definition: adjointSensitivityIncompressible.C:127
Foam::incompressible::sensitivitySurface::nfOnPatchPtr_
autoPtr< volVectorField > nfOnPatchPtr_
Definition: sensitivitySurfaceIncompressible.H:130
Foam::pow
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Definition: dimensionedScalar.C:75
Foam::incompressibleAdjointMeanFlowVars::Ua
const volVectorField & Ua() const
Return const reference to velocity.
Definition: incompressibleAdjointMeanFlowVars.C:173
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
Foam::incompressible::sensitivitySurface::includeSurfaceArea_
bool includeSurfaceArea_
Include surface area in sens computation.
Definition: sensitivitySurfaceIncompressible.H:92
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
addToRunTimeSelectionTable.H
Macros for easy insertion into run-time selection tables.
Foam::deltaBoundary::makeFaceCentresAndAreas_d
vectorField makeFaceCentresAndAreas_d(const pointField &p, const pointField &p_d)
Definition: deltaBoundary.C:72
Foam::dimensioned< scalar >
Foam::incompressible::adjointSensitivity::adjointVars_
incompressibleAdjointVars & adjointVars_
Definition: adjointSensitivityIncompressible.H:85
iters
loopControl iters(runTime, aMesh.solutionDict(), "solution")
Foam::fvMesh
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:85
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::incompressible::sensitivitySurface::includeDistance_
bool includeDistance_
Include distance variation in sens computation.
Definition: sensitivitySurfaceIncompressible.H:110
Foam::incompressible::adjointSensitivity::primalVars_
incompressibleVars & primalVars_
Definition: adjointSensitivityIncompressible.H:84
Foam::Time::findInstance
word findInstance(const fileName &dir, const word &name=word::null, const IOobject::readOption rOpt=IOobject::MUST_READ, const word &stopInstance=word::null) const
Definition: Time.C:797
Foam::GeometricField::primitiveFieldRef
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field.
Definition: GeometricField.C:766
zeroGradientFaPatchFields.H
Foam::incompressible::sensitivitySurface::includeTransposeStresses_
bool includeTransposeStresses_
Include the transpose part of the adjoint stresses.
Definition: sensitivitySurfaceIncompressible.H:101
Foam::polyMesh::bounds
const boundBox & bounds() const
Return mesh bounding box.
Definition: polyMesh.H:450
Foam::autoPtr::reset
void reset(autoPtr< T > &&other) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:117
Foam::fvMesh::boundary
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:685
Foam::autoPtr
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: HashPtrTable.H:53
U
U
Definition: pEqn.H:72
Foam::sensitivity::dict_
dictionary dict_
Definition: sensitivity.H:70
Foam::incompressible::sensitivitySurface::read
void read()
Read controls and update solver pointers if necessary.
Definition: sensitivitySurfaceIncompressible.C:510
sensitivitySurfaceIncompressible.H
Foam::polyMesh::faces
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1094
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::GeometricField::Boundary
The boundary fields.
Definition: GeometricField.H:115
DebugInfo
#define DebugInfo
Report an information message using Foam::Info.
Definition: messageStream.H:382
Foam::PrimitivePatchInterpolation
Interpolation class within a primitive patch. Allows interpolation from points to faces and vice vers...
Definition: PrimitivePatchInterpolation.H:53
Foam::nl
constexpr char nl
Definition: Ostream.H:404
volSurfaceMapping.H
Foam::autoPtr::ref
T & ref()
Return reference to the managed object without nullptr checking.
Definition: autoPtr.H:161
Foam::incompressible::sensitivitySurface::clearSensitivities
virtual void clearSensitivities()
Zero sensitivity fields and their constituents.
Definition: sensitivitySurfaceIncompressible.C:900
Foam::singlePhaseTransportModel::nu
virtual tmp< volScalarField > nu() const
Return the laminar viscosity.
Definition: singlePhaseTransportModel.C:72
Foam::foamVersion::patch
const std::string patch
OpenFOAM patch number as a std::string.
Foam::GeometricField::boundaryFieldRef
Boundary & boundaryFieldRef(const bool updateAccessTime=true)
Return a reference to the boundary field.
Definition: GeometricField.C:783
Foam::Vector< label >
Foam::incompressibleAdjointVars::adjointTurbulence
const autoPtr< incompressibleAdjoint::adjointRASModel > & adjointTurbulence() const
Return const reference to the adjointRASModel.
Definition: incompressibleAdjointVars.C:70
Foam::volSurfaceMapping
Volume to surface and surface to volume mapping.
Definition: volSurfaceMapping.H:57
Foam::List< label >
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:144
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::incompressible::adjointMeshMovementSolver
Solver of the adjoint to the Laplace grid displacement equation.
Definition: adjointMeshMovementSolverIncompressible.H:68
Foam::faMesh::meshSubDir
static word meshSubDir
The mesh sub-directory name (usually "faMesh")
Definition: faMesh.H:471
Foam::shapeSensitivitiesBase::clearSensitivities
void clearSensitivities()
Zero sensitivity fields and their constituents.
Definition: shapeSensitivitiesBase.C:175
Foam::face::points
pointField points(const UList< point > &pts) const
Return the points corresponding to this face.
Definition: faceI.H:87
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::IOList< label >
Foam::incompressible::sensitivitySurface::CfOnPatchPtr_
autoPtr< volVectorField > CfOnPatchPtr_
Definition: sensitivitySurfaceIncompressible.H:132
Foam::word::null
static const word null
An empty word.
Definition: word.H:80
famLaplacian.H
Calculate the matrix for the laplacian of the field.
Foam::boundBox
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
Foam::incompressible::sensitivitySurface::addGeometricSens
void addGeometricSens()
Definition: sensitivitySurfaceIncompressible.C:61
Foam::faMesh
Finite area mesh. Used for 2-D non-Euclidian finite area method.
Definition: faMesh.H:82
Foam::fvMesh::time
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:280
Foam::VectorSpace< Vector< scalar >, scalar, 3 >::zero
static const Vector< scalar > zero
Definition: VectorSpace.H:115
Foam::dictionary::add
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:640
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
Foam::plusEqOp
Definition: ops.H:72
Foam::incompressible::sensitivitySurface::smoothSensitivities_
bool smoothSensitivities_
Definition: sensitivitySurfaceIncompressible.H:123
Foam::incompressible::sensitivitySurface::includeMeshMovement_
bool includeMeshMovement_
Include mesh movement variation in sens computation.
Definition: sensitivitySurfaceIncompressible.H:113
Foam::incompressible::sensitivitySurface::setSuffixName
void setSuffixName()
Set suffix name for sensitivity fields.
Definition: sensitivitySurfaceIncompressible.C:199
Foam::dictionary::getOrDefault
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:148
Foam::shapeSensitivitiesBase::setSuffix
void setSuffix(const word &suffix)
Set suffix.
Definition: shapeSensitivitiesBase.C:223
Foam::GeometricField< scalar, faPatchField, areaMesh >
Foam::IOobject::NO_READ
Definition: IOobject.H:188
Foam::incompressible::sensitivitySurface::readDict
virtual bool readDict(const dictionary &dict)
Read dict if changed.
Definition: sensitivitySurfaceIncompressible.C:570
Foam::gMax
Type gMax(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:592
Foam::faMatrix::relax
void relax(const scalar alpha)
Relax matrix (for steady-state solution).
Definition: faMatrix.C:519
Foam::incompressibleVars
Base class for solution control classes.
Definition: incompressibleVars.H:54
Foam::GeometricField::boundaryField
const Boundary & boundaryField() const
Return const-reference to the boundary field.
Definition: GeometricFieldI.H:62
Foam::incompressible::adjointSensitivity::write
virtual void write(const word &baseName=word::null)
Write sensitivity fields.
Definition: adjointSensitivityIncompressible.C:137
Foam::dimless
const dimensionSet dimless
Dimensionless.
Definition: dimensionSets.C:189
Foam::incompressible::sensitivitySurface::SfOnPatchPtr_
autoPtr< volVectorField > SfOnPatchPtr_
Definition: sensitivitySurfaceIncompressible.H:131
Foam::objectiveManager::getObjectiveFunctions
PtrList< objective > & getObjectiveFunctions()
Return reference to objective functions.
Definition: objectiveManager.C:296
Foam::IOobject::MUST_READ
Definition: IOobject.H:185
Foam::incompressible::adjointSensitivity::objectiveManager_
objectiveManager & objectiveManager_
Definition: adjointSensitivityIncompressible.H:86