mirror of
https://git.salome-platform.org/gitpub/modules/smesh.git
synced 2024-12-26 01:10:35 +05:00
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:
parent
e0552dbb7f
commit
9ac965c0e3
9
doc/examples/filters_ex40.py
Normal file
9
doc/examples/filters_ex40.py
Normal 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))
|
24
doc/examples/quality_controls_ex24.py
Normal file
24
doc/examples/quality_controls_ex24.py
Normal 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)
|
@ -73,6 +73,7 @@ SET(BAD_TESTS
|
||||
filters_ex36.py
|
||||
filters_ex37.py
|
||||
filters_ex38.py
|
||||
filters_ex40.py
|
||||
filters_node_nb_conn.py
|
||||
filters_belong2group.py
|
||||
generate_flat_elements.py
|
||||
@ -119,6 +120,7 @@ SET(BAD_TESTS
|
||||
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
|
||||
|
BIN
doc/gui/images/scaled_jacobian.png
Normal file
BIN
doc/gui/images/scaled_jacobian.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
BIN
doc/gui/images/scaled_jacobian_hexa.png
Normal file
BIN
doc/gui/images/scaled_jacobian_hexa.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
doc/gui/images/scaled_jacobian_mesh_tetra.png
Normal file
BIN
doc/gui/images/scaled_jacobian_mesh_tetra.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
doc/gui/images/scaled_jacobian_tetra.png
Normal file
BIN
doc/gui/images/scaled_jacobian_tetra.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
@ -48,6 +48,7 @@ Volume quality controls:
|
||||
* :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`
|
||||
@ -99,4 +100,5 @@ To manage the quality controls call pop-up in the VTK viewer and select "Control
|
||||
max_element_length_3d.rst
|
||||
bare_border_volumes.rst
|
||||
over_constrained_volumes.rst
|
||||
scalar_bar.rst
|
||||
scalar_bar.rst
|
||||
scaled_jacobian.rst
|
42
doc/gui/input/scaled_jacobian.rst
Normal file
42
doc/gui/input/scaled_jacobian.rst
Normal 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.
|
@ -61,6 +61,24 @@ filters 3D mesh elements (volumes) according to the aspect ratio value:
|
||||
|
||||
**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
|
||||
|
@ -240,3 +240,13 @@ Element Diameter 3D
|
||||
: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>`
|
||||
|
@ -47,7 +47,8 @@ module SMESH
|
||||
FT_Taper,
|
||||
FT_Skew,
|
||||
FT_Area,
|
||||
FT_Volume3D,
|
||||
FT_Volume3D,
|
||||
FT_ScaledJacobian,
|
||||
FT_MaxElementLength2D,
|
||||
FT_MaxElementLength3D,
|
||||
FT_FreeBorders,
|
||||
@ -170,6 +171,7 @@ module SMESH
|
||||
};
|
||||
interface BallDiameter : NumericalFunctor{};
|
||||
interface NodeConnectivityNumber : NumericalFunctor{};
|
||||
interface ScaledJacobian : NumericalFunctor{};
|
||||
|
||||
|
||||
/*!
|
||||
@ -598,6 +600,7 @@ module SMESH
|
||||
MultiConnection2D CreateMultiConnection2D();
|
||||
BallDiameter CreateBallDiameter();
|
||||
NodeConnectivityNumber CreateNodeConnectivityNumber();
|
||||
ScaledJacobian CreateScaledJacobian();
|
||||
/*!
|
||||
* Create logical functors ( predicates )
|
||||
*/
|
||||
|
BIN
resources/mesh_scaled_jacobian.png
Normal file
BIN
resources/mesh_scaled_jacobian.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
@ -2351,6 +2351,70 @@ SMDSAbs_ElementType NodeConnectivityNumber::GetType() const
|
||||
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
|
||||
*/
|
||||
|
@ -404,6 +404,17 @@ namespace SMESH{
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
|
@ -953,6 +953,14 @@ void SMESH_ActorDef::SetControlMode( eControl theMode, bool theCheckEntityMode )
|
||||
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();
|
||||
@ -1112,7 +1120,6 @@ void SMESH_ActorDef::SetControlMode( eControl theMode, bool theCheckEntityMode )
|
||||
QString aTitle = QString(myScalarBarActor->GetTitle());
|
||||
aTitle.replace(QRegExp("(:\\s).*"),"\\1"+ QString::number(GetNumberControlEntities()));
|
||||
myScalarBarActor->SetTitle(aTitle.toUtf8().constData());
|
||||
|
||||
}
|
||||
else {
|
||||
if(theCheckEntityMode){
|
||||
|
@ -139,7 +139,7 @@ class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor
|
||||
|
||||
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,
|
||||
|
@ -80,9 +80,17 @@ static int Tetra_RE [4][4] = { // REVERSED -> FORWARD (EXTERNAL)
|
||||
{ 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 },
|
||||
@ -363,13 +371,18 @@ struct XYZ {
|
||||
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);
|
||||
}
|
||||
@ -387,6 +400,13 @@ inline double XYZ::Magnitude() {
|
||||
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);
|
||||
}
|
||||
|
||||
//================================================================================
|
||||
/*!
|
||||
@ -694,7 +714,6 @@ static double getTetraVolume(const SMDS_MeshNode* n1,
|
||||
//function : GetSize
|
||||
//purpose : Return element volume
|
||||
//=======================================================================
|
||||
|
||||
double SMDS_VolumeTool::GetSize() const
|
||||
{
|
||||
double V = 0.;
|
||||
@ -847,6 +866,334 @@ double SMDS_VolumeTool::GetSize() const
|
||||
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 :
|
||||
|
@ -103,6 +103,9 @@ class SMDS_EXPORT SMDS_VolumeTool
|
||||
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;
|
||||
|
@ -1162,6 +1162,8 @@ namespace
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1778,6 +1780,7 @@ namespace
|
||||
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 );
|
||||
@ -3902,6 +3905,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
|
||||
case SMESHOp::OpEqualFace:
|
||||
case SMESHOp::OpAspectRatio3D:
|
||||
case SMESHOp::OpVolume:
|
||||
case SMESHOp::OpScaledJacobian:
|
||||
case SMESHOp::OpMaxElementLength3D:
|
||||
case SMESHOp::OpBareBorderVolume:
|
||||
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::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" );
|
||||
@ -4353,7 +4358,7 @@ void SMESHGUI::initialize( CAM_Application* app )
|
||||
<< 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++ )
|
||||
@ -4469,6 +4474,7 @@ void SMESHGUI::initialize( CAM_Application* app )
|
||||
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 );
|
||||
@ -4626,6 +4632,7 @@ void SMESHGUI::initialize( CAM_Application* app )
|
||||
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 );
|
||||
@ -5103,6 +5110,10 @@ void SMESHGUI::initialize( CAM_Application* app )
|
||||
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 );
|
||||
|
@ -1568,6 +1568,7 @@ void SMESHGUI_FilterTable::updateAdditionalWidget()
|
||||
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 ||
|
||||
@ -1816,6 +1817,7 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int /*col*/,
|
||||
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;
|
||||
|
||||
@ -2284,6 +2286,7 @@ const QMap<int, QString>& SMESHGUI_FilterTable::getCriteria (const int theType)
|
||||
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;
|
||||
}
|
||||
|
@ -1684,6 +1684,8 @@ QString SMESHGUI_ElemInfo::ctrl2str( int control )
|
||||
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:
|
||||
|
@ -122,6 +122,7 @@ namespace SMESHOp {
|
||||
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
|
||||
|
@ -371,6 +371,7 @@ QString SMESHGUI_Selection::controlMode( int ind ) const
|
||||
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;
|
||||
@ -429,6 +430,7 @@ bool SMESHGUI_Selection::isNumFunctor( int ind ) const
|
||||
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:
|
||||
|
@ -941,6 +941,9 @@ bool SMESH::SelectionProxy::elementControl( int id, int control, double precisio
|
||||
case SMESH::FT_BallDiameter:
|
||||
functor.reset( new SMESH::Controls::BallDiameter() );
|
||||
break;
|
||||
case SMESH::FT_ScaledJacobian:
|
||||
functor.reset( new SMESH::Controls::ScaledJacobian() );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1009,6 +1012,9 @@ bool SMESH::SelectionProxy::elementControl( int id, int control, double precisio
|
||||
case SMESH::FT_BallDiameter:
|
||||
functor = manager->CreateBallDiameter();
|
||||
break;
|
||||
case SMESH::FT_ScaledJacobian:
|
||||
functor = manager->CreateScaledJacobian();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -611,6 +611,10 @@
|
||||
<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>
|
||||
|
@ -95,6 +95,10 @@
|
||||
<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>
|
||||
@ -1316,6 +1320,10 @@
|
||||
<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>
|
||||
@ -3912,6 +3920,10 @@ Use Display Entity menu command to show them.
|
||||
<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>
|
||||
@ -4624,6 +4636,10 @@ Use Display Entity menu command to show them.
|
||||
<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>
|
||||
@ -6496,6 +6512,10 @@ Please enter correct value and try again</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>
|
||||
|
@ -99,6 +99,10 @@
|
||||
<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>
|
||||
@ -1316,6 +1320,10 @@
|
||||
<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>
|
||||
@ -3911,6 +3919,10 @@ Utilisez le menu "Visualiser une entité" pour les afficher.
|
||||
<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>
|
||||
@ -4623,6 +4635,10 @@ Utilisez le menu "Visualiser une entité" pour les afficher.
|
||||
<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>
|
||||
|
@ -71,6 +71,10 @@
|
||||
<source>NODE_CONNECTIVITY_NB</source>
|
||||
<translation>節点接続番号</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SCALED_JACOBIAN</source>
|
||||
<translation>スケーリングされたヤコビアン</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>FREE_EDGES</source>
|
||||
<translation>フリーエッジ</translation>
|
||||
@ -1119,6 +1123,10 @@
|
||||
<source>MEN_VOLUME_3D</source>
|
||||
<translation>ボリューム</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>MEN_SCALED_JACOBIAN</source>
|
||||
<translation>スケーリングされたヤコビアン</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>MEN_WARP</source>
|
||||
<translation>変形の角度</translation>
|
||||
@ -3519,6 +3527,10 @@
|
||||
<source>STB_VOLUMES</source>
|
||||
<translation>ボリューム</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>STB_SCALED_JACOBIAN</source>
|
||||
<translation>スケーリングされたヤコビアン</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>STB_VOLUME_3D</source>
|
||||
<translation>ボリューム</translation>
|
||||
@ -4183,6 +4195,10 @@
|
||||
<source>TOP_VOLUMES</source>
|
||||
<translation>ボリューム</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>TOP_SCALED_JACOBIAN</source>
|
||||
<translation>スケーリングされたヤコビアン</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>TOP_VOLUME_3D</source>
|
||||
<translation>ボリューム</translation>
|
||||
@ -5921,7 +5937,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>VOLUME_3D</source>
|
||||
<translation>ボリューム</translation>
|
||||
<translation>スケーリングされたヤコビアン</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARPING</source>
|
||||
|
@ -301,6 +301,8 @@ namespace {
|
||||
// - 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.
|
||||
@ -325,6 +327,7 @@ namespace {
|
||||
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 );
|
||||
}
|
||||
|
@ -460,6 +460,21 @@ namespace SMESH {
|
||||
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
|
||||
@ -2126,6 +2141,13 @@ namespace SMESH {
|
||||
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()
|
||||
{
|
||||
@ -3076,6 +3098,9 @@ namespace SMESH {
|
||||
case SMESH::FT_NodeConnectivityNumber:
|
||||
aFunctor = aFilterMgr->CreateNodeConnectivityNumber();
|
||||
break;
|
||||
case SMESH::FT_ScaledJacobian:
|
||||
aFunctor = aFilterMgr->CreateScaledJacobian();
|
||||
break;
|
||||
|
||||
// Predicates
|
||||
|
||||
@ -3512,6 +3537,7 @@ namespace SMESH {
|
||||
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";
|
||||
@ -3568,6 +3594,7 @@ namespace SMESH {
|
||||
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;
|
||||
@ -4141,6 +4168,7 @@ namespace SMESH {
|
||||
"FT_Skew",
|
||||
"FT_Area",
|
||||
"FT_Volume3D",
|
||||
"FT_ScaledJacobian",
|
||||
"FT_MaxElementLength2D",
|
||||
"FT_MaxElementLength3D",
|
||||
"FT_FreeBorders",
|
||||
|
@ -351,6 +351,18 @@ namespace SMESH
|
||||
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();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
@ -1113,6 +1125,7 @@ namespace SMESH
|
||||
Skew_ptr CreateSkew();
|
||||
Area_ptr CreateArea();
|
||||
Volume3D_ptr CreateVolume3D();
|
||||
ScaledJacobian_ptr CreateScaledJacobian();
|
||||
MaxElementLength2D_ptr CreateMaxElementLength2D();
|
||||
MaxElementLength3D_ptr CreateMaxElementLength3D();
|
||||
Length_ptr CreateLength();
|
||||
|
@ -414,6 +414,7 @@ namespace SMESH
|
||||
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;
|
||||
|
@ -1233,6 +1233,8 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
|
||||
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()
|
||||
@ -7469,6 +7471,19 @@ class Mesh(metaclass = MeshMeta):
|
||||
|
||||
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.
|
||||
|
144
test/SMESH_controls_scaled_jacobian.py
Normal file
144
test/SMESH_controls_scaled_jacobian.py
Normal 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 )
|
@ -44,6 +44,7 @@ SET(BAD_TESTS
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user