Salome HOME
Fix regressions caused by improvements
[modules/smesh.git] / src / SMESH_SWIG / smesh_algorithm.py
1 # Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
2 #
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License, or (at your option) any later version.
7 #
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 # Lesser General Public License for more details.
12 #
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 #
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 #
19
20 ## @package smesh_algorithm
21 #  Python API for base Mesh_Algorithm class.
22 #  This package is a part of SALOME %Mesh module Python API
23
24 import salome
25 from salome.geom import geomBuilder
26 import SMESH, StdMeshers
27
28 ## The base class to define meshing algorithms
29 #
30 #  @note This class should not be used directly, it is supposed to be sub-classed
31 #  for implementing Python API for specific meshing algorithms
32 #
33 #  For each meshing algorithm, a python class inheriting from class %Mesh_Algorithm
34 #  should be defined. This descendant class should have two attributes defining the way
35 #  it is created by class Mesh (see e.g. class @ref StdMeshersBuilder.StdMeshersBuilder_Segment "StdMeshersBuilder_Segment"
36 #  in StdMeshersBuilder package):
37 #  - @c meshMethod attribute defines name of method of class smesh.Mesh by calling which the
38 #    python class of algorithm is created; this method is dynamically added to the smesh.Mesh class
39 #    in runtime. For example, if in @c class MyPlugin_Algorithm this attribute is defined as
40 #    @code
41 #    meshMethod = "MyAlgorithm"
42 #    @endcode
43 #    then an instance of @c MyPlugin_Algorithm can be created by the direct invocation of the function
44 #    of smesh.Mesh class:
45 #    @code
46 #    my_algo = mesh.MyAlgorithm()
47 #    @endcode
48 #  - @c algoType defines type of algorithm and is used mostly to discriminate
49 #    algorithms that are created by the same method of class smesh.Mesh. For example, if this attribute
50 #    is specified in @c MyPlugin_Algorithm class as
51 #    @code
52 #    algoType = "MyPLUGIN"
53 #    @endcode
54 #    then it's creation code can be:
55 #    @code
56 #    my_algo = mesh.MyAlgorithm(algo="MyPLUGIN")
57 #    @endcode
58 #  @ingroup l2_algorithms
59 class Mesh_Algorithm:
60     
61     ## Private constuctor
62     def __init__(self):
63         self.mesh = None
64         self.geom = None
65         self.subm = None
66         self.algo = None
67         pass
68
69     ## Finds a hypothesis in the study by its type name and parameters.
70     #  Finds only the hypotheses created in smeshpyD engine.
71     #  @return SMESH.SMESH_Hypothesis
72     def FindHypothesis (self, hypname, args, CompareMethod, smeshpyD):
73         study = smeshpyD.GetCurrentStudy()
74         if not study: return None
75         #to do: find component by smeshpyD object, not by its data type
76         scomp = study.FindComponent(smeshpyD.ComponentDataType())
77         if scomp is not None:
78             res,hypRoot = scomp.FindSubObject(SMESH.Tag_HypothesisRoot)
79             # Check if the root label of the hypotheses exists
80             if res and hypRoot is not None:
81                 iter = study.NewChildIterator(hypRoot)
82                 # Check all published hypotheses
83                 while iter.More():
84                     hypo_so_i = iter.Value()
85                     attr = hypo_so_i.FindAttribute("AttributeIOR")[1]
86                     if attr is not None:
87                         anIOR = attr.Value()
88                         hypo_o_i = salome.orb.string_to_object(anIOR)
89                         if hypo_o_i is not None:
90                             # Check if this is a hypothesis
91                             hypo_i = hypo_o_i._narrow(SMESH.SMESH_Hypothesis)
92                             if hypo_i is not None:
93                                 # Check if the hypothesis belongs to current engine
94                                 if smeshpyD.GetObjectId(hypo_i) > 0:
95                                     # Check if this is the required hypothesis
96                                     if hypo_i.GetName() == hypname:
97                                         # Check arguments
98                                         if CompareMethod(hypo_i, args):
99                                             # found!!!
100                                             return hypo_i
101                                         pass
102                                     pass
103                                 pass
104                             pass
105                         pass
106                     iter.Next()
107                     pass
108                 pass
109             pass
110         return None
111
112     ## Finds the algorithm in the study by its type name.
113     #  Finds only the algorithms, which have been created in smeshpyD engine.
114     #  @return SMESH.SMESH_Algo
115     def FindAlgorithm (self, algoname, smeshpyD):
116         study = smeshpyD.GetCurrentStudy()
117         if not study: return None
118         #to do: find component by smeshpyD object, not by its data type
119         scomp = study.FindComponent(smeshpyD.ComponentDataType())
120         if scomp is not None:
121             res,hypRoot = scomp.FindSubObject(SMESH.Tag_AlgorithmsRoot)
122             # Check if the root label of the algorithms exists
123             if res and hypRoot is not None:
124                 iter = study.NewChildIterator(hypRoot)
125                 # Check all published algorithms
126                 while iter.More():
127                     algo_so_i = iter.Value()
128                     attr = algo_so_i.FindAttribute("AttributeIOR")[1]
129                     if attr is not None:
130                         anIOR = attr.Value()
131                         algo_o_i = salome.orb.string_to_object(anIOR)
132                         if algo_o_i is not None:
133                             # Check if this is an algorithm
134                             algo_i = algo_o_i._narrow(SMESH.SMESH_Algo)
135                             if algo_i is not None:
136                                 # Checks if the algorithm belongs to the current engine
137                                 if smeshpyD.GetObjectId(algo_i) > 0:
138                                     # Check if this is the required algorithm
139                                     if algo_i.GetName() == algoname:
140                                         # found!!!
141                                         return algo_i
142                                     pass
143                                 pass
144                             pass
145                         pass
146                     iter.Next()
147                     pass
148                 pass
149             pass
150         return None
151
152     ## If the algorithm is global, returns 0; \n
153     #  else returns the submesh associated to this algorithm.
154     def GetSubMesh(self):
155         return self.subm
156
157     ## Returns the wrapped mesher.
158     def GetAlgorithm(self):
159         return self.algo
160
161     ## Gets the list of hypothesis that can be used with this algorithm
162     def GetCompatibleHypothesis(self):
163         mylist = []
164         if self.algo:
165             mylist = self.algo.GetCompatibleHypothesis()
166         return mylist
167
168     ## Gets the name of the algorithm
169     def GetName(self):
170         from salome.smesh.smeshBuilder import GetName
171         return GetName(self.algo)
172
173     ## Sets the name to the algorithm
174     def SetName(self, name):
175         self.mesh.smeshpyD.SetName(self.algo, name)
176
177     ## Gets the id of the algorithm
178     def GetId(self):
179         return self.algo.GetId()
180
181     ## Private method.
182     def Create(self, mesh, geom, hypo, so="libStdMeshersEngine.so"):
183         if geom is None and mesh.mesh.HasShapeToMesh():
184             raise RuntimeError, "Attemp to create " + hypo + " algoritm on None shape"
185         algo = self.FindAlgorithm(hypo, mesh.smeshpyD)
186         if algo is None:
187             algo = mesh.smeshpyD.CreateHypothesis(hypo, so)
188             pass
189         self.Assign(algo, mesh, geom)
190         return self.algo
191
192     ## Private method
193     def Assign(self, algo, mesh, geom):
194         from salome.smesh.smeshBuilder import AssureGeomPublished, TreatHypoStatus, GetName
195         if geom is None and mesh.mesh.HasShapeToMesh():
196             raise RuntimeError, "Attemp to create " + algo + " algoritm on None shape"
197         self.mesh = mesh
198         if not geom or geom.IsSame( mesh.geom ):
199             self.geom = mesh.geom
200         else:
201             self.geom = geom
202             AssureGeomPublished( mesh, geom )
203             self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName())
204         self.algo = algo
205         status = mesh.AddHypothesis(self.algo, self.geom)
206         return
207
208     def CompareHyp (self, hyp, args):
209         print "CompareHyp is not implemented for ", self.__class__.__name__, ":", hyp.GetName()
210         return False
211
212     def CompareEqualHyp (self, hyp, args):
213         return True
214
215     ## Private method
216     def Hypothesis (self, hyp, args=[], so="libStdMeshersEngine.so",
217                     UseExisting=0, CompareMethod="", toAdd=True):
218         from salome.smesh.smeshBuilder import TreatHypoStatus, GetName
219         hypo = None
220         if UseExisting:
221             if CompareMethod == "": CompareMethod = self.CompareHyp
222             hypo = self.FindHypothesis(hyp, args, CompareMethod, self.mesh.smeshpyD)
223             pass
224         if hypo is None:
225             hypo = self.mesh.smeshpyD.CreateHypothesis(hyp, so)
226             a = ""
227             s = "="
228             for arg in args:
229                 argStr = str(arg)
230                 if isinstance( arg, geomBuilder.GEOM._objref_GEOM_Object ):
231                     argStr = arg.GetStudyEntry()
232                     if not argStr: argStr = "GEOM_Obj_%s", arg.GetEntry()
233                 if len( argStr ) > 10:
234                     argStr = argStr[:7]+"..."
235                     if argStr[0] == '[': argStr += ']'
236                 a = a + s + argStr
237                 s = ","
238                 pass
239             if len(a) > 50:
240                 a = a[:47]+"..."
241             self.mesh.smeshpyD.SetName(hypo, hyp + a)
242             pass
243         geomName=""
244         if self.geom:
245             geomName = GetName(self.geom)
246         if toAdd:
247             status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
248             TreatHypoStatus( status, GetName(hypo), geomName, 0, self.mesh )
249         return hypo
250
251     ## Returns entry of the shape to mesh in the study
252     def MainShapeEntry(self):
253         if not self.mesh or not self.mesh.GetMesh(): return ""
254         if not self.mesh.GetMesh().HasShapeToMesh(): return ""
255         shape = self.mesh.GetShape()
256         return shape.GetStudyEntry()
257
258     ## Defines "ViscousLayers" hypothesis to give parameters of layers of prisms to build
259     #  near mesh boundary. This hypothesis can be used by several 3D algorithms:
260     #  NETGEN 3D, MG-Tetra, Hexahedron(i,j,k)
261     #  @param thickness total thickness of layers of prisms
262     #  @param numberOfLayers number of layers of prisms
263     #  @param stretchFactor factor (>1.0) of growth of layer thickness towards inside of mesh
264     #  @param faces list of geometrical faces (or their ids).
265     #         Viscous layers are either generated on these faces or not, depending on
266     #         the value of \a isFacesToIgnore parameter.
267     #  @param isFacesToIgnore if \c True, the Viscous layers are not generated on the
268     #         faces specified by the previous parameter (\a faces).
269     #  @param extrMethod extrusion method defines how position of new nodes are found during
270     #         prism construction and how creation of distorted and intersecting prisms is
271     #         prevented. Possible values are:
272     #       - StdMeshers.SURF_OFFSET_SMOOTH (default) method extrudes nodes along normal
273     #         to underlying geometrical surface. Smoothing of internal surface of
274     #         element layers can be used to avoid creation of invalid prisms.
275     #       - StdMeshers.FACE_OFFSET method extrudes nodes along average normal of
276     #         surrounding mesh faces till intersection with a neighbor mesh face
277     #         translated along its own normal by the layers thickness. Thickness
278     #         of layers can be limited to avoid creation of invalid prisms.
279     #       - StdMeshers.NODE_OFFSET method extrudes nodes along average normal of
280     #         surrounding mesh faces by the layers thickness. Thickness of
281     #         layers can be limited to avoid creation of invalid prisms.
282     #  @ingroup l3_hypos_additi
283     def ViscousLayers(self, thickness, numberOfLayers, stretchFactor,
284                       faces=[], isFacesToIgnore=True, extrMethod=StdMeshers.SURF_OFFSET_SMOOTH ):
285         if not isinstance(self.algo, SMESH._objref_SMESH_3D_Algo):
286             raise TypeError, "ViscousLayers are supported by 3D algorithms only"
287         if not "ViscousLayers" in self.GetCompatibleHypothesis():
288             raise TypeError, "ViscousLayers are not supported by %s"%self.algo.GetName()
289         if faces and isinstance( faces[0], geomBuilder.GEOM._objref_GEOM_Object ):
290             faceIDs = []
291             for shape in faces:
292                 ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] )
293                 for f in ff:
294                     faceIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f))
295             faces = faceIDs
296         hyp = self.Hypothesis("ViscousLayers",
297                               [thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore],
298                               toAdd=False)
299         hyp.SetTotalThickness( thickness )
300         hyp.SetNumberLayers( numberOfLayers )
301         hyp.SetStretchFactor( stretchFactor )
302         hyp.SetFaces( faces, isFacesToIgnore )
303         hyp.SetMethod( extrMethod )
304         self.mesh.AddHypothesis( hyp, self.geom )
305         return hyp
306
307     ## Defines "ViscousLayers2D" hypothesis to give parameters of layers of quadrilateral
308     #  elements to build near mesh boundary. This hypothesis can be used by several 2D algorithms:
309     #  NETGEN 2D, NETGEN 1D-2D, Quadrangle (mapping), MEFISTO, MG-CADSurf
310     #  @param thickness total thickness of layers of quadrilaterals
311     #  @param numberOfLayers number of layers
312     #  @param stretchFactor factor (>1.0) of growth of layer thickness towards inside of mesh
313     #  @param edges list of geometrical edges (or their ids).
314     #         Viscous layers are either generated on these edges or not, depending on
315     #         the value of \a isEdgesToIgnore parameter.
316     #  @param isEdgesToIgnore if \c True, the Viscous layers are not generated on the
317     #         edges specified by the previous parameter (\a edges).
318     #  @ingroup l3_hypos_additi
319     def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor,
320                         edges=[], isEdgesToIgnore=True ):
321         if not isinstance(self.algo, SMESH._objref_SMESH_2D_Algo):
322             raise TypeError, "ViscousLayers2D are supported by 2D algorithms only"
323         if not "ViscousLayers2D" in self.GetCompatibleHypothesis():
324             raise TypeError, "ViscousLayers2D are not supported by %s"%self.algo.GetName()
325         if edges and isinstance( edges[0], geomBuilder.GEOM._objref_GEOM_Object ):
326             edgeIDs = []
327             for shape in edges:
328                 ee = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"])
329                 for e in ee:
330                     edgeIDs.append( self.mesh.geompyD.GetSubShapeID( self.mesh.geom, e ))
331             edges = edgeIDs
332         hyp = self.Hypothesis("ViscousLayers2D",
333                               [thickness, numberOfLayers, stretchFactor, edges, isEdgesToIgnore],
334                               toAdd=False)
335         hyp.SetTotalThickness(thickness)
336         hyp.SetNumberLayers(numberOfLayers)
337         hyp.SetStretchFactor(stretchFactor)
338         hyp.SetEdges(edges, isEdgesToIgnore)
339         self.mesh.AddHypothesis( hyp, self.geom )
340         return hyp
341
342     ## Transform a list of either edges or tuples (edge, 1st_vertex_of_edge)
343     #  into a list acceptable to SetReversedEdges() of some 1D hypotheses
344     #  @ingroup l3_hypos_1dhyps
345     def ReversedEdgeIndices(self, reverseList):
346         from salome.smesh.smeshBuilder import FirstVertexOnCurve
347         resList = []
348         geompy = self.mesh.geompyD
349         for i in reverseList:
350             if isinstance( i, int ):
351                 s = geompy.SubShapes(self.mesh.geom, [i])[0]
352                 if s.GetShapeType() != geomBuilder.GEOM.EDGE:
353                     raise TypeError, "Not EDGE index given"
354                 resList.append( i )
355             elif isinstance( i, geomBuilder.GEOM._objref_GEOM_Object ):
356                 if i.GetShapeType() != geomBuilder.GEOM.EDGE:
357                     raise TypeError, "Not an EDGE given"
358                 resList.append( geompy.GetSubShapeID(self.mesh.geom, i ))
359             elif len( i ) > 1:
360                 e = i[0]
361                 v = i[1]
362                 if not isinstance( e, geomBuilder.GEOM._objref_GEOM_Object ) or \
363                    not isinstance( v, geomBuilder.GEOM._objref_GEOM_Object ):
364                     raise TypeError, "A list item must be a tuple (edge, 1st_vertex_of_edge)"
365                 if v.GetShapeType() == geomBuilder.GEOM.EDGE and \
366                    e.GetShapeType() == geomBuilder.GEOM.VERTEX:
367                     v,e = e,v
368                 if e.GetShapeType() != geomBuilder.GEOM.EDGE or \
369                    v.GetShapeType() != geomBuilder.GEOM.VERTEX:
370                     raise TypeError, "A list item must be a tuple (edge, 1st_vertex_of_edge)"
371                 vFirst = FirstVertexOnCurve( self.mesh, e )
372                 tol    = geompy.Tolerance( vFirst )[-1]
373                 if geompy.MinDistance( v, vFirst ) > 1.5*tol:
374                     resList.append( geompy.GetSubShapeID(self.mesh.geom, e ))
375             else:
376                 raise TypeError, "Item must be either an edge or tuple (edge, 1st_vertex_of_edge)"
377         return resList
378