DAObjFuncForce.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2 
3  DAFoam : Discrete Adjoint with OpenFOAM
4  Version : v3
5 
6 \*---------------------------------------------------------------------------*/
7 
8 #include "DAObjFuncForce.H"
9 
10 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
11 
12 namespace Foam
13 {
14 
15 defineTypeNameAndDebug(DAObjFuncForce, 0);
16 addToRunTimeSelectionTable(DAObjFunc, DAObjFuncForce, dictionary);
17 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
18 
20  const fvMesh& mesh,
21  const DAOption& daOption,
22  const DAModel& daModel,
23  const DAIndex& daIndex,
24  const DAResidual& daResidual,
25  const word objFuncName,
26  const word objFuncPart,
27  const dictionary& objFuncDict)
28  : DAObjFunc(
29  mesh,
30  daOption,
31  daModel,
32  daIndex,
33  daResidual,
34  objFuncName,
35  objFuncPart,
36  objFuncDict),
37  daTurb_(daModel.getDATurbulenceModel())
38 {
39 
40  // for computing force, first read in some parameters from objFuncDict_
41  // these parameters are only for force objective
42 
43  // Assign type, this is common for all objectives
44  objFuncDict_.readEntry<word>("type", objFuncType_);
45 
46  // we support three direction modes
47  dirMode_ = objFuncDict_.getWord("directionMode");
48  if (dirMode_ == "fixedDirection")
49  {
50  scalarList dir;
51  objFuncDict_.readEntry<scalarList>("direction", dir);
52  forceDir_[0] = dir[0];
53  forceDir_[1] = dir[1];
54  forceDir_[2] = dir[2];
55  }
56  else if (dirMode_ == "parallelToFlow" || dirMode_ == "normalToFlow")
57  {
58  // initial value for forceDir_. it will be dynamically adjusted later
59  forceDir_ = {1.0, 0.0, 0.0};
60  word alphaName = objFuncDict_.getWord("alphaName");
61  dictionary alphaSubDict = daOption_.getAllOptions().subDict("designVar").subDict(alphaName);
62  wordList patches;
63  alphaSubDict.readEntry<wordList>("patches", patches);
64  inoutRefPatchName_ = patches[0];
65  HashTable<label> axisIndices;
66  axisIndices.set("x", 0);
67  axisIndices.set("y", 1);
68  axisIndices.set("z", 2);
69  word flowAxis = alphaSubDict.getWord("flowAxis");
70  word normalAxis = alphaSubDict.getWord("normalAxis");
71  flowAxisIndex_ = axisIndices[flowAxis];
72  normalAxisIndex_ = axisIndices[normalAxis];
73  }
74  else
75  {
76  FatalErrorIn(" ") << "directionMode for "
77  << objFuncName << " " << objFuncPart << " not valid!"
78  << "Options: fixedDirection, parallelToFlow, normalToFlow."
79  << abort(FatalError);
80  }
81 
82  if (fabs(mag(forceDir_) - 1.0) > 1.0e-8)
83  {
84  FatalErrorIn(" ") << "the magnitude of the direction parameter in "
85  << objFuncName << " " << objFuncPart << " is not 1.0!"
86  << abort(FatalError);
87  }
88 
89  objFuncDict_.readEntry<scalar>("scale", scale_);
90 
91  // setup the connectivity for force, this is needed in Foam::DAJacCondFdW
92  // need to determine the name of pressure because some buoyant OF solver use
93  // p_rgh as pressure
94  word pName = "p";
95  if (mesh_.thisDb().foundObject<volScalarField>("p_rgh"))
96  {
97  pName = "p_rgh";
98  }
99 #ifdef IncompressibleFlow
100  // For incompressible flow, it depends on zero level
101  // of U, nut, and p, and one level of U
102  objFuncConInfo_ = {
103  {"U", "nut", pName}, // level 0
104  {"U"}}; // level 1
105 #endif
106 
107 #ifdef CompressibleFlow
108  // For compressible flow, it depends on zero level
109  // of U, nut, T, and p, and one level of U
110  objFuncConInfo_ = {
111  {"U", "nut", "T", pName}, // level 0
112  {"U"}}; // level 1
113 #endif
114 
115  // now replace nut with the corrected name for the selected turbulence model
116  daModel.correctModelStates(objFuncConInfo_[0]);
117 }
118 
121  const labelList& objFuncFaceSources,
122  const labelList& objFuncCellSources,
123  scalarList& objFuncFaceValues,
124  scalarList& objFuncCellValues,
125  scalar& objFuncValue)
126 {
127  /*
128  Description:
129  Calculate the force which consist of pressure and viscous components.
130  This code is modified based on:
131  src/functionObjects/forcces/forces.C
132 
133  Input:
134  objFuncFaceSources: List of face source (index) for this objective
135 
136  objFuncCellSources: List of cell source (index) for this objective
137 
138  Output:
139  objFuncFaceValues: the discrete value of objective for each face source (index).
140  This will be used for computing df/dw in the adjoint.
141 
142  objFuncCellValues: the discrete value of objective on each cell source (index).
143  This will be used for computing df/dw in the adjoint.
144 
145  objFuncValue: the sum of objective, reduced across all processsors and scaled by "scale"
146  */
147 
148  if (dirMode_ != "fixedDirection")
149  {
150  this->updateForceDir(forceDir_);
151  }
152 
153  // reload the scale, which may be needed for multipoint optimization
154  objFuncDict_.readEntry<scalar>("scale", scale_);
155 
156  // initialize faceValues to zero
157  forAll(objFuncFaceValues, idxI)
158  {
159  objFuncFaceValues[idxI] = 0.0;
160  }
161  // initialize objFunValue
162  objFuncValue = 0.0;
163 
164  const objectRegistry& db = mesh_.thisDb();
165  const volScalarField& p = db.lookupObject<volScalarField>("p");
166 
167  const surfaceVectorField::Boundary& Sfb = mesh_.Sf().boundaryField();
168 
169  tmp<volSymmTensorField> tdevRhoReff = daTurb_.devRhoReff();
170  const volSymmTensorField::Boundary& devRhoReffb = tdevRhoReff().boundaryField();
171 
172  // calculate discrete force for each objFuncFace
173  forAll(objFuncFaceSources, idxI)
174  {
175  const label& objFuncFaceI = objFuncFaceSources[idxI];
176  label bFaceI = objFuncFaceI - daIndex_.nLocalInternalFaces;
177  const label patchI = daIndex_.bFacePatchI[bFaceI];
178  const label faceI = daIndex_.bFaceFaceI[bFaceI];
179 
180  // normal force
181  vector fN(Sfb[patchI][faceI] * p.boundaryField()[patchI][faceI]);
182  // tangential force
183  vector fT(Sfb[patchI][faceI] & devRhoReffb[patchI][faceI]);
184  // project the force to forceDir
185  objFuncFaceValues[idxI] = scale_ * ((fN + fT) & forceDir_);
186 
187  objFuncValue += objFuncFaceValues[idxI];
188  }
189 
190  // need to reduce the sum of force across all processors
191  reduce(objFuncValue, sumOp<scalar>());
192 
193  return;
194 }
195 
196 void DAObjFuncForce::updateForceDir(vector& forceDir)
197 {
198  /*
199  Description:
200  Dynamically adjust the force direction based on the flow direction from
201  far field
202  NOTE: we have special implementation for forward mode AD because
203  we need to progagate the aoa seed to here. The problem of the regular
204  treatment is that we use reduce(flowDir[0], maxOp<scalar>()); to get the
205  flowDir for thoese processors that have no inout patches, this reduce
206  function will lose track of AD seeds for aoa.
207 
208  Output:
209  forceDir: the force direction vector
210  */
211 
213  {
214  // DAUtility::angleOfAttackRadForwardAD is set, this is dF/dAOA forwardMode
215  // derivative, use special treatment here
216 
217  scalar compA = cos(DAUtility::angleOfAttackRadForwardAD);
218  scalar compB = sin(DAUtility::angleOfAttackRadForwardAD);
219 
220  if (dirMode_ == "parallelToFlow")
221  {
222  forceDir[flowAxisIndex_] = compA;
223  forceDir[normalAxisIndex_] = compB;
224  }
225  else if (dirMode_ == "normalToFlow")
226  {
227  forceDir[flowAxisIndex_] = -compB;
228  forceDir[normalAxisIndex_] = compA;
229  }
230  else
231  {
232  FatalErrorIn(" ") << "directionMode not valid!"
233  << "Options: parallelToFlow, normalToFlow."
234  << abort(FatalError);
235  }
236  }
237  else
238  {
239  // DAUtility::angleOfAttackRadForwardAD is not set, usual regular forceDir computation
240 
241  label patchI = mesh_.boundaryMesh().findPatchID(inoutRefPatchName_);
242 
243  volVectorField& U =
244  const_cast<volVectorField&>(mesh_.thisDb().lookupObject<volVectorField>("U"));
245 
246  vector flowDir = {-1e16, -1e16, -1e16};
247 
248  // for decomposed domain, don't set BC if the patch is empty
249  if (mesh_.boundaryMesh()[patchI].size() > 0)
250  {
251  if (U.boundaryField()[patchI].type() == "fixedValue")
252  {
253  flowDir = U.boundaryField()[patchI][0];
254  flowDir = flowDir / mag(flowDir);
255  }
256  else if (U.boundaryField()[patchI].type() == "inletOutlet")
257  {
258  // perturb inletValue
259  mixedFvPatchField<vector>& inletOutletPatch =
260  refCast<mixedFvPatchField<vector>>(U.boundaryFieldRef()[patchI]);
261  flowDir = inletOutletPatch.refValue()[0];
262  flowDir = flowDir / mag(flowDir);
263  }
264  else
265  {
266  FatalErrorIn("") << "boundaryType: " << U.boundaryField()[patchI].type()
267  << " not supported!"
268  << "Available options are: fixedValue, inletOutlet"
269  << abort(FatalError);
270  }
271  }
272 
273  // need to reduce the sum of force across all processors, this is because some of
274  // the processor might not own the inoutRefPatchName_ so their flowDir will be -1e16, but
275  // when calling the following reduce function, they will get the correct flowDir
276  // computed by other processors
277  reduce(flowDir[0], maxOp<scalar>());
278  reduce(flowDir[1], maxOp<scalar>());
279  reduce(flowDir[2], maxOp<scalar>());
280 
281  if (dirMode_ == "parallelToFlow")
282  {
283  forceDir = flowDir;
284  }
285  else if (dirMode_ == "normalToFlow")
286  {
287  forceDir[flowAxisIndex_] = -flowDir[normalAxisIndex_];
288  forceDir[normalAxisIndex_] = flowDir[flowAxisIndex_];
289  }
290  else
291  {
292  FatalErrorIn(" ") << "directionMode not valid!"
293  << "Options: parallelToFlow, normalToFlow."
294  << abort(FatalError);
295  }
296  }
297 }
298 
299 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
300 
301 } // End namespace Foam
302 
303 // ************************************************************************* //
Foam::DAObjFunc::objFuncType_
word objFuncType_
the type of the objective function
Definition: DAObjFunc.H:66
U
U
Definition: pEqnPimpleDyM.H:60
forAll
forAll(pseudoP.boundaryField(), patchI)
Definition: solvePseudoPEqn.H:10
Foam::DAIndex::bFacePatchI
labelList bFacePatchI
Definition: DAIndex.H:110
Foam::DAOption
Definition: DAOption.H:29
Foam::DAObjFunc::daIndex_
const DAIndex & daIndex_
DAIndex object.
Definition: DAObjFunc.H:54
Foam::DAObjFuncForce::flowAxisIndex_
label flowAxisIndex_
flowAxisIndex_ for the alpha design variable with tan(U_normal/U_flow)
Definition: DAObjFuncForce.H:41
Foam::DAObjFuncForce::daTurb_
const DATurbulenceModel & daTurb_
DATurbulenceModel object.
Definition: DAObjFuncForce.H:50
Foam::DAObjFuncForce::DAObjFuncForce
DAObjFuncForce(const fvMesh &mesh, const DAOption &daOption, const DAModel &daModel, const DAIndex &daIndex, const DAResidual &daResidual, const word objFuncName, const word objFuncPart, const dictionary &objFuncDict)
Definition: DAObjFuncForce.C:19
daOption
DAOption daOption(mesh, pyOptions_)
Foam::DAUtility::angleOfAttackRadForwardAD
static scalar angleOfAttackRadForwardAD
angle of attack in radian used in forward mode AD
Definition: DAUtility.H:126
p
volScalarField & p
Definition: createRefsPimple.H:6
Foam::DAOption::getAllOptions
const dictionary & getAllOptions() const
return a reference of allOptions_ dictionary
Definition: DAOption.H:56
Foam::DAObjFuncForce::forceDir_
vector forceDir_
the direction of the force
Definition: DAObjFuncForce.H:32
Foam::DAObjFuncForce::updateForceDir
void updateForceDir(vector &forceDir)
dynamically adjust the force direction
Definition: DAObjFuncForce.C:196
mesh
fvMesh & mesh
Definition: createRefsHeatTransfer.H:4
Foam::DAObjFunc::mesh_
const fvMesh & mesh_
fvMesh
Definition: DAObjFunc.H:45
Foam::DAObjFuncForce::inoutRefPatchName_
word inoutRefPatchName_
the reference patch name from the alpha design variable dict patches[0] from which we compute the flo...
Definition: DAObjFuncForce.H:38
Foam::DAIndex
Definition: DAIndex.H:32
Foam::DAModel
Definition: DAModel.H:59
Foam
Definition: multiFreqScalarFvPatchField.C:144
Foam::DATurbulenceModel::devRhoReff
tmp< volSymmTensorField > devRhoReff() const
dev terms
Definition: DATurbulenceModel.C:306
Foam::DAObjFunc::daOption_
const DAOption & daOption_
DAOption object.
Definition: DAObjFunc.H:48
Foam::DAIndex::nLocalInternalFaces
label nLocalInternalFaces
local internal face size
Definition: DAIndex.H:98
Foam::DAResidual
Definition: DAResidual.H:35
DAObjFuncForce.H
Foam::DAObjFuncForce::dirMode_
word dirMode_
if dynamically adjusting the angle what mode to use
Definition: DAObjFuncForce.H:35
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(DAFvSource, 0)
Foam::addToRunTimeSelectionTable
addToRunTimeSelectionTable(DAFvSource, DAFvSourceActuatorDisk, dictionary)
Foam::DAObjFunc::scale_
scalar scale_
scale of the objective function
Definition: DAObjFunc.H:87
daModel
DAModel daModel(mesh, daOption)
Foam::DAObjFunc::objFuncConInfo_
List< List< word > > objFuncConInfo_
the connectivity information for the objective function
Definition: DAObjFunc.H:93
daIndex
DAIndex daIndex(mesh, daOption, daModel)
Foam::DAObjFunc::objFuncDict_
const dictionary & objFuncDict_
dictionary containing the information for the objective function
Definition: DAObjFunc.H:69
Foam::DAObjFuncForce::normalAxisIndex_
label normalAxisIndex_
normalAxisIndex_ for the alpha design variable with tan(U_normal/U_flow)
Definition: DAObjFuncForce.H:44
Foam::DAIndex::bFaceFaceI
labelList bFaceFaceI
Definition: DAIndex.H:116
Foam::DAObjFuncForce::calcObjFunc
virtual void calcObjFunc(const labelList &objFuncFaceSources, const labelList &objFuncCellSources, scalarList &objFuncFaceValues, scalarList &objFuncCellValues, scalar &objFuncValue)
calculate the value of objective function
Definition: DAObjFuncForce.C:120
Foam::DAObjFunc
Definition: DAObjFunc.H:33