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.
79 :class:`~SMESH.SMESH_Hypothesis`
81 study = salome.myStudy
82 if not study: return None
83 #to do: find component by smeshpyD object, not by its data type
84 scomp = study.FindComponent(smeshpyD.ComponentDataType())
86 res,hypRoot = scomp.FindSubObject(SMESH.Tag_HypothesisRoot)
87 # Check if the root label of the hypotheses exists
88 if res and hypRoot is not None:
89 iter = study.NewChildIterator(hypRoot)
90 # Check all published hypotheses
92 hypo_so_i = iter.Value()
93 attr = hypo_so_i.FindAttribute("AttributeIOR")[1]
96 if not anIOR: continue # prevent exception in orb.string_to_object()
97 hypo_o_i = salome.orb.string_to_object(anIOR)
98 if hypo_o_i is not None:
99 # Check if this is a hypothesis
100 hypo_i = hypo_o_i._narrow(SMESH.SMESH_Hypothesis)
101 if hypo_i is not None:
102 # Check if the hypothesis belongs to current engine
103 if smeshpyD.GetObjectId(hypo_i) > 0:
104 # Check if this is the required hypothesis
105 if hypo_i.GetName() == hypname:
107 if CompareMethod(hypo_i, args):
121 def FindAlgorithm (self, algoname, smeshpyD):
123 Finds the algorithm in the study by its type name.
124 Finds only the algorithms, which have been created in smeshBuilder engine.
129 study = salome.myStudy
130 if not study: return None
131 #to do: find component by smeshpyD object, not by its data type
132 scomp = study.FindComponent(smeshpyD.ComponentDataType())
133 if scomp is not None:
134 res,hypRoot = scomp.FindSubObject(SMESH.Tag_AlgorithmsRoot)
135 # Check if the root label of the algorithms exists
136 if res and hypRoot is not None:
137 iter = study.NewChildIterator(hypRoot)
138 # Check all published algorithms
140 algo_so_i = iter.Value()
141 attr = algo_so_i.FindAttribute("AttributeIOR")[1]
144 if not anIOR: continue # prevent exception in orb.string_to_object()
145 algo_o_i = salome.orb.string_to_object(anIOR)
146 if algo_o_i is not None:
147 # Check if this is an algorithm
148 algo_i = algo_o_i._narrow(SMESH.SMESH_Algo)
149 if algo_i is not None:
150 # Checks if the algorithm belongs to the current engine
151 if smeshpyD.GetObjectId(algo_i) > 0:
152 # Check if this is the required algorithm
153 if algo_i.GetName() == algoname:
166 def GetSubMesh(self):
168 If the algorithm is global, returns 0;
169 else returns the :class:`~SMESH.SMESH_subMesh` associated to this algorithm.
173 def GetAlgorithm(self):
175 Returns the wrapped mesher.
179 def GetCompatibleHypothesis(self):
181 Gets the list of hypothesis that can be used with this algorithm
185 mylist = self.algo.GetCompatibleHypothesis()
190 Gets the name of the algorithm
192 from salome.smesh.smeshBuilder import GetName
193 return GetName(self.algo)
195 def SetName(self, name):
197 Sets the name to the algorithm
199 self.mesh.smeshpyD.SetName(self.algo, name)
203 Gets the id of the algorithm
205 return self.algo.GetId()
207 def Create(self, mesh, geom, hypo, so="libStdMeshersEngine.so"):
211 if geom is None and mesh.mesh.HasShapeToMesh():
212 raise RuntimeError("Attempt to create " + hypo + " algorithm on None shape")
213 algo = self.FindAlgorithm(hypo, mesh.smeshpyD)
215 algo = mesh.smeshpyD.CreateHypothesis(hypo, so)
217 self.Assign(algo, mesh, geom)
220 def Assign(self, algo, mesh, geom):
224 from salome.smesh.smeshBuilder import AssureGeomPublished, TreatHypoStatus, GetName
225 if geom is None and mesh.mesh.HasShapeToMesh():
226 raise RuntimeError("Attempt to create " + algo + " algorithm on None shape")
228 if not geom or geom.IsSame( mesh.geom ):
229 self.geom = mesh.geom
232 AssureGeomPublished( mesh, geom )
233 self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName())
235 status = mesh.AddHypothesis(self.algo, self.geom)
238 def CompareHyp (self, hyp, args):
239 print("CompareHyp is not implemented for ", self.__class__.__name__, ":", hyp.GetName())
242 def CompareEqualHyp (self, hyp, args):
245 def Hypothesis (self, hyp, args=[], so="libStdMeshersEngine.so",
246 UseExisting=0, CompareMethod="", toAdd=True):
250 from salome.smesh.smeshBuilder import TreatHypoStatus, GetName
253 if CompareMethod == "": CompareMethod = self.CompareHyp
254 hypo = self.FindHypothesis(hyp, args, CompareMethod, self.mesh.smeshpyD)
257 hypo = self.mesh.smeshpyD.CreateHypothesis(hyp, so)
262 if isinstance( arg, geomBuilder.GEOM._objref_GEOM_Object ):
263 argStr = arg.GetStudyEntry()
264 if not argStr: argStr = "GEOM_Obj_%s", arg.GetEntry()
265 if len( argStr ) > 10:
266 argStr = argStr[:7]+"..."
267 if argStr[0] == '[': argStr += ']'
273 self.mesh.smeshpyD.SetName(hypo, hyp + a)
277 geomName = GetName(self.geom)
279 status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
280 TreatHypoStatus( status, GetName(hypo), geomName, 0, self.mesh )
283 def MainShapeEntry(self):
285 Returns entry of the shape to mesh in the study
287 if not self.mesh or not self.mesh.GetMesh(): return ""
288 if not self.mesh.GetMesh().HasShapeToMesh(): return ""
289 shape = self.mesh.GetShape()
290 return shape.GetStudyEntry()
292 def ViscousLayers(self, thickness, numberOfLayers, stretchFactor,
293 faces=[], isFacesToIgnore=True, extrMethod=StdMeshers.SURF_OFFSET_SMOOTH ):
295 Defines "ViscousLayers" hypothesis to give parameters of layers of prisms to build
296 near mesh boundary. This hypothesis can be used by several 3D algorithms:
297 NETGEN 3D, MG-Tetra, Hexahedron(i,j,k)
300 thickness: total thickness of layers of prisms
301 numberOfLayers: number of layers of prisms
302 stretchFactor: factor (>1.0) of growth of layer thickness towards inside of mesh
303 faces: list of geometrical faces (or their ids).
304 Viscous layers are either generated on these faces or not, depending on
305 the value of **isFacesToIgnore** parameter.
306 isFacesToIgnore: if *True*, the Viscous layers are not generated on the
307 faces specified by the previous parameter (**faces**).
308 extrMethod: extrusion method defines how position of new nodes are found during
309 prism construction and how creation of distorted and intersecting prisms is
310 prevented. Possible values are:
312 - StdMeshers.SURF_OFFSET_SMOOTH (default) method extrudes nodes along normal
313 to underlying geometrical surface. Smoothing of internal surface of
314 element layers can be used to avoid creation of invalid prisms.
315 - StdMeshers.FACE_OFFSET method extrudes nodes along average normal of
316 surrounding mesh faces till intersection with a neighbor mesh face
317 translated along its own normal by the layers thickness. Thickness
318 of layers can be limited to avoid creation of invalid prisms.
319 - StdMeshers.NODE_OFFSET method extrudes nodes along average normal of
320 surrounding mesh faces by the layers thickness. Thickness of
321 layers can be limited to avoid creation of invalid prisms.
324 if not isinstance(self.algo, SMESH._objref_SMESH_3D_Algo):
325 raise TypeError("ViscousLayers are supported by 3D algorithms only")
326 if not "ViscousLayers" in self.GetCompatibleHypothesis():
327 raise TypeError("ViscousLayers are not supported by %s"%self.algo.GetName())
328 if faces and isinstance( faces, geomBuilder.GEOM._objref_GEOM_Object ):
330 if faces and isinstance( faces[0], geomBuilder.GEOM._objref_GEOM_Object ):
333 ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] )
335 faceIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f))
337 hyp = self.Hypothesis("ViscousLayers",
338 [thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore],
340 hyp.SetTotalThickness( thickness )
341 hyp.SetNumberLayers( numberOfLayers )
342 hyp.SetStretchFactor( stretchFactor )
343 hyp.SetFaces( faces, isFacesToIgnore )
344 hyp.SetMethod( extrMethod )
345 self.mesh.AddHypothesis( hyp, self.geom )
348 def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor,
349 edges=[], isEdgesToIgnore=True ):
351 Defines "ViscousLayers2D" hypothesis to give parameters of layers of quadrilateral
352 elements to build near mesh boundary. This hypothesis can be used by several 2D algorithms:
353 NETGEN 2D, NETGEN 1D-2D, Quadrangle (mapping), MEFISTO, MG-CADSurf
356 thickness: total thickness of layers of quadrilaterals
357 numberOfLayers: number of layers
358 stretchFactor: factor (>1.0) of growth of layer thickness towards inside of mesh
359 edges: list of geometrical edges (or their ids).
360 Viscous layers are either generated on these edges or not, depending on
361 the value of **isEdgesToIgnore** parameter.
362 isEdgesToIgnore: if *True*, the Viscous layers are not generated on the
363 edges specified by the previous parameter (**edges**).
366 if not isinstance(self.algo, SMESH._objref_SMESH_2D_Algo):
367 raise TypeError("ViscousLayers2D are supported by 2D algorithms only")
368 if not "ViscousLayers2D" in self.GetCompatibleHypothesis():
369 raise TypeError("ViscousLayers2D are not supported by %s"%self.algo.GetName())
370 if edges and not isinstance( edges, list ) and not isinstance( edges, tuple ):
372 if edges and isinstance( edges[0], geomBuilder.GEOM._objref_GEOM_Object ):
375 ee = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"])
377 edgeIDs.append( self.mesh.geompyD.GetSubShapeID( self.mesh.geom, e ))
379 hyp = self.Hypothesis("ViscousLayers2D",
380 [thickness, numberOfLayers, stretchFactor, edges, isEdgesToIgnore],
382 hyp.SetTotalThickness(thickness)
383 hyp.SetNumberLayers(numberOfLayers)
384 hyp.SetStretchFactor(stretchFactor)
385 hyp.SetEdges(edges, isEdgesToIgnore)
386 self.mesh.AddHypothesis( hyp, self.geom )
389 def ReversedEdgeIndices(self, reverseList):
391 Transform a list of either edges or tuples (edge, 1st_vertex_of_edge)
392 into a list acceptable to SetReversedEdges() of some 1D hypotheses
395 from salome.smesh.smeshBuilder import FirstVertexOnCurve
397 geompy = self.mesh.geompyD
398 for i in reverseList:
399 if isinstance( i, int ):
400 s = geompy.SubShapes(self.mesh.geom, [i])[0]
401 if s.GetShapeType() != geomBuilder.GEOM.EDGE:
402 raise TypeError("Not EDGE index given")
404 elif isinstance( i, geomBuilder.GEOM._objref_GEOM_Object ):
405 if i.GetShapeType() != geomBuilder.GEOM.EDGE:
406 raise TypeError("Not an EDGE given")
407 resList.append( geompy.GetSubShapeID(self.mesh.geom, i ))
411 if not isinstance( e, geomBuilder.GEOM._objref_GEOM_Object ) or \
412 not isinstance( v, geomBuilder.GEOM._objref_GEOM_Object ):
413 raise TypeError("A list item must be a tuple (edge, 1st_vertex_of_edge)")
414 if v.GetShapeType() == geomBuilder.GEOM.EDGE and \
415 e.GetShapeType() == geomBuilder.GEOM.VERTEX:
417 if e.GetShapeType() != geomBuilder.GEOM.EDGE or \
418 v.GetShapeType() != geomBuilder.GEOM.VERTEX:
419 raise TypeError("A list item must be a tuple (edge, 1st_vertex_of_edge)")
420 vFirst = FirstVertexOnCurve( self.mesh, e )
421 tol = geompy.Tolerance( vFirst )[-1]
422 if geompy.MinDistance( v, vFirst ) > 1.5*tol:
423 resList.append( geompy.GetSubShapeID(self.mesh.geom, e ))
425 raise TypeError("Item must be either an edge or tuple (edge, 1st_vertex_of_edge)")