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-------------------------------------------------------------------------------
12License
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"
35#include "faMatrices.H"
36#include "famSup.H"
37#include "famLaplacian.H"
38#include "volSurfaceMapping.H"
41
42// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
43
44namespace Foam
45{
46
47namespace incompressible
48{
49
50// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
51
54(
58);
59
60// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
61
63{
65 {
66 // Grab objective refs
67 PtrList<objective>& functions
69 // Compute sens for all points in parameterized patches.
70 // Interfacing points will be accumulated later
72 (
73 createZeroBoundaryPointFieldPtr<vector>(mesh_)
74 );
76 (
77 createZeroBoundaryPointFieldPtr<vector>(mesh_)
78 );
79 // Geometric (or "direct") sensitivities are better computed directly
80 // on the points
81 for (const label patchI : sensitivityPatchIDs_)
82 {
83 const fvPatch& patch = mesh_.boundary()[patchI];
84 const vectorField nf(patch.nf());
85
86 // point sens result for patch
87 vectorField& patchdSdb = pointSensdSdb()[patchI];
88 vectorField& patchdndb = pointSensdndb()[patchI];
89
90 vectorField dSdbMultiplierTot(patch.size(), Zero);
91 vectorField dndbMultiplierTot(patch.size(), Zero);
92 for (auto& fun : functions)
93 {
94 dSdbMultiplierTot += fun.weight()*fun.dSdbMultiplier(patchI);
95 dndbMultiplierTot += fun.weight()*fun.dndbMultiplier(patchI);
96 }
97 // Correspondence of local point addressing to global point
98 // addressing
99 const labelList& meshPoints = patch.patch().meshPoints();
100 // List with mesh faces. Global addressing
101 const faceList& faces = mesh_.faces();
102 // Each local patch point belongs to these local patch faces
103 // (local numbering)
104 const labelListList& patchPointFaces = patch.patch().pointFaces();
105 // index of first face in patch
106 const label patchStartIndex = patch.start();
107 // geometry differentiation engine
108 deltaBoundary dBoundary(mesh_);
109 // Loop over patch points.
110 // Collect contributions from each boundary face this point
111 // belongs to
112 forAll(meshPoints, ppI)
113 {
114 const labelList& pointFaces = patchPointFaces[ppI];
115 for (label localFaceIndex : pointFaces)
116 {
117 label globalFaceIndex = patchStartIndex + localFaceIndex;
118 const face& faceI = faces[globalFaceIndex];
119 // Point coordinates. All indices in global numbering
120 const pointField p(faceI.points(mesh_.points()));
121 tensorField p_d(faceI.size(), Zero);
122 forAll(faceI, facePointI)
123 {
124 if (faceI[facePointI] == meshPoints[ppI])
125 {
126 p_d[facePointI] = tensor::I;
127 }
128 }
129 const tensorField deltaNormals
130 (
131 dBoundary.makeFaceCentresAndAreas_d(p, p_d)
132 );
133
134 // Element [1] is the variation in the (dimensional) normal
135 const tensor& deltaSf = deltaNormals[1];
136 patchdSdb[ppI] +=
137 dSdbMultiplierTot[localFaceIndex] & deltaSf;
138
139 // Element [2] is the variation in the unit normal
140 const tensor& deltaNf = deltaNormals[2];
141 patchdndb[ppI] +=
142 dndbMultiplierTot[localFaceIndex] & deltaNf;
143 }
144 }
145 }
146 // Do parallel communications to avoid wrong values at processor
147 // boundaries
148 vectorField dSdbGlobal(mesh_.nPoints(), Zero);
149 vectorField dndbGlobal(mesh_.nPoints(), Zero);
150 for (const label patchI : sensitivityPatchIDs_)
151 {
152 const labelList& meshPoints =
153 mesh_.boundaryMesh()[patchI].meshPoints();
154 forAll(meshPoints, ppI)
155 {
156 const label globaPointI = meshPoints[ppI];
157 dSdbGlobal[globaPointI] += pointSensdSdb()[patchI][ppI];
158 dndbGlobal[globaPointI] += pointSensdndb()[patchI][ppI];
159 }
160 }
161 // Accumulate over processors
163 (
164 mesh_, dSdbGlobal, plusEqOp<vector>(), vector::zero
165 );
167 (
168 mesh_, dndbGlobal, plusEqOp<vector>(), vector::zero
169 );
170 // Transfer back to local fields and map to faces
171 for (const label patchI : sensitivityPatchIDs_)
172 {
173 const fvPatch& patch = mesh_.boundary()[patchI];
174 const labelList& meshPoints = patch.patch().meshPoints();
175 const scalarField& magSf = patch.magSf();
176 pointSensdSdb()[patchI].map(dSdbGlobal, meshPoints);
177 pointSensdndb()[patchI].map(dndbGlobal, meshPoints);
178 // Map dSf/dx and dnf/dx term from points to faces. Ideally, all
179 // sensitivities should be computed at points rather than faces.
180 PrimitivePatchInterpolation<polyPatch> patchInter(patch.patch());
181 vectorField dSdbFace
182 (
183 patchInter.pointToFaceInterpolate(pointSensdSdb()[patchI])
184 );
185 // dSdb already contains the face area. Divide with it to make it
186 // compatible with the rest of the terms
187 dSdbFace /= magSf;
188
189 tmp<vectorField> tdndbFace =
190 patchInter.pointToFaceInterpolate(pointSensdndb()[patchI]);
191 const vectorField& dndbFace = tdndbFace();
192
193 // Add to sensitivity fields
194 wallFaceSensVecPtr_()[patchI] += dSdbFace + dndbFace;
195 }
196 }
197}
198
199
201{
202 word suffix(dict().getOrDefault<word>("suffix", word::null));
203 // Determine suffix for fields holding the sens
205 {
207 (
208 adjointVars_.solverName() + "ESI" + suffix
209 );
210 }
211 else
212 {
214 (
215 adjointVars_.solverName() + "SI" + suffix
216 );
217 }
218}
219
220
222{
223 // Read in parameters
224 const label iters(dict().getOrDefault<label>("iters", 500));
225 const scalar tolerance(dict().getOrDefault<scalar>("tolerance", 1.e-06));
226 autoPtr<faMesh> aMeshPtr(nullptr);
227
228 IOobject faceLabels
229 (
230 "faceLabels",
232 (
234 "faceLabels",
236 ),
238 mesh_,
241 );
242
243 // If the faMesh already exists, read it
244 if (faceLabels.typeHeaderOk<labelIOList>(false))
245 {
246 Info<< "Reading the already constructed faMesh" << endl;
247 aMeshPtr.reset(new faMesh(mesh_));
248 }
249 else
250 {
251 // Dictionary used to construct the faMesh
252 dictionary faMeshDefinition;
253
254 IOobject faMeshDefinitionDict
255 (
256 "faMeshDefinition",
258 mesh_,
261 );
262
263 // If the faMeshDefinitionDict exists, use it to construct the mesh
264 if (faMeshDefinitionDict.typeHeaderOk<IOdictionary>(false))
265 {
266 Info<< "Reading faMeshDefinition from system " << endl;
267 faMeshDefinition = IOdictionary(faMeshDefinitionDict);
268 }
269 // Otherwise, faMesh is generated from all patches on which we compute
270 // sensitivities
271 else
272 {
273 Info<< "Constructing faMeshDefinition from sensitivity patches"
274 << endl;
275 wordList polyMeshPatches(sensitivityPatchIDs_.size());
276 label i(0);
277 for (const label patchID : sensitivityPatchIDs_)
278 {
279 polyMeshPatches[i++] = mesh_.boundary()[patchID].name();
280 }
281 faMeshDefinition.add<wordList>("polyMeshPatches", polyMeshPatches);
282 (void)faMeshDefinition.subDictOrAdd("boundary");
283 }
284
285 // Construct faMesh
286 aMeshPtr.reset(new faMesh(mesh_, faMeshDefinition));
287 }
288 faMesh& aMesh = aMeshPtr.ref();
289
290 // Physical radius of the smoothing, provided either directly or computed
291 // based on the average 'length' of boundary faces
292 const scalar Rphysical
293 (dict().getOrDefault<scalar>("radius", computeRadius(aMesh)));
295 << "Physical radius of the sensitivity smoothing "
296 << Rphysical << nl << endl;
297
298 // Radius used as the diffusivity in the Helmholtz filter, computed as a
299 // function of the physical radius
300 const dimensionedScalar RpdeSqr
301 (
302 "RpdeSqr", dimArea, sqr(Rphysical/(2.*::sqrt(3.)))
303 );
304
305 dimensionedScalar one("1", dimless, 1.);
306
307 // Mapping engine
309
310 // Source term in faMatrix needs to be an areaField
311 areaScalarField sens
312 (
314 (
315 "sens",
316 mesh_.time().timeName(),
317 mesh_,
320 ),
321 aMesh,
324 );
325
326 // Copy sensitivities to area field
327 sens.primitiveFieldRef() =
328 vsm.mapToSurface<scalar>(wallFaceSensNormalPtr_());
329
330 // Initialisation of the smoothed sensitivities field based on the original
331 // sensitivities
332 areaScalarField smoothedSens("smoothedSens", sens);
333 for (label iter = 0; iter < iters; ++iter)
334 {
335 Info<< "Sensitivity smoothing iteration " << iter << endl;
336
337 faScalarMatrix smoothEqn
338 (
339 fam::Sp(one, smoothedSens)
340 - fam::laplacian(RpdeSqr, smoothedSens)
341 ==
342 sens
343 );
344
345 smoothEqn.relax();
346
347 const scalar residual(mag(smoothEqn.solve().initialResidual()));
348
350 << "Max smoothSens " << gMax(mag(smoothedSens)()) << endl;
351
352 // Print execution time
354
355 // Check convergence
356 if (residual < tolerance)
357 {
358 Info<< "\n***Reached smoothing equation convergence limit, "
359 "iteration " << iter << "***\n\n";
360 break;
361 }
362 }
363
364 // Field used to write the smoothed sensitivity field to file
365 volScalarField volSmoothedSens
366 (
368 (
369 "smoothedSurfaceSens" + surfaceFieldSuffix_,
370 mesh_.time().timeName(),
371 mesh_,
374 ),
375 mesh_,
377 );
378
379 // Transfer result back to volField and write
380 vsm.mapToVolume(smoothedSens, volSmoothedSens.boundaryFieldRef());
381 volSmoothedSens.write();
382}
383
384
386{
387 scalar averageArea(gAverage(aMesh.S().field()));
388 const Vector<label>& geometricD = mesh_.geometricD();
389 const boundBox& bounds = mesh_.bounds();
390 forAll(geometricD, iDir)
391 {
392 if (geometricD[iDir] == -1)
393 {
394 averageArea /= bounds.span()[iDir];
395 }
396 }
397 scalar mult = dict().getOrDefault<scalar>("meanRadiusMultiplier", 10);
398
399 return mult*pow(averageArea, scalar(1)/scalar(mesh_.nGeometricD() - 1));
400}
401
402
403// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
404
406(
407 const fvMesh& mesh,
408 const dictionary& dict,
410)
411:
414 includeSurfaceArea_(false),
415 includePressureTerm_(false),
416 includeGradStressTerm_(false),
417 includeTransposeStresses_(false),
418 useSnGradInTranposeStresses_(false),
419 includeDivTerm_(false),
420 includeDistance_(false),
421 includeMeshMovement_(false),
422 includeObjective_(false),
423 writeGeometricInfo_(false),
424 smoothSensitivities_(false),
425 eikonalSolver_(nullptr),
426 meshMovementSolver_(nullptr),
427
428 nfOnPatchPtr_(nullptr),
429 SfOnPatchPtr_(nullptr),
430 CfOnPatchPtr_(nullptr)
431{
432 read();
434
435 // Allocate boundary field pointer
436 wallFaceSensVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
437 wallFaceSensNormalPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
438 wallFaceSensNormalVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
439
440 // Allocate fields to contain geometric info
442 {
443 nfOnPatchPtr_.reset
444 (
446 (
448 (
449 "nfOnPatch",
450 mesh.time().timeName(),
451 mesh,
454 ),
455 mesh,
457 )
458 );
459
460 SfOnPatchPtr_.reset
461 (
463 (
465 (
466 "SfOnPatch",
467 mesh.time().timeName(),
468 mesh,
471 ),
472 mesh,
474 )
475 );
476
477 CfOnPatchPtr_.reset
478 (
480 (
482 (
483 "CfOnPatch",
484 mesh.time().timeName(),
485 mesh,
488 ),
489 mesh,
491 )
492 );
493 }
494
495 // Allocate appropriate space for the sensitivity field
497}
498
499
500// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
501
503{
505 dict().getOrDefault<bool>("includeSurfaceArea", true);
507 dict().getOrDefault<bool>("includePressure", true);
509 dict().getOrDefault<bool>("includeGradStressTerm", true);
511 dict().getOrDefault<bool>("includeTransposeStresses", true);
513 dict().getOrDefault<bool>("useSnGradInTranposeStresses", false);
514 includeDivTerm_ = dict().getOrDefault<bool>("includeDivTerm", false);
516 dict().getOrDefault<bool>
517 (
518 "includeDistance",
519 adjointVars_.adjointTurbulence().ref().includeDistance()
520 );
522 dict().getOrDefault<bool>("includeMeshMovement", true);
524 dict().getOrDefault<bool>("includeObjectiveContribution", true);
526 dict().getOrDefault<bool>("writeGeometricInfo", false);
528 dict().getOrDefault<bool>("smoothSensitivities", false);
529
530 // Allocate new solvers if necessary
532 {
533 eikonalSolver_.reset
534 (
536 (
537 mesh_,
538 dict_,
541 sensitivityPatchIDs_
542 )
543 );
544 }
546 {
548 (
550 (
551 mesh_,
552 dict_,
553 *this,
554 sensitivityPatchIDs_,
556 )
557 );
558 }
559}
560
561
562bool sensitivitySurface::readDict(const dictionary& dict)
563{
564 if (sensitivity::readDict(dict))
565 {
566 if (eikonalSolver_)
567 {
568 eikonalSolver_().readDict(dict);
569 }
570
572 {
573 meshMovementSolver_().readDict(dict);
574 }
575
576 return true;
577 }
578
579 return false;
580}
581
582
584{
585 label nFaces(0);
586 for (const label patchI : sensitivityPatchIDs_)
587 {
588 nFaces += mesh_.boundary()[patchI].size();
589 }
591}
592
593
595{
596 // Grab references
597 const volScalarField& p = primalVars_.p();
598 const volVectorField& U = primalVars_.U();
599
600 const volScalarField& pa = adjointVars_.pa();
601 const volVectorField& Ua = adjointVars_.Ua();
604
605 // Accumulate source for additional post-processing PDEs, if necessary
607 {
608 eikonalSolver_->accumulateIntegrand(dt);
609 }
610
612 {
613 meshMovementSolver_->accumulateIntegrand(dt);
614 }
615
616 // Terms from the adjoint turbulence model
617 const boundaryVectorField& adjointTMsensitivities =
618 adjointTurbulence->wallShapeSensitivities();
619
621 << " Calculating adjoint sensitivity. " << endl;
622
623 tmp<volScalarField> tnuEff = adjointTurbulence->nuEff();
624 const volScalarField& nuEff = tnuEff.ref();
625
626 // Sensitivities do not include locale surface area by default.
627 // The part of the sensitivities that multiplies dxFace/db follows
628
629 // Deal with the stress part first since it's the most awkward in terms
630 // of memory managment
632 {
633 // Terms corresponding to contributions from converting delta
634 // to thetas are added through the corresponding adjoint
635 // boundary conditions instead of grabbing contributions from
636 // the objective function. Useful to have a unified
637 // formulation for low- and high-re meshes
638
640 const volVectorField& gradp = tgradp.ref();
641 for (const label patchI : sensitivityPatchIDs_)
642 {
643 const fvPatch& patch = mesh_.boundary()[patchI];
644 tmp<vectorField> tnf = patch.nf();
645 const fvPatchVectorField& Uab = Ua.boundaryField()[patchI];
646 wallFaceSensVecPtr_()[patchI] -=
647 (Uab & tnf)*gradp.boundaryField()[patchI]*dt;
648 }
649 tgradp.clear();
650
651 // We only need to modify the boundaryField of gradU locally.
652 // If grad(U) is cached then
653 // a. The .ref() call fails since the tmp is initialised from a
654 // const ref
655 // b. we would be changing grad(U) for all other places in the code
656 // that need it
657 // So, always allocate new memory and avoid registering the new field
658 tmp<volTensorField> tgradU =
659 volTensorField::New("gradULocal", fvc::grad(U));
660 volTensorField::Boundary& gradUbf = tgradU.ref().boundaryFieldRef();
661
662 // Explicitly correct the boundary gradient to get rid of the
663 // tangential component
664 forAll(mesh_.boundary(), patchI)
665 {
666 const fvPatch& patch = mesh_.boundary()[patchI];
667 if (isA<wallFvPatch>(patch))
668 {
669 tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
670 gradUbf[patchI] = tnf*U.boundaryField()[patchI].snGrad();
671 }
672 }
673
674 tmp<volSymmTensorField> tstress = nuEff*twoSymm(tgradU);
675 const volSymmTensorField& stress = tstress.cref();
677 (Foam::createZeroFieldPtr<vector>(mesh_, "temp", sqr(dimVelocity)));
678 volVectorField& temp = ptemp.ref();
679 for (label idir = 0; idir < pTraits<vector>::nComponents; ++idir)
680 {
681 unzipRow(stress, idir, temp);
682 volTensorField gradStressDir(fvc::grad(temp));
683 for (const label patchI : sensitivityPatchIDs_)
684 {
685 const fvPatch& patch = mesh_.boundary()[patchI];
686 tmp<vectorField> tnf = patch.nf();
687 const fvPatchVectorField& Uab = Ua.boundaryField()[patchI];
688 wallFaceSensVecPtr_()[patchI] +=
689 (
690 Uab.component(idir)
691 *(gradStressDir.boundaryField()[patchI] & tnf)
692 )*dt;
693 }
694 }
695 }
696
697 // Transpose part of the adjoint stresses
698 // Dealt with separately to deallocate gradUa as soon as possible
700 {
701 tmp<volTensorField> tgradUa = fvc::grad(Ua);
702 const volTensorField::Boundary& gradUabf =
703 tgradUa.cref().boundaryField();
704
705 for (const label patchI : sensitivityPatchIDs_)
706 {
707 const fvPatch& patch = mesh_.boundary()[patchI];
708 tmp<vectorField> tnf = patch.nf();
709 const vectorField& nf = tnf();
710 vectorField gradUaNf
711 (
713 ? (Ua.boundaryField()[patchI].snGrad() & nf)*nf
714 : (gradUabf[patchI] & nf)
715 );
716 wallFaceSensVecPtr_()[patchI] -=
717 nuEff.boundaryField()[patchI]
718 *(gradUaNf & U.boundaryField()[patchI].snGrad())*nf;
719 }
720 }
721
722 for (const label patchI : sensitivityPatchIDs_)
723 {
724 const fvPatch& patch = mesh_.boundary()[patchI];
725 tmp<vectorField> tnf = patch.nf();
726 const vectorField& nf = tnf();
727
728 // Includes spurious tangential gradU part. Deprecated
729 /*
730 vectorField stressAndPressureTerm =
731 (
732 - (
733 Ua.boundaryField()[patchI].snGrad()
734 + (gradUa.boundaryField()[patchI] & nf)
735 ) * nuEff.boundaryField()[patchI]
736 + pa.boundaryField()[patchI] *nf
737 ) & gradU.boundaryField()[patchI].T();
738 */
739
740 // Adjoint stress term
741 vectorField stressTerm
742 (
743 - (
744 Ua.boundaryField()[patchI].snGrad()
745 & U.boundaryField()[patchI].snGrad()
746 )
747 * nuEff.boundaryField()[patchI]
748 * nf
749 );
750
751 if (includeDivTerm_)
752 {
753 stressTerm +=
754 scalar(1./3.)*nuEff.boundaryField()[patchI]
755 * (
756 ((Ua.boundaryField()[patchI].snGrad() &nf)*nf)
757 & U.boundaryField()[patchI].snGrad()
758 )
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);
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 + pressureTerm
795 + adjointTMsensitivities[patchI]
796 + dxdbMultiplierTot
797 )*dt;
798 }
799
800 // Add terms from physics other than the typical incompressible flow eqns
802 (wallFaceSensVecPtr_(), sensitivityPatchIDs_, dt);
803
804 // Add the sensitivity part corresponding to changes of the normal vector
805 // Computed at points and mapped to faces
807}
808
809
811{
812 // Update geometric fields for use by external users
814 {
815 for (const label patchI : sensitivityPatchIDs_)
816 {
817 const fvPatch& patch = mesh_.boundary()[patchI];
818 tmp<vectorField> tnf = patch.nf();
819 const vectorField& nf = tnf();
820 const vectorField& Sf = patch.Sf();
821 const vectorField& Cf = patch.Cf();
822
823 nfOnPatchPtr_().boundaryFieldRef()[patchI] = nf;
824 SfOnPatchPtr_().boundaryFieldRef()[patchI] = Sf;
825 CfOnPatchPtr_().boundaryFieldRef()[patchI] = Cf;
826 }
827 }
828
829 // Solve extra equations if necessary
830 // Solved using accumulated sources over time
831 autoPtr<boundaryVectorField> distanceSensPtr(nullptr);
833 {
834 eikonalSolver_->solve();
835 distanceSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
836 const boundaryVectorField& sens =
837 eikonalSolver_->distanceSensitivities();
838 for (const label patchI : sensitivityPatchIDs_)
839 {
840 distanceSensPtr()[patchI] = sens[patchI];
841 }
842 }
843
844 autoPtr<boundaryVectorField> meshMovementSensPtr(nullptr);
846 {
847 meshMovementSolver_->solve();
848 meshMovementSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
849 const boundaryVectorField& sens =
850 meshMovementSolver_->meshMovementSensitivities();
851 for (const label patchI : sensitivityPatchIDs_)
852 {
853 meshMovementSensPtr()[patchI] = sens[patchI];
854 }
855 }
856
857
858 // Project to normal face vector
859 label nPassedFaces(0);
860 for (const label patchI : sensitivityPatchIDs_)
861 {
862 const fvPatch& patch = mesh_.boundary()[patchI];
863 tmp<vectorField> tnf(patch.nf());
864 const vectorField& nf = tnf();
865
866 // Distance related terms
868 {
869 wallFaceSensVecPtr_()[patchI] += distanceSensPtr()[patchI];
870 }
871
872 // Mesh movement related terms
874 {
875 wallFaceSensVecPtr_()[patchI] += meshMovementSensPtr()[patchI];
876 }
877
879 {
880 wallFaceSensVecPtr_()[patchI] *= patch.magSf();
881 }
882
883 wallFaceSensNormalPtr_()[patchI] = wallFaceSensVecPtr_()[patchI] & nf;
884 wallFaceSensNormalVecPtr_()[patchI] =
885 wallFaceSensNormalPtr_()[patchI] * nf;
886
887 forAll(patch, fI)
888 {
889 derivatives_[nPassedFaces + fI]
890 = wallFaceSensNormalPtr_()[patchI][fI];
891 }
892 nPassedFaces += patch.size();
893 }
894
895 // Smooth sensitivities if needed
897 {
899 }
900}
901
902
904{
905 // Reset terms in post-processing PDEs
907 {
908 eikonalSolver_->reset();
909 }
911 {
912 meshMovementSolver_->reset();
913 }
914 // Reset sensitivity fields
917}
918
919
921{
922 return eikonalSolver_;
923}
924
925
926void sensitivitySurface::write(const word& baseName)
927{
931
933 {
934 nfOnPatchPtr_().write();
935 SfOnPatchPtr_().write();
936 CfOnPatchPtr_().write();
937 }
938}
939
940
941// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
942
943} // End namespace Foam
944} // End namespace incompressible
945
946// ************************************************************************* //
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
const Field< Type > & field() const
Return field.
tmp< Field< cmptType > > component(const direction) const
Return a component field of the field.
Definition: Field.C:545
Generic GeometricBoundaryField class.
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field.
Boundary & boundaryFieldRef(const bool updateAccessTime=true)
Return a reference to the boundary field.
const Boundary & boundaryField() const
Return const-reference to the boundary field.
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:57
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:170
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.
void setSize(const label n)
Alias for resize()
Definition: List.H:218
Interpolation class within a primitive patch. Allows interpolation from points to faces and vice vers...
tmp< Field< Type > > pointToFaceInterpolate(const Field< Type > &pf) const
Interpolate from points to faces.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition: PtrList.H:73
static const Tensor I
Definition: Tensor.H:81
fileName caseSystem() const
Definition: TimePathsI.H:119
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
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
static word timeName(const scalar t, const int precision=precision_)
Definition: Time.C:780
Ostream & printExecutionTime(OSstream &os) const
Print the elapsed ExecutionTime (cpu-time), ClockTime.
Definition: TimeIO.C:618
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:106
Templated 3D Vector derived from VectorSpace adding construction from 3 components,...
Definition: Vector.H:65
Base class for adjoint solvers.
Definition: adjointSolver.H:60
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
T & ref()
Return reference to the managed object without nullptr checking.
Definition: autoPtr.H:161
void reset(autoPtr< T > &&other) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:117
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:64
vector span() const
The bounding box span (from minimum to maximum)
Definition: boundBoxI.H:127
Differentiation of the mesh data structure.
Definition: deltaBoundary.H:59
vectorField makeFaceCentresAndAreas_d(const pointField &p, const pointField &p_d)
Definition: deltaBoundary.C:72
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
dictionary & subDictOrAdd(const word &keyword, enum keyType::option matchOpt=keyType::REGEX)
Find and return a sub-dictionary for manipulation.
Definition: dictionary.C:500
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:640
A special matrix type and solver, designed for finite area solutions of scalar equations....
Definition: faMatrix.H:76
void relax(const scalar alpha)
Relax matrix (for steady-state solution).
Definition: faMatrix.C:491
SolverPerformance< Type > solve(const dictionary &)
Solve returning the solution statistics.
Definition: faMatrixSolve.C:55
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition: faMesh.H:100
const DimensionedField< scalar, areaMesh > & S() const
Return face areas.
Definition: faMesh.C:780
static word meshSubDir
The mesh sub-directory name (usually "faMesh")
Definition: faMesh.H:504
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
pointField points(const UList< point > &pts) const
Return the points corresponding to this face.
Definition: faceI.H:87
virtual bool write()
Write the output fields.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:91
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:712
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:290
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:71
const volScalarField & pa() const
Return const reference to pressure.
const volVectorField & Ua() const
Return const reference to velocity.
Base class for incompressibleAdjoint solvers.
virtual void additionalSensitivityMapTerms(boundaryVectorField &sensitivityMap, const labelHashSet &patchIDs, const scalar dt)
const autoPtr< incompressibleAdjoint::adjointRASModel > & adjointTurbulence() const
Return const reference to the adjointRASModel.
const volVectorField & U() const
Return const reference to velocity.
const volScalarField & p() const
Return const reference to pressure.
const autoPtr< incompressible::RASModelVariables > & RASModelVariables() const
Return const reference to the turbulence model variables.
Solver of the adjoint to the Laplace grid displacement equation.
Abstract base class for adjoint-based sensitivities in incompressible flows.
virtual void clearSensitivities()
Zero sensitivity fields and their constituents.
Calculation of adjoint based sensitivities at wall faces.
bool includeTransposeStresses_
Include the transpose part of the adjoint stresses.
virtual void clearSensitivities()
Zero sensitivity fields and their constituents.
autoPtr< adjointEikonalSolver > & getAdjointEikonalSolver()
Get adjoint eikonal solver.
bool includeDistance_
Include distance variation in sens computation.
bool useSnGradInTranposeStresses_
Use snGrad in the transpose part of the adjoint stresses.
virtual void assembleSensitivities()
Assemble sensitivities.
void computeDerivativesSize()
Compute the number of faces on sensitivityPatchIDs_.
void setSuffixName()
Set suffix name for sensitivity fields.
bool includePressureTerm_
Include the adjoint pressure term in sens computation.
bool includeGradStressTerm_
Include the term containing the grad of the stress at the boundary.
bool includeSurfaceArea_
Include surface area in sens computation.
bool writeGeometricInfo_
Write geometric info for use by external programs.
void read()
Read controls and update solver pointers if necessary.
bool includeMeshMovement_
Include mesh movement variation in sens computation.
bool includeDivTerm_
Include the term from the deviatoric part of the stresses.
virtual void accumulateIntegrand(const scalar dt)
Accumulate sensitivity integrands.
autoPtr< adjointMeshMovementSolver > meshMovementSolver_
bool includeObjective_
Include terms directly emerging from the objective function.
PtrList< objective > & getObjectiveFunctions()
Return reference to objective functions.
A class representing the concept of 1 (one) that can be used to avoid manipulating objects known to b...
Definition: one.H:62
label nGeometricD() const
Return the number of valid geometric dimensions in the mesh.
Definition: polyMesh.C:883
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1108
virtual const fileName & dbDir() const
Override the objectRegistry dbDir for a single-region case.
Definition: polyMesh.C:837
const boundBox & bounds() const
Return mesh bounding box.
Definition: polyMesh.H:462
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:456
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1083
const Vector< label > & geometricD() const
Return the vector of geometric directions in mesh.
Definition: polyMesh.C:872
label nPoints() const noexcept
Number of mesh points.
virtual bool write(const bool valid=true) const
Write using setting from DB.
const fvMesh & mesh_
Definition: sensitivity.H:69
dictionary dict_
Definition: sensitivity.H:70
const dictionary & dict() const
Return the construction dictionary.
Definition: sensitivity.C:57
void clearSensitivities()
Zero sensitivity fields and their constituents.
void setSuffix(const word &suffix)
Set suffix.
void write()
Write sensitivity fields.
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
A class for managing temporary objects.
Definition: tmp.H:65
const T & cref() const
Definition: tmpI.H:213
void clear() const noexcept
Definition: tmpI.H:287
T & ref() const
Definition: tmpI.H:227
const word & solverName() const
Return solver name.
Definition: variablesSet.C:84
Volume to surface and surface to volume mapping.
tmp< Field< Type > > mapToSurface(const GeometricBoundaryField< Type, fvPatchField, volMesh > &df) const
Map volume boundary field to surface.
void mapToVolume(const GeometricField< Type, faPatchField, areaMesh > &af, GeometricBoundaryField< Type, fvPatchField, volMesh > &bf) const
Map surface field to volume boundary field.
A class for handling words, derived from Foam::string.
Definition: word.H:68
Author Zeljko Tukovic, FMENA Hrvoje Jasak, Wikki Ltd.
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
U
Definition: pEqn.H:72
volScalarField & p
dynamicFvMesh & mesh
volSurfaceMapping vsm(aMesh)
Calculate the matrix for the laplacian of the field.
Calculate the finiteArea matrix for implicit and explicit sources.
const labelList nFaces(UPstream::listGatherValues< label >(aMesh.nFaces()))
#define DebugInfo
Report an information message using Foam::Info.
tmp< faMatrix< Type > > laplacian(const GeometricField< Type, faPatchField, areaMesh > &vf)
Definition: famLaplacian.C:49
zeroField Sp(const Foam::zero, const GeometricField< Type, faPatchField, areaMesh > &)
A no-op source.
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh > > grad(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcGrad.C:54
Namespace for OpenFOAM.
const dimensionSet dimless
Dimensionless.
dimensionedSymmTensor sqr(const dimensionedVector &dv)
const dimensionSet dimArea(sqr(dimLength))
Definition: dimensionSets.H:59
dimensionedSymmTensor twoSymm(const dimensionedSymmTensor &dt)
const dimensionSet dimVelocity
messageStream Info
Information stream (stdout output on master, null elsewhere)
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
dimensionedScalar sqrt(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Type gAverage(const FieldField< Field, Type > &f)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
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)
Type gMax(const FieldField< Field, Type > &f)
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
loopControl iters(runTime, aMesh.solutionDict(), "solution")
dictionary dict
faMesh aMesh(mesh)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
A non-counting (dummy) refCount.
Definition: refCount.H:59