X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESH_SWIG%2FsmeshBuilder.py;h=2c7211828d54774216d8c8a6fbdb613a0d35b386;hp=3372442a92c2d6493049601c8dc3d8ed39119785;hb=HEAD;hpb=382f2cc4abb2ee8553a911aeb27348e96c39d197 diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index 3372442a9..ce1bfdc13 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -1,4 +1,4 @@ -# Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE +# Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -216,7 +216,7 @@ NO_NAME = "NoName" def GetName(obj): """ Return a name of an object - + Returns: object name """ @@ -429,26 +429,26 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): def init_smesh(self,geompyD = None): """ Set Geometry component - """ + """ #print("init_smesh") self.UpdateStudy(geompyD) notebook.myStudy = salome.myStudy def Mesh(self, obj=0, name=0): """ - Create a mesh. This mesh can be either + Create a mesh. This mesh can be either * an empty mesh not bound to geometry, if *obj* == 0 * an empty mesh bound to geometry, if *obj* is GEOM.GEOM_Object * a mesh wrapping a :class:`CORBA mesh ` given as *obj* parameter. Parameters: - obj: either + obj: either 1. a :class:`CORBA mesh ` got by calling e.g. :: - salome.myStudy.FindObjectID("0:1:2:3").GetObject() + salome.myStudy.FindObjectID("0:1:2:3").GetObject() 2. a geometrical object for meshing 3. none. @@ -462,6 +462,22 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): obj,name = name,obj return Mesh(self, self.geompyD, obj, name) + def ParallelMesh(self, obj, name=0, split_geom=True): + """ + Create a parallel mesh. + + Parameters: + obj: geometrical object for meshing + name: the name for the new mesh. + split_geom: If True split the geometry and create the assoicated + sub meshes + + Returns: + an instance of class :class:`ParallelMesh`. + """ + return ParallelMesh(self, self.geompyD, obj, + split_geom=split_geom, name=name) + def RemoveMesh( self, mesh ): """ Delete a mesh @@ -648,7 +664,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): if sc: sb.LoadWith(sc, self) pass - + def SetEnablePublish( self, theIsEnablePublish ): """ Set enable publishing in the study. Calling SetEnablePublish( False ) allows to @@ -677,7 +693,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): Create a Mesh object(s) importing data from the given MED file Returns: - a tuple ( list of class :class:`Mesh` instances, + a tuple ( list of class :class:`Mesh` instances, :class:`SMESH.DriverMED_ReadStatus` ) """ @@ -685,18 +701,6 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ] return aMeshes, aStatus - def CreateMeshesFromSAUV( self,theFileName ): - """ - Create a Mesh object(s) importing data from the given SAUV file - - Returns: - a tuple ( list of class :class:`Mesh` instances, :class:`SMESH.DriverMED_ReadStatus` ) - """ - - aSmeshMeshes, aStatus = SMESH._objref_SMESH_Gen.CreateMeshesFromSAUV(self,theFileName) - aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ] - return aMeshes, aStatus - def CreateMeshesFromSTL( self, theFileName ): """ Create a Mesh object importing data from the given STL file @@ -737,6 +741,19 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): if error.comment: print("*** CreateMeshesFromGMF() errors:\n", error.comment) return Mesh(self, self.geompyD, aSmeshMesh), error + def CreateMeshesFromMESHIO(self, theFileName): + """ + Create a Mesh object(s) importing data from from any file supported by meshio library. + + Returns: + a tuple ( list of class :class:`Mesh` instances, + :class:`SMESH.DriverMED_ReadStatus` ) + """ + + aSmeshMeshes, aStatus = SMESH._objref_SMESH_Gen.CreateMeshesFromMESHIO(self, theFileName) + aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ] + return aMeshes, aStatus + def Concatenate( self, meshes, uniteIdenticalGroups, mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False, name = "", meshToAppendTo = None): @@ -756,7 +773,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): Returns: an instance of class :class:`Mesh` - See also: + See also: :meth:`Mesh.Append` """ @@ -785,12 +802,32 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): aMesh = Mesh( self, self.geompyD, aSmeshMesh, name=name ) return aMesh + def CreateDualMesh( self, mesh, meshName, adaptToShape): + """ + Create a dual of a mesh. + + Parameters: + mesh: Tetrahedron mesh + :class:`mesh, `. + + meshName: a name of the new mesh + adpatToShape: if true project boundary points on shape + + Returns: + an instance of class :class:`Mesh` + """ + if isinstance( mesh, Mesh ): + mesh = mesh.GetMesh() + dualMesh = SMESH._objref_SMESH_Gen.CreateDualMesh(self, mesh, meshName, adaptToShape) + return Mesh(self, self.geompyD, dualMesh) + + def CopyMesh( self, meshPart, meshName, toCopyGroups=False, toKeepIDs=False): """ Create a mesh by copying a part of another mesh. Parameters: - meshPart: a part of mesh to copy, either + meshPart: a part of mesh to copy, either :class:`mesh, sub-mesh, group or filter `. To copy nodes or elements not forming any mesh object, pass result of :meth:`Mesh.GetIDSource` as *meshPart* @@ -822,7 +859,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): meshName: an optional name of the new mesh. If omitted, the mesh name is kept. toCopyGroups: to create groups in the new mesh. toReuseHypotheses: to reuse hypotheses of the *sourceMesh*. - toCopyElements: to copy mesh elements present on non-modified sub-shapes of + toCopyElements: to copy mesh elements present on non-modified sub-shapes of *sourceMesh*. Returns: tuple ( ok, newMesh, newGroups, newSubMeshes, newHypotheses, invalidEntries ) @@ -1179,6 +1216,8 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): functor = aFilterMgr.CreateAspectRatio3D() elif theCriterion == FT_Warping: functor = aFilterMgr.CreateWarping() + elif theCriterion == FT_Warping3D: + functor = aFilterMgr.CreateWarping3D() elif theCriterion == FT_MinimumAngle: functor = aFilterMgr.CreateMinimumAngle() elif theCriterion == FT_Taper: @@ -1209,6 +1248,8 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): functor = aFilterMgr.CreateNodeConnectivityNumber() elif theCriterion == FT_BallDiameter: functor = aFilterMgr.CreateBallDiameter() + elif theCriterion == FT_ScaledJacobian: + functor = aFilterMgr.CreateScaledJacobian() else: print("Error: given parameter is not numerical functor type.") aFilterMgr.UnRegister() @@ -1297,7 +1338,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): Returns: minimum distance value - See also: + See also: :meth:`GetMinDistance` """ @@ -1325,7 +1366,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): Returns: :class:`SMESH.Measure` structure or None if input data is invalid - See also: + See also: :meth:`MinDistance` """ @@ -1372,7 +1413,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): Returns: tuple of six values (minX, minY, minZ, maxX, maxY, maxZ) - See also: + See also: :meth:`GetBoundingBox` """ @@ -1393,7 +1434,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): Returns: :class:`SMESH.Measure` structure - See also: + See also: :meth:`BoundingBox` """ @@ -1472,14 +1513,14 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): def GetGravityCenter(self, obj): """ Get gravity center of all nodes of a mesh object. - - Parameters: + + Parameters: obj: :class:`mesh, sub-mesh, group or filter ` - Returns: + Returns: Three components of the gravity center (x,y,z) - See also: + See also: :meth:`Mesh.BaryCenter` """ if isinstance(obj, Mesh): obj = obj.mesh @@ -1493,11 +1534,11 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): """ Computes a radian measure of an angle defined by 3 points: <(p1,p2,p3) - Parameters: - p1,p2,p3: coordinates of 3 points defined by either SMESH.PointStruct + Parameters: + p1,p2,p3: coordinates of 3 points defined by either SMESH.PointStruct or list [x,y,z] - Returns: + Returns: Angle in radians """ if isinstance( p1, list ): p1 = PointStruct(*p1) @@ -1563,13 +1604,13 @@ class Mesh(metaclass = MeshMeta): It also has methods to define groups of mesh elements, to modify a mesh (by addition of new nodes and elements and by changing the existing entities), to get information about a mesh and to export a mesh in different formats. - """ + """ geom = 0 mesh = 0 editor = 0 - def __init__(self, smeshpyD, geompyD, obj=0, name=0): + def __init__(self, smeshpyD, geompyD, obj=0, name=0, parallel=False): """ Constructor @@ -1602,7 +1643,12 @@ class Mesh(metaclass = MeshMeta): else: geo_name = "%s_%s to mesh"%(self.geom.GetShapeType(), id(self.geom)%100) geompyD.addToStudy( self.geom, geo_name ) - self.SetMesh( self.smeshpyD.CreateMesh(self.geom) ) + if parallel and isinstance(self, ParallelMesh): + mymesh = self.smeshpyD.CreateParallelMesh(self.geom) + mymesh2 = mymesh._narrow(SMESH._objref_SMESH_Mesh) + self.SetMesh( mymesh ) + else: + self.SetMesh( self.smeshpyD.CreateMesh(self.geom) ) elif isinstance(obj, SMESH._objref_SMESH_Mesh): self.SetMesh(obj) @@ -1653,17 +1699,17 @@ class Mesh(metaclass = MeshMeta): if self.geom: self.geompyD = None try: - so = salome.ObjectToSObject( self.geom ) - comp = so.GetFatherComponent() - if comp.ComponentDataType() == "SHAPERSTUDY": - import shaperBuilder - self.geompyD = shaperBuilder.New() + if salome.sg.hasDesktop(): + so = salome.ObjectToSObject( self.geom ) + comp = so.GetFatherComponent() + if comp.ComponentDataType() == "SHAPERSTUDY": + import shaperBuilder + self.geompyD = shaperBuilder.New() except: pass if not self.geompyD: self.geompyD = self.geom.GetGen() pass - pass def GetMesh(self): """ @@ -1854,7 +1900,6 @@ class Mesh(metaclass = MeshMeta): geom = self.geom return self.smeshpyD.Evaluate(self.mesh, geom) - def Compute(self, geom=0, discardModifs=False, refresh=False): """ Compute the mesh and return the status of the computation @@ -1969,6 +2014,13 @@ class Mesh(metaclass = MeshMeta): return ok + def CheckCompute(self): + """ + Check if the mesh was properly compute + """ + if not self.mesh.IsComputedOK(): + raise Exception("Could not compute {}".format(self.GetName())) + def GetComputeErrors(self, shape=0 ): """ Return a list of error messages (:class:`SMESH.ComputeError`) of the last :meth:`Compute` @@ -2093,12 +2145,12 @@ class Mesh(metaclass = MeshMeta): def SetMeshOrder(self, submeshes): """ Set priority of sub-meshes. It works in two ways: - + * For sub-meshes with assigned algorithms of same dimension generating mesh of *several dimensions*, it sets the order in which the sub-meshes are computed. * For the rest sub-meshes, it sets the order in which the sub-meshes are checked - when looking for meshing parameters to apply to a sub-shape. To impose the - order in which sub-meshes with uni-dimensional algorithms are computed, + when looking for meshing parameters to apply to a sub-shape. To impose the + order in which sub-meshes with uni-dimensional algorithms are computed, call **submesh.Compute()** in a desired order. Parameters: @@ -2137,7 +2189,7 @@ class Mesh(metaclass = MeshMeta): def AutomaticTetrahedralization(self, fineness=0): """ - Compute a tetrahedral mesh using AutomaticLength + MEFISTO + Tetrahedron + Compute a tetrahedral mesh using AutomaticLength + Triangle + Tetrahedron Parameters: fineness: [0.0,1.0] defines mesh fineness @@ -2299,6 +2351,78 @@ class Mesh(metaclass = MeshMeta): self.mesh.RemoveHypothesis( self.geom, hyp ) pass pass + + def ExportMEDCoupling(self, *args, **kwargs): + """ + Export the mesh in a memory representation. + + Parameters: + auto_groups (boolean): parameter for creating/not creating + the groups Group_On_All_Nodes, Group_On_All_Faces, ... ; + the typical use is auto_groups=False. + overwrite (boolean): parameter for overwriting/not overwriting the file + meshPart: a part of mesh (:class:`sub-mesh, group or filter `) + to export instead of the mesh + autoDimension: if *True* (default), a space dimension of a MED mesh can be either + + - 1D if all mesh nodes lie on OX coordinate axis, or + - 2D if all mesh nodes lie on XOY coordinate plane, or + - 3D in the rest cases. + + If *autoDimension* is *False*, the space dimension is always 3. + fields: list of GEOM fields defined on the shape to mesh. + geomAssocFields: each character of this string means a need to export a + corresponding field; correspondence between fields and characters + is following: + + - 'v' stands for "_vertices_" field; + - 'e' stands for "_edges_" field; + - 'f' stands for "_faces_" field; + - 's' stands for "_solids_" field. + + zTolerance (float): tolerance in Z direction. If Z coordinate of a node is + close to zero within a given tolerance, the coordinate is set to zero. + If *ZTolerance* is negative (default), the node coordinates are kept as is. + saveNumbers(boolean) : enable saving numbers of nodes and cells. + """ + auto_groups = args[0] if len(args) > 0 else False + meshPart = args[1] if len(args) > 1 else None + autoDimension = args[2] if len(args) > 2 else True + fields = args[3] if len(args) > 3 else [] + geomAssocFields = args[4] if len(args) > 4 else '' + z_tolerance = args[5] if len(args) > 5 else -1. + saveNumbers = args[6] if len(args) > 6 else True + # process keywords arguments + auto_groups = kwargs.get("auto_groups", auto_groups) + meshPart = kwargs.get("meshPart", meshPart) + autoDimension = kwargs.get("autoDimension", autoDimension) + fields = kwargs.get("fields", fields) + geomAssocFields = kwargs.get("geomAssocFields", geomAssocFields) + z_tolerance = kwargs.get("zTolerance", z_tolerance) + saveNumbers = kwargs.get("saveNumbers", saveNumbers) + + # invoke engine's function + if meshPart or fields or geomAssocFields or z_tolerance > 0 or not saveNumbers: + unRegister = genObjUnRegister() + if isinstance( meshPart, list ): + meshPart = self.GetIDSource( meshPart, SMESH.ALL ) + unRegister.set( meshPart ) + + z_tolerance,Parameters,hasVars = ParseParameters(z_tolerance) + self.mesh.SetParameters(Parameters) + + intPtr = self.mesh.ExportPartToMEDCoupling(meshPart, auto_groups, autoDimension, + fields, geomAssocFields, z_tolerance, + saveNumbers ) + import medcoupling + dab = medcoupling.FromPyIntPtrToDataArrayByte(intPtr) + return medcoupling.MEDFileData.New(dab) + else: + intPtr = self.mesh.ExportMEDCoupling(auto_groups, autoDimension) + import medcoupling + dab = medcoupling.FromPyIntPtrToDataArrayByte(intPtr) + return medcoupling.MEDFileMesh.New(dab) + def ExportMED(self, *args, **kwargs): """ Export the mesh in a file in MED format @@ -2311,13 +2435,14 @@ class Mesh(metaclass = MeshMeta): the typical use is auto_groups=False. version (int): define the version (xy, where version is x.y.z) of MED file format. For instance med 3.2.1 is coded 3*10+2 = 32, med 4.0.0 is coded 4*10+0 = 40. - The rules of compatibility to write a mesh in an older version than - the current version depend on the current version. For instance, + The rules of compatibility to write a mesh in an older version than + the current version depend on the current version. For instance, with med 4.0 it is possible to write/append med files in 4.0.0 (default) or 3.2.1 or 3.3.1 formats. If the version is equal to -1, the version is not changed (default). overwrite (boolean): parameter for overwriting/not overwriting the file - meshPart: a part of mesh (:class:`sub-mesh, group or filter `) to export instead of the mesh + meshPart: a part of mesh (:class:`sub-mesh, group or filter `) + to export instead of the mesh autoDimension: if *True* (default), a space dimension of a MED mesh can be either - 1D if all mesh nodes lie on OX coordinate axis, or @@ -2326,8 +2451,8 @@ class Mesh(metaclass = MeshMeta): If *autoDimension* is *False*, the space dimension is always 3. fields: list of GEOM fields defined on the shape to mesh. - geomAssocFields: each character of this string means a need to export a - corresponding field; correspondence between fields and characters + geomAssocFields: each character of this string means a need to export a + corresponding field; correspondence between fields and characters is following: - 'v' stands for "_vertices_" field; @@ -2335,9 +2460,10 @@ class Mesh(metaclass = MeshMeta): - 'f' stands for "_faces_" field; - 's' stands for "_solids_" field. - zTolerance (float): tolerance in Z direction. If Z coordinate of a node is + zTolerance (float): tolerance in Z direction. If Z coordinate of a node is close to zero within a given tolerance, the coordinate is set to zero. If *ZTolerance* is negative (default), the node coordinates are kept as is. + saveNumbers (boolean) : enable saving numbers of nodes and cells. """ # process positional arguments #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility @@ -2350,6 +2476,7 @@ class Mesh(metaclass = MeshMeta): fields = args[6] if len(args) > 6 else [] geomAssocFields = args[7] if len(args) > 7 else '' z_tolerance = args[8] if len(args) > 8 else -1. + saveNumbers = args[9] if len(args) > 9 else True # process keywords arguments auto_groups = kwargs.get("auto_groups", auto_groups) version = kwargs.get("version", version) @@ -2360,9 +2487,13 @@ class Mesh(metaclass = MeshMeta): fields = kwargs.get("fields", fields) geomAssocFields = kwargs.get("geomAssocFields", geomAssocFields) z_tolerance = kwargs.get("zTolerance", z_tolerance) + saveNumbers = kwargs.get("saveNumbers", saveNumbers) + + if isinstance( meshPart, Mesh): + meshPart = meshPart.GetMesh() # invoke engine's function - if meshPart or fields or geomAssocFields or z_tolerance > 0: + if meshPart or fields or geomAssocFields or z_tolerance > 0 or not saveNumbers: unRegister = genObjUnRegister() if isinstance( meshPart, list ): meshPart = self.GetIDSource( meshPart, SMESH.ALL ) @@ -2373,59 +2504,47 @@ class Mesh(metaclass = MeshMeta): self.mesh.ExportPartToMED( meshPart, fileName, auto_groups, version, overwrite, autoDimension, - fields, geomAssocFields, z_tolerance) + fields, geomAssocFields, z_tolerance, saveNumbers ) else: self.mesh.ExportMED(fileName, auto_groups, version, overwrite, autoDimension) - def ExportSAUV(self, f, auto_groups=0): - """ - Export the mesh in a file in SAUV format - - - Parameters: - f: is the file name - auto_groups: boolean parameter for creating/not creating - the groups Group_On_All_Nodes, Group_On_All_Faces, ... ; - the typical use is auto_groups=False. - """ - - self.mesh.ExportSAUV(f, auto_groups) - - def ExportDAT(self, f, meshPart=None): + def ExportDAT(self, f, meshPart=None, renumber=True): """ Export the mesh in a file in DAT format Parameters: f: the file name meshPart: a part of mesh (:class:`sub-mesh, group or filter `) to export instead of the mesh + renumber(boolean): enable renumbering nodes and cells in order to eliminate holes in numbering """ - if meshPart: + if meshPart or not renumber: unRegister = genObjUnRegister() if isinstance( meshPart, list ): meshPart = self.GetIDSource( meshPart, SMESH.ALL ) unRegister.set( meshPart ) - self.mesh.ExportPartToDAT( meshPart, f ) + self.mesh.ExportPartToDAT( meshPart, f, renumber ) else: - self.mesh.ExportDAT(f) + self.mesh.ExportDAT( f, renumber ) - def ExportUNV(self, f, meshPart=None): + def ExportUNV(self, f, meshPart=None, renumber=True): """ Export the mesh in a file in UNV format Parameters: f: the file name meshPart: a part of mesh (:class:`sub-mesh, group or filter `) to export instead of the mesh + renumber(boolean): enable renumbering nodes and cells in order to eliminate holes in numbering """ - if meshPart: + if meshPart or not renumber: unRegister = genObjUnRegister() if isinstance( meshPart, list ): meshPart = self.GetIDSource( meshPart, SMESH.ALL ) unRegister.set( meshPart ) - self.mesh.ExportPartToUNV( meshPart, f ) + self.mesh.ExportPartToUNV( meshPart, f, renumber ) else: - self.mesh.ExportUNV(f) + self.mesh.ExportUNV( f, renumber ) def ExportSTL(self, f, ascii=1, meshPart=None): """ @@ -2490,6 +2609,47 @@ class Mesh(metaclass = MeshMeta): meshPart = self.mesh self.mesh.ExportGMF(meshPart, f, True) + def ExportMESHIO( + self, + fileName, + selectedFilter, + meshPart + ): + """ + Exports a part of mesh to a file with meshio library + through an intermediate MED file. + + Parametrs described below are the same as for ExportMED() method. + However, we know that _pyMesh::Process(const Handle(_pyCommand)& theCommand) method + change a position of meshPart argument when dump to a Python script for whatever reason + this way: + - to 5th place for ExportMED command + - to last place for the rest commands + + So, for this method meshPart moved to the end of the args. + Look at src/SMESH_I/SMESH_2smeshpy.cxx for related source code. + + The same note is for the name of the method that was dumped as ExportPartToMESHIO(), + but then processing just removes PartTo from the middle of the name as it was done + for all export methods. + + Parameters: + fileName: is the file name + selectedFilter: filter string selected by user in a file dialog + meshPart: a part of mesh (:class:`sub-mesh, group or filter `) + to export instead of the mesh + """ + + if isinstance(meshPart, Mesh): + meshPart = meshPart.GetMesh() + + self.mesh.ExportPartToMESHIO( + meshPart, + fileName, + selectedFilter + ) + + def ExportToMED(self, *args, **kwargs): """ Deprecated, used only for compatibility! Please, use :meth:`ExportMED` method instead. @@ -2509,7 +2669,7 @@ class Mesh(metaclass = MeshMeta): If **autoDimension** is *False*, the space dimension is always 3. """ - + print("WARNING: ExportToMED() is deprecated, use ExportMED() instead") # process positional arguments #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility @@ -2586,7 +2746,7 @@ class Mesh(metaclass = MeshMeta): Create an empty standalone mesh group Parameters: - elementType: the :class:`type ` of elements in the group; + elementType: the :class:`type ` of elements in the group; either of (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME) name: the name of the mesh group @@ -2653,7 +2813,15 @@ class Mesh(metaclass = MeshMeta): elif tgeo == "SOLID" or tgeo == "COMPSOLID": typ = VOLUME elif tgeo == "COMPOUND": - sub = self.geompyD.SubShapeAll( shape, self.geompyD.ShapeType["SHAPE"]) + try: + sub = self.geompyD.SubShapeAll( shape, self.geompyD.ShapeType["SHAPE"]) + except: + # try to get the SHAPERSTUDY engine directly, because GetGen does not work because of + # simplification of access in geomBuilder: omniORB.registerObjref + from SHAPERSTUDY_utils import getEngine + gen = getEngine() + if gen: + sub = gen.GetIShapesOperations().ExtractSubShapes(shape, self.geompyD.ShapeType["SHAPE"], False) if not sub: raise ValueError("_groupTypeFromShape(): empty geometric group or compound '%s'" % GetName(shape)) return self._groupTypeFromShape( sub[0] ) @@ -2818,7 +2986,7 @@ class Mesh(metaclass = MeshMeta): def GetGroups(self, elemType = SMESH.ALL): """ - Get the list of groups existing in the mesh in the order of creation + Get the list of groups existing in the mesh in the order of creation (starting from the oldest one) Parameters: @@ -3529,7 +3697,7 @@ class Mesh(metaclass = MeshMeta): Return the type of mesh element or node Returns: - the value from :class:`SMESH.ElementType` enumeration. + the value from :class:`SMESH.ElementType` enumeration. Return SMESH.ALL if element or node with the given ID does not exist """ @@ -3823,7 +3991,7 @@ class Mesh(metaclass = MeshMeta): Returns: a list of three double values - See also: + See also: :meth:`smeshBuilder.GetGravityCenter` """ @@ -3941,7 +4109,7 @@ class Mesh(metaclass = MeshMeta): Returns: tuple of six values (minX, minY, minZ, maxX, maxY, maxZ) - See Also: + See Also: :meth:`GetBoundingBox()` """ @@ -3964,7 +4132,7 @@ class Mesh(metaclass = MeshMeta): Returns: :class:`SMESH.Measure` structure - See Also: + See Also: :meth:`BoundingBox()` """ @@ -4035,6 +4203,16 @@ class Mesh(metaclass = MeshMeta): return self.editor.RemoveNodes(IDsOfNodes) + def RemoveNodeWithReconnection(self, nodeID ): + """ + Remove a node along with changing surrounding faces to cover a hole. + + Parameters: + nodeID: ID of node to remove + """ + + return self.editor.RemoveNodeWithReconnection( nodeID ) + def RemoveOrphanNodes(self): """ Remove all orphan (free) nodes from mesh @@ -4090,7 +4268,7 @@ class Mesh(metaclass = MeshMeta): Returns: an object (a new group or a temporary :class:`SMESH.SMESH_IDSource`) holding IDs of new and/or found 0D elements. IDs of 0D elements - can be retrieved from the returned object by + can be retrieved from the returned object by calling :meth:`GetIDs() ` """ @@ -4464,7 +4642,7 @@ class Mesh(metaclass = MeshMeta): edges = self.GetIDSource( edges, SMESH.EDGE ) unRegister.set( edges ) return self.editor.Get1DBranches( edges, startNode ) - + def FindSharpEdges( self, angle, addExisting=False ): """ Return sharp edges of faces and non-manifold ones. @@ -4528,6 +4706,30 @@ class Mesh(metaclass = MeshMeta): return self.editor.DeleteDiag(NodeID1, NodeID2) + def AddNodeOnSegment(self, Node1, Node2, position = 0.5): + """ + Replace each triangle bound by Node1-Node2 segment with + two triangles by connecting a node made on the link with a node + opposite to the link. + + Parameters: + Node1: ID of the first node + Node2: ID of the second node + position: location [0,1] of the new node on the segment + """ + return self.editor.AddNodeOnSegment(Node1, Node2, position) + + def AddNodeOnFace(self, face, x, y, z): + """ + Split a face into triangles by adding a new node onto the face + and connecting the new node with face nodes + + Parameters: + face: ID of the face + x,y,z: coordinates of the new node + """ + return self.editor.AddNodeOnFace(face, x, y, z) + def Reorient(self, IDsOfElements=None): """ Reorient elements by ids @@ -4601,6 +4803,29 @@ class Mesh(metaclass = MeshMeta): theFace = -1 return self.editor.Reorient2D( the2DObject, theDirection, theFace, thePoint ) + def Reorient2DByNeighbours(self, objectFaces, referenceFaces=[]): + """ + Reorient faces contained in a list of *objectFaces* + equally to faces contained in a list of *referenceFaces*. + + Parameters: + objectFaces: list of :class:`mesh, sub-mesh, group, filter ` holding faces to reorient. + referenceFaces: list of :class:`sub-mesh, group, filter ` holding reference faces. It can be empty, then any face in *objectFaces* is used as the reference. + + Returns: + number of reoriented faces. + """ + if not isinstance( objectFaces, list ): + objectFaces = [ objectFaces ] + for i,obj2D in enumerate( objectFaces ): + if isinstance( obj2D, Mesh ): + objectFaces[i] = obj2D.GetMesh() + if not isinstance( referenceFaces, list ): + referenceFaces = [ referenceFaces ] + + return self.editor.Reorient2DByNeighbours( objectFaces, referenceFaces ) + + def Reorient2DBy3D(self, the2DObject, the3DObject, theOutsideNormal=True ): """ Reorient faces according to adjacent volumes. @@ -4754,7 +4979,7 @@ class Mesh(metaclass = MeshMeta): a quadrangle. Parameters: - theElements: the faces to be splitted. This can be either + theElements: the faces to be splitted. This can be either :class:`mesh, sub-mesh, group, filter ` or a list of face IDs. By default all quadrangles are split @@ -4823,8 +5048,8 @@ class Mesh(metaclass = MeshMeta): to numerical functors. Returns: - * 1 if 1-3 diagonal is better, - * 2 if 2-4 diagonal is better, + * 1 if 1-3 diagonal is better, + * 2 if 2-4 diagonal is better, * 0 if error occurs. Note: @@ -4976,7 +5201,7 @@ class Mesh(metaclass = MeshMeta): This operation uses :doc:`pattern_mapping` functionality for splitting. Parameters: - theObject: the object from which the list of hexahedrons is taken; + theObject: the object from which the list of hexahedrons is taken; this is :class:`mesh, sub-mesh, group or filter ` theNode000,theNode001: within the range [0,7]; gives the orientation of the pattern relatively each hexahedron: the (0,0,0) key-point of the pattern @@ -5305,6 +5530,32 @@ class Mesh(metaclass = MeshMeta): if mesh: mesh = self.smeshpyD.Mesh(mesh) return mesh, group + def MakeBoundaryOfEachElement(self, groupName="", meshName="", toCopyAll=False, groups=[] ): + """ + Create boundary elements around the whole mesh or groups of elements + + Parameters: + groupName: a name of group to store all boundary elements in, + "" means not to create the group + meshName: a name of a new mesh, which is a copy of the initial + mesh + created boundary elements; "" means not to create the new mesh + toCopyAll: if True, the whole initial mesh will be copied into + the new mesh else only boundary elements will be copied into the new mesh + groups: list of :class:`sub-meshes, groups or filters ` of elements to make boundary around + + Returns: + tuple( long, mesh, group ) + - long - number of added boundary elements + - mesh - the :class:`Mesh` where elements were added to + - group - the :class:`group ` of boundary elements or None + """ + dimension=SMESH.BND_2DFROM3D + toCreateAllElements = True # create all boundary elements in the mesh + nb, mesh, group = self.editor.MakeBoundaryElements( dimension,groupName,meshName, + toCopyAll,toCreateAllElements,groups) + if mesh: mesh = self.smeshpyD.Mesh(mesh) + return nb, mesh, group + def MakeBoundaryElements(self, dimension=SMESH.BND_2DFROM3D, groupName="", meshName="", toCopyAll=False, groups=[]): """ @@ -5328,9 +5579,9 @@ class Mesh(metaclass = MeshMeta): - mesh - the :class:`Mesh` where elements were added to - group - the :class:`group ` of boundary elements or None """ - + toCreateAllElements = False # create only elements in the boundary of the solid nb, mesh, group = self.editor.MakeBoundaryElements(dimension,groupName,meshName, - toCopyAll,groups) + toCopyAll,toCreateAllElements,groups) if mesh: mesh = self.smeshpyD.Mesh(mesh) return nb, mesh, group @@ -5468,7 +5719,7 @@ class Mesh(metaclass = MeshMeta): of all steps, else - size of each step Returns: - the list of created :class:`groups ` if *MakeGroups* == True, + the list of created :class:`groups ` if *MakeGroups* == True, empty list otherwise """ @@ -5524,7 +5775,7 @@ class Mesh(metaclass = MeshMeta): - a list of tree components of the point or - a node ID or - a GEOM point - angles: list of angles in radians. Nodes at each extrusion step are rotated + angles: list of angles in radians. Nodes at each extrusion step are rotated around *basePoint*, additionally to previous steps. anglesVariation: forces the computation of rotation angles as linear variation of the given *angles* along path steps @@ -5742,13 +5993,13 @@ class Mesh(metaclass = MeshMeta): PathShape: optional shape (edge or wire) which defines the sub-mesh of the mesh defined by *PathObject* if the mesh contains not only path segments, else it can be None NodeStart: the first or the last node on the path. Defines the direction of extrusion HasAngles: not used obsolete - Angles: list of angles in radians. Nodes at each extrusion step are rotated + Angles: list of angles in radians. Nodes at each extrusion step are rotated around *basePoint*, additionally to previous steps. LinearVariation: forces the computation of rotation angles as linear variation of the given Angles along path steps HasRefPoint: allows using the reference point RefPoint: optional scaling and rotation center (mass center of the extruded - elements by default). The User can specify any point as the Reference Point. + elements by default). The User can specify any point as the Reference Point. *RefPoint* can be either GEOM Vertex, [x,y,z] or :class:`SMESH.PointStruct` MakeGroups: forces the generation of new groups from existing ones ScaleFactors: optional scale factors to apply during extrusion @@ -5756,7 +6007,7 @@ class Mesh(metaclass = MeshMeta): else *scaleFactors* [i] is applied to nodes at the i-th extrusion step Returns: - list of created :class:`groups ` and + list of created :class:`groups ` and :class:`error code ` Example: :ref:`tui_extrusion_along_path` """ @@ -5776,7 +6027,7 @@ class Mesh(metaclass = MeshMeta): Angles,AnglesParameters,hasVars = ParseAngles(Angles) ScaleFactors,ScalesParameters,hasVars = ParseParameters(ScaleFactors) Parameters = AnglesParameters + var_separator + \ - RefPoint.parameters + var_separator + ScalesParameters + RefPoint.parameters + var_separator + ScalesParameters self.mesh.SetParameters(Parameters) return self.editor.ExtrusionAlongPathObjects(Nodes, Edges, Faces, PathObject, PathShape, NodeStart, @@ -5797,7 +6048,7 @@ class Mesh(metaclass = MeshMeta): Path: 1D mesh or 1D sub-mesh, along which proceeds the extrusion NodeStart: the start node from Path. Defines the direction of extrusion HasAngles: not used obsolete - Angles: list of angles in radians. Nodes at each extrusion step are rotated + Angles: list of angles in radians. Nodes at each extrusion step are rotated around *basePoint*, additionally to previous steps. LinearVariation: forces the computation of rotation angles as linear variation of the given Angles along path steps @@ -5840,7 +6091,7 @@ class Mesh(metaclass = MeshMeta): PathShape: shape (edge) defines the sub-mesh for the path NodeStart: the first or the last node on the edge. Defines the direction of extrusion HasAngles: not used obsolete - Angles: list of angles in radians. Nodes at each extrusion step are rotated + Angles: list of angles in radians. Nodes at each extrusion step are rotated around *basePoint*, additionally to previous steps. HasRefPoint: allows using the reference point RefPoint: the reference point around which the shape is rotated (the mass center of the shape by default). @@ -5881,7 +6132,7 @@ class Mesh(metaclass = MeshMeta): PathShape: shape (edge) defines the sub-mesh for the path NodeStart: the first or the last node on the edge. Defines the direction of extrusion HasAngles: not used obsolete - Angles: list of angles in radians. Nodes at each extrusion step are rotated + Angles: list of angles in radians. Nodes at each extrusion step are rotated around *basePoint*, additionally to previous steps. HasRefPoint: allows using the reference point RefPoint: the reference point around which the shape is rotated (the mass center of the shape by default). @@ -5892,7 +6143,7 @@ class Mesh(metaclass = MeshMeta): variation of the given Angles along path steps Returns: - list of created :class:`groups ` and + list of created :class:`groups ` and :class:`error code ` if *MakeGroups* == True, only :class:`error code ` otherwise Example: :ref:`tui_extrusion_along_path` @@ -5919,7 +6170,7 @@ class Mesh(metaclass = MeshMeta): PathShape: shape (edge) defines the sub-mesh for the path NodeStart: the first or the last node on the edge. Defines the direction of extrusion HasAngles: not used obsolete - Angles: list of angles in radians. Nodes at each extrusion step are rotated + Angles: list of angles in radians. Nodes at each extrusion step are rotated around *basePoint*, additionally to previous steps. HasRefPoint: allows using the reference point RefPoint: the reference point around which the shape is rotated (the mass center of the shape by default). @@ -5930,7 +6181,7 @@ class Mesh(metaclass = MeshMeta): variation of the given Angles along path steps Returns: - list of created :class:`groups ` and + list of created :class:`groups ` and :class:`error code ` if *MakeGroups* == True, only :class:`error code ` otherwise Example: :ref:`tui_extrusion_along_path` @@ -5957,7 +6208,7 @@ class Mesh(metaclass = MeshMeta): PathShape: shape (edge) defines the sub-mesh for the path NodeStart: the first or the last node on the edge. Defines the direction of extrusion HasAngles: not used obsolete - Angles: list of angles in radians. Nodes at each extrusion step are rotated + Angles: list of angles in radians. Nodes at each extrusion step are rotated around *basePoint*, additionally to previous steps. HasRefPoint: allows using the reference point RefPoint: the reference point around which the shape is rotated (the mass center of the shape by default). @@ -5968,7 +6219,7 @@ class Mesh(metaclass = MeshMeta): variation of the given Angles along path steps Returns: - list of created :class:`groups ` and + list of created :class:`groups ` and :class:`error code ` if *MakeGroups* == True, only :class:`error code ` otherwise Example: :ref:`tui_extrusion_along_path` @@ -6378,7 +6629,7 @@ class Mesh(metaclass = MeshMeta): theObject (SMESH.SMESH_IDSource): the source object (mesh, sub-mesh, group or filter) theValue (float): signed offset size MakeGroups (boolean): forces the generation of new groups from existing ones - CopyElements (boolean): if *NewMeshName* is empty, True means to keep original elements, + CopyElements (boolean): if *NewMeshName* is empty, True means to keep original elements, False means to remove original elements. NewMeshName (string): the name of a mesh to create. If empty, offset elements are added to this mesh @@ -6759,7 +7010,7 @@ class Mesh(metaclass = MeshMeta): Parameters: theElements: container of elements to duplicate. It can be a - :class:`mesh, sub-mesh, group, filter ` + :class:`mesh, sub-mesh, group, filter ` or a list of element IDs. If *theElements* is a :class:`Mesh`, elements of highest dimension are duplicated theGroupName: a name of group to contain the generated elements. @@ -6769,7 +7020,7 @@ class Mesh(metaclass = MeshMeta): in any group. Returns: - a :class:`group ` where the new elements are added. + a :class:`group ` where the new elements are added. None if *theGroupName* == "". """ @@ -7038,7 +7289,7 @@ class Mesh(metaclass = MeshMeta): return self.editor.CreateHoleSkin( radius, theShape, groupName, theNodesCoords ) def MakePolyLine(self, segments, groupName='', isPreview=False ): - """ + """ Create a polyline consisting of 1D mesh elements each lying on a 2D element of the initial triangle mesh. Positions of new nodes are found by cutting the mesh by the plane passing through pairs of points specified by each :class:`SMESH.PolySegment` structure. @@ -7056,7 +7307,7 @@ class Mesh(metaclass = MeshMeta): segments: list of :class:`SMESH.PolySegment` defining positions of cutting planes. groupName: optional name of a group where created mesh segments will be added. - """ + """ editor = self.editor if isPreview: editor = self.mesh.GetMeshEditPreviewer() @@ -7211,10 +7462,10 @@ class Mesh(metaclass = MeshMeta): """ Computes a radian measure of an angle defined by 3 nodes: <(node1,node2,node3) - Parameters: + Parameters: node1,node2,node3: IDs of the three nodes - Returns: + Returns: Angle in radians [0,PI]. -1 if failure case. """ p1 = self.GetNodeXYZ( node1 ) @@ -7272,6 +7523,19 @@ class Mesh(metaclass = MeshMeta): return self.FunctorValue(SMESH.FT_Warping, elemId) + def GetWarping3D(self, elemId): + """ + Get warping angle of faces element of 3D elements. + + Parameters: + elemId: mesh element ID + + Returns: + element's warping angle value + """ + + return self.FunctorValue(SMESH.FT_Warping3D, elemId) + def GetMinimumAngle(self, elemId): """ Get minimum angle of 2D element. @@ -7311,6 +7575,19 @@ class Mesh(metaclass = MeshMeta): return self.FunctorValue(SMESH.FT_Skew, elemId) + def GetScaledJacobian(self, elemId): + """ + Get the scaled jacobian of 3D element id + + Parameters: + elemId: mesh element ID + + Returns: + the scaled jacobian + """ + + return self.FunctorValue(SMESH.FT_ScaledJacobian, elemId) + def GetMinMax(self, funType, meshPart=None): """ Return minimal and maximal value of a given functor. @@ -7345,6 +7622,447 @@ class Mesh(metaclass = MeshMeta): pass # end of Mesh class +def _copy_gmsh_param(dim, local_param, global_param): + if dim==3: + local_param.SetMaxSize(global_param.GetMaxSize()) + local_param.SetMinSize(global_param.GetMinSize()) + local_param.Set3DAlgo(global_param.Get3DAlgo()) + local_param.SetRecombineAll(global_param.GetRecombineAll()) + local_param.SetSubdivAlgo(global_param.GetSubdivAlgo()) + local_param.SetRemeshAlgo(global_param.GetRemeshAlgo()) + local_param.SetRemeshPara(global_param.GetRemeshPara()) + local_param.SetSmouthSteps(global_param.GetSmouthSteps()) + local_param.SetSizeFactor(global_param.GetSizeFactor()) + local_param.SetUseIncomplElem(global_param.GetUseIncomplElem()) + local_param.SetMeshCurvatureSize(global_param.GetMeshCurvatureSize()) + local_param.SetSecondOrder(global_param.GetSecondOrder()) + local_param.SetIs2d(global_param.GetIs2d()) + elif dim==2: + local_param.SetMaxSize(global_param.GetMaxSize()) + local_param.SetMinSize(global_param.GetMinSize()) + local_param.Set2DAlgo(global_param.Get2DAlgo()) + local_param.SetRecomb2DAlgo(global_param.GetRecomb2DAlgo()) + local_param.SetRecombineAll(global_param.GetRecombineAll()) + local_param.SetSubdivAlgo(global_param.GetSubdivAlgo()) + local_param.SetRemeshAlgo(global_param.GetRemeshAlgo()) + local_param.SetRemeshPara(global_param.GetRemeshPara()) + local_param.SetSmouthSteps(global_param.GetSmouthSteps()) + local_param.SetSizeFactor(global_param.GetSizeFactor()) + local_param.SetUseIncomplElem(global_param.GetUseIncomplElem()) + local_param.SetMeshCurvatureSize(global_param.GetMeshCurvatureSize()) + local_param.SetSecondOrder(global_param.GetSecondOrder()) + local_param.SetIs2d(global_param.GetIs2d()) + +def _copy_netgen_param(dim, local_param, global_param): + """ + Create 1D/2D/3D netgen parameters from a NETGEN 1D2D3D parameter + """ + if dim==1: + #TODO: More global conversion ? or let user define it + local_param.NumberOfSegments(int(global_param.GetMaxSize())) + elif dim==2: + local_param.SetMaxSize(global_param.GetMaxSize()) + local_param.SetMinSize(global_param.GetMinSize()) + local_param.SetOptimize(global_param.GetOptimize()) + local_param.SetFineness(global_param.GetFineness()) + local_param.SetNbSegPerEdge(global_param.GetNbSegPerEdge()) + local_param.SetNbSegPerRadius(global_param.GetNbSegPerRadius()) + #TODO: Why the 0.9 to have same results + local_param.SetGrowthRate(global_param.GetGrowthRate()*0.9) + local_param.SetChordalError(global_param.GetChordalError()) + local_param.SetChordalErrorEnabled(global_param.GetChordalErrorEnabled()) + local_param.SetUseSurfaceCurvature(global_param.GetUseSurfaceCurvature()) + local_param.SetUseDelauney(global_param.GetUseDelauney()) + local_param.SetQuadAllowed(global_param.GetQuadAllowed()) + local_param.SetWorstElemMeasure(global_param.GetWorstElemMeasure()) + local_param.SetCheckChartBoundary(global_param.GetCheckChartBoundary()) + local_param.SetNbThreads(global_param.GetNbThreads()) + else: + local_param.SetMaxSize(global_param.GetMaxSize()) + local_param.SetMinSize(global_param.GetMinSize()) + local_param.SetOptimize(global_param.GetOptimize()) + local_param.SetCheckOverlapping(global_param.GetCheckOverlapping()) + local_param.SetCheckChartBoundary(global_param.GetCheckChartBoundary()) + local_param.SetFineness(global_param.GetFineness()) + local_param.SetNbSegPerEdge(global_param.GetNbSegPerEdge()) + local_param.SetNbSegPerRadius(global_param.GetNbSegPerRadius()) + local_param.SetGrowthRate(global_param.GetGrowthRate()) + local_param.SetNbThreads(global_param.GetNbThreads()) + + +def _shaperstudy2geom(geompyD, shaper_obj): + """ + Convertion of shaper object to geom object + + Parameters: + geompyD: geomBuilder instance + shaper_obj: Shaper study object + + Returns: + geom object + + """ + import tempfile + #Writing shaperstudy object into a brep file + fid, tmp_file = tempfile.mkstemp(suffix='.brep') + with open(fid, 'wb') as f: + f.write(shaper_obj.GetShapeStream()) + # Reimporting brep file into geom + real_geom = geompyD.ImportBREP(tmp_file) + os.remove(tmp_file) + + return real_geom + + +def _split_geom(geompyD, geom): + """ + Splitting geometry into n solids and a 2D/1D compound + + Parameters: + geompyD: geomBuilder instance + geom: geometrical object for meshing + + Returns: + compound containing all the 1D,2D elements + list of solids + """ + + # Splitting geometry into 3D elements and all the 2D/1D into one compound + object_solids = geompyD.ExtractShapes(geom, geompyD.ShapeType["SOLID"], + True) + + solids = [] + isolid = 0 + for solid in object_solids: + isolid += 1 + geompyD.addToStudyInFather( geom, solid, 'Solid_{}'.format(isolid) ) + solids.append(solid) + # If geom is a solid ExtractShapes will return nothin in that case geom is the solids + if isolid == 0: + solids = [geom] + + faces = [] + iface = 0 + solid_faces = geompyD.ExtractShapes(geom, geompyD.ShapeType["FACE"], + True) + for face in solid_faces: + faces.append(face) + iface += 1 + geompyD.addToStudyInFather(geom, face, + 'Face_{}'.format(iface)) + + return faces, solids + + +MULTITHREAD, MULTINODE = range(2) +class ParallelismSettings: + """ + Defines the parameters for the parallelism of ParallelMesh + """ + def __init__(self, mesh): + """ + Construsctor + + Parameters: + mesh: Instance of ParallelMesh + """ + if not(isinstance(mesh, ParallelMesh)): + raise ValueError("mesh should be a ParallelMesh") + + self._mesh = mesh + + +class MTParallelismSettings(ParallelismSettings): + """ + Defines the parameters for the parallelism of ParallelMesh using MultiThreading + """ + def __init__(self, mesh): + ParallelismSettings.__init__(self, mesh) + + # Multithreading methods + def SetNbThreads(self, nbThreads): + """ Set the number of threads for multithread """ + if nbThreads < 1: + raise ValueError("Number of threads must be stricly greater than 1") + + self._mesh.mesh.SetNbThreads(nbThreads) + + def GetNbThreads(self): + """ Get Number of threads """ + return self._mesh.mesh.GetNbThreads() + + def __str__(self): + """ str conversion """ + string = "\nParameter for MultiThreading parallelism:\n" + string += "NbThreads: {}\n".format(self.GetNbThreads()) + + return string + + +class MNParallelismSettings(ParallelismSettings): + """ + Defines the parameters for the parallelism of ParallelMesh using MultiNodal + """ + def __init__(self, mesh): + ParallelismSettings.__init__(self, mesh) + + def GetResource(self): + """ Get the resource on which to run """ + return self._mesh.mesh.GetResource() + + def SetResource(self, resource): + """ Set the resource on which to run """ + self._mesh.mesh.SetResource(resource) + + def SetNbProc(self, nbProc): + """ Set the number of Processor for multinode """ + if nbProc < 1: + raise ValueError("Number of Proc must be stricly greater than 1") + self._mesh.mesh.SetNbProc(nbProc) + + def GetNbProc(self): + """ Get Number of Processor """ + return self._mesh.mesh.GetNbProc() + + def SetNbProcPerNode(self, nbProcPerNode): + """ Set the number of Processor Per Node for multinode """ + if nbProcPerNode < 1: + raise ValueError("Number of Processor Per Node must be stricly greater than 1") + + self._mesh.mesh.SetNbProcPerNode(nbProcPerNode) + + def GetNbProcPerNode(self): + """ Get Number of Processor Per Node """ + return self._mesh.mesh.GetNbProcPerNode() + + def SetNbNode(self, nbNode): + """ Set the number of Node for multinode """ + if nbNode < 1: + raise ValueError("Number of Node must be stricly greater than 1") + self._mesh.mesh.SetNbNode(nbNode) + + def GetNbNode(self): + """ Get Number of Node """ + return self._mesh.mesh.GetNbNode() + + def SetWcKey(self, wcKey): + """ Set the number of Node for multinode """ + self._mesh.mesh.SetWcKey(wcKey) + + def GetWcKey(self): + """ Get Number of Node """ + return self._mesh.mesh.GetWcKey() + + def SetWalltime(self, walltime): + """ Set the number of Node for multinode """ + self._mesh.mesh.SetWalltime(walltime) + + def GetWalltime(self): + """ Get Number of Node """ + return self._mesh.mesh.GetWalltime() + + def __str__(self): + """ str conversion """ + string = "\nParameter for MultiNode parallelism:\n" + string += "Reource: {}\n".format(self.GetResource()) + string += "NbProc: {}\n".format(self.GetNbProc()) + string += "NbProcPerNode: {}\n".format(self.GetNbProcPerNode()) + string += "NbNode: {}\n".format(self.GetNbNode()) + string += "WcKey: {}\n".format(self.GetWcKey()) + string += "Walltime: {}\n".format(self.GetWalltime()) + + return string + + +class ParallelMesh(Mesh): + """ + Surcharge on Mesh for parallel computation of a mesh + """ + def __init__(self, smeshpyD, geompyD, geom, split_geom=True, name=0): + """ + Create a parallel mesh. + + Parameters: + smeshpyD: instance of smeshBuilder + geompyD: instance of geomBuilder + geom: geometrical object for meshing + split_geom: If true will divide geometry on solids and 1D/2D + coumpound and create the associated submeshes + name: the name for the new mesh. + + Returns: + an instance of class :class:`ParallelMesh`. + """ + + if not isinstance(geom, geomBuilder.GEOM._objref_GEOM_Object): + raise ValueError("geom argument must be a geometry") + + try: + import SHAPERSTUDY + shaper_object = SHAPERSTUDY.SHAPERSTUDY_ORB._objref_SHAPER_Object + has_shaper = True + except ImportError: + shaper_object = int + has_shaper = False + + # If we have a shaper object converting it into geom (temporary solution) + if isinstance(geom, shaper_object): + self._geom_obj = _shaperstudy2geom(geompyD, geom) + elif isinstance(geom, geomBuilder.GEOM._objref_GEOM_Object): + self._geom_obj = geom + else: + msg= "" + if not has_shaper: + msg = "\nShaper was not compiled" + raise Exception("Could not handle geom format {}.{} ".format(type(geom), msg)) + + # Splitting geometry into one geom containing 1D and 2D elements and a + # list of 3D elements + super(ParallelMesh, self).__init__(smeshpyD, geompyD, self._geom_obj, name, parallel=True) + + if split_geom: + self._faces, self._solids = _split_geom(geompyD, self._geom_obj) + + self._param = None + + def _build_submeshes(self, mesher2D, mesher3D): + """ + Contruct the submeshes for a parallel use of smesh + + Parameters: + mesher2D: name of 2D mesher for 2D parallel compute (NETGEN) + mesher3D: name of 3D mesher for 3D parallel compute (NETGEN or + GMSH) + """ + + # Building global 2D mesher + if mesher3D: + if mesher3D == "NETGEN": + algo2D = "NETGEN_2D" + elif mesher3D == "GMSH": + algo2D = "GMSH_2D" + else: + raise ValueError("mesher3D should be either NETGEN or GMSH") + + self._algo2d = self.Triangle(geom=self._geom_obj, algo=algo2D) + + # Parallel 2D + if mesher2D: + #Means that we want to mesh face of solids in parallel and not + #the volume + self._algo2d = [] + #For the moment use AutomaticLength based on finesse + # TODO: replace by input hypothesis + self._algo1d = self.Segment(geom=self._geom_obj) + + for face_id, face in enumerate(self._faces): + name = "face_{}".format(face_id) + algo2d = self.Triangle(geom=face, algo="NETGEN_2D_Remote") + self._algo2d.append(algo2d) + + if mesher3D: + self._algo3d = [] + for solid_id, solid in enumerate(self._solids): + name = "Solid_{}".format(solid_id) + if ( mesher3D == "NETGEN" ): + algo3d = self.Tetrahedron(geom=solid, algo="NETGEN_3D_Remote") + self._algo3d.append(algo3d) + elif ( mesher3D == "GMSH" ): + algo3d = self.Tetrahedron(geom=solid, algo="GMSH_3D_Remote") + self._algo3d.append(algo3d) + + def GetNbSolids(self): + """ + Return the number of 3D solids + """ + return len(self._solids) + + def GetNbFaces(self): + """ + Return the number of 2D faces + """ + return len(self._faces) + + def GetParallelismMethod(self): + """ Get the parallelims method """ + return self.mesh.GetParallelismMethod() + + def SetParallelismMethod(self, method): + """ Set the parallelims method """ + if method not in [MULTITHREAD , MULTINODE]: + raise ValueError("Parallelism method can only be 0:MultiThread or 1:MultiNode") + + self.mesh.SetParallelismMethod(method) + + if method == MULTITHREAD: + self._param = MTParallelismSettings(self) + else: + self._param = MNParallelismSettings(self) + + def GetParallelismSettings(self): + """ + Return class to set parameters for the parallelism + """ + if self._param is None: + raise Exception("You need to set Parallelism method first (SetParallelismMethod)") + return self._param + + def AddGlobalHypothesis(self, hyp): + """ + Split hypothesis to apply it to all the submeshes: + - the 1D+2D + - each of the 3D solids + + Parameters: + hyp: a hypothesis to assign + + """ + if isinstance(hyp, NETGENPlugin._objref_NETGENPlugin_Hypothesis): + copy_param = _copy_netgen_param + mesher3D = "NETGEN" + elif isinstance(hyp, GMSHPlugin._objref_GMSHPlugin_Hypothesis): + copy_param = _copy_gmsh_param + mesher3D = "GMSH" + else: + raise ValueError("param must come from NETGENPlugin or GMSHPlugin") + + self.mesh.SetParallelismDimension(3) + self._build_submeshes(None, mesher3D) + + param2d = self._algo2d.Parameters() + copy_param(2, param2d, hyp) + + for algo3d in self._algo3d: + param3d = algo3d.Parameters() + copy_param(3, param3d, hyp) + + def Add2DGlobalHypothesis(self, hyp): + """ + Split hypothesis to apply it to all the submeshes: + - the 1D + - each of the 2D faces + + Parameters: + hyp: a hypothesis to assign + + """ + if isinstance(hyp, NETGENPlugin._objref_NETGENPlugin_Hypothesis): + copy_param = _copy_netgen_param + mesher2D = "NETGEN" + else: + raise ValueError("param must come from NETGENPlugin") + + self.mesh.SetParallelismDimension(2) + self._build_submeshes(mesher2D, None) + + param1d = self._algo1d + copy_param(1, param1d, hyp) + + for algo2d in self._algo2d: + param2d = algo2d.Parameters() + copy_param(2, param2d, hyp) + + pass # End of ParallelMesh class meshProxy(SMESH._objref_SMESH_Mesh): """ @@ -7380,10 +8098,28 @@ class meshProxy(SMESH._objref_SMESH_Mesh): while len(args2) < 5: # !!!! nb of parameters for ExportToMED IDL's method args2.append(True) SMESH._objref_SMESH_Mesh.ExportMED(self, *args2) - pass + def ExportUNV(self, *args): # renumber arg added + if len( args ) == 1: + args += True, + return SMESH._objref_SMESH_Mesh.ExportUNV(self, *args) + def ExportDAT(self, *args): # renumber arg added + if len( args ) == 1: + args += True, + return SMESH._objref_SMESH_Mesh.ExportDAT(self, *args) + omniORB.registerObjref(SMESH._objref_SMESH_Mesh._NP_RepositoryId, meshProxy) +class parallelMeshProxy(SMESH._objref_SMESH_ParallelMesh): + def __init__(self,*args): + SMESH._objref_SMESH_ParallelMesh.__init__(self,*args) + def __deepcopy__(self, memo=None): + new = self.__class__(self) + return new +omniORB.registerObjref(SMESH._objref_SMESH_ParallelMesh._NP_RepositoryId, parallelMeshProxy) + + + class submeshProxy(SMESH._objref_SMESH_subMesh): """