/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2014-2023 PCOpt/NTUA Copyright (C) 2014-2023 FOSS GP ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . \*---------------------------------------------------------------------------*/ #include "adjointkOmegaSST.H" #include "wallFvPatch.H" #include "fixedValueFvPatchFields.H" #include "zeroGradientFvPatchFields.H" #include "linear.H" #include "reverseLinear.H" #include "nutkWallFunctionFvPatchScalarField.H" #include "omegaWallFunctionFvPatchScalarField.H" #include "fvOptions.H" #include "sensitivityTopO.H" #include "addToRunTimeSelectionTable.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { namespace incompressibleAdjoint { namespace adjointRASModels { // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // defineTypeNameAndDebug(adjointkOmegaSST, 0); addToRunTimeSelectionTable(adjointRASModel, adjointkOmegaSST, dictionary); // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // tmp adjointkOmegaSST::F1() const { tmp arg1 = min ( min ( max ( (scalar(1)/betaStar_)*sqrt(k())/(omega()*y_), scalar(500)*nu()/(sqr(y_)*omega()) ), (4*alphaOmega2_)*k()/(CDkOmegaPlus_*sqr(y_)) ), scalar(10) ); return tanh(pow4(arg1)); } tmp adjointkOmegaSST::F2() const { tmp arg2 = min ( max ( (scalar(2)/betaStar_)*sqrt(k())/(omega()*y_), scalar(500)*nu()/(sqr(y_)*omega()) ), scalar(100) ); return tanh(sqr(arg2)); } tmp adjointkOmegaSST::GbyNu ( const volScalarField& GbyNu0, const volScalarField& F2, const volScalarField& S2 ) const { return min ( GbyNu0, (c1_/a1_)*betaStar_*omega() *max(a1_*omega(), b1_*F2*sqrt(S2)) ); } tmp adjointkOmegaSST::GbyNu ( const volScalarField::Internal& GbyNu0, const volScalarField::Internal& F2, const volScalarField::Internal& S2 ) const { return min ( GbyNu0, (c1_/a1_)*betaStar_*omega()() *max(a1_*omega()(), b1_*F2*sqrt(S2)) ); } tmp adjointkOmegaSST::zeroFirstCell() { auto tzeroFirstCell = volScalarField::New ( "zeroFirstCell", IOobject::NO_REGISTER, mesh_, dimensionedScalar(dimless, Foam::one{}) ); auto& zeroFirstCell = tzeroFirstCell.ref(); firstCellIDs_.resize(mesh_.nCells(), -1); label counter(0); for (const fvPatchScalarField& omegab : omega().boundaryField()) { const fvPatch& patch = omegab.patch(); if (isA(omegab)) { const label patchi = patch.index(); const labelUList& faceCells = patch.faceCells(); fvPatchScalarField& bf = zeroFirstCell.boundaryFieldRef()[patchi]; forAll(faceCells, faceI) { const label cellI = faceCells[faceI]; zeroFirstCell[cellI] = 0.; bf[faceI] = 0.; firstCellIDs_[counter++] = cellI; } } } firstCellIDs_.setSize(counter); zeroFirstCell.correctBoundaryConditions(); return tzeroFirstCell; } tmp adjointkOmegaSST::dR_dnut() { const volVectorField& U = primalVars_.U(); const volVectorField& Ua = adjointVars_.UaInst(); word scheme("coeffsDiff"); tmp tdR_dnut ( dNutdbMult(U, Ua, nutRef(), scheme) + dNutdbMult(k(), ka(), alphaK_, nutRef(), scheme) + dNutdbMult(omega(), zeroFirstCell_*wa(), alphaOmega_, nutRef(), scheme) - case_1_Pk_*ka()*GbyNu0_*zeroFirstCell_ ); volScalarField& dRdnut = tdR_dnut.ref(); forAll(mesh_.boundary(), pI) { const fvPatch& patch = mesh_.boundary()[pI]; const fvPatchScalarField& nutb = nutRef().boundaryField()[pI]; const labelUList& faceCells = patch.faceCells(); if (isA(nutb)) { fvPatchScalarField& bf = dRdnut.boundaryFieldRef()[pI]; const scalarField kSnGrad(k().boundaryField()[pI].snGrad()); const scalarField omegaSnGrad ( omega().boundaryField()[pI].snGrad() ); const fvPatchScalarField& akb = alphaK_.boundaryField()[pI]; const fvPatchScalarField& aOmegab = alphaOmega_.boundaryField()[pI]; const vectorField USnGrad(U.boundaryField()[pI].snGrad()); const fvPatchTensorField& gradUb = gradU_.boundaryField()[pI]; const vectorField nf(mesh_.boundary()[pI].nf()); forAll(faceCells, fI) { const label cI(faceCells[fI]); bf[fI] = - wa()[cI]*zeroFirstCell_[cI]*aOmegab[fI]*omegaSnGrad[fI] - ka()[cI]*akb[fI]*kSnGrad[fI] - (Ua[cI] & (USnGrad[fI] + (dev2(gradUb[fI]) & nf[fI]))); } } } return tdR_dnut; } tmp adjointkOmegaSST::dnut_domega ( const volScalarField& F2, const volScalarField& S, const volScalarField& case_1_nut, const volScalarField& case_2_nut, const volScalarField& case_3_nut ) const { return ( - case_1_nut*k()/sqr(omega()) - a1_*k()/(b1_*S*F2*F2)*dF2_domega(F2, case_2_nut, case_3_nut) ); } tmp adjointkOmegaSST::dnut_dk ( const volScalarField& F2, const volScalarField& S, const volScalarField& case_2_nut ) const { return ( a1_/max(a1_*omega(), b1_*F2*S) - a1_*k()/(b1_*S*F2*F2)*dF2_dk(F2, case_2_nut) ); } tmp adjointkOmegaSST::dF2_domega ( const volScalarField& F2, const volScalarField& case_2_nut, const volScalarField& case_3_nut ) const { tmp arg2 = min ( max ( (scalar(2)/betaStar_)*sqrt(k())/(omega()*y_), scalar(500)*nu()/(sqr(y_)*omega()) ), scalar(100) ); return - scalar(2)*arg2*(1 - F2*F2)* ( case_2_nut*scalar(2)*sqrt(k())/(betaStar_*sqr(omega())*y_) + case_3_nut*scalar(500)*nu()/sqr(omega()*y_) ); } tmp adjointkOmegaSST::dF2_dk ( const volScalarField& F2, const volScalarField& case_2_nut ) const { tmp arg2 = min ( max ( (scalar(2)/betaStar_)*sqrt(k())/(omega()*y_), scalar(500)*nu()/(sqr(y_)*omega()) ), scalar(100) ); return case_2_nut*scalar(2)*arg2*(1 - F2*F2) /(betaStar_*omega()*y_*sqrt(k())); } tmp adjointkOmegaSST::dGPrime_domega() const { return ( case_2_GPrime_*c1_*betaStar_/a1_ *( max(a1_*omega(), b1_*F2_*S_) + case_1_nut_*a1_*omega() + (scalar(1) - case_1_nut_)*omega()*b1_*S_ *dF2_domega(F2_, case_2_nut_, case_3_nut_) ) ); } tmp adjointkOmegaSST::dGPrime_dk() const { return case_2_GPrime_*c1_*betaStar_/a1_*omega()*b1_*S_ *dF2_dk(F2_, case_2_nut_); } tmp adjointkOmegaSST::dR_dF1() const { const volVectorField& U = primalVars_.U(); const surfaceScalarField& phi = primalVars_.phi(); tmp tGPrime = GbyNu(GbyNu0_, F2_, S2_); tmp tdivU = fvc::div(fvc::absolute(phi, U)); word scheme("coeffsDiff"); tmp tdRdF1 ( nutRef() *( coeffsDifferentiation(k(), ka(), scheme)*(alphaK1_ - alphaK2_) + coeffsDifferentiation(omega(), zeroFirstCell_*wa(), scheme) *(alphaOmega1_ - alphaOmega2_) ) ); volScalarField& dRdF1 = tdRdF1.ref(); typedef fixedValueFvPatchScalarField fixedValue; typedef zeroGradientFvPatchScalarField zeroGrad; typedef omegaWallFunctionFvPatchScalarField omegaWF; forAll(mesh_.boundary(), pI) { const fvPatchScalarField& kb = k().boundaryField()[pI]; const fvPatchScalarField& omegab = omega().boundaryField()[pI]; fvPatchScalarField& dRdF1b = dRdF1.boundaryFieldRef()[pI]; if ( isA(kb) && (isA(omegab) || isA(omegab)) ) { dRdF1b = dRdF1b.patchInternalField(); } else if (isA(kb) && isA(omegab) ) { // Note: might need revisiting dRdF1b = dRdF1b.patchInternalField(); } } volScalarField dR_dF1_coeffs ( zeroFirstCell_*wa() *( (gamma1_ - gamma2_)*((2.0/3.0)*omega()*tdivU - tGPrime) + omega()*omega()*(beta1_ - beta2_) + CDkOmega_ ) ); forAll(mesh_.boundary(), pI) { const fvPatchScalarField& kb = k().boundaryField()[pI]; const fvPatchScalarField& omegab = omega().boundaryField()[pI]; fvPatchScalarField& dRdF1b = dR_dF1_coeffs.boundaryFieldRef()[pI]; if ( isA(kb) && (isA(omegab) || isA(omegab)) ) { dRdF1b = Zero; } else if (isA(kb) && isA(omegab)) { dRdF1b = dRdF1b.patchInternalField(); } } dRdF1 += dR_dF1_coeffs; return tdRdF1; } tmp adjointkOmegaSST::dF1_domega ( const volScalarField& arg1 ) const { return ( 4*pow3(arg1)*(scalar(1) - F1_*F1_) *( - case_1_F1_*sqrt(k())/(betaStar_*omega()*omega()*y_) - case_2_F1_*scalar(500)*nu()/sqr(omega()*y_) + case_3_F1_*scalar(4)*alphaOmega2_*k()/sqr(CDkOmegaPlus_*y_) *CDkOmega_/omega() ) ); } tmp adjointkOmegaSST::dF1_dGradOmega ( const volScalarField& arg1 ) const { return ( - case_3_F1_*scalar(4)*pow3(arg1)*(scalar(1) - F1_*F1_) *scalar(8)*k()*sqr(alphaOmega2_/(CDkOmegaPlus_*y_))/omega()*gradK_ ); } tmp adjointkOmegaSST::waEqnSourceFromF1() const { tmp arg1 = min ( min ( max ( (scalar(1)/betaStar_)*sqrt(k())/(omega()*y_), scalar(500)*nu()/(sqr(y_)*omega()) ), (4*alphaOmega2_)*k()/(CDkOmegaPlus_*sqr(y_)) ), scalar(10) ); volScalarField dR_dF1(this->dR_dF1()); volScalarField dF1_domega(this->dF1_domega(arg1)); volVectorField dF1_dGradOmega(this->dF1_dGradOmega(arg1)); surfaceScalarField dR_dGradOmega ( interpolationScheme("div(dR_dGradOmega)")(). interpolate(dR_dF1*dF1_dGradOmega) & mesh_.Sf() ); return ( dR_dF1*dF1_domega - fvc::div(dR_dGradOmega) ); } tmp adjointkOmegaSST::waEqnSourceFromCDkOmega() const { tmp tsource ( 2*zeroFirstCell_*(1 - F1_)*alphaOmega2_/omega()*wa()*gradK_ ); volVectorField& source = tsource.ref(); forAll(mesh_.boundary(), pI) { const fvPatchScalarField& omegab = omega().boundaryField()[pI]; fvPatchVectorField& sourceb = source.boundaryFieldRef()[pI]; if ( isA(omegab) || isA(omegab) ) { sourceb = Zero; } else if (isA(omegab)) { sourceb = sourceb.patchInternalField(); } } surfaceScalarField sourceFaces ( interpolationScheme("sourceAdjontkOmegaSST")(). interpolate(source) & mesh_.Sf() ); return ( // Differentiation of omega in CDkOmega fvm::SuSp(zeroFirstCell_*(1. - F1_)*CDkOmega_/omega(), wa()) // Differentiation of grad(omega) in CDkOmega + fvc::div(sourceFaces) ); } tmp adjointkOmegaSST::kaEqnSourceFromCDkOmega() const { tmp tsource ( 2.*zeroFirstCell_*(1. - F1_)*alphaOmega2_/omega()*wa()*gradOmega_ ); volVectorField& source = tsource.ref(); forAll(mesh_.boundary(), pI) { const fvPatchScalarField& kb = k().boundaryField()[pI]; fvPatchVectorField& sourceb = source.boundaryFieldRef()[pI]; if (isA(kb)) { sourceb = Zero; } else if (isA(kb)) { sourceb = sourceb.patchInternalField(); } } return fvc::div ( interpolationScheme("sourceAdjontkOmegaSST")(). interpolate(source) & mesh_.Sf() ); } tmp adjointkOmegaSST::dF1_dk ( const volScalarField& arg1 ) const { return ( 4*pow3(arg1)*(scalar(1) - F1_*F1_) *( case_1_F1_*0.5/(betaStar_*omega()*sqrt(k())*y_) + case_4_F1_*scalar(4)*alphaOmega2_/(CDkOmegaPlus_*sqr(y_)) ) ); } tmp adjointkOmegaSST::dF1_dGradK ( const volScalarField& arg1 ) const { return ( - case_3_F1_*scalar(4)*pow3(arg1)*(scalar(1) - F1_*F1_) *scalar(8)*k()*sqr(alphaOmega2_/(CDkOmegaPlus_*y_))/omega() *gradOmega_ ); } tmp adjointkOmegaSST::kaEqnSourceFromF1() const { tmp arg1 = min ( min ( max ( (scalar(1)/betaStar_)*sqrt(k())/(omega()*y_), scalar(500)*nu()/(sqr(y_)*omega()) ), (4*alphaOmega2_)*k()/(CDkOmegaPlus_*sqr(y_)) ), scalar(10) ); volScalarField dR_dF1(this->dR_dF1()); volScalarField dF1_dk(this->dF1_dk(arg1)); volVectorField dF1_dGradK(this->dF1_dGradK(arg1)); surfaceScalarField dR_dGradK ( interpolationScheme("div(dR_dGradK)")(). interpolate(dR_dF1*dF1_dGradK) & mesh_.Sf() ); return ( dR_dF1*dF1_dk - fvc::div(dR_dGradK) ); } tmp adjointkOmegaSST::coeffsDifferentiation ( const volScalarField& primalField, const volScalarField& adjointField, const word& schemeName ) const { tmp> scheme (interpolationScheme(schemeName)); surfaceScalarField snGradPrimal(fvc::snGrad(primalField)*mesh_.magSf()); surfaceScalarField flux(scheme().interpolate(adjointField)*snGradPrimal); forAll(mesh_.boundary(), pI) { const fvPatchScalarField& primalbf = primalField.boundaryField()[pI]; if (isA(primalbf)) { // Needless, but just to be safe snGradPrimal.boundaryFieldRef()[pI] = Zero; flux.boundaryFieldRef()[pI] = Zero; } else if (isA(primalbf)) { // Note: to be potentially revisited snGradPrimal.boundaryFieldRef()[pI] = Zero; flux.boundaryFieldRef()[pI] = Zero; } } return (fvc::div(flux) - adjointField*fvc::div(snGradPrimal)); } tmp adjointkOmegaSST::dNutdbMult ( const volScalarField& primalField, const volScalarField& adjointField, const volScalarField& coeffField, const volScalarField& bcField, const word& schemeName ) const { tmp> scheme (interpolationScheme(schemeName)); surfaceScalarField snGradPrimal(fvc::snGrad(primalField)*mesh_.magSf()); surfaceScalarField flux(scheme().interpolate(adjointField)*snGradPrimal); forAll(mesh_.boundary(), pI) { const fvPatchScalarField& bc = bcField.boundaryField()[pI]; if (isA(bc)) { const fvPatchScalarField& coeffFieldb = coeffField.boundaryField()[pI]; snGradPrimal.boundaryFieldRef()[pI] *= coeffFieldb/coeffFieldb.patchInternalField(); flux.boundaryFieldRef()[pI] = Zero; } else if (isA(bc)) { snGradPrimal.boundaryFieldRef()[pI] = Zero; flux.boundaryFieldRef()[pI] = Zero; } } return coeffField*(fvc::div(flux) - adjointField*fvc::div(snGradPrimal)); } tmp adjointkOmegaSST::dNutdbMult ( const volVectorField& U, const volVectorField& Ua, const volScalarField& nut, const word& schemeName ) const { tmp> scheme (interpolationScheme(schemeName)); surfaceVectorField snGradU(fvc::snGrad(U)*mesh_.magSf()); surfaceScalarField flux(scheme().interpolate(Ua) & snGradU); // Terms form the Laplacian part of the momentum stresses forAll(mesh_.boundary(), pI) { const fvPatchScalarField& bc = nut.boundaryField()[pI]; if (isA(bc)) { flux.boundaryFieldRef()[pI] = Zero; } else if (isA(bc)) { snGradU.boundaryFieldRef()[pI] = Zero; flux.boundaryFieldRef()[pI] = Zero; } } // Terms form the tranpose gradient in the momentum stresses const surfaceVectorField& Sf = mesh_.Sf(); surfaceTensorField fluxTranspose ( reverseLinear(mesh_).interpolate(Ua)*Sf ); forAll(mesh_.boundary(), pI) { const fvPatchVectorField& Ub = U.boundaryField()[pI]; if (!isA(Ub)) { const vectorField Uai(Ua.boundaryField()[pI].patchInternalField()); const vectorField& Sfb = Sf.boundaryField()[pI]; fluxTranspose.boundaryFieldRef()[pI] = Uai*Sfb; } } volScalarField M(dev2(gradU_) && fvc::div(fluxTranspose)); const DimensionedField& V = mesh_.V(); forAll(mesh_.boundary(), pI) { const fvPatchScalarField& bc = nut.boundaryField()[pI]; if (isA(bc)) { const vectorField Uai(Ua.boundaryField()[pI].patchInternalField()); const tensorField dev2GradU ( dev2(gradU_.boundaryField()[pI].patchInternalField()) ); const vectorField& Sfb = Sf.boundaryField()[pI]; const labelUList& faceCells = mesh_.boundary()[pI].faceCells(); forAll(faceCells, fI) { const label celli = faceCells[fI]; M[celli] -= ((Uai[fI] & dev2GradU[fI]) & Sfb[fI])/V[celli]; } } } M.correctBoundaryConditions(); //surfaceScalarField fluxTranspose = // fvc::interpolate(UaGradU, schemeName) & mesh_.Sf(); //forAll(mesh_.boundary(), pI) //{ // const fvPatchScalarField& bc = nut.boundaryField()[pI]; // const vectorField& Sf = mesh_.boundary()[pI].Sf(); // if (isA(bc)) // { // fluxTranspose.boundaryFieldRef()[pI] = // ( // UaGradU.boundaryField()[pI].patchInternalField() // - ( // Ua.boundaryField()[pI].patchInternalField() // & gradU_.boundaryField()[pI] // ) // ) & Sf; // } // else if (isA(bc)) // { // fluxTranspose.boundaryFieldRef()[pI] = // UaGradU.boundaryField()[pI].patchInternalField() & Sf; // } //} return fvc::div(flux) - (Ua & fvc::div(snGradU)) + M; //fvc::div(flux + fluxTranspose) - (Ua & fvc::div(snGradU)); } tmp adjointkOmegaSST::convectionMeanFlowSource ( const volScalarField& primalField, const volScalarField& adjointField ) const { // Grab the interpolation scheme from the primal convection term tmp> primalInterpolationScheme ( convectionScheme(primalField.name()) ); surfaceVectorField interpolatedPrimal ( primalInterpolationScheme().interpolate(primalField)*mesh_.Sf() ); surfaceVectorField flux ( //reverseLinear(mesh_).interpolate(adjointField) linear(mesh_).interpolate(adjointField) *interpolatedPrimal ); const volVectorField& U = primalVars_.U(); forAll(mesh_.boundary(), pI) { const fvPatchVectorField& bc = U.boundaryField()[pI]; if (isA(bc)) { flux.boundaryFieldRef()[pI] = Zero; } else if (isA(bc)) { interpolatedPrimal.boundaryFieldRef()[pI] = Zero; flux.boundaryFieldRef()[pI] = Zero; } } return (-fvc::div(flux) + adjointField*fvc::div(interpolatedPrimal)); } tmp adjointkOmegaSST::GMeanFlowSource ( tmp& GbyNuMult ) const { surfaceVectorField flux ( mesh_.Sf() & reverseLinear(mesh_).interpolate(GbyNuMult()) ); const volVectorField& U = primalVars_.U(); forAll(mesh_.boundary(), pI) { const fvPatchVectorField& bc = U.boundaryField()[pI]; if (isA(bc)) { flux.boundaryFieldRef()[pI] = Zero; } else if (isA(bc)) { flux.boundaryFieldRef()[pI] = mesh_.boundary()[pI].Sf() & GbyNuMult().boundaryField()[pI].patchInternalField(); } } return fvc::div(flux); } tmp adjointkOmegaSST::divUMeanFlowSource ( tmp& divUMult ) const { surfaceVectorField flux ( mesh_.Sf()*reverseLinear(mesh_).interpolate(divUMult()) ); const volVectorField& U = primalVars_.U(); forAll(mesh_.boundary(), pI) { const fvPatchVectorField& bc = U.boundaryField()[pI]; if (isA(bc)) { flux.boundaryFieldRef()[pI] = Zero; } else if (isA(bc)) { flux.boundaryFieldRef()[pI] = mesh_.boundary()[pI].Sf() *divUMult().boundaryField()[pI].patchInternalField(); } } divUMult.clear(); return -fvc::div(flux); } tmp adjointkOmegaSST::diffusionNutMeanFlowMult ( const volScalarField& primalField, const volScalarField& adjointField, const volScalarField& coeffField ) const { // Note: we could grab the snGrad scheme from the diffusion term directly surfaceScalarField snGradPrimal(fvc::snGrad(primalField)*mesh_.magSf()); surfaceScalarField flux ( reverseLinear(mesh_).interpolate(adjointField)*snGradPrimal ); const volVectorField& U = primalVars_.U(); forAll(mesh_.boundary(), pI) { const fvPatchVectorField& bc = U.boundaryField()[pI]; if (!isA(bc)) { flux.boundaryFieldRef()[pI] = Zero; snGradPrimal.boundaryFieldRef()[pI] = Zero; } } return (fvc::div(flux) - adjointField*fvc::div(snGradPrimal))*coeffField; } tmp adjointkOmegaSST::nutMeanFlowSource ( tmp& mult, const volScalarField& F2, const volScalarField& S, const volScalarField& case_1_nut, const volTensorField& gradU ) const { volSymmTensorField M ( mult*a1_*k()*(1 - case_1_nut)/(b1_*F2*S*S*S)*twoSymm(gradU) ); M.correctBoundaryConditions(); mult.clear(); surfaceVectorField returnFieldFlux ( mesh_.Sf() & reverseLinear(mesh_).interpolate(M) ); const volVectorField& U = primalVars_.U(); forAll(mesh_.boundary(), pI) { const fvPatchVectorField& bc = U.boundaryField()[pI]; if (isA(bc)) { returnFieldFlux.boundaryFieldRef()[pI] = Zero; } else if (isA(bc)) { returnFieldFlux.boundaryFieldRef()[pI] = mesh_.boundary()[pI].Sf() & M.boundaryField()[pI].patchInternalField(); } } // Note: potentially missing contributions form patches with a calculated // nut bc return fvc::div(returnFieldFlux); } void adjointkOmegaSST::addWallFunctionTerms ( fvScalarMatrix& kaEqn, const volScalarField& dR_dnut ) { // Add source term from the differentiation of nutWallFunction scalarField& source = kaEqn.source(); const DimensionedField& V = mesh_.V(); const volScalarField& ka = this->ka(); const volScalarField& wa = this->wa(); const volScalarField& k = this->k(); const volScalarField& omega = this->omega(); forAll(nutRef().boundaryFieldRef(), patchi) { fvPatchScalarField& nutWall = nutRef().boundaryFieldRef()[patchi]; if (isA(nutWall)) { const fvPatch& patch = mesh_.boundary()[patchi]; const scalarField& magSf = patch.magSf(); const autoPtr& turbModel = primalVars_.turbulence(); const scalarField& y = turbModel().y()[patchi]; const tmp tnuw = turbModel().nu(patchi); const scalarField& nuw = tnuw(); const nutWallFunctionFvPatchScalarField& nutWF = refCast(nutWall); const wallFunctionCoefficients& wallCoeffs = nutWF.wallCoeffs(); const scalar Cmu = wallCoeffs.Cmu(); const scalar kappa = wallCoeffs.kappa(); const scalar E = wallCoeffs.E(); const scalar yPlusLam = wallCoeffs.yPlusLam(); const scalar Cmu25 = pow025(Cmu); const labelUList& faceCells = patch.faceCells(); const fvPatchScalarField& dR_dnutw = dR_dnut.boundaryField()[patchi]; const fvPatchScalarField& omegaw = omega.boundaryField()[patchi]; bool addTermsFromOmegaWallFuction (isA(omegaw)); const fvPatchVectorField& Uw = primalVars_.U().boundaryField()[patchi]; const scalarField magGradUw(mag(Uw.snGrad())); forAll(nuw, facei) { const label celli = faceCells[facei]; const scalar sqrtkCell(sqrt(k[celli])); const scalar yPlus = Cmu25*y[facei]*sqrtkCell/nuw[facei]; const scalar logEyPlus = log(E*yPlus); const scalar dnut_dyPlus = nuw[facei]*kappa*(logEyPlus - 1)/sqr(logEyPlus); const scalar dyPlus_dk = Cmu25*y[facei]/(2*nuw[facei]*sqrtkCell); const scalar dnut_dk = dnut_dyPlus*dyPlus_dk; if (yPlusLam < yPlus) { // Terms from nutkWallFunction source[celli] -= dR_dnutw[facei]*dnut_dk*magSf[facei]; } if (addTermsFromOmegaWallFuction) { const scalar denom(Cmu25*kappa*y[facei]); const scalar omegaLog(sqrtkCell/denom); // Terms from omegaLog in omegaWallFunction source[celli] += wa[celli]*omegaLog/omega[celli] /(2*sqrtkCell*denom); // Terms from G at the first cell off the wall source[celli] += case_1_Pk_[celli]*ka[celli]*V[celli] *( (nutWall[facei] + nuw[facei]) *magGradUw[facei] *Cmu25 /(2.0*sqrtkCell*kappa*y[facei]) ); if (yPlusLam < yPlus) { source[celli] += case_1_Pk_[celli]*ka[celli]*V[celli] *dnut_dk *magGradUw[facei] *Cmu25*sqrtkCell /(kappa*y[facei]); } } } } } } void adjointkOmegaSST::updatePrimalRelatedFields() { if (changedPrimalSolution_) { Info<< "Updating primal-based fields of the adjoint turbulence " << "model ..." << endl; const volVectorField& U = primalVars_.U(); gradU_ = fvc::grad(U); gradOmega_ = fvc::grad(omega()); gradK_ = fvc::grad(k()); S2_ = 2*magSqr(symm(gradU_)) + dimensionedScalar(dimless/sqr(dimTime), 1.e-21); S_ = sqrt(S2_); GbyNu0_ = gradU_ && devTwoSymm(gradU_); // Instead of computing G directly here, delegate to RASModelVariables // to make sure G is computed consistently when the primal fields are // averaged. The local value computed here is just used to update // the switch fields /* volScalarField G(primalVars_.turbulence()->GName(), nutRef()*GbyNu0_); omega().correctBoundaryConditions(); */ volScalarField G ( IOobject ( IOobject::scopedName(type(), "G"), mesh_.time().timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimArea/pow3(dimTime), Zero) ); G.ref() = primalVars_.RASModelVariables()->G()(); CDkOmega_ = (2*alphaOmega2_)*(gradK_ & gradOmega_)/omega(); CDkOmegaPlus_ = max ( CDkOmega_, dimensionedScalar("1.0e-10", dimless/sqr(dimTime), 1.0e-10) ); F1_ = F1(); F2_ = F2(); case_1_Pk_ = neg(G - c1_*betaStar_*k()*omega()); case_2_Pk_ = pos0(G - c1_*betaStar_*k()*omega()); case_3_Pk_ = neg(a1_*omega() - b1_*F2_*S_); alphaK_ = alphaK(F1_); alphaOmega_ = alphaOmega(F1_); beta_ = beta(F1_); gamma_ = gamma(F1_); // Switch fields for F1 { volScalarField arg1_C3 ( (scalar(1)/betaStar_)*sqrt(k())/(omega()*y_) - scalar(500)*nu()/(sqr(y_)*omega()) ); volScalarField arg1_C2 ( max ( (scalar(1)/betaStar_)*sqrt(k())/(omega()*y_), scalar(500)*nu()/(sqr(y_)*omega()) ) - (4*alphaOmega2_)*k()/(CDkOmegaPlus_*sqr(y_)) ); volScalarField arg1_C1 ( min ( max ( (scalar(1)/betaStar_)*sqrt(k())/(omega()*y_), scalar(500)*nu()/(sqr(y_)*omega()) ), (4*alphaOmega2_)*k()/(CDkOmegaPlus_*sqr(y_)) ) - scalar(10) ); volScalarField CDkOmegaPlus_C1 ( CDkOmega_ - dimensionedScalar("1.0e-10", dimless/sqr(dimTime), 1.0e-10) ); case_1_F1_ = pos(arg1_C3)*neg(arg1_C2)*neg(arg1_C1); case_2_F1_ = neg0(arg1_C3)*neg(arg1_C2)*neg(arg1_C1); case_3_F1_ = pos0(arg1_C2)*neg(arg1_C1)*pos(CDkOmegaPlus_C1); case_4_F1_ = pos0(arg1_C2)*neg(arg1_C1); } // Switch fields for nut { volScalarField nut_C1(a1_*omega() - b1_*F2_*S_); volScalarField arg2_C2 ( (scalar(2)/betaStar_)*sqrt(k())/(omega()*y_) - scalar(500)*nu()/(sqr(y_)*omega()) ); volScalarField arg2_C1 ( max ( (scalar(2)/betaStar_)*sqrt(k())/(omega()*y_), scalar(500)*nu()/(sqr(y_)*omega()) ) - scalar(100) ); case_1_nut_ = pos(nut_C1); case_2_nut_ = neg0(nut_C1)*pos(arg2_C2)*neg(arg2_C1); case_3_nut_ = neg0(nut_C1)*neg0(arg2_C2)*neg(arg2_C1); } { volScalarField GPrime_C1 ( GbyNu0_ - (c1_/a1_)*betaStar_*omega()*max(a1_*omega(), b1_*F2_*S_) ); case_1_GPrime_ = neg(GPrime_C1); case_2_GPrime_ = pos0(GPrime_C1); } dnut_domega_ = dnut_domega(F2_, S_, case_1_nut_, case_2_nut_, case_3_nut_); dnut_dk_ = dnut_dk(F2_, S_, case_2_nut_); DOmegaEff_ = DomegaEff(F1_); DkEff_ = DkEff(F1_); changedPrimalSolution_ = false; } } tmp> adjointkOmegaSST::convectionScheme ( const word& varName ) const { const surfaceScalarField& phi = primalVars_.phi(); const surfaceScalarField& phiInst = primalVars_.phiInst(); word divEntry("div(" + phiInst.name() + ',' + varName +')'); ITstream& divScheme = mesh_.divScheme(divEntry); // Skip the first entry which might be 'bounded' or 'Gauss'. // If it is 'bounded', skip the second entry as well word discarded(divScheme); if (discarded == "bounded") { discarded = word(divScheme); } return surfaceInterpolationScheme::New(mesh_, phi, divScheme); } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // adjointkOmegaSST::adjointkOmegaSST ( incompressibleVars& primalVars, incompressibleAdjointMeanFlowVars& adjointVars, objectiveManager& objManager, const word& adjointTurbulenceModelName, const word& modelName ) : adjointRASModel ( modelName, primalVars, adjointVars, objManager, adjointTurbulenceModelName ), kappa_ ( dimensioned::getOrAddToDict ( "kappa", coeffDict_, 0.41 ) ), alphaK1_ ( dimensioned::getOrAddToDict ( "alphaK1", this->coeffDict_, 0.85 ) ), alphaK2_ ( dimensioned::getOrAddToDict ( "alphaK2", this->coeffDict_, 1.0 ) ), alphaOmega1_ ( dimensioned::getOrAddToDict ( "alphaOmega1", this->coeffDict_, 0.5 ) ), alphaOmega2_ ( dimensioned::getOrAddToDict ( "alphaOmega2", this->coeffDict_, 0.856 ) ), gamma1_ ( dimensioned::getOrAddToDict ( "gamma1", this->coeffDict_, 5.0/9.0 ) ), gamma2_ ( dimensioned::getOrAddToDict ( "gamma2", this->coeffDict_, 0.44 ) ), beta1_ ( dimensioned::getOrAddToDict ( "beta1", this->coeffDict_, 0.075 ) ), beta2_ ( dimensioned::getOrAddToDict ( "beta2", this->coeffDict_, 0.0828 ) ), betaStar_ ( dimensioned::getOrAddToDict ( "betaStar", this->coeffDict_, 0.09 ) ), a1_ ( dimensioned::getOrAddToDict ( "a1", this->coeffDict_, 0.31 ) ), b1_ ( dimensioned::getOrAddToDict ( "b1", this->coeffDict_, 1.0 ) ), c1_ ( dimensioned::getOrAddToDict ( "c1", this->coeffDict_, 10.0 ) ), F3_ ( Switch::getOrAddToDict ( "F3", this->coeffDict_, false ) ), y_(primalVars_.RASModelVariables()().d()), //Primal Gradient Fields gradU_ ( IOobject ( "rasModel::gradU", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedTensor(dimless/dimTime, Zero) ), gradOmega_ ( IOobject ( "rasModel::gradOmega", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedVector(dimless/dimTime/dimLength, Zero) ), gradK_ ( IOobject ( "rasModel::gradK", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedVector(dimLength/sqr(dimTime), Zero) ), S2_ ( IOobject ( "S2", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless/sqr(dimTime), Zero) ), S_ ( IOobject ( "kOmegaSST_S", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless/dimTime, Zero) ), GbyNu0_ ( IOobject ( "adjointRASModel::GbyNu0", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless/sqr(dimTime), Zero) ), CDkOmega_ ( IOobject ( "CDkOmega_", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless/sqr(dimTime), Zero) ), CDkOmegaPlus_ ( IOobject ( "CDkOmegaPlus", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless/sqr(dimTime), Zero) ), F1_ ( IOobject ( "F1", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), F2_ ( IOobject ( "F2", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), // Model Field coefficients alphaK_ ( IOobject ( "alphaK", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), alphaOmega_ ( IOobject ( "alphaOmega", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), beta_ ( IOobject ( "beta", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), gamma_ ( IOobject ( "gamma", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), case_1_F1_ ( IOobject ( "case_1_F1", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), case_2_F1_ ( IOobject ( "case_2_F1", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), case_3_F1_ ( IOobject ( "case_3_F1", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), case_4_F1_ ( IOobject ( "case_4_F1", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), case_1_Pk_ ( IOobject ( "case_1_Pk", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), case_2_Pk_ ( IOobject ( "case_2_Pk", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), case_3_Pk_ ( IOobject ( "case_3_Pk", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), case_1_nut_ ( IOobject ( "case_1_nut", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), case_2_nut_ ( IOobject ( "case_2_nut", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), case_3_nut_ ( IOobject ( "case_3_nut", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), case_1_GPrime_ ( IOobject ( "case_1_GPrime", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), case_2_GPrime_ ( IOobject ( "case_2_GPrime", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), // Zero 1rst cell field firstCellIDs_(0), zeroFirstCell_(zeroFirstCell()), // Turbulence model multipliers dnut_domega_ ( IOobject ( "dnut_domega", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(sqr(dimLength), Zero) ), dnut_dk_ ( IOobject ( "dnut_dk", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimTime, Zero) ), DOmegaEff_ ( IOobject ( "DomegaEff", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(nutRef().dimensions(), Zero) ), DkEff_ ( IOobject ( "DkEff", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(nutRef().dimensions(), Zero) ) { adjointTMVariablesBaseNames_.setSize(2); adjointTMVariablesBaseNames_[0] = "ka"; adjointTMVariablesBaseNames_[1] = "wa"; // Read in adjoint fields variablesSet::setField ( adjointTMVariable1Ptr_, mesh_, "ka", adjointVars.solverName(), adjointVars.useSolverNameForFields() ); variablesSet::setField ( adjointTMVariable2Ptr_, mesh_, "wa", adjointVars.solverName(), adjointVars.useSolverNameForFields() ); setMeanFields(); // No sensitivity contributions from the adjoint to the eikonal equation // for the moment includeDistance_ = false; // Update the primal related fields here so that functions computing // sensitivities have the updated fields in case of continuation updatePrimalRelatedFields(); } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // tmp adjointkOmegaSST::devReff() const { const volVectorField& Ua = adjointVars_.UaInst(); return devReff(Ua); } tmp adjointkOmegaSST::devReff ( const volVectorField& U ) const { return tmp::New ( IOobject ( "devRhoReff", runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), -nuEff()*devTwoSymm(fvc::grad(U)) ); } tmp adjointkOmegaSST::divDevReff(volVectorField& Ua) const { tmp tnuEff = nuEff(); const volScalarField& nuEff = tnuEff(); return ( - fvm::laplacian(nuEff, Ua) - fvc::div(nuEff*dev(fvc::grad(Ua)().T())) ); /* WIP const volVectorField& U = primalVars_.U(); const surfaceVectorField& Sf = mesh_.Sf(); tmp tflux = reverseLinear(mesh_).interpolate(Ua)*Sf; surfaceTensorField& flux = tflux.ref(); forAll(mesh_.boundary(), pI) { const fvPatchVectorField& Ub = U.boundaryField()[pI]; if (!isA(Ub)) { const vectorField Uai = Ua.boundaryField()[pI].patchInternalField(); const vectorField& Sfb = Sf.boundaryField()[pI]; flux.boundaryFieldRef()[pI] = Uai*Sfb; } } volTensorField M(nuEff*dev2(fvc::div(flux))); const DimensionedField& V = mesh_.V(); forAll(mesh_.boundary(), pI) { const fvPatchVectorField& Ub = U.boundaryField()[pI]; if (!isA(Ub)) { const fvPatchScalarField& nuEffb = nuEff.boundaryField()[pI]; const vectorField nf = mesh_.boundary()[pI].nf(); const vectorField Uai = Ua.boundaryField()[pI].patchInternalField(); const labelUList& faceCells = mesh_.boundary()[pI].faceCells(); const vectorField& Sfb = Sf.boundaryField()[pI]; forAll(faceCells, fI) { const label celli = faceCells[fI]; const tensor t(dev2(Uai[fI]*Sfb[fI])); M[celli] -= nuEffb[fI]*(t - nf[fI]*(nf[fI] & t))/V[celli]; } } } M.correctBoundaryConditions(); surfaceVectorField returnFlux = - (Sf & reverseLinear(mesh_).interpolate(M)); forAll(mesh_.boundary(), pI) { const fvPatchVectorField& Ub = U.boundaryField()[pI]; if (isA(Ub)) { returnFlux.boundaryFieldRef()[pI] = Zero; } else if (isA(Ub)) { const scalarField& deltaCoeffs = mesh_.boundary()[pI].deltaCoeffs(); const fvPatchScalarField& nuEffb = nuEff.boundaryField()[pI]; const vectorField Uai = Ua.boundaryField()[pI].patchInternalField(); const vectorField nf = mesh_.boundary()[pI].nf(); const vectorField& Sfb = Sf.boundaryField()[pI]; returnFlux.boundaryFieldRef()[pI] = - (Sfb & M.boundaryField()[pI].patchInternalField()) + nuEffb*deltaCoeffs*(nf & dev2(Uai*Sfb)); } } return ( - fvm::laplacian(nuEff, Ua) + fvc::div(returnFlux) ); */ } tmp adjointkOmegaSST::nonConservativeMomentumSource() const { return (ka()*gradK_ + wa()*gradOmega_); } tmp adjointkOmegaSST::adjointMeanFlowSource() { tmp tmeanFlowSource ( tmp::New ( IOobject ( "adjointMeanFlowSource" + type(), mesh_.time().timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedVector(dimVelocity/dimTime, Zero) ) ); volVectorField& meanFlowSource = tmeanFlowSource.ref(); // Contributions from the convection terms of the turbulence model meanFlowSource += convectionMeanFlowSource(omega(), zeroFirstCell_*wa()) + convectionMeanFlowSource(k(), ka()); // Contributions from GbyNu, including gradU tmp twoSymmGradU(twoSymm(gradU_)); tmp GbyNuMult ( // First part of GPrime and G from Pk 2.*dev(twoSymmGradU())*zeroFirstCell_ *(wa()*gamma_*case_1_GPrime_ + ka()*nutRef()*case_1_Pk_) // Second part of GPrime + twoSymmGradU()*wa()*zeroFirstCell_*gamma_*case_2_GPrime_ *(1. - case_1_nut_)*c1_/a1_*betaStar_*omega()*b1_*F2_/S_ ); twoSymmGradU.clear(); meanFlowSource += GMeanFlowSource(GbyNuMult); GbyNuMult.clear(); // Contributions from divU tmp divUMult ( (2.0/3.0)*(zeroFirstCell_*wa()*omega()*gamma_ + ka()*k()) ); meanFlowSource += divUMeanFlowSource(divUMult); // Contributions from S2, existing in nut const volVectorField& U = primalVars_.U(); const volVectorField& Ua = adjointVars_.UaInst(); tmp nutMeanFlowSourceMult ( // nut in the diffusion coefficients diffusionNutMeanFlowMult(k(), ka(), alphaK_) + diffusionNutMeanFlowMult(omega(), zeroFirstCell_*wa(), alphaOmega_) + dNutdbMult(U, Ua, nutRef(), "coeffsDiff") // nut in G - ka()*case_1_Pk_*zeroFirstCell_*GbyNu0_ ); meanFlowSource += nutMeanFlowSource ( nutMeanFlowSourceMult, F2_, S_, case_1_nut_, gradU_ ); // G at the first cell includes mag(U.snGrad()) // Add term here forAll(omega().boundaryFieldRef(), patchi) { fvPatchScalarField& omegaWall = omega().boundaryFieldRef()[patchi]; if (isA(omegaWall)) { const fvPatch& patch = mesh_.boundary()[patchi]; const autoPtr& turbModel = primalVars_.turbulence(); const scalarField& y = turbModel().y()[patchi]; const tmp tnuw = turbModel().nu(patchi); const scalarField& nuw = tnuw(); const nutWallFunctionFvPatchScalarField& nutw = refCast (nutRef().boundaryFieldRef()[patchi]); const wallFunctionCoefficients& wallCoeffs = nutw.wallCoeffs(); const scalar Cmu = wallCoeffs.Cmu(); const scalar kappa = wallCoeffs.kappa(); const scalar Cmu25 = pow025(Cmu); const labelUList& faceCells = patch.faceCells(); const fvPatchVectorField& Uw = primalVars_.U().boundaryField()[patchi]; vectorField snGradUw(Uw.snGrad()); const scalarField& deltaCoeffs = patch.deltaCoeffs(); forAll(faceCells, facei) { const label celli = faceCells[facei]; // Volume will be added when meanFlowSource is added to UaEqn meanFlowSource[celli] += ka()[celli]*case_1_Pk_[celli] *(nutw[facei] + nuw[facei]) *snGradUw[facei].normalise() *Cmu25*sqrt(k()[celli]) *deltaCoeffs[facei] /(kappa*y[facei]); } } } return tmeanFlowSource; } tmp adjointkOmegaSST::nutJacobianTMVar1() const { // Compute dnut_dk anew since the current copy of dnut_dk_ // might not be updated const volVectorField& U = primalVars_.U(); tmp S2 ( 2*magSqr(symm(fvc::grad(U))) + dimensionedScalar(dimless/sqr(dimTime), 1.e-21) ); volScalarField S(sqrt(S2)); volScalarField F2(this->F2()); // Computation of nut switches volScalarField nut_C1(a1_*omega() - b1_*F2*S); volScalarField arg2_C2 ( (scalar(2)/betaStar_)*sqrt(k())/(omega()*y_) - scalar(500)*nu()/(sqr(y_)*omega()) ); volScalarField arg2_C1 ( max ( (scalar(2)/betaStar_)*sqrt(k())/(omega()*y_), scalar(500)*nu()/(sqr(y_)*omega()) ) - scalar(100) ); volScalarField case_2_nut(neg0(nut_C1)*pos(arg2_C2)*neg(arg2_C1)); return dnut_dk(F2, S, case_2_nut); } tmp adjointkOmegaSST::nutJacobianTMVar2() const { // Compute dnut_omega anew since the current copy of dnut_domega_ // might not be updated const volVectorField& U = primalVars_.U(); tmp S2 ( 2*magSqr(symm(fvc::grad(U))) + dimensionedScalar(dimless/sqr(dimTime), 1.e-21) ); volScalarField S(sqrt(S2)); volScalarField F2(this->F2()); // Computation of nut switches volScalarField nut_C1(a1_*omega() - b1_*F2*S); volScalarField arg2_C2 ( (scalar(2)/betaStar_)*sqrt(k())/(omega()*y_) - scalar(500)*nu()/(sqr(y_)*omega()) ); volScalarField arg2_C1 ( max ( (scalar(2)/betaStar_)*sqrt(k())/(omega()*y_), scalar(500)*nu()/(sqr(y_)*omega()) ) - scalar(100) ); volScalarField case_1_nut(pos(nut_C1)); volScalarField case_2_nut(neg0(nut_C1)*pos(arg2_C2)*neg(arg2_C1)); volScalarField case_3_nut(neg0(nut_C1)*neg0(arg2_C2)*neg(arg2_C1)); return dnut_domega(F2, S, case_1_nut, case_2_nut, case_3_nut); } tmp adjointkOmegaSST::nutJacobianU ( tmp& dNutdUMult ) const { const volVectorField& U = primalVars_.U(); volTensorField gradU(fvc::grad(U)); tmp S2 ( 2*magSqr(symm(gradU)) + dimensionedScalar(dimless/sqr(dimTime), 1.e-21) ); volScalarField S(sqrt(S2)); volScalarField F2(this->F2()); // Computation of nut switches volScalarField nut_C1(a1_*omega() - b1_*F2*S); volScalarField case_1_nut(pos(nut_C1)); return nutMeanFlowSource(dNutdUMult, F2, S, case_1_nut, gradU); } tmp adjointkOmegaSST::diffusionCoeffVar1(label patchI) const { return ( alphaK_.boundaryField()[patchI]*nutRef().boundaryField()[patchI] + nu()().boundaryField()[patchI] ); } tmp adjointkOmegaSST::diffusionCoeffVar2(label patchI) const { return ( alphaOmega_.boundaryField()[patchI]*nutRef().boundaryField()[patchI] + nu()().boundaryField()[patchI] ); } void adjointkOmegaSST::correct() { adjointRASModel::correct(); if (!adjointTurbulence_) { return; } updatePrimalRelatedFields(); // Primal and adjoint fields const volVectorField& U = primalVars_.U(); const surfaceScalarField& phi = primalVars_.phi(); volScalarField dR_dnut(this->dR_dnut()); volScalarField::Internal divU(fvc::div(fvc::absolute(phi, U))); fv::options& fvOptions(fv::options::New(mesh_)); tmp waEqn ( fvm::div(-phi, wa()) + fvm::SuSp(zeroFirstCell_*fvc::div(phi), wa()) - fvm::laplacian(DOmegaEff_, wa()) + waEqnSourceFromCDkOmega() + waEqnSourceFromF1() + dR_dnut*dnut_domega_ + fvm::Sp(zeroFirstCell_*scalar(2.)*beta_*omega(), wa()) + fvm::SuSp ( zeroFirstCell_()*gamma_*((2.0/3.0)*divU - dGPrime_domega().ref()()), wa() ) - (case_2_Pk_*c1_ - scalar(1))*betaStar_*k()*ka() == fvOptions(wa()) ); // Boundary manipulate changes the diagonal component, so relax has to // come after that waEqn.ref().boundaryManipulate(wa().boundaryFieldRef()); waEqn.ref().relax(); // Sources from the objective should be added after the boundary // manipulation objectiveManager_.addSource(waEqn.ref()); fvOptions.constrain(waEqn.ref()); waEqn.ref().solve(); // Adjoint Turbulent kinetic energy equation tmp kaEqn ( fvm::div(-phi, ka()) + fvm::SuSp(fvc::div(phi), ka()) - fvm::laplacian(DkEff_, ka()) + fvm::Sp(betaStar_*omega(), ka()) - case_2_Pk_()*c1_*betaStar_*omega()()*ka()() + fvm::SuSp(scalar(2.0/3.0)*divU, ka()) + kaEqnSourceFromCDkOmega() + kaEqnSourceFromF1() + dR_dnut()*dnut_dk_() - zeroFirstCell_()*gamma_*dGPrime_dk().ref()()*wa() == fvOptions(ka()) ); kaEqn.ref().relax(); kaEqn.ref().boundaryManipulate(ka().boundaryFieldRef()); addWallFunctionTerms(kaEqn.ref(), dR_dnut); fvOptions.constrain(kaEqn.ref()); // Add sources from the objective functions objectiveManager_.addSource(kaEqn.ref()); kaEqn.ref().solve(); if (adjointVars_.getSolverControl().printMaxMags()) { dimensionedScalar maxwa = max(mag(wa())); dimensionedScalar maxka = max(mag(ka())); Info<< "Max mag (" << wa().name() << ") = " << maxwa.value() << endl; Info<< "Max mag (" << ka().name() << ") = " << maxka.value() << endl; } } const boundaryVectorField& adjointkOmegaSST::adjointMomentumBCSource() const { return adjMomentumBCSourcePtr_(); } const boundaryVectorField& adjointkOmegaSST::wallShapeSensitivities() { boundaryVectorField& wallShapeSens = wallShapeSensitivitiesPtr_(); volTensorField FITerm(FISensitivityTerm()); forAll(mesh_.boundary(), patchi) { vectorField nf(mesh_.boundary()[patchi].nf()); wallShapeSens[patchi] = nf & FITerm.boundaryField()[patchi]; } return wallShapeSens; } const boundaryVectorField& adjointkOmegaSST::wallFloCoSensitivities() { return wallFloCoSensitivitiesPtr_(); } tmp adjointkOmegaSST::distanceSensitivities() { return tmp::New ( IOobject ( "adjointEikonalSource" + type(), runTime_.timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimLength/pow3(dimTime), Zero) ); } tmp adjointkOmegaSST::FISensitivityTerm() { const volVectorField& U = primalVars_.U(); const volScalarField& kInst = primalVars_.RASModelVariables()->TMVar1Inst(); const volScalarField& omegaInst = primalVars_.RASModelVariables()->TMVar2Inst(); tmp arg1 = min ( min ( max ( (scalar(1)/betaStar_)*sqrt(k())/(omega()*y_), scalar(500)*nu()/(sqr(y_)*omega()) ), (4*alphaOmega2_)*k()/(CDkOmegaPlus_*sqr(y_)) ), scalar(10) ); // Interpolation schemes used by the primal convection terms auto kScheme(convectionScheme(kInst.name())); auto omegaScheme(convectionScheme(omegaInst.name())); const surfaceVectorField& Sf = mesh_.Sf(); tmp tFISens ( tmp::New ( IOobject ( type() + "FISensTerm", mesh_.time().timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedTensor(sqr(dimLength)/pow3(dimTime), Zero), fvPatchFieldBase::zeroGradientType() ) ); volTensorField& FISens = tFISens.ref(); FISens = // k convection - ka()*fvc::div ( kScheme().interpolate(k()) *linear(mesh_).interpolate(U)*Sf ) // k diffusion + ka()*T(fvc::grad(DkEff_*gradK_)) - DkEff_*(fvc::grad(ka())*gradK_) // omega convection - wa()*zeroFirstCell_*fvc::div ( omegaScheme().interpolate(omega()) *linear(mesh_).interpolate(U)*Sf ) // omega diffusion + wa()*zeroFirstCell_*T(fvc::grad(DOmegaEff_*gradOmega_)) - DOmegaEff_*(fvc::grad(wa()*zeroFirstCell_)*gradOmega_) // terms including GbyNu0 + ( case_1_GPrime_*wa()*gamma_ + case_1_Pk_*ka()*nutRef() )*2.*T(gradU_ & devTwoSymm(gradU_))*zeroFirstCell_ // S2 (includes contribution from nut in UEqn as well) + ( dR_dnut()*a1_*k()/(b1_*S_*S_*S_*F2_) + wa()*zeroFirstCell_*gamma_*case_2_GPrime_ *(c1_/a1_)*betaStar_*omega()*b1_*F2_/S_ )*T(gradU_ & twoSymm(gradU_))*(1. - case_1_nut_) // CDkOmega in omegaEqn + 2.*wa()*(1. - F1_)*alphaOmega2_/omega()*zeroFirstCell_ *(gradOmega_*gradK_ + gradK_*gradOmega_) // F1 - dR_dF1() *(dF1_dGradK(arg1)*gradK_ + dF1_dGradOmega(arg1)*gradOmega_); FISens.correctBoundaryConditions(); return tFISens; } tmp adjointkOmegaSST::topologySensitivities ( const word& designVarsName ) const { fv::options& fvOptions(fv::options::New(this->mesh_)); auto tres(tmp::New(mesh_.nCells(), Zero)); // Sensitivity from the source term in the k equation scalarField auxSens (k().primitiveField()*ka().primitiveField()); sensitivityTopO::postProcessSens ( tres.ref(), auxSens, fvOptions, k().name(), designVarsName ); // Sensitivity from the source term in the omega equation auxSens = omega().primitiveField()*wa().primitiveField(); sensitivityTopO::postProcessSens ( tres.ref(), auxSens, fvOptions, omega().name(), designVarsName ); return tres; } void adjointkOmegaSST::nullify() { variablesSet::nullifyField(ka()); variablesSet::nullifyField(wa()); } bool adjointkOmegaSST::read() { if (adjointRASModel::read()) { kappa_.readIfPresent(coeffDict()); alphaK1_.readIfPresent(this->coeffDict()); alphaK2_.readIfPresent(this->coeffDict()); alphaOmega1_.readIfPresent(this->coeffDict()); alphaOmega2_.readIfPresent(this->coeffDict()); gamma1_.readIfPresent(this->coeffDict()); gamma2_.readIfPresent(this->coeffDict()); beta1_.readIfPresent(this->coeffDict()); beta2_.readIfPresent(this->coeffDict()); betaStar_.readIfPresent(this->coeffDict()); a1_.readIfPresent(this->coeffDict()); b1_.readIfPresent(this->coeffDict()); c1_.readIfPresent(this->coeffDict()); F3_.readIfPresent("F3", this->coeffDict()); return true; } else { return false; } } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // } // End namespace adjointRASModels } // End namespace incompressible } // End namespace Foam // ************************************************************************* //