--- /dev/null
+# 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))
--- /dev/null
+# 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)
\ No newline at end of file
filters_ex36.py
filters_ex37.py
filters_ex38.py
+ filters_ex40.py
filters_node_nb_conn.py
filters_belong2group.py
generate_flat_elements.py
quality_controls_ex20.py
quality_controls_ex21.py
quality_controls_ex22.py
+ quality_controls_ex24.py
quality_controls_defl.py
split_biquad.py
transforming_meshes_ex01.py
* :ref:`aspect_ratio_3d_page`
* :ref:`volume_page`
* :ref:`max_element_length_3d_page`
+* :ref:`scaled_jacobian_page`
* :ref:`bare_border_volumes_page`
* :ref:`over_constrained_volumes_page`
* :ref:`double_elements_page`
max_element_length_3d.rst
bare_border_volumes.rst
over_constrained_volumes.rst
- scalar_bar.rst
+ scalar_bar.rst
+ scaled_jacobian.rst
\ No newline at end of file
--- /dev/null
+.. _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.
**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:
Warping angle
:language: python
: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>`
FT_Taper,
FT_Skew,
FT_Area,
- FT_Volume3D,
+ FT_Volume3D,
+ FT_ScaledJacobian,
FT_MaxElementLength2D,
FT_MaxElementLength3D,
FT_FreeBorders,
};
interface BallDiameter : NumericalFunctor{};
interface NodeConnectivityNumber : NumericalFunctor{};
+ interface ScaledJacobian : NumericalFunctor{};
/*!
MultiConnection2D CreateMultiConnection2D();
BallDiameter CreateBallDiameter();
NodeConnectivityNumber CreateNodeConnectivityNumber();
+ ScaledJacobian CreateScaledJacobian();
/*!
* Create logical functors ( predicates )
*/
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
*/
virtual double GetBadRate( double Value, int nbNodes ) 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;
+ };
/*
myControlActor = my3DActor;
break;
}
+ case eScaledJacobian:
+ {
+ SMESH::Controls::ScaledJacobian* aControl = new SMESH::Controls::ScaledJacobian();
+ aControl->SetPrecision( myControlsPrecision );
+ myFunctor.reset( aControl );
+ myControlActor = my3DActor;
+ break;
+ }
case eMaxElementLength2D:
{
SMESH::Controls::MaxElementLength2D* aControl = new SMESH::Controls::MaxElementLength2D();
QString aTitle = QString(myScalarBarActor->GetTitle());
aTitle.replace(QRegExp("(:\\s).*"),"\\1"+ QString::number(GetNumberControlEntities()));
myScalarBarActor->SetTitle(aTitle.toUtf8().constData());
-
}
else {
if(theCheckEntityMode){
enum eControl{eNone, eLength, eLength2D, eDeflection2D, eFreeBorders, eFreeEdges, eFreeNodes,
eFreeFaces, eMultiConnection, eArea, eTaper, eAspectRatio,
- eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D,
+ eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D, eScaledJacobian,
eMaxElementLength2D, eMaxElementLength3D, eBareBorderFace, eBareBorderVolume,
eOverConstrainedFace, eOverConstrainedVolume, eCoincidentNodes,
eCoincidentElems1D, eCoincidentElems2D, eCoincidentElems3D, eNodeConnectivityNb,
{ 0, 3, 2, 0 }};
static int Tetra_nbN [] = { 3, 3, 3, 3 };
-//
-// PYRAMID
-//
+/*
+// N1 +---------+ N2
+// | \ / |
+// | \ / |
+// | \ / |
+// | /+\ | PYRAMID
+// | / N4\ |
+// | / \ |
+// |/ \|
+// N0 +---------+ N3
+*/
static int Pyramid_F [5][5] = { // FORWARD == EXTERNAL
{ 0, 1, 2, 3, 0 }, // All faces have external normals
{ 0, 4, 1, 0, 4 },
inline XYZ operator-( const XYZ& other );
inline XYZ operator+( const XYZ& other );
inline XYZ Crossed( const XYZ& other );
+ inline XYZ operator-();
inline double Dot( const XYZ& other );
inline double Magnitude();
inline double SquareMagnitude();
+ inline XYZ Normalize();
};
inline XYZ XYZ::operator-( const XYZ& Right ) {
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 ) {
return XYZ(x + Right.x, y + Right.y, z + Right.z);
}
inline double XYZ::SquareMagnitude() {
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);
+}
//================================================================================
/*!
//function : GetSize
//purpose : Return element volume
//=======================================================================
-
double SMDS_VolumeTool::GetSize() const
{
double V = 0.;
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
//purpose :
double GetSize() const;
// Return element volume
+ double GetScaledJacobian() const;
+ // Return the scaled jacobian
+
bool GetBaryCenter (double & X, double & Y, double & Z) const;
bool IsOut(double X, double Y, double Z, double tol) const;
type = QObject::tr( "EQUAL_VOLUME" );
else if ( dynamic_cast< SMESH::Controls::NodeConnectivityNumber* >( f.get() ) )
type = QObject::tr( "NODE_CONNECTIVITY_NB" );
+ else if ( dynamic_cast< SMESH::Controls::ScaledJacobian* >( f.get() ) )
+ type = QObject::tr( "SCALED_JACOBIAN" );
return type;
}
ActionControl.Bind( SMESHOp::OpEqualFace, SMESH_Actor::eCoincidentElems2D );
ActionControl.Bind( SMESHOp::OpAspectRatio3D, SMESH_Actor::eAspectRatio3D );
ActionControl.Bind( SMESHOp::OpVolume, SMESH_Actor::eVolume3D );
+ ActionControl.Bind( SMESHOp::OpScaledJacobian, SMESH_Actor::eScaledJacobian );
ActionControl.Bind( SMESHOp::OpMaxElementLength3D, SMESH_Actor::eMaxElementLength3D );
ActionControl.Bind( SMESHOp::OpBareBorderVolume, SMESH_Actor::eBareBorderVolume );
ActionControl.Bind( SMESHOp::OpOverConstrainedVolume, SMESH_Actor::eOverConstrainedVolume );
case SMESHOp::OpEqualFace:
case SMESHOp::OpAspectRatio3D:
case SMESHOp::OpVolume:
+ case SMESHOp::OpScaledJacobian:
case SMESHOp::OpMaxElementLength3D:
case SMESHOp::OpBareBorderVolume:
case SMESHOp::OpOverConstrainedVolume:
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::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::OpNode, "NODE", "ICON_DLG_NODE" );
<< SMESHOp::OpOverConstrainedFace << SMESHOp::OpEqualFace // face controls
<< SMESHOp::OpAspectRatio3D << SMESHOp::OpVolume
<< SMESHOp::OpMaxElementLength3D << SMESHOp::OpBareBorderVolume
- << SMESHOp::OpOverConstrainedVolume << SMESHOp::OpEqualVolume; // volume controls
+ << SMESHOp::OpOverConstrainedVolume << SMESHOp::OpEqualVolume << SMESHOp::OpScaledJacobian; // volume controls
QActionGroup* aCtrlGroup = new QActionGroup( application()->desktop() );
aCtrlGroup->setExclusive( true );
for( int i = 0; i < aCtrlActions.size(); i++ )
createMenu( SMESHOp::OpBareBorderVolume, volumeId, -1 );
createMenu( SMESHOp::OpOverConstrainedVolume, volumeId, -1 );
createMenu( SMESHOp::OpEqualVolume, volumeId, -1 );
+ createMenu( SMESHOp::OpScaledJacobian, volumeId, -1 );
createMenu( separator(), ctrlId, -1 );
createMenu( SMESHOp::OpReset, ctrlId, -1 );
createMenu( separator(), ctrlId, -1 );
createTool( SMESHOp::OpBareBorderVolume, ctrl3dTb );
createTool( SMESHOp::OpOverConstrainedVolume, ctrl3dTb );
createTool( SMESHOp::OpEqualVolume, ctrl3dTb );
+ createTool( SMESHOp::OpScaledJacobian, ctrl3dTb );
int addElemTb = createTool( tr( "TB_ADD" ), QString( "SMESHAddElementToolbar" ) ) ;
createTool( SMESHOp::OpNode, addElemTb );
popupMgr()->setRule( action( SMESHOp::OpEqualVolume ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule );
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( action( SMESHOp::OpShowScalarBar ), anId, -1 );
aCriterion == SMESH::FT_Skew ||
aCriterion == SMESH::FT_Area ||
aCriterion == SMESH::FT_Volume3D ||
+ aCriterion == SMESH::FT_ScaledJacobian ||
aCriterion == SMESH::FT_MaxElementLength2D ||
aCriterion == SMESH::FT_MaxElementLength3D ||
aCriterion == SMESH::FT_Length ||
case SMESH::FT_Skew:
case SMESH::FT_Area:
case SMESH::FT_Volume3D:
+ case SMESH::FT_ScaledJacobian:
case SMESH::FT_MaxElementLength2D:
case SMESH::FT_MaxElementLength3D: anIsDoubleCriterion = true; break;
aCriteria[ SMESH::FT_EqualVolumes ] = tr("EQUAL_VOLUME");
aCriteria[ SMESH::FT_EntityType ] = tr("ENTITY_TYPE");
aCriteria[ SMESH::FT_ConnectedElements ] = tr("CONNECTED_ELEMS");
+ aCriteria[ SMESH::FT_ScaledJacobian ] = tr("SCALED_JACOBIAN");
}
return aCriteria;
}
title = tr( "AREA_ELEMENTS" ); break;
case SMESH::FT_Volume3D:
title = tr( "VOLUME_3D_ELEMENTS" ); break;
+ case SMESH::FT_ScaledJacobian:
+ title = tr( "SCALED_JACOBIAN" ); break;
case SMESH::FT_MaxElementLength2D:
title = tr( "MAX_ELEMENT_LENGTH_2D" ); break;
case SMESH::FT_MaxElementLength3D:
OpBareBorderVolume = 3303, // MENU CONTROLS - VOLUMES WITH BARE BORDER
OpOverConstrainedVolume = 3304, // MENU CONTROLS - OVERCONSTRAINED VOLUMES
OpEqualVolume = 3305, // MENU CONTROLS - DOUBLE VOLUMES
+ OpScaledJacobian = 3306, // MENU CONTROLS - SCALED JACOBIAN
OpOverallMeshQuality = 3400, // MENU CONTROLS - OVERALL MESH QUALITY
// Modification -------------------//--------------------------------
OpNode = 4000, // MENU MODIFICATION - ADD - NODE
case SMESH_Actor::eMultiConnection2D: mode = "eMultiConnection2D"; break;
case SMESH_Actor::eArea: mode = "eArea"; 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::eMaxElementLength3D: mode = "eMaxElementLength3D"; break;
case SMESH_Actor::eTaper: mode = "eTaper"; break;
case SMESH_Actor::eMultiConnection2D:
case SMESH_Actor::eArea:
case SMESH_Actor::eVolume3D:
+ case SMESH_Actor::eScaledJacobian:
case SMESH_Actor::eMaxElementLength2D:
case SMESH_Actor::eMaxElementLength3D:
case SMESH_Actor::eTaper:
case SMESH::FT_BallDiameter:
functor.reset( new SMESH::Controls::BallDiameter() );
break;
+ case SMESH::FT_ScaledJacobian:
+ functor.reset( new SMESH::Controls::ScaledJacobian() );
+ break;
default:
break;
}
case SMESH::FT_BallDiameter:
functor = manager->CreateBallDiameter();
break;
+ case SMESH::FT_ScaledJacobian:
+ functor = manager->CreateScaledJacobian();
+ break;
default:
break;
}
<source>ICON_VOLUME_3D</source>
<translation>mesh_volume_3d.png</translation>
</message>
+ <message>
+ <source>ICON_SCALED_JACOBIAN</source>
+ <translation>mesh_scaled_jacobian.png</translation>
+ </message>
<message>
<source>ICON_BARE_BORDER_VOLUME</source>
<translation>bare_border_volume.png</translation>
<source>BARE_BORDER_VOLUME</source>
<translation>Volumes with bare border</translation>
</message>
+ <message>
+ <source>SCALED_JACOBIAN</source>
+ <translation>Scaled Jacobian</translation>
+ </message>
<message>
<source>OVER_CONSTRAINED_VOLUME</source>
<translation>Over-constrained volumes</translation>
<source>MEN_VOLUME_3D</source>
<translation>Volume</translation>
</message>
+ <message>
+ <source>MEN_SCALED_JACOBIAN</source>
+ <translation>Scaled Jacobian</translation>
+ </message>
<message>
<source>MEN_WARP</source>
<translation>Warping Angle</translation>
<source>STB_VOLUME_3D</source>
<translation>Volume</translation>
</message>
+ <message>
+ <source>STB_SCALED_JACOBIAN</source>
+ <translation>Scaled Jacobian</translation>
+ </message>
<message>
<source>STB_WARP</source>
<translation>Warping angle</translation>
<source>TOP_VOLUME_3D</source>
<translation>Volume</translation>
</message>
+ <message>
+ <source>TOP_SCALED_JACOBIAN</source>
+ <translation>Scaled Jacobian</translation>
+ </message>
<message>
<source>TOP_WARP</source>
<translation>Warping angle</translation>
<source>VOLUME_3D</source>
<translation>Volume</translation>
</message>
+ <message>
+ <source>SCALED_JACOBIAN</source>
+ <translation>Scaled Jacobian</translation>
+ </message>
<message>
<source>WARPING</source>
<translation>Warping</translation>
<source>OVER_CONSTRAINED_VOLUME</source>
<translation>Volumes sur-contraints</translation>
</message>
+ <message>
+ <source>SCALED_JACOBIAN</source>
+ <translation>Jacobien normalisé</translation>
+ </message>
<message>
<source>MIN_DIAG_ELEMENTS</source>
<translation>Diagonale minimum</translation>
<source>MEN_VOLUME_3D</source>
<translation>Volume</translation>
</message>
+ <message>
+ <source>MEN_SCALED_JACOBIAN</source>
+ <translation>Jacobien normalisé</translation>
+ </message>
<message>
<source>MEN_WARP</source>
<translation>Angle de déformation</translation>
<source>STB_VOLUME_3D</source>
<translation>Volume</translation>
</message>
+ <message>
+ <source>STB_SCALED_JACOBIAN</source>
+ <translation>Jacobien normalisé</translation>
+ </message>
<message>
<source>STB_WARP</source>
<translation>Angle de déformation</translation>
<source>TOP_VOLUME_3D</source>
<translation>Volume</translation>
</message>
+ <message>
+ <source>TOP_SCALED_JACOBIAN</source>
+ <translation>Jacobien normalisé</translation>
+ </message>
<message>
<source>TOP_WARP</source>
<translation>Angle de déformation</translation>
<source>NODE_CONNECTIVITY_NB</source>
<translation>節点接続番号</translation>
</message>
+ <message>
+ <source>SCALED_JACOBIAN</source>
+ <translation>スケーリングされたヤコビアン</translation>
+ </message>
<message>
<source>FREE_EDGES</source>
<translation>フリーエッジ</translation>
<source>MEN_VOLUME_3D</source>
<translation>ボリューム</translation>
</message>
+ <message>
+ <source>MEN_SCALED_JACOBIAN</source>
+ <translation>スケーリングされたヤコビアン</translation>
+ </message>
<message>
<source>MEN_WARP</source>
<translation>変形の角度</translation>
<source>STB_VOLUMES</source>
<translation>ボリューム</translation>
</message>
+ <message>
+ <source>STB_SCALED_JACOBIAN</source>
+ <translation>スケーリングされたヤコビアン</translation>
+ </message>
<message>
<source>STB_VOLUME_3D</source>
<translation>ボリューム</translation>
<source>TOP_VOLUMES</source>
<translation>ボリューム</translation>
</message>
+ <message>
+ <source>TOP_SCALED_JACOBIAN</source>
+ <translation>スケーリングされたヤコビアン</translation>
+ </message>
<message>
<source>TOP_VOLUME_3D</source>
<translation>ボリューム</translation>
</message>
<message>
<source>VOLUME_3D</source>
- <translation>ã\83\9cã\83ªã\83¥ã\83¼ã\83 </translation>
+ <translation>ã\82¹ã\82±ã\83¼ã\83ªã\83³ã\82°ã\81\95ã\82\8cã\81\9fã\83¤ã\82³ã\83\93ã\82¢ã\83³</translation>
</message>
<message>
<source>WARPING</source>
// - FT_Deflection2D = 22
// v 9.3.0: FT_Undefined == 50, new items:
// - 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
// undef2newItems (see below) accordingly.
undef2newItems[ 48 ].push_back( 22 );
undef2newItems[ 49 ].push_back( 22 );
undef2newItems[ 50 ].push_back( 22 );
+ undef2newItems[ 51 ].push_back( 8 );
ASSERT( undef2newItems.rbegin()->first == SMESH::FT_Undefined );
}
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
Description : Functor for calculating maximum length of 2D element
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()
{
case SMESH::FT_NodeConnectivityNumber:
aFunctor = aFilterMgr->CreateNodeConnectivityNumber();
break;
+ case SMESH::FT_ScaledJacobian:
+ aFunctor = aFilterMgr->CreateScaledJacobian();
+ break;
// Predicates
case FT_Skew : return "Skew";
case FT_Area : return "Area";
case FT_Volume3D : return "Volume3D";
+ case FT_ScaledJacobian : return "ScaledJacobian";
case FT_MaxElementLength2D : return "Max element length 2D";
case FT_MaxElementLength3D : return "Max element length 3D";
case FT_BelongToMeshGroup : return "Belong to Mesh Group";
else if ( theStr.equals( "Skew" ) ) return FT_Skew;
else if ( theStr.equals( "Area" ) ) return FT_Area;
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 3D" ) ) return FT_MaxElementLength3D;
else if ( theStr.equals( "Belong to Mesh Group" ) ) return FT_BelongToMeshGroup;
"FT_Skew",
"FT_Area",
"FT_Volume3D",
+ "FT_ScaledJacobian",
"FT_MaxElementLength2D",
"FT_MaxElementLength3D",
"FT_FreeBorders",
NodeConnectivityNumber_i();
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();
+ };
/*
Skew_ptr CreateSkew();
Area_ptr CreateArea();
Volume3D_ptr CreateVolume3D();
+ ScaledJacobian_ptr CreateScaledJacobian();
MaxElementLength2D_ptr CreateMaxElementLength2D();
MaxElementLength3D_ptr CreateMaxElementLength3D();
Length_ptr CreateLength();
case FT_Skew: myStream<< "aSkew"; break;
case FT_Area: myStream<< "aArea"; break;
case FT_Volume3D: myStream<< "aVolume3D"; break;
+ case FT_ScaledJacobian: myStream<< "aScaledJacobian"; break;
case FT_MaxElementLength2D: myStream<< "aMaxElementLength2D"; break;
case FT_MaxElementLength3D: myStream<< "aMaxElementLength3D"; break;
case FT_FreeBorders: myStream<< "aFreeBorders"; break;
functor = aFilterMgr.CreateNodeConnectivityNumber()
elif theCriterion == FT_BallDiameter:
functor = aFilterMgr.CreateBallDiameter()
+ elif theCriterion == FT_ScaledJacobian:
+ functor = aFilterMgr.CreateScaledJacobian()
else:
print("Error: given parameter is not numerical functor type.")
aFilterMgr.UnRegister()
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):
"""
Return minimal and maximal value of a given functor.
--- /dev/null
+# -*- 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 )
SMESH_box3_tetra.py
SMESH_box_tetra.py
SMESH_controls.py
+ SMESH_controls_scaled_jacobian.py
SMESH_fixation_netgen.py
SMESH_fixation_tetra.py
SMESH_flight_skin.py