[bos #35147] [EDF] (2023-T1) Decompose Viscous Layer API.

Delete .vscode/settings.json

Publish shrinkGeometry.

Refactor StdMeshers_Cartesian_3D and StdMeshers_Cartesian_VL classes to allow passing an arbitrary shrink mesh to the viscous layer builder. Use StdMeshers_Cartesian_VL in StdMeshers_ViscousLayerBuilder to handle geometry shrinking and viscous layer building.

Create maps to link shrink solid and the solid assign to the shrink mesh. Code cleanup.

Defining map btw original shape (TopAbs_COMPOUND) and result shrink object. Refactor to support viscous layer of faces. Code clean up and add of tests.

Documentation and code cleanup

erase debug comment.

Modif after code review.

Avoid compilation warning from ViscousLayerBuilder and ViscousLayerBuilder_i classes.
This commit is contained in:
cconopoima 2023-07-25 16:15:25 -03:00
parent e3d582dca7
commit d3c3260cd9
19 changed files with 1551 additions and 130 deletions

View File

@ -0,0 +1,84 @@
# Viscous layers construction
import salome
salome.salome_init_without_session()
import SMESH
from salome.geom import geomBuilder
from salome.smesh import smeshBuilder
geom_builder = geomBuilder.New()
smesh_builder = smeshBuilder.New()
X = geom_builder.MakeVectorDXDYDZ( 1,0,0 )
O = geom_builder.MakeVertex( 100,50,50 )
plane = geom_builder.MakePlane( O, X, 200 ) # plane YZ
box = geom_builder.MakeBoxDXDYDZ(200,100,100)
shape = geom_builder.MakeHalfPartition( box, plane )
faces = geom_builder.SubShapeAllSorted(shape, geom_builder.ShapeType["FACE"])
face1 = faces[1]
# 4 left, 34 middle, 50 right
# Have to pass the middle face id, otherwise it is going to create two disjoint boxes
# because the common face is not going to be ignored and both boxes are going to shrink
# in this direction too
ignoreFaces = [4,34,50]
geom_builder.addToStudy( shape, "shape" )
geom_builder.addToStudyInFather( shape, face1, "face1")
# 3D Viscous layers
mesh = smesh_builder.Mesh(shape, "CFD")
ViscousBuilder = mesh.ViscousLayerBuilder()
thickness = 20
numberOfLayers = 10
stretchFactor = 1.5
groupName = "Boundary layers"
ViscousBuilder.setBuilderParameters( thickness, numberOfLayers, stretchFactor,
ignoreFaces, # optional
groupName = groupName ) # optional
Shrinkshape = ViscousBuilder.GetShrinkGeometry()
shrinkMesh = smesh_builder.Mesh(Shrinkshape, "Shrink")
shrinkMesh.Segment().NumberOfSegments( 4 )
faces = geom_builder.SubShapeAllSorted(Shrinkshape, geom_builder.ShapeType["FACE"])
shrinkFace1 = faces[1]
shrinkMesh.Triangle()
shrinkMesh.Quadrangle(shrinkFace1)
algo3D = shrinkMesh.Tetrahedron()
if not shrinkMesh.Compute(): raise Exception("Error when computing Mesh")
#Add viscous layer
FinalMesh = ViscousBuilder.AddLayers( shrinkMesh )
mesh.MakeGroup("Tetras",SMESH.VOLUME,SMESH.FT_ElemGeomType,"=",SMESH.Geom_TETRA)
mesh.MakeGroup("Pyras",SMESH.VOLUME,SMESH.FT_ElemGeomType,"=",SMESH.Geom_PYRAMID)
mesh.MakeGroup("Prims",SMESH.VOLUME,SMESH.FT_ElemGeomType,"=",SMESH.Geom_PENTA)
# 2D Viscous layers
# 3 edges of the 4 edges of face1
edgeIds = geom_builder.SubShapeAllIDs( face1, geom_builder.ShapeType["EDGE"])[:-1]
mesh = smesh_builder.Mesh(face1,"Face1")
ViscousBuilder = mesh.ViscousLayerBuilder()
ViscousBuilder.setBuilderParameters( 2, 3, 1.5,
edgeIds, True, # optional
groupName = groupName ) # optional
#For 2D, edges are not selectable (to be developed in occt) the entire face is shrink
shrinkFace = ViscousBuilder.GetShrinkGeometry()
shrinkMesh = smesh_builder.Mesh(shrinkFace, "VicsousLayers2D")
shrinkMesh.Segment().NumberOfSegments( 5 )
algo2D = shrinkMesh.Triangle()
if not shrinkMesh.Compute(): raise Exception("Error when computing Mesh of shrink face")
FinalMeshFace = ViscousBuilder.AddLayers( shrinkMesh )

View File

@ -37,6 +37,7 @@ SET(BAD_TESTS
defining_hypotheses_ex10.py
defining_hypotheses_ex11.py
defining_hypotheses_ex17.py
defining_hypotheses_vlapi_ex17.py
defining_hypotheses_adaptive1d.py
filters_ex01.py
filters_ex02.py

View File

@ -136,6 +136,27 @@ computations.
**See also** a sample TUI script of a :ref:`tui_viscous_layers`.
.. _viscous_layers_api_anchor:
Viscous Layers API
####################################
The Viscous layer API is available on TUI. Allows to compute a shrink version of the geometry. This shrank version can be passed to any mesher and be used to
build the viscous layer from the mesh computed in the shrank geometry. The current implementation only support the **Face offset** method to extrude the
nodes from the shrank mesh to the original geometry.
This implementation supports 3D (Solids and Solid Compound) and 2D (Face) geometries. For the 3D case, the faces Ids are
used to identify the faces (perpendicular to it) where the solid is to be reduced. For the 2D case, the edges Ids can be provided but will not have any effect
on the geometry computation (this control is not available in the opencascade library), therefore, for this case the entire face is shrank.
The Viscous Layer API receive the same parameters as the Viscous Layers Hypothesis and implements four methods:
* The constructor ``ViscousLayerBuilder()``
* The parameters definitions ``setBuilderParameters(...)``
* The ``GetShrinkGeometry()`` method that returns the shrink version of the original geomtry.
* The ``AddLayers( shrinkMesh )`` method that returns the complet version of the mesh (shrink+viscous layer)
**See also** a sample TUI script of a :ref:`tui_viscous_layers_api`.
.. _quadratic_mesh_anchor:

View File

@ -251,6 +251,16 @@ Viscous layers construction
:download:`Download this script <../../examples/defining_hypotheses_ex17.py>`
.. _tui_viscous_layers_api:
Viscous layers API construction
###########################
.. literalinclude:: ../../examples/defining_hypotheses_vlapi_ex17.py
:language: python
:download:`Download this script <../../examples/defining_hypotheses_vlapi_ex17.py>`
.. _tui_radial_prism:
Radial Prism example

View File

@ -26,10 +26,11 @@
#ifndef _SMESH_BASICHYPOTHESIS_IDL_
#define _SMESH_BASICHYPOTHESIS_IDL_
#include "GEOM_Gen.idl"
#include "SALOME_Exception.idl"
#include "SMESH_Hypothesis.idl"
#include "SMESH_Mesh.idl"
/*!
* StdMeshers: interfaces to standard hypotheses and algorithms
*/
@ -1247,6 +1248,39 @@ module StdMeshers
interface StdMeshers_Cartesian_3D : SMESH::SMESH_3D_Algo
{
};
/*!
* StdMeshers_Cartesian_3D: interface of "ViscousLayerBuilder" algorithm
*/
interface StdMeshers_ViscousLayerBuilder : SMESH::SMESH_2D_Algo
{
/*!
* Set faces to exclude from the definition of face to shrink
*/
void SetIgnoreFaces(in SMESH::long_array faceIDs) raises (SALOME::SALOME_Exception);
// SMESH::long_array GetIgnoreFaces();
/*!
* Set faces either to exclude from treatment or to make the offset geometry on.
*/
void SetFaces(in SMESH::long_array faceIDs,
in boolean toIgnore) raises (SALOME::SALOME_Exception);
// SMESH::long_array GetFaces();
// boolean GetIsToIgnoreFaces();
void SetTotalThickness(in double thickness) raises (SALOME::SALOME_Exception);
void SetNumberLayers(in short numberOfLayers ) raises (SALOME::SALOME_Exception);
void SetStretchFactor(in double strechFactor ) raises (SALOME::SALOME_Exception);
void SetMethod( in VLExtrusionMethod how );
void SetGroupName(in string name);
GEOM::GEOM_Object GetShrinkGeometry( in SMESH::SMESH_Mesh finalMesh, in GEOM::GEOM_Object theObject );
/*!
* Build the prismatic layer from the shrink mesh
*/
boolean AddLayers( in SMESH::SMESH_Mesh sourceMesh, in SMESH::SMESH_Mesh finalMesh, in GEOM::GEOM_Object theObject );
};
};

View File

@ -25,6 +25,7 @@ LIBRARY = "libStdMeshersEngine.so"
from salome.smesh.smesh_algorithm import Mesh_Algorithm
import StdMeshers
from salome.geom import geomBuilder
#----------------------------
# Mesh algo type identifiers
@ -2013,3 +2014,106 @@ class StdMeshersBuilder_UseExisting_2D(Mesh_Algorithm):
pass
pass # end of StdMeshersBuilder_UseExisting_2D class
class StdMeshersBuilder_ViscousLayer(Mesh_Algorithm):
""" Defines the prismatic layer builder.
It is created by calling smeshBuilder.Mesh.ViscousLayerBuilder(geom=TheGeometry)
"""
meshMethod = "ViscousLayerBuilder"
"""
name of the dynamic method in smeshBuilder.Mesh class
"""
algoType = "ViscousLayerBuilder"
"""
type of algorithm used with helper function in smeshBuilder.Mesh class
"""
docHelper = "Viscous layer builder for 2D and 3D geometries"
"""
doc string of the method
"""
# On create method it will call create method from mesh python class
#
def __init__(self, mesh, geom = 0 ):
"""
Private constructor.
Parameters:
mesh: parent mesh object algorithm is assigned to
geom: geometry (shape/sub-shape) algorithm is assigned to;
if it is :code:`0` (default), the algorithm is assigned to the main shape
"""
self.thickness = None
self.numberOfLayers = None
self.stretchFactor = None
self.elementsId = []
self.isElementToIgnore = True
self.extrMethod = StdMeshers.SURF_OFFSET_SMOOTH
self.groupName = ""
self.shrinkGeometry = None
self.algo = self.Create(mesh, geom, self.algoType)
pass
def setBuilderParameters( self, thickness, numberOfLayers, stretchFactor, elementsId=[],
isElementToIgnore=True, extrMethod=StdMeshers.SURF_OFFSET_SMOOTH, groupName="" ):
self.thickness = thickness
self.numberOfLayers = numberOfLayers
self.stretchFactor = stretchFactor
self.elementsId = elementsId # can be faces or edges
self.isElementToIgnore = isElementToIgnore
self.extrMethod = extrMethod
self.groupName = groupName
self.algo.SetTotalThickness( thickness )
self.algo.SetNumberLayers( numberOfLayers )
self.algo.SetStretchFactor( stretchFactor )
#Faces are set based on int ids so if a collection of face geom objects is recived cast it to int
if elementsId and isinstance( elementsId, geomBuilder.GEOM._objref_GEOM_Object ):
elementsId = [ elementsId ]
if elementsId and isinstance( elementsId[0], geomBuilder.GEOM._objref_GEOM_Object ):
elementsIDs = []
for shape in elementsId:
try:
ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] )
if ( len( ff ) == 0 ):
#try to get edges
ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"] )
for f in ff:
elementsIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f))
except:
# try to get the SHAPERSTUDY engine directly, because GetGen does not work because of
# simplification of access in geomBuilder: omniORB.registerObjref
from SHAPERSTUDY_utils import getEngine
gen = getEngine()
if gen:
aShapeOp = gen.GetIShapesOperations()
ff = aShapeOp.ExtractSubShapes( shape, self.mesh.geompyD.ShapeType["FACE"], False)
if (len(ff)==0):
#try to get edges
ff = aShapeOp.ExtractSubShapes( shape, self.mesh.geompyD.ShapeType["EDGE"], False)
for f in ff:
elementsIDs.append( aShapeOp.GetSubShapeIndex( self.mesh.geom, f ))
elementsId = elementsIDs
self.algo.SetFaces( elementsId, isElementToIgnore )
self.algo.SetGroupName( groupName )
self.algo.SetMethod( extrMethod )
def GetShrinkGeometry( self ):
if isinstance(self.geom, geomBuilder.GEOM._objref_GEOM_Object):
self.shrinkGeometry = self.algo.GetShrinkGeometry( self.mesh.GetMesh(), self.geom )
return self.shrinkGeometry
def AddLayers( self, shrinkMesh ):
success = self.algo.AddLayers( shrinkMesh.GetMesh(), self.mesh.GetMesh(), self.geom )
if ( success ):
return self.mesh #Return the original mesh of the builder
else:
return shrinkMesh
pass # end of StdMeshersBuilder_ViscousLayer class

View File

@ -125,6 +125,7 @@ SET(StdMeshers_HEADERS
StdMeshers_PolygonPerFace_2D.hxx
StdMeshers_PolyhedronPerSolid_3D.hxx
StdMeshers_BlockRenumber.hxx
StdMeshers_ViscousLayerBuilder.hxx
)
# --- sources ---
@ -190,6 +191,7 @@ SET(StdMeshers_SOURCES
StdMeshers_PolygonPerFace_2D.cxx
StdMeshers_PolyhedronPerSolid_3D.cxx
StdMeshers_BlockRenumber.cxx
StdMeshers_ViscousLayerBuilder.cxx
)
# --- rules ---

View File

@ -182,6 +182,17 @@ bool StdMeshers_Cartesian_3D::CheckHypothesis (SMESH_Mesh& aMesh,
namespace
{
/*!
* \brief Temporary mesh to hold
*/
struct TmpMesh: public SMESH_Mesh
{
TmpMesh() {
_isShapeToMesh = (_id = 0);
_meshDS = new SMESHDS_Mesh( _id, true );
}
};
typedef int TGeomID; // IDs of sub-shapes
typedef TopTools_ShapeMapHasher TShapeHasher; // non-oriented shape hasher
typedef std::array< int, 3 > TIJK;
@ -6406,13 +6417,15 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh,
if ( offsetShape.IsNull() )
throw SALOME_Exception( error );
SMESH_Mesh* offsetMesh = builder.MakeOffsetMesh();
SMESH_Mesh* offsetMesh = new TmpMesh();
offsetMesh->ShapeToMesh( offsetShape );
offsetMesh->GetSubMesh( offsetShape )->DependsOn();
this->_isComputeOffset = true;
if ( ! this->Compute( *offsetMesh, offsetShape ))
return false;
return builder.MakeViscousLayers( theMesh, theShape );
return builder.MakeViscousLayers( *offsetMesh, theMesh, theShape );
}
// The algorithm generates the mesh in following steps:

View File

@ -30,6 +30,7 @@
#include <SMESHDS_Mesh.hxx>
#include <SMESHDS_SubMesh.hxx>
#include <SMESH_Algo.hxx>
#include <SMESH_MeshAlgos.hxx>
#include <SMESH_Mesh.hxx>
#include <SMESH_MeshEditor.hxx>
#include <SMESH_MesherHelper.hxx>
@ -37,9 +38,12 @@
#include <SMESH_subMesh.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepTopAdaptor_FClass2d.hxx>
#include <BRep_Builder.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepGProp.hxx>
#include <BRepTopAdaptor_FClass2d.hxx>
#include <BRep_Tool.hxx>
#include <GProp_GProps.hxx>
#include <ShapeAnalysis_Curve.hxx>
#include <ShapeAnalysis_Surface.hxx>
#include <TopExp.hxx>
@ -138,6 +142,7 @@ namespace
SMESHDS_SubMesh* sm = theOffsetMDS->MeshElements( theEOS._offsetShape );
if ( !sm || sm->NbElements() == 0 || sm->NbNodes() == 0 )
return;
theEOS._edges.resize( sm->NbNodes() );
const TopoDS_Face& initFace = TopoDS::Face( theEOS._initShape );
@ -189,13 +194,17 @@ namespace
void projectToEdge( VLEdgesOnShape & theEOS,
SMESHDS_Mesh* theOffsetMDS,
TNode2VLEdge & theN2E )
TNode2VLEdge & theN2E,
bool createVertex )
{
SMESHDS_SubMesh* sm = theOffsetMDS->MeshElements( theEOS._offsetShape );
if ( !sm || sm->NbElements() == 0 )
return;
theEOS._edges.resize( sm->NbNodes() );
int addVertexNode = createVertex ? 1 : 0;
theEOS._edges.resize( sm->NbNodes() + addVertexNode ); // +1 to set the vertex
ShapeAnalysis_Curve projector;
BRepAdaptor_Curve initCurve( TopoDS::Edge( theEOS._initShape ));
const double tol = Precision::Confusion();
@ -227,8 +236,39 @@ namespace
theN2E.Bind( offP.Node(), &vlEdge );
}
if ( createVertex )
{
// It is possible to define the vertex projections from the existing edges
// EOS._offsetShape the edge generated from the original edge
// Get the first vertex of both edges to define the connecting edges
auto offsetEdge = TopoDS::Edge( theEOS._offsetShape );
auto initEdge = TopoDS::Edge( theEOS._initShape );
TopoDS_Vertex offsetVertex;
TopoDS_Vertex initVertex;
if ( offsetEdge.Orientation() == TopAbs_FORWARD )
{
offsetVertex = TopExp::FirstVertex ( offsetEdge );
initVertex = TopExp::FirstVertex ( initEdge );
}
else
{
offsetVertex = TopExp::LastVertex ( offsetEdge );
initVertex = TopExp::LastVertex ( initEdge );
}
VLEdge & vlEdge = theEOS._edges[ iN ];
vlEdge._nodes.resize( 2 );
vlEdge._nodes[0] = SMESH_Algo::VertexNode( offsetVertex, theOffsetMDS );
gp_Pnt offP = BRep_Tool::Pnt( initVertex );
vlEdge._nodes[1] = theOffsetMDS->AddNode( offP.X(), offP.Y(), offP.Z() );
theN2E.Bind( vlEdge._nodes[0].Node(), &vlEdge );
}
return;
}
}
//================================================================================
/*!
@ -445,13 +485,12 @@ namespace
prism2polyhedron( vNodes, volumElem );
if ( const SMDS_MeshElement* vol = editor.AddElement( vNodes, volumElem ))
vol->setIsMarked( true ); // to add to group
vol->setIsMarked( true ); // to add to group
}
}
else // at inlet/outlet
{
makePolyhedron( edgesVec, vNodes, editor, volumElem );
}
editor.ClearLastCreated();
// move the face to the top of prisms, on mesh boundary
@ -467,6 +506,7 @@ namespace
* \param [inout] theMesh - offset mesh to fill in
* \param [inout] theN2E - map of node to VLEdge
* \param [inout] theFaceID - ID of WOVL FACE for new faces to set on
* \param [in] isMainShape2D - used to identify the geometry where the new elements are included
* \return bool - ok
*/
//================================================================================
@ -474,7 +514,8 @@ namespace
bool makeFaces( VLEdgesOnShape & theEOS,
SMESH_Mesh* theMesh,
TNode2VLEdge & theN2E,
const TGeomID theFaceID)
const TGeomID theFaceID,
bool isMainShape2D = false )
{
SMESHDS_SubMesh* sm = theMesh->GetMeshDS()->MeshElements( theEOS._offsetShape );
if ( !sm || sm->NbElements() == 0 )
@ -486,6 +527,27 @@ namespace
std::vector< const SMDS_MeshNode* > fNodes( 4 );
std::vector<const SMDS_MeshElement *> foundVolum;
std::vector< VLEdge*> edgesVec;
TIDSortedElemSet refSetFace;
// Check orientation of face and re
gp_XYZ refNormalVector(0.0,0.0,0.0);
if ( isMainShape2D )
{
SMESHDS_Mesh* offsetMDS = theMesh->GetMeshDS();
for ( SMDS_ElemIteratorPtr eIt = offsetMDS->elementsIterator(); eIt->more(); )
{
const SMDS_MeshElement* refFace = eIt->next(); // define the ref
if ( refFace->GetType() == SMDSAbs_Face )
{
SMESH_MeshAlgos::FaceNormal( refFace, refNormalVector, /*normalized=*/true );
break;
}
}
if ( refNormalVector.X() == 0.0 && refNormalVector.Y() == 0.0 && refNormalVector.Z() == 0.0 )
throw SALOME_Exception("No 2D element found in the mesh!\n");
}
for ( SMDS_ElemIteratorPtr eIt = sm->GetElements(); eIt->more(); )
{
const SMDS_MeshElement* edge = eIt->next();
@ -503,6 +565,7 @@ namespace
edgesVec[ i ] = theN2E( n );
}
size_t nbFaces = edgesVec[0]->_nodes.size() - 1;
for ( size_t iF = 0; iF < nbFaces; ++iF )
{
fNodes[ 0 ] = edgesVec[ 0 ]->_nodes[ iF ].Node();
@ -519,13 +582,20 @@ namespace
TIDSortedElemSet faces = { face }, volumes = { foundVolum[0] };
editor.Reorient2DBy3D( faces, volumes, /*outside=*/true );
}
else if ( isMainShape2D )
{
gp_XYZ elementNormal;
SMESH_MeshAlgos::FaceNormal( face, elementNormal, /*normalized=*/true );
if ( elementNormal * refNormalVector < 0.0 /* diff orientation from the ref element */)
editor.Reorient( face );
}
}
}
editor.ClearLastCreated();
// move the face to the top of prisms, on mesh boundary
//theMesh->GetMeshDS()->ChangeElementNodes( face, fNodes.data(), nbNodes );
}
}
return true;
}
@ -790,11 +860,16 @@ StdMeshers_Cartesian_VL::ViscousBuilder::ViscousBuilder( const StdMeshers_Viscou
{
const TopoDS_Shape& face = faces( i );
TGeomID fID = iniMDS->ShapeToIndex( face );
if ( _shapesWVL.count( fID ))
bool isMainShape2D = (mainShape.ShapeType() == TopAbs_FACE) ? true : false;
if ( _shapesWVL.count( fID ) && !isMainShape2D )
continue;
for ( TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next() )
_edge2facesWOVL[ iniMDS->ShapeToIndex( exp.Current() )].push_back( fID );
}
// When 2D meshing Need to add edges where segments need to be added due to geometry shrink
return;
}
@ -806,7 +881,96 @@ StdMeshers_Cartesian_VL::ViscousBuilder::ViscousBuilder( const StdMeshers_Viscou
StdMeshers_Cartesian_VL::ViscousBuilder::~ViscousBuilder()
{
delete _offsetMesh; _offsetMesh = 0;
delete _offsetMesh; //_offsetMesh = 0;
}
//================================================================================
/*!
* \brief Create an offset solid from a given one
* \param [in] theShape - input shape can be a solid, solidcompound or a compound with solids
* \param [in] theMesh - main mesh
* \param [out] theError - error description
* \return TopoDS_Shape - result offset shape of the same type as the received shape
*/
//================================================================================
TopoDS_Shape StdMeshers_Cartesian_VL::ViscousBuilder::MakeOffsetSolid(const TopoDS_Shape & theShape,
SMESH_Mesh & theMesh,
std::string & theError )
{
double offset = -_hyp->GetTotalThickness();
double tol = Precision::Confusion();
TopAbs_ShapeEnum typeOfShape = theShape.ShapeType();
TopTools_IndexedMapOfShape shapeList;
TopExp::MapShapes( theShape, TopAbs_SOLID, shapeList );
std::vector<TopoDS_Shape> shrinkBodies;
for ( int i = 1; i <= shapeList.Size(); ++i )
{
auto solid = shapeList( i );
// If Shape is solid call direct
BRepOffset_MakeOffset * makeOffset = new BRepOffset_MakeOffset();
makeOffset->Initialize( solid, offset, tol, BRepOffset_Skin, /*Intersection=*/false,
/*selfInter=*/false, GeomAbs_Intersection);
// exclude inlet FACEs
SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
for ( TopExp_Explorer fEx( theShape, TopAbs_FACE ); fEx.More(); fEx.Next() )
{
TGeomID fID = meshDS->ShapeToIndex( fEx.Current() );
if ( !_shapesWVL.count( fID ))
makeOffset->SetOffsetOnFace( TopoDS::Face( fEx.Current()), 0 );
}
makeOffset->MakeOffsetShape();
if ( makeOffset->IsDone() )
{
shrinkBodies.push_back( makeOffset->Shape() );
_makeOffsetCollection.push_back( makeOffset );
}
else
{
switch ( makeOffset->Error() )
{
case BRepOffset_NoError:
theError = "OK. Offset performed successfully.";break;
case BRepOffset_BadNormalsOnGeometry:
theError = "Degenerated normal on input data.";break;
case BRepOffset_C0Geometry:
theError = "C0 continuity of input data.";break;
case BRepOffset_NullOffset:
theError = "Null offset of all faces.";break;
case BRepOffset_NotConnectedShell:
theError = "Incorrect set of faces to remove, the remaining shell is not connected.";break;
case BRepOffset_CannotTrimEdges:
theError = "Can not trim edges.";break;
case BRepOffset_CannotFuseVertices:
theError = "Can not fuse vertices.";break;
case BRepOffset_CannotExtentEdge:
theError = "Can not extent edge.";break;
default:
theError = "operation not done.";
}
theError = "BRepOffset_MakeOffset error: " + theError;
return TopoDS_Shape();
}
}
if ( typeOfShape == TopAbs_COMPOUND || typeOfShape == TopAbs_COMPSOLID )
{
_solidCompound.SetGlue( BOPAlgo_GlueFull );
_solidCompound.SetToFillHistory( true );
for ( auto solid : shrinkBodies )
_solidCompound.AddArgument( solid );
_solidCompound.Perform();
return _solidCompound.Shape();
}
else
return shrinkBodies[ 0 ]; // return one solid
}
//================================================================================
@ -824,91 +988,155 @@ StdMeshers_Cartesian_VL::ViscousBuilder::MakeOffsetShape(const TopoDS_Shape & th
SMESH_Mesh & theMesh,
std::string & theError )
{
double offset = -_hyp->GetTotalThickness();
double tol = Precision::Confusion();
_makeOffset.Initialize( theShape, offset, tol, BRepOffset_Skin, /*Intersection=*/false,
/*selfInter=*/false, GeomAbs_Intersection );
// exclude inlet FACEs
SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
for ( TopExp_Explorer fEx( theShape, TopAbs_FACE ); fEx.More(); fEx.Next() )
{
TGeomID fID = meshDS->ShapeToIndex( fEx.Current() );
if ( !_shapesWVL.count( fID ))
_makeOffset.SetOffsetOnFace( TopoDS::Face( fEx.Current()), 0 );
}
double offset = -_hyp->GetTotalThickness();
double tol = Precision::Confusion();
TopAbs_ShapeEnum typeOfShape = theShape.ShapeType();
_makeOffset.MakeOffsetShape();
if ( _makeOffset.IsDone() )
// Switch here for the treatment of faces
if ( typeOfShape == TopAbs_FACE )
{
_offsetShape = _makeOffset.Shape();
SMESH_MesherHelper::WriteShape( _offsetShape );////
TopoDS_Face face = TopoDS::Face( theShape );
GProp_GProps gprops;
BRepGProp::SurfaceProperties(face, gprops); // Stores results in gprops
double faceArea = gprops.Mass();
_offsetMesh->ShapeToMesh( _offsetShape );
_offsetMesh->GetSubMesh( _offsetShape )->DependsOn();
_makeFaceOffset = BRepOffsetAPI_MakeOffset( face, GeomAbs_Intersection );
_makeFaceOffset.Perform( offset );
TopoDS_Wire wireFrame = TopoDS::Wire( _makeFaceOffset.Shape() );
TopoDS_Face shrinkFace = TopoDS::Face( BRepBuilderAPI_MakeFace( wireFrame, false ) );
BRepGProp::SurfaceProperties(shrinkFace, gprops); // Stores results in gprops
double sArea = gprops.Mass();
if ( sArea > faceArea /*recompute the shrink face because offset was done in the contrary direction as expected*/)
{
_makeFaceOffset.Perform( -offset );
wireFrame = TopoDS::Wire( _makeFaceOffset.Shape() );
shrinkFace = TopoDS::Face( BRepBuilderAPI_MakeFace( wireFrame, false ) );
}
_offsetShape = shrinkFace;
return _offsetShape;
}
switch ( _makeOffset.Error() )
else
{
case BRepOffset_NoError:
theError = "OK. Offset performed successfully.";break;
case BRepOffset_BadNormalsOnGeometry:
theError = "Degenerated normal on input data.";break;
case BRepOffset_C0Geometry:
theError = "C0 continuity of input data.";break;
case BRepOffset_NullOffset:
theError = "Null offset of all faces.";break;
case BRepOffset_NotConnectedShell:
theError = "Incorrect set of faces to remove, the remaining shell is not connected.";break;
case BRepOffset_CannotTrimEdges:
theError = "Can not trim edges.";break;
case BRepOffset_CannotFuseVertices:
theError = "Can not fuse vertices.";break;
case BRepOffset_CannotExtentEdge:
theError = "Can not extent edge.";break;
default:
theError = "operation not done.";
}
theError = "BRepOffset_MakeOffset error: " + theError;
return TopoDS_Shape();
_offsetShape = MakeOffsetSolid( theShape, theMesh, theError );
return _offsetShape;
}
}
//================================================================================
/*!
* \brief Return a sub-shape of the offset shape generated from a given initial sub-shape
* \brief Return the list of sub-shape of the same type of the offset shape generated from a given initial sub-shape
*/
//================================================================================
TopoDS_Shape StdMeshers_Cartesian_VL::ViscousBuilder::getOffsetSubShape( const TopoDS_Shape& S )
void StdMeshers_Cartesian_VL::ViscousBuilder::getOffsetSubShape( const TopoDS_Shape& S, std::vector<TopoDS_Shape>& subShapeList )
{
for( auto offset : _makeOffsetCollection )
{
const TopTools_ListOfShape& newShapes = offset->Generated( S );
if ( newShapes.Size() == 0 )
continue; // keep searching
for ( const TopoDS_Shape& ns : newShapes )
{
if ( ns.ShapeType() == S.ShapeType() )
{
if ( _solidCompound.Arguments().Size() == 0 /* only one solid shrank*/ )
{
subShapeList.push_back( ns );
}
else
{
// In boolean operations the shapes are modified or deleted
const TopTools_ListOfShape& newGlueShapes = _solidCompound.Modified( ns );
for ( TopoDS_Shape& ngs : newGlueShapes )
if ( ngs.ShapeType() == ns.ShapeType() /*&& !ngs.Checked()*/ )
subShapeList.push_back( ngs );
if ( newGlueShapes.Size() == 0 && !_solidCompound.IsDeleted( ns ) )
subShapeList.push_back( ns );
}
}
}
}
// check for _makeFaceOffset in face shrink
if ( _makeOffsetCollection.size() == 0 )
{
const TopTools_ListOfShape& newShapes = _makeFaceOffset.Generated( S );
for ( const TopoDS_Shape& ns : newShapes )
{
if ( ns.ShapeType() == S.ShapeType() )
return subShapeList.push_back( ns );
}
}
}
bool StdMeshers_Cartesian_VL::ViscousBuilder::CheckGeometryMaps( SMESH_Mesh & offsetMesh,
const TopoDS_Shape & theShape )
{
const TopTools_ListOfShape& newShapes = _makeOffset.Generated( S );
for ( const TopoDS_Shape& ns : newShapes )
if ( ns.ShapeType() == S.ShapeType() )
return ns;
return TopoDS_Shape();
SMESHDS_Mesh* offsetMDS = offsetMesh.GetMeshDS();
TopoDS_Shape shrinkGeomToMesh = offsetMDS->ShapeToMesh();
TopTools_IndexedMapOfShape shrinkGeomMap;
TopExp::MapShapes( shrinkGeomToMesh, shrinkGeomMap );
TopTools_IndexedMapOfShape offsetGeomMap;
TopExp::MapShapes( _offsetShape, offsetGeomMap );
// loop on sub-shapes to project nodes from offset boundary to initial boundary
TopAbs_ShapeEnum types[3] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE };
for ( TopAbs_ShapeEnum shType : types )
{
TopTools_IndexedMapOfShape shapes;
TopExp::MapShapes( theShape, shType, shapes );
for ( int i = 1; i <= shapes.Size(); ++i )
{
// For each type of geometry check the existence of one or more equivalents
std::vector<TopoDS_Shape> listOfShapes;
getOffsetSubShape( shapes(i), listOfShapes );
if ( listOfShapes.size() == 0 ) return false;
}
}
return true;
}
//================================================================================
/*!
* \brief Create prismatic mesh between _offsetShape and theShape
* \remark Build the viscous layer from the iteration of shrink geometry
* \param [out] theMesh - mesh to fill in
* \param [in] theShape - initial shape
* \return bool - is Ok
*/
//================================================================================
bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh & theMesh,
bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh & offsetMesh,
SMESH_Mesh & theMesh,
const TopoDS_Shape & theShape )
{
SMESHDS_Mesh* offsetMDS = _offsetMesh->GetMeshDS();
SMESHDS_Mesh* initMDS = theMesh.GetMeshDS();
SMESHDS_Mesh* offsetMDS = offsetMesh.GetMeshDS();
SMESHDS_Mesh* initMDS = theMesh.GetMeshDS();
TopoDS_Shape shrinkGeomToMesh = offsetMDS->ShapeToMesh();
bool isMainShape2D = (theShape.ShapeType() == TopAbs_FACE) ? true : false;
// Validate map of shrink+joint geometry elements
if ( !CheckGeometryMaps(offsetMesh, theShape ) && !isMainShape2D )
throw SALOME_Exception("All elements from the shrink geometry were not match to the original geometry\n");
initMDS->ClearMesh(); // avoid mesh superposition on multiple calls of addLayers
offsetMDS->SetAllCellsNotMarked();
TopTools_IndexedMapOfShape shrinkGeomMap;
TopExp::MapShapes( shrinkGeomToMesh, shrinkGeomMap );
TopTools_IndexedMapOfShape offsetGeomMap;
TopExp::MapShapes( _offsetShape, offsetGeomMap );
// Compute heights of viscous layers
std::vector< double > vlH;
computeVLHeight( _hyp, vlH );
std::vector< VLEdgesOnShape > edgesOnShape;
edgesOnShape.reserve( offsetMDS->MaxShapeIndex() + 1 );
TNode2VLEdge n2e;
@ -923,55 +1151,64 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
{
edgesOnShape.resize( edgesOnShape.size() + 1 );
VLEdgesOnShape& EOS = edgesOnShape.back();
std::vector<TopoDS_Shape> listOfShapes;
EOS._initShape = shapes( i );
EOS._offsetShape = getOffsetSubShape( EOS._initShape );
EOS._initShapeID = initMDS->ShapeToIndex( EOS._initShape );
EOS._hasVL = _shapesWVL.count( EOS._initShapeID );
EOS._toCheckCoinc = false;
if ( !EOS._hasVL )
continue;
// Get a list of subShapes of the same type generated from the same face
// It is the case with split objects.
getOffsetSubShape( EOS._initShape, listOfShapes );
for ( TopoDS_Shape& shrinkShape : listOfShapes )
{
int shapeId = offsetGeomMap.FindIndex( shrinkShape );
EOS._offsetShape = shrinkGeomMap.FindKey( shapeId );
EOS._initShapeID = initMDS->ShapeToIndex( EOS._initShape );
EOS._hasVL = _shapesWVL.count( EOS._initShapeID );
// project boundary nodes of offset mesh to boundary of init mesh
// (new nodes are created in the offset mesh)
switch( EOS._offsetShape.ShapeType() ) {
case TopAbs_VERTEX:
{
EOS._edges.resize( 1 );
EOS._edges[0]._nodes.resize( 2 );
EOS._edges[0]._nodes[0] = SMESH_Algo::VertexNode( TopoDS::Vertex( EOS._offsetShape ),
offsetMDS );
gp_Pnt offP = BRep_Tool::Pnt( TopoDS::Vertex( EOS._initShape ));
EOS._edges[0]._nodes[1] = offsetMDS->AddNode( offP.X(), offP.Y(), offP.Z() );
//EOS._edges[0]._length = offP.Distance( EOS._edges[0]._nodes[0] );
n2e.Bind( EOS._edges[0]._nodes[0].Node(), & EOS._edges[0] );
break;
}
case TopAbs_EDGE:
{
projectToEdge( EOS, offsetMDS, n2e );
break;
}
case TopAbs_FACE:
{
projectToFace( EOS, offsetMDS, n2e );
break;
}
default:;
}
EOS._toCheckCoinc = false;
if ( !EOS._hasVL )
continue;
// create nodes of layers
if ( _hyp->GetNumberLayers() > 1 )
{
//if ( _shapesWVL.count( EOS._initShapeID ))
for ( size_t i = 0; i < EOS._edges.size(); ++i )
// project boundary nodes of offset mesh to boundary of init mesh
// (new nodes are created in the offset mesh)
switch( EOS._offsetShape.ShapeType() ) {
case TopAbs_VERTEX:
{
divideVLEdge( &EOS._edges[ i ], vlH, offsetMDS );
EOS._edges.resize( 1 );
EOS._edges[0]._nodes.resize( 2 );
EOS._edges[0]._nodes[0] = SMESH_Algo::VertexNode( TopoDS::Vertex( EOS._offsetShape ),
offsetMDS );
gp_Pnt offP = BRep_Tool::Pnt( TopoDS::Vertex( EOS._initShape ));
EOS._edges[0]._nodes[1] = offsetMDS->AddNode( offP.X(), offP.Y(), offP.Z() );
//EOS._edges[0]._length = offP.Distance( EOS._edges[0]._nodes[0] );
n2e.Bind( EOS._edges[0]._nodes[0].Node(), & EOS._edges[0] );
break;
}
case TopAbs_EDGE:
{
projectToEdge( EOS, offsetMDS, n2e, isMainShape2D /* add vertex from edges*/ );
break;
}
case TopAbs_FACE:
{
projectToFace( EOS, offsetMDS, n2e );
break;
}
default:;
}
}
} // loop on shapes
} // loop on shape types
// create nodes of layers
if ( _hyp->GetNumberLayers() > 1 )
{
//if ( _shapesWVL.count( EOS._initShapeID ))
for ( size_t i = 0; i < EOS._edges.size(); ++i )
{
divideVLEdge( &EOS._edges[ i ], vlH, offsetMDS );
}
}
} // loop on generated shrink shape
}//loop on original shape
} // loop on shape types
// create prisms
bool prismsOk = true;
for ( size_t i = 0; i < edgesOnShape.size(); ++i )
@ -979,10 +1216,11 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
VLEdgesOnShape& EOS = edgesOnShape[ i ];
if ( EOS._initShape.ShapeType() == TopAbs_FACE && EOS._hasVL )
{
if ( !makePrisms( EOS, _offsetMesh, n2e ))
if ( !makePrisms( EOS, &offsetMesh, n2e ))
prismsOk = false;
}
}
if ( prismsOk )
{
// create faces on FACEs WOVL
@ -994,22 +1232,40 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
auto e2f = _edge2facesWOVL.find( EOS._initShapeID );
if ( e2f != _edge2facesWOVL.end() && !e2f->second.empty() )
{
TopoDS_Shape f = initMDS->IndexToShape( e2f->second[0] );
TopoDS_Shape f2 = getOffsetSubShape( f );
//cout << e2f->second[0] << " OFF " << offsetMDS->ShapeToIndex( f2 ) << endl;
makeFaces( EOS, _offsetMesh, n2e, offsetMDS->ShapeToIndex( f2 ) );
TopoDS_Shape f = initMDS->IndexToShape( e2f->second[0] );
std::vector<TopoDS_Shape> listOfShapes;
getOffsetSubShape( f, listOfShapes );
for( TopoDS_Shape& subShape : listOfShapes )
{
int shapeId = offsetGeomMap.FindIndex( subShape );
TopoDS_Shape f2 = shrinkGeomMap.FindKey( shapeId );
makeFaces( EOS, & offsetMesh, n2e, offsetMDS->ShapeToIndex( f2 ) );
}
}
}
}
}
// copy offset mesh to the main one
if ( isMainShape2D )
{
// create faces on FACEs of the inflate viscous layer in 2D faces
for ( size_t i = 0; i < edgesOnShape.size(); ++i )
{
VLEdgesOnShape& EOS = edgesOnShape[ i ];
if ( EOS._initShape.ShapeType() == TopAbs_EDGE && EOS._hasVL /* iterate in market edges with viscous layer*/)
{
int shapeId = offsetMDS->ShapeToIndex( shrinkGeomToMesh );
makeFaces( EOS, & offsetMesh, n2e, shapeId, isMainShape2D ); // pass face Id of shrink geometry
}
}
}
// copy offset mesh to the main one
initMDS->Modified();
initMDS->CompactMesh();
smIdType nShift = initMDS->NbNodes();
TGeomID solidID = initMDS->ShapeToIndex( theShape );
copyMesh( _offsetMesh, & theMesh, solidID );
copyMesh( & offsetMesh, & theMesh, solidID );
if ( !prismsOk )
{
@ -1028,9 +1284,9 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
{
VLEdgesOnShape& EOS = edgesOnShape[ i ];
if ( EOS._hasVL )
setBnd2Sub( EOS, &theMesh, _offsetMesh, n2e, nShift, nodesToCheckCoinc );
setBnd2Sub( EOS, &theMesh, &offsetMesh, n2e, nShift, nodesToCheckCoinc );
else
setBnd2FVWL( EOS, &theMesh, _offsetMesh, nShift );
setBnd2FVWL( EOS, &theMesh, &offsetMesh, nShift );
}
// merge coincident nodes
@ -1052,5 +1308,6 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
}
}
return prismsOk;
}
}

View File

@ -26,11 +26,15 @@
#ifndef __StdMeshers_Cartesian_VL_HXX__
#define __StdMeshers_Cartesian_VL_HXX__
#include <BOPAlgo_Builder.hxx>
#include <BRepOffset_MakeOffset.hxx>
#include <BRepOffsetAPI_MakeOffset.hxx>
#include <set>
#include <map>
#include <vector>
class TopoDS_Face;
class StdMeshers_ViscousLayers;
class SMESH_Mesh;
@ -47,23 +51,34 @@ namespace StdMeshers_Cartesian_VL
TopoDS_Shape MakeOffsetShape(const TopoDS_Shape & theShape,
SMESH_Mesh & theMesh,
std::string & theError );
std::string & theError );
SMESH_Mesh* MakeOffsetMesh();
bool MakeViscousLayers( SMESH_Mesh & theMesh,
const TopoDS_Shape & theShape );
bool MakeViscousLayers( SMESH_Mesh & offsetMesh,
SMESH_Mesh & theMesh,
const TopoDS_Shape & theShape );
private:
TopoDS_Shape MakeOffsetSolid(const TopoDS_Shape & theShape,
SMESH_Mesh & theMesh,
std::string & theError );
TopoDS_Shape getOffsetSubShape( const TopoDS_Shape& S );
bool CheckGeometryMaps( SMESH_Mesh & offsetMesh,
const TopoDS_Shape & theShape );
void getOffsetSubShape( const TopoDS_Shape& S, std::vector<TopoDS_Shape>& listOfShapes );
const StdMeshers_ViscousLayers* _hyp;
BRepOffset_MakeOffset _makeOffset;
std::vector<BRepOffset_MakeOffset*> _makeOffsetCollection; // collection to
BRepOffsetAPI_MakeOffset _makeFaceOffset; // to define shrink of planar faces. The face is shrink in all
BOPAlgo_Builder _solidCompound; // to glue solids with common faces after shrinking then with BRepOffset_MakeOffset
SMESH_Mesh* _offsetMesh;
TopoDS_Shape _offsetShape;
std::set< int > _shapesWVL; // shapes with viscous layers
std::map< int, std::vector< int > > _edge2facesWOVL; // EDGE 2 FACEs w/o VL
std::set< int > _shapesWVL; // shapes with viscous layers
std::map< int, std::vector< int > > _edge2facesWOVL; // EDGE 2 FACEs w/o VL
};
}

View File

@ -0,0 +1,134 @@
// Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE
//
// 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 : StdMeshers_ViscousLayerBuilder.cxx
// Module : SMESH
// Author : Cesar Conopoima (cce)
//
#include "SMESHDS_Mesh.hxx"
#include "SMESH_ControlsDef.hxx"
#include "SMESH_Gen.hxx"
#include "SMESH_Mesh.hxx"
#include "SMESH_MeshAlgos.hxx"
#include "SMESH_MeshEditor.hxx"
#include "SMESH_MesherHelper.hxx"
#include "StdMeshers_ViscousLayerBuilder.hxx"
#include <TopoDS.hxx>
#include <vector>
//=======================================================================
//function : StdMeshers_ViscousLayerBuilder
//purpose : Implements
//=======================================================================
StdMeshers_ViscousLayerBuilder::StdMeshers_ViscousLayerBuilder(int hypId,
SMESH_Gen* gen)
: SMESH_2D_Algo(hypId, gen)
{
_name = "StdMeshers_ViscousLayerBuilder";
_hyp = new StdMeshers_ViscousLayers2D( hypId, gen );
}
bool StdMeshers_ViscousLayerBuilder::CheckHypothesis(SMESH_Mesh& aMesh,
const TopoDS_Shape& aShape,
SMESH_Hypothesis::Hypothesis_Status& aStatus)
{
(void) aMesh;
(void) aShape;
(void) aStatus;
return true;
}
bool StdMeshers_ViscousLayerBuilder::Compute(SMESH_Mesh& /*aMesh*/, const TopoDS_Shape& /*aShape*/)
{
return true;
}
bool StdMeshers_ViscousLayerBuilder::Evaluate(SMESH_Mesh & /*aMesh*/, const TopoDS_Shape & /*aShape*/,
MapShapeNbElems& /*aResMap*/ )
{
return true;
}
bool StdMeshers_ViscousLayerBuilder::IsApplicable( const TopoDS_Shape &S, bool /*toCheckAll*/, int algoDim )
{
if ( S.ShapeType() > TopAbs_FACE )
return false;
return ( std::abs( algoDim ) == 3 || std::abs( algoDim ) == 2 ) ? true : false;
}
void StdMeshers_ViscousLayerBuilder::SetBndShapes(const std::vector<int>& faceIds, bool toIgnore)
{
_hyp->SetBndShapes( faceIds, toIgnore );
} // --------------------------------------------------------------------------------
void StdMeshers_ViscousLayerBuilder::SetTotalThickness(double thickness)
{
_hyp->SetTotalThickness( thickness );
} // --------------------------------------------------------------------------------
void StdMeshers_ViscousLayerBuilder::SetNumberLayers(int nb)
{
_hyp->SetNumberLayers( nb );
} // --------------------------------------------------------------------------------
void StdMeshers_ViscousLayerBuilder::SetStretchFactor(double factor)
{
_hyp->SetStretchFactor( factor );
} // --------------------------------------------------------------------------------
void StdMeshers_ViscousLayerBuilder::SetMethod( StdMeshers_ViscousLayers::ExtrusionMethod method )
{
_hyp->SetMethod( method );
} // --------------------------------------------------------------------------------
void StdMeshers_ViscousLayerBuilder::SetGroupName(const std::string& name)
{
_hyp->SetGroupName( name );
}
//=======================================================================
//function : ~StdMeshers_ViscousLayerBuilder
//purpose :
//=======================================================================
StdMeshers_ViscousLayerBuilder::~StdMeshers_ViscousLayerBuilder()
{
}
TopoDS_Shape StdMeshers_ViscousLayerBuilder::GetShrinkGeometry( SMESH_Mesh & theMesh, const TopoDS_Shape& theShape )
{
_vlBuilder = new StdMeshers_Cartesian_VL::ViscousBuilder( _hyp, theMesh, theShape );
std::string error = "";
_offsetShape = _vlBuilder->MakeOffsetShape( theShape, theMesh, error );
if ( error != "" )
throw SALOME_Exception( error );
return _offsetShape;
}
bool StdMeshers_ViscousLayerBuilder::AddLayers( SMESH_Mesh & shrinkMesh, SMESH_Mesh & theMesh, const TopoDS_Shape& theShape )
{
bool success = _vlBuilder->MakeViscousLayers( shrinkMesh, theMesh, theShape );
if ( !success )
throw SALOME_Exception( "Error building viscous layer from shrink geometry." );
return success;
}

View File

@ -0,0 +1,107 @@
// Copyright (C) 2007-2023 CEA/DEN, EDF R&D, OPEN CASCADE
//
// 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 : StdMeshers_ViscousLayersBuilder.hxx
// Module : SMESH
//
#ifndef _SMESH_ViscourLayerBuilder_HXX_
#define _SMESH_ViscourLayerBuilder_HXX_
#include <BRepOffset_MakeOffset.hxx>
#include <BRepOffset_Offset.hxx>
#include "SMESH_StdMeshers.hxx"
#include "SMESH_Hypothesis.hxx"
#include "StdMeshers_Cartesian_VL.hxx"
#include "StdMeshers_ViscousLayers.hxx"
#include "StdMeshers_ViscousLayers2D.hxx"
class STDMESHERS_EXPORT StdMeshers_ViscousLayerBuilder: public SMESH_2D_Algo
{
public:
StdMeshers_ViscousLayerBuilder(int hypId, SMESH_Gen* gen);
~StdMeshers_ViscousLayerBuilder();
virtual bool CheckHypothesis(SMESH_Mesh& aMesh,
const TopoDS_Shape& aShape,
SMESH_Hypothesis::Hypothesis_Status& aStatus);
virtual bool Compute(SMESH_Mesh& /*aMesh*/, const TopoDS_Shape& /*aShape*/ );
virtual bool Evaluate(SMESH_Mesh & /*aMesh*/, const TopoDS_Shape & /*aShape*/,
MapShapeNbElems& /*aResMap*/ );
/*!
* \brief Check if the algo is applicable to the geometry and dimension
*/
virtual bool IsApplicable( const TopoDS_Shape &S, bool /*toCheckAll*/, int algoDim );
void SetBndShapes(const std::vector<int>& shapeIds, bool toIgnore);
// std::vector<int> GetBndShapes() const { return _shapeIds; }
// bool IsToIgnoreShapes() const { return _isToIgnoreShapes; }
void SetTotalThickness(double thickness);
// double GetTotalThickness() const { return _thickness; }
void SetNumberLayers(int nb);
// int GetNumberLayers() const { return _nbLayers; }
void SetStretchFactor(double factor);
// double GetStretchFactor() const { return _stretchFactor; }
void SetMethod( StdMeshers_ViscousLayers::ExtrusionMethod how );
// StdMeshers_ViscousLayers::ExtrusionMethod GetMethod() const { return _method; }
// name of a group to create
void SetGroupName(const std::string& name);
// const std::string& GetGroupName() const { return _groupName; }
/*!
* \brief Compute a shrink version of the geometry.
* Use the BRepOffset_MakeOffset to perfom the operations for Solids.
* Use BRepBuilderAPI_MakeFace to perform the operation for planar faces.
* \remark For possitive offsets, planar faces are shrink in all directions BRepBuilderAPI_MakeFace does not support coarse grained edge selection.
* \param theMesh - the built mesh
* \param theShape - the geometry to be shrink
* \retval TopoDS_Shape - a new shape of the shrink geometry
*/
TopoDS_Shape GetShrinkGeometry( SMESH_Mesh & theMesh, const TopoDS_Shape & theShape );
/*!
* \brief Build the elements of the viscous layer based on the shrinkMesh and copied to theMesh
* \param shrinkMesh - the mesh defined on the shrink geometry
* \param theMesh - the final mesh with the combination of the shrink mesh and the viscous layer
* \param theShape - the original geometry
* \retval bool - Ok if success in the operation
*/
bool AddLayers( SMESH_Mesh & shrinkMesh, SMESH_Mesh & theMesh, const TopoDS_Shape & theShape );
private:
StdMeshers_ViscousLayers2D* _hyp;
StdMeshers_Cartesian_VL::ViscousBuilder* _vlBuilder;
BRepOffset_MakeOffset _makeOffset;
BRepOffset_Offset _makeFaceOffset;
TopoDS_Shape _offsetShape;
};
#endif

View File

@ -115,6 +115,7 @@ SET(StdMeshersEngine_HEADERS
StdMeshers_PolygonPerFace_2D_i.hxx
StdMeshers_PolyhedronPerSolid_3D_i.hxx
StdMeshers_BlockRenumber_i.hxx
StdMeshers_ViscousLayerBuilder_i.hxx
)
# --- sources ---
@ -169,6 +170,7 @@ SET(StdMeshersEngine_SOURCES
StdMeshers_PolygonPerFace_2D_i.cxx
StdMeshers_PolyhedronPerSolid_3D_i.cxx
StdMeshers_BlockRenumber_i.cxx
StdMeshers_ViscousLayerBuilder_i.cxx
)
# --- rules ---

View File

@ -0,0 +1,205 @@
// Copyright (C) 2007-2023 CEA/DEN, EDF R&D, OPEN CASCADE
//
// 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
//
// SMESH SMESH_I : idl implementation based on 'SMESH' unit's classes
// File : StdMeshers_ViscousLayers_i.cxx
// Module : SMESH
//
#include "StdMeshers_ViscousLayerBuilder_i.hxx"
#include "SMESH_Gen.hxx"
#include "SMESH_Gen_i.hxx"
#include "SMESH_Group.hxx"
#include "SMESH_Group_i.hxx"
#include "SMESH_PythonDump.hxx"
#include "BRepTools.hxx"
#include "Utils_CorbaException.hxx"
#include "utilities.h"
#include <TCollection_AsciiString.hxx>
#include CORBA_SERVER_HEADER(SMESH_Group)
using namespace std;
//=============================================================================
/*!
* StdMeshers_ViscousLayerBuilder_i::StdMeshers_ViscousLayerBuilder_i
*
* Constructor
*/
//=============================================================================
StdMeshers_ViscousLayerBuilder_i::StdMeshers_ViscousLayerBuilder_i( PortableServer::POA_ptr thePOA,
::SMESH_Gen* theGenImpl )
: SALOME::GenericObj_i( thePOA ),
SMESH_Hypothesis_i( thePOA ),
SMESH_Algo_i( thePOA ),
SMESH_2D_Algo_i( thePOA )
{
myBaseImpl = new ::StdMeshers_ViscousLayerBuilder( theGenImpl->GetANewId(),
theGenImpl );
}
::StdMeshers_ViscousLayerBuilder* StdMeshers_ViscousLayerBuilder_i::GetImpl()
{
return ( ::StdMeshers_ViscousLayerBuilder* )myBaseImpl;
}
//================================================================================
/*!
* \brief Verify whether hypothesis supports given entity type
* \param type - dimension (see SMESH::Dimension enumeration)
* \retval CORBA::Boolean - TRUE if dimension is supported, FALSE otherwise
*
* Verify whether hypothesis supports given entity type (see SMESH::Dimension enumeration)
*/
//================================================================================
CORBA::Boolean StdMeshers_ViscousLayerBuilder_i::IsDimSupported( SMESH::Dimension type )
{
return type == SMESH::DIM_3D || type == SMESH::DIM_2D;
}
void StdMeshers_ViscousLayerBuilder_i::SetFaces(const ::SMESH::long_array& faceIDs,
CORBA::Boolean toIgnore)
{
vector<int> ids( faceIDs.length() );
for ( unsigned i = 0; i < ids.size(); ++i )
if (( ids[i] = faceIDs[i] ) < 1 )
THROW_SALOME_CORBA_EXCEPTION( "Invalid face id", SALOME::BAD_PARAM );
GetImpl()->SetBndShapes( ids, toIgnore );
SMESH::TPythonDump() << _this() << ".SetFaces( " << faceIDs << ", " << toIgnore << " )";
}
void StdMeshers_ViscousLayerBuilder_i::SetIgnoreFaces(const ::SMESH::long_array& faceIDs)
{
vector<int> ids( faceIDs.length() );
for ( unsigned i = 0; i < ids.size(); ++i )
if (( ids[i] = faceIDs[i] ) < 1 )
THROW_SALOME_CORBA_EXCEPTION( "Invalid face id", SALOME::BAD_PARAM );
GetImpl()->SetBndShapes( ids, /*toIgnore=*/true );
SMESH::TPythonDump() << _this() << ".SetIgnoreFaces( " << faceIDs << " )";
}
void StdMeshers_ViscousLayerBuilder_i::SetTotalThickness(::CORBA::Double thickness)
{
if ( thickness < 1e-100 )
THROW_SALOME_CORBA_EXCEPTION( "Invalid thickness", SALOME::BAD_PARAM );
GetImpl()->SetTotalThickness(thickness);
SMESH::TPythonDump() << _this() << ".SetTotalThickness( " << SMESH::TVar(thickness) << " )";
}
void StdMeshers_ViscousLayerBuilder_i::SetNumberLayers(::CORBA::Short nb)
{
if ( nb < 1 )
THROW_SALOME_CORBA_EXCEPTION( "Invalid number of layers", SALOME::BAD_PARAM );
GetImpl()->SetNumberLayers( nb );
SMESH::TPythonDump() << _this() << ".SetNumberLayers( " << SMESH::TVar(nb) << " )";
}
void StdMeshers_ViscousLayerBuilder_i::SetStretchFactor(::CORBA::Double factor)
{
if ( factor < 1 )
THROW_SALOME_CORBA_EXCEPTION( "Invalid stretch factor, it must be >= 1.0", SALOME::BAD_PARAM );
GetImpl()->SetStretchFactor(factor);
SMESH::TPythonDump() << _this() << ".SetStretchFactor( " << SMESH::TVar(factor) << " )";
}
void StdMeshers_ViscousLayerBuilder_i::SetMethod( ::StdMeshers::VLExtrusionMethod how )
{
GetImpl()->SetMethod( ::StdMeshers_ViscousLayers::ExtrusionMethod( how ));
const char* methNames[3] = { "SURF_OFFSET_SMOOTH",
"FACE_OFFSET",
"NODE_OFFSET" };
if ( how >= 0 && how < 3 )
SMESH::TPythonDump() << _this() << ".SetMethod( StdMeshers." << methNames[ how ]<< " )";
}
void StdMeshers_ViscousLayerBuilder_i::SetGroupName(const char* name)
{
GetImpl()->SetGroupName( name );
SMESH::TPythonDump() << _this() << ".SetGroupName( '" << name << "' )";
}
GEOM::GEOM_Object_ptr StdMeshers_ViscousLayerBuilder_i::GetShrinkGeometry( SMESH::SMESH_Mesh_ptr finalMesh, GEOM::GEOM_Object_ptr theShapeObject )
{
GEOM::GEOM_Object_var aShapeObj;
TopoDS_Shape theShape = StdMeshers_ObjRefUlils::GeomObjectToShape( theShapeObject );
SMESH_Mesh_i* theFinalMesh_i = SMESH::DownCast< SMESH_Mesh_i* >( finalMesh );
TopoDS_Shape shrinkGeometry;
try
{
shrinkGeometry = GetImpl()->GetShrinkGeometry( theFinalMesh_i->GetImpl(), theShape );
}
catch ( std::exception& exc )
{
std::cout << exc.what() << "\n";
THROW_SALOME_CORBA_EXCEPTION( exc.what(), SALOME::INTERNAL_ERROR );
return aShapeObj; // Maybe better to return a init and empty object(?)
}
if ( !shrinkGeometry.IsNull() )
{
std::ostringstream streamShape;
//Write TopoDS_Shape in ASCII format to the stream
BRepTools::Write(shrinkGeometry, streamShape);
//Returns the number of bytes that have been stored in the stream's buffer.
int size = streamShape.str().size();
//Allocate octect buffer of required size
CORBA::Octet* OctetBuf = SALOMEDS::TMPFile::allocbuf(size);
//Copy ostrstream content to the octect buffer
memcpy(OctetBuf, streamShape.str().c_str(), size);
//Create and return TMPFile
SALOMEDS::TMPFile_var SeqFile = new SALOMEDS::TMPFile(size,size,OctetBuf,1);
// Get the geom engine
GEOM::GEOM_Gen_var geomEngine = theShapeObject->GetGen();
auto iOp = geomEngine->GetIInsertOperations();
aShapeObj = iOp->RestoreShape( SeqFile );
geomEngine->AddInStudy( aShapeObj, "Shrink", GEOM::GEOM_Object::_nil());
}
return aShapeObj;
}
CORBA::Boolean StdMeshers_ViscousLayerBuilder_i::AddLayers( SMESH::SMESH_Mesh_ptr shrinkMesh, SMESH::SMESH_Mesh_ptr finalMesh, GEOM::GEOM_Object_ptr theShapeObject )
{
TopoDS_Shape theShape = StdMeshers_ObjRefUlils::GeomObjectToShape( theShapeObject );
SMESH_Mesh_i* shrinkMesh_i = SMESH::DownCast< SMESH_Mesh_i* >( shrinkMesh );
SMESH_Mesh_i* theFinalMesh_i = SMESH::DownCast< SMESH_Mesh_i* >( finalMesh );
bool success = GetImpl()->AddLayers( shrinkMesh_i->GetImpl(), theFinalMesh_i->GetImpl(), theShape );
return success;
}
//=============================================================================
/*!
* StdMeshers_ViscousLayerBuilder_i::~StdMeshers_ViscousLayerBuilder_i
*
* Destructor
*/
//=============================================================================
StdMeshers_ViscousLayerBuilder_i::~StdMeshers_ViscousLayerBuilder_i()
{
}

View File

@ -0,0 +1,73 @@
// Copyright (C) 2007-2023 CEA/DEN, EDF R&D, OPEN CASCADE
//
// 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 : StdMeshers_ViscousLayerBuilder_i.hxx
// Module : SMESH
//
#ifndef _SMESH_ViscousLayersBuilder_I_HXX_
#define _SMESH_ViscousLayersBuilder_I_HXX_
#include "SMESH_StdMeshers_I.hxx"
#include <SALOMEconfig.h>
#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis)
#include "SMESH_2D_Algo_i.hxx"
#include "SMESH_Hypothesis_i.hxx"
#include "SMESH_Mesh_i.hxx"
#include "StdMeshers_ViscousLayerBuilder.hxx"
#include "StdMeshers_ObjRefUlils.hxx"
class SMESH_Gen;
class STDMESHERS_I_EXPORT StdMeshers_ViscousLayerBuilder_i:
public virtual POA_StdMeshers::StdMeshers_ViscousLayerBuilder,
public virtual SMESH_2D_Algo_i
{
public:
// Constructor
StdMeshers_ViscousLayerBuilder_i( PortableServer::POA_ptr thePOA,
::SMESH_Gen* theGenImpl );
// Destructor
virtual ~StdMeshers_ViscousLayerBuilder_i();
// Verify whether algorithm supports given entity type
CORBA::Boolean IsDimSupported( SMESH::Dimension type );
// Get implementation
::StdMeshers_ViscousLayerBuilder* GetImpl();
void SetIgnoreFaces(const ::SMESH::long_array& faceIDs);
void SetFaces(const SMESH::long_array& faceIDs,
CORBA::Boolean toIgnore);
void SetTotalThickness(::CORBA::Double thickness);
void SetNumberLayers(::CORBA::Short nb);
void SetStretchFactor(::CORBA::Double factor);
void SetMethod( ::StdMeshers::VLExtrusionMethod how );
void SetGroupName(const char* name);
// Compute and return the shrink geometry
GEOM::GEOM_Object_ptr GetShrinkGeometry( SMESH::SMESH_Mesh_ptr finalMesh, GEOM::GEOM_Object_ptr theShapeObject );
// Build the viscous layer on the specified faces/edges available in the sourceMesh and consolidate the result in the finalMesh
CORBA::Boolean AddLayers( SMESH::SMESH_Mesh_ptr sourceMesh, SMESH::SMESH_Mesh_ptr finalMesh, GEOM::GEOM_Object_ptr theShapeObject );
};
#endif

View File

@ -77,6 +77,7 @@
#include "StdMeshers_UseExisting_1D2D_i.hxx"
#include "StdMeshers_ViscousLayers2D_i.hxx"
#include "StdMeshers_ViscousLayers_i.hxx"
#include "StdMeshers_ViscousLayerBuilder_i.hxx"
namespace SMESH {
class ApplicableToAny
@ -206,7 +207,7 @@ STDMESHERS_I_EXPORT
else if (strcmp(aHypName, "CartesianParameters3D") == 0)
aCreator = new StdHypothesisCreator_i<StdMeshers_CartesianParameters3D_i>;
else if (strcmp(aHypName, "BlockRenumber") == 0)
aCreator = new StdHypothesisCreator_i<StdMeshers_BlockRenumber_i>;
aCreator = new StdHypothesisCreator_i<StdMeshers_BlockRenumber_i>;
// Algorithms
else if (strcmp(aHypName, "Regular_1D") == 0)
@ -248,7 +249,9 @@ STDMESHERS_I_EXPORT
else if (strcmp(aHypName, "PolygonPerFace_2D") == 0)
aCreator = new StdHypothesisCreator_i<StdMeshers_PolygonPerFace_2D_i>;
else if (strcmp(aHypName, "PolyhedronPerSolid_3D") == 0)
aCreator = new StdHypothesisCreator_i<StdMeshers_PolyhedronPerSolid_3D_i>;
aCreator = new StdHypothesisCreator_i<StdMeshers_PolyhedronPerSolid_3D_i>;
else if (strcmp(aHypName, "ViscousLayerBuilder") == 0)
aCreator = new StdHypothesisCreator_i<StdMeshers_ViscousLayerBuilder_i>;
return aCreator;
}

View File

@ -0,0 +1,145 @@
# -*- coding: iso-8859-1 -*-
# Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE
#
# 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
#
import math
import salome
salome.salome_init_without_session()
import GEOM
import SHAPERSTUDY
from salome.geom import geomBuilder
from salome.smesh import smeshBuilder
from salome.shaper import model
def assertAlmostEqual(a,b,tol):
if ( abs(a-b) < tol ):
return True
else:
print( "not close vals", a, b )
return False
geompy = geomBuilder.New()
O = geompy.MakeVertex(0, 0, 0)
OX = geompy.MakeVectorDXDYDZ(1, 0, 0)
OY = geompy.MakeVectorDXDYDZ(0, 1, 0)
OZ = geompy.MakeVectorDXDYDZ(0, 0, 1)
# create a disk
geompy.addToStudy( O, 'O' )
geompy.addToStudy( OX, 'OX' )
geompy.addToStudy( OY, 'OY' )
geompy.addToStudy( OZ, 'OZ' )
Box = geompy.MakeBox(0,0,0,10,10,10)
smesh_builder = smeshBuilder.New()
MesherBox = smesh_builder.Mesh(Box, "Box")
viscousBuilder = MesherBox.ViscousLayerBuilder()
#############BOX AND TETRA ELEMENTS
#Set prismatic layer parameters
offset = 0.7
numLayers = 4
viscousBuilder.setBuilderParameters( offset, numLayers, 1.2, [13], False )
ShrinkBox = viscousBuilder.GetShrinkGeometry()
#Mesh the shrink box
MesherShinkBox = smesh_builder.Mesh(ShrinkBox, "ShrinkMesh")
ShrinkBoxMesh = MesherShinkBox.Tetrahedron(smeshBuilder.NETGEN_1D2D3D)
#Compute
success = MesherShinkBox.Compute()
assert( success )
assert( MesherShinkBox.NbVolumes() == 5 ) # if Fails! change the default value of volumes when meshing with Netgen!
FinalMesh = viscousBuilder.AddLayers( MesherShinkBox )
assert( FinalMesh.NbVolumes() == 5 + numLayers * 2 ) # here 2 stands for the number of face elements per face in the box
assert( FinalMesh.NbFaces() == 6 * 2 + 4 * numLayers ) # here is the number of face elements for the box + the new faces in the VL. (6 is the number of sides in the box)
#Testing the configuration where face 13 is ignored and so the offset is applied to all other faces
viscousBuilder.setBuilderParameters( offset, numLayers, 1.2, [13], True )
ShrinkBox2 = viscousBuilder.GetShrinkGeometry()
#Mesh the shrink box
MesherShinkBox2 = smesh_builder.Mesh(ShrinkBox2, "ShrinkMesh2")
ShrinkBoxMesh2 = MesherShinkBox2.Tetrahedron(smeshBuilder.NETGEN_1D2D3D)
#Compute
success = MesherShinkBox2.Compute()
assert( success )
#Test the number of elements on the shrink mesh
assert( MesherShinkBox2.NbVolumes() == 5 ) # if Fails! change the default (default hypo) number of volumes when meshing with Netgen!
FinalMesh2 = viscousBuilder.AddLayers( MesherShinkBox2 )
assert( FinalMesh2.NbVolumes() == 5 + numLayers * 2 * 5 ) # here 2 stands for the number of face elements per face in the box
assert( FinalMesh2.NbFaces() == 6 * 2 + 4 * numLayers ) # here is the number of face elements for the box + the new faces in the VL. (6 is the number of sides in the box)
#############END BOX AND TETRA ELEMENTS
#############MESH SQUARE FACE
Face = geompy.MakeFaceHW(5, 5, 1)
Disk = geompy.MakeDiskR(5, 1)
MesherSqr = smesh_builder.Mesh(Face, "Face")
viscousBuilder = MesherSqr.ViscousLayerBuilder()
#Set prismatic layer parameters
offset = 0.5
numberOfLayers = 6
viscousBuilder.setBuilderParameters( offset, numberOfLayers, 1.2 )
ShrinkFace = viscousBuilder.GetShrinkGeometry()
#Mesh the shrink face
MesherShinkFace = smesh_builder.Mesh(ShrinkFace, "ShrinkFaceMesh")
algo = MesherShinkFace.Segment()
numOfSegments = 4
algo.NumberOfSegments(numOfSegments)
ShrinkFaceMesh = MesherShinkFace.Triangle()
#Compute
success = MesherShinkFace.Compute()
assert( success )
numFaceElementShrinkGeom = MesherShinkFace.NbFaces()
FinalFaceMesh = viscousBuilder.AddLayers( MesherShinkFace )
# Check the number of additional elements
# numOfSegments * 4 * numberOfLayers
finalNumOfElements = FinalFaceMesh.NbFaces()
assert( numFaceElementShrinkGeom + 4 * numOfSegments * numberOfLayers == finalNumOfElements )
#############END MESH SQUARE FACE
#############MESH CIRCULAR FACE
MesherCircle = smesh_builder.Mesh(Disk, "Disk")
viscousBuilder = MesherCircle.ViscousLayerBuilder()
viscousBuilder.setBuilderParameters( offset, numberOfLayers, 1.2 )
ShrinkCircle = viscousBuilder.GetShrinkGeometry()
MesherShinkCircle = smesh_builder.Mesh(ShrinkCircle, "ShrinkCircleMesh")
algo = MesherShinkCircle.Segment()
numOfSegments = 12
algo.NumberOfSegments(numOfSegments)
ShrinkCircleMesh = MesherShinkCircle.Triangle()
#Compute
success = MesherShinkCircle.Compute()
numFaceElementShrinkGeom = MesherShinkCircle.NbFaces()
assert( success )
FinalCircleMesh = viscousBuilder.AddLayers( MesherShinkCircle )
finalNumOfElements = FinalCircleMesh.NbFaces()
assert( numFaceElementShrinkGeom + numOfSegments * numberOfLayers == finalNumOfElements )
#############END MESH CIRCULAR FACE

View File

@ -0,0 +1,209 @@
# -*- coding: iso-8859-1 -*-
# Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE
#
# 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
#
import math
import salome
salome.salome_init_without_session()
import GEOM
import SHAPERSTUDY
from salome.geom import geomBuilder
from salome.smesh import smeshBuilder
from salome.shaper import model
def assertAlmostEqual(a,b,tol):
if ( abs(a-b) < tol ):
return True
else:
print( "not close vals", a, b )
return False
geompy = geomBuilder.New()
O = geompy.MakeVertex(0, 0, 0)
OX = geompy.MakeVectorDXDYDZ(1, 0, 0)
OY = geompy.MakeVectorDXDYDZ(0, 1, 0)
OZ = geompy.MakeVectorDXDYDZ(0, 0, 1)
# create a disk
geompy.addToStudy( O, 'O' )
geompy.addToStudy( OX, 'OX' )
geompy.addToStudy( OY, 'OY' )
geompy.addToStudy( OZ, 'OZ' )
Box = geompy.MakeBox(0,0,0,10,10,10)
smesh_builder = smeshBuilder.New()
MesherBox = smesh_builder.Mesh(Box, "Box")
viscousBuilder = MesherBox.ViscousLayerBuilder()
#Set prismatic layer parameters
offset = 0.1
####SHRINK THE BOX IN ALL DIRECTIONS
#No list of faces is passed and the isToIgnore flag true by default so the offset if applied to the entire geometry
viscousBuilder.setBuilderParameters( offset, 4, 1.2 )
ShrinkBox = viscousBuilder.GetShrinkGeometry()
BoxProperties = geompy.BasicProperties(Box)
ShrinkBoxProperties = geompy.BasicProperties(ShrinkBox)
assert( BoxProperties[2] > ShrinkBoxProperties[2] )
assert( assertAlmostEqual( BoxProperties[2], (10.0)**(3.0), 1e-12 ) )
#The geometry is shrank in all directions
assert( assertAlmostEqual( ShrinkBoxProperties[2], (10.0-offset*2)**(3), 1e-12 ) )
####END SHRINK THE BOX IN ALL DIRECTIONS
####SHRINK THE BOX EXCEPT FOR ONE FACE
viscousBuilder = MesherBox.ViscousLayerBuilder()
selectableFaces = geompy.SubShapeAllSortedCentresIDs(Box, geompy.ShapeType["FACE"])
# Set face 1 TO BE ignored
viscousBuilder.setBuilderParameters( offset, 4, 1.2, [ selectableFaces[ 0 ] ], True ) # Shrink in all faces except face id
ShrinkBox = viscousBuilder.GetShrinkGeometry()
ShrinkBoxProperties = geompy.BasicProperties(ShrinkBox)
selectableShrinkFaces = geompy.SubShapeAllSortedCentresIDs(ShrinkBox, geompy.ShapeType["FACE"])
assert( assertAlmostEqual( ShrinkBoxProperties[2], (10.0-offset*2)**(2)*(10.0-offset), 1e-12 ) )
####END SHRINK THE BOX EXCEPT FOR ONE FACE
####SHRINK THE BOX IN DIRECTION OF ONLY ONE FACE
# Set face 1 TO NOT be ignored
viscousBuilder.setBuilderParameters( offset, 4, 1.2, [ selectableFaces[ 0 ] ], False ) # Shrink only the faceid
ShrinkBox = viscousBuilder.GetShrinkGeometry()
ShrinkBoxProperties = geompy.BasicProperties(ShrinkBox)
assert( assertAlmostEqual( ShrinkBoxProperties[2], (10.0)**(2)*(10.0-offset), 1e-12 ) )
selectableShrinkFaces = geompy.SubShapeAllSortedCentresIDs(ShrinkBox, geompy.ShapeType["FACE"])
####END SHRINK THE BOX IN DIRECTION OF ONLY ONE FACE
####DO NOT SHRINK THE BOX
viscousBuilder.setBuilderParameters( offset, 4, 1.2, isElementToIgnore = False )
ShrinkBox = viscousBuilder.GetShrinkGeometry()
BoxProperties = geompy.BasicProperties(Box)
ShrinkBoxProperties = geompy.BasicProperties(ShrinkBox)
assert( assertAlmostEqual( BoxProperties[2], ShrinkBoxProperties[2], 1e-12) )
####END DO NOT SHRINK THE BOX
####SHRINK THE ENTIRE SPHERE
#Test shrinking sphere
Radius = 10.0
Sphere = geompy.MakeSphere(0,0,0,Radius)
MesherSphere = smesh_builder.Mesh(Sphere, "Sphere")
viscousBuilder = MesherSphere.ViscousLayerBuilder()
viscousBuilder.setBuilderParameters( offset, 4, 1.2 )
ShrinkSphere = viscousBuilder.GetShrinkGeometry()
ShrinkSphereProperties = geompy.BasicProperties(ShrinkSphere)
assert( ShrinkSphereProperties[2] < 4.0/3.0*math.pi * Radius**3 )
assert( assertAlmostEqual( ShrinkSphereProperties[2], 4.0/3.0*math.pi*(10.0-offset)**(3), 1e-12 ) )
####END SHRINK THE ENTIRE SPHERE
####SHRINK THE ENTIRE CYLINDER
#Test shrinking cylinder
Cylinder = geompy.MakeCylinderRH(10,30)
MesherCylinder = smesh_builder.Mesh(Cylinder, "Cylinder")
viscousBuilder = MesherCylinder.ViscousLayerBuilder()
viscousBuilder.setBuilderParameters( offset, 4, 1.2 )
ShrinkCylinder = viscousBuilder.GetShrinkGeometry()
CylinderProp = geompy.BasicProperties(Cylinder)
ShirnkCylinderProp = geompy.BasicProperties(ShrinkCylinder)
assert( CylinderProp[2] > ShirnkCylinderProp[2] )
####END SHRINK THE ENTIRE CYLINDER
####SHRINK THE ENTIRE TUBE
#Test shrinking tube
Circle_1 = geompy.MakeCircle(None, None, 20)
Circle_2 = geompy.MakeCircle(None, None, 10)
Face_1 = geompy.MakeFaceWires([Circle_1, Circle_2], 1)
Tube = geompy.MakePrismDXDYDZ(Face_1, 0, 0, 100)
MesherTube = smesh_builder.Mesh(Tube, "Tube")
viscousBuilder = MesherTube.ViscousLayerBuilder()
viscousBuilder.setBuilderParameters( offset, 4, 1.2 )
ShrinkTube = viscousBuilder.GetShrinkGeometry()
TubeProp = geompy.BasicProperties(Tube)
ShirnkTubeProp = geompy.BasicProperties(ShrinkTube)
assert( TubeProp[2] > ShirnkTubeProp[2] )
####END SHRINK THE ENTIRE TUBE
####SHRINK COMPOUND OBJECT TO GENERATE COMPOUND WITH COMMON FACE
X = geompy.MakeVectorDXDYDZ( 1,0,0 )
O = geompy.MakeVertex( 100,50,50 )
plane = geompy.MakePlane( O, X, 200 ) # plane YZ
lX = 200
lYlZ = 100
box = geompy.MakeBoxDXDYDZ(lX,lYlZ,lYlZ)
sBox = geompy.MakeHalfPartition( box, plane )
# Generate a uniquebody whit coincident faces
# 4 left, 34 middle, 50 right
ignoreFaces = [4,34,50]
geompy.addToStudy( sBox, "SisterBox" )
MesherSBox = smesh_builder.Mesh( sBox, "SisterBoxMesh")
ViscousBuilder = MesherSBox.ViscousLayerBuilder()
thickness = 20
numberOfLayers = 10
stretchFactor = 1.5
ViscousBuilder.setBuilderParameters( thickness, numberOfLayers, stretchFactor, ignoreFaces )
ShrinkSBox = ViscousBuilder.GetShrinkGeometry()
SBoxProp = geompy.BasicProperties(sBox)
ShirnksBoxProp = geompy.BasicProperties(ShrinkSBox)
assert( assertAlmostEqual(ShirnksBoxProp[2], lX * (lYlZ - 2.0*thickness)**(2.0), 1e-12 ) )
####END SHRINK COMPOUND OBJECT TO GENERATE COMPUND WITH COMMON FACE
####SHRINK COMPOUND OBJECT TO GENERATE TWO DISJOINT SOLIDS
ignoreFaces = [4,50]
ViscousBuilder.setBuilderParameters( thickness, numberOfLayers, stretchFactor, ignoreFaces )
ShrinkSBox2 = ViscousBuilder.GetShrinkGeometry()
SBoxProp = geompy.BasicProperties(sBox)
ShirnksBoxProp2 = geompy.BasicProperties(ShrinkSBox2)
assert( assertAlmostEqual(ShirnksBoxProp2[2], (lX -2.0*thickness) * (lYlZ - 2.0*thickness)**(2.0), 1e-12 ) )
####END SHRINK COMPOUND OBJECT TO GENERATE TWO DISJOINT SOLIDS
######SHRINK SQUARE
offset = 0.5
numberOfLayers = 6
Face = geompy.MakeFaceHW(5, 5, 1)
MesherSqr = smesh_builder.Mesh(Face, "Face")
viscousBuilder = MesherSqr.ViscousLayerBuilder()
viscousBuilder.setBuilderParameters( offset, numberOfLayers, 1.2 )
ShrinkFace = viscousBuilder.GetShrinkGeometry()
FaceProperties = geompy.BasicProperties(Face)
ShrinkFaceProperties = geompy.BasicProperties(ShrinkFace)
#Test smaller face
assert( ShrinkFaceProperties[1] < FaceProperties[1] )
assertAlmostEqual( ShrinkFaceProperties[1], (5.0-offset*2.0)**(2.0), 1e-12 )
######END SHRINK SQUARE
######SHRINK CIRCLE
Disk = geompy.MakeDiskR(5, 1)
#Test with circle
MesherCircle = smesh_builder.Mesh(Disk, "Disk")
viscousBuilder = MesherCircle.ViscousLayerBuilder()
viscousBuilder.setBuilderParameters( offset, numberOfLayers, 1.2 )
ShrinkCircle = viscousBuilder.GetShrinkGeometry()
FaceProperties = geompy.BasicProperties(Disk)
ShrinkFaceProperties = geompy.BasicProperties(ShrinkCircle)
assert( ShrinkFaceProperties[1] < FaceProperties[1] )
######END SHRINK CIRCLE

View File

@ -37,6 +37,7 @@ SET(BAD_TESTS
ex29_refine.py
ex_MakePolyLine.py
test_smeshplugins.py
test_vlapi_growthlayer.py
PAL_MESH_041_mesh.py
PAL_MESH_043_3D.py
SMESH_BelongToGeom.py
@ -77,6 +78,7 @@ SET(GOOD_TESTS
create_penta_biquad.py
extrusion_penta_biquad.py
test_polyhedron_per_solid.py
test_vlapi_shrinkgeometry.py
ex01_cube2build.py
ex02_cube2primitive.py