Conservative GGI bridging updates and fixes

Scaling the fluxes and killing non-orthogonal correction vectors in case
bridging is used, both in order to ensure global conservation across bridged GGI
with potentially partially overlapping faces.
This commit is contained in:
Vuko Vukcevic 2018-03-15 07:43:51 +01:00
parent 412eaba6a5
commit 88cdcdc222
6 changed files with 101 additions and 74 deletions

View file

@ -119,6 +119,7 @@ $(constraintFvPatchFields)/symmetry/symmetryFvPatchFields.C
$(constraintFvPatchFields)/wedge/wedgeFvPatchFields.C
$(constraintFvPatchFields)/wedge/wedgeFvPatchScalarField.C
$(constraintFvPatchFields)/wedge/wedgeFvPatchVectorNFields.C
$(constraintFvPatchFields)/ggi/ggiFvPatchScalarField.C
$(constraintFvPatchFields)/ggi/ggiFvPatchFields.C
$(constraintFvPatchFields)/ggi/ggiFvPatchVectorNFields.C
$(constraintFvPatchFields)/jumpGgi/jumpGgiFvPatchFields.C

View file

@ -38,6 +38,7 @@ Note on parallelisation
#include "ggiFvPatchField.H"
#include "symmTransformField.H"
#include "coeffFields.H"
#include "fvMatrices.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -520,12 +521,6 @@ void Foam::ggiFvPatchField<Type>::manipulateValueCoeffs
// Scale partially overlapping boundary coeffs to ensure conservation
ggiPatch_.shadow().scalePartialFaces(slaveBC);
// Info<< "MANIPULATING VALUE COEFFS" << endl;
// Info<< "Slave internal coeffs: " << slaveIC << nl
// << "Slave boundary coeffs: " << slaveBC << nl
// << "Master internal coeffs: " << masterIC << nl
// << "Master boundary coeffs: " << masterBC << endl;
}
}
@ -552,12 +547,6 @@ void Foam::ggiFvPatchField<Type>::manipulateGradientCoeffs
Field<Type>& slaveIC = matrix.internalCoeffs()[sPatchI];
Field<Type>& slaveBC = matrix.boundaryCoeffs()[sPatchI];
// Info<< "ORIGINAL COEFFS" << endl;
// Info<< "Slave internal coeffs: " << slaveIC << nl
// << "Slave boundary coeffs: " << slaveBC << nl
// << "Master internal coeffs: " << masterIC << nl
// << "Master boundary coeffs: " << masterBC << endl;
// Get surface area magnitudes
const scalarField& magSfMaster = ggiPatch_.magSf();
const scalarField& magSfSlave = ggiPatch_.shadow().magSf();
@ -579,12 +568,6 @@ void Foam::ggiFvPatchField<Type>::manipulateGradientCoeffs
const Field<Type> slaveInterpolatedBC =
magSfMaster*ggiPatch_.interpolate(slaveBC/magSfSlave);
// Info<< "INTERPOLATED COEFFS" << endl;
// Info<< "Slave internal coeffs: " << slaveInterpolatedIC << nl
// << "Slave boundary coeffs: " << slaveInterpolatedBC << nl
// << "Master internal coeffs: " << masterInterpolatedIC << nl
// << "Master boundary coeffs: " << masterInterpolatedBC << endl;
// Set partially covered master coeffs using slave data
ggiPatch_.setPartialFaces(slaveInterpolatedBC, masterIC);
@ -610,12 +593,6 @@ void Foam::ggiFvPatchField<Type>::manipulateGradientCoeffs
// Add to partially overlapping slave internal coeffs to ensure
// conservation. Note: boundary coeffs must be negated
ggiPatch_.shadow().addToPartialFaces((-slaveBC)(), slaveIC);
// Info<< "MANIPULATING GRADIENT COEFFS" << endl;
// Info<< "Slave internal coeffs: " << slaveIC << nl
// << "Slave boundary coeffs: " << slaveBC << nl
// << "Master internal coeffs: " << masterIC << nl
// << "Master boundary coeffs: " << masterBC << endl;
}
}

View file

@ -290,6 +290,8 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "ggiFvPatchScalarField.H"
#ifdef NoRepository
# include "ggiFvPatchField.C"
#endif

View file

@ -25,13 +25,14 @@ Author
Vuko Vukcevic, Wikki Ltd. All rights reserved
Description
Specilalisation of manipulateMatrix member function for scalars needed to
Specilalisation of patchFlux member function for scalars needed to
ensure conservation across GGI patches that are partially covered if the
bridge overlap switch is on.
\*---------------------------------------------------------------------------*/
#include "ggiFvPatchField.H"
#include "surfaceFields.H"
#include "fvScalarMatrix.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -42,51 +43,87 @@ namespace Foam
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<>
void Foam::ggiFvPatchField<scalar>::manipulateMatrix(fvMatrix<scalar>& matrix)
void Foam::ggiFvPatchField<scalar>::patchFlux
(
GeometricField<scalar, fvsPatchField, surfaceMesh>& flux,
const fvMatrix<scalar>& matrix
) const
{
Info<< "IN MANIPULATE MATRIX!" << endl;
// Since we have adjusted the internal/boundary coefficients in the
// manipulateMatrix member function below, we must not use
// patchNeighbourField for reconstructing the flux. We only need to use
// interpolated shadow field. VV, 6/Mar/2018.
// Get patch ID
const label patchI = this->patch().index();
// Get internal field
const scalarField& iField = this->internalField();
// Get shadow face-cells and assemble shadow field
const unallocLabelList& sfc = ggiPatch_.shadow().faceCells();
scalarField sField(sfc.size());
forAll (sField, i)
{
sField[i] = iField[sfc[i]];
}
// Interpolate shadow to this side. Note: must not bridge since internal
// coeffs and boundary coeffs take it into account
scalarField neighbourField(ggiPatch_.interpolate(sField));
// Conservative treatment for bridged overlap
if (ggiPatch_.bridgeOverlap())
{
// Get this patch and shadow patch index
const label patchI = this->patch().index();
const label sPatchI = ggiPatch_.shadowIndex();
// Only set fully uncovered faces. Partially covered faces taken into
// account by manipulating value and gradient matrix coefficients. Note:
// mirror field is the same as patch internal field
ggiPatch_.setUncoveredFaces
(
this->patchInternalField()(),
neighbourField
);
}
// Get all matrix coefficients
scalarField& thisIC = matrix.internalCoeffs()[patchI];
scalarField& thisBC = matrix.boundaryCoeffs()[patchI];
scalarField& shadowIC = matrix.internalCoeffs()[sPatchI];
scalarField& shadowBC = matrix.boundaryCoeffs()[sPatchI];
// Calculate the flux with correct neighbour field (fully uncovered faces
// bridged, while partially uncovered faces taken into account by
// manipulating value and gradient matrix coefficients in order to ensure
// conservation for both convection and diffusion part across partially
// overlapping faces). VV, 14/Mar/2018.
flux.boundaryField()[patchI] =
matrix.internalCoeffs()[patchI]*this->patchInternalField()
- matrix.boundaryCoeffs()[patchI]*neighbourField;
// if (!ggiPatch_.master())
// Scale the flux on slave patch to ensure global conservation across this
// partially overlapping GGI patch. The slight disbalance can happen since
// we interpolate the matrix coeffs and field separately, and we should do
// it together to ensure conservation. Current code design does not easily
// allow this, so this is a meaningful temporary solution when we have
// partially overlapping faces. VV, 14/Mar/2018.
if (ggiPatch_.bridgeOverlap() && !ggiPatch_.master())
{
// This is master, interpolate shadow on this side
const scalarField shadowInterpolatedIC = ggiPatch_.interpolate(shadowIC);
const scalarField shadowInterpolatedBC = ggiPatch_.interpolate(shadowBC);
// This is slave patch, master already updated the fluxes and we can use
// that info to scale the fluxes on this side
// Set new internal coeffs using the data from the other side and
// taking into account partially and fully uncovered faces
const scalarField origIC = thisIC;
thisIC = shadowInterpolatedBC;
ggiPatch_.scaleForPartialCoverage(origIC, thisIC);
ggiPatch_.scaleForPartialCoverage(origIC, thisIC);
// Get the total flux through master patch
const scalar masterFlux =
gSum(flux.boundaryField()[ggiPatch_.shadowIndex()]);
// Set new boundary coeffs using the data from the other side and
// taking into account partially and fully uncovered faces
const scalarField origBC = thisBC;
thisBC = shadowInterpolatedIC;
ggiPatch_.scaleForPartialCoverage(origBC, thisBC);
ggiPatch_.scaleForPartialCoverage(origBC, thisBC);
// Get the total flux through slave patch
const scalar slaveFlux = gSum(flux.boundaryField()[patchI]);
Info<< "This new internal coeffs: " << thisIC << nl
<< "This old internal coeffs: " << origIC << nl
<< "This shadow boundary coeffs" << shadowBC << nl << endl;
// Calculate the scaling factor. Note: negative sign since master and
// slave fluxes have opposite sign
const scalar scalingFactor = -masterFlux/(slaveFlux + SMALL);
Info<< "This new boundary coeffs: " << thisBC << nl
<< "This old boundary coeffs: " << origBC << nl
<< "This shadow internale coeffs" << shadowIC << nl << endl;
// Scale the slave flux to ensure global patch conservation
flux.boundaryField()[patchI] *= scalingFactor;
if (debug)
{
Info<< "Scaling flux on patch: " << ggiPatch_.name()
<< " with " << scalingFactor
<< " to ensure conservation." << endl;
}
}
}

View file

@ -25,7 +25,7 @@ Author
Vuko Vukcevic, Wikki Ltd. All rights reserved
Description
Specilalisation of manipulateMatrix member function for scalars needed to
Specilalisation of patchFlux member function for scalars needed to
ensure conservation across GGI patches that are partially covered if the
bridge overlap switch is on.
@ -47,10 +47,11 @@ namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<>
void Foam::ggiFvPatchField<scalar>::manipulateMatrix
void Foam::ggiFvPatchField<scalar>::patchFlux
(
fvMatrix<scalar>& matrix
);
GeometricField<scalar, fvsPatchField, surfaceMesh>& flux,
const fvMatrix<scalar>& matrix
) const;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View file

@ -156,6 +156,14 @@ void Foam::ggiFvPatch::makeCorrVecs(vectorField& cv) const
// Non-orthogonality correction on a ggi interface
// MB, 7/April/2009
// No non-orthognal correction if the bridge overlap is switched on to
// ensure conservative interpolation for partially overlapping faces
if (bridgeOverlap())
{
cv = vector::zero;
}
else
{
// Calculate correction vectors on coupled patches
const scalarField& patchDeltaCoeffs = deltaCoeffs();
@ -165,6 +173,7 @@ void Foam::ggiFvPatch::makeCorrVecs(vectorField& cv) const
// If non-orthogonality is over 90 deg, kill correction vector
// HJ, 6/Jan/2011
cv = pos(patchDeltas & n)*(n - patchDeltas*patchDeltaCoeffs);
}
}