/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 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 .
\*---------------------------------------------------------------------------*/
#include "turbulentDFSEMInletFvPatchVectorField.H"
#include "volFields.H"
#include "addToRunTimeSelectionTable.H"
#include "fvPatchFieldMapper.H"
#include "momentOfInertia.H"
#include "cartesianCS.H"
#include "OFstream.H"
#include "globalIndex.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
Foam::label Foam::turbulentDFSEMInletFvPatchVectorField::seedIterMax_ = 1000;
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::turbulentDFSEMInletFvPatchVectorField::writeEddyOBJ() const
{
{
// Output the bounding box
OFstream os(db().time().path()/"eddyBox.obj");
const polyPatch& pp = this->patch().patch();
const labelList& boundaryPoints = pp.boundaryPoints();
const pointField& localPoints = pp.localPoints();
vector offset = patchNormal_*maxSigmaX_;
forAll(boundaryPoints, i)
{
point p = localPoints[boundaryPoints[i]];
p += offset;
os << "v " << p.x() << " " << p.y() << " " << p.z() << nl;
}
forAll(boundaryPoints, i)
{
point p = localPoints[boundaryPoints[i]];
p -= offset;
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;
//}
}
{
const Time& time = db().time();
OFstream os
(
time.path()/"eddies_" + Foam::name(time.timeIndex()) + ".obj"
);
label pointOffset = 0;
forAll(eddies_, eddyI)
{
const eddy& e = eddies_[eddyI];
pointOffset += e.writeSurfaceOBJ(pointOffset, patchNormal_, os);
}
}
}
void Foam::turbulentDFSEMInletFvPatchVectorField::writeLumleyCoeffs() const
{
// Output list of xi vs eta
// Before interpolation/raw data
if (interpolateR_)
{
AverageIOField Rexp
(
IOobject
(
"R",
this->db().time().caseConstant(),
"boundaryData"/patch().name()/"0",
this->db(),
IOobject::MUST_READ,
IOobject::AUTO_WRITE,
false
)
);
OFstream os(db().time().path()/"lumley_input.out");
os << "# xi" << token::TAB << "eta" << endl;
forAll(Rexp, faceI)
{
// 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_.empty())
{
// vectorGlobalIOField samplePoints
vectorIOField samplePoints
(
IOobject
(
"points",
this->db().time().caseConstant(),
"boundaryData"/this->patch().name(),
this->db(),
IOobject::MUST_READ,
IOobject::AUTO_WRITE,
false
)
);
const fileName samplePointsFile = samplePoints.filePath();
if (debug)
{
InfoInFunction
<< " 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_();
}
void Foam::turbulentDFSEMInletFvPatchVectorField::initialisePatch()
{
const vectorField nf(patch().nf());
// Patch normal points into domain
patchNormal_ = -gAverage(nf);
// Check that patch is planar
scalar error = max(magSqr(patchNormal_ + nf));
if (error > SMALL)
{
WarningInFunction
<< "Patch " << patch().name() << " is not planar"
<< endl;
}
patchNormal_ /= mag(patchNormal_) + ROOTVSMALL;
// Decompose the patch faces into triangles to enable point search
const polyPatch& patch = this->patch().patch();
const pointField& points = patch.points();
// Triangulate the patch faces and create addressing
DynamicList