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