mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: setTurbulenceFields: new automatic initialisation method for turbulence fields
This commit is contained in:
committed by
Mark Olesen
parent
c5be97a52a
commit
a371f1792b
@ -0,0 +1,3 @@
|
||||
setTurbulenceFields.C
|
||||
|
||||
EXE = $(FOAM_APPBIN)/setTurbulenceFields
|
||||
@ -0,0 +1,22 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
|
||||
-I$(LIB_SRC)/TurbulenceModels/incompressible/lnInclude \
|
||||
-I$(LIB_SRC)/TurbulenceModels/compressible/lnInclude \
|
||||
-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
|
||||
-I$(LIB_SRC)/transportModels \
|
||||
-I$(LIB_SRC)/transportModels/compressible/lnInclude \
|
||||
-I$(LIB_SRC)/transportModels/incompressible/singlePhaseTransportModel
|
||||
|
||||
EXE_LIBS = \
|
||||
-lfiniteVolume \
|
||||
-lfvOptions \
|
||||
-lmeshTools \
|
||||
-lturbulenceModels \
|
||||
-lincompressibleTurbulenceModels \
|
||||
-lcompressibleTurbulenceModels \
|
||||
-lfluidThermophysicalModels \
|
||||
-lincompressibleTransportModels \
|
||||
-lcompressibleTransportModels \
|
||||
-lgenericPatchFields
|
||||
@ -0,0 +1,531 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Application
|
||||
setTurbulenceFields
|
||||
|
||||
Group
|
||||
grpPreProcessingUtilities
|
||||
|
||||
Description
|
||||
Initialises turbulence fields according to
|
||||
various empirical governing equations.
|
||||
|
||||
References:
|
||||
\verbatim
|
||||
Initialisation method (tag:M):
|
||||
Manceau, R. (n.d.).
|
||||
A two-step automatic initialization
|
||||
procedure for RANS computations.
|
||||
(Unpublished).
|
||||
|
||||
Previous-version of the initialisation model (tag:LM):
|
||||
Lardeau, S., & Manceau, R. (2014).
|
||||
Computations of complex flow configurations using
|
||||
a modified elliptic-blending Reynolds-stress model.
|
||||
10th International ERCOFTAC Symposium on Engineering
|
||||
Turbulence Modelling and Measurements. Marbella, Spain.
|
||||
https://hal.archives-ouvertes.fr/hal-01051799
|
||||
\endverbatim
|
||||
|
||||
Usage
|
||||
Minimal example by using \c system/setTurbulenceFieldsDict:
|
||||
\verbatim
|
||||
// Mandatory entries
|
||||
uRef <scalar>;
|
||||
|
||||
// Optional entries
|
||||
initialiseU <bool>;
|
||||
initialiseEpsilon <bool>;
|
||||
initialiseK <bool>;
|
||||
initialiseOmega <bool>;
|
||||
initialiseR <bool>;
|
||||
writeF <bool>;
|
||||
|
||||
kappa <scalar>;
|
||||
Cmu <scalar>;
|
||||
dPlusRef <scalar>;
|
||||
|
||||
f <word>;
|
||||
U <word>;
|
||||
epsilon <word>;
|
||||
k <word>;
|
||||
omega <word>;
|
||||
R <word>;
|
||||
\endverbatim
|
||||
|
||||
where the entries mean:
|
||||
\table
|
||||
Property | Description | Type | Reqd | Deflt
|
||||
uRef | Reference speed | scalar | yes | -
|
||||
initialiseU | Flag to initialise U | bool | no | false
|
||||
initialiseEpsilon | Flag to initialise epsilon | bool | no | false
|
||||
initialiseK | Flag to initialise k | bool | no | false
|
||||
initialiseOmega | Flag to initialise omega | bool | no | false
|
||||
initialiseR | Flag to initialise R | bool | no | false
|
||||
writeF | Flag to write elliptic-blending field, f | bool | no | false
|
||||
kappa | von Karman constant | scalar | no | 0.41
|
||||
Cmu | Empirical constant | scalar | no | 0.09
|
||||
dPlusRef | Reference dPlus | scalar | no | 15
|
||||
f | Name of operand f field | word | no | f
|
||||
U | Name of operand U field | word | no | U
|
||||
epsilon | Name of operand epsilon field | word | no | epsilon
|
||||
k | Name of operand k field | word | no | k
|
||||
omega | Name of operand omega field | word | no | omega
|
||||
R | Name of operand R field | word | no | R
|
||||
\endtable
|
||||
|
||||
Note
|
||||
- Time that the utility applies to is determined by the
|
||||
\c controlDict.startFrom and \c controlDict.startTime entries.
|
||||
- The utility modifies near-wall fields, hence
|
||||
can be more effective for low-Re mesh cases.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "fvCFD.H"
|
||||
#include "singlePhaseTransportModel.H"
|
||||
#include "turbulentTransportModel.H"
|
||||
#include "turbulentFluidThermoModel.H"
|
||||
#include "wallFvPatch.H"
|
||||
#include "fixedValueFvPatchFields.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
void InfoField(const word& fldName)
|
||||
{
|
||||
Info<< "Writing field: " << fldName << nl << endl;
|
||||
}
|
||||
|
||||
|
||||
IOobject createIOobject
|
||||
(
|
||||
const fvMesh& mesh,
|
||||
const word& name,
|
||||
IOobject::readOption rOpt = IOobject::READ_IF_PRESENT
|
||||
)
|
||||
{
|
||||
return
|
||||
IOobject
|
||||
(
|
||||
name,
|
||||
mesh.time().timeName(),
|
||||
mesh,
|
||||
rOpt,
|
||||
IOobject::NO_WRITE,
|
||||
false // do not register
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
tmp<volScalarField> nu
|
||||
(
|
||||
const fvMesh& mesh,
|
||||
const volVectorField& U
|
||||
)
|
||||
{
|
||||
const Time& runTime = mesh.time();
|
||||
|
||||
if
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
basicThermo::dictName,
|
||||
runTime.constant(),
|
||||
mesh
|
||||
).typeHeaderOk<IOdictionary>(true)
|
||||
)
|
||||
{
|
||||
// Compressible
|
||||
autoPtr<fluidThermo> pThermo(fluidThermo::New(mesh));
|
||||
fluidThermo& thermo = pThermo();
|
||||
volScalarField rho(thermo.rho());
|
||||
|
||||
// Create phi
|
||||
#include "compressibleCreatePhi.H"
|
||||
|
||||
autoPtr<compressible::turbulenceModel> turbulence
|
||||
(
|
||||
compressible::turbulenceModel::New
|
||||
(
|
||||
rho,
|
||||
U,
|
||||
phi,
|
||||
thermo
|
||||
)
|
||||
);
|
||||
|
||||
turbulence->validate();
|
||||
|
||||
return tmp<volScalarField>::New(turbulence->nu());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Incompressible
|
||||
|
||||
// Create phi
|
||||
#include "createPhi.H"
|
||||
|
||||
singlePhaseTransportModel laminarTransport(U, phi);
|
||||
|
||||
autoPtr<incompressible::turbulenceModel> turbulence
|
||||
(
|
||||
incompressible::turbulenceModel::New(U, phi, laminarTransport)
|
||||
);
|
||||
|
||||
turbulence->validate();
|
||||
|
||||
return tmp<volScalarField>::New(turbulence->nu());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Calculate elliptic blending function
|
||||
// between near-wall and weakly-inhomogeneous regions
|
||||
void calcF
|
||||
(
|
||||
const volScalarField& L,
|
||||
volScalarField& f
|
||||
)
|
||||
{
|
||||
tmp<volScalarField> tinvLsqr = scalar(1)/sqr(L);
|
||||
const volScalarField& invLsqr = tinvLsqr.cref();
|
||||
|
||||
// (M:Eq. 6)
|
||||
tmp<fvScalarMatrix> fEqn
|
||||
(
|
||||
fvm::Sp(invLsqr, f)
|
||||
- fvm::laplacian(f)
|
||||
==
|
||||
invLsqr
|
||||
);
|
||||
|
||||
tinvLsqr.clear();
|
||||
|
||||
fEqn.ref().relax();
|
||||
solve(fEqn);
|
||||
|
||||
// (M:p. 2)
|
||||
const dimensioned<scalarMinMax> fMinMax
|
||||
(
|
||||
dimless,
|
||||
scalarMinMax(Zero, scalar(1) - Foam::exp(-scalar(400)/scalar(50)))
|
||||
);
|
||||
|
||||
f.clip(fMinMax);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
// Main program:
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::addNote
|
||||
(
|
||||
"Sets initial turbulence fields based on"
|
||||
" various empirical equations"
|
||||
);
|
||||
argList::noFunctionObjects();
|
||||
argList::addOption("dict", "file", "Alternative setTurbulenceFieldsDict");
|
||||
|
||||
#include "addRegionOption.H"
|
||||
|
||||
#include "setRootCase.H"
|
||||
#include "createTime.H"
|
||||
|
||||
const word dictName("setTurbulenceFieldsDict");
|
||||
#include "setSystemRunTimeDictionaryIO.H"
|
||||
Info<< "Reading " << dictIO.name() << nl << endl;
|
||||
IOdictionary dict(dictIO);
|
||||
|
||||
#include "createNamedMesh.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
IOstream::defaultPrecision(15);
|
||||
|
||||
|
||||
// Dictionary input (M:p. 2)
|
||||
|
||||
const scalar uRef = dict.getCheck<scalar>("uRef", scalarMinMax::ge(SMALL));
|
||||
const dimensionedScalar uTau(dimVelocity, 0.05*uRef);
|
||||
const scalar kappa =
|
||||
dict.getCheckOrDefault<scalar>("kappa", 0.41, scalarMinMax::ge(SMALL));
|
||||
const scalar Cmu =
|
||||
dict.getCheckOrDefault<scalar>("Cmu", 0.09, scalarMinMax::ge(SMALL));
|
||||
const scalar dPlusRef =
|
||||
dict.getCheckOrDefault<scalar>("dPlusRef", 15, scalarMinMax::ge(SMALL));
|
||||
const word fName = dict.getOrDefault<word>("f", "f");
|
||||
const word UName = dict.getOrDefault<word>("U", "U");
|
||||
const word epsilonName = dict.getOrDefault<word>("epsilon", "epsilon");
|
||||
const word kName = dict.getOrDefault<word>("k", "k");
|
||||
const word omegaName = dict.getOrDefault<word>("omega", "omega");
|
||||
const word RName = dict.getOrDefault<word>("R", "R");
|
||||
const bool initU = dict.getOrDefault<bool>("initialiseU", false);
|
||||
const bool initEpsilon =
|
||||
dict.getOrDefault<bool>("initialiseEpsilon", false);
|
||||
const bool initK = dict.getOrDefault<bool>("initialiseK", false);
|
||||
const bool initOmega = dict.getOrDefault<bool>("initialiseOmega", false);
|
||||
const bool initR = dict.getOrDefault<bool>("initialiseR", false);
|
||||
const bool writeF = dict.getOrDefault<bool>("writeF", false);
|
||||
|
||||
|
||||
// Start initialising the operand fields
|
||||
|
||||
// Read operand fields
|
||||
|
||||
auto tU = tmp<volVectorField>::New
|
||||
(
|
||||
createIOobject(mesh, UName, IOobject::MUST_READ),
|
||||
mesh
|
||||
);
|
||||
|
||||
// Infer the initial BCs from the velocity
|
||||
const wordList bcTypes
|
||||
(
|
||||
tU.cref().boundaryField().size(),
|
||||
fixedValueFvPatchScalarField::typeName
|
||||
);
|
||||
|
||||
tmp<volScalarField> tepsilon;
|
||||
tmp<volScalarField> tk;
|
||||
tmp<volScalarField> tomega;
|
||||
tmp<volSymmTensorField> tR;
|
||||
|
||||
if (initEpsilon)
|
||||
{
|
||||
tepsilon = tmp<volScalarField>::New
|
||||
(
|
||||
createIOobject(mesh, epsilonName),
|
||||
mesh,
|
||||
dimensionedScalar(sqr(dimLength)/pow3(dimTime), SMALL),
|
||||
bcTypes
|
||||
);
|
||||
}
|
||||
|
||||
if (initK)
|
||||
{
|
||||
tk = tmp<volScalarField>::New
|
||||
(
|
||||
createIOobject(mesh, kName),
|
||||
mesh,
|
||||
dimensionedScalar(sqr(dimLength/dimTime), SMALL),
|
||||
bcTypes
|
||||
);
|
||||
}
|
||||
|
||||
if (initOmega)
|
||||
{
|
||||
tomega = tmp<volScalarField>::New
|
||||
(
|
||||
createIOobject(mesh, omegaName),
|
||||
mesh,
|
||||
dimensionedScalar(dimless/dimTime, SMALL),
|
||||
bcTypes
|
||||
);
|
||||
}
|
||||
|
||||
if (initR)
|
||||
{
|
||||
tR = tmp<volSymmTensorField>::New
|
||||
(
|
||||
createIOobject(mesh, RName),
|
||||
mesh,
|
||||
dimensionedSymmTensor(sqr(dimLength/dimTime), Zero),
|
||||
bcTypes
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Create elliptic blending factor field
|
||||
|
||||
volScalarField f
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
fName,
|
||||
runTime.timeName(),
|
||||
mesh,
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false // do not register
|
||||
),
|
||||
mesh,
|
||||
dimensionedScalar(dimless, scalar(1)),
|
||||
fixedValueFvPatchField<scalar>::typeName
|
||||
);
|
||||
|
||||
for (fvPatchScalarField& pfld : f.boundaryFieldRef())
|
||||
{
|
||||
if (isA<wallFvPatch>(pfld.patch()))
|
||||
{
|
||||
pfld == Zero;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create auxillary fields for the initialisation
|
||||
|
||||
tmp<volScalarField> tnu = nu(mesh, tU.cref());
|
||||
const volScalarField& nu = tnu.cref();
|
||||
|
||||
// (M:p. 2)
|
||||
tmp<volScalarField> tL = scalar(50)*nu/uTau;
|
||||
const volScalarField& L = tL.cref();
|
||||
|
||||
calcF(L, f);
|
||||
|
||||
// (M:Eq. 8)
|
||||
tmp<volScalarField> td = -tL*Foam::log(scalar(1) - f);
|
||||
const volScalarField& d = td.cref();
|
||||
|
||||
// (M:p. 2)
|
||||
const volScalarField dPlus(d*uTau/nu);
|
||||
|
||||
// (M:Eq. 11)
|
||||
const volScalarField epsilon
|
||||
(
|
||||
pow4(uTau)/(kappa*nu*max(dPlus, dPlusRef))
|
||||
);
|
||||
|
||||
// (M:Eq. 13)
|
||||
const volScalarField fk(Foam::exp(-dPlus/scalar(25)));
|
||||
|
||||
// (M:Eq. 12)
|
||||
const volScalarField k
|
||||
(
|
||||
(epsilon*sqr(td)*sqr(fk))/(2*nu)
|
||||
+ sqr(uTau)*sqr(scalar(1) - fk)/Foam::sqrt(Cmu)
|
||||
);
|
||||
|
||||
|
||||
// Initialise operand fields
|
||||
|
||||
if (initU)
|
||||
{
|
||||
volVectorField& U = tU.ref();
|
||||
|
||||
// Reichardt’s law (M:Eq. 10)
|
||||
const scalar C = 7.8;
|
||||
const scalar B1 = 11;
|
||||
const scalar B2 = 3;
|
||||
const volScalarField fRei
|
||||
(
|
||||
Foam::log(scalar(1) + kappa*dPlus)/kappa
|
||||
+ C*
|
||||
(
|
||||
scalar(1)
|
||||
- Foam::exp(-dPlus/B1)
|
||||
- dPlus/B1*Foam::exp(-dPlus/B2)
|
||||
)
|
||||
);
|
||||
|
||||
// (M:Eq. 9)
|
||||
const dimensionedScalar maxU(dimVelocity, SMALL);
|
||||
U *= min(scalar(1), fRei*uTau/max(mag(U), maxU));
|
||||
}
|
||||
|
||||
if (tepsilon.valid())
|
||||
{
|
||||
tepsilon.ref() = epsilon;
|
||||
}
|
||||
|
||||
if (tk.valid())
|
||||
{
|
||||
tk.ref() = k;
|
||||
}
|
||||
|
||||
if (tomega.valid())
|
||||
{
|
||||
const dimensionedScalar k0(sqr(dimLength/dimTime), SMALL);
|
||||
tomega.ref() = Cmu*epsilon/(k + k0);
|
||||
}
|
||||
|
||||
if (tR.valid())
|
||||
{
|
||||
volSymmTensorField& R = tR.ref();
|
||||
|
||||
// (M:Eq. 3)
|
||||
const volSphericalTensorField Rdiag(k*twoThirdsI);
|
||||
forAll(R, celli)
|
||||
{
|
||||
R[celli] = Rdiag[celli];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write operand fields
|
||||
|
||||
Info<< endl;
|
||||
|
||||
if (initU)
|
||||
{
|
||||
InfoField(tU->name());
|
||||
tU->write();
|
||||
}
|
||||
|
||||
if (tepsilon.valid())
|
||||
{
|
||||
InfoField(tepsilon->name());
|
||||
tepsilon->write();
|
||||
}
|
||||
|
||||
if (tk.valid())
|
||||
{
|
||||
InfoField(tk->name());
|
||||
tk->write();
|
||||
}
|
||||
|
||||
if (tomega.valid())
|
||||
{
|
||||
InfoField(tomega->name());
|
||||
tomega->write();
|
||||
}
|
||||
|
||||
if (tR.valid())
|
||||
{
|
||||
InfoField(tR->name());
|
||||
tR->write();
|
||||
}
|
||||
|
||||
if (writeF)
|
||||
{
|
||||
InfoField(f.name());
|
||||
f.write();
|
||||
}
|
||||
|
||||
|
||||
Info<< nl;
|
||||
runTime.printExecutionTime(Info);
|
||||
|
||||
Info<< "End\n" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
Reference in New Issue
Block a user