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