Modifications to properly handle parallel compute for 2D

This commit is contained in:
yoann.audouin 2024-01-02 14:58:58 +01:00 committed by cesarconopoima
parent b0b5c3242d
commit aa034dad38
13 changed files with 174 additions and 74 deletions

View File

@ -45,8 +45,8 @@ boxes = []
# boxes.append(box) # boxes.append(box)
#With 6 boxes works #With 6 boxes works
#But simplify for 2 boxes to also Test possibility of rewritting the #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 # 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. # because the input mesh will not match the exported/imported box geometry.
for i in range(nbox): for i in range(nbox):
@ -78,12 +78,19 @@ all_boxes = geompy.MakeGlueFaces(all_boxes, 1e-07)
geompy.addToStudy(all_boxes, 'Glued_Faces_1') geompy.addToStudy(all_boxes, 'Glued_Faces_1')
rubik_cube = geompy.MakeGlueEdges(all_boxes, 1e-07) rubik_cube = geompy.MakeGlueEdges(all_boxes, 1e-07)
geompy.addToStudy(all_boxes, 'rubik_cube') geompy.addToStudy(rubik_cube, 'rubik_cube')
smesh = smeshBuilder.New() smesh = smeshBuilder.New()
print("Creating Parallel Mesh") 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") print("Setting parallelism method")
par_mesh.SetParallelismMethod(smeshBuilder.MULTITHREAD) par_mesh.SetParallelismMethod(smeshBuilder.MULTITHREAD)

View File

@ -54,11 +54,11 @@ all_boxes = geompy.MakeGlueFaces(all_boxes, 1e-07)
geompy.addToStudy(all_boxes, 'Glued_Faces_1') geompy.addToStudy(all_boxes, 'Glued_Faces_1')
rubik_cube = geompy.MakeGlueEdges(all_boxes, 1e-07) rubik_cube = geompy.MakeGlueEdges(all_boxes, 1e-07)
geompy.addToStudy(all_boxes, 'rubik_cube') geompy.addToStudy(rubik_cube, 'rubik_cube')
smesh = smeshBuilder.New() smesh = smeshBuilder.New()
print("Creating Parallel Mesh") 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") print("Creating hypoehtesis for gmsh")
GMSH_3D_Parameters_1 = smesh.CreateHypothesis( 'GMSH_Parameters', GMSH_3D_Parameters_1 = smesh.CreateHypothesis( 'GMSH_Parameters',

View File

@ -54,7 +54,7 @@ all_boxes = geompy.MakeGlueFaces(all_boxes, 1e-07)
geompy.addToStudy(all_boxes, 'Glued_Faces_1') geompy.addToStudy(all_boxes, 'Glued_Faces_1')
rubik_cube = geompy.MakeGlueEdges(all_boxes, 1e-07) rubik_cube = geompy.MakeGlueEdges(all_boxes, 1e-07)
geompy.addToStudy(all_boxes, 'rubik_cube') geompy.addToStudy(rubik_cube, 'rubik_cube')
smesh = smeshBuilder.New() smesh = smeshBuilder.New()

View File

@ -1109,6 +1109,9 @@ module SMESH
long GetParallelismMethod(); long GetParallelismMethod();
void SetParallelismMethod(in long aMethod); void SetParallelismMethod(in long aMethod);
long GetParallelismDimension();
void SetParallelismDimension(in long aDim);
// Parameters for MutliThreading // Parameters for MutliThreading
long GetNbThreads(); long GetNbThreads();
void SetNbThreads(in long nbThreads); void SetNbThreads(in long nbThreads);

View File

@ -394,7 +394,7 @@ bool SMESH_Gen::parallelComputeSubMeshes(
// do not mesh vertices of a pseudo shape // do not mesh vertices of a pseudo shape
const TopoDS_Shape& shape = smToCompute->GetSubShape(); const TopoDS_Shape& shape = smToCompute->GetSubShape();
const TopAbs_ShapeEnum shapeType = shape.ShapeType(); 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 ) if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX )
continue; continue;
@ -402,22 +402,10 @@ bool SMESH_Gen::parallelComputeSubMeshes(
// Waiting for all threads for the previous type to end // Waiting for all threads for the previous type to end
aMesh.wait(); aMesh.wait();
std::string file_name; std::string file_name="";
switch(previousShapeType){ if (previousShapeType == aParMesh.GetDumpElement())
case TopAbs_FACE: file_name = "Mesh"+std::to_string(aParMesh.GetParallelismDimension()-1)+"D.med";
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;
}
if(file_name != "") if(file_name != "")
{ {
fs::path mesh_file = fs::path(aParMesh.GetTmpFolder()) / fs::path(file_name); fs::path mesh_file = fs::path(aParMesh.GetTmpFolder()) / fs::path(file_name);
@ -439,7 +427,7 @@ bool SMESH_Gen::parallelComputeSubMeshes(
continue; continue;
} }
// Parallelism is only for 3D parts // Parallelism is only for 3D parts
if(shapeType!=TopAbs_SOLID){ if(shapeType!=aMesh.GetParallelElement()){
compute_function(smToCompute, computeEvent, compute_function(smToCompute, computeEvent,
shapeSM, aShapeOnly, allowedSubShapes, shapeSM, aShapeOnly, allowedSubShapes,
aShapesId); aShapesId);

View File

@ -397,6 +397,7 @@ class SMESH_EXPORT SMESH_Mesh
virtual void wait(){}; virtual void wait(){};
virtual bool IsParallel(){throw SALOME_Exception("Calling SMESH_Mesh::IsParallel");return false;}; 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( virtual bool ComputeSubMeshes(
SMESH_Gen* gen, SMESH_Gen* gen,

View File

@ -151,6 +151,34 @@ void SMESH_ParallelMesh::SetNbThreads(long nbThreads)
_NbThreads=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( bool SMESH_ParallelMesh::ComputeSubMeshes(
SMESH_Gen* gen, SMESH_Gen* gen,
SMESH_Mesh & aMesh, SMESH_Mesh & aMesh,

View File

@ -81,11 +81,16 @@ class SMESH_EXPORT SMESH_ParallelMesh: public SMESH_Mesh
// //
bool IsParallel() override {return true;}; bool IsParallel() override {return true;};
int GetParallelElement() override;
int GetDumpElement();
// Parallelims paramaters // Parallelims paramaters
int GetParallelismMethod() {return _method;}; int GetParallelismMethod() {return _method;};
void SetParallelismMethod(int aMethod) {_method = aMethod;}; void SetParallelismMethod(int aMethod) {_method = aMethod;};
int GetParallelismDimension() {return _paraDim;};
void SetParallelismDimension(int aDim) {_paraDim = aDim;};
// Mutlithreading parameters // Mutlithreading parameters
int GetNbThreads() {return _NbThreads;}; int GetNbThreads() {return _NbThreads;};
void SetNbThreads(long nbThreads); void SetNbThreads(long nbThreads);
@ -134,6 +139,7 @@ class SMESH_EXPORT SMESH_ParallelMesh: public SMESH_Mesh
#endif #endif
boost::filesystem::path tmp_folder; boost::filesystem::path tmp_folder;
int _method = ParallelismMethod::MultiThread; int _method = ParallelismMethod::MultiThread;
int _paraDim = 3;
int _NbThreads = std::thread::hardware_concurrency(); int _NbThreads = std::thread::hardware_concurrency();

View File

@ -48,6 +48,7 @@ class SMESH_EXPORT SMESH_SequentialMesh: public SMESH_Mesh
void wait() override {}; void wait() override {};
bool IsParallel() override {return false;}; bool IsParallel() override {return false;};
int GetParallelElement() override {return 0;};
bool ComputeSubMeshes ( bool ComputeSubMeshes (
SMESH_Gen* gen, SMESH_Gen* gen,

View File

@ -1517,7 +1517,7 @@ bool SMESH_subMesh::ComputeStateEngine(compute_event event)
// check submeshes needed // check submeshes needed
// When computing in parallel mode we do not have a additional layer of submesh // 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 // 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; bool subComputed = false, subFailed = false;
if (!algo->OnlyUnaryInput()) { if (!algo->OnlyUnaryInput()) {
// --- commented for bos#22320 to compute all sub-shapes at once if possible; // --- commented for bos#22320 to compute all sub-shapes at once if possible;

View File

@ -81,6 +81,25 @@ void SMESH_ParallelMesh_i::SetParallelismMethod(CORBA::Long aMethod){
DownCast()->SetParallelismMethod(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 * \brief Get the number of threads for a parallel computation

View File

@ -53,6 +53,9 @@ class SMESH_I_EXPORT SMESH_ParallelMesh_i:
CORBA::Long GetParallelismMethod(); CORBA::Long GetParallelismMethod();
void SetParallelismMethod(CORBA::Long aMethod); void SetParallelismMethod(CORBA::Long aMethod);
CORBA::Long GetParallelismDimension();
void SetParallelismDimension(CORBA::Long aDim);
CORBA::Long GetNbThreads(); CORBA::Long GetNbThreads();
void SetNbThreads(CORBA::Long nbThreads); void SetNbThreads(CORBA::Long nbThreads);

View File

@ -462,7 +462,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
obj,name = name,obj obj,name = name,obj
return Mesh(self, self.geompyD, obj, name) 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. Create a parallel mesh.
@ -476,7 +476,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
an instance of class :class:`ParallelMesh`. an instance of class :class:`ParallelMesh`.
""" """
return ParallelMesh(self, self.geompyD, obj, 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 ): 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 Create 1D/2D/3D netgen parameters from a NETGEN 1D2D3D parameter
""" """
if dim==1: if dim==1:
#TODO: Try to identify why we need to substract 1 to have same results #TODO: More global conversion ? or let user define it
local_param.NumberOfSegments(int(global_param.GetNbSegPerEdge())-1) local_param.NumberOfSegments(int(global_param.GetMaxSize()))
elif dim==2: elif dim==2:
local_param.SetMaxSize(global_param.GetMaxSize()) local_param.SetMaxSize(global_param.GetMaxSize())
local_param.SetMinSize(global_param.GetMinSize()) local_param.SetMinSize(global_param.GetMinSize())
@ -7667,23 +7667,15 @@ def _split_geom(geompyD, geom):
faces = [] faces = []
iface = 0 iface = 0
for isolid, solid in enumerate(solids): solid_faces = geompyD.ExtractShapes(geom, geompyD.ShapeType["FACE"],
solid_faces = geompyD.ExtractShapes(solid, geompyD.ShapeType["FACE"], True)
True) for face in solid_faces:
for face in solid_faces: faces.append(face)
faces.append(face) iface += 1
iface += 1 geompyD.addToStudyInFather(geom, face,
geompyD.addToStudyInFather(solid, face, 'Face_{}'.format(iface))
'Face_{}'.format(iface))
# Creating submesh for edges 1D/2D part return faces, solids
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
MULTITHREAD, MULTINODE = range(2) MULTITHREAD, MULTINODE = range(2)
@ -7810,7 +7802,7 @@ class ParallelMesh(Mesh):
""" """
Surcharge on Mesh for parallel computation of a 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. Create a parallel mesh.
@ -7833,48 +7825,64 @@ class ParallelMesh(Mesh):
import shaperBuilder import shaperBuilder
# If we have a shaper object converting it into geom (temporary solution) # If we have a shaper object converting it into geom (temporary solution)
if isinstance(geom, SHAPERSTUDY.SHAPERSTUDY_ORB._objref_SHAPER_Object): if isinstance(geom, SHAPERSTUDY.SHAPERSTUDY_ORB._objref_SHAPER_Object):
geom_obj = _shaperstudy2geom(geompyD, geom) self._geom_obj = _shaperstudy2geom(geompyD, geom)
else: else:
geom_obj = geom self._geom_obj = geom
# Splitting geometry into one geom containing 1D and 2D elements and a # Splitting geometry into one geom containing 1D and 2D elements and a
# list of 3D elements # 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: if split_geom:
self._all_faces, self._solids = _split_geom(geompyD, geom_obj) 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": if mesher3D == "NETGEN":
self._algo2d = self.Triangle(geom=geom_obj, algo="NETGEN_2D") algo2D = "NETGEN_2D"
elif mesher3D == "GMSH": elif mesher3D == "GMSH":
self._algo2d = self.Triangle(geom=geom_obj, algo="GMSH_2D") algo2D = "GMSH_2D"
else: else:
raise ValueError("mesher3D should be either NETGEN or GMSH") raise ValueError("mesher3D should be either NETGEN or GMSH")
self._algo2d = self.Triangle(geom=self._geom_obj, algo=algo2D)
if mesher2D is not None: # Parallel 2D
#Means that we want to mesh face of solids in parallel and not if mesher2D:
#the volume #Means that we want to mesh face of solids in parallel and not
self._algo2d = [] #the volume
#For the moment use AutomaticLength based on finesse self._algo2d = []
self._algo1d = self.Segment().AutomaticLength(0.1) #For the moment use AutomaticLength based on finesse
# TODO: replace by input hypothesis
self._algo1d = self.Segment(geom=self._geom_obj)
for solid_id, solid in enumerate(self._solids): for face_id, face in enumerate(self._faces):
name = "Solid_{}".format(solid_id) name = "face_{}".format(face_id)
algo2d = self.Triangle(geom=solid, algo="NETGEN_2D_Remote") algo2d = self.Triangle(geom=face, algo="NETGEN_2D_Remote")
self._algo2d.append(algo2d) self._algo2d.append(algo2d)
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)
self._param = None 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): def GetNbSolids(self):
""" """
@ -7882,6 +7890,12 @@ class ParallelMesh(Mesh):
""" """
return len(self._solids) return len(self._solids)
def GetNbFaces(self):
"""
Return the number of 2D faces
"""
return len(self._faces)
def GetParallelismMethod(self): def GetParallelismMethod(self):
""" Get the parallelims method """ """ Get the parallelims method """
return self.mesh.GetParallelismMethod() return self.mesh.GetParallelismMethod()
@ -7918,11 +7932,16 @@ class ParallelMesh(Mesh):
""" """
if isinstance(hyp, NETGENPlugin._objref_NETGENPlugin_Hypothesis): if isinstance(hyp, NETGENPlugin._objref_NETGENPlugin_Hypothesis):
copy_param = _copy_netgen_param copy_param = _copy_netgen_param
mesher3D = "NETGEN"
elif isinstance(hyp, GMSHPlugin._objref_GMSHPlugin_Hypothesis): elif isinstance(hyp, GMSHPlugin._objref_GMSHPlugin_Hypothesis):
copy_param = _copy_gmsh_param copy_param = _copy_gmsh_param
mesher3D = "GMSH"
else: else:
raise ValueError("param must come from NETGENPlugin or GMSHPlugin") raise ValueError("param must come from NETGENPlugin or GMSHPlugin")
self.mesh.SetParallelismDimension(3)
self._build_submeshes(None, mesher3D)
param2d = self._algo2d.Parameters() param2d = self._algo2d.Parameters()
copy_param(2, param2d, hyp) copy_param(2, param2d, hyp)
@ -7930,6 +7949,31 @@ class ParallelMesh(Mesh):
param3d = algo3d.Parameters() param3d = algo3d.Parameters()
copy_param(3, param3d, hyp) 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 pass # End of ParallelMesh