From 79ec421e552f58dc6a2adb96fc1fed5807f01670 Mon Sep 17 00:00:00 2001
From: Henry <Henry>
Date: Tue, 27 Jan 2015 15:06:03 +0000
Subject: [PATCH] 
 src/TurbulenceModels/incompressible/turbulentTransportModels/RAS/kkLOmega:
 Corrected errors in implementation and from original paper according to    
 Furst, J. (2013).     Numerical simulation of transitional flows with laminar
 kinetic energy.     Engineering MECHANICS, 20(5), 379-388.

Thanks to Jan-Niklas Klatt for analysing problems with and correcting
the implementation and testing corrections to the model proposed by
Furst.
---
 .../incompressibleTurbulenceModel.H           |   3 +
 .../RAS/kkLOmega/kkLOmega.C                   | 193 ++++++++++--------
 .../RAS/kkLOmega/kkLOmega.H                   |  41 +++-
 3 files changed, 141 insertions(+), 96 deletions(-)

diff --git a/src/TurbulenceModels/incompressible/incompressibleTurbulenceModel.H b/src/TurbulenceModels/incompressible/incompressibleTurbulenceModel.H
index 251bfd179f1..99528cfb187 100644
--- a/src/TurbulenceModels/incompressible/incompressibleTurbulenceModel.H
+++ b/src/TurbulenceModels/incompressible/incompressibleTurbulenceModel.H
@@ -61,6 +61,9 @@ protected:
 
         geometricOneField rho_;
 
+
+    // Protected member functions
+
         //- ***HGW Temporary function to be removed when the run-time selectable
         //  thermal transport layer is complete
         virtual void correctNut()
diff --git a/src/TurbulenceModels/incompressible/turbulentTransportModels/RAS/kkLOmega/kkLOmega.C b/src/TurbulenceModels/incompressible/turbulentTransportModels/RAS/kkLOmega/kkLOmega.C
index a32ce3b4afe..cdbf2a97c82 100644
--- a/src/TurbulenceModels/incompressible/turbulentTransportModels/RAS/kkLOmega/kkLOmega.C
+++ b/src/TurbulenceModels/incompressible/turbulentTransportModels/RAS/kkLOmega/kkLOmega.C
@@ -56,16 +56,16 @@ tmp<volScalarField> kkLOmega::fINT() const
     (
         min
         (
-            kl_/(Cint_*(kl_ + kt_ + kMin_)),
+            kt_/(Cint_*(kl_ + kt_ + kMin_)),
             dimensionedScalar("1.0", dimless, 1.0)
         )
     );
 }
 
 
-tmp<volScalarField> kkLOmega::fSS(const volScalarField& omega) const
+tmp<volScalarField> kkLOmega::fSS(const volScalarField& Omega) const
 {
-    return(exp(-sqr(Css_*nu()*omega/(kt_ + kMin_))));
+    return(exp(-sqr(Css_*nu()*Omega/(kt_ + kMin_))));
 }
 
 
@@ -75,16 +75,17 @@ tmp<volScalarField> kkLOmega::Cmu(const volScalarField& S) const
 }
 
 
-tmp<volScalarField> kkLOmega::BetaTS(const volScalarField& Rew) const
+tmp<volScalarField> kkLOmega::BetaTS(const volScalarField& ReOmega) const
 {
-    return(scalar(1) - exp(-sqr(max(Rew - CtsCrit_, scalar(0)))/Ats_));
+    return(scalar(1) - exp(-sqr(max(ReOmega - CtsCrit_, scalar(0)))/Ats_));
 }
 
 
 tmp<volScalarField> kkLOmega::fTaul
 (
     const volScalarField& lambdaEff,
-    const volScalarField& ktL
+    const volScalarField& ktL,
+    const volScalarField& Omega
 ) const
 {
     return
@@ -97,7 +98,7 @@ tmp<volScalarField> kkLOmega::fTaul
             (
                 sqr
                 (
-                    lambdaEff*omega_
+                    lambdaEff*Omega
                   + dimensionedScalar
                     (
                         "ROOTVSMALL",
@@ -133,8 +134,8 @@ tmp<volScalarField> kkLOmega::fOmega
         scalar(1)
       - exp
         (
-            -0.41
-           * pow4
+           -0.41
+           *pow4
             (
                 lambdaEff
               / (
@@ -152,7 +153,7 @@ tmp<volScalarField> kkLOmega::fOmega
 }
 
 
-tmp<volScalarField> kkLOmega::gammaBP(const volScalarField& omega) const
+tmp<volScalarField> kkLOmega::phiBP(const volScalarField& Omega) const
 {
     return
     (
@@ -162,11 +163,11 @@ tmp<volScalarField> kkLOmega::gammaBP(const volScalarField& omega) const
             (
                 kt_/nu()
              / (
-                    omega
+                    Omega
                   + dimensionedScalar
                     (
                         "ROTVSMALL",
-                        omega.dimensions(),
+                        Omega.dimensions(),
                         ROOTVSMALL
                     )
                 )
@@ -179,7 +180,7 @@ tmp<volScalarField> kkLOmega::gammaBP(const volScalarField& omega) const
 }
 
 
-tmp<volScalarField> kkLOmega::gammaNAT
+tmp<volScalarField> kkLOmega::phiNAT
 (
     const volScalarField& ReOmega,
     const volScalarField& fNatCrit
@@ -200,12 +201,19 @@ tmp<volScalarField> kkLOmega::gammaNAT
 }
 
 
+tmp<volScalarField> kkLOmega::D(const volScalarField& k) const
+{
+    return nu()*magSqr(fvc::grad(sqrt(k)));
+}
+
+
 // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
 
 void kkLOmega::correctNut()
 {
-    nut_ = kt_/omega_;
-    nut_.correctBoundaryConditions();
+    // Currently this function is not implemented due to the complexity of
+    // evaluating nut.  Better calculate nut at the end of correct()
+    notImplemented("kkLOmega::correctNut()");
 }
 
 
@@ -490,11 +498,11 @@ kkLOmega::kkLOmega
         ),
         mesh_
     ),
-    omega_
+    kl_
     (
         IOobject
         (
-            IOobject::groupName("omega", U.group()),
+            IOobject::groupName("kl", U.group()),
             runTime_.timeName(),
             mesh_,
             IOobject::MUST_READ,
@@ -502,11 +510,11 @@ kkLOmega::kkLOmega
         ),
         mesh_
     ),
-    kl_
+    omega_
     (
         IOobject
         (
-            IOobject::groupName("kl", U.group()),
+            IOobject::groupName("omega", U.group()),
             runTime_.timeName(),
             mesh_,
             IOobject::MUST_READ,
@@ -514,17 +522,26 @@ kkLOmega::kkLOmega
         ),
         mesh_
     ),
-    y_(wallDist::New(mesh_).y())
+    epsilon_
+    (
+        IOobject
+        (
+            "epsilon",
+            runTime_.timeName(),
+            mesh_
+        ),
+        kt_*omega_ + D(kl_) + D(kt_)
+    ),    y_(wallDist::New(mesh_).y())
 {
     bound(kt_, kMin_);
     bound(kl_, kMin_);
     bound(omega_, omegaMin_);
+    bound(epsilon_, epsilonMin_);
 
     if (type == typeName)
     {
-        // This is only an approximate nut, so only good for initialization
-        // not restart
-        // correctNut();
+        // Evaluating nut_ is complex so start from the field read from file
+        nut_.correctBoundaryConditions();
 
         printCoeffs(type);
     }
@@ -584,22 +601,28 @@ void kkLOmega::correct()
         return;
     }
 
+    const volScalarField lambdaT(sqrt(kt_)/(omega_ + omegaMin_));
 
-    const volScalarField kT(kt_ + kl_);
-
-    const volScalarField lambdaT(sqrt(kT)/(omega_ + omegaMin_));
     const volScalarField lambdaEff(min(Clambda_*y_, lambdaT));
 
     const volScalarField fw
     (
-        lambdaEff/(lambdaT + dimensionedScalar("SMALL", dimLength, ROOTVSMALL))
+        pow
+        (
+            lambdaEff
+           /(lambdaT + dimensionedScalar("SMALL", dimLength, ROOTVSMALL)),
+            2.0/3.0
+        )
     );
 
-    const volTensorField gradU(fvc::grad(U_));
-    const volScalarField omega(sqrt(2.0)*mag(skew(gradU)));
-    const volScalarField S2(2.0*magSqr(symm(gradU)));
+    tmp<volTensorField> tgradU(fvc::grad(U_));
+    const volTensorField& gradU = tgradU();
 
-    const volScalarField ktS(fSS(omega)*fw*kt_);
+    const volScalarField Omega(sqrt(2.0)*mag(skew(gradU)));
+
+    const volScalarField S2(2.0*magSqr(dev(symm(gradU))));
+
+    const volScalarField ktS(fSS(Omega)*fw*kt_);
 
     const volScalarField nuts
     (
@@ -607,20 +630,19 @@ void kkLOmega::correct()
        *fINT()
        *Cmu(sqrt(S2))*sqrt(ktS)*lambdaEff
     );
-
     const volScalarField Pkt(nuts*S2);
 
     const volScalarField ktL(kt_ - ktS);
-    const volScalarField ReOmega(sqr(y_)*omega/nu());
+    const volScalarField ReOmega(sqr(y_)*Omega/nu());
     const volScalarField nutl
     (
         min
         (
-            C11_*fTaul(lambdaEff, ktL)*omega*sqr(lambdaEff)
-          * sqrt(ktL)*lambdaEff/nu()
-          + C12_*BetaTS(ReOmega)*ReOmega*sqr(y_)*omega
-          ,
-            0.5*(kl_ + ktL)/sqrt(S2)
+            C11_*fTaul(lambdaEff, ktL, Omega)*Omega*sqr(lambdaEff)
+           *sqrt(ktL)*lambdaEff/nu()
+          + C12_*BetaTS(ReOmega)*ReOmega*sqr(y_)*Omega
+        ,
+            0.5*(kl_ + ktL)/(sqrt(S2) + omegaMin_)
         )
     );
 
@@ -637,52 +659,58 @@ void kkLOmega::correct()
 
     const volScalarField Rbp
     (
-        CR_*(1.0 - exp(-gammaBP(omega)()/Abp_))*omega_
-      / (fw + fwMin)
+        CR_*(1.0 - exp(-phiBP(Omega)()/Abp_))*omega_
+       /(fw + fwMin)
     );
 
     const volScalarField fNatCrit(1.0 - exp(-Cnc_*sqrt(kl_)*y_/nu()));
+
     // Natural source term divided by kl_
     const volScalarField Rnat
     (
-        CrNat_*(1.0 - exp(-gammaNAT(ReOmega, fNatCrit)/Anat_))*omega
+        CrNat_*(1.0 - exp(-phiNAT(ReOmega, fNatCrit)/Anat_))*Omega
     );
 
-    const volScalarField Dt(nu()*magSqr(fvc::grad(sqrt(kt_))));
 
-    // Turbulent kinetic energy equation
-    tmp<fvScalarMatrix> ktEqn
+    omega_.boundaryField().updateCoeffs();
+
+    // Turbulence specific dissipation rate equation
+    tmp<fvScalarMatrix> omegaEqn
     (
-        fvm::ddt(kt_)
-      + fvm::div(phi_, kt_)
-      - fvm::laplacian(DkEff(alphaTEff), kt_, "laplacian(alphaTEff,kt)")
+        fvm::ddt(omega_)
+      + fvm::div(phi_, omega_)
+      - fvm::laplacian(DomegaEff(alphaTEff), omega_)
      ==
-        Pkt
-      + (Rbp + Rnat)*kl_
-      - Dt
-      - fvm::Sp(omega_, kt_)
+        Cw1_*Pkt*omega_/(kt_ + kMin_)
+      - fvm::SuSp
+        (
+            (1.0 - CwR_/(fw + fwMin))*kl_*(Rbp + Rnat)/(kt_ + kMin_)
+          , omega_
+        )
+      - fvm::Sp(Cw2_*sqr(fw)*omega_, omega_)
+      + (
+            Cw3_*fOmega(lambdaEff, lambdaT)*alphaTEff*sqr(fw)*sqrt(kt_)
+        )().dimensionedInternalField()/pow3(y_.dimensionedInternalField())
     );
 
-    ktEqn().relax();
-    ktEqn().boundaryManipulate(kt_.boundaryField());
+    omegaEqn().relax();
+    omegaEqn().boundaryManipulate(omega_.boundaryField());
 
-    solve(ktEqn);
-    bound(kt_, kMin_);
+    solve(omegaEqn);
+    bound(omega_, omegaMin_);
 
 
-    const volScalarField Dl(nu()*magSqr(fvc::grad(sqrt(kl_))));
+    const volScalarField Dl(D(kl_));
 
     // Laminar kinetic energy equation
     tmp<fvScalarMatrix> klEqn
     (
         fvm::ddt(kl_)
       + fvm::div(phi_, kl_)
-      - fvm::laplacian(nu(), kl_, "laplacian(nu,kl)")
+      - fvm::laplacian(nu(), kl_)
      ==
         Pkl
-      - fvm::Sp(Rbp, kl_)
-      - fvm::Sp(Rnat, kl_)
-      - Dl
+      - fvm::Sp(Rbp + Rnat + Dl/(kl_ + kMin_), kl_)
     );
 
     klEqn().relax();
@@ -692,40 +720,33 @@ void kkLOmega::correct()
     bound(kl_, kMin_);
 
 
-    omega_.boundaryField().updateCoeffs();
+    const volScalarField Dt(D(kt_));
 
-    // Turbulence specific dissipation rate equation
-    tmp<fvScalarMatrix> omegaEqn
+    // Turbulent kinetic energy equation
+    tmp<fvScalarMatrix> ktEqn
     (
-        fvm::ddt(omega_)
-      + fvm::div(phi_, omega_)
-      - fvm::laplacian
-        (
-            DomegaEff(alphaTEff),
-            omega_,
-            "laplacian(alphaTEff,omega)"
-        )
+        fvm::ddt(kt_)
+      + fvm::div(phi_, kt_)
+      - fvm::laplacian(DkEff(alphaTEff), kt_)
      ==
-        Cw1_*Pkt*omega_/(kt_ + kMin_)
-      + fvm::SuSp
-        (
-            (CwR_/(fw + fwMin) - 1.0)*kl_*(Rbp + Rnat)/(kt_ + kMin_)
-          , omega_
-        )
-      - fvm::Sp(Cw2_*omega_, omega_)
-      + (
-            Cw3_*fOmega(lambdaEff, lambdaT)*alphaTEff*sqr(fw)*sqrt(kt_)
-        )().dimensionedInternalField()/pow3(y_.dimensionedInternalField())
+        Pkt
+      + (Rbp + Rnat)*kl_
+      - fvm::Sp(omega_ + Dt/(kt_+ kMin_), kt_)
     );
 
+    ktEqn().relax();
+    ktEqn().boundaryManipulate(kt_.boundaryField());
 
-    omegaEqn().relax();
-    omegaEqn().boundaryManipulate(omega_.boundaryField());
+    solve(ktEqn);
+    bound(kt_, kMin_);
+
+
+    // Update total fluctuation kinetic energy dissipation rate
+    epsilon_ = kt_*omega_ + Dl + Dt;
+    bound(epsilon_, epsilonMin_);
 
-    solve(omegaEqn);
-    bound(omega_, omegaMin_);
 
-    // Re-calculate viscosity
+    // Re-calculate turbulent viscosity
     nut_ = nuts + nutl;
     nut_.correctBoundaryConditions();
 }
diff --git a/src/TurbulenceModels/incompressible/turbulentTransportModels/RAS/kkLOmega/kkLOmega.H b/src/TurbulenceModels/incompressible/turbulentTransportModels/RAS/kkLOmega/kkLOmega.H
index d565d5b33fe..68ba3793804 100644
--- a/src/TurbulenceModels/incompressible/turbulentTransportModels/RAS/kkLOmega/kkLOmega.H
+++ b/src/TurbulenceModels/incompressible/turbulentTransportModels/RAS/kkLOmega/kkLOmega.H
@@ -31,7 +31,7 @@ Description
     Low Reynolds-number k-kl-omega turbulence model for
     incompressible flows.
 
-    Turbulence model described in:
+    This turbulence model is described in:
     \verbatim
         Walters, D. K., & Cokljat, D. (2008).
         A three-equation eddy-viscosity model for Reynolds-averaged
@@ -39,6 +39,17 @@ Description
         Journal of Fluids Engineering, 130(12), 121401.
     \endverbatim
 
+    however the paper contains several errors which must be corrected for the
+    model to operation correctly as explained in
+
+    \verbatim
+        Furst, J. (2013).
+        Numerical simulation of transitional flows with laminar kinetic energy.
+        Engineering MECHANICS, 20(5), 379-388.
+    \endverbatim
+
+    All these corrections and updates are included in this implementation.
+
     The default model coefficients are
     \verbatim
         kkLOmegaCoeffs
@@ -116,7 +127,8 @@ class kkLOmega
         tmp<volScalarField> fTaul
         (
             const volScalarField& lambdaEff,
-            const volScalarField& ktL
+            const volScalarField& ktL,
+            const volScalarField& omega
         ) const;
 
         tmp<volScalarField> alphaT
@@ -132,14 +144,16 @@ class kkLOmega
             const volScalarField& lambdaT
         ) const;
 
-        tmp<volScalarField> gammaBP(const volScalarField& omega) const;
+        tmp<volScalarField> phiBP(const volScalarField& omega) const;
 
-        tmp<volScalarField> gammaNAT
+        tmp<volScalarField> phiNAT
         (
             const volScalarField& ReOmega,
             const volScalarField& fNatCrit
         ) const;
 
+        tmp<volScalarField> D(const volScalarField& k) const;
+
 
 protected:
 
@@ -179,8 +193,9 @@ protected:
         // Fields
 
             volScalarField kt_;
-            volScalarField omega_;
             volScalarField kl_;
+            volScalarField omega_;
+            volScalarField epsilon_;
 
             //- Wall distance
             //  Note: different to wall distance in parent RASModel
@@ -250,7 +265,7 @@ public:
         }
 
         //- Return the turbulence kinetic energy
-        virtual tmp<volScalarField> k() const
+        virtual tmp<volScalarField> kt() const
         {
             return kt_;
         }
@@ -261,8 +276,8 @@ public:
             return omega_;
         }
 
-        //- Return the turbulence kinetic energy dissipation rate
-        virtual tmp<volScalarField> epsilon() const
+        //- Return the total fluctuation kinetic energy
+        virtual tmp<volScalarField> k() const
         {
             return tmp<volScalarField>
             (
@@ -270,16 +285,22 @@ public:
                 (
                     IOobject
                     (
-                        "epsilon",
+                        "k",
                         mesh_.time().timeName(),
                         mesh_
                     ),
-                    kt_*omega_,
+                    kt_ + kl_,
                     omega_.boundaryField().types()
                 )
             );
         }
 
+        //- Return the total fluctuation kinetic energy dissipation rate
+        virtual tmp<volScalarField> epsilon() const
+        {
+            return epsilon_;
+        }
+
         //- Solve the turbulence equations and correct the turbulence viscosity
         virtual void correct();
 };
-- 
GitLab