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:
parent
412eaba6a5
commit
88cdcdc222
6 changed files with 101 additions and 74 deletions
|
@ -119,6 +119,7 @@ $(constraintFvPatchFields)/symmetry/symmetryFvPatchFields.C
|
||||||
$(constraintFvPatchFields)/wedge/wedgeFvPatchFields.C
|
$(constraintFvPatchFields)/wedge/wedgeFvPatchFields.C
|
||||||
$(constraintFvPatchFields)/wedge/wedgeFvPatchScalarField.C
|
$(constraintFvPatchFields)/wedge/wedgeFvPatchScalarField.C
|
||||||
$(constraintFvPatchFields)/wedge/wedgeFvPatchVectorNFields.C
|
$(constraintFvPatchFields)/wedge/wedgeFvPatchVectorNFields.C
|
||||||
|
$(constraintFvPatchFields)/ggi/ggiFvPatchScalarField.C
|
||||||
$(constraintFvPatchFields)/ggi/ggiFvPatchFields.C
|
$(constraintFvPatchFields)/ggi/ggiFvPatchFields.C
|
||||||
$(constraintFvPatchFields)/ggi/ggiFvPatchVectorNFields.C
|
$(constraintFvPatchFields)/ggi/ggiFvPatchVectorNFields.C
|
||||||
$(constraintFvPatchFields)/jumpGgi/jumpGgiFvPatchFields.C
|
$(constraintFvPatchFields)/jumpGgi/jumpGgiFvPatchFields.C
|
||||||
|
|
|
@ -38,6 +38,7 @@ Note on parallelisation
|
||||||
#include "ggiFvPatchField.H"
|
#include "ggiFvPatchField.H"
|
||||||
#include "symmTransformField.H"
|
#include "symmTransformField.H"
|
||||||
#include "coeffFields.H"
|
#include "coeffFields.H"
|
||||||
|
#include "fvMatrices.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
@ -520,12 +521,6 @@ void Foam::ggiFvPatchField<Type>::manipulateValueCoeffs
|
||||||
|
|
||||||
// Scale partially overlapping boundary coeffs to ensure conservation
|
// Scale partially overlapping boundary coeffs to ensure conservation
|
||||||
ggiPatch_.shadow().scalePartialFaces(slaveBC);
|
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>& slaveIC = matrix.internalCoeffs()[sPatchI];
|
||||||
Field<Type>& slaveBC = matrix.boundaryCoeffs()[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
|
// Get surface area magnitudes
|
||||||
const scalarField& magSfMaster = ggiPatch_.magSf();
|
const scalarField& magSfMaster = ggiPatch_.magSf();
|
||||||
const scalarField& magSfSlave = ggiPatch_.shadow().magSf();
|
const scalarField& magSfSlave = ggiPatch_.shadow().magSf();
|
||||||
|
@ -579,12 +568,6 @@ void Foam::ggiFvPatchField<Type>::manipulateGradientCoeffs
|
||||||
const Field<Type> slaveInterpolatedBC =
|
const Field<Type> slaveInterpolatedBC =
|
||||||
magSfMaster*ggiPatch_.interpolate(slaveBC/magSfSlave);
|
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
|
// Set partially covered master coeffs using slave data
|
||||||
ggiPatch_.setPartialFaces(slaveInterpolatedBC, masterIC);
|
ggiPatch_.setPartialFaces(slaveInterpolatedBC, masterIC);
|
||||||
|
@ -610,12 +593,6 @@ void Foam::ggiFvPatchField<Type>::manipulateGradientCoeffs
|
||||||
// Add to partially overlapping slave internal coeffs to ensure
|
// Add to partially overlapping slave internal coeffs to ensure
|
||||||
// conservation. Note: boundary coeffs must be negated
|
// conservation. Note: boundary coeffs must be negated
|
||||||
ggiPatch_.shadow().addToPartialFaces((-slaveBC)(), slaveIC);
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -290,6 +290,8 @@ public:
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#include "ggiFvPatchScalarField.H"
|
||||||
|
|
||||||
#ifdef NoRepository
|
#ifdef NoRepository
|
||||||
# include "ggiFvPatchField.C"
|
# include "ggiFvPatchField.C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,13 +25,14 @@ Author
|
||||||
Vuko Vukcevic, Wikki Ltd. All rights reserved
|
Vuko Vukcevic, Wikki Ltd. All rights reserved
|
||||||
|
|
||||||
Description
|
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
|
ensure conservation across GGI patches that are partially covered if the
|
||||||
bridge overlap switch is on.
|
bridge overlap switch is on.
|
||||||
|
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "ggiFvPatchField.H"
|
#include "ggiFvPatchField.H"
|
||||||
|
#include "surfaceFields.H"
|
||||||
#include "fvScalarMatrix.H"
|
#include "fvScalarMatrix.H"
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
@ -42,51 +43,87 @@ namespace Foam
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
template<>
|
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())
|
if (ggiPatch_.bridgeOverlap())
|
||||||
{
|
{
|
||||||
// Get this patch and shadow patch index
|
// Only set fully uncovered faces. Partially covered faces taken into
|
||||||
const label patchI = this->patch().index();
|
// account by manipulating value and gradient matrix coefficients. Note:
|
||||||
const label sPatchI = ggiPatch_.shadowIndex();
|
// mirror field is the same as patch internal field
|
||||||
|
ggiPatch_.setUncoveredFaces
|
||||||
|
(
|
||||||
|
this->patchInternalField()(),
|
||||||
|
neighbourField
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Get all matrix coefficients
|
// Calculate the flux with correct neighbour field (fully uncovered faces
|
||||||
scalarField& thisIC = matrix.internalCoeffs()[patchI];
|
// bridged, while partially uncovered faces taken into account by
|
||||||
scalarField& thisBC = matrix.boundaryCoeffs()[patchI];
|
// manipulating value and gradient matrix coefficients in order to ensure
|
||||||
scalarField& shadowIC = matrix.internalCoeffs()[sPatchI];
|
// conservation for both convection and diffusion part across partially
|
||||||
scalarField& shadowBC = matrix.boundaryCoeffs()[sPatchI];
|
// 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 slave patch, master already updated the fluxes and we can use
|
||||||
|
// that info to scale the fluxes on this side
|
||||||
|
|
||||||
|
// Get the total flux through master patch
|
||||||
|
const scalar masterFlux =
|
||||||
|
gSum(flux.boundaryField()[ggiPatch_.shadowIndex()]);
|
||||||
|
|
||||||
|
// Get the total flux through slave patch
|
||||||
|
const scalar slaveFlux = gSum(flux.boundaryField()[patchI]);
|
||||||
|
|
||||||
|
// Calculate the scaling factor. Note: negative sign since master and
|
||||||
|
// slave fluxes have opposite sign
|
||||||
|
const scalar scalingFactor = -masterFlux/(slaveFlux + SMALL);
|
||||||
|
|
||||||
|
// Scale the slave flux to ensure global patch conservation
|
||||||
|
flux.boundaryField()[patchI] *= scalingFactor;
|
||||||
|
|
||||||
|
if (debug)
|
||||||
{
|
{
|
||||||
// This is master, interpolate shadow on this side
|
Info<< "Scaling flux on patch: " << ggiPatch_.name()
|
||||||
const scalarField shadowInterpolatedIC = ggiPatch_.interpolate(shadowIC);
|
<< " with " << scalingFactor
|
||||||
const scalarField shadowInterpolatedBC = ggiPatch_.interpolate(shadowBC);
|
<< " to ensure conservation." << endl;
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
Info<< "This new internal coeffs: " << thisIC << nl
|
|
||||||
<< "This old internal coeffs: " << origIC << nl
|
|
||||||
<< "This shadow boundary coeffs" << shadowBC << nl << endl;
|
|
||||||
|
|
||||||
Info<< "This new boundary coeffs: " << thisBC << nl
|
|
||||||
<< "This old boundary coeffs: " << origBC << nl
|
|
||||||
<< "This shadow internale coeffs" << shadowIC << nl << endl;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ Author
|
||||||
Vuko Vukcevic, Wikki Ltd. All rights reserved
|
Vuko Vukcevic, Wikki Ltd. All rights reserved
|
||||||
|
|
||||||
Description
|
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
|
ensure conservation across GGI patches that are partially covered if the
|
||||||
bridge overlap switch is on.
|
bridge overlap switch is on.
|
||||||
|
|
||||||
|
@ -47,10 +47,11 @@ namespace Foam
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void Foam::ggiFvPatchField<scalar>::manipulateMatrix
|
void Foam::ggiFvPatchField<scalar>::patchFlux
|
||||||
(
|
(
|
||||||
fvMatrix<scalar>& matrix
|
GeometricField<scalar, fvsPatchField, surfaceMesh>& flux,
|
||||||
);
|
const fvMatrix<scalar>& matrix
|
||||||
|
) const;
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
|
@ -156,15 +156,24 @@ void Foam::ggiFvPatch::makeCorrVecs(vectorField& cv) const
|
||||||
// Non-orthogonality correction on a ggi interface
|
// Non-orthogonality correction on a ggi interface
|
||||||
// MB, 7/April/2009
|
// MB, 7/April/2009
|
||||||
|
|
||||||
// Calculate correction vectors on coupled patches
|
// No non-orthognal correction if the bridge overlap is switched on to
|
||||||
const scalarField& patchDeltaCoeffs = deltaCoeffs();
|
// ensure conservative interpolation for partially overlapping faces
|
||||||
|
if (bridgeOverlap())
|
||||||
|
{
|
||||||
|
cv = vector::zero;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Calculate correction vectors on coupled patches
|
||||||
|
const scalarField& patchDeltaCoeffs = deltaCoeffs();
|
||||||
|
|
||||||
const vectorField patchDeltas = delta();
|
const vectorField patchDeltas = delta();
|
||||||
const vectorField n = nf();
|
const vectorField n = nf();
|
||||||
|
|
||||||
// If non-orthogonality is over 90 deg, kill correction vector
|
// If non-orthogonality is over 90 deg, kill correction vector
|
||||||
// HJ, 6/Jan/2011
|
// HJ, 6/Jan/2011
|
||||||
cv = pos(patchDeltas & n)*(n - patchDeltas*patchDeltaCoeffs);
|
cv = pos(patchDeltas & n)*(n - patchDeltas*patchDeltaCoeffs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in a new issue