# Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # ## @package smesh_algorithm # Python API for base Mesh_Algorithm class. # This package is a part of SALOME %Mesh module Python API import salome from salome.geom import geomBuilder import SMESH, StdMeshers class Mesh_Algorithm: """ The base class to define meshing algorithms Note: This class should not be used directly, it is supposed to be sub-classed for implementing Python API for specific meshing algorithms For each meshing algorithm, a python class inheriting from class *Mesh_Algorithm* should be defined. This descendant class should have two attributes defining the way it is created by class :class:`~smeshBuilder.Mesh` (see e.g. class :class:`~StdMeshersBuilder.StdMeshersBuilder_Segment`): - :code:`meshMethod` attribute defines name of method of class :class:`~smeshBuilder.Mesh` by calling which the python class of algorithm is created; this method is dynamically added to the :class:`~smeshBuilder.Mesh` class in runtime. For example, if in :code:`class MyPlugin_Algorithm` this attribute is defined as:: meshMethod = "MyAlgorithm" then an instance of :code:`MyPlugin_Algorithm` can be created by the direct invocation of the function of :class:`~smeshBuilder.Mesh` class:: my_algo = mesh.MyAlgorithm() - :code:`algoType` defines type of algorithm and is used mostly to discriminate algorithms that are created by the same method of class :class:`~smeshBuilder.Mesh`. For example, if this attribute is specified in :code:`MyPlugin_Algorithm` class as:: algoType = "MyPLUGIN" then it's creation code can be:: my_algo = mesh.MyAlgorithm(algo="MyPLUGIN") """ def __init__(self): """ Private constructor """ self.mesh = None self.geom = None self.subm = None self.algo = None pass def FindHypothesis (self, hypname, args, CompareMethod, smeshpyD): """ Finds a hypothesis in the study by its type name and parameters. Finds only the hypotheses created in smeshBuilder engine. Returns: :class:`~SMESH.SMESH_Hypothesis` """ study = salome.myStudy if not study: return None #to do: find component by smeshpyD object, not by its data type scomp = study.FindComponent(smeshpyD.ComponentDataType()) if scomp is not None: res,hypRoot = scomp.FindSubObject(SMESH.Tag_HypothesisRoot) # Check if the root label of the hypotheses exists if res and hypRoot is not None: iter = study.NewChildIterator(hypRoot) # Check all published hypotheses while iter.More(): hypo_so_i = iter.Value() attr = hypo_so_i.FindAttribute("AttributeIOR")[1] if attr is not None: anIOR = attr.Value() if not anIOR: continue # prevent exception in orb.string_to_object() hypo_o_i = salome.orb.string_to_object(anIOR) if hypo_o_i is not None: # Check if this is a hypothesis hypo_i = hypo_o_i._narrow(SMESH.SMESH_Hypothesis) if hypo_i is not None: # Check if the hypothesis belongs to current engine if smeshpyD.GetObjectId(hypo_i) > 0: # Check if this is the required hypothesis if hypo_i.GetName() == hypname: # Check arguments if CompareMethod(hypo_i, args): # found!!! return hypo_i pass pass pass pass pass iter.Next() pass pass pass return None def FindAlgorithm (self, algoname, smeshpyD): """ Finds the algorithm in the study by its type name. Finds only the algorithms, which have been created in smeshBuilder engine. Returns: SMESH.SMESH_Algo """ study = salome.myStudy if not study: return None #to do: find component by smeshpyD object, not by its data type scomp = study.FindComponent(smeshpyD.ComponentDataType()) if scomp is not None: res,hypRoot = scomp.FindSubObject(SMESH.Tag_AlgorithmsRoot) # Check if the root label of the algorithms exists if res and hypRoot is not None: iter = study.NewChildIterator(hypRoot) # Check all published algorithms while iter.More(): algo_so_i = iter.Value() attr = algo_so_i.FindAttribute("AttributeIOR")[1] if attr is not None: anIOR = attr.Value() if not anIOR: continue # prevent exception in orb.string_to_object() algo_o_i = salome.orb.string_to_object(anIOR) if algo_o_i is not None: # Check if this is an algorithm algo_i = algo_o_i._narrow(SMESH.SMESH_Algo) if algo_i is not None: # Checks if the algorithm belongs to the current engine if smeshpyD.GetObjectId(algo_i) > 0: # Check if this is the required algorithm if algo_i.GetName() == algoname: # found!!! return algo_i pass pass pass pass iter.Next() pass pass pass return None def GetSubMesh(self): """ If the algorithm is global, returns 0; else returns the :class:`~SMESH.SMESH_subMesh` associated to this algorithm. """ return self.subm def GetAlgorithm(self): """ Returns the wrapped mesher. """ return self.algo def GetCompatibleHypothesis(self): """ Gets the list of hypothesis that can be used with this algorithm """ mylist = [] if self.algo: mylist = self.algo.GetCompatibleHypothesis() return mylist def GetName(self): """ Gets the name of the algorithm """ from salome.smesh.smeshBuilder import GetName return GetName(self.algo) def SetName(self, name): """ Sets the name to the algorithm """ self.mesh.smeshpyD.SetName(self.algo, name) def GetId(self): """ Gets the id of the algorithm """ return self.algo.GetId() def Create(self, mesh, geom, hypo, so="libStdMeshersEngine.so"): """ Private method. """ if geom is None and mesh.mesh.HasShapeToMesh(): raise RuntimeError("Attempt to create " + hypo + " algorithm on None shape") algo = self.FindAlgorithm(hypo, mesh.smeshpyD) if algo is None: algo = mesh.smeshpyD.CreateHypothesis(hypo, so) pass self.Assign(algo, mesh, geom) return self.algo def Assign(self, algo, mesh, geom): """ Private method """ from salome.smesh.smeshBuilder import AssureGeomPublished, TreatHypoStatus, GetName if geom is None and mesh.mesh.HasShapeToMesh(): raise RuntimeError("Attempt to create " + algo + " algorithm on None shape") self.mesh = mesh if not geom or geom.IsSame( mesh.geom ): self.geom = mesh.geom else: self.geom = geom AssureGeomPublished( mesh, geom ) self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName()) self.algo = algo status = mesh.AddHypothesis(self.algo, self.geom) return def CompareHyp (self, hyp, args): print("CompareHyp is not implemented for ", self.__class__.__name__, ":", hyp.GetName()) return False def CompareEqualHyp (self, hyp, args): return True def Hypothesis (self, hyp, args=[], so="libStdMeshersEngine.so", UseExisting=0, CompareMethod="", toAdd=True): """ Private method """ from salome.smesh.smeshBuilder import TreatHypoStatus, GetName hypo = None if UseExisting: if CompareMethod == "": CompareMethod = self.CompareHyp hypo = self.FindHypothesis(hyp, args, CompareMethod, self.mesh.smeshpyD) pass if hypo is None: hypo = self.mesh.smeshpyD.CreateHypothesis(hyp, so) a = "" s = "=" for arg in args: argStr = str(arg) if isinstance( arg, geomBuilder.GEOM._objref_GEOM_Object ): argStr = arg.GetStudyEntry() if not argStr: argStr = "GEOM_Obj_%s", arg.GetEntry() if len( argStr ) > 10: argStr = argStr[:7]+"..." if argStr[0] == '[': argStr += ']' a = a + s + argStr s = "," pass if len(a) > 50: a = a[:47]+"..." self.mesh.smeshpyD.SetName(hypo, hyp + a) pass geomName="" if self.geom: geomName = GetName(self.geom) if toAdd: status = self.mesh.mesh.AddHypothesis(self.geom, hypo) TreatHypoStatus( status, GetName(hypo), geomName, 0, self.mesh ) return hypo def MainShapeEntry(self): """ Returns entry of the shape to mesh in the study """ if not self.mesh or not self.mesh.GetMesh(): return "" if not self.mesh.GetMesh().HasShapeToMesh(): return "" shape = self.mesh.GetShape() return shape.GetStudyEntry() def ViscousLayers(self, thickness, numberOfLayers, stretchFactor, faces=[], isFacesToIgnore=True, extrMethod=StdMeshers.SURF_OFFSET_SMOOTH ): """ Defines "ViscousLayers" hypothesis to give parameters of layers of prisms to build near mesh boundary. This hypothesis can be used by several 3D algorithms: NETGEN 3D, MG-Tetra, Hexahedron(i,j,k) Parameters: thickness: total thickness of layers of prisms numberOfLayers: number of layers of prisms stretchFactor: factor (>1.0) of growth of layer thickness towards inside of mesh faces: list of geometrical faces (or their ids). Viscous layers are either generated on these faces or not, depending on the value of **isFacesToIgnore** parameter. isFacesToIgnore: if *True*, the Viscous layers are not generated on the faces specified by the previous parameter (**faces**). extrMethod: extrusion method defines how position of new nodes are found during prism construction and how creation of distorted and intersecting prisms is prevented. Possible values are: - StdMeshers.SURF_OFFSET_SMOOTH (default) method extrudes nodes along normal to underlying geometrical surface. Smoothing of internal surface of element layers can be used to avoid creation of invalid prisms. - StdMeshers.FACE_OFFSET method extrudes nodes along average normal of surrounding mesh faces till intersection with a neighbor mesh face translated along its own normal by the layers thickness. Thickness of layers can be limited to avoid creation of invalid prisms. - StdMeshers.NODE_OFFSET method extrudes nodes along average normal of surrounding mesh faces by the layers thickness. Thickness of layers can be limited to avoid creation of invalid prisms. """ if not isinstance(self.algo, SMESH._objref_SMESH_3D_Algo): raise TypeError("ViscousLayers are supported by 3D algorithms only") if not "ViscousLayers" in self.GetCompatibleHypothesis(): raise TypeError("ViscousLayers are not supported by %s"%self.algo.GetName()) if faces and isinstance( faces, geomBuilder.GEOM._objref_GEOM_Object ): faces = [ faces ] if faces and isinstance( faces[0], geomBuilder.GEOM._objref_GEOM_Object ): faceIDs = [] for shape in faces: ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] ) for f in ff: faceIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f)) faces = faceIDs hyp = self.Hypothesis("ViscousLayers", [thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore], toAdd=False) hyp.SetTotalThickness( thickness ) hyp.SetNumberLayers( numberOfLayers ) hyp.SetStretchFactor( stretchFactor ) hyp.SetFaces( faces, isFacesToIgnore ) hyp.SetMethod( extrMethod ) self.mesh.AddHypothesis( hyp, self.geom ) return hyp def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor, edges=[], isEdgesToIgnore=True ): """ Defines "ViscousLayers2D" hypothesis to give parameters of layers of quadrilateral elements to build near mesh boundary. This hypothesis can be used by several 2D algorithms: NETGEN 2D, NETGEN 1D-2D, Quadrangle (mapping), MEFISTO, MG-CADSurf Parameters: thickness: total thickness of layers of quadrilaterals numberOfLayers: number of layers stretchFactor: factor (>1.0) of growth of layer thickness towards inside of mesh edges: list of geometrical edges (or their ids). Viscous layers are either generated on these edges or not, depending on the value of **isEdgesToIgnore** parameter. isEdgesToIgnore: if *True*, the Viscous layers are not generated on the edges specified by the previous parameter (**edges**). """ if not isinstance(self.algo, SMESH._objref_SMESH_2D_Algo): raise TypeError("ViscousLayers2D are supported by 2D algorithms only") if not "ViscousLayers2D" in self.GetCompatibleHypothesis(): raise TypeError("ViscousLayers2D are not supported by %s"%self.algo.GetName()) if edges and not isinstance( edges, list ) and not isinstance( edges, tuple ): edges = [edges] if edges and isinstance( edges[0], geomBuilder.GEOM._objref_GEOM_Object ): edgeIDs = [] for shape in edges: ee = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"]) for e in ee: edgeIDs.append( self.mesh.geompyD.GetSubShapeID( self.mesh.geom, e )) edges = edgeIDs hyp = self.Hypothesis("ViscousLayers2D", [thickness, numberOfLayers, stretchFactor, edges, isEdgesToIgnore], toAdd=False) hyp.SetTotalThickness(thickness) hyp.SetNumberLayers(numberOfLayers) hyp.SetStretchFactor(stretchFactor) hyp.SetEdges(edges, isEdgesToIgnore) self.mesh.AddHypothesis( hyp, self.geom ) return hyp def ReversedEdgeIndices(self, reverseList): """ Transform a list of either edges or tuples (edge, 1st_vertex_of_edge) into a list acceptable to SetReversedEdges() of some 1D hypotheses """ from salome.smesh.smeshBuilder import FirstVertexOnCurve resList = [] geompy = self.mesh.geompyD for i in reverseList: if isinstance( i, int ): s = geompy.SubShapes(self.mesh.geom, [i])[0] if s.GetShapeType() != geomBuilder.GEOM.EDGE: raise TypeError("Not EDGE index given") resList.append( i ) elif isinstance( i, geomBuilder.GEOM._objref_GEOM_Object ): if i.GetShapeType() != geomBuilder.GEOM.EDGE: raise TypeError("Not an EDGE given") resList.append( geompy.GetSubShapeID(self.mesh.geom, i )) elif len( i ) > 1: e = i[0] v = i[1] if not isinstance( e, geomBuilder.GEOM._objref_GEOM_Object ) or \ not isinstance( v, geomBuilder.GEOM._objref_GEOM_Object ): raise TypeError("A list item must be a tuple (edge, 1st_vertex_of_edge)") if v.GetShapeType() == geomBuilder.GEOM.EDGE and \ e.GetShapeType() == geomBuilder.GEOM.VERTEX: v,e = e,v if e.GetShapeType() != geomBuilder.GEOM.EDGE or \ v.GetShapeType() != geomBuilder.GEOM.VERTEX: raise TypeError("A list item must be a tuple (edge, 1st_vertex_of_edge)") vFirst = FirstVertexOnCurve( self.mesh, e ) tol = geompy.Tolerance( vFirst )[-1] if geompy.MinDistance( v, vFirst ) > 1.5*tol: resList.append( geompy.GetSubShapeID(self.mesh.geom, e )) else: raise TypeError("Item must be either an edge or tuple (edge, 1st_vertex_of_edge)") return resList