Program Listing for File ODEWallModelFvPatchScalarField.C
↰ Return to documentation for file (wallModels/ODEWallModelFvPatchScalarField.C
)
/*---------------------------------------------------------------------------* \
License
This file is part of libWallModelledLES.
libWallModelledLES 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.
libWallModelledLES 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 libWallModelledLES.
If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "ODEWallModelFvPatchScalarField.H"
#include "addToRunTimeSelectionTable.H"
#include "codeRules.H"
#include "scalarListIOList.H"
#include "helpers.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#if !defined(DOXYGEN_SHOULD_SKIP_THIS)
namespace Foam
{
defineTypeNameAndDebug(ODEWallModelFvPatchScalarField, 0);
}
#endif
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::ODEWallModelFvPatchScalarField::writeLocalEntries(Ostream& os) const
{
wallModelFvPatchScalarField::writeLocalEntries(os);
eddyViscosity_->write(os);
sampler_->write(os);
os.writeKeyword("eps") << eps_ << token::END_STATEMENT << endl;
os.writeKeyword("maxIter") << maxIter_ << token::END_STATEMENT << endl;
os.writeKeyword("nMeshY") << nMeshY_ << token::END_STATEMENT << endl;
}
Foam::scalar
Foam::ODEWallModelFvPatchScalarField::
integrate(const scalarList & y, const scalarList & v) const
{
// trapezoidal rule for now
scalar integral = 0;
for (int i=0; i<y.size()-1; i++)
{
integral += (y[i+1] - y[i])*(v[i+1] + v[i]);
}
return 0.5*integral;
}
void Foam::ODEWallModelFvPatchScalarField::createMeshes()
{
if (debug)
{
Info<< "Creating 1D mesh for patch " << patch().name();
}
// Number of points in the mesh normal to the wall
label n=nMeshY_;
forAll(patch(), faceI)
{
scalar dx = sampler().h()[faceI]/(n -1);
meshes_[faceI].resize(n, 0.0);
forAll(meshes_[faceI], pointI)
{
// uniform distribution
meshes_[faceI][pointI] = pointI*dx;
}
}
if (debug)
{
Info<< " Done" << nl;;
}
}
Foam::tmp<Foam::scalarField>
Foam::ODEWallModelFvPatchScalarField::calcNut() const
{
if (debug)
{
Info<< "Updating nut for patch " << patch().name() << nl;
}
const label patchi = patch().index();
tmp<scalarField> nuw = this->nu(patchi);
const scalarListIOList & wallGradU =
sampler_->db().lookupObject<scalarListIOList>("wallGradU");
scalarField magGradU(Helpers::mag(wallGradU));
return max
(
scalar(0),
sqr(calcUTau(magGradU))/(magGradU + ROOTVSMALL) - nuw
);
}
Foam::tmp<Foam::scalarField>
Foam::ODEWallModelFvPatchScalarField::
calcUTau(const scalarField & magGradU) const
{
const label patchi = patch().index();
const label patchSize = patch().size();
tmp<scalarField> tnuw = this->nu(patchi);
const scalarField& nuw = tnuw();
// vectorField for storing the source term
vectorField sourceField(patchSize, vector(0, 0, 0));
// Compute the source term
source(sourceField);
const scalarListIOList & U = sampler().db().lookupObject<scalarListIOList>("U");
scalarField magU(patch().size());
forAll(magU, i)
{
magU[i] = mag(vector(U[i][0], U[i][1], U[i][2]));
}
// Turbulent viscosity
const scalarField & nutw = *this;
// Computed uTau
tmp<scalarField> tuTau(new scalarField(patchSize, 0.0));
scalarField & uTau =
#ifdef FOAM_NEW_TMP_RULES
tuTau.ref();
#else
tuTau();
#endif
// Compute uTau for each face
forAll(uTau, faceI)
{
// Points of the 1d wall-normal mesh
const scalarList & y = meshes_[faceI];
// Starting guess using definition
scalar tau = (nutw[faceI] + nuw[faceI])*magGradU[faceI];
if (tau > ROOTVSMALL)
{
for (int iterI=0; iterI<maxIter_; iterI++)
{
scalarList nutValues =
eddyViscosity_->value(sampler(), faceI, y, sqrt(tau), nuw[faceI]);
scalar integral = integrate(y, 1/(nuw[faceI] + nutValues));
scalar integral2 = integrate(y, y/(nuw[faceI] + nutValues));
if (mag(integral) < VSMALL )
{
WarningIn
(
"Foam::ODEWallModelFvPatchScalarField::calcUTau()"
)
<< "When calculating newTau, division by zero occurred."
<< nl;
};
vector UFaceI(U[faceI][0], U[faceI][1], U[faceI][2]);
scalar newTau =
sqr(magU[faceI]) + sqr(mag(sourceField[faceI])*integral2) -
2*(UFaceI & sourceField[faceI])*integral2;
newTau = sqrt(newTau)/integral;
scalar error = mag(tau - newTau)/tau;
tau = newTau;
if (error < eps_)
{
if (debug > 1)
{
Info<< "tau_w converged after " << iterI + 1
<< " iterations." << nl;
}
break;
}
if ((debug > 1) && (iterI == maxIter_-1))
{
WarningIn
(
"Foam::ODEWallModelFvPatchScalarField::calcUTau()"
)
<< "tau_w did not converge to desired tolerance "
<< eps_ << ". Error value: " << error << nl;
}
}
uTau[faceI] = max(0.0, sqrt(tau));
}
}
// Grab global uTau field
volScalarField & uTauField =
const_cast<volScalarField &>
(
db().lookupObject<volScalarField>("uTauPredicted")
);
// Assign computed uTau to the boundary field of the global field
#ifdef FOAM_NEW_GEOMFIELD_RULES
uTauField.boundaryFieldRef()[patch().index()]
#else
uTauField.boundaryField()[patch().index()]
#endif
==
uTau;
return tuTau;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::ODEWallModelFvPatchScalarField::
ODEWallModelFvPatchScalarField
(
const fvPatch& p,
const DimensionedField<scalar, volMesh>& iF
)
:
wallModelFvPatchScalarField(p, iF),
sampler_(nullptr),
meshes_(patch().size()),
maxIter_(10),
eps_(1e-3),
nMeshY_(30)
{
if (debug)
{
Info<< "Constructing ODEWallModelfvPatchScalarField (o1) "
<< "from copy and DimensionedField for patch " << patch().name()
<< nl;
}
createMeshes();
}
Foam::ODEWallModelFvPatchScalarField::
ODEWallModelFvPatchScalarField
(
const ODEWallModelFvPatchScalarField& orig,
const fvPatch& p,
const DimensionedField<scalar, volMesh>& iF,
const fvPatchFieldMapper& mapper
)
:
wallModelFvPatchScalarField(orig, p, iF, mapper),
#ifdef FOAM_AUTOPTR_HAS_CLONE_METHOD
eddyViscosity_(orig.eddyViscosity_.clone()),
#else
eddyViscosity_(orig.eddyViscosity_, false),
#endif
sampler_(new SingleCellSampler(orig.sampler())),
meshes_(orig.meshes_),
maxIter_(orig.maxIter_),
eps_(orig.eps_),
nMeshY_(orig.nMeshY_)
{
if (debug)
{
Info<< "Constructing ODEWallModelfvPatchScalarField (o2) "
<< "from copy and DimensionedField for patch " << patch().name()
<< nl;
}
eddyViscosity_->addFieldsToSampler(sampler());
}
Foam::ODEWallModelFvPatchScalarField::
ODEWallModelFvPatchScalarField
(
const fvPatch& p,
const DimensionedField<scalar, volMesh>& iF,
const dictionary& dict
)
:
wallModelFvPatchScalarField(p, iF, dict),
eddyViscosity_(EddyViscosity::New(dict.subDict("EddyViscosity"))),
sampler_
(
new SingleCellSampler
(
p,
averagingTime(),
dict.lookupOrDefault<word>("interpolationType", "cell"),
dict.lookupOrDefault<word>("sampler", "Tree"),
dict.lookupOrDefault<word>("lengthScaleType", "CubeRootVol"),
dict.lookupOrDefault<bool>("hIsIndex", false)
)
),
meshes_(patch().size()),
maxIter_(dict.lookupOrDefault<label>("maxIter", 10)),
eps_(dict.lookupOrDefault<scalar>("eps", 1e-3)),
nMeshY_(dict.lookupOrDefault<label>("nMeshY", 30))
{
if (debug)
{
Info<< "Constructing ODEWallModelfvPatchScalarField (o3) "
<< "from copy and DimensionedField for patch " << patch().name()
<< nl;
}
createMeshes();
eddyViscosity_->addFieldsToSampler(sampler());
}
#ifdef FOAM_FVPATCHFIELD_NO_COPY
#else
Foam::ODEWallModelFvPatchScalarField::
ODEWallModelFvPatchScalarField
(
const ODEWallModelFvPatchScalarField& orig
)
:
wallModelFvPatchScalarField(orig),
#ifdef FOAM_AUTOPTR_HAS_CLONE_METHOD
eddyViscosity_(orig.eddyViscosity_.clone()),
#else
eddyViscosity_(orig.eddyViscosity_, false),
#endif
sampler_(new SingleCellSampler(orig.sampler())),
meshes_(orig.meshes_),
maxIter_(orig.maxIter_),
eps_(orig.eps_),
nMeshY_(orig.nMeshY_)
{
if (debug)
{
Info<< "Constructing ODEWallModelfvPatchScalarField (o4) "
<< "from copy and DimensionedField for patch " << patch().name()
<< nl;
}
eddyViscosity_->addFieldsToSampler(sampler());
}
#endif
Foam::ODEWallModelFvPatchScalarField::
ODEWallModelFvPatchScalarField
(
const ODEWallModelFvPatchScalarField& orig,
const DimensionedField<scalar, volMesh>& iF
)
:
wallModelFvPatchScalarField(orig, iF),
#ifdef FOAM_AUTOPTR_HAS_CLONE_METHOD
eddyViscosity_(orig.eddyViscosity_.clone()),
#else
eddyViscosity_(orig.eddyViscosity_, false),
#endif
sampler_(new SingleCellSampler(orig.sampler_())),
meshes_(orig.meshes_),
maxIter_(orig.maxIter_),
eps_(orig.eps_),
nMeshY_(orig.nMeshY_)
{
if (debug)
{
Info<< "Constructing ODEWallModelfvPatchScalarField (o5) "
<< "from copy and DimensionedField for patch " << patch().name()
<< nl;
}
eddyViscosity_->addFieldsToSampler(sampler());
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::ODEWallModelFvPatchScalarField::write(Ostream& os) const
{
wallModelFvPatchScalarField::write(os);
}
void Foam::ODEWallModelFvPatchScalarField::updateCoeffs()
{
if (updated())
{
return;
}
sampler().recomputeFields();
sampler().sample();
wallModelFvPatchScalarField::updateCoeffs();
}
// ************************************************************************* //