mirror of
https://git.salome-platform.org/gitpub/modules/smesh.git
synced 2025-01-14 02:30:33 +05:00
2283860a0a
partially roll back 0f2942 because of hung up at calling any method of shaperBuilder in TUI mode
482 lines
22 KiB
Python
482 lines
22 KiB
Python
# Copyright (C) 2007-2021 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
|
|
#
|
|
|
|
## @package smesh_algorithm
|
|
# Python API for base Mesh_Algorithm class.
|
|
# This package is a part of SALOME %Mesh module Python API
|
|
|
|
import salome
|
|
from salome.geom import geomBuilder
|
|
import SMESH, StdMeshers
|
|
|
|
class Mesh_Algorithm:
|
|
"""
|
|
The base class to define meshing algorithms
|
|
|
|
Note:
|
|
This class should not be used directly, it is supposed to be sub-classed
|
|
for implementing Python API for specific meshing algorithms
|
|
|
|
For each meshing algorithm, a python class inheriting from class *Mesh_Algorithm*
|
|
should be defined. This descendant class should have two attributes defining the way
|
|
it is created by class :class:`~smeshBuilder.Mesh` (see e.g. class :class:`~StdMeshersBuilder.StdMeshersBuilder_Segment`):
|
|
|
|
- :code:`meshMethod` attribute defines name of method of class :class:`~smeshBuilder.Mesh` by calling which the
|
|
python class of algorithm is created; this method is dynamically added to the :class:`~smeshBuilder.Mesh` class
|
|
in runtime. For example, if in :code:`class MyPlugin_Algorithm` this attribute is defined as::
|
|
|
|
meshMethod = "MyAlgorithm"
|
|
|
|
then an instance of :code:`MyPlugin_Algorithm` can be created by the direct invocation of the function
|
|
of :class:`~smeshBuilder.Mesh` class::
|
|
|
|
my_algo = mesh.MyAlgorithm()
|
|
|
|
- :code:`algoType` defines type of algorithm and is used mostly to discriminate
|
|
algorithms that are created by the same method of class :class:`~smeshBuilder.Mesh`. For example, if this attribute
|
|
is specified in :code:`MyPlugin_Algorithm` class as::
|
|
|
|
algoType = "MyPLUGIN"
|
|
|
|
then it's creation code can be::
|
|
|
|
my_algo = mesh.MyAlgorithm(algo="MyPLUGIN")
|
|
"""
|
|
|
|
|
|
def __init__(self):
|
|
"""
|
|
Private constructor
|
|
"""
|
|
self.mesh = None
|
|
self.geom = None
|
|
self.subm = None
|
|
self.algo = None
|
|
pass
|
|
|
|
def FindHypothesis (self, hypname, args, CompareMethod, smeshpyD):
|
|
"""
|
|
Finds a hypothesis in the study by its type name and parameters.
|
|
Finds only the hypotheses created in smeshBuilder engine.
|
|
|
|
Returns:
|
|
:class:`~SMESH.SMESH_Hypothesis`
|
|
"""
|
|
study = salome.myStudy
|
|
if not study: return None
|
|
#to do: find component by smeshpyD object, not by its data type
|
|
scomp = study.FindComponent(smeshpyD.ComponentDataType())
|
|
if scomp is not None:
|
|
res,hypRoot = scomp.FindSubObject(SMESH.Tag_HypothesisRoot)
|
|
# Check if the root label of the hypotheses exists
|
|
if res and hypRoot is not None:
|
|
iter = study.NewChildIterator(hypRoot)
|
|
# Check all published hypotheses
|
|
while iter.More():
|
|
hypo_so_i = iter.Value()
|
|
attr = hypo_so_i.FindAttribute("AttributeIOR")[1]
|
|
if attr is not None:
|
|
anIOR = attr.Value()
|
|
if not anIOR: continue # prevent exception in orb.string_to_object()
|
|
hypo_o_i = salome.orb.string_to_object(anIOR)
|
|
if hypo_o_i is not None:
|
|
# Check if this is a hypothesis
|
|
hypo_i = hypo_o_i._narrow(SMESH.SMESH_Hypothesis)
|
|
if hypo_i is not None:
|
|
# Check if the hypothesis belongs to current engine
|
|
if smeshpyD.GetObjectId(hypo_i) > 0:
|
|
# Check if this is the required hypothesis
|
|
if hypo_i.GetName() == hypname:
|
|
# Check arguments
|
|
if CompareMethod(hypo_i, args):
|
|
# found!!!
|
|
return hypo_i
|
|
pass
|
|
pass
|
|
pass
|
|
pass
|
|
pass
|
|
iter.Next()
|
|
pass
|
|
pass
|
|
pass
|
|
return None
|
|
|
|
def FindAlgorithm (self, algoname, smeshpyD):
|
|
"""
|
|
Finds the algorithm in the study by its type name.
|
|
Finds only the algorithms, which have been created in smeshBuilder engine.
|
|
|
|
Returns:
|
|
SMESH.SMESH_Algo
|
|
"""
|
|
study = salome.myStudy
|
|
if not study: return None
|
|
#to do: find component by smeshpyD object, not by its data type
|
|
scomp = study.FindComponent(smeshpyD.ComponentDataType())
|
|
if scomp is not None:
|
|
res,hypRoot = scomp.FindSubObject(SMESH.Tag_AlgorithmsRoot)
|
|
# Check if the root label of the algorithms exists
|
|
if res and hypRoot is not None:
|
|
iter = study.NewChildIterator(hypRoot)
|
|
# Check all published algorithms
|
|
while iter.More():
|
|
algo_so_i = iter.Value()
|
|
attr = algo_so_i.FindAttribute("AttributeIOR")[1]
|
|
if attr is not None:
|
|
anIOR = attr.Value()
|
|
if not anIOR: continue # prevent exception in orb.string_to_object()
|
|
algo_o_i = salome.orb.string_to_object(anIOR)
|
|
if algo_o_i is not None:
|
|
# Check if this is an algorithm
|
|
algo_i = algo_o_i._narrow(SMESH.SMESH_Algo)
|
|
if algo_i is not None:
|
|
# Checks if the algorithm belongs to the current engine
|
|
if smeshpyD.GetObjectId(algo_i) > 0:
|
|
# Check if this is the required algorithm
|
|
if algo_i.GetName() == algoname:
|
|
# found!!!
|
|
return algo_i
|
|
pass
|
|
pass
|
|
pass
|
|
pass
|
|
iter.Next()
|
|
pass
|
|
pass
|
|
pass
|
|
return None
|
|
|
|
def GetSubMesh(self):
|
|
"""
|
|
If the algorithm is global, returns 0;
|
|
else returns the :class:`~SMESH.SMESH_subMesh` associated to this algorithm.
|
|
"""
|
|
return self.subm
|
|
|
|
def GetAlgorithm(self):
|
|
"""
|
|
Returns the wrapped mesher.
|
|
"""
|
|
return self.algo
|
|
|
|
def GetCompatibleHypothesis(self):
|
|
"""
|
|
Gets the list of hypothesis that can be used with this algorithm
|
|
"""
|
|
mylist = []
|
|
if self.algo:
|
|
mylist = self.algo.GetCompatibleHypothesis()
|
|
return mylist
|
|
|
|
def GetName(self):
|
|
"""
|
|
Gets the name of the algorithm
|
|
"""
|
|
from salome.smesh.smeshBuilder import GetName
|
|
return GetName(self.algo)
|
|
|
|
def SetName(self, name):
|
|
"""
|
|
Sets the name to the algorithm
|
|
"""
|
|
self.mesh.smeshpyD.SetName(self.algo, name)
|
|
|
|
def GetId(self):
|
|
"""
|
|
Gets the id of the algorithm
|
|
"""
|
|
return self.algo.GetId()
|
|
|
|
def Create(self, mesh, geom, hypo, so="libStdMeshersEngine.so"):
|
|
"""
|
|
Private method.
|
|
"""
|
|
if geom is None and mesh.mesh.HasShapeToMesh():
|
|
raise RuntimeError("Attempt to create " + hypo + " algorithm on None shape")
|
|
algo = self.FindAlgorithm(hypo, mesh.smeshpyD)
|
|
if algo is None:
|
|
algo = mesh.smeshpyD.CreateHypothesis(hypo, so)
|
|
pass
|
|
self.Assign(algo, mesh, geom)
|
|
return self.algo
|
|
|
|
def Assign(self, algo, mesh, geom):
|
|
"""
|
|
Private method
|
|
"""
|
|
from salome.smesh.smeshBuilder import AssureGeomPublished, TreatHypoStatus, GetName
|
|
if geom is None and mesh.mesh.HasShapeToMesh():
|
|
raise RuntimeError("Attempt to create " + algo + " algorithm on None shape")
|
|
self.mesh = mesh
|
|
if not geom or geom.IsSame( mesh.geom ):
|
|
self.geom = mesh.geom
|
|
else:
|
|
self.geom = geom
|
|
AssureGeomPublished( mesh, geom )
|
|
self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName())
|
|
self.algo = algo
|
|
status = mesh.AddHypothesis(self.algo, self.geom)
|
|
return
|
|
|
|
def CompareHyp (self, hyp, args):
|
|
print("CompareHyp is not implemented for ", self.__class__.__name__, ":", hyp.GetName())
|
|
return False
|
|
|
|
def CompareEqualHyp (self, hyp, args):
|
|
return True
|
|
|
|
def Hypothesis (self, hyp, args=[], so="libStdMeshersEngine.so",
|
|
UseExisting=0, CompareMethod="", toAdd=True):
|
|
"""
|
|
Private method
|
|
"""
|
|
from salome.smesh.smeshBuilder import TreatHypoStatus, GetName
|
|
hypo = None
|
|
if UseExisting:
|
|
if CompareMethod == "": CompareMethod = self.CompareHyp
|
|
hypo = self.FindHypothesis(hyp, args, CompareMethod, self.mesh.smeshpyD)
|
|
pass
|
|
if hypo is None:
|
|
hypo = self.mesh.smeshpyD.CreateHypothesis(hyp, so)
|
|
a = ""
|
|
s = "="
|
|
for arg in args:
|
|
argStr = str(arg)
|
|
if isinstance( arg, geomBuilder.GEOM._objref_GEOM_Object ):
|
|
argStr = arg.GetStudyEntry()
|
|
if not argStr: argStr = "GEOM_Obj_%s", arg.GetEntry()
|
|
if len( argStr ) > 10:
|
|
argStr = argStr[:7]+"..."
|
|
if argStr[0] == '[': argStr += ']'
|
|
a = a + s + argStr
|
|
s = ","
|
|
pass
|
|
if len(a) > 50:
|
|
a = a[:47]+"..."
|
|
self.mesh.smeshpyD.SetName(hypo, hyp + a)
|
|
pass
|
|
geomName=""
|
|
if self.geom:
|
|
geomName = GetName(self.geom)
|
|
if toAdd:
|
|
status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
|
|
TreatHypoStatus( status, GetName(hypo), geomName, 0, self.mesh )
|
|
return hypo
|
|
|
|
def MainShapeEntry(self):
|
|
"""
|
|
Returns entry of the shape to mesh in the study
|
|
"""
|
|
if not self.mesh or not self.mesh.GetMesh(): return ""
|
|
if not self.mesh.GetMesh().HasShapeToMesh(): return ""
|
|
shape = self.mesh.GetShape()
|
|
return shape.GetStudyEntry()
|
|
|
|
def ViscousLayers(self, thickness, numberOfLayers, stretchFactor,
|
|
faces=[], isFacesToIgnore=True,
|
|
extrMethod=StdMeshers.SURF_OFFSET_SMOOTH, groupName=""):
|
|
"""
|
|
Defines "ViscousLayers" hypothesis to give parameters of layers of prisms to build
|
|
near mesh boundary. This hypothesis can be used by several 3D algorithms:
|
|
NETGEN 3D, MG-Tetra, Hexahedron(i,j,k)
|
|
|
|
Parameters:
|
|
thickness: total thickness of layers of prisms
|
|
numberOfLayers: number of layers of prisms
|
|
stretchFactor: factor (>1.0) of growth of layer thickness towards inside of mesh
|
|
faces: list of geometrical faces (or their ids).
|
|
Viscous layers are either generated on these faces or not, depending on
|
|
the value of **isFacesToIgnore** parameter.
|
|
isFacesToIgnore: if *True*, the Viscous layers are not generated on the
|
|
faces specified by the previous parameter (**faces**).
|
|
extrMethod: extrusion method defines how position of new nodes are found during
|
|
prism construction and how creation of distorted and intersecting prisms is
|
|
prevented. Possible values are:
|
|
|
|
- StdMeshers.SURF_OFFSET_SMOOTH (default) method extrudes nodes along normal
|
|
to underlying geometrical surface. Smoothing of internal surface of
|
|
element layers can be used to avoid creation of invalid prisms.
|
|
- StdMeshers.FACE_OFFSET method extrudes nodes along average normal of
|
|
surrounding mesh faces till intersection with a neighbor mesh face
|
|
translated along its own normal by the layers thickness. Thickness
|
|
of layers can be limited to avoid creation of invalid prisms.
|
|
- StdMeshers.NODE_OFFSET method extrudes nodes along average normal of
|
|
surrounding mesh faces by the layers thickness. Thickness of
|
|
layers can be limited to avoid creation of invalid prisms.
|
|
groupName: name of a group to contain elements of layers. If not provided,
|
|
no group is created. The group is created upon mesh generation.
|
|
It can be retrieved by calling
|
|
::
|
|
|
|
group = mesh.GetGroupByName( groupName, SMESH.VOLUME )[0]
|
|
|
|
Returns:
|
|
StdMeshers.StdMeshers_ViscousLayers hypothesis
|
|
"""
|
|
|
|
if not isinstance(self.algo, SMESH._objref_SMESH_3D_Algo):
|
|
raise TypeError("ViscousLayers are supported by 3D algorithms only")
|
|
if not "ViscousLayers" in self.GetCompatibleHypothesis():
|
|
raise TypeError("ViscousLayers are not supported by %s"%self.algo.GetName())
|
|
if faces and isinstance( faces, geomBuilder.GEOM._objref_GEOM_Object ):
|
|
faces = [ faces ]
|
|
if faces and isinstance( faces[0], geomBuilder.GEOM._objref_GEOM_Object ):
|
|
faceIDs = []
|
|
for shape in faces:
|
|
try:
|
|
ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] )
|
|
for f in ff:
|
|
faceIDs.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)
|
|
for f in ff:
|
|
faceIDs.append( aShapeOp.GetSubShapeIndex( self.mesh.geom, f ))
|
|
faces = faceIDs
|
|
hyp = self.Hypothesis("ViscousLayers",
|
|
[thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore],
|
|
toAdd=False)
|
|
hyp.SetTotalThickness( thickness )
|
|
hyp.SetNumberLayers( numberOfLayers )
|
|
hyp.SetStretchFactor( stretchFactor )
|
|
hyp.SetFaces( faces, isFacesToIgnore )
|
|
hyp.SetMethod( extrMethod )
|
|
hyp.SetGroupName( groupName )
|
|
self.mesh.AddHypothesis( hyp, self.geom )
|
|
return hyp
|
|
|
|
def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor,
|
|
edges=[], isEdgesToIgnore=True, groupName="" ):
|
|
"""
|
|
Defines "ViscousLayers2D" hypothesis to give parameters of layers of quadrilateral
|
|
elements to build near mesh boundary. This hypothesis can be used by several 2D algorithms:
|
|
NETGEN 2D, NETGEN 1D-2D, Quadrangle (mapping), MEFISTO, MG-CADSurf
|
|
|
|
Parameters:
|
|
thickness: total thickness of layers of quadrilaterals
|
|
numberOfLayers: number of layers
|
|
stretchFactor: factor (>1.0) of growth of layer thickness towards inside of mesh
|
|
edges: list of geometrical edges (or their ids).
|
|
Viscous layers are either generated on these edges or not, depending on
|
|
the value of **isEdgesToIgnore** parameter.
|
|
isEdgesToIgnore: if *True*, the Viscous layers are not generated on the
|
|
edges specified by the previous parameter (**edges**).
|
|
groupName: name of a group to contain elements of layers. If not provided,
|
|
no group is created. The group is created upon mesh generation.
|
|
It can be retrieved by calling
|
|
::
|
|
|
|
group = mesh.GetGroupByName( groupName, SMESH.FACE )[0]
|
|
|
|
Returns:
|
|
StdMeshers.StdMeshers_ViscousLayers2D hypothesis
|
|
"""
|
|
|
|
if not isinstance(self.algo, SMESH._objref_SMESH_2D_Algo):
|
|
raise TypeError("ViscousLayers2D are supported by 2D algorithms only")
|
|
if not "ViscousLayers2D" in self.GetCompatibleHypothesis():
|
|
raise TypeError("ViscousLayers2D are not supported by %s"%self.algo.GetName())
|
|
if edges and not isinstance( edges, list ) and not isinstance( edges, tuple ):
|
|
edges = [edges]
|
|
if edges and isinstance( edges[0], geomBuilder.GEOM._objref_GEOM_Object ):
|
|
edgeIDs = []
|
|
for shape in edges:
|
|
try:
|
|
ee = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"])
|
|
for e in ee:
|
|
edgeIDs.append( self.mesh.geompyD.GetSubShapeID( self.mesh.geom, e ))
|
|
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()
|
|
ee = aShapeOp.ExtractSubShapes( shape, self.mesh.geompyD.ShapeType["EDGE"], False)
|
|
for e in ee:
|
|
edgeIDs.append( aShapeOp.GetSubShapeIndex( self.mesh.geom, e ))
|
|
edges = edgeIDs
|
|
hyp = self.Hypothesis("ViscousLayers2D",
|
|
[thickness, numberOfLayers, stretchFactor, edges, isEdgesToIgnore],
|
|
toAdd=False)
|
|
hyp.SetTotalThickness(thickness)
|
|
hyp.SetNumberLayers(numberOfLayers)
|
|
hyp.SetStretchFactor(stretchFactor)
|
|
hyp.SetEdges(edges, isEdgesToIgnore)
|
|
hyp.SetGroupName( groupName )
|
|
self.mesh.AddHypothesis( hyp, self.geom )
|
|
return hyp
|
|
|
|
def ReversedEdgeIndices(self, reverseList):
|
|
"""
|
|
Transform a list of either edges or tuples (edge, 1st_vertex_of_edge)
|
|
into a list acceptable to SetReversedEdges() of some 1D hypotheses
|
|
"""
|
|
|
|
resList = []
|
|
geompy = self.mesh.geompyD
|
|
for i in reverseList:
|
|
if isinstance( i, int ):
|
|
s = geompy.GetSubShape(self.mesh.geom, [i])
|
|
|
|
#bos #20082 begin:
|
|
if s is None and type(self.geom) != geomBuilder.GEOM._objref_GEOM_Object:
|
|
# try to get the SHAPERSTUDY engine directly, as 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()
|
|
s = aShapeOp.GetSubShape(self.mesh.geom, i)
|
|
#bos #20082 end
|
|
|
|
if s.GetShapeType() != geomBuilder.GEOM.EDGE:
|
|
raise TypeError("Not EDGE index given")
|
|
resList.append( i )
|
|
elif isinstance( i, geomBuilder.GEOM._objref_GEOM_Object ):
|
|
if i.GetShapeType() != geomBuilder.GEOM.EDGE:
|
|
raise TypeError("Not an EDGE given")
|
|
resList.append( geompy.GetSubShapeID(self.mesh.geom, i ))
|
|
elif len( i ) > 1:
|
|
e = i[0]
|
|
v = i[1]
|
|
if not isinstance( e, geomBuilder.GEOM._objref_GEOM_Object ) or \
|
|
not isinstance( v, geomBuilder.GEOM._objref_GEOM_Object ):
|
|
raise TypeError("A list item must be a tuple (edge, 1st_vertex_of_edge)")
|
|
if v.GetShapeType() == geomBuilder.GEOM.EDGE and \
|
|
e.GetShapeType() == geomBuilder.GEOM.VERTEX:
|
|
v,e = e,v
|
|
if e.GetShapeType() != geomBuilder.GEOM.EDGE or \
|
|
v.GetShapeType() != geomBuilder.GEOM.VERTEX:
|
|
raise TypeError("A list item must be a tuple (edge, 1st_vertex_of_edge)")
|
|
vFirst = geompy.GetVertexByIndex( e, 0, False )
|
|
tol = geompy.Tolerance( vFirst )[-1]
|
|
if geompy.MinDistance( v, vFirst ) > 1.5*tol:
|
|
resList.append( geompy.GetSubShapeID(self.mesh.geom, e ))
|
|
else:
|
|
raise TypeError("Item must be either an edge or tuple (edge, 1st_vertex_of_edge)")
|
|
return resList
|
|
|