Salome HOME
Join modifications from branch OCC_debug_for_3_2_0b1
[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_Netgen
387 # ------------------------------
388
389 class Mesh_Netgen(Mesh_Algorithm):
390     """
391     Class to define a NETGEN-based 2D or 3D algorithm
392     that need no discrete boundary (i.e. independent)
393     """
394
395     is3D = 0
396
397     def __init__(self, mesh, is3D, geom=0):
398         """
399          Private constructor
400         """
401         self.is3D = is3D
402         if is3D:
403             self.Create(mesh, geom, "NETGEN_2D3D", "libNETGENEngine.so")
404         else:
405             self.Create(mesh, geom, "NETGEN_2D", "libNETGENEngine.so")
406
407     def Parameters(self):
408         """
409          Define hypothesis containing parameters of the algorithm
410         """
411         if self.is3D:
412             hyp = self.Hypothesis("NETGEN_Parameters", [], "libNETGENEngine.so")
413         else:
414             hyp = self.Hypothesis("NETGEN_Parameters_2D", [], "libNETGENEngine.so")
415         return hyp
416
417 # Public class: Mesh
418 # ==================
419
420 class Mesh:
421     """
422     Class to define a mesh
423     """
424
425     geom = 0
426     mesh = 0
427
428     def __init__(self, geom, name=0):
429         """
430          Constructor
431
432          Creates mesh on the shape \a geom,
433          sets GUI name of this mesh to \a name.
434          \param geom Shape to be meshed
435          \param name Study name of the mesh
436         """
437         self.geom = geom
438         self.mesh = smesh.CreateMesh(geom)
439         if name == 0:
440             SetName(self.mesh, GetName(geom))
441         else:
442             SetName(self.mesh, name)
443
444     def GetMesh(self):
445         """
446          Method that returns the mesh
447         """
448         return self.mesh
449
450     def GetShape(self):
451         """
452          Method that returns the shape associated to the mesh
453         """
454         return self.geom
455
456     def MeshDimension(self):
457         """
458         Returns mesh dimension depending on shape one
459         """
460         shells = geompy.SubShapeAllIDs( self.geom, geompy.ShapeType["SHELL"] )
461         if len( shells ) > 0 :
462             return 3
463         elif geompy.NumberOfFaces( self.geom ) > 0 :
464             return 2
465         elif geompy.NumberOfEdges( self.geom ) > 0 :
466             return 1
467         else:
468             return 0;
469         pass
470
471     def Segment(self, algo=REGULAR, geom=0):
472         """
473          Creates a segment discretization 1D algorithm.
474          If the optional \a algo parameter is not sets, this algorithm is REGULAR.
475          If the optional \a geom parameter is not sets, this algorithm is global.
476          Otherwise, this algorithm define a submesh based on \a geom subshape.
477          \param algo values are smesh.REGULAR or smesh.PYTHON for discretization via python function
478          \param geom If defined, subshape to be meshed
479         """
480         ## if Segment(geom) is called by mistake
481         if ( isinstance( algo, geompy.GEOM._objref_GEOM_Object)):
482             algo, geom = geom, algo
483             pass
484         if algo == REGULAR:
485             return Mesh_Segment(self, geom)
486         elif algo == PYTHON:
487             return Mesh_Segment_Python(self, geom)
488         else:
489             return Mesh_Segment(self, geom)
490
491     def Triangle(self, geom=0):
492         """
493          Creates a triangle 2D algorithm for faces.
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_Triangle(self, geom)
499
500     def Quadrangle(self, geom=0):
501         """
502          Creates a quadrangle 2D algorithm for faces.
503          If the optional \a geom parameter is not sets, this algorithm is global.
504          Otherwise, this algorithm define a submesh based on \a geom subshape.
505          \param geom If defined, subshape to be meshed
506         """
507         return Mesh_Quadrangle(self, geom)
508
509     def Tetrahedron(self, algo, geom=0):
510         """
511          Creates a tetrahedron 3D algorithm for solids.
512          The parameter \a algo permits to choice the algorithm: NETGEN or GHS3D
513          If the optional \a geom parameter is not sets, this algorithm is global.
514          Otherwise, this algorithm define a submesh based on \a geom subshape.
515          \param algo values are: smesh.NETGEN, smesh.GHS3D
516          \param geom If defined, subshape to be meshed
517         """
518         ## if Tetrahedron(geom) is called by mistake
519         if ( isinstance( algo, geompy.GEOM._objref_GEOM_Object)):
520             algo, geom = geom, algo
521             pass
522         return Mesh_Tetrahedron(self, algo, geom)
523
524     def Hexahedron(self, geom=0):
525         """
526          Creates a hexahedron 3D algorithm for solids.
527          If the optional \a geom parameter is not sets, this algorithm is global.
528          Otherwise, this algorithm define a submesh based on \a geom subshape.
529          \param geom If defined, subshape to be meshed
530         """
531         return Mesh_Hexahedron(self, geom)
532
533     def Netgen(self, is3D, geom=0):
534         """
535          Creates a NETGEN-based 2D or 3D independent algorithm (i.e. needs no
536          discrete boundary).
537          If the optional \a geom parameter is not sets, this algorithm is global.
538          Otherwise, this algorithm defines a submesh based on \a geom subshape.
539          \param is3D If 0 then algorithm is 2D, otherwise 3D
540          \param geom If defined, subshape to be meshed
541         """
542         return Mesh_Netgen(self, is3D, geom)
543
544     def Compute(self):
545         """
546         Compute the mesh and return the status of the computation
547         """
548         ok = smesh.Compute(self.mesh, self.geom)
549         if not ok:
550             errors = smesh.GetAlgoState( self.mesh, self.geom )
551             allReasons = ""
552             for err in errors:
553                 if err.isGlobalAlgo:
554                     glob = " global "
555                 else:
556                     glob = " local "
557                     pass
558                 dim = str(err.algoDim)
559                 if err.name == SMESH.MISSING_ALGO:
560                     reason = glob + dim + "D algorithm is missing"
561                 elif err.name == SMESH.MISSING_HYPO:
562                     name = '"' + err.algoName + '"'
563                     reason = glob + dim + "D algorithm " + name + " misses " + dim + "D hypothesis"
564                 else:
565                     reason = "Global \"Not Conform mesh allowed\" hypothesis is missing"
566                     pass
567                 if allReasons != "":
568                     allReasons += "\n"
569                     pass
570                 allReasons += reason
571                 pass
572             if allReasons != "":
573                 print '"' + GetName(self.mesh) + '"',"not computed:"
574                 print allReasons
575                 pass
576             pass
577         if salome.sg.hasDesktop():
578             smeshgui = salome.ImportComponentGUI("SMESH")
579             smeshgui.Init(salome.myStudyId)
580             smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), ok )
581             salome.sg.updateObjBrowser(1)
582             pass
583         return ok
584
585     def AutomaticTetrahedralization(self, fineness=0):
586         """
587         Compute tetrahedral mesh using AutomaticLength + MEFISTO + NETGEN
588         The parameter \a fineness [0.-1.] defines mesh fineness
589         """
590         dim = self.MeshDimension()
591         # assign hypotheses
592         self.RemoveGlobalHypotheses()
593         self.Segment().AutomaticLength(fineness)
594         if dim > 1 :
595             self.Triangle().LengthFromEdges()
596             pass
597         if dim > 2 :
598             self.Tetrahedron(NETGEN)
599             pass
600         return self.Compute()
601
602     def AutomaticHexahedralization(self, fineness=0):
603         """
604         Compute hexahedral mesh using AutomaticLength + Quadrangle + Hexahedron
605         The parameter \a fineness [0.-1.] defines mesh fineness
606         """
607         dim = self.MeshDimension()
608         # assign hypotheses
609         self.RemoveGlobalHypotheses()
610         self.Segment().AutomaticLength(fineness)
611         if dim > 1 :
612             self.Quadrangle()
613             pass
614         if dim > 2 :
615             self.Hexahedron()            
616             pass
617         return self.Compute()
618
619     def RemoveGlobalHypotheses(self):
620         """
621         Removes all global hypotheses
622         """
623         current_hyps = self.mesh.GetHypothesisList( self.geom )
624         for hyp in current_hyps:
625             self.mesh.RemoveHypothesis( self.geom, hyp )
626             pass
627         pass
628
629     def Group(self, grp, name=""):
630         """
631          Create a mesh group based on geometric object \a grp
632          and give a \a name, if this parameter is not defined
633          the name is the same as the geometric group name
634          \param grp  is a geometric group, a vertex, an edge, a face or a solid
635          \param name is the name of the mesh group
636         """
637         if name == "":
638             name = grp.GetName()
639
640         type = []
641         tgeo = str(grp.GetShapeType())
642         if tgeo == "VERTEX":
643             type = SMESH.NODE
644         elif tgeo == "EDGE":
645             type = SMESH.EDGE
646         elif tgeo == "FACE":
647             type = SMESH.FACE
648         elif tgeo == "SOLID":
649             type = SMESH.VOLUME
650         elif tgeo == "SHELL":
651             type = SMESH.VOLUME
652         elif tgeo == "COMPOUND":
653             if len( geompy.GetObjectIDs( grp )) == 0:
654                 print "Mesh.Group: empty geometric group", GetName( grp )
655                 return 0
656             tgeo = geompy.GetType(grp)
657             if tgeo == geompy.ShapeType["VERTEX"]:
658                 type = SMESH.NODE
659             elif tgeo == geompy.ShapeType["EDGE"]:
660                 type = SMESH.EDGE
661             elif tgeo == geompy.ShapeType["FACE"]:
662                 type = SMESH.FACE
663             elif tgeo == geompy.ShapeType["SOLID"]:
664                 type = SMESH.VOLUME
665
666         if type == []:
667             print "Mesh.Group: bad first argument: expected a group, a vertex, an edge, a face or a solid"
668             return 0
669         else:
670             return self.mesh.CreateGroupFromGEOM(type, name, grp)
671
672     def ExportToMED(self, f, version, opt=0):
673         """
674          Export the mesh in a file with the MED format and choice the \a version of MED format
675          \param f is the file name
676          \param version values are SMESH.MED_V2_1, SMESH.MED_V2_2
677         """
678         self.mesh.ExportToMED(f, opt, version)
679
680     def ExportMED(self, f, opt=0):
681         """
682          Export the mesh in a file with the MED format
683          \param f is the file name
684         """
685         self.mesh.ExportMED(f, opt)
686
687     def ExportDAT(self, f):
688         """
689          Export the mesh in a file with the DAT format
690          \param f is the file name
691         """
692         self.mesh.ExportDAT(f)
693
694     def ExportUNV(self, f):
695         """
696          Export the mesh in a file with the UNV format
697          \param f is the file name
698         """
699         self.mesh.ExportUNV(f)
700
701     def ExportSTL(self, f, ascii=1):
702         """
703          Export the mesh in a file with the STL format
704          \param f is the file name
705          \param ascii defined the kind of file contents
706         """
707         self.mesh.ExportSTL(f, ascii)