Salome HOME
Join modifications from branch OCC_development_for_3_2_0a2
[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         self.mesh = mesh
132         piece = mesh.geom
133         if geom==0:
134             self.geom = piece
135             name = GetName(piece)
136         else:
137             self.geom = geom
138             name = GetName(geom)
139             if name==NO_NAME:
140                 name = geompy.SubShapeName(geom, piece)
141                 geompy.addToStudyInFather(piece, geom, name)
142             self.subm = mesh.mesh.GetSubMesh(geom, hypo)
143
144         self.algo = smesh.CreateHypothesis(hypo, so)
145         SetName(self.algo, name + "/" + hypo)
146         status = mesh.mesh.AddHypothesis(self.geom, self.algo)
147         self.TreatHypoStatus( status, hypo, name, 1 )
148
149     def Hypothesis(self, hyp, args=[], so="libStdMeshersEngine.so"):
150         """
151          Private method
152         """
153         hypo = smesh.CreateHypothesis(hyp, so)
154         a = ""
155         s = "="
156         i = 0
157         n = len(args)
158         while i<n:
159             a = a + s + str(args[i])
160             s = ","
161             i = i + 1
162         name = GetName(self.geom)
163         SetName(hypo, name + "/" + hyp + a)
164         status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
165         self.TreatHypoStatus( status, hyp, name, 0 )
166         return hypo
167
168 # Public class: Mesh_Segment
169 # --------------------------
170
171 class Mesh_Segment(Mesh_Algorithm):
172     """
173     Class to define a segment 1D algorithm for discretization
174     """
175
176     def __init__(self, mesh, geom=0):
177         """
178          Private constructor
179         """
180         self.Create(mesh, geom, "Regular_1D")
181
182     def LocalLength(self, l):
183         """
184          Define "LocalLength" hypothesis to cut an edge in several segments with the same length
185          \param l for the length of segments that cut an edge
186         """
187         hyp = self.Hypothesis("LocalLength", [l])
188         hyp.SetLength(l)
189         return hyp
190
191     def NumberOfSegments(self, n, s=[]):
192         """
193          Define "NumberOfSegments" hypothesis to cut an edge in several fixed number of segments
194          \param n for the number of segments that cut an edge
195          \param s for the scale factor (optional)
196         """
197         if s == []:
198             hyp = self.Hypothesis("NumberOfSegments", [n])
199         else:
200             hyp = self.Hypothesis("NumberOfSegments", [n,s])
201             hyp.SetDistrType( 1 )
202             hyp.SetScaleFactor(s)
203         hyp.SetNumberOfSegments(n)
204         return hyp
205
206     def Arithmetic1D(self, start, end):
207         """
208          Define "Arithmetic1D" hypothesis to cut an edge in several segments with arithmetic length increasing
209          \param start for the length of the first segment
210          \param end   for the length of the last  segment
211         """
212         hyp = self.Hypothesis("Arithmetic1D", [start, end])
213         hyp.SetLength(start, 1)
214         hyp.SetLength(end  , 0)
215         return hyp
216
217     def StartEndLength(self, start, end):
218         """
219          Define "StartEndLength" hypothesis to cut an edge in several segments with geometric length increasing
220          \param start for the length of the first segment
221          \param end   for the length of the last  segment
222         """
223         hyp = self.Hypothesis("StartEndLength", [start, end])
224         hyp.SetLength(start, 1)
225         hyp.SetLength(end  , 0)
226         return hyp
227
228     def Deflection1D(self, d):
229         """
230          Define "Deflection1D" hypothesis
231          \param d for the deflection
232         """
233         hyp = self.Hypothesis("Deflection1D", [d])
234         hyp.SetDeflection(d)
235         return hyp
236
237     def Propagation(self):
238         """
239          Define "Propagation" hypothesis that propagate all other hypothesis on all others edges that are in
240          the opposite side in the case of quadrangular faces
241         """
242         return self.Hypothesis("Propagation")
243
244     def AutomaticLength(self, fineness=0):
245         """
246          Define "AutomaticLength" hypothesis
247          \param fineness for the fineness [0-1]
248         """
249         hyp = self.Hypothesis("AutomaticLength")
250         hyp.SetFineness( fineness )
251         return hyp
252
253     def QuadraticMesh(self):
254         """
255          Define "QuadraticMesh" hypothesis, forcing construction of quadratic edges.
256          If the 2D mesher sees that all boundary edges are quadratic ones,
257          it generates quadratic faces, else it generates linear faces using
258          medium nodes as if they were vertex ones.
259          The 3D mesher generates quadratic volumes only if all boundary faces
260          are quadratic ones, else it fails.
261         """
262         hyp = self.Hypothesis("QuadraticMesh")
263         return hyp
264
265 # Public class: Mesh_Segment_Python
266 # ---------------------------------
267
268 class Mesh_Segment_Python(Mesh_Segment):
269     """
270     Class to define a segment 1D algorithm for discretization with python function
271     """
272
273     def __init__(self, mesh, geom=0):
274         """
275          Private constructor
276         """
277         import Python1dPlugin
278         self.Create(mesh, geom, "Python_1D", "libPython1dEngine.so")
279
280     def PythonSplit1D(self, n, func):
281         """
282          Define "PythonSplit1D" hypothesis based on the Erwan Adam patch, awaiting equivalent SALOME functionality
283          \param n for the number of segments that cut an edge
284          \param func for the python function that calculate the length of all segments
285         """
286         hyp = self.Hypothesis("PythonSplit1D", [n], "libPython1dEngine.so")
287         hyp.SetNumberOfSegments(n)
288         hyp.SetPythonLog10RatioFunction(func)
289         return hyp
290
291 # Public class: Mesh_Triangle
292 # ---------------------------
293
294 class Mesh_Triangle(Mesh_Algorithm):
295     """
296     Class to define a triangle 2D algorithm
297     """
298
299     def __init__(self, mesh, geom=0):
300         """
301          Private constructor
302         """
303         self.Create(mesh, geom, "MEFISTO_2D")
304
305     def MaxElementArea(self, area):
306         """
307          Define "MaxElementArea" hypothesis to give the maximun area of each triangles
308          \param area for the maximum area of each triangles
309         """
310         hyp = self.Hypothesis("MaxElementArea", [area])
311         hyp.SetMaxElementArea(area)
312         return hyp
313
314     def LengthFromEdges(self):
315         """
316          Define "LengthFromEdges" hypothesis to build triangles based on the length of the edges taken from the wire
317         """
318         return self.Hypothesis("LengthFromEdges")
319
320 # Public class: Mesh_Quadrangle
321 # -----------------------------
322
323 class Mesh_Quadrangle(Mesh_Algorithm):
324     """
325     Class to define a quadrangle 2D algorithm
326     """
327
328     def __init__(self, mesh, geom=0):
329         """
330          Private constructor
331         """
332         self.Create(mesh, geom, "Quadrangle_2D")
333
334     def QuadranglePreference(self):
335         """
336          Define "QuadranglePreference" hypothesis, forcing construction
337          of quadrangles if the number of nodes on opposite edges is not the same
338          in the case where the global number of nodes on edges is even
339         """
340         hyp = self.Hypothesis("QuadranglePreference")
341         return hyp
342
343 # Public class: Mesh_Tetrahedron
344 # ------------------------------
345
346 class Mesh_Tetrahedron(Mesh_Algorithm):
347     """
348     Class to define a tetrahedron 3D algorithm
349     """
350
351     def __init__(self, mesh, algo, geom=0):
352         """
353          Private constructor
354         """
355         if algo == NETGEN:
356             self.Create(mesh, geom, "NETGEN_3D", "libNETGENEngine.so")
357         elif algo == GHS3D:
358             import GHS3DPlugin
359             self.Create(mesh, geom, "GHS3D_3D" , "libGHS3DEngine.so")
360
361     def MaxElementVolume(self, vol):
362         """
363          Define "MaxElementVolume" hypothesis to give the maximun volume of each tetrahedral
364          \param vol for the maximum volume of each tetrahedral
365         """
366         hyp = self.Hypothesis("MaxElementVolume", [vol])
367         hyp.SetMaxElementVolume(vol)
368         return hyp
369
370 # Public class: Mesh_Hexahedron
371 # ------------------------------
372
373 class Mesh_Hexahedron(Mesh_Algorithm):
374     """
375     Class to define a hexahedron 3D algorithm
376     """
377
378     def __init__(self, mesh, geom=0):
379         """
380          Private constructor
381         """
382         self.Create(mesh, geom, "Hexa_3D")
383
384 # Public class: Mesh
385 # ==================
386
387 class Mesh:
388     """
389     Class to define a mesh
390     """
391
392     geom = 0
393     mesh = 0
394
395     def __init__(self, geom, name=0):
396         """
397          Constructor
398
399          Creates mesh on the shape \a geom,
400          sets GUI name of this mesh to \a name.
401          \param geom Shape to be meshed
402          \param name Study name of the mesh
403         """
404         self.geom = geom
405         self.mesh = smesh.CreateMesh(geom)
406         if name == 0:
407             SetName(self.mesh, GetName(geom))
408         else:
409             SetName(self.mesh, name)
410
411     def GetMesh(self):
412         """
413          Method that returns the mesh
414         """
415         return self.mesh
416
417     def GetShape(self):
418         """
419          Method that returns the shape associated to the mesh
420         """
421         return self.geom
422
423     def MeshDimension(self):
424         """
425         Returns mesh dimension depending on shape one
426         """
427         shells = geompy.SubShapeAllIDs( self.geom, geompy.ShapeType["SHELL"] )
428         if len( shells ) > 0 :
429             return 3
430         elif geompy.NumberOfFaces( self.geom ) > 0 :
431             return 2
432         elif geompy.NumberOfEdges( self.geom ) > 0 :
433             return 1
434         else:
435             return 0;
436         pass
437
438     def Segment(self, algo=REGULAR, geom=0):
439         """
440          Creates a segment discretization 1D algorithm.
441          If the optional \a algo parameter is not sets, this algorithm is REGULAR.
442          If the optional \a geom parameter is not sets, this algorithm is global.
443          Otherwise, this algorithm define a submesh based on \a geom subshape.
444          \param algo values are smesh.REGULAR or smesh.PYTHON for discretization via python function
445          \param geom If defined, subshape to be meshed
446         """
447         ## if Segment(geom) is called by mistake
448         if ( isinstance( algo, geompy.GEOM._objref_GEOM_Object)):
449             algo, geom = geom, algo
450             pass
451         if algo == REGULAR:
452             return Mesh_Segment(self, geom)
453         elif algo == PYTHON:
454             return Mesh_Segment_Python(self, geom)
455         else:
456             return Mesh_Segment(self, geom)
457
458     def Triangle(self, geom=0):
459         """
460          Creates a triangle 2D algorithm for faces.
461          If the optional \a geom parameter is not sets, this algorithm is global.
462          Otherwise, this algorithm define a submesh based on \a geom subshape.
463          \param geom If defined, subshape to be meshed
464         """
465         return Mesh_Triangle(self, geom)
466
467     def Quadrangle(self, geom=0):
468         """
469          Creates a quadrangle 2D algorithm for faces.
470          If the optional \a geom parameter is not sets, this algorithm is global.
471          Otherwise, this algorithm define a submesh based on \a geom subshape.
472          \param geom If defined, subshape to be meshed
473         """
474         return Mesh_Quadrangle(self, geom)
475
476     def Tetrahedron(self, algo, geom=0):
477         """
478          Creates a tetrahedron 3D algorithm for solids.
479          The parameter \a algo permits to choice the algorithm: NETGEN or GHS3D
480          If the optional \a geom parameter is not sets, this algorithm is global.
481          Otherwise, this algorithm define a submesh based on \a geom subshape.
482          \param algo values are: smesh.NETGEN, smesh.GHS3D
483          \param geom If defined, subshape to be meshed
484         """
485         ## if Tetrahedron(geom) is called by mistake
486         if ( isinstance( algo, geompy.GEOM._objref_GEOM_Object)):
487             algo, geom = geom, algo
488             pass
489         return Mesh_Tetrahedron(self, algo, geom)
490
491     def Hexahedron(self, geom=0):
492         """
493          Creates a hexahedron 3D algorithm for solids.
494          If the optional \a geom parameter is not sets, this algorithm is global.
495          Otherwise, this algorithm define a submesh based on \a geom subshape.
496          \param geom If defined, subshape to be meshed
497         """
498         return Mesh_Hexahedron(self, geom)
499
500     def Compute(self):
501         """
502         Compute the mesh and return the status of the computation
503         """
504         ok = smesh.Compute(self.mesh, self.geom)
505         if not ok:
506             errors = smesh.GetAlgoState( self.mesh, self.geom )
507             allReasons = ""
508             for err in errors:
509                 if err.isGlobalAlgo:
510                     glob = " global "
511                 else:
512                     glob = " local "
513                     pass
514                 dim = str(err.algoDim)
515                 if err.name == SMESH.MISSING_ALGO:
516                     reason = glob + dim + "D algorithm is missing"
517                 elif err.name == SMESH.MISSING_HYPO:
518                     name = '"' + err.algoName + '"'
519                     reason = glob + dim + "D algorithm " + name + " misses " + dim + "D hypothesis"
520                 else:
521                     reason = "Global \"Not Conform mesh allowed\" hypothesis is missing"
522                     pass
523                 if allReasons != "":
524                     allReasons += "\n"
525                     pass
526                 allReasons += reason
527                 pass
528             if allReasons != "":
529                 print '"' + GetName(self.mesh) + '"',"not computed:"
530                 print allReasons
531                 pass
532             pass
533         if salome.sg.hasDesktop():
534             smeshgui = salome.ImportComponentGUI("SMESH")
535             smeshgui.Init(salome.myStudyId)
536             smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), ok )
537             salome.sg.updateObjBrowser(1)
538             pass
539         return ok
540
541     def AutomaticTetrahedralization(self, fineness=0):
542         """
543         Compute tetrahedral mesh using AutomaticLength + MEFISTO + NETGEN
544         The parameter \a fineness [0.-1.] defines mesh fineness
545         """
546         dim = self.MeshDimension()
547         # assign hypotheses
548         self.RemoveGlobalHypotheses()
549         self.Segment().AutomaticLength(fineness)
550         if dim > 1 :
551             self.Triangle().LengthFromEdges()
552             pass
553         if dim > 2 :
554             self.Tetrahedron(NETGEN)
555             pass
556         return self.Compute()
557
558     def AutomaticHexahedralization(self, fineness=0):
559         """
560         Compute hexahedral mesh using AutomaticLength + Quadrangle + Hexahedron
561         The parameter \a fineness [0.-1.] defines mesh fineness
562         """
563         dim = self.MeshDimension()
564         # assign hypotheses
565         self.RemoveGlobalHypotheses()
566         self.Segment().AutomaticLength(fineness)
567         if dim > 1 :
568             self.Quadrangle()
569             pass
570         if dim > 2 :
571             self.Hexahedron()            
572             pass
573         return self.Compute()
574
575     def RemoveGlobalHypotheses(self):
576         """
577         Removes all global hypotheses
578         """
579         current_hyps = self.mesh.GetHypothesisList( self.geom )
580         for hyp in current_hyps:
581             self.mesh.RemoveHypothesis( self.geom, hyp )
582             pass
583         pass
584
585     def Group(self, grp, name=""):
586         """
587          Create a mesh group based on geometric object \a grp
588          and give a \a name, if this parameter is not defined
589          the name is the same as the geometric group name
590          \param grp  is a geometric group, a vertex, an edge, a face or a solid
591          \param name is the name of the mesh group
592         """
593         if name == "":
594             name = grp.GetName()
595
596         type = []
597         tgeo = str(grp.GetShapeType())
598         if tgeo == "VERTEX":
599             type = SMESH.NODE
600         elif tgeo == "EDGE":
601             type = SMESH.EDGE
602         elif tgeo == "FACE":
603             type = SMESH.FACE
604         elif tgeo == "SOLID":
605             type = SMESH.VOLUME
606         elif tgeo == "SHELL":
607             type = SMESH.VOLUME
608         elif tgeo == "COMPOUND":
609             tgeo = geompy.GetType(grp)
610             if tgeo == geompy.ShapeType["VERTEX"]:
611                 type = SMESH.NODE
612             elif tgeo == geompy.ShapeType["EDGE"]:
613                 type = SMESH.EDGE
614             elif tgeo == geompy.ShapeType["FACE"]:
615                 type = SMESH.FACE
616             elif tgeo == geompy.ShapeType["SOLID"]:
617                 type = SMESH.VOLUME
618
619         if type == []:
620             print "Mesh.Group: bad first argument: expected a group, a vertex, an edge, a face or a solid"
621             return 0
622         else:
623             return self.mesh.CreateGroupFromGEOM(type, name, grp)
624
625     def ExportToMED(self, f, version, opt=0):
626         """
627          Export the mesh in a file with the MED format and choice the \a version of MED format
628          \param f is the file name
629          \param version values are SMESH.MED_V2_1, SMESH.MED_V2_2
630         """
631         self.mesh.ExportToMED(f, opt, version)
632
633     def ExportMED(self, f, opt=0):
634         """
635          Export the mesh in a file with the MED format
636          \param f is the file name
637         """
638         self.mesh.ExportMED(f, opt)
639
640     def ExportDAT(self, f):
641         """
642          Export the mesh in a file with the DAT format
643          \param f is the file name
644         """
645         self.mesh.ExportDAT(f)
646
647     def ExportUNV(self, f):
648         """
649          Export the mesh in a file with the UNV format
650          \param f is the file name
651         """
652         self.mesh.ExportUNV(f)
653
654     def ExportSTL(self, f, ascii=1):
655         """
656          Export the mesh in a file with the STL format
657          \param f is the file name
658          \param ascii defined the kind of file contents
659         """
660         self.mesh.ExportSTL(f, ascii)