bos #32738 [CEA] Scaled Jacobian quality mesh measure for volumetric elements.

Erase non tracke files

Adding some comments on SMESH_Controls. Fixing compilation warning on SMDS_VolumeTool and add missing lines in interface files.

Add implemented tests to tests.set

Correction on SMESH_msg_fr and copyright msg of python test.
This commit is contained in:
cconopoima 2023-05-23 16:47:39 -03:00 committed by Christophe Bourcier
parent e0552dbb7f
commit 9ac965c0e3
36 changed files with 838 additions and 10 deletions

View File

@ -0,0 +1,9 @@
# Scaled Jacobian
# create mesh with volumes
from mechanic import *
# get volumes with scaled jacobian > 0.75
filter = smesh_builder.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_MoreThan, 0.75 )
ids = mesh.GetIdsFromFilter(filter)
print("Number of volumes with scaled jacobian > 0.75:", len(ids))

View File

@ -0,0 +1,24 @@
# Scaled Jacobian
from mechanic import *
# Criterion : Scaled Jacobian > 0.75
scaledJacobian = 0.75
aFilter = smesh_builder.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_MoreThan, scaledJacobian)
anIds = mesh.GetIdsFromFilter(aFilter)
# print the result
print("Criterion: Scaled Jacobian > ", scaledJacobian, " Nb = ", len(anIds))
j = 1
for i in range(len(anIds)):
if j > 20: j = 1; print("")
print(anIds[i], end=' ')
j = j + 1
pass
print("")
# create a group
aGroup = mesh.CreateEmptyGroup(SMESH.FACE, "Scaled Jacobian > " + repr(scaledJacobian))
aGroup.Add(anIds)

View File

@ -73,6 +73,7 @@ SET(BAD_TESTS
filters_ex36.py filters_ex36.py
filters_ex37.py filters_ex37.py
filters_ex38.py filters_ex38.py
filters_ex40.py
filters_node_nb_conn.py filters_node_nb_conn.py
filters_belong2group.py filters_belong2group.py
generate_flat_elements.py generate_flat_elements.py
@ -119,6 +120,7 @@ SET(BAD_TESTS
quality_controls_ex20.py quality_controls_ex20.py
quality_controls_ex21.py quality_controls_ex21.py
quality_controls_ex22.py quality_controls_ex22.py
quality_controls_ex24.py
quality_controls_defl.py quality_controls_defl.py
split_biquad.py split_biquad.py
transforming_meshes_ex01.py transforming_meshes_ex01.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -48,6 +48,7 @@ Volume quality controls:
* :ref:`aspect_ratio_3d_page` * :ref:`aspect_ratio_3d_page`
* :ref:`volume_page` * :ref:`volume_page`
* :ref:`max_element_length_3d_page` * :ref:`max_element_length_3d_page`
* :ref:`scaled_jacobian_page`
* :ref:`bare_border_volumes_page` * :ref:`bare_border_volumes_page`
* :ref:`over_constrained_volumes_page` * :ref:`over_constrained_volumes_page`
* :ref:`double_elements_page` * :ref:`double_elements_page`
@ -100,3 +101,4 @@ To manage the quality controls call pop-up in the VTK viewer and select "Control
bare_border_volumes.rst bare_border_volumes.rst
over_constrained_volumes.rst over_constrained_volumes.rst
scalar_bar.rst scalar_bar.rst
scaled_jacobian.rst

View File

@ -0,0 +1,42 @@
.. _scaled_jacobian_page:
***************
Scaled Jacobian
***************
The **Scaled Jacobian** mesh quality criteria, is a scalar measure of the deviation from the perfect element in the geometrical sense, this measure normalize the range of reported values
between [0,1] for a normal element, the value of 1 is considered a perfect element and 0 a element with a collapsed side. Negative values are also accepted for invalid elements.
The **Scaled Jacobian** is implemented for volumetric elements returning 0 for polyhedrons. For tetrahedron and hexahedron the close form
is defined in `[1] <https://gitlab.kitware.com/third-party/verdict/-/blob/master/SAND2007-2853p.pdf>`_, for pyramids the minimum scaled jacobian of the four tetrahedrons formed
in the four vertices of the pyramid base is reported, for pentahedrons a decomposition into tetrahedron is also done and finally for hexahedron prisms the minimum scaled jacobian between two pentahedrons and one hexahedron is reported.
* Geometrically the Scaled Jacobian of a **tetrahedron** can be understood by the follow figure:
.. image:: ../images/scaled_jacobian_tetra.png
:align: center
The reported Scaled Jacobian will be 1 if :math:`\alpha=45^{\circ}`
* For **hexadrons** this measure return 1 for the perfect non rotated elements:
.. image:: ../images/scaled_jacobian_hexa.png
:align: center
The reported Scaled Jacobian will be 1 if :math:`\alpha=0^{\circ}` for all the vertices
*To visualize the Scaled Jacobian quality criterion in your mesh:*
.. |img| image:: ../images/scaled_jacobian.png
#. Display your mesh in the viewer.
#. Choose **Controls > Volume Controls > Scaled Jacobian** or click *"Scaled Jacobian"* button |img| of the toolbar.
Your mesh will be displayed in the viewer with its elements colored according to the applied mesh quality control criterion:
.. image:: ../images/scaled_jacobian_mesh_tetra.png
:align: center
**See Also** a sample TUI Script of a :ref:`tui_scaled_jacobian` filter.

View File

@ -61,6 +61,24 @@ filters 3D mesh elements (volumes) according to the aspect ratio value:
**See also:** :ref:`tui_aspect_ratio_3d` **See also:** :ref:`tui_aspect_ratio_3d`
.. _filter_scaled_jacobian:
Scaled Jacobian
===============
filters 3D mesh elements (volumes) according to the scaled jacobian value:
* element type is *SMESH.VOLUME*
* functor type is *SMESH.FT_ScaledJacobian*
* threshold is floating point value
.. literalinclude:: ../../examples/filters_ex40.py
:language: python
:download:`Download this script <../../examples/filters_ex40.py>`
**See also:** :ref:`tui_scaled_jacobian`
.. _filter_warping_angle: .. _filter_warping_angle:
Warping angle Warping angle

View File

@ -240,3 +240,13 @@ Element Diameter 3D
:language: python :language: python
:download:`Download this script <../../examples/quality_controls_ex22.py>` :download:`Download this script <../../examples/quality_controls_ex22.py>`
.. _tui_scaled_jacobian:
Scaled Jacobian
===================
.. literalinclude:: ../../examples/quality_controls_ex24.py
:language: python
:download:`Download this script <../../examples/quality_controls_ex24.py>`

View File

@ -48,6 +48,7 @@ module SMESH
FT_Skew, FT_Skew,
FT_Area, FT_Area,
FT_Volume3D, FT_Volume3D,
FT_ScaledJacobian,
FT_MaxElementLength2D, FT_MaxElementLength2D,
FT_MaxElementLength3D, FT_MaxElementLength3D,
FT_FreeBorders, FT_FreeBorders,
@ -170,6 +171,7 @@ module SMESH
}; };
interface BallDiameter : NumericalFunctor{}; interface BallDiameter : NumericalFunctor{};
interface NodeConnectivityNumber : NumericalFunctor{}; interface NodeConnectivityNumber : NumericalFunctor{};
interface ScaledJacobian : NumericalFunctor{};
/*! /*!
@ -598,6 +600,7 @@ module SMESH
MultiConnection2D CreateMultiConnection2D(); MultiConnection2D CreateMultiConnection2D();
BallDiameter CreateBallDiameter(); BallDiameter CreateBallDiameter();
NodeConnectivityNumber CreateNodeConnectivityNumber(); NodeConnectivityNumber CreateNodeConnectivityNumber();
ScaledJacobian CreateScaledJacobian();
/*! /*!
* Create logical functors ( predicates ) * Create logical functors ( predicates )
*/ */

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -2351,6 +2351,70 @@ SMDSAbs_ElementType NodeConnectivityNumber::GetType() const
return SMDSAbs_Node; return SMDSAbs_Node;
} }
//================================================================================
/*
Class : ScaledJacobian
Description : Functor returning the ScaledJacobian for volumetric elements
*/
//================================================================================
double ScaledJacobian::GetValue( long theElementId )
{
if ( theElementId && myMesh ) {
SMDS_VolumeTool aVolumeTool;
if ( aVolumeTool.Set( myMesh->FindElement( theElementId )))
return aVolumeTool.GetScaledJacobian();
}
return 0;
/*
//VTK version not used because lack of implementation for HEXAGONAL_PRISM.
//Several mesh quality measures implemented in vtkMeshQuality can be accessed left here as reference
double aVal = 0;
myCurrElement = myMesh->FindElement( theElementId );
if ( myCurrElement )
{
VTKCellType cellType = myCurrElement->GetVtkType();
vtkUnstructuredGrid* grid = const_cast<SMDS_Mesh*>( myMesh )->GetGrid();
vtkCell* avtkCell = grid->GetCell( myCurrElement->GetVtkID() );
switch ( cellType )
{
case VTK_QUADRATIC_TETRA:
case VTK_TETRA:
aVal = Round( vtkMeshQuality::TetScaledJacobian( avtkCell ));
break;
case VTK_QUADRATIC_HEXAHEDRON:
case VTK_HEXAHEDRON:
aVal = Round( vtkMeshQuality::HexScaledJacobian( avtkCell ));
break;
case VTK_QUADRATIC_WEDGE:
case VTK_WEDGE: //Pentahedron
aVal = Round( vtkMeshQuality::WedgeScaledJacobian( avtkCell ));
break;
case VTK_QUADRATIC_PYRAMID:
case VTK_PYRAMID:
aVal = Round( vtkMeshQuality::PyramidScaledJacobian( avtkCell ));
break;
case VTK_HEXAGONAL_PRISM:
case VTK_POLYHEDRON:
default:
break;
}
}
return aVal;
*/
}
double ScaledJacobian::GetBadRate( double Value, int /*nbNodes*/ ) const
{
return Value;
}
SMDSAbs_ElementType ScaledJacobian::GetType() const
{
return SMDSAbs_Volume;
}
/* /*
PREDICATES PREDICATES
*/ */

View File

@ -405,6 +405,17 @@ namespace SMESH{
virtual SMDSAbs_ElementType GetType() const; virtual SMDSAbs_ElementType GetType() const;
}; };
/*
Class : ScaledJacobian
Description : Functor returning the ScaledJacobian as implemeted in VTK for volumetric elements
*/
class SMESHCONTROLS_EXPORT ScaledJacobian: public virtual NumericalFunctor{
public:
virtual double GetValue( long theNodeId );
virtual double GetBadRate( double Value, int nbNodes ) const;
virtual SMDSAbs_ElementType GetType() const;
};
/* /*
PREDICATES PREDICATES

View File

@ -953,6 +953,14 @@ void SMESH_ActorDef::SetControlMode( eControl theMode, bool theCheckEntityMode )
myControlActor = my3DActor; myControlActor = my3DActor;
break; break;
} }
case eScaledJacobian:
{
SMESH::Controls::ScaledJacobian* aControl = new SMESH::Controls::ScaledJacobian();
aControl->SetPrecision( myControlsPrecision );
myFunctor.reset( aControl );
myControlActor = my3DActor;
break;
}
case eMaxElementLength2D: case eMaxElementLength2D:
{ {
SMESH::Controls::MaxElementLength2D* aControl = new SMESH::Controls::MaxElementLength2D(); SMESH::Controls::MaxElementLength2D* aControl = new SMESH::Controls::MaxElementLength2D();
@ -1112,7 +1120,6 @@ void SMESH_ActorDef::SetControlMode( eControl theMode, bool theCheckEntityMode )
QString aTitle = QString(myScalarBarActor->GetTitle()); QString aTitle = QString(myScalarBarActor->GetTitle());
aTitle.replace(QRegExp("(:\\s).*"),"\\1"+ QString::number(GetNumberControlEntities())); aTitle.replace(QRegExp("(:\\s).*"),"\\1"+ QString::number(GetNumberControlEntities()));
myScalarBarActor->SetTitle(aTitle.toUtf8().constData()); myScalarBarActor->SetTitle(aTitle.toUtf8().constData());
} }
else { else {
if(theCheckEntityMode){ if(theCheckEntityMode){

View File

@ -139,7 +139,7 @@ class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor
enum eControl{eNone, eLength, eLength2D, eDeflection2D, eFreeBorders, eFreeEdges, eFreeNodes, enum eControl{eNone, eLength, eLength2D, eDeflection2D, eFreeBorders, eFreeEdges, eFreeNodes,
eFreeFaces, eMultiConnection, eArea, eTaper, eAspectRatio, eFreeFaces, eMultiConnection, eArea, eTaper, eAspectRatio,
eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D, eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D, eScaledJacobian,
eMaxElementLength2D, eMaxElementLength3D, eBareBorderFace, eBareBorderVolume, eMaxElementLength2D, eMaxElementLength3D, eBareBorderFace, eBareBorderVolume,
eOverConstrainedFace, eOverConstrainedVolume, eCoincidentNodes, eOverConstrainedFace, eOverConstrainedVolume, eCoincidentNodes,
eCoincidentElems1D, eCoincidentElems2D, eCoincidentElems3D, eNodeConnectivityNb, eCoincidentElems1D, eCoincidentElems2D, eCoincidentElems3D, eNodeConnectivityNb,

View File

@ -80,9 +80,17 @@ static int Tetra_RE [4][4] = { // REVERSED -> FORWARD (EXTERNAL)
{ 0, 3, 2, 0 }}; { 0, 3, 2, 0 }};
static int Tetra_nbN [] = { 3, 3, 3, 3 }; static int Tetra_nbN [] = { 3, 3, 3, 3 };
// /*
// PYRAMID // N1 +---------+ N2
// // | \ / |
// | \ / |
// | \ / |
// | /+\ | PYRAMID
// | / N4\ |
// | / \ |
// |/ \|
// N0 +---------+ N3
*/
static int Pyramid_F [5][5] = { // FORWARD == EXTERNAL static int Pyramid_F [5][5] = { // FORWARD == EXTERNAL
{ 0, 1, 2, 3, 0 }, // All faces have external normals { 0, 1, 2, 3, 0 }, // All faces have external normals
{ 0, 4, 1, 0, 4 }, { 0, 4, 1, 0, 4 },
@ -363,13 +371,18 @@ struct XYZ {
inline XYZ operator-( const XYZ& other ); inline XYZ operator-( const XYZ& other );
inline XYZ operator+( const XYZ& other ); inline XYZ operator+( const XYZ& other );
inline XYZ Crossed( const XYZ& other ); inline XYZ Crossed( const XYZ& other );
inline XYZ operator-();
inline double Dot( const XYZ& other ); inline double Dot( const XYZ& other );
inline double Magnitude(); inline double Magnitude();
inline double SquareMagnitude(); inline double SquareMagnitude();
inline XYZ Normalize();
}; };
inline XYZ XYZ::operator-( const XYZ& Right ) { inline XYZ XYZ::operator-( const XYZ& Right ) {
return XYZ(x - Right.x, y - Right.y, z - Right.z); return XYZ(x - Right.x, y - Right.y, z - Right.z);
} }
inline XYZ XYZ::operator-() {
return XYZ(-x,-y,-z);
}
inline XYZ XYZ::operator+( const XYZ& Right ) { inline XYZ XYZ::operator+( const XYZ& Right ) {
return XYZ(x + Right.x, y + Right.y, z + Right.z); return XYZ(x + Right.x, y + Right.y, z + Right.z);
} }
@ -387,6 +400,13 @@ inline double XYZ::Magnitude() {
inline double XYZ::SquareMagnitude() { inline double XYZ::SquareMagnitude() {
return (x * x + y * y + z * z); return (x * x + y * y + z * z);
} }
inline XYZ XYZ::Normalize() {
double magnitude = Magnitude();
if ( magnitude != 0.0 )
return XYZ(x /= magnitude,y /= magnitude,z /= magnitude );
else
return XYZ(x,y,z);
}
//================================================================================ //================================================================================
/*! /*!
@ -694,7 +714,6 @@ static double getTetraVolume(const SMDS_MeshNode* n1,
//function : GetSize //function : GetSize
//purpose : Return element volume //purpose : Return element volume
//======================================================================= //=======================================================================
double SMDS_VolumeTool::GetSize() const double SMDS_VolumeTool::GetSize() const
{ {
double V = 0.; double V = 0.;
@ -847,6 +866,334 @@ double SMDS_VolumeTool::GetSize() const
return V; return V;
} }
//=======================================================================
//function : getTetraScaledJacobian
//purpose : Given the smesh nodes in the canonical order of the tetrahedron, return the scaled jacobian
//=======================================================================
static double getTetraScaledJacobian(const SMDS_MeshNode* n0,
const SMDS_MeshNode* n1,
const SMDS_MeshNode* n2,
const SMDS_MeshNode* n3)
{
const double sqrt = std::sqrt(2.0);
// Get the coordinates
XYZ p0( n0 );
XYZ p1( n1 );
XYZ p2( n2 );
XYZ p3( n3 );
// Define the edges connecting the nodes
XYZ L0 = p1-p0;
XYZ L1 = p2-p1;
XYZ L2 = p2-p0; // invert the definition of doc to get the proper orientation of the crossed product
XYZ L3 = p3-p0;
XYZ L4 = p3-p1;
XYZ L5 = p3-p2;
double Jacobian = L2.Crossed( L0 ).Dot( L3 );
double norm0 = L0.Magnitude();
double norm1 = L1.Magnitude();
double norm2 = L2.Magnitude();
double norm3 = L3.Magnitude();
double norm4 = L4.Magnitude();
double norm5 = L5.Magnitude();
std::array<double, 5> norms{};
norms[0] = Jacobian;
norms[1] = norm3*norm4*norm5;
norms[2] = norm1*norm2*norm5;
norms[3] = norm0*norm1*norm4;
norms[4] = norm0*norm2*norm3;
auto findMaxNorm = std::max_element(norms.begin(), norms.end());
double maxNorm = *findMaxNorm;
if ( std::fabs( maxNorm ) < std::numeric_limits<double>::min() )
maxNorm = std::numeric_limits<double>::max();
return Jacobian * sqrt / maxNorm;
}
//=======================================================================
//function : getPyramidScaledJacobian
//purpose : Given the pyramid, compute the scaled jacobian of the four tetrahedrons and return the minimun value.
//=======================================================================
static double getPyramidScaledJacobian(const SMDS_MeshNode* n0,
const SMDS_MeshNode* n1,
const SMDS_MeshNode* n2,
const SMDS_MeshNode* n3,
const SMDS_MeshNode* n4)
{
const double sqrt = std::sqrt(2.0);
std::array<double, 4> tetScaledJacobian{};
tetScaledJacobian[0] = getTetraScaledJacobian(n0, n1, n3, n4);
tetScaledJacobian[1] = getTetraScaledJacobian(n1, n2, n0, n4);
tetScaledJacobian[2] = getTetraScaledJacobian(n2, n3, n1, n4);
tetScaledJacobian[3] = getTetraScaledJacobian(n3, n0, n2, n4);
auto minEntry = std::min_element(tetScaledJacobian.begin(), tetScaledJacobian.end());
double scaledJacobian = (*minEntry) * 2.0/sqrt;
return scaledJacobian < 1.0 ? scaledJacobian : 1.0 - (scaledJacobian - 1.0);
}
//=======================================================================
//function : getHexaScaledJacobian
//purpose : Evaluate the scaled jacobian on the eight vertices of the hexahedron and return the minimal registered value
//remark : Follow the reference numeration described at the top of the class.
//=======================================================================
static double getHexaScaledJacobian(const SMDS_MeshNode* n0,
const SMDS_MeshNode* n1,
const SMDS_MeshNode* n2,
const SMDS_MeshNode* n3,
const SMDS_MeshNode* n4,
const SMDS_MeshNode* n5,
const SMDS_MeshNode* n6,
const SMDS_MeshNode* n7)
{
// Scaled jacobian is an scalar quantity measuring the deviation of the geometry from the perfect geometry
// Get the coordinates
XYZ p0( n0 );
XYZ p1( n1 );
XYZ p2( n2 );
XYZ p3( n3 );
XYZ p4( n4 );
XYZ p5( n5 );
XYZ p6( n6 );
XYZ p7( n7 );
// Define the edges connecting the nodes
XYZ L0 = (p1-p0).Normalize();
XYZ L1 = (p2-p1).Normalize();
XYZ L2 = (p3-p2).Normalize();
XYZ L3 = (p3-p0).Normalize();
XYZ L4 = (p4-p0).Normalize();
XYZ L5 = (p5-p1).Normalize();
XYZ L6 = (p6-p2).Normalize();
XYZ L7 = (p7-p3).Normalize();
XYZ L8 = (p5-p4).Normalize();
XYZ L9 = (p6-p5).Normalize();
XYZ L10 = (p7-p6).Normalize();
XYZ L11 = (p7-p4).Normalize();
XYZ X0 = (p1-p0+p2-p3+p6-p7+p5-p4).Normalize();
XYZ X1 = (p3-p0+p2-p1+p7-p4+p6-p5).Normalize();
XYZ X2 = (p4-p0+p7-p3+p5-p1+p6-p2).Normalize();
std::array<double, 9> scaledJacobian{};
//Scaled jacobian of nodes following their numeration
scaledJacobian[0] = L4.Crossed( L3).Dot( L0 ); // For L0
scaledJacobian[1] = L5.Crossed(-L0).Dot( L1 ); // For L1
scaledJacobian[2] = L6.Crossed(-L1).Dot( L2 ); // For L2
scaledJacobian[3] = L7.Crossed(-L2).Dot(-L3 ); // For L3
scaledJacobian[4] = -L4.Crossed( L8).Dot( L11 ); // For L11
scaledJacobian[5] = -L5.Crossed( L9).Dot(-L8 ); // For L8
scaledJacobian[6] = -L6.Crossed(L10).Dot(-L9 ); // For L9
scaledJacobian[7] = -L7.Crossed(-L11).Dot(-L10 ); // For L10
scaledJacobian[8] = X2.Crossed( X1).Dot( X0 ); // For principal axes
auto minScaledJacobian = std::min_element(scaledJacobian.begin(), scaledJacobian.end());
return *minScaledJacobian;
}
//=======================================================================
//function : getTetraNormalizedJacobian
//purpose : Return the jacobian of the tetrahedron based on normalized vectors
//=======================================================================
static double getTetraNormalizedJacobian(const SMDS_MeshNode* n0,
const SMDS_MeshNode* n1,
const SMDS_MeshNode* n2,
const SMDS_MeshNode* n3)
{
const double sqrt = std::sqrt(2.0);
// Get the coordinates
XYZ p0( n0 );
XYZ p1( n1 );
XYZ p2( n2 );
XYZ p3( n3 );
// Define the normalized edges connecting the nodes
XYZ L0 = (p1-p0).Normalize();
XYZ L2 = (p2-p0).Normalize(); // invert the definition of doc to get the proper orientation of the crossed product
XYZ L3 = (p3-p0).Normalize();
return L2.Crossed( L0 ).Dot( L3 );
}
//=======================================================================
//function : getPentaScaledJacobian
//purpose : Evaluate the scaled jacobian on the pentahedron based on decomposed tetrahedrons
//=======================================================================
/*
// + N1
// /|\
// / | \
// / | \
// / | \
// N0 +---------+ N2
// | | | NUMERATION RERENCE FOLLOWING POSSITIVE RIGHT HAND RULE
// | + N4 |
// | / \ | PENTAHEDRON
// | / \ |
// | / \ |
// |/ \|
// N3 +---------+ N5
//
// N1
// +
// |\
// /| \
// / | \
// N0 +--|---+ N2 TETRAHEDRON ASSOCIATED TO N0
// \ | / Numeration passed to getTetraScaledJacobian
// \ | / N0=N0; N1=N2; N2=N3; N3=N1
// \| /
// |/
// +
// N3
//
// N1
// +
// /|\
// / | \
// / | \
// N2 +---|---+ N5 TETRAHEDRON ASSOCIATED TO N2
// \ | / Numeration passed to getTetraScaledJacobian
// \ | / N0=N2; N1=N5; N2=N0; N3=N1
// \ |/
// \|
// +
// N0
//
// N4
// +
// /|\
// / | \
// / | \
// N3 +---|---+ N0 TETRAHEDRON ASSOCIATED TO N3
// \ | / Numeration passed to getTetraScaledJacobian
// \ | / N0=N3; N1=N0; N2=N5; N3=N4
// \ | /
// \|/
// +
// N5
//
// N3
// +
// /|\
// / | \
// / | \
// N1 +---|---+ N2 TETRAHEDRON ASSOCIATED TO N1
// \ | / Numeration passed to getTetraScaledJacobian
// \ | / N0=N1; N1=N2; N2=N0; N3=N3
// \ | /
// \|/
// +
// N0
//
// ...
*/
static double getPentaScaledJacobian(const SMDS_MeshNode* n0,
const SMDS_MeshNode* n1,
const SMDS_MeshNode* n2,
const SMDS_MeshNode* n3,
const SMDS_MeshNode* n4,
const SMDS_MeshNode* n5)
{
std::array<double, 6> scaledJacobianOfReferenceTetra{};
scaledJacobianOfReferenceTetra[0] = getTetraNormalizedJacobian(n0, n2, n3, n1); // For n0
scaledJacobianOfReferenceTetra[1] = getTetraNormalizedJacobian(n2, n5, n0, n1); // For n2
scaledJacobianOfReferenceTetra[2] = getTetraNormalizedJacobian(n3, n0, n5, n4); // For n3
scaledJacobianOfReferenceTetra[3] = getTetraNormalizedJacobian(n5, n3, n2, n4); // For n5
scaledJacobianOfReferenceTetra[4] = getTetraNormalizedJacobian(n1, n2, n0, n3); // For n1
scaledJacobianOfReferenceTetra[5] = getTetraNormalizedJacobian(n4, n3, n5, n2); // For n4
auto minScaledJacobian = std::min_element(scaledJacobianOfReferenceTetra.begin(), scaledJacobianOfReferenceTetra.end());
double minScalJac = (*minScaledJacobian)* 2.0 / std::sqrt(3.0);
if (minScalJac > 0)
return std::min(minScalJac, std::numeric_limits<double>::max());
return std::max(minScalJac, -std::numeric_limits<double>::max());
}
//=======================================================================
//function : getHexaPrismScaledJacobian
//purpose : Evaluate the scaled jacobian on the hexaprism by decomposing the goemetry into three 1hexa + 2 pentahedrons
//=======================================================================
static double getHexaPrismScaledJacobian(const SMDS_MeshNode* n0,
const SMDS_MeshNode* n1,
const SMDS_MeshNode* n2,
const SMDS_MeshNode* n3,
const SMDS_MeshNode* n4,
const SMDS_MeshNode* n5,
const SMDS_MeshNode* n6,
const SMDS_MeshNode* n7,
const SMDS_MeshNode* n8,
const SMDS_MeshNode* n9,
const SMDS_MeshNode* n10,
const SMDS_MeshNode* n11)
{
// The Pentahedron from the left
// n0=n0; n1=n1; n2=n2; n3=n6; n4=n7, n5=n8;
double scaledJacobianPentleft = getPentaScaledJacobian( n0, n1, n2, n6, n7, n8 );
// The core Hexahedron
// n0=n0; n1=n2, n2=n3; n3=n5; n4=n6; n5=n8; n6=n9; n7=n11
double scaledJacobianHexa = getHexaScaledJacobian( n0, n2, n3, n5, n6, n8, n9, n11 );
// The Pentahedron from the right
// n0=n5; n1=n4; n2=n3; n3=n11; n4=n10; n5=n9
double scaledJacobianPentright = getPentaScaledJacobian( n5, n4, n3, n11, n10, n9 );
return std::min( scaledJacobianHexa, std::min( scaledJacobianPentleft, scaledJacobianPentright ) );
}
//=======================================================================
//function : GetScaledJacobian
//purpose : Return element Scaled Jacobian using the generic definition given
// in https://gitlab.kitware.com/third-party/verdict/-/blob/master/SAND2007-2853p.pdf
//=======================================================================
double SMDS_VolumeTool::GetScaledJacobian() const
{
// For Tetra, call directly the getTetraScaledJacobian
double scaledJacobian = 0.;
VolumeType type = GetVolumeType();
switch (type)
{
case TETRA:
case QUAD_TETRA:
scaledJacobian = getTetraScaledJacobian( myVolumeNodes[0], myVolumeNodes[1], myVolumeNodes[2], myVolumeNodes[3] );
break;
case HEXA:
case QUAD_HEXA:
scaledJacobian = getHexaScaledJacobian( myVolumeNodes[0], myVolumeNodes[1], myVolumeNodes[2], myVolumeNodes[3],
myVolumeNodes[4], myVolumeNodes[5], myVolumeNodes[6], myVolumeNodes[7] );
break;
case PYRAM:
case QUAD_PYRAM:
scaledJacobian = getPyramidScaledJacobian( myVolumeNodes[0], myVolumeNodes[1], myVolumeNodes[2], myVolumeNodes[3], myVolumeNodes[4] );
break;
case PENTA:
case QUAD_PENTA:
scaledJacobian = getPentaScaledJacobian( myVolumeNodes[0], myVolumeNodes[1],
myVolumeNodes[2], myVolumeNodes[3],
myVolumeNodes[4], myVolumeNodes[5] );
break;
case HEX_PRISM:
scaledJacobian = getHexaPrismScaledJacobian( myVolumeNodes[0], myVolumeNodes[1], myVolumeNodes[2], myVolumeNodes[3],
myVolumeNodes[4], myVolumeNodes[5], myVolumeNodes[6], myVolumeNodes[7],
myVolumeNodes[8], myVolumeNodes[9], myVolumeNodes[10], myVolumeNodes[11]);
break;
default:
break;
}
return scaledJacobian;
}
//======================================================================= //=======================================================================
//function : GetBaryCenter //function : GetBaryCenter
//purpose : //purpose :

View File

@ -103,6 +103,9 @@ class SMDS_EXPORT SMDS_VolumeTool
double GetSize() const; double GetSize() const;
// Return element volume // Return element volume
double GetScaledJacobian() const;
// Return the scaled jacobian
bool GetBaryCenter (double & X, double & Y, double & Z) const; bool GetBaryCenter (double & X, double & Y, double & Z) const;
bool IsOut(double X, double Y, double Z, double tol) const; bool IsOut(double X, double Y, double Z, double tol) const;

View File

@ -1162,6 +1162,8 @@ namespace
type = QObject::tr( "EQUAL_VOLUME" ); type = QObject::tr( "EQUAL_VOLUME" );
else if ( dynamic_cast< SMESH::Controls::NodeConnectivityNumber* >( f.get() ) ) else if ( dynamic_cast< SMESH::Controls::NodeConnectivityNumber* >( f.get() ) )
type = QObject::tr( "NODE_CONNECTIVITY_NB" ); type = QObject::tr( "NODE_CONNECTIVITY_NB" );
else if ( dynamic_cast< SMESH::Controls::ScaledJacobian* >( f.get() ) )
type = QObject::tr( "SCALED_JACOBIAN" );
return type; return type;
} }
@ -1778,6 +1780,7 @@ namespace
ActionControl.Bind( SMESHOp::OpEqualFace, SMESH_Actor::eCoincidentElems2D ); ActionControl.Bind( SMESHOp::OpEqualFace, SMESH_Actor::eCoincidentElems2D );
ActionControl.Bind( SMESHOp::OpAspectRatio3D, SMESH_Actor::eAspectRatio3D ); ActionControl.Bind( SMESHOp::OpAspectRatio3D, SMESH_Actor::eAspectRatio3D );
ActionControl.Bind( SMESHOp::OpVolume, SMESH_Actor::eVolume3D ); ActionControl.Bind( SMESHOp::OpVolume, SMESH_Actor::eVolume3D );
ActionControl.Bind( SMESHOp::OpScaledJacobian, SMESH_Actor::eScaledJacobian );
ActionControl.Bind( SMESHOp::OpMaxElementLength3D, SMESH_Actor::eMaxElementLength3D ); ActionControl.Bind( SMESHOp::OpMaxElementLength3D, SMESH_Actor::eMaxElementLength3D );
ActionControl.Bind( SMESHOp::OpBareBorderVolume, SMESH_Actor::eBareBorderVolume ); ActionControl.Bind( SMESHOp::OpBareBorderVolume, SMESH_Actor::eBareBorderVolume );
ActionControl.Bind( SMESHOp::OpOverConstrainedVolume, SMESH_Actor::eOverConstrainedVolume ); ActionControl.Bind( SMESHOp::OpOverConstrainedVolume, SMESH_Actor::eOverConstrainedVolume );
@ -3902,6 +3905,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
case SMESHOp::OpEqualFace: case SMESHOp::OpEqualFace:
case SMESHOp::OpAspectRatio3D: case SMESHOp::OpAspectRatio3D:
case SMESHOp::OpVolume: case SMESHOp::OpVolume:
case SMESHOp::OpScaledJacobian:
case SMESHOp::OpMaxElementLength3D: case SMESHOp::OpMaxElementLength3D:
case SMESHOp::OpBareBorderVolume: case SMESHOp::OpBareBorderVolume:
case SMESHOp::OpOverConstrainedVolume: case SMESHOp::OpOverConstrainedVolume:
@ -4213,6 +4217,7 @@ void SMESHGUI::initialize( CAM_Application* app )
createSMESHAction( SMESHOp::OpBareBorderVolume, "BARE_BORDER_VOLUME", "ICON_BARE_BORDER_VOLUME", 0, true ); createSMESHAction( SMESHOp::OpBareBorderVolume, "BARE_BORDER_VOLUME", "ICON_BARE_BORDER_VOLUME", 0, true );
createSMESHAction( SMESHOp::OpOverConstrainedVolume, "OVER_CONSTRAINED_VOLUME", "ICON_OVER_CONSTRAINED_VOLUME", 0, true ); createSMESHAction( SMESHOp::OpOverConstrainedVolume, "OVER_CONSTRAINED_VOLUME", "ICON_OVER_CONSTRAINED_VOLUME", 0, true );
createSMESHAction( SMESHOp::OpEqualVolume, "EQUAL_VOLUME", "ICON_EQUAL_VOLUME", 0, true ); createSMESHAction( SMESHOp::OpEqualVolume, "EQUAL_VOLUME", "ICON_EQUAL_VOLUME", 0, true );
createSMESHAction( SMESHOp::OpScaledJacobian, "SCALED_JACOBIAN", "ICON_SCALED_JACOBIAN", 0, true );
createSMESHAction( SMESHOp::OpOverallMeshQuality, "OVERALL_MESH_QUALITY", "ICON_OVL_MESH_QUALITY" ); createSMESHAction( SMESHOp::OpOverallMeshQuality, "OVERALL_MESH_QUALITY", "ICON_OVL_MESH_QUALITY" );
createSMESHAction( SMESHOp::OpNode, "NODE", "ICON_DLG_NODE" ); createSMESHAction( SMESHOp::OpNode, "NODE", "ICON_DLG_NODE" );
@ -4353,7 +4358,7 @@ void SMESHGUI::initialize( CAM_Application* app )
<< SMESHOp::OpOverConstrainedFace << SMESHOp::OpEqualFace // face controls << SMESHOp::OpOverConstrainedFace << SMESHOp::OpEqualFace // face controls
<< SMESHOp::OpAspectRatio3D << SMESHOp::OpVolume << SMESHOp::OpAspectRatio3D << SMESHOp::OpVolume
<< SMESHOp::OpMaxElementLength3D << SMESHOp::OpBareBorderVolume << SMESHOp::OpMaxElementLength3D << SMESHOp::OpBareBorderVolume
<< SMESHOp::OpOverConstrainedVolume << SMESHOp::OpEqualVolume; // volume controls << SMESHOp::OpOverConstrainedVolume << SMESHOp::OpEqualVolume << SMESHOp::OpScaledJacobian; // volume controls
QActionGroup* aCtrlGroup = new QActionGroup( application()->desktop() ); QActionGroup* aCtrlGroup = new QActionGroup( application()->desktop() );
aCtrlGroup->setExclusive( true ); aCtrlGroup->setExclusive( true );
for( int i = 0; i < aCtrlActions.size(); i++ ) for( int i = 0; i < aCtrlActions.size(); i++ )
@ -4469,6 +4474,7 @@ void SMESHGUI::initialize( CAM_Application* app )
createMenu( SMESHOp::OpBareBorderVolume, volumeId, -1 ); createMenu( SMESHOp::OpBareBorderVolume, volumeId, -1 );
createMenu( SMESHOp::OpOverConstrainedVolume, volumeId, -1 ); createMenu( SMESHOp::OpOverConstrainedVolume, volumeId, -1 );
createMenu( SMESHOp::OpEqualVolume, volumeId, -1 ); createMenu( SMESHOp::OpEqualVolume, volumeId, -1 );
createMenu( SMESHOp::OpScaledJacobian, volumeId, -1 );
createMenu( separator(), ctrlId, -1 ); createMenu( separator(), ctrlId, -1 );
createMenu( SMESHOp::OpReset, ctrlId, -1 ); createMenu( SMESHOp::OpReset, ctrlId, -1 );
createMenu( separator(), ctrlId, -1 ); createMenu( separator(), ctrlId, -1 );
@ -4626,6 +4632,7 @@ void SMESHGUI::initialize( CAM_Application* app )
createTool( SMESHOp::OpBareBorderVolume, ctrl3dTb ); createTool( SMESHOp::OpBareBorderVolume, ctrl3dTb );
createTool( SMESHOp::OpOverConstrainedVolume, ctrl3dTb ); createTool( SMESHOp::OpOverConstrainedVolume, ctrl3dTb );
createTool( SMESHOp::OpEqualVolume, ctrl3dTb ); createTool( SMESHOp::OpEqualVolume, ctrl3dTb );
createTool( SMESHOp::OpScaledJacobian, ctrl3dTb );
int addElemTb = createTool( tr( "TB_ADD" ), QString( "SMESHAddElementToolbar" ) ) ; int addElemTb = createTool( tr( "TB_ADD" ), QString( "SMESHAddElementToolbar" ) ) ;
createTool( SMESHOp::OpNode, addElemTb ); createTool( SMESHOp::OpNode, addElemTb );
@ -5103,6 +5110,10 @@ void SMESHGUI::initialize( CAM_Application* app )
popupMgr()->setRule( action( SMESHOp::OpEqualVolume ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( SMESHOp::OpEqualVolume ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule );
popupMgr()->setRule( action( SMESHOp::OpEqualVolume ), "controlMode = 'eCoincidentElems3D'", QtxPopupMgr::ToggleRule ); popupMgr()->setRule( action( SMESHOp::OpEqualVolume ), "controlMode = 'eCoincidentElems3D'", QtxPopupMgr::ToggleRule );
popupMgr()->insert ( action( SMESHOp::OpScaledJacobian ), aSubId, -1 );
popupMgr()->setRule( action( SMESHOp::OpScaledJacobian ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule );
popupMgr()->setRule( action( SMESHOp::OpScaledJacobian ), "controlMode = 'eScaledJacobian'", QtxPopupMgr::ToggleRule );
popupMgr()->insert( separator(), anId, -1 ); popupMgr()->insert( separator(), anId, -1 );
popupMgr()->insert( action( SMESHOp::OpShowScalarBar ), anId, -1 ); popupMgr()->insert( action( SMESHOp::OpShowScalarBar ), anId, -1 );

View File

@ -1568,6 +1568,7 @@ void SMESHGUI_FilterTable::updateAdditionalWidget()
aCriterion == SMESH::FT_Skew || aCriterion == SMESH::FT_Skew ||
aCriterion == SMESH::FT_Area || aCriterion == SMESH::FT_Area ||
aCriterion == SMESH::FT_Volume3D || aCriterion == SMESH::FT_Volume3D ||
aCriterion == SMESH::FT_ScaledJacobian ||
aCriterion == SMESH::FT_MaxElementLength2D || aCriterion == SMESH::FT_MaxElementLength2D ||
aCriterion == SMESH::FT_MaxElementLength3D || aCriterion == SMESH::FT_MaxElementLength3D ||
aCriterion == SMESH::FT_Length || aCriterion == SMESH::FT_Length ||
@ -1816,6 +1817,7 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int /*col*/,
case SMESH::FT_Skew: case SMESH::FT_Skew:
case SMESH::FT_Area: case SMESH::FT_Area:
case SMESH::FT_Volume3D: case SMESH::FT_Volume3D:
case SMESH::FT_ScaledJacobian:
case SMESH::FT_MaxElementLength2D: case SMESH::FT_MaxElementLength2D:
case SMESH::FT_MaxElementLength3D: anIsDoubleCriterion = true; break; case SMESH::FT_MaxElementLength3D: anIsDoubleCriterion = true; break;
@ -2284,6 +2286,7 @@ const QMap<int, QString>& SMESHGUI_FilterTable::getCriteria (const int theType)
aCriteria[ SMESH::FT_EqualVolumes ] = tr("EQUAL_VOLUME"); aCriteria[ SMESH::FT_EqualVolumes ] = tr("EQUAL_VOLUME");
aCriteria[ SMESH::FT_EntityType ] = tr("ENTITY_TYPE"); aCriteria[ SMESH::FT_EntityType ] = tr("ENTITY_TYPE");
aCriteria[ SMESH::FT_ConnectedElements ] = tr("CONNECTED_ELEMS"); aCriteria[ SMESH::FT_ConnectedElements ] = tr("CONNECTED_ELEMS");
aCriteria[ SMESH::FT_ScaledJacobian ] = tr("SCALED_JACOBIAN");
} }
return aCriteria; return aCriteria;
} }

View File

@ -1684,6 +1684,8 @@ QString SMESHGUI_ElemInfo::ctrl2str( int control )
title = tr( "AREA_ELEMENTS" ); break; title = tr( "AREA_ELEMENTS" ); break;
case SMESH::FT_Volume3D: case SMESH::FT_Volume3D:
title = tr( "VOLUME_3D_ELEMENTS" ); break; title = tr( "VOLUME_3D_ELEMENTS" ); break;
case SMESH::FT_ScaledJacobian:
title = tr( "SCALED_JACOBIAN" ); break;
case SMESH::FT_MaxElementLength2D: case SMESH::FT_MaxElementLength2D:
title = tr( "MAX_ELEMENT_LENGTH_2D" ); break; title = tr( "MAX_ELEMENT_LENGTH_2D" ); break;
case SMESH::FT_MaxElementLength3D: case SMESH::FT_MaxElementLength3D:

View File

@ -122,6 +122,7 @@ namespace SMESHOp {
OpBareBorderVolume = 3303, // MENU CONTROLS - VOLUMES WITH BARE BORDER OpBareBorderVolume = 3303, // MENU CONTROLS - VOLUMES WITH BARE BORDER
OpOverConstrainedVolume = 3304, // MENU CONTROLS - OVERCONSTRAINED VOLUMES OpOverConstrainedVolume = 3304, // MENU CONTROLS - OVERCONSTRAINED VOLUMES
OpEqualVolume = 3305, // MENU CONTROLS - DOUBLE VOLUMES OpEqualVolume = 3305, // MENU CONTROLS - DOUBLE VOLUMES
OpScaledJacobian = 3306, // MENU CONTROLS - SCALED JACOBIAN
OpOverallMeshQuality = 3400, // MENU CONTROLS - OVERALL MESH QUALITY OpOverallMeshQuality = 3400, // MENU CONTROLS - OVERALL MESH QUALITY
// Modification -------------------//-------------------------------- // Modification -------------------//--------------------------------
OpNode = 4000, // MENU MODIFICATION - ADD - NODE OpNode = 4000, // MENU MODIFICATION - ADD - NODE

View File

@ -371,6 +371,7 @@ QString SMESHGUI_Selection::controlMode( int ind ) const
case SMESH_Actor::eMultiConnection2D: mode = "eMultiConnection2D"; break; case SMESH_Actor::eMultiConnection2D: mode = "eMultiConnection2D"; break;
case SMESH_Actor::eArea: mode = "eArea"; break; case SMESH_Actor::eArea: mode = "eArea"; break;
case SMESH_Actor::eVolume3D: mode = "eVolume3D"; break; case SMESH_Actor::eVolume3D: mode = "eVolume3D"; break;
case SMESH_Actor::eScaledJacobian: mode = "eScaledJacobian"; break;
case SMESH_Actor::eMaxElementLength2D: mode = "eMaxElementLength2D"; break; case SMESH_Actor::eMaxElementLength2D: mode = "eMaxElementLength2D"; break;
case SMESH_Actor::eMaxElementLength3D: mode = "eMaxElementLength3D"; break; case SMESH_Actor::eMaxElementLength3D: mode = "eMaxElementLength3D"; break;
case SMESH_Actor::eTaper: mode = "eTaper"; break; case SMESH_Actor::eTaper: mode = "eTaper"; break;
@ -429,6 +430,7 @@ bool SMESHGUI_Selection::isNumFunctor( int ind ) const
case SMESH_Actor::eMultiConnection2D: case SMESH_Actor::eMultiConnection2D:
case SMESH_Actor::eArea: case SMESH_Actor::eArea:
case SMESH_Actor::eVolume3D: case SMESH_Actor::eVolume3D:
case SMESH_Actor::eScaledJacobian:
case SMESH_Actor::eMaxElementLength2D: case SMESH_Actor::eMaxElementLength2D:
case SMESH_Actor::eMaxElementLength3D: case SMESH_Actor::eMaxElementLength3D:
case SMESH_Actor::eTaper: case SMESH_Actor::eTaper:

View File

@ -941,6 +941,9 @@ bool SMESH::SelectionProxy::elementControl( int id, int control, double precisio
case SMESH::FT_BallDiameter: case SMESH::FT_BallDiameter:
functor.reset( new SMESH::Controls::BallDiameter() ); functor.reset( new SMESH::Controls::BallDiameter() );
break; break;
case SMESH::FT_ScaledJacobian:
functor.reset( new SMESH::Controls::ScaledJacobian() );
break;
default: default:
break; break;
} }
@ -1009,6 +1012,9 @@ bool SMESH::SelectionProxy::elementControl( int id, int control, double precisio
case SMESH::FT_BallDiameter: case SMESH::FT_BallDiameter:
functor = manager->CreateBallDiameter(); functor = manager->CreateBallDiameter();
break; break;
case SMESH::FT_ScaledJacobian:
functor = manager->CreateScaledJacobian();
break;
default: default:
break; break;
} }

View File

@ -611,6 +611,10 @@
<source>ICON_VOLUME_3D</source> <source>ICON_VOLUME_3D</source>
<translation>mesh_volume_3d.png</translation> <translation>mesh_volume_3d.png</translation>
</message> </message>
<message>
<source>ICON_SCALED_JACOBIAN</source>
<translation>mesh_scaled_jacobian.png</translation>
</message>
<message> <message>
<source>ICON_BARE_BORDER_VOLUME</source> <source>ICON_BARE_BORDER_VOLUME</source>
<translation>bare_border_volume.png</translation> <translation>bare_border_volume.png</translation>

View File

@ -95,6 +95,10 @@
<source>BARE_BORDER_VOLUME</source> <source>BARE_BORDER_VOLUME</source>
<translation>Volumes with bare border</translation> <translation>Volumes with bare border</translation>
</message> </message>
<message>
<source>SCALED_JACOBIAN</source>
<translation>Scaled Jacobian</translation>
</message>
<message> <message>
<source>OVER_CONSTRAINED_VOLUME</source> <source>OVER_CONSTRAINED_VOLUME</source>
<translation>Over-constrained volumes</translation> <translation>Over-constrained volumes</translation>
@ -1316,6 +1320,10 @@
<source>MEN_VOLUME_3D</source> <source>MEN_VOLUME_3D</source>
<translation>Volume</translation> <translation>Volume</translation>
</message> </message>
<message>
<source>MEN_SCALED_JACOBIAN</source>
<translation>Scaled Jacobian</translation>
</message>
<message> <message>
<source>MEN_WARP</source> <source>MEN_WARP</source>
<translation>Warping Angle</translation> <translation>Warping Angle</translation>
@ -3912,6 +3920,10 @@ Use Display Entity menu command to show them.
<source>STB_VOLUME_3D</source> <source>STB_VOLUME_3D</source>
<translation>Volume</translation> <translation>Volume</translation>
</message> </message>
<message>
<source>STB_SCALED_JACOBIAN</source>
<translation>Scaled Jacobian</translation>
</message>
<message> <message>
<source>STB_WARP</source> <source>STB_WARP</source>
<translation>Warping angle</translation> <translation>Warping angle</translation>
@ -4624,6 +4636,10 @@ Use Display Entity menu command to show them.
<source>TOP_VOLUME_3D</source> <source>TOP_VOLUME_3D</source>
<translation>Volume</translation> <translation>Volume</translation>
</message> </message>
<message>
<source>TOP_SCALED_JACOBIAN</source>
<translation>Scaled Jacobian</translation>
</message>
<message> <message>
<source>TOP_WARP</source> <source>TOP_WARP</source>
<translation>Warping angle</translation> <translation>Warping angle</translation>
@ -6496,6 +6512,10 @@ Please enter correct value and try again</translation>
<source>VOLUME_3D</source> <source>VOLUME_3D</source>
<translation>Volume</translation> <translation>Volume</translation>
</message> </message>
<message>
<source>SCALED_JACOBIAN</source>
<translation>Scaled Jacobian</translation>
</message>
<message> <message>
<source>WARPING</source> <source>WARPING</source>
<translation>Warping</translation> <translation>Warping</translation>

View File

@ -99,6 +99,10 @@
<source>OVER_CONSTRAINED_VOLUME</source> <source>OVER_CONSTRAINED_VOLUME</source>
<translation>Volumes sur-contraints</translation> <translation>Volumes sur-contraints</translation>
</message> </message>
<message>
<source>SCALED_JACOBIAN</source>
<translation>Jacobien normalisé</translation>
</message>
<message> <message>
<source>MIN_DIAG_ELEMENTS</source> <source>MIN_DIAG_ELEMENTS</source>
<translation>Diagonale minimum</translation> <translation>Diagonale minimum</translation>
@ -1316,6 +1320,10 @@
<source>MEN_VOLUME_3D</source> <source>MEN_VOLUME_3D</source>
<translation>Volume</translation> <translation>Volume</translation>
</message> </message>
<message>
<source>MEN_SCALED_JACOBIAN</source>
<translation>Jacobien normalisé</translation>
</message>
<message> <message>
<source>MEN_WARP</source> <source>MEN_WARP</source>
<translation>Angle de déformation</translation> <translation>Angle de déformation</translation>
@ -3911,6 +3919,10 @@ Utilisez le menu &quot;Visualiser une entité&quot; pour les afficher.
<source>STB_VOLUME_3D</source> <source>STB_VOLUME_3D</source>
<translation>Volume</translation> <translation>Volume</translation>
</message> </message>
<message>
<source>STB_SCALED_JACOBIAN</source>
<translation>Jacobien normalisé</translation>
</message>
<message> <message>
<source>STB_WARP</source> <source>STB_WARP</source>
<translation>Angle de déformation</translation> <translation>Angle de déformation</translation>
@ -4623,6 +4635,10 @@ Utilisez le menu &quot;Visualiser une entité&quot; pour les afficher.
<source>TOP_VOLUME_3D</source> <source>TOP_VOLUME_3D</source>
<translation>Volume</translation> <translation>Volume</translation>
</message> </message>
<message>
<source>TOP_SCALED_JACOBIAN</source>
<translation>Jacobien normalisé</translation>
</message>
<message> <message>
<source>TOP_WARP</source> <source>TOP_WARP</source>
<translation>Angle de déformation</translation> <translation>Angle de déformation</translation>

View File

@ -71,6 +71,10 @@
<source>NODE_CONNECTIVITY_NB</source> <source>NODE_CONNECTIVITY_NB</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>SCALED_JACOBIAN</source>
<translation></translation>
</message>
<message> <message>
<source>FREE_EDGES</source> <source>FREE_EDGES</source>
<translation></translation> <translation></translation>
@ -1119,6 +1123,10 @@
<source>MEN_VOLUME_3D</source> <source>MEN_VOLUME_3D</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>MEN_SCALED_JACOBIAN</source>
<translation></translation>
</message>
<message> <message>
<source>MEN_WARP</source> <source>MEN_WARP</source>
<translation></translation> <translation></translation>
@ -3519,6 +3527,10 @@
<source>STB_VOLUMES</source> <source>STB_VOLUMES</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>STB_SCALED_JACOBIAN</source>
<translation></translation>
</message>
<message> <message>
<source>STB_VOLUME_3D</source> <source>STB_VOLUME_3D</source>
<translation></translation> <translation></translation>
@ -4183,6 +4195,10 @@
<source>TOP_VOLUMES</source> <source>TOP_VOLUMES</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>TOP_SCALED_JACOBIAN</source>
<translation></translation>
</message>
<message> <message>
<source>TOP_VOLUME_3D</source> <source>TOP_VOLUME_3D</source>
<translation></translation> <translation></translation>
@ -5921,7 +5937,7 @@
</message> </message>
<message> <message>
<source>VOLUME_3D</source> <source>VOLUME_3D</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<source>WARPING</source> <source>WARPING</source>

View File

@ -301,6 +301,8 @@ namespace {
// - FT_Deflection2D = 22 // - FT_Deflection2D = 22
// v 9.3.0: FT_Undefined == 50, new items: // v 9.3.0: FT_Undefined == 50, new items:
// - FT_Length3D = 22 // - FT_Length3D = 22
// v 9.12.0: FT_Undefined == 51, new items:
// - FT_ScaledJacobian = 8
// //
// It's necessary to continue recording this history and to fill // It's necessary to continue recording this history and to fill
// undef2newItems (see below) accordingly. // undef2newItems (see below) accordingly.
@ -325,6 +327,7 @@ namespace {
undef2newItems[ 48 ].push_back( 22 ); undef2newItems[ 48 ].push_back( 22 );
undef2newItems[ 49 ].push_back( 22 ); undef2newItems[ 49 ].push_back( 22 );
undef2newItems[ 50 ].push_back( 22 ); undef2newItems[ 50 ].push_back( 22 );
undef2newItems[ 51 ].push_back( 8 );
ASSERT( undef2newItems.rbegin()->first == SMESH::FT_Undefined ); ASSERT( undef2newItems.rbegin()->first == SMESH::FT_Undefined );
} }

View File

@ -460,6 +460,21 @@ namespace SMESH {
return SMESH::FT_Volume3D; return SMESH::FT_Volume3D;
} }
/*
Class : ScaledJacobian_i
Description : Functor for calculating volume of 3D element
*/
ScaledJacobian_i::ScaledJacobian_i()
{
myNumericalFunctorPtr.reset( new Controls::ScaledJacobian() );
myFunctorPtr = myNumericalFunctorPtr;
}
FunctorType ScaledJacobian_i::GetFunctorType()
{
return SMESH::FT_ScaledJacobian;
}
/* /*
Class : MaxElementLength2D_i Class : MaxElementLength2D_i
Description : Functor for calculating maximum length of 2D element Description : Functor for calculating maximum length of 2D element
@ -2126,6 +2141,13 @@ namespace SMESH {
return anObj._retn(); return anObj._retn();
} }
ScaledJacobian_ptr FilterManager_i::CreateScaledJacobian()
{
SMESH::ScaledJacobian_i* aServant = new SMESH::ScaledJacobian_i();
SMESH::ScaledJacobian_var anObj = aServant->_this();
TPythonDump()<<aServant<<" = "<<this<<".CreateScaledJacobian()";
return anObj._retn();
}
MaxElementLength2D_ptr FilterManager_i::CreateMaxElementLength2D() MaxElementLength2D_ptr FilterManager_i::CreateMaxElementLength2D()
{ {
@ -3076,6 +3098,9 @@ namespace SMESH {
case SMESH::FT_NodeConnectivityNumber: case SMESH::FT_NodeConnectivityNumber:
aFunctor = aFilterMgr->CreateNodeConnectivityNumber(); aFunctor = aFilterMgr->CreateNodeConnectivityNumber();
break; break;
case SMESH::FT_ScaledJacobian:
aFunctor = aFilterMgr->CreateScaledJacobian();
break;
// Predicates // Predicates
@ -3512,6 +3537,7 @@ namespace SMESH {
case FT_Skew : return "Skew"; case FT_Skew : return "Skew";
case FT_Area : return "Area"; case FT_Area : return "Area";
case FT_Volume3D : return "Volume3D"; case FT_Volume3D : return "Volume3D";
case FT_ScaledJacobian : return "ScaledJacobian";
case FT_MaxElementLength2D : return "Max element length 2D"; case FT_MaxElementLength2D : return "Max element length 2D";
case FT_MaxElementLength3D : return "Max element length 3D"; case FT_MaxElementLength3D : return "Max element length 3D";
case FT_BelongToMeshGroup : return "Belong to Mesh Group"; case FT_BelongToMeshGroup : return "Belong to Mesh Group";
@ -3568,6 +3594,7 @@ namespace SMESH {
else if ( theStr.equals( "Skew" ) ) return FT_Skew; else if ( theStr.equals( "Skew" ) ) return FT_Skew;
else if ( theStr.equals( "Area" ) ) return FT_Area; else if ( theStr.equals( "Area" ) ) return FT_Area;
else if ( theStr.equals( "Volume3D" ) ) return FT_Volume3D; else if ( theStr.equals( "Volume3D" ) ) return FT_Volume3D;
else if ( theStr.equals( "ScaledJacobian" ) ) return FT_ScaledJacobian;
else if ( theStr.equals( "Max element length 2D" ) ) return FT_MaxElementLength2D; else if ( theStr.equals( "Max element length 2D" ) ) return FT_MaxElementLength2D;
else if ( theStr.equals( "Max element length 3D" ) ) return FT_MaxElementLength3D; else if ( theStr.equals( "Max element length 3D" ) ) return FT_MaxElementLength3D;
else if ( theStr.equals( "Belong to Mesh Group" ) ) return FT_BelongToMeshGroup; else if ( theStr.equals( "Belong to Mesh Group" ) ) return FT_BelongToMeshGroup;
@ -4141,6 +4168,7 @@ namespace SMESH {
"FT_Skew", "FT_Skew",
"FT_Area", "FT_Area",
"FT_Volume3D", "FT_Volume3D",
"FT_ScaledJacobian",
"FT_MaxElementLength2D", "FT_MaxElementLength2D",
"FT_MaxElementLength3D", "FT_MaxElementLength3D",
"FT_FreeBorders", "FT_FreeBorders",

View File

@ -352,6 +352,18 @@ namespace SMESH
FunctorType GetFunctorType(); FunctorType GetFunctorType();
}; };
/*
Class : ScaledJacobian_i
Description : Functor returning the scaled jacobian
*/
class SMESH_I_EXPORT ScaledJacobian_i: public virtual POA_SMESH::ScaledJacobian,
public virtual NumericalFunctor_i
{
public:
ScaledJacobian_i();
FunctorType GetFunctorType();
};
/* /*
PREDICATES PREDICATES
@ -1113,6 +1125,7 @@ namespace SMESH
Skew_ptr CreateSkew(); Skew_ptr CreateSkew();
Area_ptr CreateArea(); Area_ptr CreateArea();
Volume3D_ptr CreateVolume3D(); Volume3D_ptr CreateVolume3D();
ScaledJacobian_ptr CreateScaledJacobian();
MaxElementLength2D_ptr CreateMaxElementLength2D(); MaxElementLength2D_ptr CreateMaxElementLength2D();
MaxElementLength3D_ptr CreateMaxElementLength3D(); MaxElementLength3D_ptr CreateMaxElementLength3D();
Length_ptr CreateLength(); Length_ptr CreateLength();

View File

@ -414,6 +414,7 @@ namespace SMESH
case FT_Skew: myStream<< "aSkew"; break; case FT_Skew: myStream<< "aSkew"; break;
case FT_Area: myStream<< "aArea"; break; case FT_Area: myStream<< "aArea"; break;
case FT_Volume3D: myStream<< "aVolume3D"; break; case FT_Volume3D: myStream<< "aVolume3D"; break;
case FT_ScaledJacobian: myStream<< "aScaledJacobian"; break;
case FT_MaxElementLength2D: myStream<< "aMaxElementLength2D"; break; case FT_MaxElementLength2D: myStream<< "aMaxElementLength2D"; break;
case FT_MaxElementLength3D: myStream<< "aMaxElementLength3D"; break; case FT_MaxElementLength3D: myStream<< "aMaxElementLength3D"; break;
case FT_FreeBorders: myStream<< "aFreeBorders"; break; case FT_FreeBorders: myStream<< "aFreeBorders"; break;

View File

@ -1233,6 +1233,8 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
functor = aFilterMgr.CreateNodeConnectivityNumber() functor = aFilterMgr.CreateNodeConnectivityNumber()
elif theCriterion == FT_BallDiameter: elif theCriterion == FT_BallDiameter:
functor = aFilterMgr.CreateBallDiameter() functor = aFilterMgr.CreateBallDiameter()
elif theCriterion == FT_ScaledJacobian:
functor = aFilterMgr.CreateScaledJacobian()
else: else:
print("Error: given parameter is not numerical functor type.") print("Error: given parameter is not numerical functor type.")
aFilterMgr.UnRegister() aFilterMgr.UnRegister()
@ -7469,6 +7471,19 @@ class Mesh(metaclass = MeshMeta):
return self.FunctorValue(SMESH.FT_Skew, elemId) return self.FunctorValue(SMESH.FT_Skew, elemId)
def GetScaledJacobian(self, elemId):
"""
Get the scaled jacobian of 3D element id
Parameters:
elemId: mesh element ID
Returns:
the scaled jacobian
"""
return self.FunctorValue(SMESH.FT_ScaledJacobian, elemId)
def GetMinMax(self, funType, meshPart=None): def GetMinMax(self, funType, meshPart=None):
""" """
Return minimal and maximal value of a given functor. Return minimal and maximal value of a given functor.

View File

@ -0,0 +1,144 @@
# -*- coding: iso-8859-1 -*-
# Copyright (C) 2016-2023 CEA/DEN, EDF R&D
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
#
# File : SMESH_controls_scaled_jacobian.py
# Author : Cesar Conopoima
# Module : SMESH
#
import salome
import math
salome.salome_init_without_session()
import GEOM
import SMESH
from salome.geom import geomBuilder
from salome.smesh import smeshBuilder
def assertWithDelta( refval, testvals, delta ):
return ( refval <= testvals+delta and refval >= testvals-delta )
geompy = geomBuilder.New()
smesh_builder = smeshBuilder.New()
Box_1 = geompy.MakeBoxDXDYDZ(10, 10, 10)
geompy.addToStudy( Box_1, 'Box_1' )
smesh = smeshBuilder.New()
Mesh_1 = smesh.Mesh(Box_1,'Mesh_1')
NETGEN_1D_2D_3D = Mesh_1.Tetrahedron(algo=smeshBuilder.NETGEN_1D2D3D)
Done = Mesh_1.Compute()
if not Done:
raise Exception("Error when computing NETGEN_1D2D3D Mesh for quality control test")
#For tetra elements
perfect = 1.0
externals = math.sqrt( 2.0 )/2.0
notPerfectElements = smesh.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_LessThan, perfect - 1e-12 )
perfectElements = smesh.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_EqualTo, perfect )
externalElements = smesh.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_EqualTo, externals )
notPerfectIds = Mesh_1.GetIdsFromFilter(notPerfectElements)
perfectIds = Mesh_1.GetIdsFromFilter(perfectElements)
externalsIds = Mesh_1.GetIdsFromFilter(externalElements)
assert( len(notPerfectIds) == 4 )
assert( len(perfectIds) == 1 )
assert( len(externalsIds) == 4 )
# Test GetScaledJacobian by elementId
for id in range(len(perfectIds)):
assert( assertWithDelta( perfect, Mesh_1.GetScaledJacobian( perfectIds[ id ] ), 1e-12) )
for id in range(len(externalsIds)):
assert( assertWithDelta( externals, Mesh_1.GetScaledJacobian( externalsIds[ id ] ), 1e-12) )
#For hexa elements
Mesh_2 = smesh.Mesh(Box_1,'Mesh_2')
Cartesian_3D = Mesh_2.BodyFitted()
Body_Fitting_Parameters_1 = Cartesian_3D.SetGrid([ [ '5.0' ], [ 0, 1 ]],[ [ '5.0' ], [ 0, 1 ]],[ [ '5.0' ], [ 0, 1 ]],4,0)
Done = Mesh_2.Compute()
if not Done:
raise Exception("Error when computing BodyFitted Mesh for quality control test")
notPerfectIds = Mesh_2.GetIdsFromFilter(notPerfectElements)
perfectIds = Mesh_2.GetIdsFromFilter(perfectElements)
assert( len(notPerfectIds) == 0 )
assert( len(perfectIds) == 8 )
# Test GetScaledJacobian by elementId
for id in range(len(perfectIds)):
assert( assertWithDelta( perfect, Mesh_2.GetScaledJacobian( perfectIds[ id ] ), 1e-12) )
#For hexa elements with poor quality
Mesh_3 = smesh.Mesh(Box_1,'Mesh_3')
Cartesian_3D = Mesh_3.BodyFitted()
Body_Fitting_Parameters_1 = Cartesian_3D.SetGrid([ [ '5.0' ], [ 0, 1 ]],[ [ '5.0' ], [ 0, 1 ]],[ [ '5.0' ], [ 0, 1 ]],4,0)
Body_Fitting_Parameters_1.SetAxesDirs( SMESH.DirStruct( SMESH.PointStruct ( 1, 0, 1 )), SMESH.DirStruct( SMESH.PointStruct ( 0, 1, 0 )), SMESH.DirStruct( SMESH.PointStruct ( 0, 0, 1 )) )
Done = Mesh_3.Compute()
if not Done:
raise Exception("Error when computing BodyFitted Distorted Mesh for quality control test")
#Polyhedrons return zero scaled jacobian because of lack for a decomposition into simpler forms
Polys = 0.0
#Hexahedrons that are distorted by an angle of 45
# Scaled Jacobian which is a measure of elements distortion
# will return cos(45) = math.sqrt( 2.0 )/2.0
distorted = math.sqrt( 2.0 )/2.0
polysElements = smesh.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_EqualTo, Polys )
distortedElements = smesh.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_EqualTo, distorted )
polysIds = Mesh_3.GetIdsFromFilter(polysElements)
distortedIds = Mesh_3.GetIdsFromFilter(distortedElements)
assert( len(polysIds) == 4 )
assert( len(distortedIds) == 8 )
# Test GetScaledJacobian by elementId
for id in range(len(distortedIds)):
assert( assertWithDelta( distorted, Mesh_3.GetScaledJacobian( distortedIds[ id ] ), 1e-12 ) )
#Test the pentahedron
Mesh_4 = smesh.Mesh(Box_1,'Mesh_4')
Cartesian_3D = Mesh_4.BodyFitted()
Body_Fitting_Parameters_1 = Cartesian_3D.SetGrid([ [ '4' ], [ 0, 1 ]],[ [ '4' ], [ 0, 1 ]],[ [ '4' ], [ 0, 1 ]],4,0)
Body_Fitting_Parameters_1.SetAxesDirs( SMESH.DirStruct( SMESH.PointStruct ( 1, 0, 1 )), SMESH.DirStruct( SMESH.PointStruct ( 0, 1, 0 )), SMESH.DirStruct( SMESH.PointStruct ( 0, 0, 1 )) )
Body_Fitting_Parameters_1.SetSizeThreshold( 4 )
Body_Fitting_Parameters_1.SetToAddEdges( 0 )
Body_Fitting_Parameters_1.SetGridSpacing( [ '2' ], [ 0, 1 ], 0 )
Body_Fitting_Parameters_1.SetGridSpacing( [ '2' ], [ 0, 1 ], 1 )
Body_Fitting_Parameters_1.SetGridSpacing( [ '2' ], [ 0, 1 ], 2 )
Done = Mesh_4.Compute()
if not Done:
raise Exception("Error when computing BodyFitted Distorted Mesh for quality control test")
pentahedrons = 0.6
pentasAndPolys = smesh.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_LessThan, pentahedrons )
#Distorted hexas
polysIds = Mesh_4.GetIdsFromFilter(polysElements)
pentasAndPolysIds = Mesh_4.GetIdsFromFilter(pentasAndPolys)
assert( len(pentasAndPolysIds) - len(polysIds) == 10 )

View File

@ -44,6 +44,7 @@ SET(BAD_TESTS
SMESH_box3_tetra.py SMESH_box3_tetra.py
SMESH_box_tetra.py SMESH_box_tetra.py
SMESH_controls.py SMESH_controls.py
SMESH_controls_scaled_jacobian.py
SMESH_fixation_netgen.py SMESH_fixation_netgen.py
SMESH_fixation_tetra.py SMESH_fixation_tetra.py
SMESH_flight_skin.py SMESH_flight_skin.py