Salome HOME
Merge remote-tracking branch 'origin/master' into V8_5_BR
[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 Mesh (see e.g. class :class:`~StdMeshersBuilder.StdMeshersBuilder_Segment`
39     in StdMeshersBuilder package):
40
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
44                 ::
45
46                         meshMethod = "MyAlgorithm"
47
48                 then an instance of :code:`MyPlugin_Algorithm` can be created by the direct invocation of the function
49                 of smesh.Mesh class:
50                 ::
51     
52                         my_algo = mesh.MyAlgorithm()
53     
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
57                 ::
58     
59                         algoType = "MyPLUGIN"
60
61                 then it's creation code can be:
62                 ::
63
64                         my_algo = mesh.MyAlgorithm(algo="MyPLUGIN")
65     """
66     
67     
68     def __init__(self):
69         """
70         Private constuctor
71         """
72         self.mesh = None
73         self.geom = None
74         self.subm = None
75         self.algo = None
76         pass
77
78     def FindHypothesis (self, hypname, args, CompareMethod, smeshpyD):
79         """
80         Finds a hypothesis in the study by its type name and parameters.
81         Finds only the hypotheses created in smeshpyD engine.
82         Returns: 
83                 SMESH.SMESH_Hypothesis
84         """
85         study = smeshpyD.GetCurrentStudy()
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())
89         if scomp is not None:
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
95                 while iter.More():
96                     hypo_so_i = iter.Value()
97                     attr = hypo_so_i.FindAttribute("AttributeIOR")[1]
98                     if attr is not None:
99                         anIOR = attr.Value()
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:
110                                         # Check arguments
111                                         if CompareMethod(hypo_i, args):
112                                             # found!!!
113                                             return hypo_i
114                                         pass
115                                     pass
116                                 pass
117                             pass
118                         pass
119                     iter.Next()
120                     pass
121                 pass
122             pass
123         return None
124
125     def FindAlgorithm (self, algoname, smeshpyD):
126         """
127         Finds the algorithm in the study by its type name.
128         Finds only the algorithms, which have been created in smeshpyD engine.
129
130         Returns:
131                 SMESH.SMESH_Algo
132         """
133         study = smeshpyD.GetCurrentStudy()
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
143                 while iter.More():
144                     algo_so_i = iter.Value()
145                     attr = algo_so_i.FindAttribute("AttributeIOR")[1]
146                     if attr is not None:
147                         anIOR = attr.Value()
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:
158                                         # found!!!
159                                         return algo_i
160                                     pass
161                                 pass
162                             pass
163                         pass
164                     iter.Next()
165                     pass
166                 pass
167             pass
168         return None
169
170     def GetSubMesh(self):
171         """
172         If the algorithm is global, returns 0; 
173         else returns the submesh associated to this algorithm.
174         """
175         return self.subm
176
177     def GetAlgorithm(self):
178         """
179         Returns the wrapped mesher.
180         """
181         return self.algo
182
183     def GetCompatibleHypothesis(self):
184         """
185         Gets the list of hypothesis that can be used with this algorithm
186         """
187         mylist = []
188         if self.algo:
189             mylist = self.algo.GetCompatibleHypothesis()
190         return mylist
191
192     def GetName(self):
193         """
194         Gets the name of the algorithm
195         """
196         from salome.smesh.smeshBuilder import GetName
197         return GetName(self.algo)
198
199     def SetName(self, name):
200         """
201         Sets the name to the algorithm
202         """
203         self.mesh.smeshpyD.SetName(self.algo, name)
204
205     def GetId(self):
206         """
207         Gets the id of the algorithm
208         """
209         return self.algo.GetId()
210
211     def Create(self, mesh, geom, hypo, so="libStdMeshersEngine.so"):
212         """
213         Private method.
214         """
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)
218         if algo is None:
219             algo = mesh.smeshpyD.CreateHypothesis(hypo, so)
220             pass
221         self.Assign(algo, mesh, geom)
222         return self.algo
223
224     def Assign(self, algo, mesh, geom):
225         """
226         Private method
227         """
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"
231         self.mesh = mesh
232         if not geom or geom.IsSame( mesh.geom ):
233             self.geom = mesh.geom
234         else:
235             self.geom = geom
236             AssureGeomPublished( mesh, geom )
237             self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName())
238         self.algo = algo
239         status = mesh.AddHypothesis(self.algo, self.geom)
240         return
241
242     def CompareHyp (self, hyp, args):
243         print "CompareHyp is not implemented for ", self.__class__.__name__, ":", hyp.GetName()
244         return False
245
246     def CompareEqualHyp (self, hyp, args):
247         return True
248
249     def Hypothesis (self, hyp, args=[], so="libStdMeshersEngine.so",
250                     UseExisting=0, CompareMethod="", toAdd=True):
251         """
252         Private method
253         """
254         from salome.smesh.smeshBuilder import TreatHypoStatus, GetName
255         hypo = None
256         if UseExisting:
257             if CompareMethod == "": CompareMethod = self.CompareHyp
258             hypo = self.FindHypothesis(hyp, args, CompareMethod, self.mesh.smeshpyD)
259             pass
260         if hypo is None:
261             hypo = self.mesh.smeshpyD.CreateHypothesis(hyp, so)
262             a = ""
263             s = "="
264             for arg in args:
265                 argStr = str(arg)
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 += ']'
272                 a = a + s + argStr
273                 s = ","
274                 pass
275             if len(a) > 50:
276                 a = a[:47]+"..."
277             self.mesh.smeshpyD.SetName(hypo, hyp + a)
278             pass
279         geomName=""
280         if self.geom:
281             geomName = GetName(self.geom)
282         if toAdd:
283             status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
284             TreatHypoStatus( status, GetName(hypo), geomName, 0, self.mesh )
285         return hypo
286
287     def MainShapeEntry(self):
288         """
289         Returns entry of the shape to mesh in the study
290         """
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()
295
296     def ViscousLayers(self, thickness, numberOfLayers, stretchFactor,
297                       faces=[], isFacesToIgnore=True, extrMethod=StdMeshers.SURF_OFFSET_SMOOTH ):
298         """
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)
302
303         Parameters:
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:
315
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.
326         """
327         
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 ):
333             faces = [ faces ]
334         if faces and isinstance( faces[0], geomBuilder.GEOM._objref_GEOM_Object ):
335             faceIDs = []
336             for shape in faces:
337                 ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] )
338                 for f in ff:
339                     faceIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f))
340             faces = faceIDs
341         hyp = self.Hypothesis("ViscousLayers",
342                               [thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore],
343                               toAdd=False)
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 )
350         return hyp
351
352     def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor,
353                         edges=[], isEdgesToIgnore=True ):
354         """
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
358
359         Parameters:
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**).
368         """
369         
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 ):
375             edges = [edges]
376         if edges and isinstance( edges[0], geomBuilder.GEOM._objref_GEOM_Object ):
377             edgeIDs = []
378             for shape in edges:
379                 ee = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"])
380                 for e in ee:
381                     edgeIDs.append( self.mesh.geompyD.GetSubShapeID( self.mesh.geom, e ))
382             edges = edgeIDs
383         hyp = self.Hypothesis("ViscousLayers2D",
384                               [thickness, numberOfLayers, stretchFactor, edges, isEdgesToIgnore],
385                               toAdd=False)
386         hyp.SetTotalThickness(thickness)
387         hyp.SetNumberLayers(numberOfLayers)
388         hyp.SetStretchFactor(stretchFactor)
389         hyp.SetEdges(edges, isEdgesToIgnore)
390         self.mesh.AddHypothesis( hyp, self.geom )
391         return hyp
392
393     def ReversedEdgeIndices(self, reverseList):
394         """
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
397         """
398         
399         from salome.smesh.smeshBuilder import FirstVertexOnCurve
400         resList = []
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"
407                 resList.append( i )
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 ))
412             elif len( i ) > 1:
413                 e = i[0]
414                 v = i[1]
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:
420                     v,e = e,v
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 ))
428             else:
429                 raise TypeError, "Item must be either an edge or tuple (edge, 1st_vertex_of_edge)"
430         return resList
431