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 
78  autoPtr<faMesh> aMeshPtr = faMesh::TryNew(mesh_);
79 
80  if (aMeshPtr)
81  {
82  Info<< "Loaded the existing faMesh" << nl;
83  }
84  else
85  {
86  // Dictionary used to construct the faMesh
87  dictionary faMeshDefinition;
88 
89  // Check and read system/faMeshDefinition
90  {
91  IOobject io
92  (
93  "faMeshDefinition",
94  mesh_.time().caseSystem(),
95  mesh_,
99  );
100 
101  if (io.typeHeaderOk<IOdictionary>(false))
102  {
103  Info<< "Using system/faMeshDefinition" << nl;
104  faMeshDefinition = IOdictionary(io);
105  }
106  else if (debug)
107  {
108  Info<< "No " << io.name() << " in " << io.path() << nl;
109  }
110  }
111 
112  // Check and read system/finite-area/faMeshDefinition
113  if (faMeshDefinition.empty())
114  {
115  IOobject io
116  (
117  "faMeshDefinition",
119  mesh_,
123  );
124 
125  if (io.typeHeaderOk<IOdictionary>(false))
126  {
127  Info<< "Using system/finite-area/faMeshDefinition" << nl;
128  faMeshDefinition = IOdictionary(io);
129  }
130  else if (debug)
131  {
132  Info<< "No " << io.name() << " in " << io.path() << nl;
133  }
134  }
135 
136  // No specified faMeshDefinition?
137  // - generate faMesh from all patches on which we compute sensitivities
138 
139  if (faMeshDefinition.empty())
140  {
141  wordList polyMeshPatches(sensitivityPatchIDs_.size());
142  label i(0);
143  for (const label patchID : sensitivityPatchIDs_)
144  {
145  polyMeshPatches[i++] = mesh_.boundary()[patchID].name();
146  }
147  faMeshDefinition.add<wordList>("polyMeshPatches", polyMeshPatches);
148  (void)faMeshDefinition.subDictOrAdd("boundary");
149 
150  // TBD: Place all edges into the "defaultPatch" ?
151  // faMeshDefinition.subDictOrAdd("defaultPatch")
152  // .add("name", "undefined");
153 
154  Info<< "Create faMeshDefinition from sensitivity patches"
155  << nl << nl;
156 
157  faMeshDefinition.writeEntry("faMeshDefinition", Info);
158  }
159 
160  // Construct faMesh from faMeshDefinition
161  aMeshPtr.reset(new faMesh(mesh_, faMeshDefinition));
162  }
163  faMesh& aMesh = *aMeshPtr;
164 
165 
166  // Physical radius of the smoothing, provided either directly or computed
167  // based on the average 'length' of boundary faces
168  const scalar Rphysical
169  (dict().getOrDefault<scalar>("radius", computeRadius(aMesh)));
170  DebugInfo
171  << "Physical radius of the sensitivity smoothing "
172  << Rphysical << nl << endl;
173 
174  // Radius used as the diffusivity in the Helmholtz filter, computed as a
175  // function of the physical radius
176  const dimensionedScalar RpdeSqr
177  (
178  "RpdeSqr", dimArea, sqr(Rphysical/(2.*::sqrt(3.)))
179  );
180 
182 
183  // Mapping engine
184  volSurfaceMapping vsm(aMesh);
185 
186  // Source term in faMatrix needs to be an areaField
187  areaVectorField sens
188  (
189  aMesh.newIOobject("sens"),
190  aMesh,
193  );
194 
195  // Copy sensitivities to area field
196  sens.primitiveFieldRef() =
197  vsm.mapToSurface<vector>(wallFaceSensVecPtr_());
198 
199  // Initialisation of the smoothed sensitivities field based on the original
200  // sensitivities
201  areaVectorField smoothedSens("smoothedSens", sens);
202  for (label iter = 0; iter < iters; ++iter)
203  {
204  Info<< "Sensitivity smoothing iteration " << iter << endl;
205 
206  faVectorMatrix smoothEqn
207  (
208  fam::Sp(one, smoothedSens)
209  - fam::laplacian(RpdeSqr, smoothedSens)
210  ==
211  sens
212  );
213 
214  smoothEqn.relax();
215 
216  const scalar residual(mag(smoothEqn.solve().initialResidual()));
217 
218  DebugInfo
219  << "Max smoothSens " << gMax(mag(smoothedSens)()) << endl;
220 
221  // Print execution time
223 
224  // Check convergence
225  if (residual < tolerance)
226  {
227  Info<< "\n***Reached smoothing equation convergence limit, "
228  "iteration " << iter << "***\n\n";
229  break;
230  }
231  }
232 
233  // Transfer smooth sensitivity field to wallFaceSensVecPtr_ for defining
234  // derivatives_
235  vsm.mapToVolume(smoothedSens, wallFaceSensVecPtr_());
236 
237  // Write normal, regularised sensitivities to file
238  volScalarField volSmoothedSens
239  (
240  mesh_.newIOobject("smoothedSurfaceSens" + suffix_),
241  mesh_,
243  );
244  areaVectorField nf(aMesh.faceAreaNormals());
245  nf.normalise();
246  areaScalarField smoothedSensNormal(smoothedSens & nf);
247  vsm.mapToVolume(smoothedSensNormal, volSmoothedSens.boundaryFieldRef());
248  volSmoothedSens.write();
249 }
250 
251 
252 scalar sensitivitySurface::computeRadius(const faMesh& aMesh)
253 {
254  scalar averageArea(gAverage(aMesh.S().field()));
255  const Vector<label>& geometricD = mesh_.geometricD();
256  const boundBox& bounds = mesh_.bounds();
257  forAll(geometricD, iDir)
258  {
259  if (geometricD[iDir] == -1)
260  {
261  averageArea /= bounds.span()[iDir];
262  }
263  }
264  scalar mult = dict().getOrDefault<scalar>("meanRadiusMultiplier", 10);
265 
266  return mult*pow(averageArea, scalar(1)/scalar(mesh_.nGeometricD() - 1));
267 }
268 
269 
270 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
271 
272 sensitivitySurface::sensitivitySurface
273 (
274  const fvMesh& mesh,
275  const dictionary& dict,
277 )
278 :
280  smoothSensitivities_(dict.getOrDefault("smoothSensitivities", false)),
281  returnVectorField_
282  (dict.getOrDefault<bool>("returnVectorField", true))
283  //finalResultIncludesArea_
284  // (dict.getOrDefault<bool>("finalResultIncludesArea", false))
285 {
286  // Allocate boundary field pointers
287  wallFaceSensVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
288  wallFaceSensNormalPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
289  wallFaceSensNormalVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
292 }
293 
294 
295 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
296 
298 {
300  smoothSensitivities_ = dict().getOrDefault("smoothSensitivities", false);
302  dict().getOrDefault<bool>("returnVectorField", true);
303  //finalResultIncludesArea_ =
304  // dict().getOrDefault<bool>("finalResultIncludesArea", false);
305 }
306 
307 
309 (
310  autoPtr<designVariables>& designVars
311 )
312 {
313  // Compute point-based sensitivities
315 
316  // Transfer point sensitivities to point field
317  vectorField pointSens(mesh_.nPoints(), Zero);
318  for (const label patchI : sensitivityPatchIDs_)
319  {
320  const polyPatch& pp = mesh_.boundaryMesh()[patchI];
321  const labelList& meshPoints = pp.meshPoints();
322  forAll(meshPoints, ppi)
323  {
324  pointSens[meshPoints[ppi]] = wallPointSensVecPtr_()[patchI][ppi];
325  }
326  }
327 
328  // vectorField face-sensitivities
329  vectorField faceVecSens(computeFaceDerivativesSize(false), Zero);
330 
331  // Map sensitivities from points to faces
332  volPointInterpolationAdjoint interpolation(mesh_);
333  interpolation.interpolateSensitivitiesField
334  (pointSens, faceVecSens, sensitivityPatchIDs_);
335 
336  // Transfer non-regularised sensitivities to wallFaceSens* fields and write
337  label nPassedFaces(0);
338  for (const label patchI : sensitivityPatchIDs_)
339  {
340  const fvPatch& patch = mesh_.boundary()[patchI];
341  tmp<vectorField> nf = patch.nf();
342  wallFaceSensVecPtr_()[patchI] =
343  SubField<vector>(faceVecSens, patch.size(), nPassedFaces)
344  /patch.magSf();
345  wallFaceSensNormalPtr_()[patchI] = wallFaceSensVecPtr_()[patchI] & nf();
346  wallFaceSensNormalVecPtr_()[patchI] =
347  wallFaceSensNormalPtr_()[patchI]*nf;
348  nPassedFaces += patch.size();
349  }
350  write();
351 
352  // Regularise sensitivities if necessary
354  {
356  }
357 
358  // Make sure we have the correct sensitivities size
360  nPassedFaces = 0;
361  for (const label patchI : sensitivityPatchIDs_)
362  {
363  const fvPatch& patch = mesh_.boundary()[patchI];
364  const vectorField nf(patch.nf());
365  if (returnVectorField_)
366  {
367  const Vector<label>& sd = mesh_.solutionD();
368  forAll(patch, fI)
369  {
370  const label gfI = nPassedFaces + fI;
371  const vector& fSens = wallFaceSensVecPtr_()[patchI][fI];
372  derivatives_[3*gfI ] = scalar(sd[0] == -1 ? 0 : fSens.x());
373  derivatives_[3*gfI + 1] = scalar(sd[1] == -1 ? 0 : fSens.y());
374  derivatives_[3*gfI + 2] = scalar(sd[2] == -1 ? 0 : fSens.z());
375  }
376  }
377  else
378  {
379  forAll(patch, fI)
380  {
381  derivatives_[nPassedFaces + fI]
382  = wallFaceSensVecPtr_()[patchI][fI] & nf[fI];
383  }
384  }
385  nPassedFaces += patch.size();
386  }
387 }
388 
389 
390 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
391 
392 } // End namespace Foam
393 
394 // ************************************************************************* //
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:133
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)
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:1133
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.
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)
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:72
virtual void assembleSensitivities(autoPtr< designVariables > &designVars)
Assemble sensitivities.
label size() const noexcept
The number of elements in table.
Definition: HashTable.H:358
zeroField Sp(const Foam::zero, const GeometricField< Type, faPatchField, areaMesh > &)
A no-op source.
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
void setSize(const label n)
Alias for resize()
Definition: List.H:320
dynamicFvMesh & mesh
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:609
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.
int debug
Static debugging option.
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:607
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
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.
static autoPtr< faMesh > TryNew(const word &meshName, const polyMesh &pMesh)
Read construction from polyMesh if all files are available.
Definition: faMeshNew.C:188
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
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
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition: zero.H:57
const boundBox & bounds() const noexcept
Return mesh bounding box.
Definition: polyMesh.H:617
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...
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
IOobject newIOobject(const word &name, IOobjectOption ioOpt) const
Create an IOobject at the current time instance (timeName) with the specified options.
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
static const word & prefix() noexcept
The prefix to the parent registry name: finite-area.
Definition: faMesh.C:66
GeometricField< vector, faPatchField, areaMesh > areaVectorField
Definition: areaFieldsFwd.H:76
Do not request registration (bool: false)
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)
A class representing the concept of 1 (one) that can be used to avoid manipulating objects known to b...
Definition: one.H:56
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127