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 Mesh (see e.g. class :class:`~StdMeshersBuilder.StdMeshersBuilder_Segment`
39 in StdMeshersBuilder package):
41 - :code:`meshMethod` attribute defines name of method of class smesh.Mesh by calling which the
42 python class of algorithm is created; this method is dynamically added to the smesh.Mesh class
43 in runtime. For example, if in :code:`class MyPlugin_Algorithm` this attribute is defined as
46 meshMethod = "MyAlgorithm"
48 then an instance of :code:`MyPlugin_Algorithm` can be created by the direct invocation of the function
52 my_algo = mesh.MyAlgorithm()
54 - :code:`algoType` defines type of algorithm and is used mostly to discriminate
55 algorithms that are created by the same method of class smesh.Mesh. For example, if this attribute
56 is specified in :code:`MyPlugin_Algorithm` class as
61 then it's creation code can be:
64 my_algo = mesh.MyAlgorithm(algo="MyPLUGIN")
78 def FindHypothesis (self, hypname, args, CompareMethod, smeshpyD):
80 Finds a hypothesis in the study by its type name and parameters.
81 Finds only the hypotheses created in smeshpyD engine.
83 SMESH.SMESH_Hypothesis
85 study = salome.myStudy
86 if not study: return None
87 #to do: find component by smeshpyD object, not by its data type
88 scomp = study.FindComponent(smeshpyD.ComponentDataType())
90 res,hypRoot = scomp.FindSubObject(SMESH.Tag_HypothesisRoot)
91 # Check if the root label of the hypotheses exists
92 if res and hypRoot is not None:
93 iter = study.NewChildIterator(hypRoot)
94 # Check all published hypotheses
96 hypo_so_i = iter.Value()
97 attr = hypo_so_i.FindAttribute("AttributeIOR")[1]
100 if not anIOR: continue # prevent exception in orb.string_to_object()
101 hypo_o_i = salome.orb.string_to_object(anIOR)
102 if hypo_o_i is not None:
103 # Check if this is a hypothesis
104 hypo_i = hypo_o_i._narrow(SMESH.SMESH_Hypothesis)
105 if hypo_i is not None:
106 # Check if the hypothesis belongs to current engine
107 if smeshpyD.GetObjectId(hypo_i) > 0:
108 # Check if this is the required hypothesis
109 if hypo_i.GetName() == hypname:
111 if CompareMethod(hypo_i, args):
125 def FindAlgorithm (self, algoname, smeshpyD):
127 Finds the algorithm in the study by its type name.
128 Finds only the algorithms, which have been created in smeshpyD engine.
133 study = salome.myStudy
134 if not study: return None
135 #to do: find component by smeshpyD object, not by its data type
136 scomp = study.FindComponent(smeshpyD.ComponentDataType())
137 if scomp is not None:
138 res,hypRoot = scomp.FindSubObject(SMESH.Tag_AlgorithmsRoot)
139 # Check if the root label of the algorithms exists
140 if res and hypRoot is not None:
141 iter = study.NewChildIterator(hypRoot)
142 # Check all published algorithms
144 algo_so_i = iter.Value()
145 attr = algo_so_i.FindAttribute("AttributeIOR")[1]
148 if not anIOR: continue # prevent exception in orb.string_to_object()
149 algo_o_i = salome.orb.string_to_object(anIOR)
150 if algo_o_i is not None:
151 # Check if this is an algorithm
152 algo_i = algo_o_i._narrow(SMESH.SMESH_Algo)
153 if algo_i is not None:
154 # Checks if the algorithm belongs to the current engine
155 if smeshpyD.GetObjectId(algo_i) > 0:
156 # Check if this is the required algorithm
157 if algo_i.GetName() == algoname:
170 def GetSubMesh(self):
172 If the algorithm is global, returns 0;
173 else returns the submesh associated to this algorithm.
177 def GetAlgorithm(self):
179 Returns the wrapped mesher.
183 def GetCompatibleHypothesis(self):
185 Gets the list of hypothesis that can be used with this algorithm
189 mylist = self.algo.GetCompatibleHypothesis()
194 Gets the name of the algorithm
196 from salome.smesh.smeshBuilder import GetName
197 return GetName(self.algo)
199 def SetName(self, name):
201 Sets the name to the algorithm
203 self.mesh.smeshpyD.SetName(self.algo, name)
207 Gets the id of the algorithm
209 return self.algo.GetId()
211 def Create(self, mesh, geom, hypo, so="libStdMeshersEngine.so"):
215 if geom is None and mesh.mesh.HasShapeToMesh():
216 raise RuntimeError("Attempt to create " + hypo + " algorithm on None shape")
217 algo = self.FindAlgorithm(hypo, mesh.smeshpyD)
219 algo = mesh.smeshpyD.CreateHypothesis(hypo, so)
221 self.Assign(algo, mesh, geom)
224 def Assign(self, algo, mesh, geom):
228 from salome.smesh.smeshBuilder import AssureGeomPublished, TreatHypoStatus, GetName
229 if geom is None and mesh.mesh.HasShapeToMesh():
230 raise RuntimeError("Attempt to create " + algo + " algorithm on None shape")
232 if not geom or geom.IsSame( mesh.geom ):
233 self.geom = mesh.geom
236 AssureGeomPublished( mesh, geom )
237 self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName())
239 status = mesh.AddHypothesis(self.algo, self.geom)
242 def CompareHyp (self, hyp, args):
243 print("CompareHyp is not implemented for ", self.__class__.__name__, ":", hyp.GetName())
246 def CompareEqualHyp (self, hyp, args):
249 def Hypothesis (self, hyp, args=[], so="libStdMeshersEngine.so",
250 UseExisting=0, CompareMethod="", toAdd=True):
254 from salome.smesh.smeshBuilder import TreatHypoStatus, GetName
257 if CompareMethod == "": CompareMethod = self.CompareHyp
258 hypo = self.FindHypothesis(hyp, args, CompareMethod, self.mesh.smeshpyD)
261 hypo = self.mesh.smeshpyD.CreateHypothesis(hyp, so)
266 if isinstance( arg, geomBuilder.GEOM._objref_GEOM_Object ):
267 argStr = arg.GetStudyEntry()
268 if not argStr: argStr = "GEOM_Obj_%s", arg.GetEntry()
269 if len( argStr ) > 10:
270 argStr = argStr[:7]+"..."
271 if argStr[0] == '[': argStr += ']'
277 self.mesh.smeshpyD.SetName(hypo, hyp + a)
281 geomName = GetName(self.geom)
283 status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
284 TreatHypoStatus( status, GetName(hypo), geomName, 0, self.mesh )
287 def MainShapeEntry(self):
289 Returns entry of the shape to mesh in the study
291 if not self.mesh or not self.mesh.GetMesh(): return ""
292 if not self.mesh.GetMesh().HasShapeToMesh(): return ""
293 shape = self.mesh.GetShape()
294 return shape.GetStudyEntry()
296 def ViscousLayers(self, thickness, numberOfLayers, stretchFactor,
297 faces=[], isFacesToIgnore=True, extrMethod=StdMeshers.SURF_OFFSET_SMOOTH ):
299 Defines "ViscousLayers" hypothesis to give parameters of layers of prisms to build
300 near mesh boundary. This hypothesis can be used by several 3D algorithms:
301 NETGEN 3D, MG-Tetra, Hexahedron(i,j,k)
304 thickness: total thickness of layers of prisms
305 numberOfLayers: number of layers of prisms
306 stretchFactor: factor (>1.0) of growth of layer thickness towards inside of mesh
307 faces: list of geometrical faces (or their ids).
308 Viscous layers are either generated on these faces or not, depending on
309 the value of **isFacesToIgnore** parameter.
310 isFacesToIgnore: if *True*, the Viscous layers are not generated on the
311 faces specified by the previous parameter (**faces**).
312 extrMethod: extrusion method defines how position of new nodes are found during
313 prism construction and how creation of distorted and intersecting prisms is
314 prevented. Possible values are:
316 - StdMeshers.SURF_OFFSET_SMOOTH (default) method extrudes nodes along normal
317 to underlying geometrical surface. Smoothing of internal surface of
318 element layers can be used to avoid creation of invalid prisms.
319 - StdMeshers.FACE_OFFSET method extrudes nodes along average normal of
320 surrounding mesh faces till intersection with a neighbor mesh face
321 translated along its own normal by the layers thickness. Thickness
322 of layers can be limited to avoid creation of invalid prisms.
323 - StdMeshers.NODE_OFFSET method extrudes nodes along average normal of
324 surrounding mesh faces by the layers thickness. Thickness of
325 layers can be limited to avoid creation of invalid prisms.
328 if not isinstance(self.algo, SMESH._objref_SMESH_3D_Algo):
329 raise TypeError("ViscousLayers are supported by 3D algorithms only")
330 if not "ViscousLayers" in self.GetCompatibleHypothesis():
331 raise TypeError("ViscousLayers are not supported by %s"%self.algo.GetName())
332 if faces and isinstance( faces, geomBuilder.GEOM._objref_GEOM_Object ):
334 if faces and isinstance( faces[0], geomBuilder.GEOM._objref_GEOM_Object ):
337 ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] )
339 faceIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f))
341 hyp = self.Hypothesis("ViscousLayers",
342 [thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore],
344 hyp.SetTotalThickness( thickness )
345 hyp.SetNumberLayers( numberOfLayers )
346 hyp.SetStretchFactor( stretchFactor )
347 hyp.SetFaces( faces, isFacesToIgnore )
348 hyp.SetMethod( extrMethod )
349 self.mesh.AddHypothesis( hyp, self.geom )
352 def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor,
353 edges=[], isEdgesToIgnore=True ):
355 Defines "ViscousLayers2D" hypothesis to give parameters of layers of quadrilateral
356 elements to build near mesh boundary. This hypothesis can be used by several 2D algorithms:
357 NETGEN 2D, NETGEN 1D-2D, Quadrangle (mapping), MEFISTO, MG-CADSurf
360 thickness: total thickness of layers of quadrilaterals
361 numberOfLayers: number of layers
362 stretchFactor: factor (>1.0) of growth of layer thickness towards inside of mesh
363 edges: list of geometrical edges (or their ids).
364 Viscous layers are either generated on these edges or not, depending on
365 the value of **isEdgesToIgnore** parameter.
366 isEdgesToIgnore: if *True*, the Viscous layers are not generated on the
367 edges specified by the previous parameter (**edges**).
370 if not isinstance(self.algo, SMESH._objref_SMESH_2D_Algo):
371 raise TypeError("ViscousLayers2D are supported by 2D algorithms only")
372 if not "ViscousLayers2D" in self.GetCompatibleHypothesis():
373 raise TypeError("ViscousLayers2D are not supported by %s"%self.algo.GetName())
374 if edges and not isinstance( edges, list ) and not isinstance( edges, tuple ):
376 if edges and isinstance( edges[0], geomBuilder.GEOM._objref_GEOM_Object ):
379 ee = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"])
381 edgeIDs.append( self.mesh.geompyD.GetSubShapeID( self.mesh.geom, e ))
383 hyp = self.Hypothesis("ViscousLayers2D",
384 [thickness, numberOfLayers, stretchFactor, edges, isEdgesToIgnore],
386 hyp.SetTotalThickness(thickness)
387 hyp.SetNumberLayers(numberOfLayers)
388 hyp.SetStretchFactor(stretchFactor)
389 hyp.SetEdges(edges, isEdgesToIgnore)
390 self.mesh.AddHypothesis( hyp, self.geom )
393 def ReversedEdgeIndices(self, reverseList):
395 Transform a list of either edges or tuples (edge, 1st_vertex_of_edge)
396 into a list acceptable to SetReversedEdges() of some 1D hypotheses
399 from salome.smesh.smeshBuilder import FirstVertexOnCurve
401 geompy = self.mesh.geompyD
402 for i in reverseList:
403 if isinstance( i, int ):
404 s = geompy.SubShapes(self.mesh.geom, [i])[0]
405 if s.GetShapeType() != geomBuilder.GEOM.EDGE:
406 raise TypeError("Not EDGE index given")
408 elif isinstance( i, geomBuilder.GEOM._objref_GEOM_Object ):
409 if i.GetShapeType() != geomBuilder.GEOM.EDGE:
410 raise TypeError("Not an EDGE given")
411 resList.append( geompy.GetSubShapeID(self.mesh.geom, i ))
415 if not isinstance( e, geomBuilder.GEOM._objref_GEOM_Object ) or \
416 not isinstance( v, geomBuilder.GEOM._objref_GEOM_Object ):
417 raise TypeError("A list item must be a tuple (edge, 1st_vertex_of_edge)")
418 if v.GetShapeType() == geomBuilder.GEOM.EDGE and \
419 e.GetShapeType() == geomBuilder.GEOM.VERTEX:
421 if e.GetShapeType() != geomBuilder.GEOM.EDGE or \
422 v.GetShapeType() != geomBuilder.GEOM.VERTEX:
423 raise TypeError("A list item must be a tuple (edge, 1st_vertex_of_edge)")
424 vFirst = FirstVertexOnCurve( self.mesh, e )
425 tol = geompy.Tolerance( vFirst )[-1]
426 if geompy.MinDistance( v, vFirst ) > 1.5*tol:
427 resList.append( geompy.GetSubShapeID(self.mesh.geom, e ))
429 raise TypeError("Item must be either an edge or tuple (edge, 1st_vertex_of_edge)")