Salome HOME
Modifications to properly handle parallel compute for 2D cce/38045 30/head
authoryoann.audouin <yoann.audouin@edf.fr>
Tue, 2 Jan 2024 13:58:58 +0000 (14:58 +0100)
committercesarconopoima <cesar.conopoima@opencascade.com>
Thu, 18 Jan 2024 10:27:15 +0000 (10:27 +0000)
13 files changed:
doc/examples/creating_parallel_2D_mesh.py
doc/examples/creating_parallel_gmsh_mesh.py
doc/examples/creating_parallel_mesh.py
idl/SMESH_Mesh.idl
src/SMESH/SMESH_Gen.cxx
src/SMESH/SMESH_Mesh.hxx
src/SMESH/SMESH_ParallelMesh.cxx
src/SMESH/SMESH_ParallelMesh.hxx
src/SMESH/SMESH_SequentialMesh.hxx
src/SMESH/SMESH_subMesh.cxx
src/SMESH_I/SMESH_ParallelMesh_i.cxx
src/SMESH_I/SMESH_ParallelMesh_i.hxx
src/SMESH_SWIG/smeshBuilder.py

index a351bfc779bd07a30719ef4ed731e7fa2753a157..2515543aafbac5a51c3a6696be161a2569b0f34b 100644 (file)
@@ -45,8 +45,8 @@ boxes = []
 
 #             boxes.append(box)
 
-#With 6 boxes works 
-#But simplify for 2 boxes to also Test possibility of rewritting the 
+#With 6 boxes works
+#But simplify for 2 boxes to also Test possibility of rewritting the
 # input mesh from other parallel tests. In that case this test will break
 # because the input mesh will not match the exported/imported box geometry.
 for i in range(nbox):
@@ -78,12 +78,19 @@ all_boxes = geompy.MakeGlueFaces(all_boxes, 1e-07)
 geompy.addToStudy(all_boxes, 'Glued_Faces_1')
 
 rubik_cube = geompy.MakeGlueEdges(all_boxes, 1e-07)
-geompy.addToStudy(all_boxes, 'rubik_cube')
+geompy.addToStudy(rubik_cube, 'rubik_cube')
 
 
 smesh = smeshBuilder.New()
 print("Creating Parallel Mesh")
-par_mesh = smesh.ParallelMesh(rubik_cube, name="par_mesh", mesher2D="NETGEN_2D_Remote")
+par_mesh = smesh.ParallelMesh(rubik_cube, name="par_mesh")
+
+print("Creating hypoehtesis for netgen")
+NETGEN_2D_Parameters_1 = smesh.CreateHypothesisByAverageLength( 'NETGEN_Parameters_2D',
+                                         'NETGENEngine', 34.641, 0 )
+
+print("Adding hypothesis")
+par_mesh.Add2DGlobalHypothesis(NETGEN_2D_Parameters_1)
 
 print("Setting parallelism method")
 par_mesh.SetParallelismMethod(smeshBuilder.MULTITHREAD)
index a028f6525ff2e8cc4c236c94fbe4c2083cfe3c6e..51465214fbc8a229d4bd9308af059ea6a54915ce 100644 (file)
@@ -54,11 +54,11 @@ all_boxes = geompy.MakeGlueFaces(all_boxes, 1e-07)
 geompy.addToStudy(all_boxes, 'Glued_Faces_1')
 
 rubik_cube = geompy.MakeGlueEdges(all_boxes, 1e-07)
-geompy.addToStudy(all_boxes, 'rubik_cube')
+geompy.addToStudy(rubik_cube, 'rubik_cube')
 
 smesh = smeshBuilder.New()
 print("Creating Parallel Mesh")
-par_mesh = smesh.ParallelMesh(rubik_cube, name="par_mesh", mesher3D="GMSH")
+par_mesh = smesh.ParallelMesh(rubik_cube, name="par_mesh")
 
 print("Creating hypoehtesis for gmsh")
 GMSH_3D_Parameters_1 = smesh.CreateHypothesis( 'GMSH_Parameters',
index 3096749549730b2adedc7bfce0151eedc7cb8493..1a69fbd80284f681cfb51bccdaa88d5fb44574e6 100644 (file)
@@ -54,7 +54,7 @@ all_boxes = geompy.MakeGlueFaces(all_boxes, 1e-07)
 geompy.addToStudy(all_boxes, 'Glued_Faces_1')
 
 rubik_cube = geompy.MakeGlueEdges(all_boxes, 1e-07)
-geompy.addToStudy(all_boxes, 'rubik_cube')
+geompy.addToStudy(rubik_cube, 'rubik_cube')
 
 
 smesh = smeshBuilder.New()
index 8ef9a454b0fb7018dc6e1278cff14c83e0e923c2..142252a4c1d9d43cd19ea52bc02f09523d297af8 100644 (file)
@@ -1109,6 +1109,9 @@ module SMESH
     long GetParallelismMethod();
     void SetParallelismMethod(in long aMethod);
 
+    long GetParallelismDimension();
+    void SetParallelismDimension(in long aDim);
+
     // Parameters for MutliThreading
     long GetNbThreads();
     void SetNbThreads(in long nbThreads);
index 9f75ddfa50756e8b6d89414e19eea07fde00e952..08a5512b274a6d310a3a84943b99eec5eae02ccc 100644 (file)
@@ -394,7 +394,7 @@ bool SMESH_Gen::parallelComputeSubMeshes(
     // do not mesh vertices of a pseudo shape
     const TopoDS_Shape&        shape = smToCompute->GetSubShape();
     const TopAbs_ShapeEnum shapeType = shape.ShapeType();
-    // Not doing in parallel 1D and 2D meshes
+    // Not doing in parallel 1D meshes
     if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX )
       continue;
 
@@ -402,22 +402,10 @@ bool SMESH_Gen::parallelComputeSubMeshes(
       // Waiting for all threads for the previous type to end
       aMesh.wait();
 
-      std::string file_name;
-      switch(previousShapeType){
-        case TopAbs_FACE:
-          file_name = "Mesh2D.med";
-          break;
-        case TopAbs_EDGE:
-          file_name = "Mesh1D.med";
-          break;
-        //case TopAbs_VERTEX:
-        //  file_name = "Mesh0D.med";
-        //  break;
-        case TopAbs_SOLID:
-        default:
-          file_name = "";
-          break;
-      }
+      std::string file_name="";
+      if (previousShapeType == aParMesh.GetDumpElement())
+        file_name = "Mesh"+std::to_string(aParMesh.GetParallelismDimension()-1)+"D.med";
+
       if(file_name != "")
       {
         fs::path mesh_file = fs::path(aParMesh.GetTmpFolder()) / fs::path(file_name);
@@ -439,7 +427,7 @@ bool SMESH_Gen::parallelComputeSubMeshes(
       continue;
     }
     // Parallelism is only for 3D parts
-    if(shapeType!=TopAbs_SOLID){
+    if(shapeType!=aMesh.GetParallelElement()){
       compute_function(smToCompute, computeEvent,
                       shapeSM, aShapeOnly, allowedSubShapes,
                       aShapesId);
index 4fa3a355d4626bb0150768b32c40a7b0ede1dc2b..adb4c03f6a8c54eee8d34322b88e1b1ded9a27b3 100644 (file)
@@ -397,6 +397,7 @@ class SMESH_EXPORT SMESH_Mesh
   virtual void wait(){};
 
   virtual bool IsParallel(){throw SALOME_Exception("Calling SMESH_Mesh::IsParallel");return false;};
+  virtual int GetParallelElement(){throw SALOME_Exception("Calling SMESH_Mesh::GetParallelElement");return 0;};
 
   virtual bool ComputeSubMeshes(
             SMESH_Gen* gen,
index 4b49486e0afc693f54fe96a3d391b2dde60d82aa..b45e52797a9f7e3ea083cc8a81af2a3c3494c16f 100644 (file)
@@ -151,6 +151,34 @@ void SMESH_ParallelMesh::SetNbThreads(long nbThreads)
   _NbThreads=nbThreads;
 };
 
+//=============================================================================
+/*!
+ * \brief Get the element associated to the dimension of the parallelism
+ */
+//=============================================================================
+int SMESH_ParallelMesh::GetParallelElement()
+{
+  if (_paraDim==2){
+    return TopAbs_FACE;
+  }else{
+    return TopAbs_SOLID;
+  }
+};
+
+//=============================================================================
+/*!
+ * \brief Get the element associated to the dimension of the parallelism
+ */
+//=============================================================================
+int SMESH_ParallelMesh::GetDumpElement()
+{
+  if (_paraDim==2){
+    return TopAbs_EDGE;
+  }else{
+    return TopAbs_FACE;
+  }
+};
+
 bool SMESH_ParallelMesh::ComputeSubMeshes(
           SMESH_Gen* gen,
           SMESH_Mesh & aMesh,
index 4a418a49f31a4fde82847f1f0e90027e54a50e84..70cf77a355377716a1058a17e107661b1afdd799 100644 (file)
@@ -81,11 +81,16 @@ class SMESH_EXPORT SMESH_ParallelMesh: public SMESH_Mesh
 
   //
   bool IsParallel() override {return true;};
+  int GetParallelElement() override;
+  int GetDumpElement();
 
   // Parallelims paramaters
   int GetParallelismMethod() {return _method;};
   void SetParallelismMethod(int aMethod) {_method = aMethod;};
 
+  int GetParallelismDimension() {return _paraDim;};
+  void SetParallelismDimension(int aDim) {_paraDim = aDim;};
+
   // Mutlithreading parameters
   int GetNbThreads() {return _NbThreads;};
   void SetNbThreads(long nbThreads);
@@ -134,6 +139,7 @@ class SMESH_EXPORT SMESH_ParallelMesh: public SMESH_Mesh
 #endif
   boost::filesystem::path tmp_folder;
   int _method = ParallelismMethod::MultiThread;
+  int _paraDim = 3;
 
   int _NbThreads = std::thread::hardware_concurrency();
 
index 5abf93bd00a19a416686ac93806ddbdadaa92c03..1322403df697a18ba99ce3fba55f570a6d789fee 100644 (file)
@@ -48,6 +48,7 @@ class SMESH_EXPORT SMESH_SequentialMesh: public SMESH_Mesh
   void wait() override {};
 
   bool IsParallel() override {return false;};
+  int GetParallelElement() override {return 0;};
 
   bool ComputeSubMeshes (
             SMESH_Gen* gen,
index a019213ee52285ec5979354d8f8257b8d768211d..9abcbc21588332b9660cf3b2216844bd7cf3d4b8 100644 (file)
@@ -1517,7 +1517,7 @@ bool SMESH_subMesh::ComputeStateEngine(compute_event event)
         // check submeshes needed
         // When computing in parallel mode we do not have a additional layer of submesh
         // The check should not be done in parallel as that check is not thread-safe
-        if (_father->HasShapeToMesh() && (!_father->IsParallel() || shape.ShapeType() != TopAbs_SOLID )) {
+        if (_father->HasShapeToMesh() && (!_father->IsParallel() || shape.ShapeType() != _father->GetParallelElement() )) {
           bool subComputed = false, subFailed = false;
           if (!algo->OnlyUnaryInput()) {
             //  --- commented for bos#22320 to compute all sub-shapes at once if possible;
index 6e8bad1a6f84cd3ea61e257e740dd00588d15f33..3302fbaa078c039d36c24bf5b2f5a262ab2d9253 100644 (file)
@@ -81,6 +81,25 @@ void SMESH_ParallelMesh_i::SetParallelismMethod(CORBA::Long aMethod){
   DownCast()->SetParallelismMethod(aMethod);
 }
 
+//=============================================================================
+/*!
+ * \brief Get the parallell dimension
+ */
+//=============================================================================
+
+CORBA::Long SMESH_ParallelMesh_i::GetParallelismDimension(){
+  return DownCast()->GetParallelismDimension();
+}
+
+//=============================================================================
+/*!
+ * \brief Set the parallell dimension
+ */
+//=============================================================================
+void SMESH_ParallelMesh_i::SetParallelismDimension(CORBA::Long aDim){
+  DownCast()->SetParallelismDimension(aDim);
+}
+
 //=============================================================================
 /*!
  * \brief Get the number of threads for a parallel computation
index 51ae0c93f4291ba471ecdfcfe94fd79bd85100c6..a5c9a407a1b8925d8c8171cab48545a42a6af70b 100644 (file)
@@ -53,6 +53,9 @@ class SMESH_I_EXPORT SMESH_ParallelMesh_i:
   CORBA::Long GetParallelismMethod();
   void SetParallelismMethod(CORBA::Long aMethod);
 
+  CORBA::Long GetParallelismDimension();
+  void SetParallelismDimension(CORBA::Long aDim);
+
   CORBA::Long GetNbThreads();
   void SetNbThreads(CORBA::Long nbThreads);
 
index cfeda1a3acf59ce3221143e8b8d4ea4d32bac4a7..68b62eadc619c39cb8058cd0bf7d4fc7b08f5b95 100644 (file)
@@ -462,7 +462,7 @@ 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, mesher2D=None, mesher3D="NETGEN"):
+    def ParallelMesh(self, obj, name=0, split_geom=True):
         """
         Create a parallel mesh.
 
@@ -476,7 +476,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
             an instance of class :class:`ParallelMesh`.
         """
         return ParallelMesh(self, self.geompyD, obj,
-                            split_geom=split_geom, name=name, mesher2D=mesher2D, mesher3D=mesher3D )
+                            split_geom=split_geom, name=name)
 
     def RemoveMesh( self, mesh ):
         """
@@ -7582,8 +7582,8 @@ 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 to have same results
-        local_param.NumberOfSegments(int(global_param.GetNbSegPerEdge())-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())
@@ -7667,23 +7667,15 @@ def _split_geom(geompyD, 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))
+    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))
 
-    # 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
+    return faces, solids
 
 
 MULTITHREAD, MULTINODE = range(2)
@@ -7810,7 +7802,7 @@ class ParallelMesh(Mesh):
     """
     Surcharge on Mesh for parallel computation of a mesh
     """
-    def __init__(self, smeshpyD, geompyD, geom, split_geom=True, name=0, mesher2D=None, mesher3D="NETGEN"):
+    def __init__(self, smeshpyD, geompyD, geom, split_geom=True, name=0):
         """
         Create a parallel mesh.
 
@@ -7833,48 +7825,64 @@ class ParallelMesh(Mesh):
         import shaperBuilder
         # If we have a shaper object converting it into geom (temporary solution)
         if isinstance(geom, SHAPERSTUDY.SHAPERSTUDY_ORB._objref_SHAPER_Object):
-            geom_obj = _shaperstudy2geom(geompyD, geom)
+            self._geom_obj = _shaperstudy2geom(geompyD, geom)
         else:
-            geom_obj = geom
+            self._geom_obj = geom
 
         # Splitting geometry into one geom containing 1D and 2D elements and a
         # list of 3D elements
-        super(ParallelMesh, self).__init__(smeshpyD, geompyD, geom_obj, name, parallel=True)
+        super(ParallelMesh, self).__init__(smeshpyD, geompyD, self._geom_obj, name, parallel=True)
 
         if split_geom:
-            self._all_faces, self._solids = _split_geom(geompyD, geom_obj)
+            self._faces, self._solids = _split_geom(geompyD, self._geom_obj)
 
-            if mesher3D == "NETGEN":
-                self._algo2d = self.Triangle(geom=geom_obj, algo="NETGEN_2D")
-            elif mesher3D == "GMSH":
-                self._algo2d = self.Triangle(geom=geom_obj, algo="GMSH_2D")
-            else:
-                raise ValueError("mesher3D should be either NETGEN or GMSH")
+        self._param = None
 
+    def _build_submeshes(self, mesher2D, mesher3D):
+        """
+        Contruct the submeshes for a parallel use of smesh
 
-            if mesher2D is not None:
-                #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
-                self._algo1d = self.Segment().AutomaticLength(0.1)
+        Parameters:
+            mesher2D: name of 2D mesher for 2D parallel compute (NETGEN)
+            mesher3D: name of 3D mesher for 3D parallel compute (NETGEN or
+            GMSH)
+        """
 
-                for solid_id, solid in enumerate(self._solids):
-                    name = "Solid_{}".format(solid_id)
-                    algo2d = self.Triangle(geom=solid, algo="NETGEN_2D_Remote")
-                    self._algo2d.append(algo2d)
+        # Building global 2D mesher
+        if mesher3D:
+            if mesher3D == "NETGEN":
+                algo2D = "NETGEN_2D"
+            elif mesher3D == "GMSH":
+                algo2D = "GMSH_2D"
             else:
-                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)
+                raise ValueError("mesher3D should be either NETGEN or GMSH")
 
-        self._param = None
+            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):
         """
@@ -7882,6 +7890,12 @@ class ParallelMesh(Mesh):
         """
         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()
@@ -7918,11 +7932,16 @@ class ParallelMesh(Mesh):
         """
         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)
 
@@ -7930,6 +7949,31 @@ class ParallelMesh(Mesh):
             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