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

@ -141,9 +141,20 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::basicSymmetryFaPatchField<Type>::snGradTransformDiag() const Foam::basicSymmetryFaPatchField<Type>::snGradTransformDiag() const
{ {
tmp<vectorField> diag(cmptMag(this->patch().edgeNormals())); 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()));
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.
@ -155,25 +156,36 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::wedgeFaPatchField<Type>::snGradTransformDiag() const Foam::wedgeFaPatchField<Type>::snGradTransformDiag() const
{ {
const auto& rot = refCast<const wedgeFaPatch>(this->patch()).faceT(); 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 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
(
this->size(),
transformMask<Type>
( (
pow this->size(),
transformMask<Type>
( (
diagV, pow
pTraits (
< diag,
typename powProduct<vector, pTraits<Type>::rank>::type pTraits
>::zero <
typename powProduct<vector, pTraits<Type>::rank>::type
>::zero
)
) )
) );
); }
} }

View File

@ -114,22 +114,19 @@ public:
} }
// Member functions // Member Functions
// Evaluation functions //- Return gradient at boundary
virtual tmp<Field<Type>> snGrad() const;
//- Return gradient at boundary //- Evaluate the patch field
virtual tmp<Field<Type>> snGrad() const; virtual void evaluate
(
const Pstream::commsTypes commsType=Pstream::commsTypes::buffered
);
//- Evaluate the patch field //- Return face-gradient transform diagonal
virtual void evaluate virtual tmp<Field<Type>> snGradTransformDiag() const;
(
const Pstream::commsTypes commsType = Pstream::commsTypes::buffered
);
//- Return face-gradient transform diagonal
virtual tmp<Field<Type>> snGradTransformDiag() const;
}; };

View File

@ -141,9 +141,20 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::basicSymmetryFvPatchField<Type>::snGradTransformDiag() const Foam::basicSymmetryFvPatchField<Type>::snGradTransformDiag() const
{ {
tmp<vectorField> diag(cmptMag(this->patch().nf())); 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()));
return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag)); return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag));
}
} }

View File

@ -179,25 +179,33 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::directionMixedFvPatchField<Type>::snGradTransformDiag() const Foam::directionMixedFvPatchField<Type>::snGradTransformDiag() const
{ {
vectorField diag(valueFraction_.size()); // 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{});
// }
diag.replace {
( vectorField diag(valueFraction_.size());
vector::X,
sqrt(mag(valueFraction_.component(symmTensor::XX)))
);
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)); std::transform
(
valueFraction_.cbegin(),
valueFraction_.cend(),
diag.begin(),
[](const symmTensor& t)
{
return vector
(
sqrt(mag(t.xx())), sqrt(mag(t.yy())), sqrt(mag(t.zz()))
);
}
);
return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag));
}
} }

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,19 +151,21 @@ public:
// Member Functions // Member Functions
// Access //- Does the patch field perform the transformation
virtual bool doTransform() const
{
return
(
is_rotational_vectorspace_v<Type>
&& !procPatch_.parallel()
);
}
//- Does the patch field perform the transformation //- Return face transformation tensor
virtual bool doTransform() const virtual const tensorField& forwardT() const
{ {
return (pTraits<Type>::rank && !procPatch_.parallel()); return procPatch_.forwardT();
} }
//- Return face transformation tensor
virtual const tensorField& forwardT() const
{
return procPatch_.forwardT();
}
}; };

View File

@ -172,24 +172,35 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::symmetryPlaneFvPatchField<Type>::snGradTransformDiag() const Foam::symmetryPlaneFvPatchField<Type>::snGradTransformDiag() const
{ {
const vector diag(cmptMag(symmetryPlanePatch_.n())); 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()));
return tmp<Field<Type>>::New return tmp<Field<Type>>::New
(
this->size(),
transformMask<Type>
( (
//pow<vector, pTraits<Type>::rank>(diag) this->size(),
pow transformMask<Type>
( (
diag, //pow<vector, pTraits<Type>::rank>(diag)
pTraits pow
< (
typename powProduct<vector, pTraits<Type>::rank>::type diag,
>::zero pTraits
<
typename powProduct<vector, pTraits<Type>::rank>::type
>::zero
)
) )
) );
); }
} }

View File

@ -170,25 +170,36 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::wedgeFvPatchField<Type>::snGradTransformDiag() const Foam::wedgeFvPatchField<Type>::snGradTransformDiag() const
{ {
const auto& rot = refCast<const wedgeFvPatch>(this->patch()).cellT(); 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 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
(
this->size(),
transformMask<Type>
( (
pow this->size(),
( transformMask<Type>
diagV, (
pTraits pow
< (
typename powProduct<vector, pTraits<Type>::rank>::type diag,
>::zero pTraits
) <
) typename powProduct<vector, pTraits<Type>::rank>::type
); >::zero
)
)
);
}
} }

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());
@ -172,9 +178,22 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::fixedNormalSlipFvPatchField<Type>::snGradTransformDiag() const Foam::fixedNormalSlipFvPatchField<Type>::snGradTransformDiag() const
{ {
tmp<vectorField> diag(cmptMag(this->patch().nf())); 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{});
// }
return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag)); {
tmp<vectorField> diag(cmptMag(this->patch().nf()));
return transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag));
}
} }

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();
@ -188,12 +202,23 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::partialSlipFvPatchField<Type>::snGradTransformDiag() const Foam::partialSlipFvPatchField<Type>::snGradTransformDiag() const
{ {
tmp<vectorField> diag(cmptMag(this->patch().nf())); // 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{});
// }
return {
valueFraction_*pTraits<Type>::one tmp<vectorField> diag(cmptMag(this->patch().nf()));
+ (1.0 - valueFraction_)
*transformFieldMask<Type>(pow<vector, pTraits<Type>::rank>(diag)); return
(
valueFraction_*pTraits<Type>::one
+ (1.0 - valueFraction_)
* 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