ENH: finiteArea: improve robustness in code sections vulnerable to math errors

It has been observed that the finite-area framework is prone to numerical
issues when zero-valued edge lenghts, edge/face normals and face areas exist.

To improve exception handling at identified code sections to gracefully
overcome math errors, the problematic entities are lower-bounded by SMALL.
This commit is contained in:
Kutalmis Bercin
2022-12-02 15:49:20 +00:00
committed by Mark OLESEN
parent d5b7200295
commit a0f1e98d24
6 changed files with 166 additions and 38 deletions

View File

@ -4,7 +4,7 @@
sqrt sqrt
( (
2*M_PI*sigma*sqr(aMesh.edgeInterpolation::deltaCoeffs()) 2*M_PI*sigma*sqr(aMesh.edgeInterpolation::deltaCoeffs())
*aMesh.edgeInterpolation::deltaCoeffs() *mag(aMesh.edgeInterpolation::deltaCoeffs())
/rhol /rhol
) )
).value()*runTime.deltaT().value(); ).value()*runTime.deltaT().value();

View File

@ -594,6 +594,12 @@ Foam::tmp<Foam::vectorField> Foam::faMesh::calcRawEdgeNormals(int order) const
edgeNormals[edgei].removeCollinear(edgeLine.unitVec()); edgeNormals[edgei].removeCollinear(edgeLine.unitVec());
edgeNormals[edgei].normalise(); edgeNormals[edgei].normalise();
// Do not allow any mag(val) < SMALL
if (mag(edgeNormals[edgei]) < SMALL)
{
edgeNormals[edgei] = vector::uniform(SMALL);
}
} }
return tedgeNormals; return tedgeNormals;
@ -658,6 +664,12 @@ void Foam::faMesh::calcLe() const
edges_[edgei].line(localPoints), edges_[edgei].line(localPoints),
edgeNormals[edgei] edgeNormals[edgei]
); );
// Do not allow any mag(val) < SMALL
if (mag(leVectors[edgei]) < SMALL)
{
leVectors[edgei] = vector::uniform(SMALL);
}
} }
// Copy internal field // Copy internal field
@ -672,6 +684,15 @@ void Foam::faMesh::calcLe() const
{ {
const faPatch& fap = boundary()[patchi]; const faPatch& fap = boundary()[patchi];
bfld[patchi] = fap.patchRawSlice(leVectors); bfld[patchi] = fap.patchRawSlice(leVectors);
for (auto& patchEdge : bfld[patchi])
{
// Do not allow any mag(val) < SMALL
if (mag(patchEdge) < SMALL)
{
patchEdge = vector::uniform(SMALL);
}
}
} }
} }
else else
@ -692,6 +713,12 @@ void Foam::faMesh::calcLe() const
edges_[edgei].line(localPoints), edges_[edgei].line(localPoints),
edgeNormals[edgei] edgeNormals[edgei]
); );
// Do not allow any mag(val) < SMALL
if (mag(fld[edgei]) < SMALL)
{
fld[edgei] = vector::uniform(SMALL);
}
} }
} }
@ -715,6 +742,12 @@ void Foam::faMesh::calcLe() const
bndEdgeNormals[patchEdgei] bndEdgeNormals[patchEdgei]
); );
// Do not allow any mag(val) < SMALL
if (mag(pfld[patchEdgei]) < SMALL)
{
pfld[patchEdgei] = vector::uniform(SMALL);
}
++edgei; ++edgei;
} }
} }
@ -759,6 +792,13 @@ void Foam::faMesh::calcMagLe() const
for (const edge& e : internalEdges()) for (const edge& e : internalEdges())
{ {
*iter = e.mag(localPoints); *iter = e.mag(localPoints);
// Do not allow any mag(val) < SMALL
if (mag(*iter) < SMALL)
{
*iter = SMALL;
}
++iter; ++iter;
} }
} }
@ -774,6 +814,13 @@ void Foam::faMesh::calcMagLe() const
for (const edge& e : boundary()[patchi].patchSlice(edges_)) for (const edge& e : boundary()[patchi].patchSlice(edges_))
{ {
*iter = e.mag(localPoints); *iter = e.mag(localPoints);
// Do not allow any mag(val) < SMALL
if (mag(*iter) < SMALL)
{
*iter = SMALL;
}
++iter; ++iter;
} }
} }
@ -955,6 +1002,12 @@ void Foam::faMesh::calcS() const
forAll(fld, facei) forAll(fld, facei)
{ {
fld[facei] = Foam::mag(meshFaceAreas[facei]); fld[facei] = Foam::mag(meshFaceAreas[facei]);
// Do not allow any mag(val) < SMALL
if (mag(fld[facei]) < SMALL)
{
fld[facei] = SMALL;
}
} }
} }
else else
@ -968,6 +1021,13 @@ void Foam::faMesh::calcS() const
for (const face& f : faces()) for (const face& f : faces())
{ {
*iter = f.mag(localPoints); *iter = f.mag(localPoints);
// Do not allow any mag(val) < SMALL
if (mag(*iter) < SMALL)
{
*iter = SMALL;
}
++iter; ++iter;
} }
} }
@ -1028,6 +1088,15 @@ void Foam::faMesh::calcFaceAreaNormals() const
// Make unit normals // Make unit normals
fld.normalise(); fld.normalise();
for (auto& f : fld)
{
// Do not allow any mag(val) < SMALL
if (mag(f) < SMALL)
{
f = vector::uniform(SMALL);
}
}
} }
@ -1122,6 +1191,12 @@ void Foam::faMesh::calcEdgeAreaNormals() const
fld[edgei].removeCollinear(edgeLine.unitVec()); fld[edgei].removeCollinear(edgeLine.unitVec());
fld[edgei].normalise(); fld[edgei].normalise();
// Do not allow any mag(val) < SMALL
if (mag(fld[edgei]) < SMALL)
{
fld[edgei] = vector::uniform(SMALL);
}
} }
} }
@ -1148,6 +1223,12 @@ void Foam::faMesh::calcEdgeAreaNormals() const
pfld[patchEdgei].removeCollinear(edgeLine.unitVec()); pfld[patchEdgei].removeCollinear(edgeLine.unitVec());
pfld[patchEdgei].normalise(); pfld[patchEdgei].normalise();
// Do not allow any mag(val) < SMALL
if (mag(pfld[patchEdgei]) < SMALL)
{
pfld[patchEdgei] = vector::uniform(SMALL);
}
} }
} }
} }

View File

@ -478,7 +478,19 @@ Foam::tmp<Foam::vectorField> Foam::faPatch::delta() const
{ {
// Use patch-normal delta for all non-coupled BCs // Use patch-normal delta for all non-coupled BCs
const vectorField nHat(edgeNormals()); const vectorField nHat(edgeNormals());
return nHat*(nHat & (edgeCentres() - edgeFaceCentres()));
vectorField edgePN(edgeCentres() - edgeFaceCentres());
// Do not allow any mag(val) < SMALL
for (vector& edgei : edgePN)
{
if (mag(edgei) < SMALL)
{
edgei = vector::uniform(SMALL);
}
}
return nHat*(nHat & edgePN);
} }

View File

@ -115,6 +115,13 @@ void Foam::leastSquaresFaVectors::makeLeastSquaresVectors() const
label nei = neighbour[facei]; label nei = neighbour[facei];
vector d = C[nei] - C[own]; vector d = C[nei] - C[own];
// Do not allow any mag(val) < SMALL
if (mag(d) < SMALL)
{
d = vector::uniform(SMALL);
}
symmTensor wdd = (1.0/magSqr(d))*sqr(d); symmTensor wdd = (1.0/magSqr(d))*sqr(d);
dd[own] += wdd; dd[own] += wdd;
@ -169,6 +176,13 @@ void Foam::leastSquaresFaVectors::makeLeastSquaresVectors() const
label nei = neighbour[facei]; label nei = neighbour[facei];
vector d = C[nei] - C[own]; vector d = C[nei] - C[own];
// Do not allow any mag(val) < SMALL
if (mag(d) < SMALL)
{
d = vector::uniform(SMALL);
}
scalar magSfByMagSqrd = 1.0/magSqr(d); scalar magSfByMagSqrd = 1.0/magSqr(d);
lsP[facei] = magSfByMagSqrd*(invDd[own] & d); lsP[facei] = magSfByMagSqrd*(invDd[own] & d);

View File

@ -248,6 +248,12 @@ void Foam::edgeInterpolation::makeLPN() const
); );
lPNIn[edgeI] = (lPE + lEN); lPNIn[edgeI] = (lPE + lEN);
// Do not allow any mag(val) < SMALL
if (mag(lPNIn[edgeI]) < SMALL)
{
lPNIn[edgeI] = SMALL;
}
} }
@ -287,7 +293,7 @@ void Foam::edgeInterpolation::makeWeights() const
false false
), ),
mesh(), mesh(),
dimless dimensionedScalar(dimless, 1)
); );
edgeScalarField& weightingFactors = *weightingFactors_; edgeScalarField& weightingFactors = *weightingFactors_;
@ -323,15 +329,12 @@ void Foam::edgeInterpolation::makeWeights() const
+ skewCorrEdge + skewCorrEdge
); );
weightingFactorsIn[edgeI] = // weight = (0,1]
lEN const scalar lPN = lPE + lEN;
/( if (mag(lPN) > SMALL)
lPE {
# ifdef BAD_MESH_STABILISATION weightingFactorsIn[edgeI] = lEN/lPN;
+ VSMALL }
# endif
+ lEN
);
} }
forAll(mesh().boundary(), patchI) forAll(mesh().boundary(), patchI)
@ -370,7 +373,7 @@ void Foam::edgeInterpolation::makeDeltaCoeffs() const
false false
), ),
mesh(), mesh(),
dimless/dimLength dimensionedScalar(dimless/dimLength, SMALL)
); );
edgeScalarField& DeltaCoeffs = *differenceFactors_; edgeScalarField& DeltaCoeffs = *differenceFactors_;
scalarField& dc = DeltaCoeffs.primitiveFieldRef(); scalarField& dc = DeltaCoeffs.primitiveFieldRef();
@ -427,11 +430,12 @@ void Foam::edgeInterpolation::makeDeltaCoeffs() const
// Edge normal - area tangent // Edge normal - area tangent
edgeNormal = normalised(lengths[edgeI]); edgeNormal = normalised(lengths[edgeI]);
// Delta coefficient as per definition // Do not allow any mag(val) < SMALL
// dc[edgeI] = 1.0/(lPN*(unitDelta & edgeNormal)); const scalar alpha = lPN*(unitDelta & edgeNormal);
if (mag(alpha) > SMALL)
// Stabilised form for bad meshes. HJ, 23/Jul/2009 {
dc[edgeI] = 1.0/max((lPN*(unitDelta & edgeNormal)), 0.05*lPN); dc[edgeI] = scalar(1)/max(alpha, 0.05*lPN);
}
} }
@ -478,7 +482,7 @@ void Foam::edgeInterpolation::makeCorrectionVectors() const
const edgeList& edges = mesh().edges(); const edgeList& edges = mesh().edges();
const pointField& points = mesh().points(); const pointField& points = mesh().points();
scalarField deltaCoeffs(owner.size()); scalarField deltaCoeffs(owner.size(), SMALL);
vectorField& CorrVecsIn = CorrVecs.primitiveFieldRef(); vectorField& CorrVecsIn = CorrVecs.primitiveFieldRef();
@ -499,8 +503,12 @@ void Foam::edgeInterpolation::makeCorrectionVectors() const
// Edge normal - area tangent // Edge normal - area tangent
edgeNormal = normalised(lengths[edgeI]); edgeNormal = normalised(lengths[edgeI]);
// Delta coeffs // Do not allow any mag(val) < SMALL
deltaCoeffs[edgeI] = 1.0/(unitDelta & edgeNormal); const scalar alpha = unitDelta & edgeNormal;
if (mag(alpha) > SMALL)
{
deltaCoeffs[edgeI] = scalar(1)/alpha;
}
// Edge correction vector // Edge correction vector
CorrVecsIn[edgeI] = CorrVecsIn[edgeI] =
@ -570,7 +578,7 @@ void Foam::edgeInterpolation::makeSkewCorrectionVectors() const
false false
), ),
mesh(), mesh(),
dimless dimensionedVector(dimless, Zero)
); );
edgeVectorField& SkewCorrVecs = *skewCorrectionVectors_; edgeVectorField& SkewCorrVecs = *skewCorrectionVectors_;
@ -590,19 +598,22 @@ void Foam::edgeInterpolation::makeSkewCorrectionVectors() const
const vector& P = C[owner[edgeI]]; const vector& P = C[owner[edgeI]];
const vector& N = C[neighbour[edgeI]]; const vector& N = C[neighbour[edgeI]];
const vector& S = points[edges[edgeI].start()]; const vector& S = points[edges[edgeI].start()];
vector e = edges[edgeI].vec(points);
const scalar beta = magSqr((N - P)^e); // (T:Eq. 5.4)
const vector d(N - P);
const vector e(edges[edgeI].vec(points));
const vector de(d^e);
const scalar alpha = magSqr(de);
if (beta < ROOTVSMALL) if (alpha < SMALL)
{ {
// Too small - skew correction remains zero // Too small - skew correction remains zero
continue; continue;
} }
const scalar beta = -((d^(S - P)) & de)/alpha;
const scalar alpha = -(((N - P)^(S - P))&((N - P)^e))/beta; // (T:Eq. 5.3)
const vector E(S + beta*e);
vector E(S + alpha*e);
SkewCorrVecs[edgeI] = Ce[edgeI] - E; SkewCorrVecs[edgeI] = Ce[edgeI] - E;
} }
@ -630,28 +641,26 @@ void Foam::edgeInterpolation::makeSkewCorrectionVectors() const
const vector& P = C[edgeFaces[edgeI]]; const vector& P = C[edgeFaces[edgeI]];
const vector& N = ngbC[edgeI]; const vector& N = ngbC[edgeI];
const vector& S = points[patchEdges[edgeI].start()]; const vector& S = points[patchEdges[edgeI].start()];
vector e = patchEdges[edgeI].vec(points);
const scalar beta = magSqr((N - P)^e); // (T:Eq. 5.4)
const vector d(N - P);
const vector e(patchEdges[edgeI].vec(points));
const vector de(d^e);
const scalar alpha = magSqr(de);
if (beta < ROOTVSMALL) if (alpha < SMALL)
{ {
// Too small - skew correction remains zero // Too small - skew correction remains zero
continue; continue;
} }
const scalar beta = -((d^(S - P)) & de)/alpha;
const scalar alpha = -(((N - P)^(S - P))&((N - P)^e))/beta; const vector E(S + beta*e);
vector E(S + alpha*e);
patchSkewCorrVecs[edgeI] = patchSkewCorrVecs[edgeI] =
Ce.boundaryField()[patchI][edgeI] - E; Ce.boundaryField()[patchI][edgeI] - E;
} }
} }
else
{
patchSkewCorrVecs = vector::zero;
}
} }
#ifdef FA_SKEW_CORRECTION #ifdef FA_SKEW_CORRECTION

View File

@ -108,6 +108,12 @@ Foam::tmp<Foam::edgeScalarField> Foam::faNVDscheme<Type,NVDweight>::weights
d.normalise(); d.normalise();
d *= mesh.edgeInterpolation::lPN().internalField()[edge]; d *= mesh.edgeInterpolation::lPN().internalField()[edge];
// Do not allow any mag(val) < SMALL
if (mag(d) < SMALL)
{
d = vector::uniform(SMALL);
}
weights[edge] = weights[edge] =
this->weight this->weight
( (
@ -189,6 +195,12 @@ Foam::tmp<Foam::edgeScalarField> Foam::faNVDscheme<Type,NVDweight>::weights
d.normalise(); d.normalise();
d *= pLPN[edgeI]; d *= pLPN[edgeI];
// Do not allow any mag(val) < SMALL
if (mag(d) < SMALL)
{
d = vector::uniform(SMALL);
}
pWeights[edgeI] = pWeights[edgeI] =
this->weight this->weight
( (