SMESH_Mesh CreateMesh( in GEOM::GEOM_Object theObject )
raises ( SALOME::SALOME_Exception );
+ /*!
+ * Create a Mesh object, given a geometry shape.
+ * Mesh is created empty (no points, no elements).
+ * Shape is explored via GEOM_Client to create local copies.
+ * of TopoDS_Shapes and bind CORBA references of shape & subshapes
+ * with TopoDS_Shapes
+ * The mesh is a parallel one
+ */
+ SMESH_Mesh CreateParallelMesh( in GEOM::GEOM_Object theObject )
+ raises ( SALOME::SALOME_Exception );
/*!
* Create an empty mesh object
*/
long GetId();
};
+ interface SMESH_SequentialMesh:SMESH_Mesh{};
+ interface SMESH_ParallelMesh:SMESH_Mesh{};
+
};
#endif
//
//#define CHRONODEF
//
-#ifndef WIN32
-#include <boost/asio.hpp>
-#endif
#include "SMESH_Gen.hxx"
#include "SMESH_DriverMesh.hxx"
#include "SMESHDS_Document.hxx"
#include "SMESH_HypoFilter.hxx"
#include "SMESH_Mesh.hxx"
+#include "SMESH_SequentialMesh.hxx"
+#include "SMESH_ParallelMesh.hxx"
#include "SMESH_MesherHelper.hxx"
#include "SMESH_subMesh.hxx"
#include <Basics_Utils.hxx>
+#ifndef WIN32
+#include <boost/asio.hpp>
+#endif
+
using namespace std;
#ifndef WIN32
#include <boost/filesystem.hpp>
Unexpect aCatch(SalomeException);
// create a new SMESH_mesh object
- SMESH_Mesh *aMesh = new SMESH_Mesh(_localId++,
+ SMESH_Mesh *aMesh = new SMESH_SequentialMesh(
+ _localId++,
this,
theIsEmbeddedMode,
_studyContext->myDocument);
return aMesh;
}
+//=============================================================================
+/*!
+ * Creates a parallel mesh in a study.
+ * if (theIsEmbeddedMode) { mesh modification commands are not logged }
+ */
+//=============================================================================
+
+SMESH_Mesh* SMESH_Gen::CreateParallelMesh(bool theIsEmbeddedMode)
+{
+ Unexpect aCatch(SalomeException);
+
+ // create a new SMESH_mesh object
+ SMESH_Mesh *aMesh = new SMESH_ParallelMesh(
+ _localId++,
+ this,
+ theIsEmbeddedMode,
+ _studyContext->myDocument);
+ _studyContext->mapMesh[_localId-1] = aMesh;
+
+ return aMesh;
+}
//=============================================================================
/*!
continue;
// check for preview dimension limitations
- if ( aShapesId && GetShapeDim( shapeType ) > (int)aDim )
+ if ( aShapesId && SMESH_Gen::GetShapeDim( shapeType ) > (int)aDim )
{
// clear compute state not to show previous compute errors
// if preview invoked less dimension less than previous
});
+
//=============================================================================
/*!
* Algo to run the computation of all the submeshes of a mesh in parallel
SMESH_subMeshIteratorPtr smIt;
SMESH_subMesh *shapeSM = aMesh.GetSubMesh(aShape);
- // Pool of thread for computation
- // TODO: move when parallelMesh created
- aMesh.InitPoolThreads();
- aMesh.CreateTmpFolder();
-
TopAbs_ShapeEnum previousShapeType = TopAbs_VERTEX;
int nbThreads = aMesh.GetNbThreads();
MESSAGE("Compute submeshes with threads: " << nbThreads);
if(file_name != "")
{
fs::path mesh_file = fs::path(aMesh.tmp_folder) / fs::path(file_name);
- SMESH_DriverMesh::exportMesh(mesh_file.string(), aMesh, "MESH");
-
+ SMESH_DriverMesh::exportMesh(mesh_file.string(), aMesh, "MESH");
}
//Resetting threaded pool info
previousShapeType = shapeType;
}
// check for preview dimension limitations
- if ( aShapesId && GetShapeDim( shapeType ) > (int)aDim )
+ if ( aShapesId && SMESH_Gen::GetShapeDim( shapeType ) > (int)aDim )
{
// clear compute state not to show previous compute errors
// if preview invoked less dimension less than previous
aMesh.wait();
aMesh.GetMeshDS()->Modified();
- aMesh.DeleteTmpFolder();
return ret;
#endif
// ===============================================
// Mesh all the sub-shapes starting from vertices
// ===============================================
- if (aMesh.IsParallel())
- ret = parallelComputeSubMeshes(
- aMesh, aShape, aDim,
- aShapesId, allowedSubShapes,
- computeEvent,
- includeSelf,
- complexShapeFirst,
- aShapeOnly);
- else
- ret = sequentialComputeSubMeshes(
- aMesh, aShape, aDim,
- aShapesId, allowedSubShapes,
- computeEvent,
- includeSelf,
- complexShapeFirst,
- aShapeOnly);
+ aMesh.ComputeSubMeshes(
+ this,
+ aMesh, aShape, aDim,
+ aShapesId, allowedSubShapes,
+ computeEvent,
+ includeSelf,
+ complexShapeFirst,
+ aShapeOnly);
return ret;
}
~SMESH_Gen();
SMESH_Mesh* CreateMesh(bool theIsEmbeddedMode);
+ SMESH_Mesh* CreateParallelMesh(bool theIsEmbeddedMode);
enum ComputeFlags
{
int GetANewId();
-private:
-
-
+public:
bool parallelComputeSubMeshes(
SMESH_Mesh & aMesh,
const TopoDS_Shape & aShape,
const bool includeSelf,
const bool complexShapeFirst,
const bool aShapeOnly);
+
+private:
+
+
+
int _localId; // unique Id of created objects, within SMESH_Gen entity
StudyContextStruct* _studyContext;
int result=pthread_create(&thread, NULL, deleteMeshDS, (void*)_meshDS);
#endif
}
- if(_pool)
- DeletePoolThreads();
}
//================================================================================
// sort submeshes according to stored mesh order
SortByMeshOrder( theSubMeshes );
}
-
-
-//=============================================================================
-/*!
- * \brief Build folder for parallel computation
- */
-//=============================================================================
-void SMESH_Mesh::CreateTmpFolder()
-{
-#ifndef WIN32
- // Temporary folder that will be used by parallel computation
- tmp_folder = fs::temp_directory_path()/fs::unique_path(fs::path("SMESH_%%%%-%%%%"));
- fs::create_directories(tmp_folder);
-#endif
-}
-//
-//=============================================================================
-/*!
- * \brief Delete temporary folder used for parallel computation
- */
-//=============================================================================
-void SMESH_Mesh::DeleteTmpFolder()
-{
-#ifndef WIN32
- fs::remove_all(tmp_folder);
-#endif
-}
#include "SMESH_ComputeError.hxx"
#include "SMESH_Controls.hxx"
#include "SMESH_Hypothesis.hxx"
+#include "SMESH_subMesh.hxx"
#include "SMDS_Iterator.hxx"
#include "Utils_SALOME_Exception.hxx"
class DriverMED_W_SMESHDS_Mesh;
+typedef std::set<int> TSetOfInt;
typedef std::list<int> TListOfInt;
typedef std::list<TListOfInt> TListOfListOfInt;
// Parallel computation functions
-#ifdef WIN32
- virtual void Lock() {};
- virtual void Unlock() {};
-
- virtual int GetNbThreads(){return _NbThreads;};
- virtual void SetNbThreads(long nbThreads){std::cout << "Warning Parallel Meshing is disabled on Windows it will behave as a slower normal compute" << std::endl;_NbThreads=nbThreads;};
-
- virtual void InitPoolThreads(){};
- virtual void DeletePoolThreads(){};
- virtual void wait(){}
-
- virtual bool IsParallel(){return _NbThreads > 0;}
-#else
- virtual void Lock() {_my_lock.lock();};
- virtual void Unlock() {_my_lock.unlock();};
-
- virtual int GetNbThreads(){return _NbThreads;};
- virtual void SetNbThreads(long nbThreads){_NbThreads=nbThreads;};
+ virtual void Lock(){};
+ virtual void Unlock(){};
- virtual void InitPoolThreads(){_pool = new boost::asio::thread_pool(_NbThreads);};
- virtual void DeletePoolThreads(){delete _pool;};
+ virtual int GetNbThreads(){return 0;};
+ virtual void SetNbThreads(long nbThreads){(void) nbThreads;};
- virtual void wait(){_pool->join(); DeletePoolThreads(); InitPoolThreads(); }
+ virtual void InitPoolThreads(){std::cout << "Should not pass here" << std::endl;};
+ virtual void DeletePoolThreads(){std::cout << "Should not pass here" << std::endl;};
+ virtual void wait(){std::cout << "Should not pass here" << std::endl;};
- virtual bool IsParallel(){return _NbThreads > 0;}
-#endif
+ virtual bool IsParallel(){std::cout << "Should not pass here" << std::endl;return false;};
- //TODO: to remove only used by ParallelMesh
- void CreateTmpFolder();
- void DeleteTmpFolder();
+ virtual bool ComputeSubMeshes(
+ SMESH_Gen* gen,
+ SMESH_Mesh & aMesh,
+ const TopoDS_Shape & aShape,
+ const ::MeshDimension aDim,
+ TSetOfInt* aShapesId /*=0*/,
+ TopTools_IndexedMapOfShape* allowedSubShapes,
+ SMESH_subMesh::compute_event &computeEvent,
+ const bool includeSelf,
+ const bool complexShapeFirst,
+ const bool aShapeOnly){(void) gen;(void) aMesh;(void) aShape;(void) aDim;(void) aShapesId;(void) allowedSubShapes;(void) computeEvent;(void) includeSelf;(void) complexShapeFirst;(void) aShapeOnly;std::cout << "Should not pass here" << std::endl;return false;};
- // Temporary folder used during parallel Computation
-#ifndef WIN32
+ // TODO: Remove from SMESH_Mesh
boost::filesystem::path tmp_folder;
boost::asio::thread_pool * _pool = nullptr; //thread pool for computation
-#else
- std::string tmp_folder;
- bool _pool = false;
-#endif
-
-
private:
void exportMEDCommmon(DriverMED_W_SMESHDS_Mesh& myWriter,
//
#include "SMESH_ParallelMesh.hxx"
+#include "SMESH_Gen.hxx"
+
+#ifdef WIN32
+ #include <windows.h>
+#endif
+
+#ifndef WIN32
+#include <boost/filesystem.hpp>
+namespace fs=boost::filesystem;
+#endif
+
+#ifndef WIN32
+#include <boost/asio.hpp>
+#endif
+
+#include <utilities.h>
+
+#ifdef _DEBUG_
+static int MYDEBUG = 1;
+#else
+static int MYDEBUG = 0;
+#endif
+
+SMESH_ParallelMesh::SMESH_ParallelMesh(int theLocalId,
+ SMESH_Gen* theGen,
+ bool theIsEmbeddedMode,
+ SMESHDS_Document* theDocument) :SMESH_Mesh(theLocalId,
+ theGen,
+ theIsEmbeddedMode,
+ theDocument)
+{
+ InitPoolThreads();
+ CreateTmpFolder();
+};
+
+SMESH_ParallelMesh::~SMESH_ParallelMesh()
+{
+ DeletePoolThreads();
+ if(!MYDEBUG)
+ DeleteTmpFolder();
+};
+
+
+
+//=============================================================================
+/*!
+ * \brief Build folder for parallel computation
+ */
+//=============================================================================
+void SMESH_ParallelMesh::CreateTmpFolder()
+{
+#ifndef WIN32
+ // Temporary folder that will be used by parallel computation
+ tmp_folder = fs::temp_directory_path()/fs::unique_path(fs::path("SMESH_%%%%-%%%%"));
+ fs::create_directories(tmp_folder);
+#endif
+}
+//
+//=============================================================================
+/*!
+ * \brief Delete temporary folder used for parallel computation
+ */
+//=============================================================================
+void SMESH_ParallelMesh::DeleteTmpFolder()
+{
+#ifndef WIN32
+ fs::remove_all(tmp_folder);
+#endif
+}
+
+bool SMESH_ParallelMesh::ComputeSubMeshes(
+ SMESH_Gen* gen,
+ SMESH_Mesh & aMesh,
+ const TopoDS_Shape & aShape,
+ const ::MeshDimension aDim,
+ TSetOfInt* aShapesId /*=0*/,
+ TopTools_IndexedMapOfShape* allowedSubShapes,
+ SMESH_subMesh::compute_event &computeEvent,
+ const bool includeSelf,
+ const bool complexShapeFirst,
+ const bool aShapeOnly)
+{
+ return gen->parallelComputeSubMeshes(
+ aMesh, aShape, aDim,
+ aShapesId, allowedSubShapes,
+ computeEvent,
+ includeSelf,
+ complexShapeFirst,
+ aShapeOnly);
+}
#include "SMESH_Mesh.hxx"
+#include "SMESH_Gen.hxx"
+#include "SMESH_subMesh.hxx"
+
class SMESH_EXPORT SMESH_ParallelMesh: public SMESH_Mesh
{
public:
int GetNbThreads() override{return _NbThreads;};
void SetNbThreads(long nbThreads) override{_NbThreads=nbThreads;};
- void InitPoolThreads() override{_pool = new boost::asio::thread_pool(_NbThreads);};
- void DeletePoolThreads() override{delete _pool;};
+ void InitPoolThreads() override {_pool = new boost::asio::thread_pool(_NbThreads);};
+ void DeletePoolThreads() override {delete _pool;};
- void wait() override{_pool->join(); DeletePoolThreads(); InitPoolThreads(); };
+ void wait() override {_pool->join(); DeletePoolThreads(); InitPoolThreads(); };
- bool IsParallel() override{return _NbThreads > 0;};
+ bool IsParallel() override {return _NbThreads > 0;};
void CreateTmpFolder();
void DeleteTmpFolder();
- private:
- boost::filesystem::path tmp_folder;
- boost::asio::thread_pool * _pool = nullptr; //thread pool for computation
+ bool ComputeSubMeshes(
+ SMESH_Gen* gen,
+ SMESH_Mesh & aMesh,
+ const TopoDS_Shape & aShape,
+ const ::MeshDimension aDim,
+ TSetOfInt* aShapesId /*=0*/,
+ TopTools_IndexedMapOfShape* allowedSubShapes,
+ SMESH_subMesh::compute_event &computeEvent,
+ const bool includeSelf,
+ const bool complexShapeFirst,
+ const bool aShapeOnly) override;
};
#endif
// Module : SMESH
//
#include "SMESH_SequentialMesh.hxx"
+
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Iterator.hxx>
+
+#include <utilities.h>
+
+SMESH_SequentialMesh::SMESH_SequentialMesh(int theLocalId,
+ SMESH_Gen* theGen,
+ bool theIsEmbeddedMode,
+ SMESHDS_Document* theDocument) :SMESH_Mesh(theLocalId,
+ theGen,
+ theIsEmbeddedMode,
+ theDocument)
+{
+};
+
+SMESH_SequentialMesh::~SMESH_SequentialMesh()
+{
+};
+
+bool SMESH_SequentialMesh::ComputeSubMeshes(
+ SMESH_Gen* gen,
+ SMESH_Mesh & aMesh,
+ const TopoDS_Shape & aShape,
+ const ::MeshDimension aDim,
+ TSetOfInt* aShapesId /*=0*/,
+ TopTools_IndexedMapOfShape* allowedSubShapes,
+ SMESH_subMesh::compute_event &computeEvent,
+ const bool includeSelf,
+ const bool complexShapeFirst,
+ const bool aShapeOnly)
+{
+ return gen->sequentialComputeSubMeshes(
+ aMesh, aShape, aDim,
+ aShapesId, allowedSubShapes,
+ computeEvent,
+ includeSelf,
+ complexShapeFirst,
+ aShapeOnly);
+};
#include "SMESH_Mesh.hxx"
+#include "SMESH_Gen.hxx"
+#include "SMESH_subMesh.hxx"
+
class SMESH_EXPORT SMESH_SequentialMesh: public SMESH_Mesh
{
public:
void Unlock() override {};
int GetNbThreads() override {return 0;};
- void SetNbThreads(long nbThreads) {};
+ void SetNbThreads(long nbThreads) {(void) nbThreads;};
void InitPoolThreads() override {};
void DeletePoolThreads() override {};
void wait() override {};
bool IsParallel() override {return false;};
+
+ bool ComputeSubMeshes (
+ SMESH_Gen* gen,
+ SMESH_Mesh & aMesh,
+ const TopoDS_Shape & aShape,
+ const ::MeshDimension aDim,
+ TSetOfInt* aShapesId /*=0*/,
+ TopTools_IndexedMapOfShape* allowedSubShapes,
+ SMESH_subMesh::compute_event &computeEvent,
+ const bool includeSelf,
+ const bool complexShapeFirst,
+ const bool aShapeOnly) override;
+
};
#endif
${KERNEL_Registry}
${KERNEL_SalomeHDFPersist}
${KERNEL_SalomeLifeCycleCORBA}
- ${KERNEL_TOOLSDS}
+ ${KERNEL_TOOLSDS}
${KERNEL_SalomeGenericObj}
${KERNEL_SalomeIDLKERNEL}
${KERNEL_SALOMELocalTrace}
SMESH.hxx
MG_ADAPT_i.hxx
SMESH_Homard_i.hxx
+ SMESH_SequentialMesh_i.hxx
+ SMESH_ParallelMesh_i.hxx
)
# --- sources ---
#include "SMESH_PythonDump.hxx"
#include "SMESH_ControlsDef.hxx"
#include <SMESH_BoostTxtArchive.hxx>
+#include <SMESH_SequentialMesh_i.hxx>
+#include <SMESH_ParallelMesh_i.hxx>
// to pass CORBA exception through SMESH_TRY
#define SMY_OWN_CATCH catch( SALOME::SALOME_Exception& se ) { throw se; }
*/
//=============================================================================
-SMESH::SMESH_Mesh_ptr SMESH_Gen_i::createMesh()
+SMESH::SMESH_Mesh_ptr SMESH_Gen_i::createMesh(bool parallel /*=false*/)
{
Unexpect aCatch(SALOME_SalomeException);
MESSAGE( "SMESH_Gen_i::createMesh" );
SMESH_Mesh_i* meshServant = new SMESH_Mesh_i( GetPOA(), this );
// create a new mesh object
MESSAGE("myIsEmbeddedMode " << myIsEmbeddedMode);
- meshServant->SetImpl( myGen.CreateMesh( myIsEmbeddedMode ));
+ if(parallel) {
+ meshServant->SetImpl( dynamic_cast<SMESH_Mesh*>(myGen.CreateParallelMesh( myIsEmbeddedMode )));
+ }else{
+ meshServant->SetImpl( dynamic_cast<SMESH_Mesh*>(myGen.CreateMesh( myIsEmbeddedMode )));
+ }
// activate the CORBA servant of Mesh
SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( meshServant->_this() );
return mesh._retn();
}
+//=============================================================================
+/*!
+ * SMESH_Gen_i::CreateParallelMesh
+ *
+ * Create empty parallel mesh on a shape and publish it in the study
+ */
+//=============================================================================
+
+SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateParallelMesh( GEOM::GEOM_Object_ptr theShapeObject )
+{
+ Unexpect aCatch(SALOME_SalomeException);
+ if(MYDEBUG) MESSAGE( "SMESH_Gen_i::CreateParallelMesh" );
+ // create mesh
+ SMESH::SMESH_Mesh_var mesh = this->createMesh(true);
+ // set shape
+ SMESH_Mesh_i* meshServant = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+ ASSERT( meshServant );
+ meshServant->SetShape( theShapeObject );
+
+ // publish mesh in the study
+ if ( CanPublishInStudy( mesh ) ) {
+ SALOMEDS::StudyBuilder_var aStudyBuilder = getStudyServant()->NewBuilder();
+ aStudyBuilder->NewCommand(); // There is a transaction
+ SALOMEDS::SObject_wrap aSO = PublishMesh( mesh.in() );
+ aStudyBuilder->CommitCommand();
+ if ( !aSO->_is_nil() ) {
+ // Update Python script
+ TPythonDump(this) << aSO << " = " << this << ".CreateMesh(" << theShapeObject << ")";
+ }
+ }
+
+ return mesh._retn();
+}
+
//=============================================================================
/*!
* SMESH_Gen_i::CreateEmptyMesh
// Create empty mesh on a shape
SMESH::SMESH_Mesh_ptr CreateMesh( GEOM::GEOM_Object_ptr theShapeObject );
+ // Create empty parallel mesh on a shape
+ SMESH::SMESH_Mesh_ptr CreateParallelMesh( GEOM::GEOM_Object_ptr theShapeObject );
+
// Create empty mesh
SMESH::SMESH_Mesh_ptr CreateEmptyMesh();
SMESH::SMESH_Hypothesis_ptr createHypothesis( const char* theHypName,
const char* theLibName);
// Create empty mesh on shape
- SMESH::SMESH_Mesh_ptr createMesh();
+ SMESH::SMESH_Mesh_ptr createMesh(bool parallel=false);
// Check mesh icon
bool isGeomModifIcon( SMESH::SMESH_Mesh_ptr mesh );
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
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)
Surcharge on Mesh for parallel computation of a mesh
"""
- def __init__(self, smeshpyD, geompyD, geom, param, nbThreads, name=0):
+ def __split_geom(self, geompyD, geom):
"""
- Create a parallel mesh.
+ Splitting geometry into n solids and a 2D/1D compound
Parameters:
geom: geometrical object for meshing
- param: full mesh parameters
- nbThreads: Number of threads for parallelisation.
- 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")
-
- if not isinstance(param, NETGENPlugin._objref_NETGENPlugin_Hypothesis):
- raise ValueError("param must come from NETGENPlugin")
-
- if nbThreads < 1:
- raise ValueError("Number of threads must be stricly greater than 1")
-
# Splitting geometry into 3D elements and all the 2D/1D into one compound
object_solids = geompyD.ExtractShapes(geom, geompyD.ShapeType["SOLID"],
True)
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
all_faces = geompyD.MakeGlueFaces(all_faces, 1e-07)
geompyD.addToStudy(all_faces, 'global2D')
- super(ParallelMesh, self).__init__(smeshpyD, geompyD, geom, name)
+ return all_faces, solids
+
+ def __init__(self, smeshpyD, geompyD, geom, param, nbThreads, name=0):
+ """
+ Create a parallel mesh.
+
+ Parameters:
+ geom: geometrical object for meshing
+ param: full mesh parameters
+ nbThreads: Number of threads for parallelisation.
+ 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")
+
+ if not isinstance(param, NETGENPlugin._objref_NETGENPlugin_Hypothesis):
+ raise ValueError("param must come from NETGENPlugin")
+
+ if nbThreads < 1:
+ raise ValueError("Number of threads must be stricly greater than 1")
+
+ all_faces, solids = self.__split_geom(geompyD, geom)
+
+ super(ParallelMesh, self).__init__(smeshpyD, geompyD, geom, name, parallel=True)
self.mesh.SetNbThreads(nbThreads)