sensitivitySurface.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 
30 #include "sensitivitySurface.H"
32 #include "faMatrices.H"
33 #include "famSup.H"
34 #include "famLaplacian.H"
35 #include "volSurfaceMapping.H"
37 
38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
39 
40 namespace Foam
41 {
42 
43 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
44 
45 defineTypeNameAndDebug(sensitivitySurface, 0);
47 (
48  adjointSensitivity,
49  sensitivitySurface,
51 );
52 
53 
54 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
55 
57 (
58  const bool computeVectorFieldSize
59 )
60 {
61  label size(0);
62  for (const label patchI : sensitivityPatchIDs_)
63  {
64  const fvPatch& patch = mesh_.boundary()[patchI];
65  const label patchSize = patch.size();
66  size += label(computeVectorFieldSize ? 3*patchSize : patchSize);
67  }
68  return size;
69 }
70 
71 
73 {
74  // Read in parameters
75  const label iters(dict().getOrDefault<label>("iters", 500));
76  const scalar tolerance(dict().getOrDefault<scalar>("tolerance", 1.e-06));
77  autoPtr<faMesh> aMeshPtr(nullptr);
78 
79  IOobject faceLabels
80  (
81  "faceLabels",
83  (
85  "faceLabels",
87  ),
89  mesh_,
92  );
93 
94  // If the faMesh already exists, read it
95  if (faceLabels.typeHeaderOk<labelIOList>(false))
96  {
97  Info<< "Reading the already constructed faMesh" << endl;
98  aMeshPtr.reset(new faMesh(mesh_));
99  }
100  else
101  {
102  // Dictionary used to construct the faMesh
103  dictionary faMeshDefinition;
104 
105  IOobject faMeshDefinitionDict
106  (
107  "faMeshDefinition",
108  mesh_.time().caseSystem(),
109  mesh_,
112  );
113 
114  // If the faMeshDefinitionDict exists, use it to construct the mesh
115  if (faMeshDefinitionDict.typeHeaderOk<IOdictionary>(false))
116  {
117  Info<< "Reading faMeshDefinition from system " << endl;
118  faMeshDefinition = IOdictionary(faMeshDefinitionDict);
119  }
120  // Otherwise, faMesh is generated from all patches on which we compute
121  // sensitivities
122  else
123  {
124  Info<< "Constructing faMeshDefinition from sensitivity patches"
125  << endl;
126  wordList polyMeshPatches(sensitivityPatchIDs_.size());
127  label i(0);
128  for (const label patchID : sensitivityPatchIDs_)
129  {
130  polyMeshPatches[i++] = mesh_.boundary()[patchID].name();
131  }
132  faMeshDefinition.add<wordList>("polyMeshPatches", polyMeshPatches);
133  (void)faMeshDefinition.subDictOrAdd("boundary");
134  Info<< faMeshDefinition << endl;
135  }
136 
137  // Construct faMesh
138  aMeshPtr.reset(new faMesh(mesh_, faMeshDefinition));
139  }
140  faMesh& aMesh = aMeshPtr.ref();
141 
142  // Physical radius of the smoothing, provided either directly or computed
143  // based on the average 'length' of boundary faces
144  const scalar Rphysical
145  (dict().getOrDefault<scalar>("radius", computeRadius(aMesh)));
146  DebugInfo
147  << "Physical radius of the sensitivity smoothing "
148  << Rphysical << nl << endl;
149 
150  // Radius used as the diffusivity in the Helmholtz filter, computed as a
151  // function of the physical radius
152  const dimensionedScalar RpdeSqr
153  (
154  "RpdeSqr", dimArea, sqr(Rphysical/(2.*::sqrt(3.)))
155  );
156 
157  dimensionedScalar one("1", dimless, 1.);
158 
159  // Mapping engine
160  volSurfaceMapping vsm(aMesh);
161 
162  // Source term in faMatrix needs to be an areaField
163  areaVectorField sens
164  (
165  IOobject
166  (
167  "sens",
168  mesh_.time().timeName(),
169  mesh_,
172  ),
173  aMesh,
176  );
177 
178  // Copy sensitivities to area field
179  sens.primitiveFieldRef() =
180  vsm.mapToSurface<vector>(wallFaceSensVecPtr_());
181 
182  // Initialisation of the smoothed sensitivities field based on the original
183  // sensitivities
184  areaVectorField smoothedSens("smoothedSens", sens);
185  for (label iter = 0; iter < iters; ++iter)
186  {
187  Info<< "Sensitivity smoothing iteration " << iter << endl;
188 
189  faVectorMatrix smoothEqn
190  (
191  fam::Sp(one, smoothedSens)
192  - fam::laplacian(RpdeSqr, smoothedSens)
193  ==
194  sens
195  );
196 
197  smoothEqn.relax();
198 
199  const scalar residual(mag(smoothEqn.solve().initialResidual()));
200 
201  DebugInfo
202  << "Max smoothSens " << gMax(mag(smoothedSens)()) << endl;
203 
204  // Print execution time
206 
207  // Check convergence
208  if (residual < tolerance)
209  {
210  Info<< "\n***Reached smoothing equation convergence limit, "
211  "iteration " << iter << "***\n\n";
212  break;
213  }
214  }
215 
216  // Transfer smooth sensitivity field to wallFaceSensVecPtr_ for defining
217  // derivatives_
218  vsm.mapToVolume(smoothedSens, wallFaceSensVecPtr_());
219 
220  // Write normal, regularised sensitivities to file
221  volScalarField volSmoothedSens
222  (
223  IOobject
224  (
225  "smoothedSurfaceSens" + suffix_,
226  mesh_.time().timeName(),
227  mesh_,
230  ),
231  mesh_,
233  );
234  areaVectorField nf(aMesh.faceAreaNormals());
235  nf.normalise();
236  areaScalarField smoothedSensNormal(smoothedSens & nf);
237  vsm.mapToVolume(smoothedSensNormal, volSmoothedSens.boundaryFieldRef());
238  volSmoothedSens.write();
239 }
240 
241 
242 scalar sensitivitySurface::computeRadius(const faMesh& aMesh)
243 {
244  scalar averageArea(gAverage(aMesh.S().field()));
245  const Vector<label>& geometricD = mesh_.geometricD();
246  const boundBox& bounds = mesh_.bounds();
247  forAll(geometricD, iDir)
248  {
249  if (geometricD[iDir] == -1)
250  {
251  averageArea /= bounds.span()[iDir];
252  }
253  }
254  scalar mult = dict().getOrDefault<scalar>("meanRadiusMultiplier", 10);
255 
256  return mult*pow(averageArea, scalar(1)/scalar(mesh_.nGeometricD() - 1));
257 }
258 
259 
260 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
261 
262 sensitivitySurface::sensitivitySurface
263 (
264  const fvMesh& mesh,
265  const dictionary& dict,
267 )
268 :
270  smoothSensitivities_(dict.getOrDefault("smoothSensitivities", false)),
271  returnVectorField_
272  (dict.getOrDefault<bool>("returnVectorField", true))
273  //finalResultIncludesArea_
274  // (dict.getOrDefault<bool>("finalResultIncludesArea", false))
275 {
276  // Allocate boundary field pointers
277  wallFaceSensVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
278  wallFaceSensNormalPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
279  wallFaceSensNormalVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
282 }
283 
284 
285 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
286 
288 {
290  smoothSensitivities_ = dict().getOrDefault("smoothSensitivities", false);
292  dict().getOrDefault<bool>("returnVectorField", true);
293  //finalResultIncludesArea_ =
294  // dict().getOrDefault<bool>("finalResultIncludesArea", false);
295 }
296 
297 
299 (
300  autoPtr<designVariables>& designVars
301 )
302 {
303  // Compute point-based sensitivities
305 
306  // Transfer point sensitivities to point field
307  vectorField pointSens(mesh_.nPoints(), Zero);
308  for (const label patchI : sensitivityPatchIDs_)
309  {
310  const polyPatch& pp = mesh_.boundaryMesh()[patchI];
311  const labelList& meshPoints = pp.meshPoints();
312  forAll(meshPoints, ppi)
313  {
314  pointSens[meshPoints[ppi]] = wallPointSensVecPtr_()[patchI][ppi];
315  }
316  }
317 
318  // vectorField face-sensitivities
319  vectorField faceVecSens(computeFaceDerivativesSize(false), Zero);
320 
321  // Map sensitivities from points to faces
322  volPointInterpolationAdjoint interpolation(mesh_);
323  interpolation.interpolateSensitivitiesField
324  (pointSens, faceVecSens, sensitivityPatchIDs_);
325 
326  // Transfer non-regularised sensitivities to wallFaceSens* fields and write
327  label nPassedFaces(0);
328  for (const label patchI : sensitivityPatchIDs_)
329  {
330  const fvPatch& patch = mesh_.boundary()[patchI];
331  tmp<vectorField> nf = patch.nf();
332  wallFaceSensVecPtr_()[patchI] =
333  SubField<vector>(faceVecSens, patch.size(), nPassedFaces)
334  /patch.magSf();
335  wallFaceSensNormalPtr_()[patchI] = wallFaceSensVecPtr_()[patchI] & nf();
336  wallFaceSensNormalVecPtr_()[patchI] =
337  wallFaceSensNormalPtr_()[patchI]*nf;
338  nPassedFaces += patch.size();
339  }
340  write();
341 
342  // Regularise sensitivities if necessary
344  {
346  }
347 
348  // Make sure we have the correct sensitivities size
350  nPassedFaces = 0;
351  for (const label patchI : sensitivityPatchIDs_)
352  {
353  const fvPatch& patch = mesh_.boundary()[patchI];
354  const vectorField nf(patch.nf());
355  if (returnVectorField_)
356  {
357  const Vector<label>& sd = mesh_.solutionD();
358  forAll(patch, fI)
359  {
360  const label gfI = nPassedFaces + fI;
361  const vector& fSens = wallFaceSensVecPtr_()[patchI][fI];
362  derivatives_[3*gfI ] = scalar(sd[0] == -1 ? 0 : fSens.x());
363  derivatives_[3*gfI + 1] = scalar(sd[1] == -1 ? 0 : fSens.y());
364  derivatives_[3*gfI + 2] = scalar(sd[2] == -1 ? 0 : fSens.z());
365  }
366  }
367  else
368  {
369  forAll(patch, fI)
370  {
371  derivatives_[nPassedFaces + fI]
372  = wallFaceSensVecPtr_()[patchI][fI] & nf[fI];
373  }
374  }
375  nPassedFaces += patch.size();
376  }
377 }
378 
379 
380 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
381 
382 } // End namespace Foam
383 
384 // ************************************************************************* //
const fvMesh & mesh_
Definition: sensitivity.H:68
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition: faMesh.H:87
dictionary dict
autoPtr< pointBoundaryVectorField > wallPointSensVecPtr_
Wall point sens w.r.t. (x,y.z)
const volSurfaceMapping vsm(aMesh)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
word findInstance(const fileName &dir, const word &name=word::null, IOobjectOption::readOption rOpt=IOobjectOption::MUST_READ, const word &stopInstance=word::null) const
Return time instance (location) of dir that contains the file name (eg, used in reading mesh data)...
Definition: Time.C:725
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:129
labelHashSet sensitivityPatchIDs_
Patches on which to compute shape sensitivities.
dimensionedSymmTensor sqr(const dimensionedVector &dv)
const Vector< label > & solutionD() const
Return the vector of solved-for directions in mesh.
Definition: polyMesh.C:882
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
const DimensionedField< scalar, areaMesh > & S() const
Return face areas.
Definition: faMesh.C:914
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:70
autoPtr< boundaryVectorField > wallFaceSensNormalVecPtr_
Normal sens as vectors.
Base class for adjoint solvers.
Definition: adjointSolver.H:53
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
void read()
Read controls and update solver pointers if necessary.
virtual const fileName & dbDir() const
Override the objectRegistry dbDir for a single-region case.
Definition: polyMesh.C:830
faMatrix< vector > faVectorMatrix
Definition: faMatrices.H:47
Ignore writing from objectRegistry::writeObject()
const dimensionSet dimless
Dimensionless.
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
autoPtr< boundaryVectorField > wallFaceSensVecPtr_
Wall face sens w.r.t. (x,y.z)
labelList faceLabels(nFaceLabels)
autoPtr< boundaryScalarField > wallFaceSensNormalPtr_
Wall face sens projected to normal.
label nGeometricD() const
Return the number of valid geometric dimensions in the mesh.
Definition: polyMesh.C:876
static const word & zeroGradientType() noexcept
The type name for zeroGradient patch fields.
Definition: faPatchField.H:191
Macros for easy insertion into run-time selection tables.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
tmp< faMatrix< Type > > laplacian(const GeometricField< Type, faPatchField, areaMesh > &vf)
Definition: famLaplacian.C:42
fileName caseSystem() const
Return the system name for the case, which is ../system() for parallel runs.
Definition: TimePathsI.H:135
const Vector< label > & geometricD() const
Return the vector of geometric directions in mesh.
Definition: polyMesh.C:865
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:81
virtual void assembleSensitivities(autoPtr< designVariables > &designVars)
Assemble sensitivities.
label size() const noexcept
The number of elements in table.
Definition: HashTable.H:342
zeroField Sp(const Foam::zero, const GeometricField< Type, faPatchField, areaMesh > &)
A no-op source.
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
IOList< label > labelIOList
IO for a List of label.
Definition: labelIOList.H:32
void setSize(const label n)
Alias for resize()
Definition: List.H:316
dynamicFvMesh & mesh
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:608
Reading is optional [identical to LAZY_READ].
Vector< scalar > vector
Definition: vector.H:57
void smoothSensitivities()
Smooth sensitivity derivatives based on the computation of the &#39;Sobolev gradient&#39;.
scalar computeRadius(const faMesh &aMesh)
Compute the physical smoothing radius based on the average boundary face &#39;length&#39;.
Calculate the matrix for the laplacian of the field.
#define DebugInfo
Report an information message using Foam::Info.
Calculate the finiteArea matrix for implicit and explicit sources.
static word timeName(const scalar t, const int precision=precision_)
Return a time name for the given scalar time value formatted with the given precision.
Definition: Time.C:714
void normalise()
Normalise the field inplace. See notes in Field.
Type gMax(const FieldField< Field, Type > &f)
defineTypeNameAndDebug(combustionModel, 0)
bool smoothSensitivities_
Smooth sensitivity derivatives based on a surface Laplace solver.
Ostream & printExecutionTime(OSstream &os) const
Print the elapsed ExecutionTime (cpu-time), ClockTime.
Definition: TimeIO.C:604
word suffix_
Append this word to files related to the sensitivities.
const dictionary & dict() const
Return the construction dictionary.
Definition: sensitivity.H:129
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
List< word > wordList
List of word.
Definition: fileName.H:59
static word meshSubDir
The mesh sub-directory name (usually "faMesh")
Definition: faMesh.H:701
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field values.
virtual void write(const word &baseName=word::null)
Write sensitivity fields.
virtual void assembleSensitivities(autoPtr< designVariables > &designVars)
Assemble sensitivities.
label computeFaceDerivativesSize(const bool computeVectorFieldSize)
Compute the size of the return field.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Type gAverage(const FieldField< Field, Type > &f)
scalarField derivatives_
The sensitivity derivative values.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
Nothing to be read.
loopControl iters(runTime, aMesh.solutionDict(), "solution")
const std::string patch
OpenFOAM patch number as a std::string.
bool returnVectorField_
Return the complete vector of sensitivities.
vector span() const
The bounding box span (from minimum to maximum)
Definition: boundBoxI.H:192
messageStream Info
Information stream (stdout output on master, null elsewhere)
const fvBoundaryMesh & boundary() const noexcept
Return reference to boundary mesh.
Definition: fvMesh.H:395
const boundBox & bounds() const noexcept
Return mesh bounding box.
Definition: polyMesh.H:616
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
void read()
Read controls and update solver pointers if necessary.
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...
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
GeometricField< vector, faPatchField, areaMesh > areaVectorField
Definition: areaFieldsFwd.H:81
Calculation of adjoint-based sensitivities at wall points using the E-SI formulation.
const dimensionSet dimArea(sqr(dimLength))
Definition: dimensionSets.H:57
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127