Salome HOME
Merge remote branch 'origin/V8_5_asterstudy'
[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
78         Returns: 
79                 :class:`~SMESH.SMESH_Hypothesis`
80         """
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())
85         if scomp is not None:
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
91                 while iter.More():
92                     hypo_so_i = iter.Value()
93                     attr = hypo_so_i.FindAttribute("AttributeIOR")[1]
94                     if attr is not None:
95                         anIOR = attr.Value()
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:
106                                         # Check arguments
107                                         if CompareMethod(hypo_i, args):
108                                             # found!!!
109                                             return hypo_i
110                                         pass
111                                     pass
112                                 pass
113                             pass
114                         pass
115                     iter.Next()
116                     pass
117                 pass
118             pass
119         return None
120
121     def FindAlgorithm (self, algoname, smeshpyD):
122         """
123         Finds the algorithm in the study by its type name.
124         Finds only the algorithms, which have been created in smeshBuilder engine.
125
126         Returns:
127                 SMESH.SMESH_Algo
128         """
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
139                 while iter.More():
140                     algo_so_i = iter.Value()
141                     attr = algo_so_i.FindAttribute("AttributeIOR")[1]
142                     if attr is not None:
143                         anIOR = attr.Value()
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:
154                                         # found!!!
155                                         return algo_i
156                                     pass
157                                 pass
158                             pass
159                         pass
160                     iter.Next()
161                     pass
162                 pass
163             pass
164         return None
165
166     def GetSubMesh(self):
167         """
168         If the algorithm is global, returns 0; 
169         else returns the :class:`~SMESH.SMESH_subMesh` associated to this algorithm.
170         """
171         return self.subm
172
173     def GetAlgorithm(self):
174         """
175         Returns the wrapped mesher.
176         """
177         return self.algo
178
179     def GetCompatibleHypothesis(self):
180         """
181         Gets the list of hypothesis that can be used with this algorithm
182         """
183         mylist = []
184         if self.algo:
185             mylist = self.algo.GetCompatibleHypothesis()
186         return mylist
187
188     def GetName(self):
189         """
190         Gets the name of the algorithm
191         """
192         from salome.smesh.smeshBuilder import GetName
193         return GetName(self.algo)
194
195     def SetName(self, name):
196         """
197         Sets the name to the algorithm
198         """
199         self.mesh.smeshpyD.SetName(self.algo, name)
200
201     def GetId(self):
202         """
203         Gets the id of the algorithm
204         """
205         return self.algo.GetId()
206
207     def Create(self, mesh, geom, hypo, so="libStdMeshersEngine.so"):
208         """
209         Private method.
210         """
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)
214         if algo is None:
215             algo = mesh.smeshpyD.CreateHypothesis(hypo, so)
216             pass
217         self.Assign(algo, mesh, geom)
218         return self.algo
219
220     def Assign(self, algo, mesh, geom):
221         """
222         Private method
223         """
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")
227         self.mesh = mesh
228         if not geom or geom.IsSame( mesh.geom ):
229             self.geom = mesh.geom
230         else:
231             self.geom = geom
232             AssureGeomPublished( mesh, geom )
233             self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName())
234         self.algo = algo
235         status = mesh.AddHypothesis(self.algo, self.geom)
236         return
237
238     def CompareHyp (self, hyp, args):
239         print("CompareHyp is not implemented for ", self.__class__.__name__, ":", hyp.GetName())
240         return False
241
242     def CompareEqualHyp (self, hyp, args):
243         return True
244
245     def Hypothesis (self, hyp, args=[], so="libStdMeshersEngine.so",
246                     UseExisting=0, CompareMethod="", toAdd=True):
247         """
248         Private method
249         """
250         from salome.smesh.smeshBuilder import TreatHypoStatus, GetName
251         hypo = None
252         if UseExisting:
253             if CompareMethod == "": CompareMethod = self.CompareHyp
254             hypo = self.FindHypothesis(hyp, args, CompareMethod, self.mesh.smeshpyD)
255             pass
256         if hypo is None:
257             hypo = self.mesh.smeshpyD.CreateHypothesis(hyp, so)
258             a = ""
259             s = "="
260             for arg in args:
261                 argStr = str(arg)
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 += ']'
268                 a = a + s + argStr
269                 s = ","
270                 pass
271             if len(a) > 50:
272                 a = a[:47]+"..."
273             self.mesh.smeshpyD.SetName(hypo, hyp + a)
274             pass
275         geomName=""
276         if self.geom:
277             geomName = GetName(self.geom)
278         if toAdd:
279             status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
280             TreatHypoStatus( status, GetName(hypo), geomName, 0, self.mesh )
281         return hypo
282
283     def MainShapeEntry(self):
284         """
285         Returns entry of the shape to mesh in the study
286         """
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()
291
292     def ViscousLayers(self, thickness, numberOfLayers, stretchFactor,
293                       faces=[], isFacesToIgnore=True, extrMethod=StdMeshers.SURF_OFFSET_SMOOTH ):
294         """
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)
298
299         Parameters:
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:
311
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.
322         """
323         
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 ):
329             faces = [ faces ]
330         if faces and isinstance( faces[0], geomBuilder.GEOM._objref_GEOM_Object ):
331             faceIDs = []
332             for shape in faces:
333                 ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] )
334                 for f in ff:
335                     faceIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f))
336             faces = faceIDs
337         hyp = self.Hypothesis("ViscousLayers",
338                               [thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore],
339                               toAdd=False)
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 )
346         return hyp
347
348     def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor,
349                         edges=[], isEdgesToIgnore=True ):
350         """
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
354
355         Parameters:
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**).
364         """
365         
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 ):
371             edges = [edges]
372         if edges and isinstance( edges[0], geomBuilder.GEOM._objref_GEOM_Object ):
373             edgeIDs = []
374             for shape in edges:
375                 ee = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"])
376                 for e in ee:
377                     edgeIDs.append( self.mesh.geompyD.GetSubShapeID( self.mesh.geom, e ))
378             edges = edgeIDs
379         hyp = self.Hypothesis("ViscousLayers2D",
380                               [thickness, numberOfLayers, stretchFactor, edges, isEdgesToIgnore],
381                               toAdd=False)
382         hyp.SetTotalThickness(thickness)
383         hyp.SetNumberLayers(numberOfLayers)
384         hyp.SetStretchFactor(stretchFactor)
385         hyp.SetEdges(edges, isEdgesToIgnore)
386         self.mesh.AddHypothesis( hyp, self.geom )
387         return hyp
388
389     def ReversedEdgeIndices(self, reverseList):
390         """
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
393         """
394         
395         from salome.smesh.smeshBuilder import FirstVertexOnCurve
396         resList = []
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")
403                 resList.append( i )
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 ))
408             elif len( i ) > 1:
409                 e = i[0]
410                 v = i[1]
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:
416                     v,e = e,v
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 ))
424             else:
425                 raise TypeError("Item must be either an edge or tuple (edge, 1st_vertex_of_edge)")
426         return resList
427