Salome HOME
c686068866683f35e374b5b6ad4f59c50fe53dbd
[modules/smesh.git] / src / SMESH_SWIG / smesh_algorithm.py
1 # Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 #
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.
7 #
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.
12 #
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
16 #
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 #
19
20 ## @package smesh_algorithm
21 #  Python API for base Mesh_Algorithm class.
22 #  This package is a part of SALOME %Mesh module Python API
23
24 import salome
25 from salome.geom import geomBuilder
26 import SMESH, StdMeshers
27
28 ## The base class to define meshing algorithms
29 #
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
32 #
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
40 #    @code
41 #    meshMethod = "MyAlgorithm"
42 #    @endcode
43 #    then an instance of @c MyPlugin_Algorithm can be created by the direct invocation of the function
44 #    of smesh.Mesh class:
45 #    @code
46 #    my_algo = mesh.MyAlgorithm()
47 #    @endcode
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
51 #    @code
52 #    algoType = "MyPLUGIN"
53 #    @endcode
54 #    then it's creation code can be:
55 #    @code
56 #    my_algo = mesh.MyAlgorithm(algo="MyPLUGIN")
57 #    @endcode
58 #  @ingroup l2_algorithms
59 class Mesh_Algorithm:
60     
61     ## Private constuctor
62     def __init__(self):
63         self.mesh = None
64         self.geom = None
65         self.subm = None
66         self.algo = None
67         pass
68
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())
77         if scomp is not None:
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
83                 while iter.More():
84                     hypo_so_i = iter.Value()
85                     attr = hypo_so_i.FindAttribute("AttributeIOR")[1]
86                     if attr is not None:
87                         anIOR = attr.Value()
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:
98                                         # Check arguments
99                                         if CompareMethod(hypo_i, args):
100                                             # found!!!
101                                             return hypo_i
102                                         pass
103                                     pass
104                                 pass
105                             pass
106                         pass
107                     iter.Next()
108                     pass
109                 pass
110             pass
111         return None
112
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
127                 while iter.More():
128                     algo_so_i = iter.Value()
129                     attr = algo_so_i.FindAttribute("AttributeIOR")[1]
130                     if attr is not None:
131                         anIOR = attr.Value()
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:
142                                         # found!!!
143                                         return algo_i
144                                     pass
145                                 pass
146                             pass
147                         pass
148                     iter.Next()
149                     pass
150                 pass
151             pass
152         return None
153
154     ## If the algorithm is global, returns 0; \n
155     #  else returns the submesh associated to this algorithm.
156     def GetSubMesh(self):
157         return self.subm
158
159     ## Returns the wrapped mesher.
160     def GetAlgorithm(self):
161         return self.algo
162
163     ## Gets the list of hypothesis that can be used with this algorithm
164     def GetCompatibleHypothesis(self):
165         mylist = []
166         if self.algo:
167             mylist = self.algo.GetCompatibleHypothesis()
168         return mylist
169
170     ## Gets the name of the algorithm
171     def GetName(self):
172         from salome.smesh.smeshBuilder import GetName
173         return GetName(self.algo)
174
175     ## Sets the name to the algorithm
176     def SetName(self, name):
177         self.mesh.smeshpyD.SetName(self.algo, name)
178
179     ## Gets the id of the algorithm
180     def GetId(self):
181         return self.algo.GetId()
182
183     ## Private method.
184     def Create(self, mesh, geom, hypo, so="libStdMeshersEngine.so"):
185         if geom is None and mesh.mesh.HasShapeToMesh():
186             raise RuntimeError, "Attemp to create " + hypo + " algorithm on None shape"
187         algo = self.FindAlgorithm(hypo, mesh.smeshpyD)
188         if algo is None:
189             algo = mesh.smeshpyD.CreateHypothesis(hypo, so)
190             pass
191         self.Assign(algo, mesh, geom)
192         return self.algo
193
194     ## Private method
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, "Attemp to create " + algo + " algorithm on None shape"
199         self.mesh = mesh
200         if not geom or geom.IsSame( mesh.geom ):
201             self.geom = mesh.geom
202         else:
203             self.geom = geom
204             AssureGeomPublished( mesh, geom )
205             self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName())
206         self.algo = algo
207         status = mesh.AddHypothesis(self.algo, self.geom)
208         return
209
210     def CompareHyp (self, hyp, args):
211         print "CompareHyp is not implemented for ", self.__class__.__name__, ":", hyp.GetName()
212         return False
213
214     def CompareEqualHyp (self, hyp, args):
215         return True
216
217     ## Private method
218     def Hypothesis (self, hyp, args=[], so="libStdMeshersEngine.so",
219                     UseExisting=0, CompareMethod="", toAdd=True):
220         from salome.smesh.smeshBuilder import TreatHypoStatus, GetName
221         hypo = None
222         if UseExisting:
223             if CompareMethod == "": CompareMethod = self.CompareHyp
224             hypo = self.FindHypothesis(hyp, args, CompareMethod, self.mesh.smeshpyD)
225             pass
226         if hypo is None:
227             hypo = self.mesh.smeshpyD.CreateHypothesis(hyp, so)
228             a = ""
229             s = "="
230             for arg in args:
231                 argStr = str(arg)
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 += ']'
238                 a = a + s + argStr
239                 s = ","
240                 pass
241             if len(a) > 50:
242                 a = a[:47]+"..."
243             self.mesh.smeshpyD.SetName(hypo, hyp + a)
244             pass
245         geomName=""
246         if self.geom:
247             geomName = GetName(self.geom)
248         if toAdd:
249             status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
250             TreatHypoStatus( status, GetName(hypo), geomName, 0, self.mesh )
251         return hypo
252
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()
259
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[0], geomBuilder.GEOM._objref_GEOM_Object ):
292             faceIDs = []
293             for shape in faces:
294                 ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] )
295                 for f in ff:
296                     faceIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f))
297             faces = faceIDs
298         hyp = self.Hypothesis("ViscousLayers",
299                               [thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore],
300                               toAdd=False)
301         hyp.SetTotalThickness( thickness )
302         hyp.SetNumberLayers( numberOfLayers )
303         hyp.SetStretchFactor( stretchFactor )
304         hyp.SetFaces( faces, isFacesToIgnore )
305         hyp.SetMethod( extrMethod )
306         self.mesh.AddHypothesis( hyp, self.geom )
307         return hyp
308
309     ## Defines "ViscousLayers2D" hypothesis to give parameters of layers of quadrilateral
310     #  elements to build near mesh boundary. This hypothesis can be used by several 2D algorithms:
311     #  NETGEN 2D, NETGEN 1D-2D, Quadrangle (mapping), MEFISTO, MG-CADSurf
312     #  @param thickness total thickness of layers of quadrilaterals
313     #  @param numberOfLayers number of layers
314     #  @param stretchFactor factor (>1.0) of growth of layer thickness towards inside of mesh
315     #  @param edges list of geometrical edges (or their ids).
316     #         Viscous layers are either generated on these edges or not, depending on
317     #         the value of \a isEdgesToIgnore parameter.
318     #  @param isEdgesToIgnore if \c True, the Viscous layers are not generated on the
319     #         edges specified by the previous parameter (\a edges).
320     #  @ingroup l3_hypos_additi
321     def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor,
322                         edges=[], isEdgesToIgnore=True ):
323         if not isinstance(self.algo, SMESH._objref_SMESH_2D_Algo):
324             raise TypeError, "ViscousLayers2D are supported by 2D algorithms only"
325         if not "ViscousLayers2D" in self.GetCompatibleHypothesis():
326             raise TypeError, "ViscousLayers2D are not supported by %s"%self.algo.GetName()
327         if edges and isinstance( edges[0], geomBuilder.GEOM._objref_GEOM_Object ):
328             edgeIDs = []
329             for shape in edges:
330                 ee = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"])
331                 for e in ee:
332                     edgeIDs.append( self.mesh.geompyD.GetSubShapeID( self.mesh.geom, e ))
333             edges = edgeIDs
334         hyp = self.Hypothesis("ViscousLayers2D",
335                               [thickness, numberOfLayers, stretchFactor, edges, isEdgesToIgnore],
336                               toAdd=False)
337         hyp.SetTotalThickness(thickness)
338         hyp.SetNumberLayers(numberOfLayers)
339         hyp.SetStretchFactor(stretchFactor)
340         hyp.SetEdges(edges, isEdgesToIgnore)
341         self.mesh.AddHypothesis( hyp, self.geom )
342         return hyp
343
344     ## Transform a list of either edges or tuples (edge, 1st_vertex_of_edge)
345     #  into a list acceptable to SetReversedEdges() of some 1D hypotheses
346     #  @ingroup l3_hypos_1dhyps
347     def ReversedEdgeIndices(self, reverseList):
348         from salome.smesh.smeshBuilder import FirstVertexOnCurve
349         resList = []
350         geompy = self.mesh.geompyD
351         for i in reverseList:
352             if isinstance( i, int ):
353                 s = geompy.SubShapes(self.mesh.geom, [i])[0]
354                 if s.GetShapeType() != geomBuilder.GEOM.EDGE:
355                     raise TypeError, "Not EDGE index given"
356                 resList.append( i )
357             elif isinstance( i, geomBuilder.GEOM._objref_GEOM_Object ):
358                 if i.GetShapeType() != geomBuilder.GEOM.EDGE:
359                     raise TypeError, "Not an EDGE given"
360                 resList.append( geompy.GetSubShapeID(self.mesh.geom, i ))
361             elif len( i ) > 1:
362                 e = i[0]
363                 v = i[1]
364                 if not isinstance( e, geomBuilder.GEOM._objref_GEOM_Object ) or \
365                    not isinstance( v, geomBuilder.GEOM._objref_GEOM_Object ):
366                     raise TypeError, "A list item must be a tuple (edge, 1st_vertex_of_edge)"
367                 if v.GetShapeType() == geomBuilder.GEOM.EDGE and \
368                    e.GetShapeType() == geomBuilder.GEOM.VERTEX:
369                     v,e = e,v
370                 if e.GetShapeType() != geomBuilder.GEOM.EDGE or \
371                    v.GetShapeType() != geomBuilder.GEOM.VERTEX:
372                     raise TypeError, "A list item must be a tuple (edge, 1st_vertex_of_edge)"
373                 vFirst = FirstVertexOnCurve( self.mesh, e )
374                 tol    = geompy.Tolerance( vFirst )[-1]
375                 if geompy.MinDistance( v, vFirst ) > 1.5*tol:
376                     resList.append( geompy.GetSubShapeID(self.mesh.geom, e ))
377             else:
378                 raise TypeError, "Item must be either an edge or tuple (edge, 1st_vertex_of_edge)"
379         return resList
380