/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019 Norbert Weber, HZDR
-------------------------------------------------------------------------------
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 "weightedFlux.H"
// * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
template
void Foam::weightedFlux::clearOut()
{
oDelta_.reset(nullptr);
nDelta_.reset(nullptr);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template
Foam::weightedFlux::~weightedFlux()
{
clearOut();
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template
void Foam::weightedFlux::makeDeltas() const
{
const fvMesh& mesh = this->mesh();
oDelta_ = std::make_unique
(
IOobject
(
"oDelta",
mesh.pointsInstance(),
mesh
),
mesh,
dimLength
);
auto& oDelta = *oDelta_;
nDelta_ = std::make_unique
(
IOobject
(
"nDelta",
mesh.pointsInstance(),
mesh
),
mesh,
dimLength
);
auto& nDelta = *nDelta_;
const labelUList& owner = mesh.owner();
const labelUList& neighbour = mesh.neighbour();
const surfaceVectorField n(mesh.Sf()/mesh.magSf());
const vectorField& C = mesh.cellCentres();
const vectorField& Cf = mesh.faceCentres();
// all distances are NORMAL to the face,
// as in the weighting factors in surfaceInterpolation.C
forAll(owner, facei)
{
oDelta[facei] =
mag(n[facei] & (C[owner[facei]] - Cf[facei]));
nDelta[facei] =
mag(n[facei] & (C[neighbour[facei]] - Cf[facei]));
}
const fvPatchList& patches = mesh.boundary();
forAll(patches, patchi)
{
const fvPatch& currPatch = mesh.boundary()[patchi];
// Patch normal vector
const vectorField nPatch(currPatch.Sf()/currPatch.magSf());
// Processor patch
if (currPatch.coupled())
{
const labelUList& pOwner = mesh.boundary()[patchi].faceCells();
const vectorField& pCf = mesh.Cf().boundaryField()[patchi];
forAll(pOwner, facei)
{
const label own = pOwner[facei];
// All distances are NORMAL to the face
oDelta.boundaryFieldRef()[patchi][facei] =
mag(nPatch[facei] & (pCf[facei] - C[own]));
}
// Weight = delta_neighbour / delta in ORTHOGONAL direction,
nDelta.boundaryFieldRef()[patchi] =
currPatch.weights()*oDelta.boundaryFieldRef()[patchi]
/(scalar(1) - currPatch.weights());
}
else
{
const labelUList& pOwner = mesh.boundary()[patchi].faceCells();
const vectorField& pCf = mesh.Cf().boundaryField()[patchi];
forAll(pOwner, facei)
{
const label own = pOwner[facei];
// All distances are NORMAL to the face!
oDelta.boundaryFieldRef()[patchi][facei] =
mag(nPatch[facei] & (pCf[facei] - C[own]));
nDelta.boundaryFieldRef()[patchi][facei] =
mag(nPatch[facei] & (pCf[facei] - C[own]));
}
}
}
}
template
Foam::tmp>
Foam::weightedFlux::interpolate
(
const GeometricField& vf
) const
{
const fvMesh& mesh = vf.mesh();
const surfaceScalarField& oDelta = weightedFlux::oDelta();
const surfaceScalarField& nDelta = weightedFlux::nDelta();
auto tresult = tmp>::New
(
IOobject
(
"weightedFlux::interpolate(" + vf.name() + ')',
mesh.time().timeName(),
mesh
),
mesh,
vf.dimensions()
);
auto& result = tresult.ref();
const labelUList& owner = mesh.owner();
const labelUList& neighbour = mesh.neighbour();
forAll(result, facei)
{
const scalar sigmaDeltaO = sigma_[owner[facei]]/oDelta[facei];
const scalar sigmaDeltaN = sigma_[neighbour[facei]]/nDelta[facei];
result[facei] =
(vf[owner[facei]]*sigmaDeltaO + vf[neighbour[facei]]*sigmaDeltaN)
/(sigmaDeltaO + sigmaDeltaN);
}
// Interpolate patches
auto& bfld = result.boundaryFieldRef();
forAll(bfld, patchi)
{
fvsPatchField& pfld = bfld[patchi];
// If not coupled - simply copy the boundary values of the field
if (!pfld.coupled())
{
pfld = vf.boundaryField()[patchi];
}
else
{
// e.g. processor patches have to calculated separately
const labelUList& pOwner = mesh.boundary()[patchi].faceCells();
scalarField sigmaN
(
sigma_.boundaryField()[patchi].patchNeighbourField()
);
Field vfO(vf.boundaryField()[patchi].patchInternalField());
Field vfN(vf.boundaryField()[patchi].patchNeighbourField());
forAll(pOwner, facei)
{
const label own = pOwner[facei];
const scalar sigmaDeltaO =
sigma_[own]/oDelta.boundaryField()[patchi][facei];
const scalar sigmaDeltaN =
sigmaN[facei]/nDelta.boundaryField()[patchi][facei];
pfld[facei] =
(vfO[facei]*sigmaDeltaO + vfN[facei]*sigmaDeltaN)
/(sigmaDeltaO + sigmaDeltaN);
}
}
}
return tresult;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
makeSurfaceInterpolationScheme(weightedFlux)
}
// ************************************************************************* //