ENH: enforce snGradTransformDiag() as zero for rotational-invariant

- the snGradTransformDiag() is used in this type of code:

  ```
  if constexpr (!is_rotational_vectorspace_v<Type>)
  {
      // Rotational-invariant type
      return tmp<Field<Type>>::New(this->size(), pTraits<Type>::one);
  }
  else
  {
      return pTraits<Type>::one - snGradTransformDiag();
  }
  ```

  This implies that a rotational-invariant form should return 0
  and not 1 like the pow(..., 0) does.
  This is a backstop for any code that may inadvertently hit it,
  but also allows the possibility of having integer indicator fields
  without upsetting the compiler.

STYLE: doTransform() logic now uses is_rotational_vectorspace
This commit is contained in:
Mark Olesen
2025-06-25 08:23:25 +02:00
committed by Mattijs Janssens
parent 4cc8423c94
commit 202b448b8f
24 changed files with 285 additions and 136 deletions

View File

@ -117,7 +117,7 @@ public:
// Member functions // Member functions
//- Constraint handling // Constraint handling
//- Return the constraint type this pointPatchField implements //- Return the constraint type this pointPatchField implements
virtual const word& constraintType() const virtual const word& constraintType() const
@ -125,12 +125,17 @@ public:
return cyclicPointPatch::typeName; return cyclicPointPatch::typeName;
} }
//- Cyclic coupled interface functions
// Cyclic coupled interface functions
//- Does the patch field perform the transformation //- Does the patch field perform the transformation
virtual bool doTransform() const virtual bool doTransform() const
{ {
return (pTraits<Type>::rank && !cyclicPatch_.parallel()); return
(
is_rotational_vectorspace_v<Type>
&& !cyclicPatch_.parallel()
);
} }
//- Return face transformation tensor //- Return face transformation tensor

View File

@ -125,7 +125,7 @@ public:
//- Return true if running parallel //- Return true if running parallel
virtual bool coupled() const virtual bool coupled() const
{ {
return Pstream::parRun(); return UPstream::parRun();
} }
//- Does the patch field perform the transformation //- Does the patch field perform the transformation
@ -133,7 +133,7 @@ public:
{ {
return return
( (
pTraits<Type>::rank is_rotational_vectorspace_v<Type>
&& !procPatch_.procPolyPatch().parallel() && !procPatch_.procPolyPatch().parallel()
); );
} }

View File

@ -133,7 +133,7 @@ public:
//- Return true if running parallel //- Return true if running parallel
virtual bool coupled() const virtual bool coupled() const
{ {
return Pstream::parRun(); return UPstream::parRun();
} }
//- Does the patch field perform the transformation //- Does the patch field perform the transformation
@ -141,7 +141,7 @@ public:
{ {
return return
( (
pTraits<Type>::rank is_rotational_vectorspace_v<Type>
&& !procPatch_.procPolyPatch().parallel() && !procPatch_.procPolyPatch().parallel()
); );
} }

View File

@ -140,11 +140,22 @@ void Foam::basicSymmetryFaPatchField<Type>::evaluate(const Pstream::commsTypes)
template<class Type> template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::basicSymmetryFaPatchField<Type>::snGradTransformDiag() const Foam::basicSymmetryFaPatchField<Type>::snGradTransformDiag() const
{
if constexpr (!is_rotational_vectorspace_v<Type>)
{
// Rotational-invariant type
// FatalErrorInFunction
// << "Should not be called for this type"
// << ::Foam::abort(FatalError);
return tmp<Field<Type>>::New(this->size(), Foam::zero{});
}
else
{ {
tmp<vectorField> diag(cmptMag(this->patch().edgeNormals())); tmp<vectorField> diag(cmptMag(this->patch().edgeNormals()));
return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag)); return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag));
} }
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -231,6 +231,9 @@ public:
const Pstream::commsTypes commsType const Pstream::commsTypes commsType
) const = 0; ) const = 0;
// Other
//- Write //- Write
virtual void write(Ostream&) const; virtual void write(Ostream&) const;
}; };

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2017 Wikki Ltd Copyright (C) 2016-2017 Wikki Ltd
Copyright (C) 2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -86,9 +87,9 @@ Foam::transformFaPatchField<Type>::valueInternalCoeffs
const tmp<scalarField>& const tmp<scalarField>&
) const ) const
{ {
// OR (!is_rotational_vectorspace_v<Type>) if constexpr (!is_rotational_vectorspace_v<Type>)
if constexpr (std::is_arithmetic_v<Type>)
{ {
// Rotational-invariant type
return tmp<Field<Type>>::New(this->size(), pTraits<Type>::one); return tmp<Field<Type>>::New(this->size(), pTraits<Type>::one);
} }
else else
@ -119,9 +120,9 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::transformFaPatchField<Type>::gradientInternalCoeffs() const Foam::transformFaPatchField<Type>::gradientInternalCoeffs() const
{ {
// OR (!is_rotational_vectorspace_v<Type>) if constexpr (!is_rotational_vectorspace_v<Type>)
if constexpr (std::is_arithmetic_v<Type>)
{ {
// Rotational-invariant type
return tmp<Field<Type>>::New(this->size(), Foam::zero{}); return tmp<Field<Type>>::New(this->size(), Foam::zero{});
} }
else else

View File

@ -183,7 +183,11 @@ public:
//- Does the patch field perform the transformation //- Does the patch field perform the transformation
virtual bool doTransform() const virtual bool doTransform() const
{ {
return (pTraits<Type>::rank && !cyclicPatch_.parallel()); return
(
is_rotational_vectorspace_v<Type>
&& !cyclicPatch_.parallel()
);
} }
//- Return face transformation tensor //- Return face transformation tensor

View File

@ -287,7 +287,11 @@ public:
//- Does the patch field perform the transformation //- Does the patch field perform the transformation
virtual bool doTransform() const virtual bool doTransform() const
{ {
return (pTraits<Type>::rank && !procPatch_.parallel()); return
(
is_rotational_vectorspace_v<Type>
&& !procPatch_.parallel()
);
} }
//- Return face transformation tensor //- Return face transformation tensor

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2017 Wikki Ltd Copyright (C) 2016-2017 Wikki Ltd
Copyright (C) 2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -154,10 +155,20 @@ void Foam::wedgeFaPatchField<Type>::evaluate(const Pstream::commsTypes)
template<class Type> template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::wedgeFaPatchField<Type>::snGradTransformDiag() const Foam::wedgeFaPatchField<Type>::snGradTransformDiag() const
{
if constexpr (!is_rotational_vectorspace_v<Type>)
{
// Rotational-invariant type
// FatalErrorInFunction
// << "Should not be called for this type"
// << ::Foam::abort(FatalError);
return tmp<Field<Type>>::New(this->size(), Foam::zero{});
}
else
{ {
const auto& rot = refCast<const wedgeFaPatch>(this->patch()).faceT(); const auto& rot = refCast<const wedgeFaPatch>(this->patch()).faceT();
const vector diagV = 0.5*(I - rot).diag(); const vector diag = 0.5*(I - rot).diag();
return tmp<Field<Type>>::New return tmp<Field<Type>>::New
( (
@ -166,7 +177,7 @@ Foam::wedgeFaPatchField<Type>::snGradTransformDiag() const
( (
pow pow
( (
diagV, diag,
pTraits pTraits
< <
typename powProduct<vector, pTraits<Type>::rank>::type typename powProduct<vector, pTraits<Type>::rank>::type
@ -175,6 +186,7 @@ Foam::wedgeFaPatchField<Type>::snGradTransformDiag() const
) )
); );
} }
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -114,9 +114,7 @@ public:
} }
// Member functions // Member Functions
// Evaluation functions
//- Return gradient at boundary //- Return gradient at boundary
virtual tmp<Field<Type>> snGrad() const; virtual tmp<Field<Type>> snGrad() const;
@ -127,7 +125,6 @@ public:
const Pstream::commsTypes commsType=Pstream::commsTypes::buffered const Pstream::commsTypes commsType=Pstream::commsTypes::buffered
); );
//- Return face-gradient transform diagonal //- Return face-gradient transform diagonal
virtual tmp<Field<Type>> snGradTransformDiag() const; virtual tmp<Field<Type>> snGradTransformDiag() const;
}; };

View File

@ -140,11 +140,22 @@ void Foam::basicSymmetryFvPatchField<Type>::evaluate(const Pstream::commsTypes)
template<class Type> template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::basicSymmetryFvPatchField<Type>::snGradTransformDiag() const Foam::basicSymmetryFvPatchField<Type>::snGradTransformDiag() const
{
if constexpr (!is_rotational_vectorspace_v<Type>)
{
// Rotational-invariant type
// FatalErrorInFunction
// << "Should not be called for this type"
// << ::Foam::abort(FatalError);
return tmp<Field<Type>>::New(this->size(), Foam::zero{});
}
else
{ {
tmp<vectorField> diag(cmptMag(this->patch().nf())); tmp<vectorField> diag(cmptMag(this->patch().nf()));
return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag)); return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag));
} }
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -178,27 +178,35 @@ void Foam::directionMixedFvPatchField<Type>::evaluate(const Pstream::commsTypes)
template<class Type> template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::directionMixedFvPatchField<Type>::snGradTransformDiag() const Foam::directionMixedFvPatchField<Type>::snGradTransformDiag() const
{
// static_assert(!std::is_arithmetic_v<T>, "direction-mixed with scalar??");
// if constexpr (!is_rotational_vectorspace_v<Type>)
// {
// // Rotational-invariant type
// return tmp<Field<Type>>::New(this->size(), Foam::zero{});
// }
{ {
vectorField diag(valueFraction_.size()); vectorField diag(valueFraction_.size());
diag.replace std::transform
( (
vector::X, valueFraction_.cbegin(),
sqrt(mag(valueFraction_.component(symmTensor::XX))) valueFraction_.cend(),
diag.begin(),
[](const symmTensor& t)
{
return vector
(
sqrt(mag(t.xx())), sqrt(mag(t.yy())), sqrt(mag(t.zz()))
); );
diag.replace }
(
vector::Y,
sqrt(mag(valueFraction_.component(symmTensor::YY)))
);
diag.replace
(
vector::Z,
sqrt(mag(valueFraction_.component(symmTensor::ZZ)))
); );
return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag)); return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag));
} }
}
template<class Type> template<class Type>

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -97,9 +98,9 @@ Foam::transformFvPatchField<Type>::valueInternalCoeffs
const tmp<scalarField>& const tmp<scalarField>&
) const ) const
{ {
// OR (!is_rotational_vectorspace_v<Type>) if constexpr (!is_rotational_vectorspace_v<Type>)
if constexpr (std::is_arithmetic_v<Type>)
{ {
// Rotational-invariant type
return tmp<Field<Type>>::New(this->size(), pTraits<Type>::one); return tmp<Field<Type>>::New(this->size(), pTraits<Type>::one);
} }
else else
@ -130,9 +131,9 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::transformFvPatchField<Type>::gradientInternalCoeffs() const Foam::transformFvPatchField<Type>::gradientInternalCoeffs() const
{ {
// OR (!is_rotational_vectorspace_v<Type>) if constexpr (!is_rotational_vectorspace_v<Type>)
if constexpr (std::is_arithmetic_v<Type>)
{ {
// Rotational-invariant type
return tmp<Field<Type>>::New(this->size(), Foam::zero{}); return tmp<Field<Type>>::New(this->size(), Foam::zero{});
} }
else else

View File

@ -209,7 +209,11 @@ public:
//- Does the patch field perform the transformation //- Does the patch field perform the transformation
virtual bool doTransform() const virtual bool doTransform() const
{ {
return (pTraits<Type>::rank && !cyclicPatch_.parallel()); return
(
is_rotational_vectorspace_v<Type>
&& !cyclicPatch_.parallel()
);
} }
//- Return face transformation tensor //- Return face transformation tensor

View File

@ -333,7 +333,11 @@ public:
//- Does the patch field perform the transformation //- Does the patch field perform the transformation
virtual bool doTransform() const virtual bool doTransform() const
{ {
return (pTraits<Type>::rank && !cyclicACMIPatch_.parallel()); return
(
is_rotational_vectorspace_v<Type>
&& !cyclicACMIPatch_.parallel()
);
} }
//- Return face transformation tensor //- Return face transformation tensor

View File

@ -339,7 +339,11 @@ public:
//- Does the patch field perform the transformation //- Does the patch field perform the transformation
virtual bool doTransform() const virtual bool doTransform() const
{ {
return (pTraits<Type>::rank && !cyclicAMIPatch_.parallel()); return
(
is_rotational_vectorspace_v<Type>
&& !cyclicAMIPatch_.parallel()
);
} }
//- Return face transformation tensor //- Return face transformation tensor

View File

@ -298,7 +298,11 @@ public:
//- Does the patch field perform the transformation //- Does the patch field perform the transformation
virtual bool doTransform() const virtual bool doTransform() const
{ {
return (pTraits<Type>::rank && !procPatch_.parallel()); return
(
is_rotational_vectorspace_v<Type>
&& !procPatch_.parallel()
);
} }
//- Return face transformation tensor //- Return face transformation tensor

View File

@ -151,12 +151,14 @@ public:
// Member Functions // Member Functions
// Access
//- Does the patch field perform the transformation //- Does the patch field perform the transformation
virtual bool doTransform() const virtual bool doTransform() const
{ {
return (pTraits<Type>::rank && !procPatch_.parallel()); return
(
is_rotational_vectorspace_v<Type>
&& !procPatch_.parallel()
);
} }
//- Return face transformation tensor //- Return face transformation tensor

View File

@ -171,6 +171,16 @@ void Foam::symmetryPlaneFvPatchField<Type>::evaluate(const Pstream::commsTypes)
template<class Type> template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::symmetryPlaneFvPatchField<Type>::snGradTransformDiag() const Foam::symmetryPlaneFvPatchField<Type>::snGradTransformDiag() const
{
if constexpr (!is_rotational_vectorspace_v<Type>)
{
// Rotational-invariant type
// FatalErrorInFunction
// << "Should not be called for this type"
// << ::Foam::abort(FatalError);
return tmp<Field<Type>>::New(this->size(), Foam::zero{});
}
else
{ {
const vector diag(cmptMag(symmetryPlanePatch_.n())); const vector diag(cmptMag(symmetryPlanePatch_.n()));
@ -191,6 +201,7 @@ Foam::symmetryPlaneFvPatchField<Type>::snGradTransformDiag() const
) )
); );
} }
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -169,10 +169,20 @@ void Foam::wedgeFvPatchField<Type>::evaluate(const Pstream::commsTypes)
template<class Type> template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::wedgeFvPatchField<Type>::snGradTransformDiag() const Foam::wedgeFvPatchField<Type>::snGradTransformDiag() const
{
if constexpr (!is_rotational_vectorspace_v<Type>)
{
// Rotational-invariant type
// FatalErrorInFunction
// << "Should not be called for this type"
// << ::Foam::abort(FatalError);
return tmp<Field<Type>>::New(this->size(), Foam::zero{});
}
else
{ {
const auto& rot = refCast<const wedgeFvPatch>(this->patch()).cellT(); const auto& rot = refCast<const wedgeFvPatch>(this->patch()).cellT();
const vector diagV = 0.5*(I - rot).diag(); const vector diag = 0.5*(I - rot).diag();
return tmp<Field<Type>>::New return tmp<Field<Type>>::New
( (
@ -181,7 +191,7 @@ Foam::wedgeFvPatchField<Type>::snGradTransformDiag() const
( (
pow pow
( (
diagV, diag,
pTraits pTraits
< <
typename powProduct<vector, pTraits<Type>::rank>::type typename powProduct<vector, pTraits<Type>::rank>::type
@ -190,6 +200,7 @@ Foam::wedgeFvPatchField<Type>::snGradTransformDiag() const
) )
); );
} }
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -135,6 +135,12 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::fixedNormalSlipFvPatchField<Type>::snGrad() const Foam::fixedNormalSlipFvPatchField<Type>::snGrad() const
{ {
static_assert
(
is_rotational_vectorspace_v<Type>,
"normal-slip with vector, tensor only!"
);
const vectorField nHat(this->patch().nf()); const vectorField nHat(this->patch().nf());
const Field<Type> pif(this->patchInternalField()); const Field<Type> pif(this->patchInternalField());
@ -171,11 +177,24 @@ void Foam::fixedNormalSlipFvPatchField<Type>::evaluate
template<class Type> template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::fixedNormalSlipFvPatchField<Type>::snGradTransformDiag() const Foam::fixedNormalSlipFvPatchField<Type>::snGradTransformDiag() const
{
static_assert
(
is_rotational_vectorspace_v<Type>,
"normal-slip with vector, tensor only!"
);
// if constexpr (!is_rotational_vectorspace_v<Type>)
// {
// // Rotational-invariant type
// return tmp<Field<Type>>::New(this->size(), Foam::zero{});
// }
{ {
tmp<vectorField> diag(cmptMag(this->patch().nf())); tmp<vectorField> diag(cmptMag(this->patch().nf()));
return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag)); return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag));
} }
}
template<class Type> template<class Type>

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2021 OpenCFD Ltd. Copyright (C) 2017-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -142,17 +142,24 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::partialSlipFvPatchField<Type>::snGrad() const Foam::partialSlipFvPatchField<Type>::snGrad() const
{ {
tmp<vectorField> nHat = this->patch().nf();
const Field<Type> pif(this->patchInternalField()); const Field<Type> pif(this->patchInternalField());
tmp<Field<Type>> rotated;
if constexpr (!is_rotational_vectorspace_v<Type>)
{
// Rotational-invariant type
rotated.cref(pif);
}
else
{
tmp<vectorField> nHat(this->patch().nf());
rotated = transform(I - sqr(nHat), pif);
}
return return
( (
lerp lerp(rotated, refValue_, valueFraction_) - pif
(
transform(I - sqr(nHat), pif),
refValue_,
valueFraction_
) - pif
)*this->patch().deltaCoeffs(); )*this->patch().deltaCoeffs();
} }
@ -168,16 +175,23 @@ void Foam::partialSlipFvPatchField<Type>::evaluate
this->updateCoeffs(); this->updateCoeffs();
} }
tmp<vectorField> nHat = this->patch().nf(); tmp<Field<Type>> rotated;
if constexpr (!is_rotational_vectorspace_v<Type>)
{
// Rotational-invariant type
rotated = this->patchInternalField();
}
else
{
tmp<vectorField> nHat(this->patch().nf());
rotated = transform(I - sqr(nHat), this->patchInternalField());
}
Field<Type>::operator= Field<Type>::operator=
( (
lerp lerp(rotated, refValue_, valueFraction_)
(
transform(I - sqr(nHat), this->patchInternalField()),
refValue_,
valueFraction_
)
); );
parent_bctype::evaluate(); parent_bctype::evaluate();
@ -187,13 +201,24 @@ void Foam::partialSlipFvPatchField<Type>::evaluate
template<class Type> template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::partialSlipFvPatchField<Type>::snGradTransformDiag() const Foam::partialSlipFvPatchField<Type>::snGradTransformDiag() const
{
// static_assert(!std::is_arithmetic_v<T>, "partial-slip with scalar??");
// if constexpr (!is_rotational_vectorspace_v<Type>)
// {
// // Rotational-invariant type
// return tmp<Field<Type>>::New(this->size(), Foam::zero{});
// }
{ {
tmp<vectorField> diag(cmptMag(this->patch().nf())); tmp<vectorField> diag(cmptMag(this->patch().nf()));
return return
(
valueFraction_*pTraits<Type>::one valueFraction_*pTraits<Type>::one
+ (1.0 - valueFraction_) + (1.0 - valueFraction_)
*transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag)); * transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag))
);
}
} }

View File

@ -177,7 +177,11 @@ public:
//- Does the patch field perform the transformation //- Does the patch field perform the transformation
virtual bool doTransform() const virtual bool doTransform() const
{ {
return (pTraits<Type>::rank && !cyclicACMIPatch_.parallel()); return
(
is_rotational_vectorspace_v<Type>
&& !cyclicACMIPatch_.parallel()
);
} }
//- Return face transformation tensor //- Return face transformation tensor

View File

@ -161,7 +161,7 @@ public:
} }
// Member functions // Member Functions
// Constraint handling // Constraint handling
@ -177,7 +177,11 @@ public:
//- Does the patch field perform the transformation //- Does the patch field perform the transformation
virtual bool doTransform() const virtual bool doTransform() const
{ {
return (pTraits<Type>::rank && !cyclicAMIPatch_.parallel()); return
(
is_rotational_vectorspace_v<Type>
&& !cyclicAMIPatch_.parallel()
);
} }
//- Return face transformation tensor //- Return face transformation tensor