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)
#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)

View 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',

View 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()

View 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);

View 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);

View 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,

View 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,

View 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();

View 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,

View 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;

View 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

View 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);

View 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)
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":
self._algo2d = self.Triangle(geom=geom_obj, algo="NETGEN_2D")
algo2D = "NETGEN_2D"
elif mesher3D == "GMSH":
self._algo2d = self.Triangle(geom=geom_obj, algo="GMSH_2D")
algo2D = "GMSH_2D"
else:
raise ValueError("mesher3D should be either NETGEN or GMSH")
self._algo2d = self.Triangle(geom=self._geom_obj, algo=algo2D)
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)
# 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 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)
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)
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)
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):
"""
@ -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