Salome HOME
updated copyright message
[modules/smesh.git] / src / SMESH_SWIG / smeshBuilder.py
index 3fad0860b408892876a38ad7a10c09456ff0081d..91d358d7b06660eb980b1c987d624c9fde4c55ed 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
+# Copyright (C) 2007-2023  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
@@ -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
@@ -789,7 +805,6 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
         """
         if isinstance( mesh, Mesh ):
             mesh = mesh.GetMesh()
-        print("calling createdualmesh from Python")
         dualMesh = SMESH._objref_SMESH_Gen.CreateDualMesh(self, mesh, meshName, adaptToShape)
         return Mesh(self, self.geompyD, dualMesh)
 
@@ -1578,7 +1593,7 @@ class Mesh(metaclass = MeshMeta):
     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
@@ -1611,7 +1626,10 @@ 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):
+                    self.SetMesh( self.smeshpyD.CreateParallelMesh(self.geom) )
+                else:
+                    self.SetMesh( self.smeshpyD.CreateMesh(self.geom) )
 
             elif isinstance(obj, SMESH._objref_SMESH_Mesh):
                 self.SetMesh(obj)
@@ -1863,31 +1881,6 @@ class Mesh(metaclass = MeshMeta):
                 geom = self.geom
         return self.smeshpyD.Evaluate(self.mesh, geom)
 
-    def ParallelCompute(self, nbThreads, mesherNbThreads=1, geom=0, discardModifs=False, refresh=False):
-        """
-        Parallel computation of the mesh and return the status of the computation
-        The mesh must contains have be constructed using create_parallel_mesh
-
-        Parameters:
-                nbThreads: Number of threads to use for a parallel computation
-                geom: geomtrical shape on which mesh data should be computed
-                discardModifs: if True and the mesh has been edited since
-                        a last total re-compute and that may prevent successful partial re-compute,
-                        then the mesh is cleaned before Compute()
-                refresh: if *True*, Object Browser is automatically updated (when running in GUI)
-
-        Returns:
-                True or False
-        """
-        if (nbThreads <= 1):
-            raise ValueError("nbThreads must be strictly greater than 1")
-        if (mesherNbThreads < 1):
-            raise ValueError("nbThreads must be greater than 1")
-
-        self.mesh.SetMesherNbThreads(mesherNbThreads)
-        self.mesh.SetNbThreads(nbThreads)
-        return self.Compute(geom=geom, discardModifs=discardModifs, refresh=refresh)
-
     def Compute(self, geom=0, discardModifs=False, refresh=False):
         """
         Compute the mesh and return the status of the computation
@@ -1898,7 +1891,6 @@ class Mesh(metaclass = MeshMeta):
                         a last total re-compute and that may prevent successful partial re-compute,
                         then the mesh is cleaned before Compute()
                 refresh: if *True*, Object Browser is automatically updated (when running in GUI)
-                nbThreads: Number of threads to use for a parallel computation
 
         Returns:
                 True or False
@@ -7512,6 +7504,193 @@ class Mesh(metaclass = MeshMeta):
     pass # end of Mesh class
 
 
+def _copy_netgen_param(dim, local_param, global_param):
+    """
+    Create 1D/2D/3D netgen parameters from a NETGEN 1D2D3D parameter
+    """
+    if dim==1:
+        #TODO: Try to identify why we need to substract 1
+        local_param.NumberOfSegments(int(global_param.GetNbSegPerEdge())-1)
+    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())
+        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 _split_geom(geompyD, geom):
+    """
+    Splitting geometry into n solids and a 2D/1D compound
+
+    Parameters:
+        geompyD: geomBuilder instance
+        geom: geometrical object for meshing
+
+    """
+    # 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
+    for isolid, solid in enumerate(solids):
+        solid_faces = geompyD.ExtractShapes(solid, geompyD.ShapeType["FACE"],
+                                            True)
+        for face in solid_faces:
+            faces.append(face)
+            iface += 1
+            geompyD.addToStudyInFather(solid, face,
+                                       'Face_{}'.format(iface))
+
+    # Creating submesh for edges 1D/2D part
+
+    all_faces = geompyD.MakeCompound(faces)
+    geompyD.addToStudy(all_faces, 'Compound_1')
+    all_faces = geompyD.MakeGlueEdges(all_faces, 1e-07)
+    all_faces = geompyD.MakeGlueFaces(all_faces, 1e-07)
+    geompyD.addToStudy(all_faces, 'global2D')
+
+    return all_faces, solids
+
+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
+
+    def SetNbThreads(self, nbThreads):
+        """
+        Set the number of threads for multithreading
+        """
+        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()
+
+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")
+
+        # Splitting geometry into one geom containing 1D and 2D elements and a
+        # list of 3D elements
+        super(ParallelMesh, self).__init__(smeshpyD, geompyD, geom, name, parallel=True)
+
+        if split_geom:
+            self._all_faces, self._solids = _split_geom(geompyD, geom)
+
+            self.UseExistingSegments()
+            self.UseExistingFaces()
+
+            self._algo2d = self.Triangle(geom=self._all_faces, algo="NETGEN_2D")
+            self._algo3d = []
+
+            for solid_id, solid in enumerate(self._solids):
+                name = "Solid_{}".format(solid_id)
+                self.UseExistingSegments(geom=solid)
+                self.UseExistingFaces(geom=solid)
+                algo3d = self.Tetrahedron(geom=solid, algo="NETGEN_3D_Remote")
+                self._algo3d.append(algo3d)
+
+        self._param = ParallelismSettings(self)
+
+
+    def GetParallelismSettings(self):
+        """
+        Return class to set parameters for the parallelism
+        """
+        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 not isinstance(hyp, NETGENPlugin._objref_NETGENPlugin_Hypothesis):
+            raise ValueError("param must come from NETGENPlugin")
+
+        param2d = self._algo2d.Parameters()
+        _copy_netgen_param(2, param2d, hyp)
+
+        for algo3d in self._algo3d:
+
+            param3d = algo3d.Parameters()
+            _copy_netgen_param(3, param3d, hyp)
+
+
+    pass # End of ParallelMesh
+
+
 class meshProxy(SMESH._objref_SMESH_Mesh):
     """
     Private class used to compensate change of CORBA API of SMESH_Mesh for backward compatibility