DASpalartAllmarasFv3.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2 
3  DAFoam : Discrete Adjoint with OpenFOAM
4  Version : v4
5 
6  This file is modified from OpenFOAM's source code
7  src/TurbulenceModels/turbulenceModels/RAS/SpalartAllmaras/SpalartAllmaras.C
8 
9  OpenFOAM: The Open Source CFD Toolbox
10 
11  Copyright (C): 2011-2016 OpenFOAM Foundation
12 
13  OpenFOAM License:
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 "DASpalartAllmarasFv3.H"
31 
32 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36 
37 defineTypeNameAndDebug(DASpalartAllmarasFv3, 0);
38 addToRunTimeSelectionTable(DATurbulenceModel, DASpalartAllmarasFv3, dictionary);
39 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
40 
42  const word modelType,
43  const fvMesh& mesh,
44  const DAOption& daOption)
45  : DATurbulenceModel(modelType, mesh, daOption),
46  // SA parameters
47  sigmaNut_(dimensioned<scalar>::lookupOrAddToDict(
48  "sigmaNut",
49  this->coeffDict_,
50  0.66666)),
51  kappa_(dimensioned<scalar>::lookupOrAddToDict(
52  "kappa",
53  this->coeffDict_,
54  0.41)),
55 
56  Cb1_(dimensioned<scalar>::lookupOrAddToDict(
57  "Cb1",
58  this->coeffDict_,
59  0.1355)),
60  Cb2_(dimensioned<scalar>::lookupOrAddToDict(
61  "Cb2",
62  this->coeffDict_,
63  0.622)),
64  Cw1_(Cb1_ / sqr(kappa_) + (1.0 + Cb2_) / sigmaNut_),
65  Cw2_(dimensioned<scalar>::lookupOrAddToDict(
66  "Cw2",
67  this->coeffDict_,
68  0.3)),
69  Cw3_(dimensioned<scalar>::lookupOrAddToDict(
70  "Cw3",
71  this->coeffDict_,
72  2.0)),
73  Cv1_(dimensioned<scalar>::lookupOrAddToDict(
74  "Cv1",
75  this->coeffDict_,
76  7.1)),
77  Cv2_(dimensioned<scalar>::lookupOrAddToDict(
78  "Cv2",
79  this->coeffDict_,
80  5.0)),
81  // Augmented variables
82  nuTilda_(const_cast<volScalarField&>(
83  mesh.thisDb().lookupObject<volScalarField>("nuTilda"))),
84  nuTildaRes_(
85  IOobject(
86  "nuTildaRes",
87  mesh.time().timeName(),
88  mesh,
89  IOobject::NO_READ,
90  IOobject::NO_WRITE),
91  mesh,
92  dimensionedScalar("nuTildaRes", dimensionSet(0, 0, 0, 0, 0, 0, 0), 0.0),
93  zeroGradientFvPatchField<scalar>::typeName),
94  // pseudoNuTilda_ and pseudoNuTildaEqn_ for solving adjoint equation
95  pseudoNuTilda_(
96  IOobject(
97  "pseudoNuTilda",
98  mesh.time().timeName(),
99  mesh,
100  IOobject::NO_READ,
101  IOobject::NO_WRITE),
102  nuTilda_),
103  pseudoNuTildaEqn_(fvm::div(phi_, pseudoNuTilda_, "div(phi,nuTilda)")),
104  y_(mesh.thisDb().lookupObject<volScalarField>("yWall")),
105  betaFINuTilda_(
106  IOobject(
107  "betaFINuTilda",
108  mesh.time().timeName(),
109  mesh,
110  IOobject::READ_IF_PRESENT,
111  IOobject::AUTO_WRITE),
112  mesh,
113  dimensionedScalar("betaFINuTilda", dimensionSet(0, 0, 0, 0, 0, 0, 0), 1.0),
114  "zeroGradient")
115 {
116 
117  // get fvSolution and fvSchemes info for fixed-point adjoint
118  const fvSolution& myFvSolution = mesh.thisDb().lookupObject<fvSolution>("fvSolution");
119  solverDictNuTilda_ = myFvSolution.subDict("solvers").subDict("nuTilda");
120  if (myFvSolution.found("relaxationFactors"))
121  {
122  if (myFvSolution.subDict("relaxationFactors").found("equations"))
123  {
124  if (myFvSolution.subDict("relaxationFactors").subDict("equations").found("nuTilda"))
125  {
126  relaxNuTildaEqn_ = myFvSolution.subDict("relaxationFactors").subDict("equations").getScalar("nuTilda");
127  }
128  }
129  }
130 
131  // we need to reset the nuTildaRes's dimension based on the model type
132  if (turbModelType_ == "incompressible")
133  {
134  nuTildaRes_.dimensions().reset(dimensionSet(0, 2, -2, 0, 0, 0, 0));
135  }
136 
137  if (turbModelType_ == "compressible")
138  {
139  nuTildaRes_.dimensions().reset(dimensionSet(1, -1, -2, 0, 0, 0, 0));
140  }
141 }
142 
143 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
144 
145 // SA member functions. these functions are copied from
146 tmp<volScalarField> DASpalartAllmarasFv3::chi() const
147 {
148  return nuTilda_ / this->nu();
149 }
150 
151 tmp<volScalarField> DASpalartAllmarasFv3::fv1(
152  const volScalarField& chi) const
153 {
154  const volScalarField chi3(pow3(chi));
155  return chi3 / (chi3 + pow3(Cv1_));
156 }
157 
158 tmp<volScalarField> DASpalartAllmarasFv3::fv2(
159  const volScalarField& chi,
160  const volScalarField& fv1) const
161 {
162  return 1.0 / pow3(scalar(1) + chi / Cv2_);
163 }
164 
165 tmp<volScalarField> DASpalartAllmarasFv3::fv3(
166  const volScalarField& chi,
167  const volScalarField& fv1) const
168 {
169 
170  const volScalarField chiByCv2((1 / Cv2_) * chi);
171 
172  return (scalar(1) + chi * fv1)
173  * (1 / Cv2_)
174  * (3 * (scalar(1) + chiByCv2) + sqr(chiByCv2))
175  / pow3(scalar(1) + chiByCv2);
176 }
177 
178 tmp<volScalarField> DASpalartAllmarasFv3::fw(
179  const volScalarField& Stilda) const
180 {
181  volScalarField r(
182  min(
183  nuTilda_
184  / (max(
185  Stilda,
186  dimensionedScalar("SMALL", Stilda.dimensions(), SMALL))
187  * sqr(kappa_ * y_)),
188  scalar(10.0)));
189  r.boundaryFieldRef() == 0.0;
190 
191  const volScalarField g(r + Cw2_ * (pow6(r) - r));
192 
193  return g * pow((1.0 + pow6(Cw3_)) / (pow6(g) + pow6(Cw3_)), 1.0 / 6.0);
194 }
195 
196 tmp<volScalarField> DASpalartAllmarasFv3::DnuTildaEff() const
197 {
198  return tmp<volScalarField>(
199  new volScalarField("DnuTildaEff", (nuTilda_ + this->nu()) / sigmaNut_));
200 }
201 
202 // Augmented functions
203 void DASpalartAllmarasFv3::correctModelStates(wordList& modelStates) const
204 {
205  /*
206  Description:
207  Update the name in modelStates based on the selected physical model at runtime
208 
209  Example:
210  In DAStateInfo, if the modelStates reads:
211 
212  modelStates = {"nut"}
213 
214  then for the SA model, calling correctModelStates(modelStates) will give:
215 
216  modelStates={"nuTilda"}
217 
218  while calling correctModelStates(modelStates) for the SST model will give
219 
220  modelStates={"k","omega"}
221 
222  We don't udpate the names for the radiation model becasue users are
223  supposed to set modelStates={"G"}
224  */
225 
226  // replace nut with nuTilda
227  forAll(modelStates, idxI)
228  {
229  word stateName = modelStates[idxI];
230  if (stateName == "nut")
231  {
232  modelStates[idxI] = "nuTilda";
233  }
234  }
235 }
236 
238 {
239  /*
240  Description:
241  Update nut based on other turbulence variables and update the BCs
242  Also update alphat if is present
243  */
244 
245  const volScalarField chi(this->chi());
246  const volScalarField fv1(this->fv1(chi));
247  nut_ = nuTilda_ * fv1;
248 
249  nut_.correctBoundaryConditions();
250 
251  // this is basically BasicTurbulenceModel::correctNut();
252  this->correctAlphat();
253 
254  return;
255 }
256 
258 {
259  /*
260  Description:
261  Update turbulence variable boundary values
262  */
263 
264  // correct the BCs for the perturbed fields
265  nuTilda_.correctBoundaryConditions();
266 }
267 
269 {
270  /*
271  Description:
272  Update nut based on nuTilda. Note: we need to update nut and its BC since we
273  may have perturbed other turbulence vars that affect the nut values
274  */
275 
276  this->correctNut();
277 }
278 
279 void DASpalartAllmarasFv3::correctStateResidualModelCon(List<List<word>>& stateCon) const
280 {
281  /*
282  Description:
283  Update the original variable connectivity for the adjoint state
284  residuals in stateCon. Basically, we modify/add state variables based on the
285  original model variables defined in stateCon.
286 
287  Input:
288 
289  stateResCon: the connectivity levels for a state residual, defined in Foam::DAJacCon
290 
291  Example:
292  If stateCon reads:
293  stateCon=
294  {
295  {"U", "p", "nut"},
296  {"p"}
297  }
298 
299  For the SA turbulence model, calling this function for will get a new stateCon
300  stateCon=
301  {
302  {"U", "p", "nuTilda"},
303  {"p"}
304  }
305 
306  For the SST turbulence model, calling this function will give
307  stateCon=
308  {
309  {"U", "p", "k", "omega"},
310  {"p", "U"}
311  }
312  ***NOTE***: we add a extra level of U connectivity because nut is
313  related to grad(U), k, and omega in SST!
314  */
315 
316  forAll(stateCon, idxI)
317  {
318  forAll(stateCon[idxI], idxJ)
319  {
320  word conStateName = stateCon[idxI][idxJ];
321  if (conStateName == "nut")
322  {
323  stateCon[idxI][idxJ] = "nuTilda";
324  }
325  }
326  }
327 }
328 
329 void DASpalartAllmarasFv3::addModelResidualCon(HashTable<List<List<word>>>& allCon) const
330 {
331  /*
332  Description:
333  Add the connectivity levels for all physical model residuals to allCon
334 
335  Input:
336  allCon: the connectivity levels for all state residual, defined in DAJacCon
337 
338  Example:
339  If stateCon reads:
340  allCon=
341  {
342  "URes":
343  {
344  {"U", "p", "nut"},
345  {"p"}
346  }
347  }
348 
349  For the SA turbulence model, calling this function for will get a new stateCon,
350  something like this:
351  allCon=
352  {
353  "URes":
354  {
355  {"U", "p", "nuTilda"},
356  {"p"}
357  },
358  "nuTildaRes":
359  {
360  {"U", "phi", "nuTilda"},
361  {"U"}
362  }
363  }
364 
365  */
366 
367  word pName;
368 
369  if (mesh_.thisDb().foundObject<volScalarField>("p"))
370  {
371  pName = "p";
372  }
373  else if (mesh_.thisDb().foundObject<volScalarField>("p_rgh"))
374  {
375  pName = "p_rgh";
376  }
377  else
378  {
379  FatalErrorIn(
380  "Neither p nor p_rgh was found in mesh.thisDb()!"
381  "addModelResidualCon failed to setup turbulence residuals!")
382  << exit(FatalError);
383  }
384 
385  // NOTE: for compressible flow, it depends on rho so we need to add T and p
386  if (turbModelType_ == "incompressible")
387  {
388  allCon.set(
389  "nuTildaRes",
390  {
391  {"U", "nuTilda", "phi"}, // lv0
392  {"U", "nuTilda"}, // lv1
393  {"nuTilda"} // lv2
394  });
395  }
396  else if (turbModelType_ == "compressible")
397  {
398  allCon.set(
399  "nuTildaRes",
400  {
401  {"U", "T", pName, "nuTilda", "phi"}, // lv0
402  {"U", "T", pName, "nuTilda"}, // lv1
403  {"T", pName, "nuTilda"} // lv2
404  });
405  }
406 }
407 
408 void DASpalartAllmarasFv3::correct(label printToScreen)
409 {
410  /*
411  Descroption:
412  Solve the residual equations and update the state. This function will be called
413  by the DASolver. It is needed because we want to control the output frequency
414  of the residual convergence every 100 steps. If using the correct from turbulence
415  it will output residual every step which will be too much of information.
416  */
417 
418  // We set the flag solveTurbState_ to 1 such that in the calcResiduals function
419  // we will solve and update nuTilda
420  solveTurbState_ = 1;
421  dictionary dummyOptions;
422  dummyOptions.set("printToScreen", printToScreen);
423  this->calcResiduals(dummyOptions);
424  // after it, we reset solveTurbState_ = 0 such that calcResiduals will not
425  // update nuTilda when calling from the adjoint class, i.e., solveAdjoint from DASolver.
426  solveTurbState_ = 0;
427 }
428 
429 void DASpalartAllmarasFv3::calcResiduals(const dictionary& options)
430 {
431  /*
432  Descroption:
433  If solveTurbState_ == 1, this function solve and update nuTilda, and
434  is the same as calling turbulence.correct(). If solveTurbState_ == 0,
435  this function compute residuals for turbulence variables, e.g., nuTildaRes_
436 
437  Input:
438  options.isPC: 1 means computing residuals for preconditioner matrix.
439  This essentially use the first order scheme for div(phi,nuTilda)
440 
441  p_, U_, phi_, etc: State variables in OpenFOAM
442 
443  Output:
444  nuTildaRes_: If solveTurbState_ == 0, update the residual field variable
445 
446  nuTilda_: If solveTurbState_ == 1, update nuTilda
447  */
448 
449  // Copy and modify based on the "correct" function
450 
451  word divNuTildaScheme = "div(phi,nuTilda)";
452 
453  label isPC = 0;
454 
455  label printToScreen = options.lookupOrDefault("printToScreen", 0);
456 
457  if (!solveTurbState_)
458  {
459  isPC = options.getLabel("isPC");
460 
461  if (isPC)
462  {
463  divNuTildaScheme = "div(pc)";
464  }
465  }
466 
467  const volScalarField chi(this->chi());
468  const volScalarField fv1(this->fv1(chi));
469 
470  const volScalarField Stilda(
471  this->fv3(chi, fv1) * ::sqrt(2.0) * mag(skew(fvc::grad(U_)))
472  + this->fv2(chi, fv1) * nuTilda_ / sqr(kappa_ * y_));
473 
474  volScalarField rho = this->rho();
475 
476  tmp<fvScalarMatrix> nuTildaEqn(
477  fvm::ddt(phase_, rho, nuTilda_)
478  + fvm::div(phaseRhoPhi_, nuTilda_, divNuTildaScheme)
479  - fvm::laplacian(phase_ * rho * DnuTildaEff(), nuTilda_)
480  - Cb2_ / sigmaNut_ * phase_ * rho * magSqr(fvc::grad(nuTilda_))
481  == Cb1_ * phase_ * rho * Stilda * nuTilda_ * betaFINuTilda_
482  - fvm::Sp(Cw1_ * phase_ * rho * fw(Stilda) * nuTilda_ / sqr(y_), nuTilda_));
483 
484  nuTildaEqn.ref().relax();
485 
486  if (solveTurbState_)
487  {
488  // get the solver performance info such as initial
489  // and final residuals
490  SolverPerformance<scalar> solverNuTilda = solve(nuTildaEqn);
491  DAUtility::primalResidualControl(solverNuTilda, printToScreen, "nuTilda", daGlobalVar_.primalMaxRes);
492 
493  DAUtility::boundVar(allOptions_, nuTilda_, printToScreen);
494  nuTilda_.correctBoundaryConditions();
495 
496  // ***************** NOTE*****************
497  // In the original SA, it is correctNut(fv1) and fv1 is not
498  // updated based on the latest nuTilda. We use correctNut which
499  // recompute fv1 with the latest nuTilda
500  this->correctNut();
501  }
502  else
503  {
504  // calculate residuals
505  nuTildaRes_ = nuTildaEqn.ref() & nuTilda_;
506  // need to normalize residuals
507  normalizeResiduals(nuTildaRes);
508  }
509 
510  return;
511 }
512 
514  const volScalarField& mySource,
515  volScalarField& pseudoNuTilda)
516 {
517  /*
518  Description:
519  Inverse transpose product, M_nuTilda^(-T)
520  Based on inverseProduct_nuTildaEqn from simpleFoamSAPrimal, but swaping upper() and lower()
521  We won't ADR this function, so we can treat most of the arguments as const
522  */
523 
524  // Make sure pseudoNuTilda = nuTilda;
525  //if (pseudoNuTildaEqnInitialized_ == 0)
526  //{
527  /*
528  pseudoNuTilda_ = nuTilda_;
529 
530  const volScalarField chi(this->chi());
531  const volScalarField fv1(this->fv1(chi));
532 
533  // Get myStilda
534  const volScalarField Stilda(
535  this->fv3(chi, fv1) * ::sqrt(2.0) * mag(skew(fvc::grad(U_)))
536  + this->fv2(chi, fv1) * nuTilda_ / sqr(kappa_ * y_));
537 
538  // Get the pseudoNuTildaEqn,
539  // the most important thing here is to make sure the l.h.s. mathces that of nuTildaEqn.
540  // Some explicit terms that only contributes to the r.h.s. are diabled
541  pseudoNuTildaEqn_ =
542  //fvm::ddt(pseudoNuTilda_)
543  fvm::div(phi_, pseudoNuTilda_, "div(phi,nuTilda)")
544  - fvm::laplacian(DnuTildaEff(), pseudoNuTilda_)
545  + fvm::Sp(Cw1_ * fw(Stilda) * pseudoNuTilda_ / sqr(y_), pseudoNuTilda_);
546  pseudoNuTildaEqn_.relax(relaxNuTildaEqn_);
547 
548  // Swap upper() and lower()
549  List<scalar> temp = pseudoNuTildaEqn_.upper();
550  pseudoNuTildaEqn_.upper() = pseudoNuTildaEqn_.lower();
551  pseudoNuTildaEqn_.lower() = temp;
552 
553  // mark it as initialized
554  // pseudoNuTildaEqnInitialized_ = 1;
555  //}
556 
557  // Overwrite the r.h.s.
558  pseudoNuTildaEqn_.source() = mySource.primitiveField();
559 
560  // Make sure that boundary contribution to source is zero,
561  // Alternatively, we can deduct source by boundary contribution, so that it would cancel out during solve.
562  forAll(pseudoNuTilda_.boundaryField(), patchI)
563  {
564  const fvPatch& pp = pseudoNuTilda_.boundaryField()[patchI].patch();
565  forAll(pp, faceI)
566  {
567  label cellI = pp.faceCells()[faceI];
568  pseudoNuTildaEqn_.source()[cellI] -= pseudoNuTildaEqn_.boundaryCoeffs()[patchI][faceI];
569  }
570  }
571 
572  // Before solve, force xxEqn.psi to be solved into all zero
573  // This ensures the zero (internal) initial guess
574  forAll(pseudoNuTilda_.primitiveFieldRef(), cellI)
575  {
576  pseudoNuTilda_.primitiveFieldRef()[cellI] = 0;
577  }
578  // Solve using the zero (internal) initial guess
579  pseudoNuTildaEqn_.solve(solverDictNuTilda_);
580 
581  forAll(pseudoNuTilda, cellI)
582  {
583  pseudoNuTilda[cellI] = pseudoNuTilda_[cellI];
584  }
585 */
586 }
587 
589 {
590  /*
591  Description:
592  construct the pseudo nuTildaEqn,
593  which is nuTildaEqn with the lhs upper and lower arrays swapped,
594  we also don't care about the rhs of pseudo nuTildaEqn.
595  */
596 
597  // Make sure pseudoNuTilda is indeed identical to nuTilda
599  pseudoNuTilda_.correctBoundaryConditions();
600 
601  const volScalarField chi(this->chi());
602  const volScalarField fv1(this->fv1(chi));
603 
604  // Get myStilda
605  const volScalarField Stilda(
606  this->fv3(chi, fv1) * ::sqrt(2.0) * mag(skew(fvc::grad(U_)))
607  + this->fv2(chi, fv1) * nuTilda_ / sqr(kappa_ * y_));
608 
609  // Get the pseudoNuTildaEqn,
610  // the most important thing here is to make sure the l.h.s. mathces that of nuTildaEqn.
611  // Some explicit terms that only contributes to the r.h.s. are diabled
613  //fvm::ddt(pseudoNuTilda_)
614  fvm::div(phi_, pseudoNuTilda_, "div(phi,nuTilda)")
615  - fvm::laplacian(DnuTildaEff(), pseudoNuTilda_)
616  + fvm::Sp(Cw1_ * fw(Stilda) * pseudoNuTilda_ / sqr(y_), pseudoNuTilda_);
618 
619  // Swap upper() and lower()
620  // We will use the swap function once it's being moved to the DAUtility
621  List<scalar> temp = pseudoNuTildaEqn_.upper();
622  pseudoNuTildaEqn_.upper() = pseudoNuTildaEqn_.lower();
623  pseudoNuTildaEqn_.lower() = temp;
624 }
625 
626 void DASpalartAllmarasFv3::rhsSolvePseudoNuTildaEqn(const volScalarField& nuTildaSource)
627 {
628  /*
629  Description:
630  solve the pseudo nuTildaEqn with a overwritten rhs
631  */
632 
633  // Overwrite the r.h.s.
634  pseudoNuTildaEqn_.source() = nuTildaSource.primitiveField();
635 
636  // Make sure that boundary contribution to source is zero,
637  // Alternatively, we can deduct source by boundary contribution, so that it would cancel out during solve.
638  forAll(pseudoNuTilda_.boundaryField(), patchI)
639  {
640  const fvPatch& pp = pseudoNuTilda_.boundaryField()[patchI].patch();
641  forAll(pp, faceI)
642  {
643  label cellI = pp.faceCells()[faceI];
644  pseudoNuTildaEqn_.source()[cellI] -= pseudoNuTildaEqn_.boundaryCoeffs()[patchI][faceI];
645  }
646  }
647 
648  // Before solve, force xxEqn.psi to be solved into all zero
649  // This ensures the zero (internal) initial guess
650  forAll(pseudoNuTilda_.primitiveFieldRef(), cellI)
651  {
652  pseudoNuTilda_.primitiveFieldRef()[cellI] = 0;
653  }
654  // Solve using the zero (internal) initial guess
656 }
657 
658 void DASpalartAllmarasFv3::calcLduResidualTurb(volScalarField& nuTildaRes)
659 {
660  /*
661  Description:
662  calculate the turbulence residual using LDU matrix
663  */
664 
665  const volScalarField chi(this->chi());
666  const volScalarField fv1(this->fv1(chi));
667 
668  // Get myStilda
669  const volScalarField Stilda(
670  this->fv3(chi, fv1) * ::sqrt(2.0) * mag(skew(fvc::grad(U_)))
671  + this->fv2(chi, fv1) * nuTilda_ / sqr(kappa_ * y_));
672 
673  // Construct nuTildaEqn using our own SA implementation
674  fvScalarMatrix nuTildaEqn(
675  fvm::div(phi_, nuTilda_, "div(phi,nuTilda)")
676  - fvm::laplacian(DnuTildaEff(), nuTilda_)
677  - Cb2_ / sigmaNut_ * magSqr(fvc::grad(nuTilda_))
678  == Cb1_ * Stilda * nuTilda_ * betaFINuTilda_
679  - fvm::Sp(Cw1_ * fw(Stilda) * nuTilda_ / sqr(y_), nuTilda_));
680 
681  List<scalar>& nuTildaSource = nuTildaEqn.source();
682  List<scalar>& nuTildaDiag = nuTildaEqn.diag();
683 
684  // Initiate nuTildaRes, with no boundary contribution
685  for (label i = 0; i < nuTilda_.size(); i++)
686  {
687  nuTildaRes[i] = nuTildaDiag[i] * nuTilda_[i] - nuTildaSource[i];
688  }
689  nuTildaRes.primitiveFieldRef() -= nuTildaEqn.lduMatrix::H(nuTilda_);
690 
691  // Boundary correction
692  forAll(nuTilda_.boundaryField(), patchI)
693  {
694  const fvPatch& pp = nuTilda_.boundaryField()[patchI].patch();
695  forAll(pp, faceI)
696  {
697  // Both ways of getting cellI work
698  // Below is the previous way of getting the address
699  label cellI = pp.faceCells()[faceI];
700  // Below is using lduAddr().patchAddr(patchi)
701  //label cellI = nuTildaEqn.lduAddr().patchAddr(patchI)[faceI];
702  //myDiag[cellI] += TEqn.internalCoeffs()[patchI][faceI];
703  nuTildaRes[cellI] += nuTildaEqn.internalCoeffs()[patchI][faceI] * nuTilda_[cellI];
704  nuTildaRes[cellI] -= nuTildaEqn.boundaryCoeffs()[patchI][faceI];
705  }
706  }
707 
708  // Below is not necessary, but it doesn't hurt
709  nuTildaRes.correctBoundaryConditions();
710 }
711 
713  const word varName,
714  scalarField& diag,
715  scalarField& upper,
716  scalarField& lower)
717 {
718  /*
719  Description:
720  return the diag(), upper(), and lower() scalarFields from the turbulence model's fvMatrix
721  this will be use to compute the preconditioner matrix
722  */
723 
724  if (varName != "nuTilda")
725  {
726  FatalErrorIn(
727  "varName not valid. It has to be nuTilda")
728  << exit(FatalError);
729  }
730 
731  const volScalarField chi(this->chi());
732  const volScalarField fv1(this->fv1(chi));
733 
734  const volScalarField Stilda(
735  this->fv3(chi, fv1) * ::sqrt(2.0) * mag(skew(fvc::grad(U_)))
736  + this->fv2(chi, fv1) * nuTilda_ / sqr(kappa_ * y_));
737 
738  volScalarField rho = this->rho();
739 
740  fvScalarMatrix nuTildaEqn(
741  fvm::ddt(phase_, rho, nuTilda_)
742  + fvm::div(phaseRhoPhi_, nuTilda_, "div(pc)")
743  - fvm::laplacian(phase_ * rho * DnuTildaEff(), nuTilda_)
744  - Cb2_ / sigmaNut_ * phase_ * rho * magSqr(fvc::grad(nuTilda_))
745  == Cb1_ * phase_ * rho * Stilda * nuTilda_ * betaFINuTilda_
746  - fvm::Sp(Cw1_ * phase_ * rho * fw(Stilda) * nuTilda_ / sqr(y_), nuTilda_));
747 
748  nuTildaEqn.relax();
749 
750  diag = nuTildaEqn.D();
751  upper = nuTildaEqn.upper();
752  lower = nuTildaEqn.lower();
753 }
754 
755 void DASpalartAllmarasFv3::getTurbProdOverDestruct(volScalarField& PoD) const
756 {
757  /*
758  Description:
759  Return the value of the production over destruction term from the turbulence model
760  */
761 
762  const volScalarField chi(this->chi());
763  const volScalarField fv1(this->fv1(chi));
764 
765  const volScalarField Stilda(
766  this->fv3(chi, fv1) * ::sqrt(2.0) * mag(skew(fvc::grad(U_)))
767  + this->fv2(chi, fv1) * nuTilda_ / sqr(kappa_ * y_));
768 
769  volScalarField rho = this->rho();
770 
771  volScalarField P = Cb1_ * phase_ * rho * Stilda * nuTilda_;
772  volScalarField D = Cw1_ * phase_ * rho * fw(Stilda) * sqr(nuTilda_ / y_);
773 
774  forAll(P, cellI)
775  {
776  PoD[cellI] = P[cellI] / (D[cellI] + P[cellI] + 1e-16);
777  }
778 }
779 
780 void DASpalartAllmarasFv3::getTurbConvOverProd(volScalarField& CoP) const
781 {
782  /*
783  Description:
784  Return the value of the convective over production term from the turbulence model
785  */
786 
787  const volScalarField chi(this->chi());
788  const volScalarField fv1(this->fv1(chi));
789 
790  const volScalarField Stilda(
791  this->fv3(chi, fv1) * ::sqrt(2.0) * mag(skew(fvc::grad(U_)))
792  + this->fv2(chi, fv1) * nuTilda_ / sqr(kappa_ * y_));
793 
794  volScalarField rho = this->rho();
795 
796  volScalarField P = Cb1_ * phase_ * rho * Stilda * nuTilda_;
797  volScalarField C = fvc::div(phaseRhoPhi_, nuTilda_);
798 
799  forAll(P, cellI)
800  {
801  CoP[cellI] = C[cellI] / (P[cellI] + C[cellI] + 1e-16);
802  }
803 }
804 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
805 
806 } // End namespace Foam
807 
808 // ************************************************************************* //
Foam::DASpalartAllmarasFv3::solverDictNuTilda_
dictionary solverDictNuTilda_
Definition: DASpalartAllmarasFv3.H:105
Foam::DASpalartAllmarasFv3::y_
const volScalarField & y_
3D wall distance
Definition: DASpalartAllmarasFv3.H:95
Foam::DASpalartAllmarasFv3::getTurbProdOverDestruct
virtual void getTurbProdOverDestruct(volScalarField &PoD) const
return the value of the destruction term from the turbulence model
Definition: DASpalartAllmarasFv3.C:755
Foam::DASpalartAllmarasFv3::fv1
tmp< volScalarField > fv1(const volScalarField &chi) const
Definition: DASpalartAllmarasFv3.C:151
Foam::DATurbulenceModel::phi_
surfaceScalarField & phi_
face flux
Definition: DATurbulenceModel.H:83
solve
nuTilda1Eqn solve(solverDictNuTilda)
D
volVectorField & D
Definition: createRefsSolidDisplacement.H:8
Foam::DASpalartAllmarasFv3::calcResiduals
virtual void calcResiduals(const dictionary &options)
compute the turbulence residuals
Definition: DASpalartAllmarasFv3.C:429
Foam::DAOption
Definition: DAOption.H:29
Foam::DASpalartAllmarasFv3::nuTilda_
volScalarField & nuTilda_
Definition: DASpalartAllmarasFv3.H:86
Foam::addToRunTimeSelectionTable
addToRunTimeSelectionTable(DAFunction, DAFunctionForce, dictionary)
Foam::DASpalartAllmarasFv3::Cw3_
dimensionedScalar Cw3_
Definition: DASpalartAllmarasFv3.H:61
pseudoNuTilda
volScalarField & pseudoNuTilda
Definition: pseudoEqns.H:34
Foam::DASpalartAllmarasFv3::solveTurbState_
label solveTurbState_
whether to solve for turb states
Definition: DASpalartAllmarasFv3.H:101
normalizeResiduals
#define normalizeResiduals(resName)
Definition: DAMacroFunctions.H:28
DASpalartAllmarasFv3.H
Foam::DASpalartAllmarasFv3::Cw1_
dimensionedScalar Cw1_
Definition: DASpalartAllmarasFv3.H:59
Foam::DATurbulenceModel::phaseRhoPhi_
surfaceScalarField & phaseRhoPhi_
phase*phi*density field
Definition: DATurbulenceModel.H:89
Foam::DATurbulenceModel::allOptions_
const dictionary & allOptions_
all DAFoam options
Definition: DATurbulenceModel.H:71
Foam::DATurbulenceModel::rho
tmp< volScalarField > rho() const
get the density field
Definition: DATurbulenceModel.C:294
Foam::DASpalartAllmarasFv3::correctModelStates
virtual void correctModelStates(wordList &modelStates) const
update the turbulence state for DAStateInfo::regStates_
Definition: DASpalartAllmarasFv3.C:203
Foam::DASpalartAllmarasFv3::relaxNuTildaEqn_
scalar relaxNuTildaEqn_
Definition: DASpalartAllmarasFv3.H:104
Foam::DASpalartAllmarasFv3::nuTildaRes_
volScalarField nuTildaRes_
Definition: DASpalartAllmarasFv3.H:87
Foam::DASpalartAllmarasFv3::Cb1_
dimensionedScalar Cb1_
Definition: DASpalartAllmarasFv3.H:57
Foam::DASpalartAllmarasFv3::Cv1_
dimensionedScalar Cv1_
Definition: DASpalartAllmarasFv3.H:62
Foam::DASpalartAllmarasFv3::correctNut
virtual void correctNut()
update nut based on other turbulence variables and update the BCs
Definition: DASpalartAllmarasFv3.C:237
mesh
fvMesh & mesh
Definition: createRefsHeatTransfer.H:4
Foam::DASpalartAllmarasFv3::fv3
tmp< volScalarField > fv3(const volScalarField &chi, const volScalarField &fv1) const
Definition: DASpalartAllmarasFv3.C:165
Foam::DAUtility::boundVar
static void boundVar(const dictionary &allOptions, volScalarField &var, const label printToScreen)
bound a volScalar variable based on parametes defined in DAOption::allOptions_
Definition: DAUtility.C:475
Foam::DASpalartAllmarasFv3::pseudoNuTildaEqn_
fvScalarMatrix pseudoNuTildaEqn_
Definition: DASpalartAllmarasFv3.H:92
Foam::DASpalartAllmarasFv3::addModelResidualCon
virtual void addModelResidualCon(HashTable< List< List< word >>> &allCon) const
add the model residual connectivity to stateCon
Definition: DASpalartAllmarasFv3.C:329
Foam::DASpalartAllmarasFv3::calcLduResidualTurb
virtual void calcLduResidualTurb(volScalarField &nuTildaRes)
calculate the turbulence residual using LDU matrix
Definition: DASpalartAllmarasFv3.C:658
Foam::DASpalartAllmarasFv3::kappa_
dimensionedScalar kappa_
Definition: DASpalartAllmarasFv3.H:56
Foam::DASpalartAllmarasFv3::getFvMatrixFields
virtual void getFvMatrixFields(const word varName, scalarField &diag, scalarField &upper, scalarField &lower)
return the diag(), upper(), and lower() scalarFields from the turbulence model's fvMatrix
Definition: DASpalartAllmarasFv3.C:712
Foam::DASpalartAllmarasFv3::updateIntermediateVariables
virtual void updateIntermediateVariables()
update any intermediate variables that are dependent on state variables and are used in calcResiduals
Definition: DASpalartAllmarasFv3.C:268
Foam::DASpalartAllmarasFv3::betaFINuTilda_
volScalarField betaFINuTilda_
beta field for field inversion
Definition: DASpalartAllmarasFv3.H:98
Foam::DAUtility::primalResidualControl
static void primalResidualControl(const SolverPerformance< scalar > &solverP, const label printToScreen, const word varName, scalar &primalMaxRes)
control when to print the residual and also compute the maxInitRes
Definition: DAUtility.C:734
Foam::DASpalartAllmarasFv3::fw
tmp< volScalarField > fw(const volScalarField &Stilda) const
Definition: DASpalartAllmarasFv3.C:178
Foam::DASpalartAllmarasFv3::constructPseudoNuTildaEqn
virtual void constructPseudoNuTildaEqn()
construct pseudoNuTildaEqn_, which is nuTildaEqn with swapped upper and lower arrays
Definition: DASpalartAllmarasFv3.C:588
Foam::DASpalartAllmarasFv3::sigmaNut_
dimensionedScalar sigmaNut_
Definition: DASpalartAllmarasFv3.H:55
Foam::DASpalartAllmarasFv3::getTurbConvOverProd
virtual void getTurbConvOverProd(volScalarField &CoP) const
return the value of the convective over production term from the turbulence model
Definition: DASpalartAllmarasFv3.C:780
Foam::DATurbulenceModel::daGlobalVar_
DAGlobalVar & daGlobalVar_
global variable
Definition: DATurbulenceModel.H:74
Foam::DASpalartAllmarasFv3::invTranProdNuTildaEqn
virtual void invTranProdNuTildaEqn(const volScalarField &mySource, volScalarField &pseudoNuTilda)
Inverse transpose product, A_nuTilda^(-T)
Definition: DASpalartAllmarasFv3.C:513
Foam::DATurbulenceModel::U_
volVectorField & U_
velocity
Definition: DATurbulenceModel.H:80
Foam::DATurbulenceModel::nut_
volScalarField & nut_
turbulence viscosity
Definition: DATurbulenceModel.H:77
Foam::DASpalartAllmarasFv3::fv2
tmp< volScalarField > fv2(const volScalarField &chi, const volScalarField &fv1) const
Definition: DASpalartAllmarasFv3.C:158
Foam::DAGlobalVar::primalMaxRes
scalar primalMaxRes
the maximal residual for primal this var will be used in multiple classes
Definition: DAGlobalVar.H:62
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(DAFunction, 0)
Foam
Definition: checkGeometry.C:32
Foam::DASpalartAllmarasFv3::Cb2_
dimensionedScalar Cb2_
Definition: DASpalartAllmarasFv3.H:58
Foam::DASpalartAllmarasFv3::correct
virtual void correct(label printToScreen)
solve the residual equations and update the state
Definition: DASpalartAllmarasFv3.C:408
Foam::DATurbulenceModel::nu
tmp< volScalarField > nu() const
get the nu field
Definition: DATurbulenceModel.C:267
forAll
forAll(nuTilda1, cellI)
Definition: nuTilda1EqnIrkPimple.H:19
Foam::DATurbulenceModel::correctAlphat
void correctAlphat()
update alphat
Definition: DATurbulenceModel.C:203
Foam::DATurbulenceModel
Definition: DATurbulenceModel.H:52
Foam::DASpalartAllmarasFv3::chi
tmp< volScalarField > chi() const
Definition: DASpalartAllmarasFv3.C:146
Foam::DASpalartAllmarasFv3::pseudoNuTilda_
volScalarField pseudoNuTilda_
pseudoNuTilda_ and pseudoNuTildaEqn_ for solving adjoint equation
Definition: DASpalartAllmarasFv3.H:91
Foam::DATurbulenceModel::mesh_
const fvMesh & mesh_
fvMesh
Definition: DATurbulenceModel.H:65
Foam::DASpalartAllmarasFv3::Cv2_
dimensionedScalar Cv2_
Definition: DASpalartAllmarasFv3.H:63
Foam::DASpalartAllmarasFv3::DASpalartAllmarasFv3
DASpalartAllmarasFv3(const word modelType, const fvMesh &mesh, const DAOption &daOption)
Definition: DASpalartAllmarasFv3.C:41
Foam::DASpalartAllmarasFv3::Cw2_
dimensionedScalar Cw2_
Definition: DASpalartAllmarasFv3.H:60
Foam::DASpalartAllmarasFv3::correctBoundaryConditions
virtual void correctBoundaryConditions()
update turbulence variable boundary values
Definition: DASpalartAllmarasFv3.C:257
Foam::DASpalartAllmarasFv3::DnuTildaEff
tmp< volScalarField > DnuTildaEff() const
Return the effective diffusivity for nuTilda.
Definition: DASpalartAllmarasFv3.C:196
Foam::DASpalartAllmarasFv3::rhsSolvePseudoNuTildaEqn
virtual void rhsSolvePseudoNuTildaEqn(const volScalarField &nuTildaSource)
solve pseudoNuTildaEqn_ with overwritten rhs
Definition: DASpalartAllmarasFv3.C:626
Foam::DATurbulenceModel::turbModelType_
word turbModelType_
whether the turbulence model is incompressible or compressible
Definition: DATurbulenceModel.H:95
Foam::DATurbulenceModel::phase_
volScalarField phase_
phase field
Definition: DATurbulenceModel.H:86
Foam::DASpalartAllmarasFv3::correctStateResidualModelCon
virtual void correctStateResidualModelCon(List< List< word >> &stateCon) const
update the original variable connectivity for the adjoint state residuals in stateCon
Definition: DASpalartAllmarasFv3.C:279