ENH: turbulentDFSEMInlet: refactoring by PatchFunction1

- ENH: turbulentDFSEMInlet: add normalisation factors for
input Reynolds stresses, mean velocity and integral-length
scales as entries `Uref` and `Lref`.
- ENH: turbulentDFSEMInlet: add scaling factor entries, `scale`
and `m`, to enable users to tune C1 normalisation coefficient,
if need be.
- BUG: turbulentDFSEM: (fixes #1004 #1744 #2089)
- see #2090 for theoretical issues related to the DFSEM method.
This commit is contained in:
Kutalmis Bercin
2021-05-11 10:23:01 +01:00
committed by Andrew Heather
parent c6759692ba
commit b9c174312b
6 changed files with 450 additions and 678 deletions

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2015 OpenFOAM Foundation Copyright (C) 2015 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -49,37 +49,37 @@ bool Foam::eddy::setScales
vector& alpha vector& alpha
) const ) const
{ {
// Static array of gamma^2 vs c2 coefficient // Static array of gamma^2 vs c2 coefficient (PCR:Table 1)
static const scalar gamma2VsC2[8] = static const scalar gamma2VsC2[8] =
{2, 1.875, 1.737, 1.75, 0.91, 0.825, 0.806, 1.5}; {2, 1.875, 1.737, 1.75, 0.91, 0.825, 0.806, 1.5};
scalar gamma = Foam::sqrt(scalar(gamma2)); const scalar gamma = Foam::sqrt(scalar(gamma2));
// c2 coefficient retrieved from array // c2 coefficient retrieved from array
scalar c2 = gamma2VsC2[gamma2 - 1]; const scalar c2 = gamma2VsC2[gamma2 - 1];
// Length scale in largest eigenvalue direction // Length scale in the largest eigenvalue direction
label d1 = dir1_; const label d1 = dir1_;
label d2 = (d1 + 1) % 3; const label d2 = (d1 + 1) % 3;
label d3 = (d1 + 2) % 3; const label d3 = (d1 + 2) % 3;
sigma[d1] = sigmaX; sigma[d1] = sigmaX;
// Note: sigma_average = 1/3*(sigma_x + sigma_y + sigma_z) // Note: sigma_average = 1/3*(sigma_x + sigma_y + sigma_z)
// Substituting for sigma_y = sigma_x/gamma and sigma_z = sigma_y // Substituting for sigma_y = sigma_x/gamma and sigma_z = sigma_y
//sigma[d1] = 3*sigmaX/(1 + 2/gamma);
// Other length scales equal, as function of major axis length and gamma // Other length scales equal, as function of major axis length and gamma
sigma[d2] = sigma[d1]/gamma; sigma[d2] = sigma[d1]/gamma;
sigma[d3] = sigma[d2]; sigma[d3] = sigma[d2];
vector sigma2 = cmptMultiply(sigma, sigma); // (PCR:Eq. 13)
scalar slos2 = cmptSum(cmptDivide(lambda, sigma2)); const vector sigma2(cmptMultiply(sigma, sigma));
const scalar slos2 = cmptSum(cmptDivide(lambda, sigma2));
bool ok = true; bool ok = true;
for (label beta = 0; beta < 3; ++beta) for (label beta = 0; beta < vector::nComponents; ++beta)
{ {
scalar x = slos2 - 2*lambda[beta]/sigma2[beta]; const scalar x = slos2 - 2*lambda[beta]/sigma2[beta];
if (x < 0) if (x < 0)
{ {
@ -88,6 +88,7 @@ bool Foam::eddy::setScales
} }
else else
{ {
// (SST:Eq. 23)
alpha[beta] = e[beta]*sqrt(x/(2*c2)); alpha[beta] = e[beta]*sqrt(x/(2*c2));
} }
} }
@ -145,7 +146,7 @@ Foam::eddy::eddy
dir1_(0) dir1_(0)
{ {
// Principal stresses - eigenvalues returned in ascending order // Principal stresses - eigenvalues returned in ascending order
vector lambda(eigenValues(R)); const vector lambda(eigenValues(R));
// Eddy rotation from principal-to-global axes // Eddy rotation from principal-to-global axes
// - given by the 3 eigenvectors of the Reynold stress tensor as rows in // - given by the 3 eigenvectors of the Reynold stress tensor as rows in
@ -174,17 +175,17 @@ Foam::eddy::eddy
{ {
// Random length scale ratio, gamma = sigmax/sigmay = sigmax/sigmaz // Random length scale ratio, gamma = sigmax/sigmay = sigmax/sigmaz
// - using gamma^2 to ease lookup of c2 coefficient // - using gamma^2 to ease lookup of c2 coefficient
label g2 = Gamma2[i]; const label gamma2 = Gamma2[i];
if (setScales(sigmaX, g2, e, lambda, sigma_, alpha_)) if (setScales(sigmaX, gamma2, e, lambda, sigma_, alpha_))
{ {
found = true; found = true;
break; break;
} }
} }
// Normalisation coefficient (eq. 11) // Normalisation coefficient (PCR:Eq. 11)
// Note: sqrt(10*V)/sqrt(nEddy) applied outside when computing uDash // Note: sqrt(10*V)/sqrt(nEddy) applied outside when computing uPrime
c1_ = cmptAv(sigma_)/cmptProduct(sigma_)*cmptMin(sigma_); c1_ = cmptAv(sigma_)/cmptProduct(sigma_)*cmptMin(sigma_);
if (found) if (found)
@ -226,27 +227,27 @@ Foam::eddy::eddy(const eddy& e)
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::vector Foam::eddy::uDash(const point& xp, const vector& n) const Foam::vector Foam::eddy::uPrime(const point& xp, const vector& n) const
{ {
// Relative position inside eddy (global system) // Relative position inside eddy (global system) (PCR:p. 524)
const vector r = cmptDivide(xp - position(n), sigma_); const vector r(cmptDivide(xp - position(n), sigma_));
if (mag(r) > 1) if (mag(r) >= scalar(1))
{ {
return vector::zero; return vector::zero;
} }
// Relative position inside eddy (eddy principal system) // Relative position inside eddy (eddy principal system)
const vector rp = Rpg_.T() & r; const vector rp(Rpg_.T() & r);
// Shape function (eddy principal system) // Shape function (eddy principal system)
const vector q = cmptMultiply(sigma_, vector::one - cmptMultiply(rp, rp)); const vector q(cmptMultiply(sigma_, vector::one - cmptMultiply(rp, rp)));
// Fluctuating velocity (eddy principal system) (eq. 8) // Fluctuating velocity (eddy principal system) (PCR:Eq. 8)
const vector uDashp = cmptMultiply(q, rp^alpha_); const vector uPrimep(cmptMultiply(q, rp^alpha_));
// Convert into global system (eq. 10) // Convert into global system (PCR:Eq. 10)
return c1_*(Rpg_ & uDashp); return c1_*(Rpg_ & uPrimep);
} }
@ -256,7 +257,7 @@ void Foam::eddy::writeCentreOBJ
Ostream& os Ostream& os
) const ) const
{ {
point p = position(n); const point p(position(n));
os << "v " << p.x() << " " << p.y() << " " << p.z() << nl; os << "v " << p.x() << " " << p.y() << " " << p.z() << nl;
} }
@ -295,14 +296,14 @@ Foam::label Foam::eddy::writeSurfaceOBJ
x[nEddyPoints - 1] = - axisDir*s[dir1_]; x[nEddyPoints - 1] = - axisDir*s[dir1_];
label eddyPtI = 1; label eddyPtI = 1;
for (label axisI = 1; axisI < nFaceAxis; axisI++) for (label axisI = 1; axisI < nFaceAxis; ++axisI)
{ {
scalar z = s[dir1_]*cos(axisI*dPhi); const scalar z = s[dir1_]*cos(axisI*dPhi);
scalar r = sqrt(sqr(s[dir2])*(1 - sqr(z)/sqr(s[dir1_]))); const scalar r = sqrt(sqr(s[dir2])*(1 - sqr(z)/sqr(s[dir1_])));
for (label thetaI = 0; thetaI < nFaceTheta; thetaI++) for (label thetaI = 0; thetaI < nFaceTheta; ++thetaI)
{ {
scalar theta = thetaI*dTheta; const scalar theta = thetaI*dTheta;
point& p = x[eddyPtI++]; point& p = x[eddyPtI++];
p[dir1_] = z; p[dir1_] = z;
p[dir2] = r*sin(theta); p[dir2] = r*sin(theta);
@ -313,33 +314,33 @@ Foam::label Foam::eddy::writeSurfaceOBJ
// Write points // Write points
forAll(x, i) forAll(x, i)
{ {
point p = position(n) + (Rpg_ & x[i]); const point p = position(n) + (Rpg_ & x[i]);
os << "v " << p.x() << " " << p.y() << " " << p.z() << nl; os << "v " << p.x() << " " << p.y() << " " << p.z() << nl;
} }
// Write the end cap tri faces // Write the end cap tri faces
for (label faceI = 0; faceI < nFaceTheta; faceI++) for (label faceI = 0; faceI < nFaceTheta; ++faceI)
{ {
label p1 = pointI + 1; const label p1 = pointI + 1;
label p2 = p1 + faceI + 1; const label p2 = p1 + faceI + 1;
label p3 = p2 + 1; label p3 = p2 + 1;
if (faceI == nFaceTheta - 1) p3 -= nFaceTheta; if (faceI == nFaceTheta - 1) p3 -= nFaceTheta;
os << "f " << p1 << " " << p2 << " " << p3 << nl; os << "f " << p1 << " " << p2 << " " << p3 << nl;
label q1 = pointI + nEddyPoints; const label q1 = pointI + nEddyPoints;
label q2 = q1 - faceI - 1; const label q2 = q1 - faceI - 1;
label q3 = q2 - 1; label q3 = q2 - 1;
if (faceI == nFaceTheta - 1) q3 += nFaceTheta; if (faceI == nFaceTheta - 1) q3 += nFaceTheta;
os << "f " << q1 << " " << q2 << " " << q3 << nl; os << "f " << q1 << " " << q2 << " " << q3 << nl;
} }
// Write quad faces // Write quad faces
for (label axisI = 1; axisI < nFaceAxis - 1; axisI++) for (label axisI = 1; axisI < nFaceAxis - 1; ++axisI)
{ {
for (label thetaI = 0; thetaI < nFaceTheta; thetaI++) for (label thetaI = 0; thetaI < nFaceTheta; ++thetaI)
{ {
label p1 = pointI + 1 + (axisI - 1)*nFaceTheta + thetaI + 1; const label p1 = pointI + 1 + (axisI - 1)*nFaceTheta + thetaI + 1;
label p2 = p1 + nFaceTheta; const label p2 = p1 + nFaceTheta;
label p3 = p2 + 1; label p3 = p2 + 1;
label p4 = p1 + 1; label p4 = p1 + 1;

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2015 OpenFOAM Foundation Copyright (C) 2015 OpenFOAM Foundation
Copyright (C) 2016 OpenCFD Ltd. Copyright (C) 2016-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -69,7 +69,7 @@ Ostream& operator<<(Ostream& os, const eddy& e);
class eddy class eddy
{ {
// Private data // Private Data
static label Gamma2Values[8]; static label Gamma2Values[8];
static UList<label> Gamma2; static UList<label> Gamma2;
@ -83,7 +83,7 @@ class eddy
//- Distance from reference position in normal direction //- Distance from reference position in normal direction
scalar x_; scalar x_;
//- Length scales in 3-D space //- Integral-length scales in 3-D space
vector sigma_; vector sigma_;
//- Time-averaged intensity //- Time-averaged intensity
@ -133,14 +133,18 @@ public:
const label patchFaceI, // patch face index const label patchFaceI, // patch face index
const point& position0, // reference position const point& position0, // reference position
const scalar x, // distance from reference position const scalar x, // distance from reference position
const scalar sigmaX, // length scale const scalar sigmaX, // integral-length scale
const symmTensor& R, // Stress tensor const symmTensor& R, // Reynolds stress tensor
Random& rndGen Random& rndGen
); );
//- Construct copy //- Copy construct
eddy(const eddy& e); eddy(const eddy& e);
// Public Data
//- Flag to activate debug statements
static int debug; static int debug;
@ -149,26 +153,26 @@ public:
// Access // Access
//- Return the patch face index that spawned the eddy //- Return the patch face index that spawned the eddy
inline label patchFaceI() const; inline label patchFaceI() const noexcept;
//- Return the reference position //- Return the reference position
inline const point& position0() const; inline const point& position0() const noexcept;
//- Return the distance from the reference position //- Return the distance from the reference position
inline scalar x() const; inline scalar x() const noexcept;
//- Return the lLength scales in 3-D space //- Return the length scales in 3-D space
inline const vector& sigma() const; inline const vector& sigma() const noexcept;
//- Return the time-averaged intensity //- Return the time-averaged intensity
inline const vector& alpha() const; inline const vector& alpha() const noexcept;
//- Return the coordinate system transformation from local //- Return the coordinate system transformation from local
// principal to global axes //- principal to global axes
inline const tensor& Rpg() const; inline const tensor& Rpg() const noexcept;
//- Return the model coefficient c1 //- Return the model coefficient c1
inline scalar c1() const; inline scalar c1() const noexcept;
//- Return the eddy position //- Return the eddy position
inline point position(const vector& n) const; inline point position(const vector& n) const;
@ -192,10 +196,10 @@ public:
inline boundBox bounds(const bool global = true) const; inline boundBox bounds(const bool global = true) const;
// Evaluate // Evaluation
//- Return the fluctuating velocity contribution at local point xp //- Return the fluctuating velocity contribution at local point xp
vector uDash(const point& xp, const vector& n) const; vector uPrime(const point& xp, const vector& n) const;
// Writing // Writing

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2015 OpenFOAM Foundation Copyright (C) 2015 OpenFOAM Foundation
Copyright (C) 2016 OpenCFD Ltd. Copyright (C) 2016-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -39,54 +39,54 @@ Foam::scalar Foam::eddy::epsi(Random& rndGen) const
} }
inline Foam::label Foam::eddy::patchFaceI() const inline Foam::label Foam::eddy::patchFaceI() const noexcept
{ {
return patchFaceI_; return patchFaceI_;
} }
inline const Foam::point& Foam::eddy::position0() const inline const Foam::point& Foam::eddy::position0() const noexcept
{ {
return position0_; return position0_;
} }
inline Foam::scalar Foam::eddy::x() const inline Foam::scalar Foam::eddy::x() const noexcept
{ {
return x_; return x_;
} }
inline const Foam::vector& Foam::eddy::sigma() const inline const Foam::vector& Foam::eddy::sigma() const noexcept
{ {
return sigma_; return sigma_;
} }
inline const Foam::vector& Foam::eddy::alpha() const inline const Foam::vector& Foam::eddy::alpha() const noexcept
{ {
return alpha_; return alpha_;
} }
inline const Foam::tensor& Foam::eddy::Rpg() const inline const Foam::tensor& Foam::eddy::Rpg() const noexcept
{ {
return Rpg_; return Rpg_;
} }
inline Foam::scalar Foam::eddy::c1() const noexcept
{
return c1_;
}
inline Foam::point Foam::eddy::position(const vector& n) const inline Foam::point Foam::eddy::position(const vector& n) const
{ {
return position0_ + n*x_; return position0_ + n*x_;
} }
inline Foam::scalar Foam::eddy::c1() const
{
return c1_;
}
Foam::vector Foam::eddy::epsilon(Random& rndGen) const Foam::vector Foam::eddy::epsilon(Random& rndGen) const
{ {
return vector(epsi(rndGen), epsi(rndGen), epsi(rndGen)); return vector(epsi(rndGen), epsi(rndGen), epsi(rndGen));

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2015 OpenFOAM Foundation Copyright (C) 2015 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -27,13 +27,9 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "turbulentDFSEMInletFvPatchVectorField.H" #include "turbulentDFSEMInletFvPatchVectorField.H"
#include "volFields.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
#include "fvPatchFieldMapper.H"
#include "momentOfInertia.H" #include "momentOfInertia.H"
#include "OFstream.H" #include "OFstream.H"
#include "globalIndex.H"
#include "rawIOField.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -51,7 +47,7 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::writeEddyOBJ() const
const labelList& boundaryPoints = pp.boundaryPoints(); const labelList& boundaryPoints = pp.boundaryPoints();
const pointField& localPoints = pp.localPoints(); const pointField& localPoints = pp.localPoints();
vector offset = patchNormal_*maxSigmaX_; const vector offset(patchNormal_*maxSigmaX_);
forAll(boundaryPoints, i) forAll(boundaryPoints, i)
{ {
point p = localPoints[boundaryPoints[i]]; point p = localPoints[boundaryPoints[i]];
@ -65,24 +61,6 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::writeEddyOBJ() const
p -= offset; p -= offset;
os << "v " << p.x() << " " << p.y() << " " << p.z() << nl; os << "v " << p.x() << " " << p.y() << " " << p.z() << nl;
} }
// Draw lines between points
// Note: need to order to avoid crossing patch
//const label nPoint = boundaryPoints.size();
//
//forAll(boundaryPoints, i)
//{
// label i1 = i;
// label i2 = (i + 1) % nPoint;
// os << "l " << i1 << " " << i2 << nl;
//}
//
//forAll(boundaryPoints, i)
//{
// label i1 = i + nPoint;
// label i2 = ((i + 1) % nPoint) + nPoint;
// os << "l " << i1 << " " << i2 << nl;
//}
} }
{ {
@ -106,141 +84,31 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::writeLumleyCoeffs() const
{ {
// Output list of xi vs eta // Output list of xi vs eta
// Before interpolation/raw data OFstream os(db().time().path()/"lumley_interpolated.out");
if (interpolateR_)
os << "# xi" << token::TAB << "eta" << endl;
const scalar t = db().time().timeOutputValue();
const symmTensorField R(R_->value(t)/sqr(Uref_));
forAll(R, faceI)
{ {
const fileName valsFile // Normalised anisotropy tensor
( const symmTensor devR(dev(R[faceI]/(tr(R[faceI]))));
fileName
(
this->db().time().globalPath()
/this->db().time().constant()
/"boundaryData"
/this->patch().name()
/"0"
/"R"
)
);
IOobject io // Second tensor invariant
( const scalar ii = min(0, invariantII(devR));
valsFile, // absolute path
this->db().time(),
IOobject::MUST_READ,
IOobject::NO_WRITE,
false, // no need to register
true // is global object (currently not used)
);
const rawIOField<symmTensor> Rexp(io, false); // Third tensor invariant
const scalar iii = invariantIII(devR);
OFstream os(db().time().path()/"lumley_input.out"); // xi, eta
// See Pope - characterization of Reynolds-stress anisotropy
os << "# xi" << token::TAB << "eta" << endl; const scalar xi = cbrt(0.5*iii);
const scalar eta = sqrt(-ii/3.0);
forAll(Rexp, faceI) os << xi << token::TAB << eta << token::TAB
{ << ii << token::TAB << iii << endl;
// Normalised anisotropy tensor
symmTensor devR = dev(Rexp[faceI]/(tr(Rexp[faceI])));
// Second tensor invariant
scalar ii = min(0, invariantII(devR));
// Third tensor invariant
scalar iii = invariantIII(devR);
// xi, eta
// See Pope - characterization of Reynolds-stress anisotropy
scalar xi = cbrt(0.5*iii);
scalar eta = sqrt(-ii/3.0);
os << xi << token::TAB << eta << token::TAB
<< ii << token::TAB << iii << endl;
}
} }
// After interpolation
{
OFstream os(db().time().path()/"lumley_interpolated.out");
os << "# xi" << token::TAB << "eta" << endl;
forAll(R_, faceI)
{
// Normalised anisotropy tensor
symmTensor devR = dev(R_[faceI]/(tr(R_[faceI])));
// Second tensor invariant
scalar ii = min(0, invariantII(devR));
// Third tensor invariant
scalar iii = invariantIII(devR);
// xi, eta
// See Pope - characterization of Reynolds-stress anisotropy
scalar xi = cbrt(0.5*iii);
scalar eta = sqrt(-ii/3.0);
os << xi << token::TAB << eta << token::TAB
<< ii << token::TAB << iii << endl;
}
}
}
const Foam::pointToPointPlanarInterpolation&
Foam::turbulentDFSEMInletFvPatchVectorField::patchMapper() const
{
// Initialise interpolation (2D planar interpolation by triangulation)
if (!mapperPtr_)
{
const fileName samplePointsFile
(
this->db().time().globalPath()
/this->db().time().constant()
/"boundaryData"
/this->patch().name()
/"points"
);
IOobject io
(
samplePointsFile, // absolute path
this->db().time(),
IOobject::MUST_READ,
IOobject::NO_WRITE,
false, // no need to register
true // is global object (currently not used)
);
// Read data
const rawIOField<point> samplePoints(io, false);
DebugInFunction
<< " Read " << samplePoints.size() << " sample points from "
<< samplePointsFile << endl;
// tbd: run-time selection
bool nearestOnly =
(
!mapMethod_.empty()
&& mapMethod_ != "planarInterpolation"
);
// Allocate the interpolator
mapperPtr_.reset
(
new pointToPointPlanarInterpolation
(
samplePoints,
this->patch().patch().faceCentres(),
perturb_,
nearestOnly
)
);
}
return *mapperPtr_;
} }
@ -252,7 +120,7 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::initialisePatch()
patchNormal_ = -gAverage(nf); patchNormal_ = -gAverage(nf);
// Check that patch is planar // Check that patch is planar
scalar error = max(magSqr(patchNormal_ + nf)); const scalar error = max(magSqr(patchNormal_ + nf));
if (error > SMALL) if (error > SMALL)
{ {
@ -293,9 +161,9 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::initialisePatch()
} }
} }
forAll(sumTriMagSf_, i) for (auto& s : sumTriMagSf_)
{ {
sumTriMagSf_[i] = 0.0; s = 0.0;
} }
sumTriMagSf_[Pstream::myProcNo() + 1] = sum(triMagSf); sumTriMagSf_[Pstream::myProcNo() + 1] = sum(triMagSf);
@ -303,7 +171,7 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::initialisePatch()
Pstream::listCombineGather(sumTriMagSf_, maxEqOp<scalar>()); Pstream::listCombineGather(sumTriMagSf_, maxEqOp<scalar>());
Pstream::listCombineScatter(sumTriMagSf_); Pstream::listCombineScatter(sumTriMagSf_);
for (label i = 1; i < triMagSf.size(); i++) for (label i = 1; i < triMagSf.size(); ++i)
{ {
triMagSf[i] += triMagSf[i-1]; triMagSf[i] += triMagSf[i-1];
} }
@ -314,7 +182,7 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::initialisePatch()
triCumulativeMagSf_.transfer(triMagSf); triCumulativeMagSf_.transfer(triMagSf);
// Convert sumTriMagSf_ into cumulative sum of areas per proc // Convert sumTriMagSf_ into cumulative sum of areas per proc
for (label i = 1; i < sumTriMagSf_.size(); i++) for (label i = 1; i < sumTriMagSf_.size(); ++i)
{ {
sumTriMagSf_[i] += sumTriMagSf_[i-1]; sumTriMagSf_[i] += sumTriMagSf_[i-1];
} }
@ -336,7 +204,9 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::initialiseEddyBox()
{ {
const scalarField& magSf = patch().magSf(); const scalarField& magSf = patch().magSf();
//const scalarField cellDx(Foam::sqrt(magSf)); const scalarField L(L_->value(db().time().timeOutputValue())/Lref_);
// (PCF:Eq. 14)
const scalarField cellDx(max(Foam::sqrt(magSf), 2/patch().deltaCoeffs())); const scalarField cellDx(max(Foam::sqrt(magSf), 2/patch().deltaCoeffs()));
// Inialise eddy box extents // Inialise eddy box extents
@ -344,13 +214,10 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::initialiseEddyBox()
{ {
scalar& s = sigmax_[faceI]; scalar& s = sigmax_[faceI];
// Length scale in x direction (based on eq. 14) // Average length scale (SST:Eq. 24)
s = mag(L_[faceI]); // Personal communication regarding (PCR:Eq. 14)
s = min(s, kappa_*delta_); // - the min operator in Eq. 14 is a typo, and should be a max operator
s = min(mag(L[faceI]), kappa_*delta_);
// Allow eddies to be smaller than the mesh scale as suggested by
// the reference?
// s = min(s, nCellPerEddy_*cellDx[faceI]);
s = max(s, nCellPerEddy_*cellDx[faceI]); s = max(s, nCellPerEddy_*cellDx[faceI]);
} }
@ -383,7 +250,8 @@ Foam::pointIndexHit Foam::turbulentDFSEMInletFvPatchVectorField::setNewPosition
if (global) if (global)
{ {
scalar areaFraction = rndGen_.globalPosition<scalar>(0, patchArea_); const scalar areaFraction =
rndGen_.globalPosition<scalar>(0, patchArea_);
// Determine which processor to use // Determine which processor to use
label procI = 0; label procI = 0;
@ -400,7 +268,7 @@ Foam::pointIndexHit Foam::turbulentDFSEMInletFvPatchVectorField::setNewPosition
{ {
// Find corresponding decomposed face triangle // Find corresponding decomposed face triangle
label triI = 0; label triI = 0;
scalar offset = sumTriMagSf_[procI]; const scalar offset = sumTriMagSf_[procI];
forAllReverse(triCumulativeMagSf_, i) forAllReverse(triCumulativeMagSf_, i)
{ {
if (areaFraction > triCumulativeMagSf_[i] + offset) if (areaFraction > triCumulativeMagSf_[i] + offset)
@ -423,8 +291,8 @@ Foam::pointIndexHit Foam::turbulentDFSEMInletFvPatchVectorField::setNewPosition
{ {
// Find corresponding decomposed face triangle on local processor // Find corresponding decomposed face triangle on local processor
label triI = 0; label triI = 0;
scalar maxAreaLimit = triCumulativeMagSf_.last(); const scalar maxAreaLimit = triCumulativeMagSf_.last();
scalar areaFraction = rndGen_.position<scalar>(0, maxAreaLimit); const scalar areaFraction = rndGen_.position<scalar>(0, maxAreaLimit);
forAllReverse(triCumulativeMagSf_, i) forAllReverse(triCumulativeMagSf_, i)
{ {
@ -450,6 +318,9 @@ Foam::pointIndexHit Foam::turbulentDFSEMInletFvPatchVectorField::setNewPosition
void Foam::turbulentDFSEMInletFvPatchVectorField::initialiseEddies() void Foam::turbulentDFSEMInletFvPatchVectorField::initialiseEddies()
{ {
const scalar t = db().time().timeOutputValue();
const symmTensorField R(R_->value(t)/sqr(Uref_));
DynamicList<eddy> eddies(size()); DynamicList<eddy> eddies(size());
// Initialise eddy properties // Initialise eddy properties
@ -465,18 +336,18 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::initialiseEddies()
{ {
// Get new parallel consistent position // Get new parallel consistent position
pointIndexHit pos(setNewPosition(true)); pointIndexHit pos(setNewPosition(true));
label faceI = pos.index(); const label patchFaceI = pos.index();
// Note: only 1 processor will pick up this face // Note: only 1 processor will pick up this face
if (faceI != -1) if (patchFaceI != -1)
{ {
eddy e eddy e
( (
faceI, patchFaceI,
pos.hitPoint(), pos.hitPoint(),
rndGen_.position<scalar>(-maxSigmaX_, maxSigmaX_), rndGen_.position<scalar>(-maxSigmaX_, maxSigmaX_),
sigmax_[faceI], sigmax_[patchFaceI],
R_[faceI], R[patchFaceI],
rndGen_ rndGen_
); );
@ -526,16 +397,21 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::initialiseEddies()
WarningInFunction WarningInFunction
<< "Patch: " << patch().patch().name() << "Patch: " << patch().patch().name()
<< " on field " << internalField().name() << " on field " << internalField().name()
<< ": No eddies seeded - please check your set-up" << endl; << ": No eddies seeded - please check your set-up"
<< endl;
} }
} }
void Foam::turbulentDFSEMInletFvPatchVectorField::convectEddies void Foam::turbulentDFSEMInletFvPatchVectorField::convectEddies
( (
const vector& UBulk,
const scalar deltaT const scalar deltaT
) )
{ {
const scalar t = db().time().timeOutputValue();
const symmTensorField R(R_->value(t)/sqr(Uref_));
// Note: all operations applied to local processor only // Note: all operations applied to local processor only
label nRecycled = 0; label nRecycled = 0;
@ -543,7 +419,7 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::convectEddies
forAll(eddies_, eddyI) forAll(eddies_, eddyI)
{ {
eddy& e = eddies_[eddyI]; eddy& e = eddies_[eddyI];
e.move(deltaT*(UMean_ & patchNormal_)); e.move(deltaT*(UBulk & patchNormal_));
const scalar position0 = e.x(); const scalar position0 = e.x();
@ -555,17 +431,17 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::convectEddies
while (search && iter++ < seedIterMax_) while (search && iter++ < seedIterMax_)
{ {
// Spawn new eddy with new random properties (intensity etc) // Spawn new eddy with new random properties (intensity etc)
pointIndexHit pos(setNewPosition(false)); pointIndexHit pos(setNewPosition(false));
label faceI = pos.index(); const label patchFaceI = pos.index();
e = eddy e = eddy
( (
faceI, patchFaceI,
pos.hitPoint(), pos.hitPoint(),
position0 - floor(position0/maxSigmaX_)*maxSigmaX_, position0 - floor(position0/maxSigmaX_)*maxSigmaX_,
sigmax_[faceI], sigmax_[patchFaceI],
R_[faceI], R[patchFaceI],
rndGen_ rndGen_
); );
@ -583,27 +459,28 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::convectEddies
if (debug && nRecycled > 0) if (debug && nRecycled > 0)
{ {
Info<< "Patch: " << patch().patch().name() << " recycled " Info<< "Patch: " << patch().patch().name()
<< nRecycled << " eddies" << endl; << " recycled " << nRecycled << " eddies"
<< endl;
} }
} }
Foam::vector Foam::turbulentDFSEMInletFvPatchVectorField::uDashEddy Foam::vector Foam::turbulentDFSEMInletFvPatchVectorField::uPrimeEddy
( (
const List<eddy>& eddies, const List<eddy>& eddies,
const point& patchFaceCf const point& patchFaceCf
) const ) const
{ {
vector uDash(Zero); vector uPrime(Zero);
forAll(eddies, k) forAll(eddies, k)
{ {
const eddy& e = eddies[k]; const eddy& e = eddies[k];
uDash += e.uDash(patchFaceCf, patchNormal_); uPrime += e.uPrime(patchFaceCf, patchNormal_);
} }
return uDash; return uPrime;
} }
@ -629,8 +506,8 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::calcOverlappingProcEddies
const eddy& e = eddies_[i]; const eddy& e = eddies_[i];
// Eddy bounds // Eddy bounds
point x = e.position(patchNormal_); const point x(e.position(patchNormal_));
boundBox ebb = e.bounds(); boundBox ebb(e.bounds());
ebb.min() += x; ebb.min() += x;
ebb.max() += x; ebb.max() += x;
@ -678,10 +555,10 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::calcOverlappingProcEddies
if (procI != Pstream::myProcNo()) if (procI != Pstream::myProcNo())
{ {
// What I need to receive is what other processor is sending to me // What I need to receive is what other processor is sending to me
label nRecv = sendSizes[procI][Pstream::myProcNo()]; const label nRecv = sendSizes[procI][Pstream::myProcNo()];
constructMap[procI].setSize(nRecv); constructMap[procI].setSize(nRecv);
for (label i = 0; i < nRecv; i++) for (label i = 0; i < nRecv; ++i)
{ {
constructMap[procI][i] = segmentI++; constructMap[procI][i] = segmentI++;
} }
@ -738,37 +615,33 @@ turbulentDFSEMInletFvPatchVectorField
) )
: :
fixedValueFvPatchField<vector>(p, iF), fixedValueFvPatchField<vector>(p, iF),
delta_(Zero), U_(nullptr),
d_(Zero), R_(nullptr),
kappa_(Zero), L_(nullptr),
delta_(1.0),
perturb_(1e-5), d_(1.0),
mapMethod_("nearestCell"), kappa_(0.41),
mapperPtr_(nullptr), Uref_(1.0),
interpolateR_(false), Lref_(1.0),
interpolateL_(false), scale_(1.0),
interpolateU_(false), m_(0.5),
R_(), nCellPerEddy_(5),
L_(),
U_(),
UMean_(Zero),
patchArea_(-1), patchArea_(-1),
triFace_(), triFace_(),
triToFace_(), triToFace_(),
triCumulativeMagSf_(), triCumulativeMagSf_(),
sumTriMagSf_(Pstream::nProcs() + 1, Zero), sumTriMagSf_(Pstream::nProcs() + 1, Zero),
patchNormal_(Zero),
patchBounds_(boundBox::invertedBox),
eddies_(Zero), eddies_(Zero),
nCellPerEddy_(5),
patchNormal_(Zero),
v0_(Zero), v0_(Zero),
rndGen_(Pstream::myProcNo()), rndGen_(Pstream::myProcNo()),
sigmax_(size(), Zero), sigmax_(size(), Zero),
maxSigmaX_(Zero), maxSigmaX_(Zero),
nEddy_(Zero), nEddy_(0),
curTimeIndex_(-1), curTimeIndex_(-1),
patchBounds_(boundBox::invertedBox),
singleProc_(false), singleProc_(false),
writeEddies_(false) writeEddies_(false)
{} {}
@ -784,37 +657,33 @@ turbulentDFSEMInletFvPatchVectorField
) )
: :
fixedValueFvPatchField<vector>(ptf, p, iF, mapper), fixedValueFvPatchField<vector>(ptf, p, iF, mapper),
U_(ptf.U_.clone(patch().patch())),
R_(ptf.R_.clone(patch().patch())),
L_(ptf.L_.clone(patch().patch())),
delta_(ptf.delta_), delta_(ptf.delta_),
d_(ptf.d_), d_(ptf.d_),
kappa_(ptf.kappa_), kappa_(ptf.kappa_),
Uref_(ptf.Uref_),
perturb_(ptf.perturb_), Lref_(ptf.Lref_),
mapMethod_(ptf.mapMethod_), scale_(ptf.scale_),
mapperPtr_(nullptr), m_(ptf.m_),
interpolateR_(ptf.interpolateR_), nCellPerEddy_(ptf.nCellPerEddy_),
interpolateL_(ptf.interpolateL_),
interpolateU_(ptf.interpolateU_),
R_(ptf.R_, mapper),
L_(ptf.L_, mapper),
U_(ptf.U_, mapper),
UMean_(ptf.UMean_),
patchArea_(ptf.patchArea_), patchArea_(ptf.patchArea_),
triFace_(ptf.triFace_), triFace_(ptf.triFace_),
triToFace_(ptf.triToFace_), triToFace_(ptf.triToFace_),
triCumulativeMagSf_(ptf.triCumulativeMagSf_), triCumulativeMagSf_(ptf.triCumulativeMagSf_),
sumTriMagSf_(ptf.sumTriMagSf_), sumTriMagSf_(ptf.sumTriMagSf_),
patchNormal_(ptf.patchNormal_),
patchBounds_(ptf.patchBounds_),
eddies_(ptf.eddies_), eddies_(ptf.eddies_),
nCellPerEddy_(ptf.nCellPerEddy_),
patchNormal_(ptf.patchNormal_),
v0_(ptf.v0_), v0_(ptf.v0_),
rndGen_(ptf.rndGen_), rndGen_(ptf.rndGen_),
sigmax_(ptf.sigmax_, mapper), sigmax_(ptf.sigmax_, mapper),
maxSigmaX_(ptf.maxSigmaX_), maxSigmaX_(ptf.maxSigmaX_),
nEddy_(Zero), nEddy_(ptf.nEddy_),
curTimeIndex_(-1), curTimeIndex_(-1),
patchBounds_(ptf.patchBounds_),
singleProc_(ptf.singleProc_), singleProc_(ptf.singleProc_),
writeEddies_(ptf.writeEddies_) writeEddies_(ptf.writeEddies_)
{} {}
@ -829,46 +698,42 @@ turbulentDFSEMInletFvPatchVectorField
) )
: :
fixedValueFvPatchField<vector>(p, iF, dict), fixedValueFvPatchField<vector>(p, iF, dict),
delta_(dict.get<scalar>("delta")), U_(PatchFunction1<vector>::New(patch().patch(), "U", dict)),
d_(dict.getOrDefault<scalar>("d", 1)), R_(PatchFunction1<symmTensor>::New(patch().patch(), "R", dict)),
kappa_(dict.getOrDefault<scalar>("kappa", 0.41)), L_(PatchFunction1<scalar>::New(patch().patch(), "L", dict)),
delta_(dict.getCheck<scalar>("delta", scalarMinMax::ge(0))),
perturb_(dict.getOrDefault<scalar>("perturb", 1e-5)), d_(dict.getCheckOrDefault<scalar>("d", 1, scalarMinMax::ge(SMALL))),
mapMethod_(dict.getOrDefault<word>("mapMethod", "nearestCell")), kappa_(dict.getCheckOrDefault<scalar>("kappa", 0.41, scalarMinMax::ge(0))),
mapperPtr_(nullptr), Uref_(dict.getCheckOrDefault<scalar>("Uref", 1, scalarMinMax::ge(SMALL))),
interpolateR_(dict.getOrDefault("interpolateR", false)), Lref_(dict.getCheckOrDefault<scalar>("Lref", 1, scalarMinMax::ge(SMALL))),
interpolateL_(dict.getOrDefault("interpolateL", false)), scale_(dict.getCheckOrDefault<scalar>("scale", 1, scalarMinMax::ge(0))),
interpolateU_(dict.getOrDefault("interpolateU", false)), m_(dict.getCheckOrDefault<scalar>("m", 0.5, scalarMinMax::ge(0))),
R_(interpolateOrRead<symmTensor>("R", dict, interpolateR_)), nCellPerEddy_(dict.getOrDefault<label>("nCellPerEddy", 5)),
L_(interpolateOrRead<scalar>("L", dict, interpolateL_)),
U_(interpolateOrRead<vector>("U", dict, interpolateU_)),
UMean_(Zero),
patchArea_(-1), patchArea_(-1),
triFace_(), triFace_(),
triToFace_(), triToFace_(),
triCumulativeMagSf_(), triCumulativeMagSf_(),
sumTriMagSf_(Pstream::nProcs() + 1, Zero), sumTriMagSf_(Pstream::nProcs() + 1, Zero),
patchNormal_(Zero),
patchBounds_(boundBox::invertedBox),
eddies_(), eddies_(),
nCellPerEddy_(dict.getOrDefault<label>("nCellPerEddy", 5)),
patchNormal_(Zero),
v0_(Zero), v0_(Zero),
rndGen_(), rndGen_(),
sigmax_(size(), Zero), sigmax_(size(), Zero),
maxSigmaX_(Zero), maxSigmaX_(Zero),
nEddy_(Zero), nEddy_(0),
curTimeIndex_(-1), curTimeIndex_(-1),
patchBounds_(boundBox::invertedBox),
singleProc_(false), singleProc_(false),
writeEddies_(dict.getOrDefault("writeEddies", false)) writeEddies_(dict.getOrDefault("writeEddies", false))
{ {
eddy::debug = debug; eddy::debug = debug;
checkStresses(R_); const scalar t = db().time().timeOutputValue();
const symmTensorField R(R_->value(t)/sqr(Uref_));
// Set UMean as patch area average value checkStresses(R);
UMean_ = gSum(U_*patch().magSf())/(gSum(patch().magSf()) + ROOTVSMALL);
} }
@ -879,37 +744,33 @@ turbulentDFSEMInletFvPatchVectorField
) )
: :
fixedValueFvPatchField<vector>(ptf), fixedValueFvPatchField<vector>(ptf),
U_(ptf.U_.clone(patch().patch())),
R_(ptf.R_.clone(patch().patch())),
L_(ptf.L_.clone(patch().patch())),
delta_(ptf.delta_), delta_(ptf.delta_),
d_(ptf.d_), d_(ptf.d_),
kappa_(ptf.kappa_), kappa_(ptf.kappa_),
Uref_(ptf.Uref_),
perturb_(ptf.perturb_), Lref_(ptf.Lref_),
mapMethod_(ptf.mapMethod_), scale_(ptf.scale_),
mapperPtr_(nullptr), m_(ptf.m_),
interpolateR_(ptf.interpolateR_), nCellPerEddy_(ptf.nCellPerEddy_),
interpolateL_(ptf.interpolateL_),
interpolateU_(ptf.interpolateU_),
R_(ptf.R_),
L_(ptf.L_),
U_(ptf.U_),
UMean_(ptf.UMean_),
patchArea_(ptf.patchArea_), patchArea_(ptf.patchArea_),
triFace_(ptf.triFace_), triFace_(ptf.triFace_),
triToFace_(ptf.triToFace_), triToFace_(ptf.triToFace_),
triCumulativeMagSf_(ptf.triCumulativeMagSf_), triCumulativeMagSf_(ptf.triCumulativeMagSf_),
sumTriMagSf_(ptf.sumTriMagSf_), sumTriMagSf_(ptf.sumTriMagSf_),
patchNormal_(ptf.patchNormal_),
patchBounds_(ptf.patchBounds_),
eddies_(ptf.eddies_), eddies_(ptf.eddies_),
nCellPerEddy_(ptf.nCellPerEddy_),
patchNormal_(ptf.patchNormal_),
v0_(ptf.v0_), v0_(ptf.v0_),
rndGen_(ptf.rndGen_), rndGen_(ptf.rndGen_),
sigmax_(ptf.sigmax_), sigmax_(ptf.sigmax_),
maxSigmaX_(ptf.maxSigmaX_), maxSigmaX_(ptf.maxSigmaX_),
nEddy_(Zero), nEddy_(ptf.nEddy_),
curTimeIndex_(-1), curTimeIndex_(-1),
patchBounds_(ptf.patchBounds_),
singleProc_(ptf.singleProc_), singleProc_(ptf.singleProc_),
writeEddies_(ptf.writeEddies_) writeEddies_(ptf.writeEddies_)
{} {}
@ -923,37 +784,33 @@ turbulentDFSEMInletFvPatchVectorField
) )
: :
fixedValueFvPatchField<vector>(ptf, iF), fixedValueFvPatchField<vector>(ptf, iF),
U_(ptf.U_.clone(patch().patch())),
R_(ptf.R_.clone(patch().patch())),
L_(ptf.L_.clone(patch().patch())),
delta_(ptf.delta_), delta_(ptf.delta_),
d_(ptf.d_), d_(ptf.d_),
kappa_(ptf.kappa_), kappa_(ptf.kappa_),
Uref_(ptf.Uref_),
perturb_(ptf.perturb_), Lref_(ptf.Lref_),
mapMethod_(ptf.mapMethod_), scale_(ptf.scale_),
mapperPtr_(nullptr), m_(ptf.m_),
interpolateR_(ptf.interpolateR_), nCellPerEddy_(ptf.nCellPerEddy_),
interpolateL_(ptf.interpolateL_),
interpolateU_(ptf.interpolateU_),
R_(ptf.R_),
L_(ptf.L_),
U_(ptf.U_),
UMean_(ptf.UMean_),
patchArea_(ptf.patchArea_), patchArea_(ptf.patchArea_),
triFace_(ptf.triFace_), triFace_(ptf.triFace_),
triToFace_(ptf.triToFace_), triToFace_(ptf.triToFace_),
triCumulativeMagSf_(ptf.triCumulativeMagSf_), triCumulativeMagSf_(ptf.triCumulativeMagSf_),
sumTriMagSf_(ptf.sumTriMagSf_), sumTriMagSf_(ptf.sumTriMagSf_),
patchNormal_(ptf.patchNormal_),
patchBounds_(ptf.patchBounds_),
eddies_(ptf.eddies_), eddies_(ptf.eddies_),
nCellPerEddy_(ptf.nCellPerEddy_),
patchNormal_(ptf.patchNormal_),
v0_(ptf.v0_), v0_(ptf.v0_),
rndGen_(ptf.rndGen_), rndGen_(ptf.rndGen_),
sigmax_(ptf.sigmax_), sigmax_(ptf.sigmax_),
maxSigmaX_(ptf.maxSigmaX_), maxSigmaX_(ptf.maxSigmaX_),
nEddy_(Zero), nEddy_(ptf.nEddy_),
curTimeIndex_(-1), curTimeIndex_(-1),
patchBounds_(ptf.patchBounds_),
singleProc_(ptf.singleProc_), singleProc_(ptf.singleProc_),
writeEddies_(ptf.writeEddies_) writeEddies_(ptf.writeEddies_)
{} {}
@ -981,11 +838,11 @@ bool Foam::turbulentDFSEMInletFvPatchVectorField::checkStresses
<< exit(FatalError); << exit(FatalError);
} }
scalar a_xx = sqrt(R.xx()); const scalar a_xx = sqrt(R.xx());
scalar a_xy = R.xy()/a_xx; const scalar a_xy = R.xy()/a_xx;
scalar a_yy_2 = R.yy() - sqr(a_xy); const scalar a_yy_2 = R.yy() - sqr(a_xy);
if (a_yy_2 < 0) if (a_yy_2 < 0)
{ {
@ -996,13 +853,13 @@ bool Foam::turbulentDFSEMInletFvPatchVectorField::checkStresses
<< exit(FatalError); << exit(FatalError);
} }
scalar a_yy = Foam::sqrt(a_yy_2); const scalar a_yy = Foam::sqrt(a_yy_2);
scalar a_xz = R.xz()/a_xx; const scalar a_xz = R.xz()/a_xx;
scalar a_yz = (R.yz() - a_xy*a_xz)*a_yy; const scalar a_yz = (R.yz() - a_xy*a_xz)/a_yy;
scalar a_zz_2 = R.zz() - sqr(a_xz) - sqr(a_yz); const scalar a_zz_2 = R.zz() - sqr(a_xz) - sqr(a_yz);
if (a_zz_2 < 0) if (a_zz_2 < 0)
{ {
@ -1013,7 +870,7 @@ bool Foam::turbulentDFSEMInletFvPatchVectorField::checkStresses
<< exit(FatalError); << exit(FatalError);
} }
scalar a_zz = Foam::sqrt(a_zz_2); const scalar a_zz = Foam::sqrt(a_zz_2);
if (debug) if (debug)
{ {
@ -1036,11 +893,18 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::autoMap
{ {
fixedValueFvPatchField<vector>::autoMap(m); fixedValueFvPatchField<vector>::autoMap(m);
// Clear interpolator if (U_)
mapperPtr_.clear(); {
R_.autoMap(m); U_->autoMap(m);
L_.autoMap(m); }
U_.autoMap(m); if (R_)
{
R_->autoMap(m);
}
if (L_)
{
L_->autoMap(m);
}
sigmax_.autoMap(m); sigmax_.autoMap(m);
} }
@ -1054,15 +918,21 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::rmap
{ {
fixedValueFvPatchField<vector>::rmap(ptf, addr); fixedValueFvPatchField<vector>::rmap(ptf, addr);
const turbulentDFSEMInletFvPatchVectorField& dfsemptf = const auto& dfsemptf =
refCast<const turbulentDFSEMInletFvPatchVectorField>(ptf); refCast<const turbulentDFSEMInletFvPatchVectorField>(ptf);
R_.rmap(dfsemptf.R_, addr); if (U_)
L_.rmap(dfsemptf.L_, addr); {
U_.rmap(dfsemptf.U_, addr); U_->rmap(dfsemptf.U_(), addr);
}
// Clear interpolator if (R_)
mapperPtr_.clear(); {
R_->rmap(dfsemptf.R_(), addr);
}
if (L_)
{
L_->rmap(dfsemptf.L_(), addr);
}
sigmax_.rmap(dfsemptf.sigmax_, addr); sigmax_.rmap(dfsemptf.sigmax_, addr);
} }
@ -1087,38 +957,38 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::updateCoeffs()
if (curTimeIndex_ != db().time().timeIndex()) if (curTimeIndex_ != db().time().timeIndex())
{ {
if (debug) tmp<vectorField> UMean =
{ U_->value(db().time().timeOutputValue())/Uref_;
label n = eddies_.size();
Info<< "Number of eddies: " << returnReduce(n, sumOp<label>())
<< endl;
}
// (PCR:p. 522)
const vector UBulk
(
gSum(UMean()*patch().magSf())
/(gSum(patch().magSf()) + ROOTVSMALL)
);
// Move eddies using bulk velocity
const scalar deltaT = db().time().deltaTValue(); const scalar deltaT = db().time().deltaTValue();
convectEddies(UBulk, deltaT);
// Move eddies using mean velocity // Set mean velocity
convectEddies(deltaT);
// Set velocity
vectorField& U = *this; vectorField& U = *this;
//U = UMean_; U = UMean;
U = U_;
const pointField& Cf = patch().Cf();
// Apply second part of normalisation coefficient // Apply second part of normalisation coefficient
// Note: factor of 2 required to match reference stresses? const scalar c =
const scalar FACTOR = 2; scale_*Foam::pow(10*v0_, m_)/Foam::sqrt(scalar(nEddy_));
const scalar c = FACTOR*Foam::sqrt(10*v0_)/Foam::sqrt(scalar(nEddy_));
// In parallel, need to collect all eddies that will interact with // In parallel, need to collect all eddies that will interact with
// local faces // local faces
const pointField& Cf = patch().Cf();
if (singleProc_ || !Pstream::parRun()) if (singleProc_ || !Pstream::parRun())
{ {
forAll(U, faceI) forAll(U, faceI)
{ {
U[faceI] += c*uDashEddy(eddies_, Cf[faceI]); U[faceI] += c*uPrimeEddy(eddies_, Cf[faceI]);
} }
} }
else else
@ -1126,7 +996,7 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::updateCoeffs()
// Process local eddy contributions // Process local eddy contributions
forAll(U, faceI) forAll(U, faceI)
{ {
U[faceI] += c*uDashEddy(eddies_, Cf[faceI]); U[faceI] += c*uPrimeEddy(eddies_, Cf[faceI]);
} }
// Add contributions from overlapping eddies // Add contributions from overlapping eddies
@ -1139,30 +1009,21 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::updateCoeffs()
if (eddies.size()) if (eddies.size())
{ {
//Pout<< "Applying " << eddies.size()
// << " eddies from processor " << procI << endl;
forAll(U, faceI) forAll(U, faceI)
{ {
U[faceI] += c*uDashEddy(eddies, Cf[faceI]); U[faceI] += c*uPrimeEddy(eddies, Cf[faceI]);
} }
} }
} }
} }
// Re-scale to ensure correct flow rate // Re-scale to ensure correct flow rate
scalar fCorr = const scalar fCorr =
gSum((UMean_ & patchNormal_)*patch().magSf()) gSum((UBulk & patchNormal_)*patch().magSf())
/gSum(U & -patch().Sf()); /gSum(U & -patch().Sf());
U *= fCorr; U *= fCorr;
if (debug)
{
Info<< "Patch:" << patch().patch().name()
<< " min/max(U):" << gMin(U) << ", " << gMax(U) << endl;
}
curTimeIndex_ = db().time().timeIndex(); curTimeIndex_ = db().time().timeIndex();
if (writeEddies_) if (writeEddies_)
@ -1170,9 +1031,22 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::updateCoeffs()
writeEddyOBJ(); writeEddyOBJ();
} }
if (debug && db().time().writeTime()) if (debug)
{ {
writeLumleyCoeffs(); Info<< "Magnitude of bulk velocity: " << UBulk << endl;
label n = eddies_.size();
Info<< "Number of eddies: " << returnReduce(n, sumOp<label>())
<< endl;
Info<< "Patch:" << patch().patch().name()
<< " min/max(U):" << gMin(U) << ", " << gMax(U)
<< endl;
if (db().time().writeTime())
{
writeLumleyCoeffs();
}
} }
} }
@ -1183,38 +1057,28 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::updateCoeffs()
void Foam::turbulentDFSEMInletFvPatchVectorField::write(Ostream& os) const void Foam::turbulentDFSEMInletFvPatchVectorField::write(Ostream& os) const
{ {
fvPatchField<vector>::write(os); fvPatchField<vector>::write(os);
writeEntry("value", os);
os.writeEntry("delta", delta_); os.writeEntry("delta", delta_);
os.writeEntryIfDifferent<scalar>("d", 1.0, d_); os.writeEntryIfDifferent<scalar>("d", 1.0, d_);
os.writeEntryIfDifferent<scalar>("kappa", 0.41, kappa_); os.writeEntryIfDifferent<scalar>("kappa", 0.41, kappa_);
os.writeEntryIfDifferent<scalar>("perturb", 1e-5, perturb_); os.writeEntryIfDifferent<scalar>("Uref", 1.0, Uref_);
os.writeEntryIfDifferent<scalar>("Lref", 1.0, Lref_);
os.writeEntryIfDifferent<scalar>("scale", 1.0, scale_);
os.writeEntryIfDifferent<scalar>("m", 0.5, m_);
os.writeEntryIfDifferent<label>("nCellPerEddy", 5, nCellPerEddy_); os.writeEntryIfDifferent<label>("nCellPerEddy", 5, nCellPerEddy_);
os.writeEntryIfDifferent("writeEddies", false, writeEddies_); os.writeEntryIfDifferent("writeEddies", false, writeEddies_);
if (U_)
if (!interpolateR_)
{ {
R_.writeEntry("R", os); U_->writeData(os);
} }
if (R_)
if (!interpolateL_)
{ {
L_.writeEntry("L", os); R_->writeData(os);
} }
if (L_)
if (!interpolateU_)
{ {
U_.writeEntry("U", os); L_->writeData(os);
}
if (!mapMethod_.empty())
{
os.writeEntryIfDifferent<word>
(
"mapMethod",
"nearestCell",
mapMethod_
);
} }
writeEntry("value", os);
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2015 OpenFOAM Foundation Copyright (C) 2015 OpenFOAM Foundation
Copyright (C) 2016-2019 OpenCFD Ltd. Copyright (C) 2016-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -31,56 +31,107 @@ Group
grpInletBoundaryConditions grpInletBoundaryConditions
Description Description
Velocity boundary condition including synthesised eddies for use with LES The \c turbulentDFSEMInlet is a synthesised-eddy based velocity inlet
and DES turbulent flows. boundary condition to generate synthetic turbulence-alike time-series
from a given set of turbulence statistics for LES and hybrid RANS-LES
computations.
Reference: Reference:
\verbatim \verbatim
Poletto, R., Craft, T., & Revell, A. (2013). Standard model (tag:PCR):
A new divergence free synthetic eddy method for Poletto, R., Craft, T., & Revell, A. (2013).
the reproduction of inlet flow conditions for LES. A new divergence free synthetic eddy method for
Flow, turbulence and combustion, 91(3), 519-539. the reproduction of inlet flow conditions for LES.
DOI:10.1007/s10494-013-9488-2 Flow, turbulence and combustion, 91(3), 519-539.
\endverbatim DOI:10.1007/s10494-013-9488-2
Reynolds stress, velocity and turbulence length scale values can either Expression for the average length scale (tag:SST):
be specified directly, or mapped. If mapping, the values should be Shur, M., Strelets, M., Travin, A.,
entered in the same form as the \c timeVaryingMappedFixedValue condition, Probst, A., Probst, S., Schwamborn, D., ... & Revell, A. (2018).
except that no interpolation in time is supported. These should be Improved embedded approaches.
located in the directory: In: Mockett C., Haase W., Schwamborn D. (eds)
Go4Hybrid: Grey area mitigation for hybrid RANS-LES methods.
\verbatim Notes on Numerical Fluid Mechanics and Multidisciplinary Design.
\$FOAM_CASE/constant/boundaryData/\<patchName\>/points p. 51-87. Springer, Cham.
\$FOAM_CASE/constant/boundaryData/\<patchName\>/0/\{R|U|L\} DOI:10.1007/978-3-319-52995-0_3
\endverbatim \endverbatim
Usage Usage
Example of the boundary condition specification:
\verbatim
<patchName>
{
// Mandatory entries
type turbulentDFSEMInlet;
delta <scalar>;
R <PatchFunction1>;
U <PatchFunction1>;
L <PatchFunction1>;
// e.g.
// R uniform (<Rxx> <Rxy> <Rxz> <Ryy> <Ryz> <Rzz>);
// U uniform (<Ux> <Uy> <Uz>);
// L uniform <L>;
// Optional entries
d <scalar>;
nCellPerEddy <label>;
kappa <scalar>;
Uref <scalar>;
Lref <scalar>;
scale <scalar>;
m <scalar>;
writeEddies <bool>;
// Inherited entries
...
}
\endverbatim
where the entries mean:
\table \table
Property | Description | Required | Default value Property | Description | Type | Reqd | Deflt
value | Restart value | yes | type | Type name: turbulentDFSEMInlet | word | yes | -
delta | Local limiting length scale | yes | delta | Characteristic length scale | scalar | yes | -
R | Reynolds stress field | no | R | Reynolds-stress tensor field <!--
U | Velocity field | no | --> | PatchFunction1\<symmTensor\> | yes | -
L | Turbulence length scale field | no | U | Mean velocity field <!--
d | Eddy density (fill fraction) | no | 1 --> | PatchFunction1<vector> | yes | -
kappa | Von Karman constant | no | 0.41 L | Integral-length scale field <!--
mapMethod | Method to map reference values | no | nearestCell --> | PatchFunction1<scalar> | yes | -
perturb | Point perturbation for interpolation | no | 1e-5 d | Ratio of sum of eddy volumes to eddy box volume <!--
interpolateR | Flag to interpolate the R field | no | false --> i.e. eddy density (fill fraction) | scalar | no | 1.0
interpolateL | Flag to interpolate the L field | no | false nCellPerEddy | Minimum eddy length in units of number of cells <!--
interpolateU | Flag to interpolate the U field | no | false --> | label | no | 5
writeEddies | Flag to write eddies as OBJ file | no | no kappa | von Karman constant | scalar | no | 0.41
Uref | Normalisation factor for Reynolds-stress <!--
--> tensor and mean velocity | scalar | no | 1.0
Lref | Normalisation factor for integral-length scale <!--
--> | scalar | no | 1.0
scale | Heuristic scaling factor being applied <!--
--> on the normalisation factor C1 | scalar | no | 1.0
m | The power of V defined in C1 | scalar | no | 0.5
writeEddies | Flag to write eddies as OBJ file | bool | no | false
\endtable \endtable
Note The inherited entries are elaborated in:
- The \c delta value typically represents the characteristic scale of flow - \link fixedValueFvPatchFields.H \endlink
or flow domain, e.g. a channel half-height - \link PatchFunction1.H \endlink
- For \c R, \c U and \c L specification: if the entry is not user input, - \link MappedFile.H \endlink
it is assumed that the data will be mapped
SeeAlso Note
timeVaryingMappedFixedValueFvPatchField - The \c delta value typically represents the characteristic scale of flow
turbulentDigitalFilterInlet or flow domain, e.g. a channel half height for plane channel flows.
- \c nCellPerEddy and \c scale entries are heuristic entries
which do not exist in the standard method, yet are necessary
to reproduce the results published in the original journal paper.
- In the original journal paper, \c C1 in Eq. 11 is not dimensionless.
It is not clear whether this dimensionality issue was intentional.
To alleviate this matter, users can alter the input entry \c m, which is
the power of the eddy-box volume defined in the \c C1, to obtain a
dimensionless \c C1 coefficient. The default value of \c m is 0.5,
which is the value stated in the original journal paper,
and \c m=1/3 leads to a dimensionless \c C1.
SourceFiles SourceFiles
turbulentDFSEMInletFvPatchVectorField.C turbulentDFSEMInletFvPatchVectorField.C
@ -94,15 +145,13 @@ SourceFiles
#include "Random.H" #include "Random.H"
#include "eddy.H" #include "eddy.H"
#include "pointIndexHit.H" #include "pointIndexHit.H"
#include "instantList.H" #include "PatchFunction1.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam namespace Foam
{ {
class pointToPointPlanarInterpolation;
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class turbulentDFSEMInletFvPatchVectorField Declaration Class turbulentDFSEMInletFvPatchVectorField Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -116,50 +165,38 @@ class turbulentDFSEMInletFvPatchVectorField
//- Maximum number of attempts when seeding eddies //- Maximum number of attempts when seeding eddies
static label seedIterMax_; static label seedIterMax_;
//- Characteristic length scale, e.g. half channel height //- Mean velocity field
autoPtr<PatchFunction1<vector>> U_;
//- Reynolds stress tensor field
autoPtr<PatchFunction1<symmTensor>> R_;
//- Integral-length scale field
autoPtr<PatchFunction1<scalar>> L_;
//- Characteristic length scale
const scalar delta_; const scalar delta_;
//- Ratio of sum of eddy volumes to eddy box volume; default = 1 //- Ratio of sum of eddy volumes to eddy box volume, i.e. eddy density
const scalar d_; const scalar d_;
//- Von Karman constant //- von Karman constant
const scalar kappa_; const scalar kappa_;
//- Global numbering for faces //- Normalisation factor for Reynolds-stress tensor and mean velocity
mutable autoPtr<globalIndex> globalFacesPtr_; const scalar Uref_;
//- Normalisation factor for integral-length scale
const scalar Lref_;
// Table reading for patch inlet flow properties //- Heuristic scaling factor being applied on the normalisation factor
const scalar scale_;
//- Fraction of perturbation (fraction of bounding box) to add //- The power of V defined in C1
scalar perturb_; const scalar m_;
//- Interpolation scheme to use (nearestCell | planarInterpolation) //- Minimum eddy length in units of number of cells
word mapMethod_; const label nCellPerEddy_;
//- 2D interpolation (for 'planarInterpolation' mapMethod)
mutable autoPtr<pointToPointPlanarInterpolation> mapperPtr_;
//- Flag to identify to interpolate the R field
bool interpolateR_;
//- Flag to identify to interpolate the L field
bool interpolateL_;
//- Flag to identify to interpolate the U field
bool interpolateU_;
//- Reynolds stress tensor
symmTensorField R_;
//- Length scale
scalarField L_;
//- Inlet velocity
vectorField U_;
//- Mean inlet velocity
vector UMean_;
// Patch information // Patch information
@ -179,46 +216,51 @@ class turbulentDFSEMInletFvPatchVectorField
//- Cumulative area fractions per processor //- Cumulative area fractions per processor
scalarList sumTriMagSf_; scalarList sumTriMagSf_;
//- Patch normal into the domain
vector patchNormal_;
//- List of eddies //- Patch bounds (local processor)
List<eddy> eddies_; boundBox patchBounds_;
//- Minimum number of cells required to resolve an eddy
label nCellPerEddy_;
//- Patch normal into the domain // Eddy information
vector patchNormal_;
//- Eddy box volume //- List of eddies
scalar v0_; List<eddy> eddies_;
//- Random number generator //- Eddy box volume
Random rndGen_; scalar v0_;
//- Length scale per patch face //- Random number generator
scalarField sigmax_; Random rndGen_;
//- Maximum length scale (across all processors) //- Integral-length scale per patch face
scalar maxSigmaX_; scalarField sigmax_;
//- Global number of eddies //- Maximum integral-length scale (across all processors)
label nEddy_; scalar maxSigmaX_;
//- Current time index (used for updating) //- Global number of eddies
label curTimeIndex_; label nEddy_;
//- Patch bounds (local processor) //- Current time index (used for updating)
boundBox patchBounds_; label curTimeIndex_;
//- Single processor contains all eddies (flag) //- Single processor contains all eddies (flag)
bool singleProc_; bool singleProc_;
//- Flag to write the eddies to file //- Flag to write the eddies to file
bool writeEddies_; bool writeEddies_;
// Private Member Functions // Private Member Functions
//- Write Lumley coefficients to file
void writeLumleyCoeffs() const;
//- Write eddy info in OBJ format
void writeEddyOBJ() const;
//- Initialise info for patch point search //- Initialise info for patch point search
void initialisePatch(); void initialisePatch();
@ -231,37 +273,11 @@ class turbulentDFSEMInletFvPatchVectorField
//- Initialise eddies //- Initialise eddies
void initialiseEddies(); void initialiseEddies();
//- Convect the eddies //- Convect the eddies with the bulk velocity
void convectEddies(const scalar deltaT); void convectEddies(const vector& UBulk, const scalar deltaT);
//- Calculate the velocity fluctuation at a point //- Return velocity fluctuation vector at a given point
vector uDashEddy(const List<eddy>& eddies, const point& globalX) const; vector uPrimeEddy(const List<eddy>& eddies, const point& globalX) const;
//- Helper function to interpolate values from the boundary data or
//- read from dictionary
template<class Type>
tmp<Field<Type>> interpolateOrRead
(
const word& fieldName,
const dictionary& dict,
bool& interpolateField
) const;
//- Helper function to interpolate values from the boundary data
template<class Type>
tmp<Field<Type>> interpolateBoundaryData
(
const word& fieldName
) const;
//- Write Lumley coefficients to file
void writeLumleyCoeffs() const;
//- Write eddy info in OBJ format
void writeEddyOBJ() const;
//- Return a reference to the patch mapper object
const pointToPointPlanarInterpolation& patchMapper() const;
//- Return eddies from remote processors that interact with local //- Return eddies from remote processors that interact with local
//- processor //- processor
@ -345,11 +361,11 @@ public:
// Member Functions // Member Functions
//- Helper function to check that Reynold stresses are valid //- Return true if input Reynold stresses are valid
static bool checkStresses(const symmTensorField& Rf); static bool checkStresses(const symmTensorField& Rf);
// Mapping functions // Mapping
//- Map (and resize as needed) from self given a mapping object //- Map (and resize as needed) from self given a mapping object
virtual void autoMap(const fvPatchFieldMapper& m); virtual void autoMap(const fvPatchFieldMapper& m);
@ -362,14 +378,16 @@ public:
); );
// Evaluation functions // Evaluation
//- Update the coefficients associated with the patch field //- Update the coefficients associated with the patch field
virtual void updateCoeffs(); virtual void updateCoeffs();
//- Write // IO
virtual void write(Ostream&) const;
//- Write
virtual void write(Ostream&) const;
}; };
@ -379,12 +397,6 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "turbulentDFSEMInletFvPatchVectorFieldTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif #endif
// ************************************************************************* // // ************************************************************************* //

View File

@ -1,109 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2015 OpenFOAM Foundation
Copyright (C) 2016-2020 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/>.
\*---------------------------------------------------------------------------*/
#include "pointToPointPlanarInterpolation.H"
#include "Time.H"
#include "rawIOField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::turbulentDFSEMInletFvPatchVectorField::interpolateOrRead
(
const word& fieldName,
const dictionary& dict,
bool& interpolateField
) const
{
if (dict.found(fieldName))
{
tmp<Field<Type>> tFld
(
new Field<Type>
(
fieldName,
dict,
this->patch().size()
)
);
interpolateField = false;
return tFld;
}
else
{
interpolateField = true;
return interpolateBoundaryData<Type>(fieldName);
}
}
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::turbulentDFSEMInletFvPatchVectorField::interpolateBoundaryData
(
const word& fieldName
) const
{
const word& patchName = this->patch().name();
const fileName valsFile
(
fileName
(
this->db().time().globalPath()
/this->db().time().constant()
/"boundaryData"
/patchName
/"0"
/fieldName
)
);
IOobject io
(
valsFile, // absolute path
this->db().time(),
IOobject::MUST_READ,
IOobject::NO_WRITE,
false, // no need to register
true // is global object (currently not used)
);
const rawIOField<Type> vals(io, false);
Info<< "Turbulent DFSEM patch " << patchName
<< ": interpolating field " << fieldName
<< " from " << valsFile << endl;
return patchMapper().interpolate(vals);
}
// ************************************************************************* //