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
28 ## The base class to define meshing algorithms
30 # @note This class should not be used directly, it is supposed to be sub-classed
31 # for implementing Python API for specific meshing algorithms
33 # For each meshing algorithm, a python class inheriting from class %Mesh_Algorithm
34 # should be defined. This descendant class should have two attributes defining the way
35 # it is created by class Mesh (see e.g. class @ref StdMeshersBuilder.StdMeshersBuilder_Segment "StdMeshersBuilder_Segment"
36 # in StdMeshersBuilder package):
37 # - @c meshMethod attribute defines name of method of class smesh.Mesh by calling which the
38 # python class of algorithm is created; this method is dynamically added to the smesh.Mesh class
39 # in runtime. For example, if in @c class MyPlugin_Algorithm this attribute is defined as
41 # meshMethod = "MyAlgorithm"
43 # then an instance of @c MyPlugin_Algorithm can be created by the direct invocation of the function
44 # of smesh.Mesh class:
46 # my_algo = mesh.MyAlgorithm()
48 # - @c algoType defines type of algorithm and is used mostly to discriminate
49 # algorithms that are created by the same method of class smesh.Mesh. For example, if this attribute
50 # is specified in @c MyPlugin_Algorithm class as
52 # algoType = "MyPLUGIN"
54 # then it's creation code can be:
56 # my_algo = mesh.MyAlgorithm(algo="MyPLUGIN")
58 # @ingroup l2_algorithms
69 ## Finds a hypothesis in the study by its type name and parameters.
70 # Finds only the hypotheses created in smeshpyD engine.
71 # @return SMESH.SMESH_Hypothesis
72 def FindHypothesis (self, hypname, args, CompareMethod, smeshpyD):
73 study = smeshpyD.GetCurrentStudy()
74 if not study: return None
75 #to do: find component by smeshpyD object, not by its data type
76 scomp = study.FindComponent(smeshpyD.ComponentDataType())
78 res,hypRoot = scomp.FindSubObject(SMESH.Tag_HypothesisRoot)
79 # Check if the root label of the hypotheses exists
80 if res and hypRoot is not None:
81 iter = study.NewChildIterator(hypRoot)
82 # Check all published hypotheses
84 hypo_so_i = iter.Value()
85 attr = hypo_so_i.FindAttribute("AttributeIOR")[1]
88 if not anIOR: continue # prevent exception in orb.string_to_object()
89 hypo_o_i = salome.orb.string_to_object(anIOR)
90 if hypo_o_i is not None:
91 # Check if this is a hypothesis
92 hypo_i = hypo_o_i._narrow(SMESH.SMESH_Hypothesis)
93 if hypo_i is not None:
94 # Check if the hypothesis belongs to current engine
95 if smeshpyD.GetObjectId(hypo_i) > 0:
96 # Check if this is the required hypothesis
97 if hypo_i.GetName() == hypname:
99 if CompareMethod(hypo_i, args):
113 ## Finds the algorithm in the study by its type name.
114 # Finds only the algorithms, which have been created in smeshpyD engine.
115 # @return SMESH.SMESH_Algo
116 def FindAlgorithm (self, algoname, smeshpyD):
117 study = smeshpyD.GetCurrentStudy()
118 if not study: return None
119 #to do: find component by smeshpyD object, not by its data type
120 scomp = study.FindComponent(smeshpyD.ComponentDataType())
121 if scomp is not None:
122 res,hypRoot = scomp.FindSubObject(SMESH.Tag_AlgorithmsRoot)
123 # Check if the root label of the algorithms exists
124 if res and hypRoot is not None:
125 iter = study.NewChildIterator(hypRoot)
126 # Check all published algorithms
128 algo_so_i = iter.Value()
129 attr = algo_so_i.FindAttribute("AttributeIOR")[1]
132 if not anIOR: continue # prevent exception in orb.string_to_object()
133 algo_o_i = salome.orb.string_to_object(anIOR)
134 if algo_o_i is not None:
135 # Check if this is an algorithm
136 algo_i = algo_o_i._narrow(SMESH.SMESH_Algo)
137 if algo_i is not None:
138 # Checks if the algorithm belongs to the current engine
139 if smeshpyD.GetObjectId(algo_i) > 0:
140 # Check if this is the required algorithm
141 if algo_i.GetName() == algoname:
154 ## If the algorithm is global, returns 0; \n
155 # else returns the submesh associated to this algorithm.
156 def GetSubMesh(self):
159 ## Returns the wrapped mesher.
160 def GetAlgorithm(self):
163 ## Gets the list of hypothesis that can be used with this algorithm
164 def GetCompatibleHypothesis(self):
167 mylist = self.algo.GetCompatibleHypothesis()
170 ## Gets the name of the algorithm
172 from salome.smesh.smeshBuilder import GetName
173 return GetName(self.algo)
175 ## Sets the name to the algorithm
176 def SetName(self, name):
177 self.mesh.smeshpyD.SetName(self.algo, name)
179 ## Gets the id of the algorithm
181 return self.algo.GetId()
184 def Create(self, mesh, geom, hypo, so="libStdMeshersEngine.so"):
185 if geom is None and mesh.mesh.HasShapeToMesh():
186 raise RuntimeError, "Attempt to create " + hypo + " algorithm on None shape"
187 algo = self.FindAlgorithm(hypo, mesh.smeshpyD)
189 algo = mesh.smeshpyD.CreateHypothesis(hypo, so)
191 self.Assign(algo, mesh, geom)
195 def Assign(self, algo, mesh, geom):
196 from salome.smesh.smeshBuilder import AssureGeomPublished, TreatHypoStatus, GetName
197 if geom is None and mesh.mesh.HasShapeToMesh():
198 raise RuntimeError, "Attempt to create " + algo + " algorithm on None shape"
200 if not geom or geom.IsSame( mesh.geom ):
201 self.geom = mesh.geom
204 AssureGeomPublished( mesh, geom )
205 self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName())
207 status = mesh.AddHypothesis(self.algo, self.geom)
210 def CompareHyp (self, hyp, args):
211 print "CompareHyp is not implemented for ", self.__class__.__name__, ":", hyp.GetName()
214 def CompareEqualHyp (self, hyp, args):
218 def Hypothesis (self, hyp, args=[], so="libStdMeshersEngine.so",
219 UseExisting=0, CompareMethod="", toAdd=True):
220 from salome.smesh.smeshBuilder import TreatHypoStatus, GetName
223 if CompareMethod == "": CompareMethod = self.CompareHyp
224 hypo = self.FindHypothesis(hyp, args, CompareMethod, self.mesh.smeshpyD)
227 hypo = self.mesh.smeshpyD.CreateHypothesis(hyp, so)
232 if isinstance( arg, geomBuilder.GEOM._objref_GEOM_Object ):
233 argStr = arg.GetStudyEntry()
234 if not argStr: argStr = "GEOM_Obj_%s", arg.GetEntry()
235 if len( argStr ) > 10:
236 argStr = argStr[:7]+"..."
237 if argStr[0] == '[': argStr += ']'
243 self.mesh.smeshpyD.SetName(hypo, hyp + a)
247 geomName = GetName(self.geom)
249 status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
250 TreatHypoStatus( status, GetName(hypo), geomName, 0, self.mesh )
253 ## Returns entry of the shape to mesh in the study
254 def MainShapeEntry(self):
255 if not self.mesh or not self.mesh.GetMesh(): return ""
256 if not self.mesh.GetMesh().HasShapeToMesh(): return ""
257 shape = self.mesh.GetShape()
258 return shape.GetStudyEntry()
260 ## Defines "ViscousLayers" hypothesis to give parameters of layers of prisms to build
261 # near mesh boundary. This hypothesis can be used by several 3D algorithms:
262 # NETGEN 3D, MG-Tetra, Hexahedron(i,j,k)
263 # @param thickness total thickness of layers of prisms
264 # @param numberOfLayers number of layers of prisms
265 # @param stretchFactor factor (>1.0) of growth of layer thickness towards inside of mesh
266 # @param faces list of geometrical faces (or their ids).
267 # Viscous layers are either generated on these faces or not, depending on
268 # the value of \a isFacesToIgnore parameter.
269 # @param isFacesToIgnore if \c True, the Viscous layers are not generated on the
270 # faces specified by the previous parameter (\a faces).
271 # @param extrMethod extrusion method defines how position of new nodes are found during
272 # prism construction and how creation of distorted and intersecting prisms is
273 # prevented. Possible values are:
274 # - StdMeshers.SURF_OFFSET_SMOOTH (default) method extrudes nodes along normal
275 # to underlying geometrical surface. Smoothing of internal surface of
276 # element layers can be used to avoid creation of invalid prisms.
277 # - StdMeshers.FACE_OFFSET method extrudes nodes along average normal of
278 # surrounding mesh faces till intersection with a neighbor mesh face
279 # translated along its own normal by the layers thickness. Thickness
280 # of layers can be limited to avoid creation of invalid prisms.
281 # - StdMeshers.NODE_OFFSET method extrudes nodes along average normal of
282 # surrounding mesh faces by the layers thickness. Thickness of
283 # layers can be limited to avoid creation of invalid prisms.
284 # @ingroup l3_hypos_additi
285 def ViscousLayers(self, thickness, numberOfLayers, stretchFactor,
286 faces=[], isFacesToIgnore=True, extrMethod=StdMeshers.SURF_OFFSET_SMOOTH ):
287 if not isinstance(self.algo, SMESH._objref_SMESH_3D_Algo):
288 raise TypeError, "ViscousLayers are supported by 3D algorithms only"
289 if not "ViscousLayers" in self.GetCompatibleHypothesis():
290 raise TypeError, "ViscousLayers are not supported by %s"%self.algo.GetName()
291 if faces and isinstance( faces, geomBuilder.GEOM._objref_GEOM_Object ):
293 if faces and isinstance( faces[0], geomBuilder.GEOM._objref_GEOM_Object ):
296 ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] )
298 faceIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f))
300 hyp = self.Hypothesis("ViscousLayers",
301 [thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore],
303 hyp.SetTotalThickness( thickness )
304 hyp.SetNumberLayers( numberOfLayers )
305 hyp.SetStretchFactor( stretchFactor )
306 hyp.SetFaces( faces, isFacesToIgnore )
307 hyp.SetMethod( extrMethod )
308 self.mesh.AddHypothesis( hyp, self.geom )
311 ## Defines "ViscousLayers2D" hypothesis to give parameters of layers of quadrilateral
312 # elements to build near mesh boundary. This hypothesis can be used by several 2D algorithms:
313 # NETGEN 2D, NETGEN 1D-2D, Quadrangle (mapping), MEFISTO, MG-CADSurf
314 # @param thickness total thickness of layers of quadrilaterals
315 # @param numberOfLayers number of layers
316 # @param stretchFactor factor (>1.0) of growth of layer thickness towards inside of mesh
317 # @param edges list of geometrical edges (or their ids).
318 # Viscous layers are either generated on these edges or not, depending on
319 # the value of \a isEdgesToIgnore parameter.
320 # @param isEdgesToIgnore if \c True, the Viscous layers are not generated on the
321 # edges specified by the previous parameter (\a edges).
322 # @ingroup l3_hypos_additi
323 def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor,
324 edges=[], isEdgesToIgnore=True ):
325 if not isinstance(self.algo, SMESH._objref_SMESH_2D_Algo):
326 raise TypeError, "ViscousLayers2D are supported by 2D algorithms only"
327 if not "ViscousLayers2D" in self.GetCompatibleHypothesis():
328 raise TypeError, "ViscousLayers2D are not supported by %s"%self.algo.GetName()
329 if edges and not isinstance( edges, list ) and not isinstance( edges, tuple ):
331 if edges and isinstance( edges[0], geomBuilder.GEOM._objref_GEOM_Object ):
334 ee = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"])
336 edgeIDs.append( self.mesh.geompyD.GetSubShapeID( self.mesh.geom, e ))
338 hyp = self.Hypothesis("ViscousLayers2D",
339 [thickness, numberOfLayers, stretchFactor, edges, isEdgesToIgnore],
341 hyp.SetTotalThickness(thickness)
342 hyp.SetNumberLayers(numberOfLayers)
343 hyp.SetStretchFactor(stretchFactor)
344 hyp.SetEdges(edges, isEdgesToIgnore)
345 self.mesh.AddHypothesis( hyp, self.geom )
348 ## Transform a list of either edges or tuples (edge, 1st_vertex_of_edge)
349 # into a list acceptable to SetReversedEdges() of some 1D hypotheses
350 # @ingroup l3_hypos_1dhyps
351 def ReversedEdgeIndices(self, reverseList):
352 from salome.smesh.smeshBuilder import FirstVertexOnCurve
354 geompy = self.mesh.geompyD
355 for i in reverseList:
356 if isinstance( i, int ):
357 s = geompy.SubShapes(self.mesh.geom, [i])[0]
358 if s.GetShapeType() != geomBuilder.GEOM.EDGE:
359 raise TypeError, "Not EDGE index given"
361 elif isinstance( i, geomBuilder.GEOM._objref_GEOM_Object ):
362 if i.GetShapeType() != geomBuilder.GEOM.EDGE:
363 raise TypeError, "Not an EDGE given"
364 resList.append( geompy.GetSubShapeID(self.mesh.geom, i ))
368 if not isinstance( e, geomBuilder.GEOM._objref_GEOM_Object ) or \
369 not isinstance( v, geomBuilder.GEOM._objref_GEOM_Object ):
370 raise TypeError, "A list item must be a tuple (edge, 1st_vertex_of_edge)"
371 if v.GetShapeType() == geomBuilder.GEOM.EDGE and \
372 e.GetShapeType() == geomBuilder.GEOM.VERTEX:
374 if e.GetShapeType() != geomBuilder.GEOM.EDGE or \
375 v.GetShapeType() != geomBuilder.GEOM.VERTEX:
376 raise TypeError, "A list item must be a tuple (edge, 1st_vertex_of_edge)"
377 vFirst = FirstVertexOnCurve( self.mesh, e )
378 tol = geompy.Tolerance( vFirst )[-1]
379 if geompy.MinDistance( v, vFirst ) > 1.5*tol:
380 resList.append( geompy.GetSubShapeID(self.mesh.geom, e ))
382 raise TypeError, "Item must be either an edge or tuple (edge, 1st_vertex_of_edge)"