smesh/src/SMESH_SWIG/smesh_algorithm.py
2019-02-14 15:33:05 +03:00

428 lines
19 KiB
Python

# Copyright (C) 2007-2019 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 ):
"""
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.
"""
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:
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))
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 )
self.mesh.AddHypothesis( hyp, self.geom )
return hyp
def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor,
edges=[], isEdgesToIgnore=True ):
"""
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**).
"""
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:
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 ))
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)
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
"""
from salome.smesh.smeshBuilder import FirstVertexOnCurve
resList = []
geompy = self.mesh.geompyD
for i in reverseList:
if isinstance( i, int ):
s = geompy.SubShapes(self.mesh.geom, [i])[0]
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 = FirstVertexOnCurve( self.mesh, e )
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