Salome HOME
PAL12037. Add protection against None shapes and empty geom groups
[modules/smesh.git] / src / SMESH_SWIG / smesh.py
1 #  Copyright (C) 2005  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 #  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
3 #
4 #  This library is free software; you can redistribute it and/or
5 #  modify it under the terms of the GNU Lesser General Public
6 #  License as published by the Free Software Foundation; either
7 #  version 2.1 of the License.
8 #
9 #  This library is distributed in the hope that it will be useful,
10 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 #  Lesser General Public License for more details.
13 #
14 #  You should have received a copy of the GNU Lesser General Public
15 #  License along with this library; if not, write to the Free Software
16 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 #  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
19 #
20 #  File   : smesh.py
21 #  Author : Francis KLOSS, OCC
22 #  Module : SMESH
23
24 """
25  \namespace smesh
26  \brief Module smesh
27 """
28
29 import salome
30 import geompy
31 import StdMeshers
32 import SMESH
33
34 # Public variables
35 # ----------------
36
37 REGULAR = 1
38 PYTHON  = 2
39
40 NETGEN  = 3
41 GHS3D   = 4
42
43 smesh = salome.lcc.FindOrLoadComponent("FactoryServer", "SMESH")
44 smesh.SetCurrentStudy(salome.myStudy)
45
46 # Private functions
47 # -----------------
48
49 NO_NAME = "NoName"
50
51 def GetName(obj):
52     ior  = salome.orb.object_to_string(obj)
53     sobj = salome.myStudy.FindObjectIOR(ior)
54     if sobj is None:
55         return NO_NAME
56     else:
57         attr = sobj.FindAttribute("AttributeName")[1]
58         return attr.Value()
59
60 def SetName(obj, name):
61     ior  = salome.orb.object_to_string(obj)
62     sobj = salome.myStudy.FindObjectIOR(ior)
63     attr = sobj.FindAttribute("AttributeName")[1]
64     attr.SetValue(name)
65
66 # Algorithms and hypothesis
67 # =========================
68
69 # Private class: Mesh_Algorithm
70 # -----------------------------
71
72 class Mesh_Algorithm:
73     """
74     Mother class to define algorithm, recommended to don't use directly
75     """
76
77     mesh = 0
78     geom = 0
79     subm = 0
80     algo = 0
81
82     def GetSubMesh(self):
83         """
84          If the algorithm is global, return 0
85          else return the submesh associated to this algorithm
86         """
87         return self.subm
88
89     def GetAlgorithm(self):
90         """
91          Return the wrapped mesher
92         """
93         return self.algo
94
95     def TreatHypoStatus(self, status, hypName, geomName, isAlgo):
96         """
97         Private method. Print error message if a hypothesis was not assigned
98         """
99         if isAlgo:
100             hypType = "algorithm"
101         else:
102             hypType = "hypothesis"
103         if status == SMESH.HYP_UNKNOWN_FATAL :
104             reason = "for unknown reason"
105         elif status == SMESH.HYP_INCOMPATIBLE :
106             reason = "this hypothesis mismatches algorithm"
107         elif status == SMESH.HYP_NOTCONFORM :
108             reason = "not conform mesh would be built"
109         elif status == SMESH.HYP_ALREADY_EXIST :
110             reason = hypType + " of the same dimension already assigned to this shape"
111         elif status == SMESH.HYP_BAD_DIM :
112             reason = hypType + " mismatches shape"
113         elif status == SMESH.HYP_CONCURENT :
114             reason = "there are concurrent hypotheses on sub-shapes"
115         elif status == SMESH.HYP_BAD_SUBSHAPE :
116             reason = "shape is neither the main one, nor its subshape, nor a valid group"
117         else:
118             return
119         hypName = '"' + hypName + '"'
120         geomName= '"' + geomName+ '"'
121         if status < SMESH.HYP_UNKNOWN_FATAL:
122             print hypName, "was assigned to",    geomName,"but", reason
123         else:
124             print hypName, "was not assigned to",geomName,":", reason
125         pass
126
127     def Create(self, mesh, geom, hypo, so="libStdMeshersEngine.so"):
128         """
129          Private method
130         """
131         if geom is None:
132             raise RuntimeError, "Attemp to create " + hypo + " algoritm on None shape"
133         self.mesh = mesh
134         piece = mesh.geom
135         if geom==0:
136             self.geom = piece
137             name = GetName(piece)
138         else:
139             self.geom = geom
140             name = GetName(geom)
141             if name==NO_NAME:
142                 name = geompy.SubShapeName(geom, piece)
143                 geompy.addToStudyInFather(piece, geom, name)
144             self.subm = mesh.mesh.GetSubMesh(geom, hypo)
145
146         self.algo = smesh.CreateHypothesis(hypo, so)
147         SetName(self.algo, name + "/" + hypo)
148         status = mesh.mesh.AddHypothesis(self.geom, self.algo)
149         self.TreatHypoStatus( status, hypo, name, 1 )
150
151     def Hypothesis(self, hyp, args=[], so="libStdMeshersEngine.so"):
152         """
153          Private method
154         """
155         hypo = smesh.CreateHypothesis(hyp, so)
156         a = ""
157         s = "="
158         i = 0
159         n = len(args)
160         while i<n:
161             a = a + s + str(args[i])
162             s = ","
163             i = i + 1
164         name = GetName(self.geom)
165         SetName(hypo, name + "/" + hyp + a)
166         status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
167         self.TreatHypoStatus( status, hyp, name, 0 )
168         return hypo
169
170 # Public class: Mesh_Segment
171 # --------------------------
172
173 class Mesh_Segment(Mesh_Algorithm):
174     """
175     Class to define a segment 1D algorithm for discretization
176     """
177
178     def __init__(self, mesh, geom=0):
179         """
180          Private constructor
181         """
182         self.Create(mesh, geom, "Regular_1D")
183
184     def LocalLength(self, l):
185         """
186          Define "LocalLength" hypothesis to cut an edge in several segments with the same length
187          \param l for the length of segments that cut an edge
188         """
189         hyp = self.Hypothesis("LocalLength", [l])
190         hyp.SetLength(l)
191         return hyp
192
193     def NumberOfSegments(self, n, s=[]):
194         """
195          Define "NumberOfSegments" hypothesis to cut an edge in several fixed number of segments
196          \param n for the number of segments that cut an edge
197          \param s for the scale factor (optional)
198         """
199         if s == []:
200             hyp = self.Hypothesis("NumberOfSegments", [n])
201         else:
202             hyp = self.Hypothesis("NumberOfSegments", [n,s])
203             hyp.SetDistrType( 1 )
204             hyp.SetScaleFactor(s)
205         hyp.SetNumberOfSegments(n)
206         return hyp
207
208     def Arithmetic1D(self, start, end):
209         """
210          Define "Arithmetic1D" hypothesis to cut an edge in several segments with arithmetic length increasing
211          \param start for the length of the first segment
212          \param end   for the length of the last  segment
213         """
214         hyp = self.Hypothesis("Arithmetic1D", [start, end])
215         hyp.SetLength(start, 1)
216         hyp.SetLength(end  , 0)
217         return hyp
218
219     def StartEndLength(self, start, end):
220         """
221          Define "StartEndLength" hypothesis to cut an edge in several segments with geometric length increasing
222          \param start for the length of the first segment
223          \param end   for the length of the last  segment
224         """
225         hyp = self.Hypothesis("StartEndLength", [start, end])
226         hyp.SetLength(start, 1)
227         hyp.SetLength(end  , 0)
228         return hyp
229
230     def Deflection1D(self, d):
231         """
232          Define "Deflection1D" hypothesis
233          \param d for the deflection
234         """
235         hyp = self.Hypothesis("Deflection1D", [d])
236         hyp.SetDeflection(d)
237         return hyp
238
239     def Propagation(self):
240         """
241          Define "Propagation" hypothesis that propagate all other hypothesis on all others edges that are in
242          the opposite side in the case of quadrangular faces
243         """
244         return self.Hypothesis("Propagation")
245
246     def AutomaticLength(self, fineness=0):
247         """
248          Define "AutomaticLength" hypothesis
249          \param fineness for the fineness [0-1]
250         """
251         hyp = self.Hypothesis("AutomaticLength")
252         hyp.SetFineness( fineness )
253         return hyp
254
255     def QuadraticMesh(self):
256         """
257          Define "QuadraticMesh" hypothesis, forcing construction of quadratic edges.
258          If the 2D mesher sees that all boundary edges are quadratic ones,
259          it generates quadratic faces, else it generates linear faces using
260          medium nodes as if they were vertex ones.
261          The 3D mesher generates quadratic volumes only if all boundary faces
262          are quadratic ones, else it fails.
263         """
264         hyp = self.Hypothesis("QuadraticMesh")
265         return hyp
266
267 # Public class: Mesh_Segment_Python
268 # ---------------------------------
269
270 class Mesh_Segment_Python(Mesh_Segment):
271     """
272     Class to define a segment 1D algorithm for discretization with python function
273     """
274
275     def __init__(self, mesh, geom=0):
276         """
277          Private constructor
278         """
279         import Python1dPlugin
280         self.Create(mesh, geom, "Python_1D", "libPython1dEngine.so")
281
282     def PythonSplit1D(self, n, func):
283         """
284          Define "PythonSplit1D" hypothesis based on the Erwan Adam patch, awaiting equivalent SALOME functionality
285          \param n for the number of segments that cut an edge
286          \param func for the python function that calculate the length of all segments
287         """
288         hyp = self.Hypothesis("PythonSplit1D", [n], "libPython1dEngine.so")
289         hyp.SetNumberOfSegments(n)
290         hyp.SetPythonLog10RatioFunction(func)
291         return hyp
292
293 # Public class: Mesh_Triangle
294 # ---------------------------
295
296 class Mesh_Triangle(Mesh_Algorithm):
297     """
298     Class to define a triangle 2D algorithm
299     """
300
301     def __init__(self, mesh, geom=0):
302         """
303          Private constructor
304         """
305         self.Create(mesh, geom, "MEFISTO_2D")
306
307     def MaxElementArea(self, area):
308         """
309          Define "MaxElementArea" hypothesis to give the maximun area of each triangles
310          \param area for the maximum area of each triangles
311         """
312         hyp = self.Hypothesis("MaxElementArea", [area])
313         hyp.SetMaxElementArea(area)
314         return hyp
315
316     def LengthFromEdges(self):
317         """
318          Define "LengthFromEdges" hypothesis to build triangles based on the length of the edges taken from the wire
319         """
320         return self.Hypothesis("LengthFromEdges")
321
322 # Public class: Mesh_Quadrangle
323 # -----------------------------
324
325 class Mesh_Quadrangle(Mesh_Algorithm):
326     """
327     Class to define a quadrangle 2D algorithm
328     """
329
330     def __init__(self, mesh, geom=0):
331         """
332          Private constructor
333         """
334         self.Create(mesh, geom, "Quadrangle_2D")
335
336     def QuadranglePreference(self):
337         """
338          Define "QuadranglePreference" hypothesis, forcing construction
339          of quadrangles if the number of nodes on opposite edges is not the same
340          in the case where the global number of nodes on edges is even
341         """
342         hyp = self.Hypothesis("QuadranglePreference")
343         return hyp
344
345 # Public class: Mesh_Tetrahedron
346 # ------------------------------
347
348 class Mesh_Tetrahedron(Mesh_Algorithm):
349     """
350     Class to define a tetrahedron 3D algorithm
351     """
352
353     def __init__(self, mesh, algo, geom=0):
354         """
355          Private constructor
356         """
357         if algo == NETGEN:
358             self.Create(mesh, geom, "NETGEN_3D", "libNETGENEngine.so")
359         elif algo == GHS3D:
360             import GHS3DPlugin
361             self.Create(mesh, geom, "GHS3D_3D" , "libGHS3DEngine.so")
362
363     def MaxElementVolume(self, vol):
364         """
365          Define "MaxElementVolume" hypothesis to give the maximun volume of each tetrahedral
366          \param vol for the maximum volume of each tetrahedral
367         """
368         hyp = self.Hypothesis("MaxElementVolume", [vol])
369         hyp.SetMaxElementVolume(vol)
370         return hyp
371
372 # Public class: Mesh_Hexahedron
373 # ------------------------------
374
375 class Mesh_Hexahedron(Mesh_Algorithm):
376     """
377     Class to define a hexahedron 3D algorithm
378     """
379
380     def __init__(self, mesh, geom=0):
381         """
382          Private constructor
383         """
384         self.Create(mesh, geom, "Hexa_3D")
385
386 # Public class: Mesh
387 # ==================
388
389 class Mesh:
390     """
391     Class to define a mesh
392     """
393
394     geom = 0
395     mesh = 0
396
397     def __init__(self, geom, name=0):
398         """
399          Constructor
400
401          Creates mesh on the shape \a geom,
402          sets GUI name of this mesh to \a name.
403          \param geom Shape to be meshed
404          \param name Study name of the mesh
405         """
406         self.geom = geom
407         self.mesh = smesh.CreateMesh(geom)
408         if name == 0:
409             SetName(self.mesh, GetName(geom))
410         else:
411             SetName(self.mesh, name)
412
413     def GetMesh(self):
414         """
415          Method that returns the mesh
416         """
417         return self.mesh
418
419     def GetShape(self):
420         """
421          Method that returns the shape associated to the mesh
422         """
423         return self.geom
424
425     def MeshDimension(self):
426         """
427         Returns mesh dimension depending on shape one
428         """
429         shells = geompy.SubShapeAllIDs( self.geom, geompy.ShapeType["SHELL"] )
430         if len( shells ) > 0 :
431             return 3
432         elif geompy.NumberOfFaces( self.geom ) > 0 :
433             return 2
434         elif geompy.NumberOfEdges( self.geom ) > 0 :
435             return 1
436         else:
437             return 0;
438         pass
439
440     def Segment(self, algo=REGULAR, geom=0):
441         """
442          Creates a segment discretization 1D algorithm.
443          If the optional \a algo parameter is not sets, this algorithm is REGULAR.
444          If the optional \a geom parameter is not sets, this algorithm is global.
445          Otherwise, this algorithm define a submesh based on \a geom subshape.
446          \param algo values are smesh.REGULAR or smesh.PYTHON for discretization via python function
447          \param geom If defined, subshape to be meshed
448         """
449         ## if Segment(geom) is called by mistake
450         if ( isinstance( algo, geompy.GEOM._objref_GEOM_Object)):
451             algo, geom = geom, algo
452             pass
453         if algo == REGULAR:
454             return Mesh_Segment(self, geom)
455         elif algo == PYTHON:
456             return Mesh_Segment_Python(self, geom)
457         else:
458             return Mesh_Segment(self, geom)
459
460     def Triangle(self, geom=0):
461         """
462          Creates a triangle 2D algorithm for faces.
463          If the optional \a geom parameter is not sets, this algorithm is global.
464          Otherwise, this algorithm define a submesh based on \a geom subshape.
465          \param geom If defined, subshape to be meshed
466         """
467         return Mesh_Triangle(self, geom)
468
469     def Quadrangle(self, geom=0):
470         """
471          Creates a quadrangle 2D algorithm for faces.
472          If the optional \a geom parameter is not sets, this algorithm is global.
473          Otherwise, this algorithm define a submesh based on \a geom subshape.
474          \param geom If defined, subshape to be meshed
475         """
476         return Mesh_Quadrangle(self, geom)
477
478     def Tetrahedron(self, algo, geom=0):
479         """
480          Creates a tetrahedron 3D algorithm for solids.
481          The parameter \a algo permits to choice the algorithm: NETGEN or GHS3D
482          If the optional \a geom parameter is not sets, this algorithm is global.
483          Otherwise, this algorithm define a submesh based on \a geom subshape.
484          \param algo values are: smesh.NETGEN, smesh.GHS3D
485          \param geom If defined, subshape to be meshed
486         """
487         ## if Tetrahedron(geom) is called by mistake
488         if ( isinstance( algo, geompy.GEOM._objref_GEOM_Object)):
489             algo, geom = geom, algo
490             pass
491         return Mesh_Tetrahedron(self, algo, geom)
492
493     def Hexahedron(self, geom=0):
494         """
495          Creates a hexahedron 3D algorithm for solids.
496          If the optional \a geom parameter is not sets, this algorithm is global.
497          Otherwise, this algorithm define a submesh based on \a geom subshape.
498          \param geom If defined, subshape to be meshed
499         """
500         return Mesh_Hexahedron(self, geom)
501
502     def Compute(self):
503         """
504         Compute the mesh and return the status of the computation
505         """
506         ok = smesh.Compute(self.mesh, self.geom)
507         if not ok:
508             errors = smesh.GetAlgoState( self.mesh, self.geom )
509             allReasons = ""
510             for err in errors:
511                 if err.isGlobalAlgo:
512                     glob = " global "
513                 else:
514                     glob = " local "
515                     pass
516                 dim = str(err.algoDim)
517                 if err.name == SMESH.MISSING_ALGO:
518                     reason = glob + dim + "D algorithm is missing"
519                 elif err.name == SMESH.MISSING_HYPO:
520                     name = '"' + err.algoName + '"'
521                     reason = glob + dim + "D algorithm " + name + " misses " + dim + "D hypothesis"
522                 else:
523                     reason = "Global \"Not Conform mesh allowed\" hypothesis is missing"
524                     pass
525                 if allReasons != "":
526                     allReasons += "\n"
527                     pass
528                 allReasons += reason
529                 pass
530             if allReasons != "":
531                 print '"' + GetName(self.mesh) + '"',"not computed:"
532                 print allReasons
533                 pass
534             pass
535         if salome.sg.hasDesktop():
536             smeshgui = salome.ImportComponentGUI("SMESH")
537             smeshgui.Init(salome.myStudyId)
538             smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), ok )
539             salome.sg.updateObjBrowser(1)
540             pass
541         return ok
542
543     def AutomaticTetrahedralization(self, fineness=0):
544         """
545         Compute tetrahedral mesh using AutomaticLength + MEFISTO + NETGEN
546         The parameter \a fineness [0.-1.] defines mesh fineness
547         """
548         dim = self.MeshDimension()
549         # assign hypotheses
550         self.RemoveGlobalHypotheses()
551         self.Segment().AutomaticLength(fineness)
552         if dim > 1 :
553             self.Triangle().LengthFromEdges()
554             pass
555         if dim > 2 :
556             self.Tetrahedron(NETGEN)
557             pass
558         return self.Compute()
559
560     def AutomaticHexahedralization(self, fineness=0):
561         """
562         Compute hexahedral mesh using AutomaticLength + Quadrangle + Hexahedron
563         The parameter \a fineness [0.-1.] defines mesh fineness
564         """
565         dim = self.MeshDimension()
566         # assign hypotheses
567         self.RemoveGlobalHypotheses()
568         self.Segment().AutomaticLength(fineness)
569         if dim > 1 :
570             self.Quadrangle()
571             pass
572         if dim > 2 :
573             self.Hexahedron()            
574             pass
575         return self.Compute()
576
577     def RemoveGlobalHypotheses(self):
578         """
579         Removes all global hypotheses
580         """
581         current_hyps = self.mesh.GetHypothesisList( self.geom )
582         for hyp in current_hyps:
583             self.mesh.RemoveHypothesis( self.geom, hyp )
584             pass
585         pass
586
587     def Group(self, grp, name=""):
588         """
589          Create a mesh group based on geometric object \a grp
590          and give a \a name, if this parameter is not defined
591          the name is the same as the geometric group name
592          \param grp  is a geometric group, a vertex, an edge, a face or a solid
593          \param name is the name of the mesh group
594         """
595         if name == "":
596             name = grp.GetName()
597
598         type = []
599         tgeo = str(grp.GetShapeType())
600         if tgeo == "VERTEX":
601             type = SMESH.NODE
602         elif tgeo == "EDGE":
603             type = SMESH.EDGE
604         elif tgeo == "FACE":
605             type = SMESH.FACE
606         elif tgeo == "SOLID":
607             type = SMESH.VOLUME
608         elif tgeo == "SHELL":
609             type = SMESH.VOLUME
610         elif tgeo == "COMPOUND":
611             if len( geompy.GetObjectIDs( grp )) == 0:
612                 print "Mesh.Group: empty geometric group", GetName( grp )
613                 return 0
614             tgeo = geompy.GetType(grp)
615             if tgeo == geompy.ShapeType["VERTEX"]:
616                 type = SMESH.NODE
617             elif tgeo == geompy.ShapeType["EDGE"]:
618                 type = SMESH.EDGE
619             elif tgeo == geompy.ShapeType["FACE"]:
620                 type = SMESH.FACE
621             elif tgeo == geompy.ShapeType["SOLID"]:
622                 type = SMESH.VOLUME
623
624         if type == []:
625             print "Mesh.Group: bad first argument: expected a group, a vertex, an edge, a face or a solid"
626             return 0
627         else:
628             return self.mesh.CreateGroupFromGEOM(type, name, grp)
629
630     def ExportToMED(self, f, version, opt=0):
631         """
632          Export the mesh in a file with the MED format and choice the \a version of MED format
633          \param f is the file name
634          \param version values are SMESH.MED_V2_1, SMESH.MED_V2_2
635         """
636         self.mesh.ExportToMED(f, opt, version)
637
638     def ExportMED(self, f, opt=0):
639         """
640          Export the mesh in a file with the MED format
641          \param f is the file name
642         """
643         self.mesh.ExportMED(f, opt)
644
645     def ExportDAT(self, f):
646         """
647          Export the mesh in a file with the DAT format
648          \param f is the file name
649         """
650         self.mesh.ExportDAT(f)
651
652     def ExportUNV(self, f):
653         """
654          Export the mesh in a file with the UNV format
655          \param f is the file name
656         """
657         self.mesh.ExportUNV(f)
658
659     def ExportSTL(self, f, ascii=1):
660         """
661          Export the mesh in a file with the STL format
662          \param f is the file name
663          \param ascii defined the kind of file contents
664         """
665         self.mesh.ExportSTL(f, ascii)