adjointSpalartAllmaras.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 -------------------------------------------------------------------------------
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 "adjointSpalartAllmaras.H"
32 #include "wallDist.H"
33 #include "wallFvPatch.H"
36 #include "coupledFvPatch.H"
37 #include "ATCModel.H"
38 
39 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
40 
41 namespace Foam
42 {
43 namespace incompressibleAdjoint
44 {
45 namespace adjointRASModels
46 {
47 
48 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
49 
50 defineTypeNameAndDebug(adjointSpalartAllmaras, 0);
52 (
53  adjointRASModel,
54  adjointSpalartAllmaras,
55  dictionary
56 );
57 
58 
59 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
60 
61 // * * * * * * * * * * * * Primal Spalart - Allmaras * * * * * * * * * * * * //
62 
64 {
65  return nuTilda()/nu();
66 }
67 
68 
70 {
71  const volScalarField chi3(pow3(chi));
72  return chi3/(chi3 + pow3(Cv1_));
73 }
74 
75 
77 (
78  const volScalarField& chi,
79  const volScalarField& fv1
80 ) const
81 {
82  return 1.0 - chi/(1.0 + chi*fv1);
83 }
84 
85 
87 (
88  const volScalarField& chi,
89  const volScalarField& fv1
90 ) const
91 {
92  volScalarField Omega(::sqrt(2.0)*mag(skew(gradU_)));
93 
94  return
95  (
96  max
97  (
98  Omega
99  + fv2(chi, fv1)*nuTilda()/sqr(kappa_*y_),
100  Cs_*Omega
101  )
102  );
103 }
104 
105 
107 (
108  const volScalarField& Stilda
109 ) const
110 {
111  auto tr =
113  (
114  min
115  (
117  scalar(10)
118  )
119  );
120  tr.ref().boundaryFieldRef() == Zero;
121 
122  return tr;
123 }
124 
125 
127 (
128  const volScalarField& Stilda
129 ) const
130 {
131  const volScalarField g(r_ + Cw2_*(pow6(r_) - r_));
132 
133  return g*pow((1.0 + pow6(Cw3_))/(pow6(g) + pow6(Cw3_)), 1.0/6.0);
134 }
135 
136 
138 {
139  return
141  ("DnuTildaEff", (nuTilda() + this->nu())/sigmaNut_);
142 }
143 
146 {
147  return primalVars_.RASModelVariables()().TMVar1();
148 }
149 
150 
152 {
153  return primalVars_.RASModelVariables()().nutRef();
154 }
155 
156 
157 // * * * * * * * * * * * Adjoint Spalart - Allmaras * * * * * * * * * * * * //
158 
160 (
161  const volScalarField& chi
162 ) const
163 {
165 
166  return 3.0*pow3(Cv1_)*sqr(chi/(chi3 + pow3(Cv1_)));
167 }
168 
169 
171 (
172  const volScalarField& chi,
173  const volScalarField& fv1,
174  const volScalarField& dFv1dChi
175 ) const
176 {
177  return (chi*chi*dFv1dChi - 1.)/sqr(1. + chi*fv1);
178 }
179 
180 
182 (
183  const volScalarField& Omega,
184  const volScalarField& fv2
185 ) const
186 {
187  volScalarField fieldSwitch
188  (
189  Omega + fv2*nuTilda()/sqr(kappa_*y_) - Cs_*Omega
190  );
191 
192  return pos(fieldSwitch) + neg(fieldSwitch)*Cs_;
193 }
194 
195 
197 (
198  const volScalarField& Omega,
199  const volScalarField& fv2,
200  const volScalarField& dFv2dChi
201 ) const
202 {
203  volScalarField invDenom(1./sqr(kappa_*y_));
204  volScalarField fieldSwitch(Omega + fv2*nuTilda()*invDenom - Cs_*Omega);
205 
206  return pos(fieldSwitch)*(dFv2dChi*nuTilda()*invDenom/nu() + fv2*invDenom);
207 }
208 
209 
211 (
212  const volScalarField& Omega,
213  const volScalarField& fv2
214 ) const
215 {
217  volScalarField fieldSwitch(Omega + aux - Cs_*Omega);
218 
219  return - 2.*pos(fieldSwitch)*aux/y_;
220 }
221 
222 
224 (
225  const volScalarField& Stilda
226 ) const
227 {
228  tmp<volScalarField> tdrdNutilda
229  (
230  1./(max(Stilda, minStilda_)*sqr(kappa_*y_))
231  *(scalar(10) - r_)/(scalar(10) - r_ + SMALL)
232  );
233  tdrdNutilda.ref().boundaryFieldRef() == Zero;
234 
235  return tdrdNutilda;
236 }
237 
238 
240 (
241  const volScalarField& Stilda
242 ) const
243 {
244  tmp<volScalarField> tdrdStilda
245  (
247  *(scalar(10) - r_)/(scalar(10) - r_ + SMALL)
248  );
249  tdrdStilda.ref().boundaryFieldRef() == Zero;
250 
251  return tdrdStilda;
252 }
253 
254 
256 (
257  const volScalarField& Stilda
258 ) const
259 {
260  tmp<volScalarField> tdrdDelta
261  (
262  - 2.*nuTilda()/(max(Stilda, minStilda_)*sqr(kappa_*y_)*y_)
263  *(scalar(10) - r_)/(scalar(10) - r_ + SMALL)
264  );
265  tdrdDelta.ref().boundaryFieldRef() == Zero;
266 
267  return tdrdDelta;
268 }
269 
270 
272 (
273  const volScalarField& Stilda
274 ) const
275 {
276  volScalarField g(r_ + Cw2_*(pow6(r_) - r_));
277 
278  dimensionedScalar pow6Cw3 = pow6(Cw3_);
279  volScalarField pow6g(pow6(g));
280 
281  return
282  pow6Cw3/(pow6g + pow6Cw3)
283  *pow((1.0 + pow6Cw3)/(pow6g + pow6Cw3), 1.0/6.0)
284  *(1.0 + Cw2_*(6.0*pow5(r_) - 1.0));
285 }
286 
287 
289 (
290  const volScalarField& Stilda,
291  const volScalarField& dfwdr,
292  const volScalarField& dStildadNuTilda
293 ) const
294 {
295  volScalarField invDenom(1./sqr(kappa_*y_));
297  return
298  dfwdr*(dr_dNuTilda(Stilda) + dr_dStilda(Stilda)*dStildadNuTilda);
299 }
300 
301 
303 (
304  const volScalarField& Stilda,
305  const volScalarField& dfwdr,
306  const volScalarField& dStildadOmega
307 ) const
308 {
309  return dfwdr*dr_dStilda(Stilda)*dStildadOmega;
310 }
311 
312 
314 (
315  const volScalarField& Stilda,
316  const volScalarField& dfwdr,
317  const volScalarField& dStildadDelta
318 ) const
319 {
320  return dfwdr*(dr_dDelta(Stilda) + dr_dStilda(Stilda)*dStildadDelta);
321 }
322 
323 
325 (
326  const volScalarField& fw,
327  const volScalarField& dfwdNuTilda
328 ) const
329 {
330  return Cw1_*(nuTilda()*dfwdNuTilda + fw)/sqr(y_);
331 }
332 
333 
335 (
336  const volScalarField& dStildadNuTilda
337 ) const
338 {
339  return - Cb1_*dStildadNuTilda;
340 }
341 
342 
344 (
345  const volScalarField& fv1,
346  const volScalarField& dFv1dChi
347 ) const
348 {
349  return dFv1dChi*nuTilda()/nu() + fv1;
350 }
351 
352 
354 {
355  // Store boundary field of the conservative part,
356  // for use in adjoint outlet boundary conditions
357  forAll(mesh_.boundary(), pI)
358  {
359  const fvPatch& patch = mesh_.boundary()[pI];
360  if(!isA<coupledFvPatch>(patch))
361  {
362  tmp<vectorField> tnf = patch.nf();
364  (tnf & momentumSourceMult_.boundaryField()[pI])
365  *nuaTilda().boundaryField()[pI];
366  }
367  }
368 
370 }
371 
372 
374 {
376  {
377  Info<< "Updating primal-based fields of the adjoint turbulence "
378  << "model ..." << endl;
379 
380  // Grab references
381  const volVectorField& U = primalVars_.U();
382 
383  // Update gradient fields
384  gradU_ = mask_*fvc::grad(U, "gradUStilda");
386 
387  const volScalarField Omega(::sqrt(2.0)*mag(skew(gradU_)));
388 
389  // Primal SA fields
390  volScalarField chi(this->chi());
391  volScalarField fv1(this->fv1(chi));
392  volScalarField fv2(this->fv2(chi, fv1));
393  Stilda_ = Stilda(chi, fv1);
394  r_ = r(Stilda_);
395  fw_ = this->fw(Stilda_);
396 
397  // Derivatives of primal fields wrt to nuTilda
398  volScalarField dFv1_dChi(this->dFv1_dChi(chi));
401  (this->dStilda_dNuTilda(Omega, fv2, dFv2_dChi));
405 
406  // Fields to be used in the nuaTilda equation
408  symm(mask_*fvc::grad(U, "adjointProductionU"));
409 
411  nuTilda()
412  *(
415  );
416 
418 
419  // Constant multiplier in the adjoint momentum source term
423 
425  2.*skew(gradU_)
426  /(Omega + dimensionedScalar("SMALL", Omega.dimensions(), SMALL))
427  *(
430  );
431 
432  // Set changedPrimalSolution_ to false to avoid recomputing these
433  // fields unless the primal has changed
434  changedPrimalSolution_ = false;
435  }
436 }
437 
438 
440 {
441  tmp<volScalarField> mask;
443  {
445  }
446  else
447  {
448  mask = tmp<volScalarField>
449  (
450  new volScalarField
451  (
452  IOobject
453  (
454  "unitMask",
455  mesh_.time().timeName(),
456  mesh_,
459  ),
460  mesh_,
461  dimensionedScalar("unit", dimless, scalar(1))
462  )
463  );
464  }
465 
466  return mask;
467 }
468 
469 
470 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
471 
472 adjointSpalartAllmaras::adjointSpalartAllmaras
473 (
474  incompressibleVars& primalVars,
476  objectiveManager& objManager,
477  const word& adjointTurbulenceModelName,
478  const word& modelName
479 )
480 :
482  (
483  modelName,
484  primalVars,
485  adjointVars,
486  objManager,
487  adjointTurbulenceModelName
488  ),
489 
490  sigmaNut_
491  (
492  dimensioned<scalar>::getOrAddToDict
493  (
494  "sigmaNut",
495  this->coeffDict_,
496  0.66666
497  )
498  ),
499  kappa_
500  (
501  dimensioned<scalar>::getOrAddToDict
502  (
503  "kappa",
504  this->coeffDict_,
505  0.41
506  )
507  ),
508 
509  Cb1_
510  (
511  dimensioned<scalar>::getOrAddToDict
512  (
513  "Cb1",
514  this->coeffDict_,
515  0.1355
516  )
517  ),
518  Cb2_
519  (
520  dimensioned<scalar>::getOrAddToDict
521  (
522  "Cb2",
523  this->coeffDict_,
524  0.622
525  )
526  ),
527  Cw1_(Cb1_/sqr(kappa_) + (1.0 + Cb2_)/sigmaNut_),
528  Cw2_
529  (
530  dimensioned<scalar>::getOrAddToDict
531  (
532  "Cw2",
533  this->coeffDict_,
534  0.3
535  )
536  ),
537  Cw3_
538  (
539  dimensioned<scalar>::getOrAddToDict
540  (
541  "Cw3",
542  this->coeffDict_,
543  2.0
544  )
545  ),
546  Cv1_
547  (
548  dimensioned<scalar>::getOrAddToDict
549  (
550  "Cv1",
551  this->coeffDict_,
552  7.1
553  )
554  ),
555  Cs_
556  (
557  dimensioned<scalar>::getOrAddToDict
558  (
559  "Cs",
560  this->coeffDict_,
561  0.3
562  )
563  ),
564 
565  limitAdjointProduction_
566  (
567  coeffDict_.getOrDefault("limitAdjointProduction", true)
568  ),
569 
570  y_(primalVars_.RASModelVariables()().d()),
571 
572  mask_(allocateMask()),
573 
574  symmAdjointProductionU_
575  (
576  IOobject
577  (
578  "symmAdjointProductionU",
579  runTime_.timeName(),
580  mesh_,
581  IOobject::NO_READ,
582  IOobject::NO_WRITE
583  ),
584  mesh_,
586  ),
587 
588  productionDestructionSource_
589  (
590  IOobject
591  (
592  "productionDestructionSource",
593  runTime_.timeName(),
594  mesh_,
595  IOobject::NO_READ,
596  IOobject::NO_WRITE
597  ),
598  mesh_,
600  ),
601 
602  Stilda_
603  (
604  IOobject
605  (
606  "Stilda",
607  runTime_.timeName(),
608  mesh_,
609  IOobject::NO_READ,
610  IOobject::NO_WRITE
611  ),
612  mesh_,
614  ),
615 
616  r_
617  (
618  IOobject
619  (
620  "r",
621  runTime_.timeName(),
622  mesh_,
623  IOobject::NO_READ,
624  IOobject::NO_WRITE
625  ),
626  mesh_,
628  ),
629 
630  fw_
631  (
632  IOobject
633  (
634  "fw",
635  runTime_.timeName(),
636  mesh_,
637  IOobject::NO_READ,
638  IOobject::NO_WRITE
639  ),
640  mesh_,
642  ),
643 
644  Cdnut_
645  (
646  IOobject
647  (
648  "Cdnut",
649  runTime_.timeName(),
650  mesh_,
651  IOobject::NO_READ,
652  IOobject::NO_WRITE
653  ),
654  mesh_,
656  ),
657 
658  momentumSourceMult_
659  (
660  IOobject
661  (
662  "momentumSourceMult",
663  runTime_.timeName(),
664  mesh_,
665  IOobject::NO_READ,
666  IOobject::NO_WRITE
667  ),
668  mesh_,
670  ),
671 
672  gradU_(fvc::grad(primalVars.U())),
673  gradNuTilda_(fvc::grad(nuTilda())),
674  minStilda_("SMALL", Stilda_.dimensions(), SMALL)
675 {
677  adjointTMVariablesBaseNames_[0] = "nuaTilda";
678  // Read nuaTilda field and reset pointer to the first
679  // adjoint turbulence model variable
681  (
683  mesh_,
684  "nuaTilda",
685  adjointVars.solverName(),
686  adjointVars.useSolverNameForFields()
687  );
688 
689  setMeanFields();
690 
691  // Set the includeDistance to true, to allow for the automatic solution
692  // of the adjoint eikonal equation when computing sensitivities
693  includeDistance_ = true;
694 
695  // Update the primal related fields here so that functions computing
696  // sensitivities have the updated fields in case of continuation
698 }
699 
700 
701 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
702 
704 {
705  const volVectorField& Ua = adjointVars_.UaInst();
706  return devReff(Ua);
707 }
708 
709 
711 (
712  const volVectorField& U
713 ) const
714 {
715  return
717  (
718  IOobject
719  (
720  "devRhoReff",
721  runTime_.timeName(),
722  mesh_,
725  ),
726  -nuEff()*dev(twoSymm(fvc::grad(U)))
727  );
728 }
729 
730 
732 {
733  tmp<volScalarField> tnuEff(nuEff());
734  const volScalarField& nuEff = tnuEff();
735 
736  return
737  (
738  - fvm::laplacian(nuEff, Ua)
739  - fvc::div(nuEff*dev(fvc::grad(Ua)().T()))
740  );
741 }
742 
743 
745 {
747  (adjointSpalartAllmaras, "adjointSpalartAllmaras::addMomentumSource");
748  // cm formulation
749  //return (- nuTilda()*fvc::grad(nuaTilda() - conservativeMomentumSource());
750 
751  // ncm formulation
753 }
754 
755 
757 {
758  volScalarField chi(this->chi());
759  volScalarField fv1(this->fv1(chi));
760  volScalarField dFv1_dChi(this->dFv1_dChi(chi));
761 
762  return dnut_dNuTilda(fv1, dFv1_dChi);
763 }
764 
765 
767 {
768  tmp<scalarField> tdiffCoeff
769  (
770  new scalarField(mesh_.boundary()[patchI].size(), Zero)
771  );
772 
773  scalarField& diffCoeff = tdiffCoeff.ref();
774 
775  diffCoeff =
776  (nuTilda().boundaryField()[patchI] + nu()().boundaryField()[patchI])
778 
779  return tdiffCoeff;
780 }
781 
782 
783 const boundaryVectorField&
785 {
786  // Computed in conservativeMomentumSource
787  return adjMomentumBCSourcePtr_();
788 }
789 
790 
792 {
794 
795  forAll(mesh_.boundary(), patchI)
796  {
797  const fvPatch& patch = mesh_.boundary()[patchI];
798 
799  tmp<vectorField> tnf = patch.nf();
800  if (isA<wallFvPatch>(patch) && patch.size() != 0)
801  {
802  wallShapeSens[patchI] =
803  - nuaTilda().boundaryField()[patchI].snGrad()
804  *diffusionCoeffVar1(patchI)
805  *nuTilda().boundaryField()[patchI].snGrad()*tnf;
806  }
807  }
808 
809  return wallShapeSens;
810 }
811 
812 
814 {
816 
817  forAll(mesh_.boundary(), patchI)
818  {
819  tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
820 
821  wallFloCoSens[patchI] =
822  nuaTilda().boundaryField()[patchI]
823  *nuTilda().boundaryField()[patchI]*tnf;
824  }
825 
826  return wallFloCoSens;
827 }
828 
829 
831 {
832  const volVectorField& U = primalVars_.U();
833  const volVectorField& Ua = adjointVars_.Ua();
834 
835  // Primal SA fields
836  volScalarField chi(this->chi());
837  volScalarField fv1(this->fv1(chi));
838  volScalarField fv2(this->fv2(chi, fv1));
839  volScalarField Omega(::sqrt(2.0)*mag(gradU_));
840 
841  // Derivatives of primal fields wrt to nuTilda
842  volScalarField dFv1_dChi(this->dFv1_dChi(chi));
847  (this->dfw_dDelta(Stilda_, dfw_dr, dStilda_dDelta));
848 
849  auto tadjointEikonalSource =
851  (
852  "adjointEikonalSource" + type(),
853  (
855  + Cw1_*sqr(nuTilda()/y_)*(dfw_dDelta - 2.*fw_/y_)
856  )*nuaTilda()
857  );
858  volScalarField& adjointEikonalSource = tadjointEikonalSource.ref();
859 
860  // if wall functions are used, add appropriate source terms
862  SAwallFunctionPatchField;
863 
864  const volScalarField::Boundary& nutBoundary = nut().boundaryField();
865  const scalarField& V = mesh_.V().field();
866 
867  tmp<volScalarField> tnuEff = nuEff();
868  const volScalarField& nuEff = tnuEff();
869 
870  forAll(nutBoundary, patchi)
871  {
872  const fvPatch& patch = mesh_.boundary()[patchi];
873  if
874  (
875  isA<SAwallFunctionPatchField>(nutBoundary[patchi])
876  && patch.size() != 0
877  )
878  {
879  const scalar kappa_(0.41);
880  const scalar E_(9.8);
881  tmp<vectorField> tnf = patch.nf();
882  const vectorField& nf = tnf.ref();
883  const scalarField& magSf = patch.magSf();
884 
885  const fvPatchVectorField& Up = U.boundaryField()[patchi];
886  const fvPatchVectorField& Uap = Ua.boundaryField()[patchi];
887  const vectorField Uc(Up.patchInternalField());
888  const vectorField Uc_t(Uc - (Uc & nf)*nf);
889 
890  // By convention, tf has the direction of the tangent
891  // PRIMAL velocity at the first cell off the wall
892  const vectorField tf(Uc_t/mag(Uc_t));
893 
894  const scalarField nuw(nuEff.boundaryField()[patchi]);
895  const scalarField nu(this->nu()().boundaryField()[patchi]);
896  const fvPatchScalarField& yC = y()[patchi];
897 
898  const scalarField magGradU(mag(Up.snGrad()));
899 
900  // Note: What happens in separation?? sign change needed
901  const scalarField vtau(sqrt(nuw*magGradU));
902 
903  // Note: mag for positive uPlus
904  const scalarField uPlus(mag(Uc)/vtau);
905 
906  const scalarField yPlus(yC*vtau/nu);
907  const scalarField kUu(min(kappa_*uPlus, scalar(50)));
908  const scalarField auxA
909  ((kappa_/E_)*(exp(kUu) - 1 - kUu - 0.5*kUu*kUu));
910  const scalarField Cwf_d(sqr(vtau)/nu/(yPlus+uPlus*(1 + auxA)));
911 
912  // Tangential components are according to tf
913  autoPtr<boundaryAdjointContribution> boundaryContrPtr
914  (
916  (
917  "objectiveManager" + objectiveManager_.adjointSolverName(),
919  "incompressible",
920  patch
921  )
922  );
923  tmp<vectorField> tsource(boundaryContrPtr->normalVelocitySource());
924 
925  const scalarField rt(tsource() & tf);
926  const scalarField Uap_t(Uap & tf);
927 
928  const labelList& faceCells = patch.faceCells();
929  forAll(faceCells, faceI)
930  {
931  label cellI = faceCells[faceI];
932  adjointEikonalSource[cellI] -=
933  2.*( rt[faceI] + Uap_t[faceI] )
934  *vtau[faceI]*Cwf_d[faceI]*magSf[faceI]
935  /V[cellI]; // Divide with cell volume since the term
936  // will be used as a source term in the
937  // adjoint eikonal equation
938  }
939  }
940  }
941 
942  return tadjointEikonalSource;
943 }
944 
945 
947 {
948  const volVectorField& U = primalVars_.U();
949 
950  tmp<volTensorField> tgradU = fvc::grad(U);
951  const volTensorField& gradU = tgradU.cref();
952  tmp<volVectorField> tgradNuTilda = fvc::grad(nuTilda());
953  volVectorField& gradNuTilda = tgradNuTilda.ref();
954  tmp<volVectorField> tgradNuaTilda = fvc::grad(nuaTilda());
955  volVectorField::Boundary& gradNuaTildab =
956  tgradNuaTilda.ref().boundaryFieldRef();
957 
958  // Explicitly correct the boundary gradient to get rid of
959  // the tangential component
960  forAll(mesh_.boundary(), patchI)
961  {
962  const fvPatch& patch = mesh_.boundary()[patchI];
963  if (isA<wallFvPatch>(patch))
964  {
965  tmp<vectorField> tnf = patch.nf();
966  const vectorField& nf = tnf();
967  // gradU:: can cause problems in zeroGradient patches for U
968  // and zero fixedValue for nuTilda.
969  // S becomes 0 and is used as a denominator in G
970  //gradU.boundaryField()[patchI] =
971  // nf * U_.boundaryField()[patchI].snGrad();
972  gradNuTilda.boundaryFieldRef()[patchI] =
973  nf*nuTilda().boundaryField()[patchI].snGrad();
974  gradNuaTildab[patchI] =
975  nf*nuaTilda().boundaryField()[patchI].snGrad();
976  }
977  }
978 
979  // delta vorticity
980  volScalarField Omega(::sqrt(2.0)*mag(skew(gradU)));
981  volTensorField deltaOmega
982  (
983  (
984  (gradU & gradU)().T() //jk
985  - (gradU & gradU.T()) //symmetric
986  )
987  /(Omega + dimensionedScalar("SMALL", Omega.dimensions(), SMALL))
988  );
989  tgradU.clear();
990 
991  volScalarField chi(this->chi());
992  volScalarField fv1(this->fv1(chi));
993  volScalarField fv2(this->fv2(chi, fv1));
994 
999 
1000  return
1002  (
1003  "volSensTerm",
1004  // jk, cm formulation for the TM model convection
1005  - (nuaTilda()*(U*gradNuTilda))
1006  // jk, symmetric in theory
1007  + nuaTilda()*fvc::grad(DnuTildaEff()*gradNuTilda)().T()
1008  // jk
1009  - DnuTildaEff()*(tgradNuaTilda*gradNuTilda)
1010  // symmetric
1011  + 2.*nuaTilda()*Cb2_/sigmaNut_*(gradNuTilda*gradNuTilda)
1012  + (
1015  )
1016  *nuaTilda()*deltaOmega // jk
1017  );
1018 }
1019 
1022 {
1024 }
1025 
1026 
1028 {
1029  addProfiling
1030  (adjointSpalartAllmaras, "adjointSpalartAllmaras::correct");
1031  if (!adjointTurbulence_)
1032  {
1033  return;
1034  }
1035 
1037 
1039 
1041  const volVectorField& Ua = adjointVars_.UaInst();
1042 
1044  volScalarField gradUaR
1045  (
1047  );
1048 
1049  dimensionedScalar oneOverSigmaNut = 1./sigmaNut_;
1050 
1051  nuaTilda().storePrevIter();
1052 
1053  tmp<fvScalarMatrix> nuaTildaEqn
1054  (
1055  fvm::ddt(nuaTilda())
1056  + fvm::div(-phi, nuaTilda())
1058  // Note: Susp
1060  + fvc::laplacian(2.0*Cb2_*oneOverSigmaNut*nuaTilda(), nuTilda())
1061  + gradNua*oneOverSigmaNut
1062  ==
1063  // always a negative contribution to the lhs. No Sp used!
1065  //always a positive contribution to the lhs. no need for SuSp
1066  - fvm::Sp(Cw1_*fw_*nuTilda()/sqr(y_), nuaTilda())
1067  - Cdnut_*gradUaR
1068  );
1069 
1070  // Add sources from the objective functions
1071  objectiveManager_.addTMEqn1Source(nuaTildaEqn.ref());
1072 
1073  nuaTildaEqn.ref().relax();
1074  solve(nuaTildaEqn);
1076  nuaTilda().relax();
1077 
1079  {
1080  scalar maxDeltaNuaTilda =
1081  gMax(mag(nuaTilda() - nuaTilda().prevIter())());
1082  dimensionedScalar maxNuaTilda = max(mag(nuaTilda()));
1083  Info<< "Max mag of nuaTilda = " << maxNuaTilda.value() << endl;
1084  Info<< "Max mag of delta nuaTilda = " << maxDeltaNuaTilda << endl;
1085  }
1086 }
1087 
1088 
1090 {
1091  if (adjointRASModel::read())
1092  {
1094  kappa_.readIfPresent(this->coeffDict());
1095 
1096  Cb1_.readIfPresent(this->coeffDict());
1097  Cb2_.readIfPresent(this->coeffDict());
1098  Cw1_ = Cb1_/sqr(kappa_) + (1.0 + Cb2_)/sigmaNut_;
1099  Cw2_.readIfPresent(this->coeffDict());
1100  Cw3_.readIfPresent(this->coeffDict());
1101  Cv1_.readIfPresent(this->coeffDict());
1102  Cs_.readIfPresent(this->coeffDict());
1103 
1104  return true;
1105  }
1106  else
1107  {
1108  return false;
1109  }
1110 }
1111 
1112 
1113 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1114 
1115 } // End namespace adjointRASModels
1116 } // End namespace incompressibleAdjoint
1117 } // End namespace Foam
1118 
1119 // ************************************************************************* //
dictionary coeffDict_
Model coefficients dictionary.
void updatePrimalRelatedFields()
Update the constant primal-related fields.
scalar uPlus
tmp< volScalarField > dfw_dNuTilda(const volScalarField &Stilda, const volScalarField &dfwdr, const volScalarField &dStildadNuTilda) const
virtual const boundaryVectorField & wallShapeSensitivities()
Sensitivity terms for shape optimisation, emerging from.
const Type & value() const noexcept
Return const reference to value.
virtual void addTMEqn1Source(fvScalarMatrix &adjTMEqn1)=0
Add contribution to first adjoint turbulence model PDE.
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh >> grad(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcGrad.C:47
bool includeDistance_
Does the turbulence model include distances and should the adjoint to the distance field be computed...
#define addProfiling(name, descr)
Define profiling trigger with specified name and description string.
virtual tmp< Field< Type > > snGrad() const
Return patch-normal gradient.
Definition: fvPatchField.C:174
tmp< volScalarField > dP_dNuTilda(const volScalarField &dStildadNuTilda) const
SolverPerformance< Type > solve(faMatrix< Type > &, const dictionary &)
Solve returning the solution statistics given convergence tolerance.
virtual tmp< scalarField > diffusionCoeffVar1(label patchI) const
Diffusion coefficient of the first primal and adjoint turbulence model equation. Needed for some adjo...
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
static autoPtr< boundaryAdjointContribution > New(const word &managerName, const word &adjointSolverName, const word &simulationType, const fvPatch &patch)
Return a reference to the selected turbulence model.
dimensionedTensor skew(const dimensionedTensor &dt)
T & ref() const
Return non-const reference to the contents of a non-null managed pointer.
Definition: tmpI.H:210
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
GeometricField< tensor, fvPatchField, volMesh > volTensorField
Definition: volFieldsFwd.H:89
dimensionedSymmTensor sqr(const dimensionedVector &dv)
tmp< GeometricField< Type, fvPatchField, volMesh > > div(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcDiv.C:42
bool readIfPresent(const dictionary &dict)
Update the value of dimensioned<Type> if found in the dictionary, lookup in dictionary with the name(...
virtual tmp< volVectorField > adjointMeanFlowSource()
Source terms to the adjoint momentum equation due to the differentiation of the turbulence model...
const volScalarField & nuTilda() const
References to the primal turbulence model variables.
class for managing incompressible objective functions.
virtual bool read()
Read adjointRASProperties dictionary.
tmp< volScalarField > dStilda_dNuTilda(const volScalarField &Omega, const volScalarField &fv2, const volScalarField &dFv2dChi) const
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:68
tmp< volScalarField > Stilda(const volScalarField &chi, const volScalarField &fv1) const
tmp< volScalarField > dFv2_dChi(const volScalarField &chi, const volScalarField &fv1, const volScalarField &dFv1dChi) const
const T & cref() const
Return const reference to the object or to the contents of a (non-null) managed pointer.
Definition: tmpI.H:196
Continuous adjoint to the Spalart-Allmaras one-eqn mixing-length model for incompressible flows...
volScalarField mask_
Field for masking (convergence enhancement)
virtual const boundaryVectorField & adjointMomentumBCSource() const
Source for the outlet adjoint momentum BC coming from differentiating the turbulence model...
Abstract base class with a fat-interface to all derived classes covering all possible ways in which t...
static void nullifyField(GeometricField< Type, PatchField, GeoMesh > &fieldPtr)
Nullify field and old times, if present.
autoPtr< boundaryVectorField > adjMomentumBCSourcePtr_
Source to the adjoint momentum BC emerging from differentiating the turbulence model.
virtual void correct()=0
Solve the adjoint turbulence equations.
Ignore writing from objectRegistry::writeObject()
const dimensionSet dimless
Dimensionless.
autoPtr< boundaryVectorField > wallShapeSensitivitiesPtr_
Wall sensitivity term for shape optimisation.
Smooth ATC in cells next to a set of patches supplied by type.
Definition: faceCells.H:52
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:361
const DimensionedField< scalar, volMesh > & V() const
Return cell volumes.
tmp< volScalarField > dD_dNuTilda(const volScalarField &fw, const volScalarField &dfwdNuTilda) const
tmp< GeometricField< Type, fvPatchField, volMesh > > laplacian(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvcLaplacian.C:40
tmp< volScalarField > r(const volScalarField &Stilda) const
dimensionedScalar neg(const dimensionedScalar &ds)
dimensionedScalar pow5(const dimensionedScalar &ds)
Macros for easy insertion into run-time selection tables.
dimensionedSymmTensor twoSymm(const dimensionedSymmTensor &dt)
tmp< volScalarField > nu() const
Return the laminar viscosity.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
Switch adjointTurbulence_
Turbulence on/off flag.
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:84
autoPtr< boundaryVectorField > wallFloCoSensitivitiesPtr_
Wall sensitivity term for flow control optimisation.
word timeName
Definition: getTimeIndex.H:3
dimensionedScalar pos(const dimensionedScalar &ds)
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:752
const surfaceScalarField & phi() const
Return const reference to volume flux.
Base class for solution control classes.
bool changedPrimalSolution_
Has the primal solution changed?
tmp< volScalarField > dStilda_dDelta(const volScalarField &Omega, const volScalarField &fv2) const
tmp< volScalarField > dr_dNuTilda(const volScalarField &Stilda) const
This boundary condition provides a wall function for the turbulent viscosity (i.e. nut) based on velocity (i.e. U). Using Spalding&#39;s law gives a continuous nut profile to the wall.
void setSize(const label n)
Alias for resize()
Definition: List.H:289
tmp< volScalarField > dr_dDelta(const volScalarField &Stilda) const
dimensionedSymmTensor dev(const dimensionedSymmTensor &dt)
dimensionedScalar exp(const dimensionedScalar &ds)
bool useSolverNameForFields() const
Append solver name to fields?
Definition: variablesSet.C:83
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
virtual tmp< volScalarField > nutJacobianTMVar1() const
Jacobian of nut wrt the first turbulence model variable.
Abstract base class for incompressible turbulence models.
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:99
bool printMaxMags() const
Print max mags of solver fields.
tmp< fvMatrix< Type > > ddt(const GeometricField< Type, fvPatchField, volMesh > &vf)
Definition: fvmDdt.C:41
const volVectorField & Ua() const
Return const reference to velocity.
volScalarField & nuaTilda()
Access to the adjoint Spalart - Allmaras field.
static tmp< volScalarField > createLimiter(const fvMesh &mesh, const dictionary &dict)
Return a limiter based on given cells. For use with classes other than ATC which employ the same smoo...
Definition: ATCModel.C:214
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:203
zeroField SuSp(const Foam::zero, const GeometricField< Type, fvPatchField, volMesh > &)
A no-op source.
wordList adjointTMVariablesBaseNames_
Base names of the adjoint fields.
dimensionedScalar tr(const dimensionedSphericalTensor &dt)
addToRunTimeSelectionTable(adjointRASModel, adjointkOmegaSST, dictionary)
autoPtr< volScalarField > adjointTMVariable1Ptr_
Adjoint turbulence model variable 1.
const word & solverName() const
Return solver name.
Definition: variablesSet.C:77
virtual tmp< volSymmTensorField > devReff() const
Return the effective stress tensor including the laminar stress.
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
zeroField Sp(const Foam::zero, const GeometricField< Type, fvPatchField, volMesh > &)
A no-op source.
const volVectorField & U() const
Return const reference to velocity.
const uniformDimensionedVectorField & g
static word timeName(const scalar t, const int precision=precision_)
Return time name of given scalar time formatted with the given precision.
Definition: Time.C:760
tmp< fvMatrix< Type > > div(const surfaceScalarField &flux, const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvmDiv.C:41
virtual tmp< Field< Type > > patchInternalField() const
Return internal field next to patch as patch field.
Definition: fvPatchField.C:182
Type gMax(const FieldField< Field, Type > &f)
tmp< volScalarField > dStilda_dOmega(const volScalarField &Omega, const volScalarField &fv2) const
virtual void correct()
Solve the adjoint turbulence equations.
const dictionary & coeffDict() const
Const access to the coefficients dictionary.
tmp< volScalarField > dFv1_dChi(const volScalarField &chi) const
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
const solverControl & getSolverControl() const
Return const reference to solverControl.
const autoPtr< incompressible::RASModelVariables > & RASModelVariables() const
Return const reference to the turbulence model variables.
tmp< volScalarField > dnut_dNuTilda(const volScalarField &fv1, const volScalarField &dFv1dChi) const
const word & adjointSolverName() const
Return name of the adjointSolver.
Manages the adjoint mean flow fields and their mean values.
const volVectorField & UaInst() const
Return const reference to velocity.
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
dimensionedScalar pow3(const dimensionedScalar &ds)
tmp< volScalarField > dfw_dOmega(const volScalarField &Stilda, const volScalarField &dfwdr, const volScalarField &dStildadOmega) const
U
Definition: pEqn.H:72
void relax(const scalar alpha)
Relax field (for steady-state solution).
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:50
dimensionedSymmTensor symm(const dimensionedSymmTensor &dt)
virtual tmp< fvVectorMatrix > divDevReff(volVectorField &U) const
Return the diffusion term for the momentum equation.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
tmp< fvMatrix< Type > > laplacian(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvmLaplacian.C:41
virtual const boundaryVectorField & wallFloCoSensitivities()
Sensitivity terms for flow control, emerging from the.
scalar yPlus
tmp< volScalarField > fw(const volScalarField &Stilda) const
Nothing to be read.
tmp< volScalarField > fv2(const volScalarField &chi, const volScalarField &fv1) const
const std::string patch
OpenFOAM patch number as a std::string.
const dimensionSet dimTime(0, 0, 1, 0, 0, 0, 0)
Definition: dimensionSets.H:51
Boundary & boundaryFieldRef(const bool updateAccessTime=true)
Return a reference to the boundary field.
tmp< volScalarField > dfw_dr(const volScalarField &Stilda) const
void correctBoundaryConditions()
Correct boundary field.
virtual void nullify()
Nullify all adjoint turbulence model fields and their old times.
dimensionedScalar pow6(const dimensionedScalar &ds)
messageStream Info
Information stream (stdout output on master, null elsewhere)
objectiveManager & objectiveManager_
Reference to the objectiveManager.
Internal & ref(const bool updateAccessTime=true)
Same as internalFieldRef()
tmp< volScalarField > dr_dStilda(const volScalarField &Stilda) const
void storePrevIter() const
Store the field as the previous iteration value.
void clear() const noexcept
If object pointer points to valid object: delete object and set pointer to nullptr.
Definition: tmpI.H:263
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
virtual tmp< volScalarField > distanceSensitivities()
Sensitivity terms resulting from the differentiation of the distance field. Misses dxdb...
virtual tmp< volScalarField > nuEff() const
Return the effective viscosity.
tmp< volScalarField > fv1(const volScalarField &chi) const
A class for managing temporary objects.
Definition: HashPtrTable.H:50
virtual tmp< volTensorField > FISensitivityTerm()
Term contributing to the computation of FI-based sensitivities.
tmp< volVectorField > conservativeMomentumSource()
Conservative source term for the adjoint momentum equations.
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:166
const nearWallDist & y() const
Return the near wall distances.
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
tmp< volScalarField > dfw_dDelta(const volScalarField &Stilda, const volScalarField &dfwdr, const volScalarField &dStildadDelta) const
const volScalarField & nut() const
Return the turbulence viscosity.
bool limitAdjointProduction_
Whether to limit the adjoint production term to enhance stability.
static void setField(autoPtr< GeometricField< Type, fvPatchField, volMesh >> &fieldPtr, const fvMesh &mesh, const word &baseName, const word &solverName, const bool useSolverNameForFields)
Read vol fields.
Namespace for OpenFOAM.
tmp< GeometricField< typename outerProduct< vector, Type >::type, faPatchField, areaMesh >> grad(const GeometricField< Type, faePatchField, edgeMesh > &ssf)
Definition: facGrad.C:49
const dimensionSet & dimensions() const noexcept
Return dimensions.
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:705
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:157