Salome HOME
Typo-fix by Kunda + fix user doc generation
[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 class Mesh_Algorithm:
29     """
30     The base class to define meshing algorithms
31
32     Note:
33         This class should not be used directly, it is supposed to be sub-classed
34         for implementing Python API for specific meshing algorithms
35
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`):
39
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::
43
44           meshMethod = "MyAlgorithm"
45
46       then an instance of :code:`MyPlugin_Algorithm` can be created by the direct invocation of the function
47       of :class:`~smeshBuilder.Mesh` class::
48     
49           my_algo = mesh.MyAlgorithm()
50     
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::
54     
55           algoType = "MyPLUGIN"
56
57       then it's creation code can be::
58
59           my_algo = mesh.MyAlgorithm(algo="MyPLUGIN")
60     """
61     
62     
63     def __init__(self):
64         """
65         Private constructor
66         """
67         self.mesh = None
68         self.geom = None
69         self.subm = None
70         self.algo = None
71         pass
72
73     def FindHypothesis (self, hypname, args, CompareMethod, smeshpyD):
74         """
75         Finds a hypothesis in the study by its type name and parameters.
76         Finds only the hypotheses created in smeshBuilder engine.
77         Returns: 
78                 :class:`~SMESH.SMESH_Hypothesis`
79         """
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())
84         if scomp is not None:
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
90                 while iter.More():
91                     hypo_so_i = iter.Value()
92                     attr = hypo_so_i.FindAttribute("AttributeIOR")[1]
93                     if attr is not None:
94                         anIOR = attr.Value()
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:
105                                         # Check arguments
106                                         if CompareMethod(hypo_i, args):
107                                             # found!!!
108                                             return hypo_i
109                                         pass
110                                     pass
111                                 pass
112                             pass
113                         pass
114                     iter.Next()
115                     pass
116                 pass
117             pass
118         return None
119
120     def FindAlgorithm (self, algoname, smeshpyD):
121         """
122         Finds the algorithm in the study by its type name.
123         Finds only the algorithms, which have been created in smeshBuilder engine.
124
125         Returns:
126                 SMESH.SMESH_Algo
127         """
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
138                 while iter.More():
139                     algo_so_i = iter.Value()
140                     attr = algo_so_i.FindAttribute("AttributeIOR")[1]
141                     if attr is not None:
142                         anIOR = attr.Value()
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:
153                                         # found!!!
154                                         return algo_i
155                                     pass
156                                 pass
157                             pass
158                         pass
159                     iter.Next()
160                     pass
161                 pass
162             pass
163         return None
164
165     def GetSubMesh(self):
166         """
167         If the algorithm is global, returns 0; 
168         else returns the :class:`~SMESH.SMESH_subMesh` associated to this algorithm.
169         """
170         return self.subm
171
172     def GetAlgorithm(self):
173         """
174         Returns the wrapped mesher.
175         """
176         return self.algo
177
178     def GetCompatibleHypothesis(self):
179         """
180         Gets the list of hypothesis that can be used with this algorithm
181         """
182         mylist = []
183         if self.algo:
184             mylist = self.algo.GetCompatibleHypothesis()
185         return mylist
186
187     def GetName(self):
188         """
189         Gets the name of the algorithm
190         """
191         from salome.smesh.smeshBuilder import GetName
192         return GetName(self.algo)
193
194     def SetName(self, name):
195         """
196         Sets the name to the algorithm
197         """
198         self.mesh.smeshpyD.SetName(self.algo, name)
199
200     def GetId(self):
201         """
202         Gets the id of the algorithm
203         """
204         return self.algo.GetId()
205
206     def Create(self, mesh, geom, hypo, so="libStdMeshersEngine.so"):
207         """
208         Private method.
209         """
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)
213         if algo is None:
214             algo = mesh.smeshpyD.CreateHypothesis(hypo, so)
215             pass
216         self.Assign(algo, mesh, geom)
217         return self.algo
218
219     def Assign(self, algo, mesh, geom):
220         """
221         Private method
222         """
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")
226         self.mesh = mesh
227         if not geom or geom.IsSame( mesh.geom ):
228             self.geom = mesh.geom
229         else:
230             self.geom = geom
231             AssureGeomPublished( mesh, geom )
232             self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName())
233         self.algo = algo
234         status = mesh.AddHypothesis(self.algo, self.geom)
235         return
236
237     def CompareHyp (self, hyp, args):
238         print("CompareHyp is not implemented for ", self.__class__.__name__, ":", hyp.GetName())
239         return False
240
241     def CompareEqualHyp (self, hyp, args):
242         return True
243
244     def Hypothesis (self, hyp, args=[], so="libStdMeshersEngine.so",
245                     UseExisting=0, CompareMethod="", toAdd=True):
246         """
247         Private method
248         """
249         from salome.smesh.smeshBuilder import TreatHypoStatus, GetName
250         hypo = None
251         if UseExisting:
252             if CompareMethod == "": CompareMethod = self.CompareHyp
253             hypo = self.FindHypothesis(hyp, args, CompareMethod, self.mesh.smeshpyD)
254             pass
255         if hypo is None:
256             hypo = self.mesh.smeshpyD.CreateHypothesis(hyp, so)
257             a = ""
258             s = "="
259             for arg in args:
260                 argStr = str(arg)
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 += ']'
267                 a = a + s + argStr
268                 s = ","
269                 pass
270             if len(a) > 50:
271                 a = a[:47]+"..."
272             self.mesh.smeshpyD.SetName(hypo, hyp + a)
273             pass
274         geomName=""
275         if self.geom:
276             geomName = GetName(self.geom)
277         if toAdd:
278             status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
279             TreatHypoStatus( status, GetName(hypo), geomName, 0, self.mesh )
280         return hypo
281
282     def MainShapeEntry(self):
283         """
284         Returns entry of the shape to mesh in the study
285         """
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()
290
291     def ViscousLayers(self, thickness, numberOfLayers, stretchFactor,
292                       faces=[], isFacesToIgnore=True, extrMethod=StdMeshers.SURF_OFFSET_SMOOTH ):
293         """
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)
297
298         Parameters:
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:
310
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.
321         """
322         
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 ):
328             faces = [ faces ]
329         if faces and isinstance( faces[0], geomBuilder.GEOM._objref_GEOM_Object ):
330             faceIDs = []
331             for shape in faces:
332                 ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] )
333                 for f in ff:
334                     faceIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f))
335             faces = faceIDs
336         hyp = self.Hypothesis("ViscousLayers",
337                               [thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore],
338                               toAdd=False)
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 )
345         return hyp
346
347     def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor,
348                         edges=[], isEdgesToIgnore=True ):
349         """
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
353
354         Parameters:
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**).
363         """
364         
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 ):
370             edges = [edges]
371         if edges and isinstance( edges[0], geomBuilder.GEOM._objref_GEOM_Object ):
372             edgeIDs = []
373             for shape in edges:
374                 ee = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"])
375                 for e in ee:
376                     edgeIDs.append( self.mesh.geompyD.GetSubShapeID( self.mesh.geom, e ))
377             edges = edgeIDs
378         hyp = self.Hypothesis("ViscousLayers2D",
379                               [thickness, numberOfLayers, stretchFactor, edges, isEdgesToIgnore],
380                               toAdd=False)
381         hyp.SetTotalThickness(thickness)
382         hyp.SetNumberLayers(numberOfLayers)
383         hyp.SetStretchFactor(stretchFactor)
384         hyp.SetEdges(edges, isEdgesToIgnore)
385         self.mesh.AddHypothesis( hyp, self.geom )
386         return hyp
387
388     def ReversedEdgeIndices(self, reverseList):
389         """
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
392         """
393         
394         from salome.smesh.smeshBuilder import FirstVertexOnCurve
395         resList = []
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")
402                 resList.append( i )
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 ))
407             elif len( i ) > 1:
408                 e = i[0]
409                 v = i[1]
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:
415                     v,e = e,v
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 ))
423             else:
424                 raise TypeError("Item must be either an edge or tuple (edge, 1st_vertex_of_edge)")
425         return resList
426