1 # Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License, or (at your option) any later version.
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # Lesser General Public License for more details.
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 ## @package smesh_algorithm
21 # Python API for base Mesh_Algorithm class.
22 # This package is a part of SALOME %Mesh module Python API
25 from salome.geom import geomBuilder
26 import SMESH, StdMeshers
30 The base class to define meshing algorithms
33 This class should not be used directly, it is supposed to be sub-classed
34 for implementing Python API for specific meshing algorithms
36 For each meshing algorithm, a python class inheriting from class *Mesh_Algorithm*
37 should be defined. This descendant class should have two attributes defining the way
38 it is created by class :class:`~smeshBuilder.Mesh` (see e.g. class :class:`~StdMeshersBuilder.StdMeshersBuilder_Segment`):
40 - :code:`meshMethod` attribute defines name of method of class :class:`~smeshBuilder.Mesh` by calling which the
41 python class of algorithm is created; this method is dynamically added to the :class:`~smeshBuilder.Mesh` class
42 in runtime. For example, if in :code:`class MyPlugin_Algorithm` this attribute is defined as::
44 meshMethod = "MyAlgorithm"
46 then an instance of :code:`MyPlugin_Algorithm` can be created by the direct invocation of the function
47 of :class:`~smeshBuilder.Mesh` class::
49 my_algo = mesh.MyAlgorithm()
51 - :code:`algoType` defines type of algorithm and is used mostly to discriminate
52 algorithms that are created by the same method of class :class:`~smeshBuilder.Mesh`. For example, if this attribute
53 is specified in :code:`MyPlugin_Algorithm` class as::
57 then it's creation code can be::
59 my_algo = mesh.MyAlgorithm(algo="MyPLUGIN")
73 def FindHypothesis (self, hypname, args, CompareMethod, smeshpyD):
75 Finds a hypothesis in the study by its type name and parameters.
76 Finds only the hypotheses created in smeshBuilder engine.
78 :class:`~SMESH.SMESH_Hypothesis`
80 study = salome.myStudy
81 if not study: return None
82 #to do: find component by smeshpyD object, not by its data type
83 scomp = study.FindComponent(smeshpyD.ComponentDataType())
85 res,hypRoot = scomp.FindSubObject(SMESH.Tag_HypothesisRoot)
86 # Check if the root label of the hypotheses exists
87 if res and hypRoot is not None:
88 iter = study.NewChildIterator(hypRoot)
89 # Check all published hypotheses
91 hypo_so_i = iter.Value()
92 attr = hypo_so_i.FindAttribute("AttributeIOR")[1]
95 if not anIOR: continue # prevent exception in orb.string_to_object()
96 hypo_o_i = salome.orb.string_to_object(anIOR)
97 if hypo_o_i is not None:
98 # Check if this is a hypothesis
99 hypo_i = hypo_o_i._narrow(SMESH.SMESH_Hypothesis)
100 if hypo_i is not None:
101 # Check if the hypothesis belongs to current engine
102 if smeshpyD.GetObjectId(hypo_i) > 0:
103 # Check if this is the required hypothesis
104 if hypo_i.GetName() == hypname:
106 if CompareMethod(hypo_i, args):
120 def FindAlgorithm (self, algoname, smeshpyD):
122 Finds the algorithm in the study by its type name.
123 Finds only the algorithms, which have been created in smeshBuilder engine.
128 study = salome.myStudy
129 if not study: return None
130 #to do: find component by smeshpyD object, not by its data type
131 scomp = study.FindComponent(smeshpyD.ComponentDataType())
132 if scomp is not None:
133 res,hypRoot = scomp.FindSubObject(SMESH.Tag_AlgorithmsRoot)
134 # Check if the root label of the algorithms exists
135 if res and hypRoot is not None:
136 iter = study.NewChildIterator(hypRoot)
137 # Check all published algorithms
139 algo_so_i = iter.Value()
140 attr = algo_so_i.FindAttribute("AttributeIOR")[1]
143 if not anIOR: continue # prevent exception in orb.string_to_object()
144 algo_o_i = salome.orb.string_to_object(anIOR)
145 if algo_o_i is not None:
146 # Check if this is an algorithm
147 algo_i = algo_o_i._narrow(SMESH.SMESH_Algo)
148 if algo_i is not None:
149 # Checks if the algorithm belongs to the current engine
150 if smeshpyD.GetObjectId(algo_i) > 0:
151 # Check if this is the required algorithm
152 if algo_i.GetName() == algoname:
165 def GetSubMesh(self):
167 If the algorithm is global, returns 0;
168 else returns the :class:`~SMESH.SMESH_subMesh` associated to this algorithm.
172 def GetAlgorithm(self):
174 Returns the wrapped mesher.
178 def GetCompatibleHypothesis(self):
180 Gets the list of hypothesis that can be used with this algorithm
184 mylist = self.algo.GetCompatibleHypothesis()
189 Gets the name of the algorithm
191 from salome.smesh.smeshBuilder import GetName
192 return GetName(self.algo)
194 def SetName(self, name):
196 Sets the name to the algorithm
198 self.mesh.smeshpyD.SetName(self.algo, name)
202 Gets the id of the algorithm
204 return self.algo.GetId()
206 def Create(self, mesh, geom, hypo, so="libStdMeshersEngine.so"):
210 if geom is None and mesh.mesh.HasShapeToMesh():
211 raise RuntimeError("Attempt to create " + hypo + " algorithm on None shape")
212 algo = self.FindAlgorithm(hypo, mesh.smeshpyD)
214 algo = mesh.smeshpyD.CreateHypothesis(hypo, so)
216 self.Assign(algo, mesh, geom)
219 def Assign(self, algo, mesh, geom):
223 from salome.smesh.smeshBuilder import AssureGeomPublished, TreatHypoStatus, GetName
224 if geom is None and mesh.mesh.HasShapeToMesh():
225 raise RuntimeError("Attempt to create " + algo + " algorithm on None shape")
227 if not geom or geom.IsSame( mesh.geom ):
228 self.geom = mesh.geom
231 AssureGeomPublished( mesh, geom )
232 self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName())
234 status = mesh.AddHypothesis(self.algo, self.geom)
237 def CompareHyp (self, hyp, args):
238 print("CompareHyp is not implemented for ", self.__class__.__name__, ":", hyp.GetName())
241 def CompareEqualHyp (self, hyp, args):
244 def Hypothesis (self, hyp, args=[], so="libStdMeshersEngine.so",
245 UseExisting=0, CompareMethod="", toAdd=True):
249 from salome.smesh.smeshBuilder import TreatHypoStatus, GetName
252 if CompareMethod == "": CompareMethod = self.CompareHyp
253 hypo = self.FindHypothesis(hyp, args, CompareMethod, self.mesh.smeshpyD)
256 hypo = self.mesh.smeshpyD.CreateHypothesis(hyp, so)
261 if isinstance( arg, geomBuilder.GEOM._objref_GEOM_Object ):
262 argStr = arg.GetStudyEntry()
263 if not argStr: argStr = "GEOM_Obj_%s", arg.GetEntry()
264 if len( argStr ) > 10:
265 argStr = argStr[:7]+"..."
266 if argStr[0] == '[': argStr += ']'
272 self.mesh.smeshpyD.SetName(hypo, hyp + a)
276 geomName = GetName(self.geom)
278 status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
279 TreatHypoStatus( status, GetName(hypo), geomName, 0, self.mesh )
282 def MainShapeEntry(self):
284 Returns entry of the shape to mesh in the study
286 if not self.mesh or not self.mesh.GetMesh(): return ""
287 if not self.mesh.GetMesh().HasShapeToMesh(): return ""
288 shape = self.mesh.GetShape()
289 return shape.GetStudyEntry()
291 def ViscousLayers(self, thickness, numberOfLayers, stretchFactor,
292 faces=[], isFacesToIgnore=True, extrMethod=StdMeshers.SURF_OFFSET_SMOOTH ):
294 Defines "ViscousLayers" hypothesis to give parameters of layers of prisms to build
295 near mesh boundary. This hypothesis can be used by several 3D algorithms:
296 NETGEN 3D, MG-Tetra, Hexahedron(i,j,k)
299 thickness: total thickness of layers of prisms
300 numberOfLayers: number of layers of prisms
301 stretchFactor: factor (>1.0) of growth of layer thickness towards inside of mesh
302 faces: list of geometrical faces (or their ids).
303 Viscous layers are either generated on these faces or not, depending on
304 the value of **isFacesToIgnore** parameter.
305 isFacesToIgnore: if *True*, the Viscous layers are not generated on the
306 faces specified by the previous parameter (**faces**).
307 extrMethod: extrusion method defines how position of new nodes are found during
308 prism construction and how creation of distorted and intersecting prisms is
309 prevented. Possible values are:
311 - StdMeshers.SURF_OFFSET_SMOOTH (default) method extrudes nodes along normal
312 to underlying geometrical surface. Smoothing of internal surface of
313 element layers can be used to avoid creation of invalid prisms.
314 - StdMeshers.FACE_OFFSET method extrudes nodes along average normal of
315 surrounding mesh faces till intersection with a neighbor mesh face
316 translated along its own normal by the layers thickness. Thickness
317 of layers can be limited to avoid creation of invalid prisms.
318 - StdMeshers.NODE_OFFSET method extrudes nodes along average normal of
319 surrounding mesh faces by the layers thickness. Thickness of
320 layers can be limited to avoid creation of invalid prisms.
323 if not isinstance(self.algo, SMESH._objref_SMESH_3D_Algo):
324 raise TypeError("ViscousLayers are supported by 3D algorithms only")
325 if not "ViscousLayers" in self.GetCompatibleHypothesis():
326 raise TypeError("ViscousLayers are not supported by %s"%self.algo.GetName())
327 if faces and isinstance( faces, geomBuilder.GEOM._objref_GEOM_Object ):
329 if faces and isinstance( faces[0], geomBuilder.GEOM._objref_GEOM_Object ):
332 ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] )
334 faceIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f))
336 hyp = self.Hypothesis("ViscousLayers",
337 [thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore],
339 hyp.SetTotalThickness( thickness )
340 hyp.SetNumberLayers( numberOfLayers )
341 hyp.SetStretchFactor( stretchFactor )
342 hyp.SetFaces( faces, isFacesToIgnore )
343 hyp.SetMethod( extrMethod )
344 self.mesh.AddHypothesis( hyp, self.geom )
347 def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor,
348 edges=[], isEdgesToIgnore=True ):
350 Defines "ViscousLayers2D" hypothesis to give parameters of layers of quadrilateral
351 elements to build near mesh boundary. This hypothesis can be used by several 2D algorithms:
352 NETGEN 2D, NETGEN 1D-2D, Quadrangle (mapping), MEFISTO, MG-CADSurf
355 thickness: total thickness of layers of quadrilaterals
356 numberOfLayers: number of layers
357 stretchFactor: factor (>1.0) of growth of layer thickness towards inside of mesh
358 edges: list of geometrical edges (or their ids).
359 Viscous layers are either generated on these edges or not, depending on
360 the value of **isEdgesToIgnore** parameter.
361 isEdgesToIgnore: if *True*, the Viscous layers are not generated on the
362 edges specified by the previous parameter (**edges**).
365 if not isinstance(self.algo, SMESH._objref_SMESH_2D_Algo):
366 raise TypeError("ViscousLayers2D are supported by 2D algorithms only")
367 if not "ViscousLayers2D" in self.GetCompatibleHypothesis():
368 raise TypeError("ViscousLayers2D are not supported by %s"%self.algo.GetName())
369 if edges and not isinstance( edges, list ) and not isinstance( edges, tuple ):
371 if edges and isinstance( edges[0], geomBuilder.GEOM._objref_GEOM_Object ):
374 ee = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"])
376 edgeIDs.append( self.mesh.geompyD.GetSubShapeID( self.mesh.geom, e ))
378 hyp = self.Hypothesis("ViscousLayers2D",
379 [thickness, numberOfLayers, stretchFactor, edges, isEdgesToIgnore],
381 hyp.SetTotalThickness(thickness)
382 hyp.SetNumberLayers(numberOfLayers)
383 hyp.SetStretchFactor(stretchFactor)
384 hyp.SetEdges(edges, isEdgesToIgnore)
385 self.mesh.AddHypothesis( hyp, self.geom )
388 def ReversedEdgeIndices(self, reverseList):
390 Transform a list of either edges or tuples (edge, 1st_vertex_of_edge)
391 into a list acceptable to SetReversedEdges() of some 1D hypotheses
394 from salome.smesh.smeshBuilder import FirstVertexOnCurve
396 geompy = self.mesh.geompyD
397 for i in reverseList:
398 if isinstance( i, int ):
399 s = geompy.SubShapes(self.mesh.geom, [i])[0]
400 if s.GetShapeType() != geomBuilder.GEOM.EDGE:
401 raise TypeError("Not EDGE index given")
403 elif isinstance( i, geomBuilder.GEOM._objref_GEOM_Object ):
404 if i.GetShapeType() != geomBuilder.GEOM.EDGE:
405 raise TypeError("Not an EDGE given")
406 resList.append( geompy.GetSubShapeID(self.mesh.geom, i ))
410 if not isinstance( e, geomBuilder.GEOM._objref_GEOM_Object ) or \
411 not isinstance( v, geomBuilder.GEOM._objref_GEOM_Object ):
412 raise TypeError("A list item must be a tuple (edge, 1st_vertex_of_edge)")
413 if v.GetShapeType() == geomBuilder.GEOM.EDGE and \
414 e.GetShapeType() == geomBuilder.GEOM.VERTEX:
416 if e.GetShapeType() != geomBuilder.GEOM.EDGE or \
417 v.GetShapeType() != geomBuilder.GEOM.VERTEX:
418 raise TypeError("A list item must be a tuple (edge, 1st_vertex_of_edge)")
419 vFirst = FirstVertexOnCurve( self.mesh, e )
420 tol = geompy.Tolerance( vFirst )[-1]
421 if geompy.MinDistance( v, vFirst ) > 1.5*tol:
422 resList.append( geompy.GetSubShapeID(self.mesh.geom, e ))
424 raise TypeError("Item must be either an edge or tuple (edge, 1st_vertex_of_edge)")