From: cconopoima Date: Fri, 24 Mar 2023 18:07:46 +0000 (-0300) Subject: proposal for plugin merge X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=89ec42fcdf8ef14cfdcd7b35224e0d993f1057ae;p=plugins%2Fghs3dplugin.git proposal for plugin merge --- diff --git a/idl/GHS3DPlugin_Algorithm.idl b/idl/GHS3DPlugin_Algorithm.idl index ad673c2..3467b6f 100644 --- a/idl/GHS3DPlugin_Algorithm.idl +++ b/idl/GHS3DPlugin_Algorithm.idl @@ -118,6 +118,31 @@ module GHS3DPlugin */ void SetOptimizationLevel(in short level) raises (SALOME::SALOME_Exception); short GetOptimizationLevel(); + /*! + * Algorithm selection: 0-MGTetra HPC, 1-MGTetra + */ + void SetAlgorithm(in short level) raises (SALOME::SALOME_Exception); + short GetAlgorithm(); + /*! + * Set use number of threads + */ + void SetUseNumOfThreads(in boolean setThread) raises (SALOME::SALOME_Exception); + boolean GetUseNumOfThreads(); + /*! + * Set number of threads to use + */ + void SetNumOfThreads(in short numThreads); + short GetNumOfThreads(); + /*! + * PThreadMode defined for MGTetra + */ + void SetPthreadMode(in short pThreadMode) raises (SALOME::SALOME_Exception); + short GetPthreadMode(); + /*! + * ParallelMode defined for MGTetra HPC + */ + void SetParallelMode(in short parallelMode) raises (SALOME::SALOME_Exception); + short GetParallelMode(); /*! * Path to working directory */ diff --git a/src/GHS3DPlugin/CMakeLists.txt b/src/GHS3DPlugin/CMakeLists.txt index ff46649..286387f 100644 --- a/src/GHS3DPlugin/CMakeLists.txt +++ b/src/GHS3DPlugin/CMakeLists.txt @@ -75,6 +75,7 @@ SET(GHS3DEngine_HEADERS GHS3DPlugin_OptimizerHypothesis.hxx GHS3DPlugin_OptimizerHypothesis_i.hxx MG_Tetra_API.hxx + MG_TetraHPC_API.hxx ) # --- sources --- @@ -90,6 +91,7 @@ SET(GHS3DEngine_SOURCES GHS3DPlugin_OptimizerHypothesis.cxx GHS3DPlugin_OptimizerHypothesis_i.cxx MG_Tetra_API.cxx + MG_TetraHPC_API.cxx ) # --- scripts --- diff --git a/src/GHS3DPlugin/GHS3DPlugin_GHS3D.cxx b/src/GHS3DPlugin/GHS3DPlugin_GHS3D.cxx index b7b3109..b4e93a8 100644 --- a/src/GHS3DPlugin/GHS3DPlugin_GHS3D.cxx +++ b/src/GHS3DPlugin/GHS3DPlugin_GHS3D.cxx @@ -27,6 +27,7 @@ #include "GHS3DPlugin_GHS3D.hxx" #include "GHS3DPlugin_Hypothesis.hxx" #include "MG_Tetra_API.hxx" +#include "MG_TetraHPC_API.hxx" #include #include @@ -1580,14 +1581,25 @@ static bool writeGMFFile(MG_Tetra_API* MGInput return true; } + //============================================================================= /*! *Here we are going to use the MG-Tetra mesher with geometry */ //============================================================================= - bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh& theMesh, - const TopoDS_Shape& theShape) + const TopoDS_Shape& theShape ) +{ + bool isMGTetra = _hyp->GetAlgorithm() == GHS3DPlugin_Hypothesis::MGTetra; + + if ( isMGTetra ) + return ComputeMGTetra( theMesh, theShape ); + else + return ComputeMGTetraHPC( theMesh, theShape ); +} + +bool GHS3DPlugin_GHS3D::ComputeMGTetra(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape) { bool Ok(false); TopExp_Explorer expBox ( theShape, TopAbs_SOLID ); @@ -1867,13 +1879,33 @@ bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh& theMesh, return Ok; } +bool GHS3DPlugin_GHS3D::ComputeMGTetraHPC(SMESH_Mesh& theMesh, + const TopoDS_Shape& /*theShape*/) +{ + SMESH_MesherHelper helper( theMesh ); + bool ok = ComputeMGTetraHPC( theMesh, &helper ); + return ok; +} + //============================================================================= /*! *Here we are going to use the MG-Tetra mesher w/o geometry */ -//============================================================================= +//================================0============================================= bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh& theMesh, - SMESH_MesherHelper* theHelper) + SMESH_MesherHelper* theHelper ) +{ + bool isMGTetra = _hyp->GetAlgorithm() == GHS3DPlugin_Hypothesis::MGTetra; + + if ( isMGTetra ) + return ComputeMGTetra( theMesh, theHelper ); + else + return ComputeMGTetraHPC( theMesh, theHelper ); + +} + +bool GHS3DPlugin_GHS3D::ComputeMGTetra(SMESH_Mesh& theMesh, + SMESH_MesherHelper* theHelper) { theHelper->IsQuadraticSubMesh( theHelper->GetSubShape() ); @@ -2083,6 +2115,274 @@ bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh& theMesh, return Ok; } +//============================================================================= +// Write a skin mesh into a GMF file or pass it to MG-TetraHPC API +static void exportGMFHPC( MG_TetraHPC_API* theTetraInput, + const char* theFile, + const SMESHDS_Mesh* theMeshDS) +{ + int meshID = theTetraInput->GmfOpenMesh( theFile, GmfWrite, GMFVERSION, GMFDIMENSION); + + // nodes + int iN = 0, nbNodes = theMeshDS->NbNodes(); + theTetraInput->GmfSetKwd( meshID, GmfVertices, nbNodes ); + std::map< const SMDS_MeshNode*, int, TIDCompare > node2IdMap; + SMDS_NodeIteratorPtr nodeIt = theMeshDS->nodesIterator(); + SMESH_TNodeXYZ n; + while ( nodeIt->more() ) + { + n.Set( nodeIt->next() ); + theTetraInput->GmfSetLin( meshID, GmfVertices, n.X(), n.Y(), n.Z(), n._node->getshapeId() ); + node2IdMap.insert( node2IdMap.end(), std::make_pair( n._node, ++iN )); + } + + // triangles + SMDS_ElemIteratorPtr elemIt = theMeshDS->elementGeomIterator( SMDSGeom_TRIANGLE ); + if ( elemIt->more() ) + { + int nbTria = theMeshDS->GetMeshInfo().NbElements( SMDSGeom_TRIANGLE ); + theTetraInput->GmfSetKwd(meshID, GmfTriangles, nbTria ); + for ( int gmfID = 1; elemIt->more(); ++gmfID ) + { + const SMDS_MeshElement* tria = elemIt->next(); + theTetraInput->GmfSetLin(meshID, GmfTriangles, + node2IdMap[ tria->GetNode( 0 )], + node2IdMap[ tria->GetNode( 1 )], + node2IdMap[ tria->GetNode( 2 )], + tria->getshapeId() ); + } + } + theTetraInput->GmfCloseMesh( meshID ); +} + + +//======================================================================= +//before launching salome +//SALOME_TMP_DIR (for keep tepal intermediates files) could be set in user's directories +static TCollection_AsciiString getTmpDir() +{ + TCollection_AsciiString aTmpDir; + char *Tmp_dir = getenv("SALOME_TMP_DIR"); + if (Tmp_dir == NULL) Tmp_dir = getenv("TMP"); + if(Tmp_dir != NULL) + { + aTmpDir = Tmp_dir; +#ifdef WIN32 + if(aTmpDir.Value(aTmpDir.Length()) != '\\') aTmpDir+='\\'; +#else + if(aTmpDir.Value(aTmpDir.Length()) != '/') aTmpDir+='/'; +#endif + } + else + { +#ifdef WIN32 + aTmpDir = TCollection_AsciiString("C:\\"); +#else + aTmpDir = TCollection_AsciiString("/tmp/"); +#endif + } + return aTmpDir; +} + +bool GHS3DPlugin_GHS3D::ComputeMGTetraHPC(SMESH_Mesh& theMesh, + SMESH_MesherHelper* /*theHelper*/) +{ + bool Ok=false; + TCollection_AsciiString pluginerror("MG-TETRA_HPC: "); + SMESHDS_Mesh* meshDS = theMesh.GetMeshDS(); + if ( theMesh.NbTriangles() == 0 ) + return error( COMPERR_BAD_INPUT_MESH, "From MGTetra-HPC. No triangles in the mesh" ); + + if (_hyp == NULL){ + pluginerror += "No existing parameters/hypothesis for MG-TETRA_HPC"; + cout <<"\n"<HasOptionDefined("verbose") : true; + bool proximity = _hyp->GetUseVolumeProximity(); + bool _Multithread = _hyp->GetUseNumOfThreads(); + double minSize = _hyp->GetMinSize(); + double maxSize = _hyp->GetMaxSize(); + + TCollection_AsciiString + tmpDir = getTmpDir(), + GHS3DPRL_In, + GHS3DPRL_Out, + GHS3DPRL_Out_Mesh, + GHS3DPRL_Outxml, + logFileName, + rm("rm -f "), + run_nokeep_files, + NbPart, + fileskinmed(""), + path, + casenamemed; //_MEDName.c_str()); + + casenamemed += (char *)_MEDName.c_str(); + int n = casenamemed.SearchFromEnd('/'); + + if (n>0) { + path=casenamemed.SubString(1,n); + casenamemed=casenamemed.SubString(n+1,casenamemed.Length()); + } + else + path=tmpDir; + + if (casenamemed.Length()>20){ + casenamemed=casenamemed.SubString(1,20); + cerr<<"MEDName truncated (no more 20 characters) = "<GetNumOfThreads() ); + + const char* parallelMode[] = { "none", "reproducible_given_max_number_of_threads", "reproducible", "aggressive" }; + const short myMode = _hyp->GetParallelMode(); + if ( myMode >= 0 && myMode < 4 ) { + cmd += " --parallel_mode "; + cmd += parallelMode[ myMode ]; + } + } + + cmd = cmd + " --gradation " + SMESH_Comment( _hyp->GetGradation() ); + + const char* optimizationLevel[] = { "none" , "light" , "standard" , "standard+" , "strong" }; + const short myOpt = _hyp->GetOptimizationLevel(); + if ( myOpt >= 0 && myOpt < 5 && myOpt != 3 /*not standard+ for HPC*/) { + cmd += " --optimisation_level "; + cmd += optimizationLevel[ myOpt ]; + } + + if ( minSize > 0 ) cmd = cmd + " --min_size " + SMESH_Comment( minSize ); + if ( maxSize > 0 ) cmd = cmd + " --max_size " + SMESH_Comment( maxSize ); + if ( verbose ) cmd = cmd + " --verbose " + SMESH_Comment( _hyp->GetVerboseLevel() ); + if ( proximity ) cmd = cmd + " --volume_proximity_layers " + SMESH_Comment( _hyp->GetNbVolumeProximityLayers() ); + + _hyp->SetAdvancedOptionsInCommandLine( _AdvOptions, false ); + cmd = cmd + " " + _AdvOptions.c_str(); + cmd = cmd + " --out=" + GHS3DPRL_Out_Mesh; + cmd = cmd + " 1>" + logFileName; + + cout << endl + << " Run mg-tetra_hpc as library. Creating a mesh file " << GHS3DPRL_Out_Mesh << endl + << " Creating a log file : " << logFileName << endl << endl; + + mgTetraHPC.SetLogFile( logFileName.ToCString() ); + + std::string log; + Ok = mgTetraHPC.Compute( cmd.ToCString(), log ); + + if (!Ok) + { + std::cout << "Error: " << std::endl; + std::cout << log << std::endl; + // try to guess an error from the output log + std::string log2 = mgTetraHPC.GetLog(); + if ( log2.find("Dlim" ) != std::string::npos || + log2.find("License") != std::string::npos ) + return error("License problem"); + std::cout << log2 << std::endl; + if ( log2.find("You are using an empty MPI stubs library") != std::string::npos ) + { + std:string msg = "You are using an empty MPI stubs library. Please build it first to be able to use mg-tetra_hpc_mpi.exe.\n"; + msg += "./salome context\n"; + msg += "cd $MESHGEMSHOME/stubs\n"; + msg += "mpicc meshgems_mpi.c -DMESHGEMS_LINUX_BUILD -I../include -shared -fPIC -o $MESHGEMSHOME/lib/Linux_64/libmeshgems_mpi.so"; + return error(msg); + } + return error(log); + } + + if (!_Multithread) + { + fileskinmed=path + casenamemed + "_skin.med"; + cout<<" Write file "< 0) + { + Ok = true; + pluginerror = pluginerror + "MG-tetra_hpc mesh not loaded in memory, is stored in file "+ resuMedFile; + cout<_option2value, & this->_customOption2value }; + for ( int iOp = 0; iOp < 2; ++iOp ) + { + TOptionValues::const_iterator o2v = options[iOp]->begin(); + for ( ; o2v != options[iOp]->end(); ++o2v ) + { + option = o2v->first; + value = this->GetOptionValue( option, &isDefault ); + std::cout << option << ", " << value << std::endl; + + if ( isDefault ) + continue; + + if ( value.empty() )//value == NoValue() ) + { + if ( this->_defaultOptionValues.count( option )) + continue; // non-custom option with no value + //value.clear(); + } + + if ( strncmp( "no", option.c_str(), 2 ) == 0 ) // options w/o values: --no_* + { + if ( !value.empty() && ToBool( value ) == false ) + continue; + value.clear(); + } + + if ( option[0] != '-' ) + cmd += " --"; + else + cmd += " "; + cmd += option + " " + value; + } + } +} + //================================================================================ /*! * \brief Return command to run MG-Tetra mesher excluding file prefix (-f) @@ -1715,89 +1855,64 @@ std::string GHS3DPlugin_Hypothesis::CommandToRun(const GHS3DPlugin_Hypothesis* h cmd += " --internalpoints no"; } - // verbose mode - if ( verbose && hyp ) { - cmd += " --verbose " + SMESH_Comment( hyp->myVerboseLevel ); - } + if ( hyp ) + { + // verbose mode + if ( verbose ) { + cmd += " --verbose " + SMESH_Comment( hyp->myVerboseLevel ); + } - // boundary recovery version - // if ( useBndRecovery ) { - // cmd += " -C"; - // } + // boundary recovery version + // if ( useBndRecovery ) { + // cmd += " -C"; + // } - // to use FEM correction - // if ( fem && hyp && hyp->myToUseFemCorrection) { - // cmd += " -FEM"; - // } + // to use FEM correction + // if ( fem && hyp && hyp->myToUseFemCorrection) { + // cmd += " -FEM"; + // } - // to remove initial central point. - if ( rem && hyp && hyp->myToRemoveCentralPoint ) { - if ( forExecutable ) - cmd += " --no_initial_central_point"; - else - cmd += " --centralpoint no"; - } + // to remove initial central point. + if ( rem && hyp->myToRemoveCentralPoint ) { + if ( forExecutable ) + cmd += " --no_initial_central_point"; + else + cmd += " --centralpoint no"; + } + + // options as text + // if ( !hyp->myTextOption.empty() ) { + // cmd += " " + hyp->myTextOption; + // } - // options as text - // if ( hyp && !hyp->myTextOption.empty() ) { - // cmd += " " + hyp->myTextOption; - // } - // min/max size - if ( hyp ) - { if ( hyp->GetMinSize() > 0 ) cmd += " --min_size " + SMESH_Comment( hyp->GetMinSize() ); + if ( hyp->GetMaxSize() > 0 ) cmd += " --max_size " + SMESH_Comment( hyp->GetMaxSize() ); - } - // to define volumic gradation. - if ( gra && hyp ) - { - cmd += " --gradation " + SMESH_Comment( hyp->myGradation ); - } + // to define volumic gradation. + if ( gra ) + cmd += " --gradation " + SMESH_Comment( hyp->myGradation ); - if ( hyp ) - { - // proximity - if ( hyp->GetUseVolumeProximity() ) + if ( hyp->GetUseNumOfThreads() ) { - cmd += " --volume_proximity_layers " + SMESH_Comment( hyp->GetNbVolumeProximityLayers() ); + cmd += " --max_number_of_threads " + SMESH_Comment( hyp->GetNumOfThreads() ); + const char* pthreadMode[] = { "none" , "aggressive" , "safe" }; + if ( hyp->myPthreadModeMG >= 0 && hyp->myPthreadModeMG < 3 ) { + cmd += " --pthreads_mode "; + cmd += pthreadMode[ hyp->myPthreadModeMG ]; + } } - std::string option, value; - bool isDefault; - const TOptionValues* options[] = { & hyp->_option2value, & hyp->_customOption2value }; - for ( int iOp = 0; iOp < 2; ++iOp ) + // proximity + if ( hyp->GetUseVolumeProximity() ) { - TOptionValues::const_iterator o2v = options[iOp]->begin(); - for ( ; o2v != options[iOp]->end(); ++o2v ) - { - option = o2v->first; - value = hyp->GetOptionValue( option, &isDefault ); - - if ( isDefault ) - continue; - if ( value.empty() )//value == NoValue() ) - { - if ( hyp->_defaultOptionValues.count( option )) - continue; // non-custom option with no value - //value.clear(); - } - if ( strncmp( "no", option.c_str(), 2 ) == 0 ) // options w/o values: --no_* - { - if ( !value.empty() && ToBool( value ) == false ) - continue; - value.clear(); - } - if ( option[0] != '-' ) - cmd += " --"; - else - cmd += " "; - cmd += option + " " + value; - } + cmd += " --volume_proximity_layers " + SMESH_Comment( hyp->GetNbVolumeProximityLayers() ); } + + hyp->SetAdvancedOptionsInCommandLine( cmd, true ); } #ifdef WIN32 @@ -1809,7 +1924,7 @@ std::string GHS3DPlugin_Hypothesis::CommandToRun(const GHS3DPlugin_Hypothesis* h //================================================================================ /*! - * \brief Return a unique file name + * \brief Return a unique file name for MGTetra */ //================================================================================ @@ -1835,6 +1950,34 @@ std::string GHS3DPlugin_Hypothesis::GetFileName(const GHS3DPlugin_Hypothesis* hy return aGenericName.ToCString(); } +//================================================================================ +/*! + * \brief Return a unique file name when running MGTetra HPC + */ +//================================================================================ + +std::string GHS3DPlugin_Hypothesis::GetFileNameHPC(const GHS3DPlugin_Hypothesis* hyp) +{ + std::string aTmpDir = hyp ? hyp->GetWorkingDirectory() : DefaultWorkingDirectory(); + if ( !SMESH_File( aTmpDir ).exists() ) + aTmpDir = Kernel_Utils::GetTmpDirByPath( aTmpDir ); + + const char lastChar = *aTmpDir.rbegin(); +#ifdef WIN32 + if(lastChar != '\\') aTmpDir+='\\'; +#else + if(lastChar != '/') aTmpDir+='/'; +#endif + + TCollection_AsciiString aGenericName = (char*)aTmpDir.c_str(); + aGenericName += "MGTETRAHPC_"; + aGenericName += getpid(); + aGenericName += "_"; + aGenericName += Abs((Standard_Integer)(long) aGenericName.ToCString()); + + return aGenericName.ToCString(); +} + //================================================================================ /* * Return the name of executable diff --git a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis.hxx b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis.hxx index 28279b2..97e0162 100644 --- a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis.hxx +++ b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis.hxx @@ -183,6 +183,36 @@ public: */ void SetVerboseLevel(short level); short GetVerboseLevel() const; + /*! + * Implemented algorithms to be executed [0,1] + * 0 - MGTetra-HPC + * 1 - MGTetra + */ + enum ImplementedAlgorithms { MGTetraHPC = 0, MGTetra }; + void SetAlgorithm(ImplementedAlgorithms algoId); + ImplementedAlgorithms GetAlgorithm() const; + /*! + * Set Get for flag to use pthread parallel version of the algorithm + */ + void SetUseNumOfThreads(bool setUseOfThreads); + bool GetUseNumOfThreads() const; + /*! + * Set Get num of threads to be used by MGTetra algorithms + */ + void SetNumOfThreads(short numOfThreads); + short GetNumOfThreads() const; + /*! + * Set Get pthread mode used for MGTetra + */ + enum PThreadMode { PThreadNone = 0, PThreadAggressive, Safe }; + void SetPthreadMode(PThreadMode pthreadMode ); + PThreadMode GetPthreadMode() const; + /*! + * Set Get paralle mode used for MGTetra HPC + */ + enum ParallelMode { ParallelNone = 0, ReproducibleGivenMaxNumThreads, Reproducible, ParallelAggressive }; + void SetParallelMode(ParallelMode parallelMode ); + ParallelMode GetParallelMode() const; /*! * To create new nodes */ @@ -240,16 +270,18 @@ public: void ClearOption(const std::string& optionName); TOptionValues GetOptionValues() const; const TOptionValues& GetCustomOptionValues() const { return _customOption2value; } - //static inline const char* NoValue() { return "_"; } + /*! + * \brief To set the advanced options in the execution command line + */ + void SetAdvancedOptionsInCommandLine( std::string & cmd, bool isMGTetra ) const; + //static inline const char* NoValue() { return "_"; } // struct TEnforcedEdge { // long ID; // long node1; // long node2; // std::string groupName; // }; - - /*! * \brief Return command to run MG-Tetra mesher excluding file prefix (-f) */ @@ -260,6 +292,10 @@ public: * \brief Return a unique file name */ static std::string GetFileName(const GHS3DPlugin_Hypothesis* hyp); + /*! + * \brief Return a unique file name for MGTetraHPC will have a GHS3D prefix + */ + static std::string GetFileNameHPC(const GHS3DPlugin_Hypothesis* hyp); /*! * \brief Return the name of executable */ @@ -331,6 +367,8 @@ public: static inline double DefaultGradation() { return 1.05; } static bool DefaultUseVolumeProximity() { return false; } static int DefaultNbVolumeProximityLayers() { return 2; } + static short DefaultAlgorithm() { return MGTetra; } + static short DefaultNumOfThreads() { return 4; } void SetMinMaxSizeDefault( double theMinSize, double theMaxSize ) { myMinSizeDefault = theMinSize; myMaxSizeDefault = theMaxSize; } @@ -377,10 +415,16 @@ protected: double myMinSize, myMinSizeDefault; double myMaxSize, myMaxSizeDefault; //std::string myTextOption; + short myAlgorithm; //member used to pivot between MG-Tetra and MG-Tetra + bool myUseNumOfThreads; + short myNumOfThreads; + short myPthreadModeMG; + short myPthreadModeMGHPC; TOptionValues _option2value, _customOption2value; // user defined values TOptionValues _defaultOptionValues; // default values - TOptionNames _doubleOptions, _charOptions, _boolOptions; // to find a type of option + TOptionNames _doubleOptions, _charOptions, _boolOptions; // to find a type of option + std::vector _commonMGTetraAdvancedOptions; // common advanced options for MGTetra and MGTetraHPC TGHS3DEnforcedVertexList _enfVertexList; TGHS3DEnforcedVertexCoordsValues _enfVertexCoordsSizeList; diff --git a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.cxx b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.cxx index 1713aa4..096742a 100644 --- a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.cxx +++ b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.cxx @@ -258,6 +258,104 @@ CORBA::Short GHS3DPlugin_Hypothesis_i::GetOptimizationLevel() return this->GetImpl()->GetOptimizationLevel(); } +//======================================================================= +//function : SetAlgorithm +//======================================================================= +void GHS3DPlugin_Hypothesis_i::SetAlgorithm(CORBA::Short algoId) +{ + ::GHS3DPlugin_Hypothesis::ImplementedAlgorithms algo = (::GHS3DPlugin_Hypothesis::ImplementedAlgorithms) algoId; + ASSERT(myBaseImpl); + this->GetImpl()->SetAlgorithm(algo); + SMESH::TPythonDump() << _this() << ".SetAlgorithm( " << algoId << " )"; +} + +//======================================================================= +//function : GetAlgorithm +//======================================================================= +CORBA::Short GHS3DPlugin_Hypothesis_i::GetAlgorithm() +{ + ASSERT(myBaseImpl); + return this->GetImpl()->GetAlgorithm(); +} + +//======================================================================= +//function : SetUseNumOfThreads +//======================================================================= +void GHS3DPlugin_Hypothesis_i::SetUseNumOfThreads(CORBA::Boolean setThread) +{ + ASSERT(myBaseImpl); + this->GetImpl()->SetUseNumOfThreads(setThread); + SMESH::TPythonDump() << _this() << ".SetUseNumOfThreads( " << setThread << " )"; +} + +//======================================================================= +//function : GetUseNumOfThreads +//======================================================================= +CORBA::Boolean GHS3DPlugin_Hypothesis_i::GetUseNumOfThreads() +{ + ASSERT(myBaseImpl); + return this->GetImpl()->GetUseNumOfThreads(); +} + +//======================================================================= +//function : SetNumOfThreads +//======================================================================= +void GHS3DPlugin_Hypothesis_i::SetNumOfThreads(CORBA::Short numOfThreads) +{ + ASSERT(myBaseImpl); + this->GetImpl()->SetNumOfThreads(numOfThreads); + SMESH::TPythonDump() << _this() << ".SetNumOfThreads( " << numOfThreads << " )"; +} + +//======================================================================= +//function : GetNumOfThreads +//======================================================================= +CORBA::Short GHS3DPlugin_Hypothesis_i::GetNumOfThreads() +{ + ASSERT(myBaseImpl); + return this->GetImpl()->GetNumOfThreads(); +} + +//======================================================================= +//function : SetNumOfThreads +//======================================================================= +void GHS3DPlugin_Hypothesis_i::SetPthreadMode(CORBA::Short pThreadMode) +{ + ::GHS3DPlugin_Hypothesis::PThreadMode mode = (::GHS3DPlugin_Hypothesis::PThreadMode) pThreadMode; + ASSERT(myBaseImpl); + this->GetImpl()->SetPthreadMode(mode); + SMESH::TPythonDump() << _this() << ".SetPthreadMode( " << pThreadMode << " )"; +} + +//======================================================================= +//function : GetNumOfThreads +//======================================================================= +CORBA::Short GHS3DPlugin_Hypothesis_i::GetPthreadMode() +{ + ASSERT(myBaseImpl); + return this->GetImpl()->GetPthreadMode(); +} + +//======================================================================= +//function : SetNumOfThreads +//======================================================================= +void GHS3DPlugin_Hypothesis_i::SetParallelMode(CORBA::Short parallelMode) +{ + ::GHS3DPlugin_Hypothesis::ParallelMode mode = (::GHS3DPlugin_Hypothesis::ParallelMode) parallelMode; + ASSERT(myBaseImpl); + this->GetImpl()->SetParallelMode(mode); + SMESH::TPythonDump() << _this() << ".SetParallelMode( " << parallelMode << " )"; +} + +//======================================================================= +//function : GetNumOfThreads +//======================================================================= +CORBA::Short GHS3DPlugin_Hypothesis_i::GetParallelMode() +{ + ASSERT(myBaseImpl); + return this->GetImpl()->GetParallelMode(); +} + //======================================================================= //function : SetWorkingDirectory //======================================================================= diff --git a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.hxx b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.hxx index 050a8e1..65ef921 100644 --- a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.hxx +++ b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.hxx @@ -93,6 +93,32 @@ class GHS3DPLUGIN_EXPORT GHS3DPlugin_Hypothesis_i: */ void SetOptimizationLevel(CORBA::Short level); CORBA::Short GetOptimizationLevel(); + /*! + * Algorithm Id: 0-MGTetra HPC, 1-MGTetra + */ + void SetAlgorithm(CORBA::Short algoId); + CORBA::Short GetAlgorithm(); + /*! + * Flag for set get optional use parallelism in MGTetra + */ + void SetUseNumOfThreads(CORBA::Boolean useThreads); + CORBA::Boolean GetUseNumOfThreads(); + /*! + * Get set number of threads to use on the parallel MGTetra algorithm + */ + void SetNumOfThreads(CORBA::Short numThreads); + CORBA::Short GetNumOfThreads(); + /*! + * PthreadMode: 0-PThreadNone, 1-PThreadAggressive, 2-Safe + */ + void SetPthreadMode(CORBA::Short pThreadMode); + CORBA::Short GetPthreadMode(); + /*! + * SetParallelMode level: 0-ParallelNone, 1-ReproducibleGivenMaxNumThreads, 2-Reproducible, 3-ParallelAggressive + + */ + void SetParallelMode(CORBA::Short parallelMode); + CORBA::Short GetParallelMode(); /*! * Path to working directory */ diff --git a/src/GHS3DPlugin/MG_TetraHPC_API.cxx b/src/GHS3DPlugin/MG_TetraHPC_API.cxx new file mode 100644 index 0000000..cdecdf2 --- /dev/null +++ b/src/GHS3DPlugin/MG_TetraHPC_API.cxx @@ -0,0 +1,1239 @@ +// Copyright (C) 2004-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "MG_TetraHPC_API.hxx" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef USE_MG_LIBS + +extern "C"{ +#include +#include +} + +struct MG_TetraHPC_API::LibData +{ + // MG objects + context_t * _context; + tetra_hpc_session_t * _session; + mesh_t * _tria_mesh; + sizemap_t * _sizemap; + mesh_t * _tetra_mesh; + + // data to pass to MG + std::vector _xyz; + std::vector _nodeSize; // required nodes + std::vector _edgeNodes; + int _nbRequiredEdges; + std::vector _triaNodes; + int _nbRequiredTria; + + int _count; + volatile bool& _cancelled_flag; + std::string _errorStr; + double& _progress; + + LibData( volatile bool & cancelled_flag, double& progress ) + : _context(0), _session(0), _tria_mesh(0), _sizemap(0), _tetra_mesh(0), + _nbRequiredEdges(0), _nbRequiredTria(0), + _cancelled_flag( cancelled_flag ), _progress( progress ) + { + } + // methods setting callbacks implemented after callback definitions + void Init(); + bool Compute( const std::string& outFile ); + + ~LibData() + { + if ( _tetra_mesh ) + tetra_hpc_regain_mesh( _session, _tetra_mesh ); + if ( _session ) + tetra_hpc_session_delete( _session ); + if ( _tria_mesh ) + mesh_delete( _tria_mesh ); + if ( _sizemap ) + sizemap_delete( _sizemap ); + if ( _context ) + context_delete( _context ); + + _tetra_mesh = 0; + _session = 0; + _tria_mesh = 0; + _sizemap = 0; + _context = 0; + } + + void AddError( const char *txt ) + { + if ( txt ) + _errorStr += txt; + } + + const std::string& GetErrors() + { + return _errorStr; + } + + void MG_Error(const char* txt="") + { + SMESH_Comment msg("\nMeshGems error. "); + msg << txt << "\n"; + AddError( msg.c_str() ); + } + + bool SetParam( const std::string& param, const std::string& value ) + { + status_t ret = tetra_hpc_set_param( _session, param.c_str(), value.c_str() ); +#ifdef _DEBUG_ + //std::cout << param << " = " << value << std::endl; +#endif + return ( ret == STATUS_OK ); + } + + bool Cancelled() + { + return _cancelled_flag; + } + + int ReadNbSubDomains() + { + integer nb = 0; + status_t ret = mesh_get_subdomain_count( _tetra_mesh, & nb ); + + if ( ret != STATUS_OK ) MG_Error("mesh_get_subdomain_count problem"); + return nb; + } + + int ReadNbNodes() + { + integer nb = 0; + status_t ret = mesh_get_vertex_count( _tetra_mesh, & nb ); + + if ( ret != STATUS_OK ) MG_Error("mesh_get_vertex_count problem"); + return nb; + } + + int ReadNbEdges() + { + integer nb = 0; + status_t ret = mesh_get_edge_count( _tetra_mesh, & nb ); + + if ( ret != STATUS_OK ) MG_Error("mesh_get_edge_count problem"); + return nb; + } + + int ReadNbTria() + { + integer nb = 0; + status_t ret = mesh_get_triangle_count( _tetra_mesh, & nb ); + + if ( ret != STATUS_OK ) MG_Error("mesh_get_triangle_count problem"); + return nb; + } + + int ReadNbQuads() + { + integer nb = 0; + status_t ret = mesh_get_quadrangle_count( _tetra_mesh, & nb ); + + if ( ret != STATUS_OK ) MG_Error("mesh_get_quadrangle_count problem"); + return nb; + } + + int ReadNbTetra() + { + integer nb = 0; + status_t ret = mesh_get_tetrahedron_count( _tetra_mesh, & nb ); + + if ( ret != STATUS_OK ) MG_Error("mesh_get_tetrahedron_count problem"); + return nb; + } + + int ReadNbHexa() + { + integer nb = 0; + status_t ret = mesh_get_hexahedron_count( _tetra_mesh, & nb ); + + if ( ret != STATUS_OK ) MG_Error("mesh_get_hexahedron_count problem"); + return nb; + } + + void ResetCounter() + { + _count = 1; + } + + void ReadSubDomain( int* nbNodes, int* faceInd, int* ori, int* domain ) + { + integer tag, seed_type, seed_idx, seed_orientation; + status_t ret = mesh_get_subdomain_description( _tetra_mesh, _count, + &tag, &seed_type, &seed_idx, &seed_orientation); + + if ( ret != STATUS_OK ) MG_Error( "unable to get a sub-domain description"); + + *nbNodes = 3; + *faceInd = seed_idx; + *domain = tag; + *ori = seed_orientation; + + ++_count; + } + void ReadNodeXYZ( double* x, double* y, double *z, int* /*domain*/ ) + { + real coo[3]; + status_t ret = mesh_get_vertex_coordinates( _tetra_mesh, _count, coo ); + if ( ret != STATUS_OK ) MG_Error( "unable to get resulting vertices" ); + + *x = coo[0]; + *y = coo[1]; + *z = coo[2]; + + ++_count; + } + + void ReadEdgeNodes( int* node1, int* node2, int* domain ) + { + integer vtx[2], tag; + status_t ret = mesh_get_edge_vertices( _tetra_mesh, _count, vtx); + if (ret != STATUS_OK) MG_Error( "unable to get resulting edge" ); + + *node1 = vtx[0]; + *node2 = vtx[1]; + + ret = mesh_get_edge_tag( _tetra_mesh, _count, &tag ); + if (ret != STATUS_OK) MG_Error( "unable to get resulting edge tag" ); + + *domain = tag; + + ++_count; + } + + void ReadTriaNodes( int* node1, int* node2, int* node3, int* domain ) + { + integer vtx[3], tag; + status_t ret = mesh_get_triangle_vertices( _tetra_mesh, _count, vtx); + if (ret != STATUS_OK) MG_Error( "unable to get resulting triangle" ); + + *node1 = vtx[0]; + *node2 = vtx[1]; + *node3 = vtx[2]; + + ret = mesh_get_triangle_tag( _tetra_mesh, _count, &tag ); + if (ret != STATUS_OK) MG_Error( "unable to get resulting triangle tag" ); + + *domain = tag; + + ++_count; + } + + void ReadQuadNodes( int* node1, int* node2, int* node3, int* node4, int* domain ) + { + integer vtx[4], tag; + status_t ret = mesh_get_quadrangle_vertices( _tetra_mesh, _count, vtx); + if (ret != STATUS_OK) MG_Error( "unable to get resulting quadrangle" ); + + *node1 = vtx[0]; + *node2 = vtx[1]; + *node3 = vtx[2]; + *node4 = vtx[3]; + + ret = mesh_get_quadrangle_tag( _tetra_mesh, _count, &tag ); + if (ret != STATUS_OK) MG_Error( "unable to get resulting quadrangle tag" ); + + *domain = tag; + + ++_count; + } + + void ReadTetraNodes( int* node1, int* node2, int* node3, int* node4, int* domain ) + { + integer vtx[4], tag; + status_t ret = mesh_get_tetrahedron_vertices( _tetra_mesh, _count, vtx); + if (ret != STATUS_OK) MG_Error( "unable to get resulting tetrahedron" ); + + *node1 = vtx[0]; + *node2 = vtx[1]; + *node3 = vtx[2]; + *node4 = vtx[3]; + + ret = mesh_get_tetrahedron_tag( _tetra_mesh, _count, &tag ); + if (ret != STATUS_OK) MG_Error( "unable to get resulting tetrahedron tag" ); + + *domain = tag; + + ++_count; + } + + void ReadHexaNodes( int* node1, int* node2, int* node3, int* node4, + int* node5, int* node6, int* node7, int* node8, int* domain ) + { + integer vtx[8], tag; + status_t ret = mesh_get_hexahedron_vertices( _tetra_mesh, _count, vtx); + if (ret != STATUS_OK) MG_Error( "unable to get resulting hexahedron" ); + + *node1 = vtx[0]; + *node2 = vtx[1]; + *node3 = vtx[2]; + *node4 = vtx[3]; + *node5 = vtx[4]; + *node6 = vtx[5]; + *node7 = vtx[6]; + *node8 = vtx[7]; + + ret = mesh_get_hexahedron_tag( _tetra_mesh, _count, &tag ); + if (ret != STATUS_OK) MG_Error( "unable to get resulting hexahedron tag" ); + + *domain = tag; + + ++_count; + } + + void SetNbVertices( int nb ) + { + _xyz.reserve( _xyz.capacity() + nb ); + } + + void SetNbEdges( int nb ) + { + _edgeNodes.reserve( nb * 2 ); + } + + void SetNbTria( int nb ) + { + _triaNodes.reserve( nb * 3 ); + } + + void SetNbReqVertices( int nb ) + { + _nodeSize.reserve( nb ); + } + + void SetNbReqEdges( int nb ) + { + _nbRequiredEdges = nb; + } + + void SetNbReqTria( int nb ) + { + _nbRequiredTria = nb; + } + + void AddNode( double x, double y, double z, int /*domain*/ ) + { + _xyz.push_back( x ); + _xyz.push_back( y ); + _xyz.push_back( z ); + } + + void AddSizeAtNode( double size ) + { + _nodeSize.push_back( size ); + } + + void AddEdgeNodes( int node1, int node2, int /*domain*/ ) + { + _edgeNodes.push_back( node1 ); + _edgeNodes.push_back( node2 ); + } + + void AddTriaNodes( int node1, int node2, int node3, int /*domain*/ ) + { + _triaNodes.push_back( node1 ); + _triaNodes.push_back( node2 ); + _triaNodes.push_back( node3 ); + } + + int NbNodes() + { + return _xyz.size() / 3; + } + + double* NodeCoord( int iNode ) + { + return & _xyz[ iNode * 3 ]; + } + + int NbEdges() + { + return _edgeNodes.size() / 2; + } + + int* GetEdgeNodes( int iEdge ) + { + return & _edgeNodes[ iEdge * 2 ]; + } + + int NbTriangles() + { + return _triaNodes.size() / 3; + } + + int * GetTriaNodes( int iTria ) + { + return & _triaNodes[ iTria * 3 ]; + } + + int IsVertexRequired( int iNode ) + { + return ! ( iNode < int( NbNodes() - _nodeSize.size() )); + } + + double GetSizeAtVertex( int iNode ) + { + return IsVertexRequired( iNode ) ? _nodeSize[ iNode - NbNodes() + _nodeSize.size() ] : 0.; + } +}; + +namespace // functions called by MG library to exchange with the application +{ + status_t get_vertex_count(integer * nbvtx, void *user_data) + { + MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + *nbvtx = data->NbNodes(); + + return STATUS_OK; + } + + status_t get_vertex_coordinates(integer ivtx, real * xyz, void *user_data) + { + MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + double* coord = data->NodeCoord( ivtx-1 ); + for (int j = 0; j < 3; j++) + xyz[j] = coord[j]; + + return STATUS_OK; + } + status_t get_edge_count(integer * nbedge, void *user_data) + { + MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + *nbedge = data->NbEdges(); + + return STATUS_OK; + } + + status_t get_edge_vertices(integer iedge, integer * vedge, void *user_data) + { + MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + int* nodes = data->GetEdgeNodes( iedge-1 ); + vedge[0] = nodes[0]; + vedge[1] = nodes[1]; + + return STATUS_OK; + } + + status_t get_triangle_count(integer * nbtri, void *user_data) + { + MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + *nbtri = data->NbTriangles(); + + return STATUS_OK; + } + + status_t get_triangle_vertices(integer itri, integer * vtri, void *user_data) + { + MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + int* nodes = data->GetTriaNodes( itri-1 ); + vtri[0] = nodes[0]; + vtri[1] = nodes[1]; + vtri[2] = nodes[2]; + + return STATUS_OK; + } + + // status_t get_triangle_extra_vertices(integer itri, integer * typetri, + // integer * evtri, void *user_data) + // { + // int j; + // MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + + // if (1) { + // /* We want to describe a linear "3 nodes" triangle */ + // *typetri = MESHGEMS_MESH_ELEMENT_TYPE_TRIA3; + // } else { + // /* We want to describe a quadratic "6 nodes" triangle */ + // *typetri = MESHGEMS_MESH_ELEMENT_TYPE_TRIA6; + // for (j = 0; j < 3; j++) + // evtri[j] = 0; /* the j'th quadratic vertex index of the itri'th triangle */ + // } + + // return STATUS_OK; + // } + + // status_t get_tetrahedron_count(integer * nbtetra, void *user_data) + // { + // MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + + // *nbtetra = 0; /* the number of tetra in your input mesh (0 if you describe a surface mesh) */ + + // return STATUS_OK; + // } + + // status_t get_tetrahedron_vertices(integer itetra, integer * vtetra, + // void *user_data) + // { + // int j; + // MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + + // for (j = 0; j < 4; j++) + // vtetra[j] = 0; /* the j'th vertex index of the itetra'th tetrahedron */ + + // return STATUS_OK; + // } + + status_t get_vertex_required_property(integer ivtx, integer * rvtx, void *user_data) + { + MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + *rvtx = data->IsVertexRequired( ivtx - 1 ); + + return STATUS_OK; + } + + // status_t get_vertex_weight(integer ivtx, real * wvtx, void *user_data) + // { + // MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + // *wvtx = data->GetSizeAtVertex( ivtx - 1 ); + + // return STATUS_OK; + // } + + status_t my_message_cb(message_t * msg, void *user_data) + { + char *desc; + message_get_description(msg, &desc); + + MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + data->AddError( desc ); + +#ifdef _DEBUG_ + //std::cout << desc << std::endl; +#endif + + return STATUS_OK; + } + + status_t my_interrupt_callback(integer *interrupt_status, void *user_data) + { + MG_TetraHPC_API::LibData* data = (MG_TetraHPC_API::LibData *) user_data; + *interrupt_status = ( data->Cancelled() ? INTERRUPT_STOP : INTERRUPT_CONTINUE ); + + //std::cout << "INTERRUPT_STOP" << std::endl; + + + return STATUS_OK; + } + +} // end namespace + + +void MG_TetraHPC_API::LibData::Init() +{ + status_t ret; + + // Create the meshgems working context + _context = context_new(); + if ( !_context ) MG_Error( "unable to create a new context" ); + + // Set the message callback for the _context. + ret = context_set_message_callback( _context, my_message_cb, this ); + if ( ret != STATUS_OK ) MG_Error("in context_set_message_callback"); + + // Create the structure holding the callbacks giving access to triangle mesh + _tria_mesh = mesh_new( _context ); + if ( !_tria_mesh ) MG_Error("unable to create a new mesh"); + + // Set callbacks to provide triangle mesh data + mesh_set_get_vertex_count( _tria_mesh, get_vertex_count, this ); + mesh_set_get_vertex_coordinates( _tria_mesh, get_vertex_coordinates, this ); + mesh_set_get_vertex_required_property( _tria_mesh, get_vertex_required_property, this ); + mesh_set_get_edge_count( _tria_mesh, get_edge_count, this); + mesh_set_get_edge_vertices( _tria_mesh, get_edge_vertices, this ); + mesh_set_get_triangle_count( _tria_mesh, get_triangle_count, this ); + mesh_set_get_triangle_vertices( _tria_mesh, get_triangle_vertices, this ); + + // Create a tetra session + _session = tetra_hpc_session_new( _context ); + if ( !_session ) MG_Error( "unable to create a new tetra_hpc session"); + + ret = tetra_hpc_set_interrupt_callback( _session, my_interrupt_callback, this ); + if ( ret != STATUS_OK ) MG_Error("in tetra_set_interrupt_callback"); + +} + +bool MG_TetraHPC_API::LibData::Compute( const std::string& outFile ) +{ + // MG license + std::string errorTxt; + if ( !SMESHUtils_MGLicenseKeyGen::SignMesh( _tria_mesh, errorTxt )) + { + AddError( SMESH_Comment( "Problem with library SalomeMeshGemsKeyGenerator: ") << errorTxt ); + return false; + } + + // Set surface mesh + status_t ret = tetra_hpc_set_input_mesh( _session, _tria_mesh ); + if ( ret != STATUS_OK ) MG_Error( "unable to set surface mesh"); + + // // Set a sizemap + // if ( !_nodeSize.empty() ) + // { + // _sizemap = meshgems_sizemap_new( _tria_mesh, meshgems_sizemap_type_iso_mesh_vertex, + // (void*) &get_vertex_weight, this ); + // if ( !_sizemap ) MG_Error("unable to create a new sizemap"); + + // ret = tetra_hpc_set_sizemap( _session, _sizemap ); + // if ( ret != STATUS_OK ) MG_Error( "unable to set sizemap"); + // } + + ////////////////////////////////////////////////////////////////////////////////////////// + // const char* file = "/tmp/ghs3d_IN.mesh"; + // mesh_write_mesh( _tria_mesh,file); + // std::cout << std::endl << std::endl << "Write " << file << std::endl << std::endl << std::endl; + + ret = tetra_hpc_mesh( _session ); + if ( ret != STATUS_OK ) return false; + + ret = tetra_hpc_get_mesh( _session, &_tetra_mesh); + if (ret != STATUS_OK) MG_Error( "unable to get resulting mesh"); + + mesh_write_mesh( _tetra_mesh, outFile.c_str() ); + + return true; +} + +#else // ifdef USE_MG_LIBS + +struct MG_TetraHPC_API::LibData // to avoid compiler warnings +{ + volatile bool& _cancelled_flag; + double& _progress; + LibData(volatile bool& cancelled_flag, double& progress) + : _cancelled_flag{cancelled_flag}, _progress{progress} + {} +}; + +#endif // ifdef USE_MG_LIBS + + +//================================================================================ +/*! + * \brief Constructor + */ +//================================================================================ + +MG_TetraHPC_API::MG_TetraHPC_API(volatile bool& cancelled_flag, double& progress): + _nbNodes(0), _nbEdges(0), _nbFaces(0), _nbVolumes(0) +{ + _useLib = false; + _libData = new LibData( cancelled_flag, progress ); +#ifdef USE_MG_LIBS + _useLib = true; + _libData->Init(); + if ( getenv("MG_TetraHPC_USE_EXE")) + _useLib = false; +#endif +} + +//================================================================================ +/*! + * \brief Destructor + */ +//================================================================================ + +MG_TetraHPC_API::~MG_TetraHPC_API() +{ +#ifdef USE_MG_LIBS + delete _libData; + _libData = 0; +#endif + std::set::iterator id = _openFiles.begin(); + for ( ; id != _openFiles.end(); ++id ) + ::GmfCloseMesh( *id ); + _openFiles.clear(); +} + +//================================================================================ +/*! + * \brief Return the way of MG usage + */ +//================================================================================ + +bool MG_TetraHPC_API::IsLibrary() +{ + return _useLib; +} + +//================================================================================ +/*! + * \brief Switch to usage of MG-Tetra executable + */ +//================================================================================ + +void MG_TetraHPC_API::SetUseExecutable() +{ + _useLib = false; +} + +//================================================================================ +/*! + * \brief Compute the tetra mesh + * \param [in] cmdLine - a command to run mg_tetra.exe + * \return bool - Ok or not + */ +//================================================================================ + +bool MG_TetraHPC_API::Compute( const std::string& cmdLine, std::string& errStr ) +{ + std::cout << "Command line from MG_Tetra-HPC: " << cmdLine << "\n"; + if ( _useLib ) { +#ifdef USE_MG_LIBS + + // split cmdLine + std::istringstream strm( cmdLine ); + std::istream_iterator sIt( strm ), sEnd; + std::vector< std::string > args( sIt, sEnd ); + + std::string outFile; + + // set parameters + std::string arg, param, value; + for ( size_t i = 1; i < args.size(); ++i ) + { + // look for a param name; it starts from "-" + arg = args[i]; + if ( arg.size() < 2 || arg[0] != '-') + continue; + while ( arg[0] == '-') + arg = arg.substr( 1 ); + + size_t eqPos = arg.find('='); + if ( eqPos != std::string::npos ) + { + param = arg.substr( 0, eqPos ); + value = arg.substr( eqPos+1 ); + } + else + { + param = arg; + value = ""; + } + if ( param == "out" ) + { + outFile = value; + continue; + } + while ( i+1 < args.size() && args[i+1][0] != '-' ) + { + if ( !value.empty() ) value += " "; + value += args[++i]; + } + if ( !_libData->SetParam( param, value )) + std::cout << "Warning: wrong param: '" << param <<"' = '" << value << "'" << std::endl; + } + + // compute + bool ok = _libData->Compute( outFile ); + + GetLog(); // write a log file + _logFile = ""; // not to write it again + + return ok; +#endif + } + + // add MG license key + { + std::string errorTxt, meshIn; + std::string key = SMESHUtils_MGLicenseKeyGen::GetKey( meshIn, + _nbNodes, _nbEdges, _nbFaces, _nbVolumes, + errorTxt ); + if ( key.empty() ) + { + errStr = "Problem with library SalomeMeshGemsKeyGenerator: " + errorTxt; + return false; + } + + const_cast< std::string& >( cmdLine ) += " --key " + key; + } + + std::cout << "Launching: " << cmdLine << std::endl; + + int err = system( cmdLine.c_str() ); // run + + if ( err ) + { + errStr = SMESH_Comment("system command failed with error: ") + << strerror( errno ); + return false; + } + return true; + +} + +//================================================================================ +/*! + * \brief Prepare for reading a mesh data + */ +//================================================================================ + +int MG_TetraHPC_API::GmfOpenMesh(const char* theFile, int rdOrWr, int * ver, int * dim) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + return 1; +#endif + } + int id = ::GmfOpenMesh(theFile, rdOrWr, ver, dim ); + _openFiles.insert( id ); + return id; +} + +//================================================================================ +/*! + * \brief Return nb of entities + */ +//================================================================================ + +int MG_TetraHPC_API::GmfStatKwd( int iMesh, GmfKwdCod what ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + switch ( what ) + { + case GmfSubDomainFromGeom: return _libData->ReadNbSubDomains(); + case GmfVertices: return _libData->ReadNbNodes(); + case GmfEdges: return _libData->ReadNbEdges(); + case GmfTriangles: return _libData->ReadNbTria(); + case GmfQuadrilaterals: return _libData->ReadNbQuads(); + case GmfTetrahedra: return _libData->ReadNbTetra(); + case GmfHexahedra: return _libData->ReadNbHexa(); + default: return 0; + } + return 0; +#endif + } + return ::GmfStatKwd( iMesh, what ); +} + +//================================================================================ +/*! + * \brief Prepare for reading some data + */ +//================================================================================ + +void MG_TetraHPC_API::GmfGotoKwd( int iMesh, GmfKwdCod what ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + _libData->ResetCounter(); + return; +#endif + } + ::GmfGotoKwd( iMesh, what ); +} + +//================================================================================ +/*! + * \brief Return index of a domain identified by a triangle normal + * \param [in] iMesh - mesh file index + * \param [in] what - must be GmfSubDomainFromGeom + * \param [out] nbNodes - nb nodes in a face + * \param [out] faceInd - face index + * \param [out] ori - face orientation + * \param [out] domain - domain index + * \param [in] dummy - an artificial param used to discriminate from GmfGetLin() reading + * a triangle + */ +//================================================================================ + +void MG_TetraHPC_API::GmfGetLin( int iMesh, GmfKwdCod what, int* nbNodes, int* faceInd, int* ori, int* domain, int /*dummy*/ ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + _libData->ReadSubDomain( nbNodes, faceInd, ori, domain ); + return; +#endif + } + ::GmfGetLin( iMesh, what, nbNodes, faceInd, ori, domain ); +} + +//================================================================================ +/*! + * \brief Return coordinates of a next node + */ +//================================================================================ + +void MG_TetraHPC_API::GmfGetLin(int iMesh, GmfKwdCod what, + double* x, double* y, double *z, int* domain ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + _libData->ReadNodeXYZ( x, y, z, domain ); + return; +#endif + } + ::GmfGetLin(iMesh, what, x, y, z, domain ); +} + +//================================================================================ +/*! + * \brief Return coordinates of a next node + */ +//================================================================================ + +void MG_TetraHPC_API::GmfGetLin(int iMesh, GmfKwdCod what, + float* x, float* y, float *z, int* domain ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + double X,Y,Z; + _libData->ReadNodeXYZ( &X, &Y, &Z, domain ); + *x = X; + *y = Y; + *z = Z; + return; +#endif + } + ::GmfGetLin(iMesh, what, x, y, z, domain ); +} + +//================================================================================ +/*! + * \brief Return node index of a next corner + */ +//================================================================================ + +void MG_TetraHPC_API::GmfGetLin(int iMesh, GmfKwdCod what, int* node ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + node = 0; + return; +#endif + } + ::GmfGetLin(iMesh, what, node ); +} + +//================================================================================ +/*! + * \brief Return node indices of a next edge + */ +//================================================================================ + +void MG_TetraHPC_API::GmfGetLin(int iMesh, GmfKwdCod what, int* node1, int* node2, int* domain ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + _libData->ReadEdgeNodes( node1, node2, domain ); + return; +#endif + } + ::GmfGetLin( iMesh, what, node1, node2, domain ); +} + +//================================================================================ +/*! + * \brief Return node indices of a next triangle + */ +//================================================================================ + +void MG_TetraHPC_API::GmfGetLin(int iMesh, GmfKwdCod what, + int* node1, int* node2, int* node3, int* domain ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + _libData->ReadTriaNodes( node1, node2, node3, domain ); + return; +#endif + } + ::GmfGetLin(iMesh, what, node1, node2, node3, domain ); +} + +//================================================================================ +/*! + * \brief Return node indices of a next tetrahedron or quadrangle + */ +//================================================================================ + +void MG_TetraHPC_API::GmfGetLin(int iMesh, GmfKwdCod what, + int* node1, int* node2, int* node3, int* node4, int* domain ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + if ( what == GmfQuadrilaterals ) + _libData->ReadQuadNodes( node1, node2, node3, node4, domain ); + else + _libData->ReadTetraNodes( node1, node2, node3, node4, domain ); + return; +#endif + } + ::GmfGetLin(iMesh, what, node1, node2, node3, node4, domain ); +} + +//================================================================================ +/*! + * \brief Return node indices of a next hexahedron + */ +//================================================================================ + +void MG_TetraHPC_API::GmfGetLin(int iMesh, GmfKwdCod what, + int* node1, int* node2, int* node3, int* node4, + int* node5, int* node6, int* node7, int* node8, + int* domain ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + _libData->ReadHexaNodes( node1, node2, node3, node4, + node5, node6, node7, node8, domain ); + return; +#endif + } + ::GmfGetLin(iMesh, what, node1, node2, node3, node4, node5, node6, node7, node8, domain ); +} + +//================================================================================ +/*! + * \brief Prepare for passing data to MeshGems + */ +//================================================================================ + +int MG_TetraHPC_API::GmfOpenMesh(const char* theFile, int rdOrWr, int ver, int dim) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + return 1; +#endif + } + int id = ::GmfOpenMesh(theFile, rdOrWr, ver, dim); + _openFiles.insert( id ); + return id; +} + +//================================================================================ +/*! + * \brief Set number of entities + */ +//================================================================================ + +void MG_TetraHPC_API::GmfSetKwd(int iMesh, GmfKwdCod what, int nb ) +{ + if ( iMesh == 1 ) + { + switch ( what ) { + case GmfVertices: _nbNodes = nb; break; + case GmfEdges: _nbEdges = nb; break; + case GmfTriangles: _nbFaces = nb; break; + default:; + } + } + + if ( _useLib ) { +#ifdef USE_MG_LIBS + switch ( what ) { + case GmfVertices: _libData->SetNbVertices( nb ); break; + case GmfEdges: _libData->SetNbEdges ( nb ); break; + case GmfRequiredEdges: _libData->SetNbReqEdges( nb ); break; + case GmfTriangles: _libData->SetNbTria ( nb ); break; + case GmfRequiredTriangles: _libData->SetNbReqTria ( nb ); break; + default:; + } + return; +#endif + } + ::GmfSetKwd(iMesh, what, nb ); +} + +//================================================================================ +/*! + * \brief Add coordinates of a node + */ +//================================================================================ + +void MG_TetraHPC_API::GmfSetLin(int iMesh, GmfKwdCod what, double x, double y, double z, int domain) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + _libData->AddNode( x, y, z, domain ); + return; +#endif + } + ::GmfSetLin(iMesh, what, x, y, z, domain); +} + +//================================================================================ +/*! + * \brief Set number of field entities + * \param [in] iMesh - solution file index + * \param [in] what - solution type + * \param [in] nbNodes - nb of entities + * \param [in] nbTypes - nb of data entries in each entity + * \param [in] type - types of the data entries + * + * Used to prepare to storing size at nodes + */ +//================================================================================ + +void MG_TetraHPC_API::GmfSetKwd(int iMesh, GmfKwdCod what, int nbNodes, int dummy, int type[] ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + if ( what == GmfSolAtVertices ) _libData->SetNbReqVertices( nbNodes ); + return; +#endif + } + ::GmfSetKwd(iMesh, what, nbNodes, dummy, type ); +} + +//================================================================================ +/*! + * \brief Add solution data + */ +//================================================================================ + +void MG_TetraHPC_API::GmfSetLin(int iMesh, GmfKwdCod what, double vals[]) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + _libData->AddSizeAtNode( vals[0] ); + return; +#endif + } + ::GmfSetLin(iMesh, what, vals); +} + +//================================================================================ +/*! + * \brief Add edge nodes + */ +//================================================================================ + +void MG_TetraHPC_API::GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int domain ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + _libData->AddEdgeNodes( node1, node2, domain ); + return; +#endif + } + ::GmfSetLin(iMesh, what, node1, node2, domain ); +} + +//================================================================================ +/*! + * \brief Add a 'required' flag + */ +//================================================================================ + +void MG_TetraHPC_API::GmfSetLin(int iMesh, GmfKwdCod what, int id ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + return; +#endif + } + ::GmfSetLin(iMesh, what, id ); +} + +//================================================================================ +/*! + * \brief Add triangle nodes + */ +//================================================================================ + +void MG_TetraHPC_API::GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int node3, int domain ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + _libData->AddTriaNodes( node1, node2, node3, domain ); + return; +#endif + } + ::GmfSetLin(iMesh, what, node1, node2, node3, domain ); +} + +//================================================================================ +/*! + * \brief Close a file + */ +//================================================================================ + +void MG_TetraHPC_API::GmfCloseMesh( int iMesh ) +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + return; +#endif + } + ::GmfCloseMesh( iMesh ); + _openFiles.erase( iMesh ); +} + +//================================================================================ +/*! + * \brief Return true if the log is not empty + */ +//================================================================================ + +bool MG_TetraHPC_API::HasLog() +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + return !_libData->GetErrors().empty(); +#endif + } + SMESH_File file( _logFile ); + return file.size() > 0; +} + +//================================================================================ +/*! + * \brief Return log contents + */ +//================================================================================ + +std::string MG_TetraHPC_API::GetLog() +{ + if ( _useLib ) { +#ifdef USE_MG_LIBS + const std::string& err = _libData->GetErrors(); + if ( !_logFile.empty() && !err.empty() ) + { + SMESH_File file( _logFile, /*openForReading=*/false ); + file.openForWriting(); + file.write( err.c_str(), err.size() ); + } + return err; +#endif + } + std::cout << "_logFile: " << _logFile << std::endl; + + SMESH_File file( _logFile ); + if (file.exists() && file.size() > 0) + return file.getPos(); + else + return ""; +} diff --git a/src/GHS3DPlugin/MG_TetraHPC_API.hxx b/src/GHS3DPlugin/MG_TetraHPC_API.hxx new file mode 100644 index 0000000..34fe868 --- /dev/null +++ b/src/GHS3DPlugin/MG_TetraHPC_API.hxx @@ -0,0 +1,91 @@ +// Copyright (C) 2004-2022 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef __MG_TetraHPC_IO_HXX__ +#define __MG_TetraHPC_IO_HXX__ + +#include "MG_Tetra_API.hxx" + +#include +#include + +/*! + * \brief Class providing a transparent switch between MG_TetraHPC usage as + * a library and as an executable. API of libmesh5 inherited. + */ +class MG_TetraHPC_API +{ +public: + + MG_TetraHPC_API( volatile bool& cancelled_flag, double& progress ); + ~MG_TetraHPC_API(); + + bool IsLibrary(); + bool IsExecutable() { return !IsLibrary(); } + void SetUseExecutable(); + + // IN to MESHGEMS + int GmfOpenMesh(const char* theFile, int rdOrWr, int ver, int dim); + void GmfSetKwd(int iMesh, GmfKwdCod what, int nb ); + void GmfSetLin(int iMesh, GmfKwdCod what, double x, double y, double z, int domain); + void GmfSetKwd(int iMesh, GmfKwdCod what, int nbNodes, int dummy, int type[] ); // sol type + void GmfSetLin(int iMesh, GmfKwdCod what, double vals[]); // sol + void GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int domain ); // edge + void GmfSetLin(int iMesh, GmfKwdCod what, int id ); // required + void GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int node3, int domain ); // tria + + bool Compute( const std::string& cmdLine, std::string& errStr ); + + // OUT from MESHGEMS + int GmfOpenMesh(const char* theFile, int rdOrWr, int * ver, int * dim); + int GmfStatKwd( int iMesh, GmfKwdCod what ); + void GmfGotoKwd( int iMesh, GmfKwdCod what ); + void GmfGetLin( int iMesh, GmfKwdCod what, int* nbNodes, int* faceInd, int* ori, int* domain, int dummy ); + void GmfGetLin(int iMesh, GmfKwdCod what, float* x, float* y, float *z, int* domain ); + void GmfGetLin(int iMesh, GmfKwdCod what, double* x, double* y, double *z, int* domain ); + void GmfGetLin(int iMesh, GmfKwdCod what, int* node ); + void GmfGetLin(int iMesh, GmfKwdCod what, int* node1, int* node2, int* domain ); + void GmfGetLin(int iMesh, GmfKwdCod what, int* node1, int* node2, int* node3, int* domain ); + void GmfGetLin(int iMesh, GmfKwdCod what, int* node1, int* node2, int* node3, int* node4, int* domain ); + void GmfGetLin(int iMesh, GmfKwdCod what, int* node1, int* node2, int* node3, int* node4, int* node5, int* node6, int* node7, int* node8, int* domain ); + void GmfCloseMesh( int iMesh ); + + void SetLogFile( const std::string& logFileName ) { _logFile = logFileName; } + bool HasLog(); + std::string GetLog(); + + + struct LibData; + +private: + + bool _useLib; + LibData* _libData; + std::set _openFiles; + std::string _logFile; + + + // count mesh entities for MG license key generation + int _nbNodes; + int _nbEdges; + int _nbFaces; + int _nbVolumes; +}; + +#endif diff --git a/src/GUI/GHS3DPluginGUI_AdvWidget.cxx b/src/GUI/GHS3DPluginGUI_AdvWidget.cxx index b2dc3a1..e70781f 100644 --- a/src/GUI/GHS3DPluginGUI_AdvWidget.cxx +++ b/src/GUI/GHS3DPluginGUI_AdvWidget.cxx @@ -135,3 +135,23 @@ void GHS3DPluginGUI_AdvWidget::itemChanged(QTreeWidgetItem * tblRow, int column) myOptionTable->blockSignals( false ); } } + +void GHS3DPluginGUI_AdvWidget::EnableAdvancedOptions( bool isMGTetra ) +{ + int iRow = 0, nbRows = myOptionTable->topLevelItemCount(); + // hard coded: register all possible options here + std::vector_commonOptions = { "split_overconstrained_tetrahedra" }; + std::vector::iterator tk; + for ( ; iRow < nbRows; ++iRow ) + { + // Have to allow advanced option for MGTetra HPC to work + tk = std::find( _commonOptions.begin(), + _commonOptions.end(), + myOptionTable->topLevelItem( iRow )->data( NAME_COL, PARAM_NAME ).toString().toStdString() + ); + + if ( tk == _commonOptions.end() ) + myOptionTable->topLevelItem( iRow )->setDisabled( !isMGTetra ); + + } +} \ No newline at end of file diff --git a/src/GUI/GHS3DPluginGUI_Dlg.h b/src/GUI/GHS3DPluginGUI_Dlg.h index 7fb6d65..8bb619c 100644 --- a/src/GUI/GHS3DPluginGUI_Dlg.h +++ b/src/GUI/GHS3DPluginGUI_Dlg.h @@ -49,7 +49,7 @@ public: void AddOption( const char* name_value_type, bool isCustom = false ); void GetOptionAndValue( QTreeWidgetItem * tblRow, QString& option, QString& value, bool& dflt ); - + void EnableAdvancedOptions( bool isMGTetra ); public slots: void itemChanged(QTreeWidgetItem * tblRow, int column); diff --git a/src/GUI/GHS3DPluginGUI_HypothesisCreator.cxx b/src/GUI/GHS3DPluginGUI_HypothesisCreator.cxx index bbdf366..6b477bf 100644 --- a/src/GUI/GHS3DPluginGUI_HypothesisCreator.cxx +++ b/src/GUI/GHS3DPluginGUI_HypothesisCreator.cxx @@ -49,6 +49,7 @@ #include #include +#include #include #include #include @@ -58,7 +59,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -301,10 +304,12 @@ GHS3DPluginGUI_HypothesisCreator::GHS3DPluginGUI_HypothesisCreator( const QStrin myOptimizationLevelCombo(0), myMinSizeCheck(0), myMaxSizeCheck(0), + myNumOfThreadsCheck(0), myMinSizeSpin(0), myMaxSizeSpin(0), myGradationCheck(0), myGradationSpin(0), + myNumOfThreadsSpin(0), myUseProximityGroup(0), myNbProximityLayers(0), myToMakeGroupsOfDomains(0), @@ -314,7 +319,9 @@ GHS3DPluginGUI_HypothesisCreator::GHS3DPluginGUI_HypothesisCreator( const QStrin myPThreadsModeCombo(0), myNumberOfThreadsSpin(0), mySmoothOffSliversCheck(0), - myCreateNewNodesCheck(0) + myCreateNewNodesCheck(0), + myPthreadMode(0), + myParallelMode(0) { GeomToolSelected = NULL; GeomToolSelected = getGeomSelectionTool(); @@ -354,6 +361,67 @@ bool GHS3DPluginGUI_HypothesisCreator::isOptimization() const return ( hypType() == GHS3DPlugin_OptimizerHypothesis::GetHypType() ); } +void GHS3DPluginGUI_HypothesisCreator::onRadioButtomSelect() +{ + onNumOfThreadsCheck(); + + // Disable selection of standart+ + QStandardItemModel * model = qobject_cast(myOptimizationLevelCombo->model()); + if(!model) return; + QStandardItem * item = model->item( GHS3DPlugin_Hypothesis::StandardPlus ); + if(!item) return; + + if ( myRadioBottomGroup->checkedId() == GHS3DPlugin_Hypothesis::MGTetra ) + { + // Enable selection of stadart+ + item->setEnabled(true); + // Set possibility to check memory options again. + myAdvWidget->maxMemoryCheck ->setEnabled( true ); + myAdvWidget->initialMemoryCheck ->setEnabled( true ); + + myAdvWidget->EnableAdvancedOptions( true ); + + } + else if ( myRadioBottomGroup->checkedId() == GHS3DPlugin_Hypothesis::MGTetraHPC ) + { + // Disable selection of stadart+ + item->setEnabled(false); + // Set to false memory checks and disable checkbox + myAdvWidget->maxMemoryCheck ->setChecked( false ); + myAdvWidget->initialMemoryCheck ->setChecked( false ); + myAdvWidget->maxMemoryCheck ->setEnabled( false ); + myAdvWidget->initialMemoryCheck ->setEnabled( false ); + myAdvWidget->EnableAdvancedOptions( false ); + } + +} + +void GHS3DPluginGUI_HypothesisCreator::onNumOfThreadsCheck() +{ + if ( myRadioBottomGroup->checkedId() == GHS3DPlugin_Hypothesis::MGTetra ) + { + if ( myNumOfThreadsCheck->isChecked() ) + myPthreadMode->setEnabled( true ); + else + myPthreadMode->setEnabled( false ); + + myParallelMode->setEnabled( false ); + } + else if ( myRadioBottomGroup->checkedId() == GHS3DPlugin_Hypothesis::MGTetraHPC ) + { + if ( myNumOfThreadsCheck->isChecked() ) + myParallelMode->setEnabled( true ); + else + myParallelMode->setEnabled( false ); + + myPthreadMode->setEnabled( false ); + } + else + { + + } +} + QFrame* GHS3DPluginGUI_HypothesisCreator::buildFrame() { QFrame* fr = new QFrame( 0 ); @@ -419,26 +487,64 @@ QFrame* GHS3DPluginGUI_HypothesisCreator::buildFrame() } else { + // Algorithm selection + QGroupBox* radioBottomGroup = new QGroupBox( tr("GHS3D_ALGO_SELECTION"), myStdGroup ); + myRadioBottomGroup = new QButtonGroup( radioBottomGroup ); + + QRadioButton * GM_MSH = new QRadioButton(tr("GHS3D_ALGO_MGTETRA"), radioBottomGroup ); + QRadioButton * GM_MSH_HPC = new QRadioButton(tr("GHS3D_ALGO_MGTETRAHPC"), radioBottomGroup ); + + myRadioBottomGroup->addButton( GM_MSH, 1 ); + myRadioBottomGroup->addButton( GM_MSH_HPC, 0 ); + GM_MSH->setChecked( true ); + + QGridLayout* radioBottomLayout = new QGridLayout( radioBottomGroup ); + radioBottomLayout->setSpacing( 4 ); + radioBottomLayout->setMargin( 11 ); + radioBottomLayout->addWidget( GM_MSH, 0, 0, 1, 1 ); + radioBottomLayout->addWidget( GM_MSH_HPC, 0, 1, 1, 1 ); + // Main parameters + QGroupBox* mainGroup = new QGroupBox( tr("GHS3D_MAIN_PARAMS"), myStdGroup ); + QLabel* optimizatiolLevelLbl = new QLabel( tr( "GHS3D_OPTIMIZATIOL_LEVEL" ), mainGroup ); + QLabel* pthreadModeLbl = new QLabel( tr( "GHS3D_PTHREAD_MODE" ), mainGroup ); + QLabel* parallelStrat = new QLabel( tr( "GHS3D_PARALLE_STRAT" ), mainGroup ); + + myOptimizationLevelCombo = new QComboBox( mainGroup ); + myMinSizeCheck = new QCheckBox( tr("GHS3D_MIN_SIZE"), mainGroup ); + myMaxSizeCheck = new QCheckBox( tr("GHS3D_MAX_SIZE"), mainGroup ); + myNumOfThreadsCheck = new QCheckBox( tr("GHS3D_THREADS_SIZE"), mainGroup ); + myPthreadMode = new QComboBox( mainGroup ); + myParallelMode = new QComboBox( mainGroup ); + + myMinSizeSpin = new SMESHGUI_SpinBox( mainGroup ); + myMaxSizeSpin = new SMESHGUI_SpinBox( mainGroup ); + myNumOfThreadsSpin = new SalomeApp_IntSpinBox( 1, 128, 1, mainGroup ); - QGroupBox* mainGroup = new QGroupBox( tr("GHS3D_MAIN_PARAMS"), myStdGroup ); - QLabel* optimizatiolLevelLbl = new QLabel( tr( "GHS3D_OPTIMIZATIOL_LEVEL" ), mainGroup ); - myOptimizationLevelCombo = new QComboBox( mainGroup ); - myMinSizeCheck = new QCheckBox( tr("GHS3D_MIN_SIZE"), mainGroup ); - myMaxSizeCheck = new QCheckBox( tr("GHS3D_MAX_SIZE"), mainGroup ); - myMinSizeSpin = new SMESHGUI_SpinBox( mainGroup ); - myMaxSizeSpin = new SMESHGUI_SpinBox( mainGroup ); myMinSizeCheck->setChecked( false ); myMaxSizeCheck->setChecked( false ); + myNumOfThreadsCheck->setChecked( false ); + myMinSizeSpin->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); myMaxSizeSpin->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); - myMinSizeSpin->setEnabled( false ); - myMaxSizeSpin->setEnabled( false ); - connect( myMinSizeCheck, SIGNAL( toggled(bool)), myMinSizeSpin, SLOT( setEnabled(bool))); - connect( myMaxSizeCheck, SIGNAL( toggled(bool)), myMaxSizeSpin, SLOT( setEnabled(bool))); + myNumOfThreadsSpin->setValue( 4 ); + + myMinSizeSpin ->setEnabled( false ); + myMaxSizeSpin ->setEnabled( false ); + myNumOfThreadsSpin->setEnabled(false); + myPthreadMode ->setEnabled( false ); + myParallelMode->setEnabled( false ); + + // ACTIONS ON BUTTOMS + connect( myMinSizeCheck, SIGNAL( toggled(bool)), myMinSizeSpin, SLOT( setEnabled(bool))); + connect( myMaxSizeCheck, SIGNAL( toggled(bool)), myMaxSizeSpin, SLOT( setEnabled(bool))); + connect( myNumOfThreadsCheck, SIGNAL( toggled(bool)), myNumOfThreadsSpin, SLOT( setEnabled(bool))); + connect( myNumOfThreadsCheck, SIGNAL( toggled(bool)), this, SLOT( onNumOfThreadsCheck() )); + connect( myNumOfThreadsCheck, SIGNAL( toggled(bool)), this, SLOT( onNumOfThreadsCheck() )); + connect( GM_MSH, SIGNAL( toggled( bool )),this, SLOT( onRadioButtomSelect() )); QGridLayout* mainLayout = new QGridLayout( mainGroup ); - mainLayout->setSpacing( 6 ); + mainLayout->setSpacing( 12 ); mainLayout->setMargin( 11 ); mainLayout->addWidget( optimizatiolLevelLbl, 0, 0, 1, 1 ); mainLayout->addWidget( myOptimizationLevelCombo, 0, 1, 1, 1 ); @@ -446,7 +552,13 @@ QFrame* GHS3DPluginGUI_HypothesisCreator::buildFrame() mainLayout->addWidget( myMinSizeSpin, 1, 1, 1, 1 ); mainLayout->addWidget( myMaxSizeCheck, 2, 0, 1, 1 ); mainLayout->addWidget( myMaxSizeSpin, 2, 1, 1, 1 ); - + mainLayout->addWidget( myNumOfThreadsCheck, 3, 0, 1, 1 ); + mainLayout->addWidget( myNumOfThreadsSpin, 3, 1, 1, 1 ); + mainLayout->addWidget( pthreadModeLbl, 4, 0, 1, 1 ); + mainLayout->addWidget( myPthreadMode, 4, 1, 1, 1 ); + mainLayout->addWidget( parallelStrat, 5, 0, 1, 1 ); + mainLayout->addWidget( myParallelMode, 5, 1, 1, 1 ); + // Volume proximity QGroupBox* proxyGroup = new QGroupBox( tr("GHS3D_VOLUME_PROXIMITY"), myStdGroup ); @@ -484,10 +596,13 @@ QFrame* GHS3DPluginGUI_HypothesisCreator::buildFrame() otherLayout->addWidget( myToMeshHolesCheck, 0, 0 ); otherLayout->addWidget( myToMakeGroupsOfDomains, 1, 0 ); + aStdLayout->addWidget( radioBottomGroup,row++, 0, 1, 2 ); + aStdLayout->addWidget( mainGroup, row++, 0, 1, 2 ); + aStdLayout->addWidget( proxyGroup, row++, 0, 1, 2 ); + aStdLayout->addWidget( otherGroup, row++, 0, 1, 2 ); - aStdLayout->addWidget( mainGroup, row++, 0, 1, 2 ); - aStdLayout->addWidget( proxyGroup, row++, 0, 1, 2 ); - aStdLayout->addWidget( otherGroup, row++, 0, 1, 2 ); + myPthreadMode->addItems( QStringList() << tr( "MODE_NONE" ) << tr( "MODE_AGGRESSIVE" ) << tr( "MODE_SAFE" ) ); + myParallelMode->addItems( QStringList() << tr( "MODE_NONE" ) << tr( "MODE_REPRODUCIBLE_GIVEN_MAX_THREADS" ) << tr( "MODE_REPRODUCIBLE" ) << tr( "MODE_AGGRESSIVE" ) ); } aStdLayout->setRowStretch( row, 10 ); @@ -549,7 +664,7 @@ QFrame* GHS3DPluginGUI_HypothesisCreator::buildFrame() QGridLayout* anEnfLayout = new QGridLayout(myEnfGroup); myEnforcedTableWidget = new QTableWidget(myEnfGroup); - myEnforcedTableWidget ->setMinimumWidth(300); + myEnforcedTableWidget->setMinimumWidth(300); myEnforcedTableWidget->setRowCount( 0 ); myEnforcedTableWidget->setColumnCount( ENF_VER_NB_COLUMNS ); myEnforcedTableWidget->setSortingEnabled(true); @@ -1459,7 +1574,12 @@ void GHS3DPluginGUI_HypothesisCreator::retrieveParams() const } myToMeshHolesCheck ->setChecked ( data.myToMeshHoles ); myToMakeGroupsOfDomains ->setChecked ( data.myToMakeGroupsOfDomains ); - myOptimizationLevelCombo ->setCurrentIndex( data.myOptimizationLevel ); + + if ( data.myAlgorithm == GHS3DPlugin_Hypothesis::MGTetraHPC && data.myOptimizationLevel == GHS3DPlugin_Hypothesis::StandardPlus /*not implemented by MGTetraHPC*/ ) + myOptimizationLevelCombo ->setCurrentIndex( GHS3DPlugin_Hypothesis::None ); + else + myOptimizationLevelCombo ->setCurrentIndex( data.myOptimizationLevel ); + if ( myOptimizationCombo ) // optimizer { myOptimizationCombo ->setCurrentIndex( data.myOptimization ); @@ -1471,14 +1591,19 @@ void GHS3DPluginGUI_HypothesisCreator::retrieveParams() const } else { - myMinSizeSpin->setValue( data.myMinSize ); - myMinSizeCheck->setChecked( data.myUseMinSize ); - myMaxSizeSpin->setValue( data.myMaxSize ); - myMaxSizeCheck->setChecked( data.myUseMaxSize ); - myGradationCheck->setChecked( data.myUseGradation ); - myGradationSpin->setValue( data.myUseGradation ? data.myGradation : GHS3DPlugin_Hypothesis::DefaultGradation() ); - myUseProximityGroup->setChecked( data.myUseProximity ); - myNbProximityLayers->setValue( data.myNbProximityLayers ); + myRadioBottomGroup ->button( data.myAlgorithm )->setChecked( true ); + myMinSizeSpin ->setValue( data.myMinSize ); + myMinSizeCheck ->setChecked( data.myUseMinSize ); + myMaxSizeSpin ->setValue( data.myMaxSize ); + myMaxSizeCheck ->setChecked( data.myUseMaxSize ); + myGradationCheck ->setChecked( data.myUseGradation ); + myGradationSpin ->setValue( data.myUseGradation ? data.myGradation : GHS3DPlugin_Hypothesis::DefaultGradation() ); + myUseProximityGroup ->setChecked( data.myUseProximity ); + myNbProximityLayers ->setValue( data.myNbProximityLayers ); + myNumOfThreadsCheck ->setChecked( data.myUseNumOfThreads ); + myNumOfThreadsSpin ->setValue( data.myNumOfThreads ); + myPthreadMode ->setCurrentIndex( data.myPthreadMode ); + myParallelMode ->setCurrentIndex( data.myParallelMode ); } myAdvWidget->maxMemoryCheck ->setChecked ( data.myMaximumMemory > 0 ); myAdvWidget->maxMemorySpin ->setValue @@ -1501,7 +1626,7 @@ void GHS3DPluginGUI_HypothesisCreator::retrieveParams() const myAdvWidget->AddOption( that->myCustomOptions[i].in() ); } myAdvWidget->myOptionTable->resizeColumnToContents( OPTION_NAME_COLUMN ); - + myAdvWidget->EnableAdvancedOptions( data.myAlgorithm == GHS3DPlugin_Hypothesis::MGTetra ); TEnfVertexList::const_iterator it; int rowCount = 0; @@ -1703,6 +1828,7 @@ bool GHS3DPluginGUI_HypothesisCreator::readParamsFromHypo( GHS3DHypothesisData& h_data.myNumberOfThreads = 1; h_data.mySmoothOffSlivers = 1; } + h_data.myAlgorithm = h->GetAlgorithm(); h_data.myOptimizationLevel = h->GetOptimizationLevel(); h_data.myMinSize = h->GetMinSize(); h_data.myMaxSize = h->GetMaxSize(); @@ -1731,6 +1857,10 @@ bool GHS3DPluginGUI_HypothesisCreator::readParamsFromHypo( GHS3DHypothesisData& //h_data.myTextOption = h->GetAdvancedOption(); h_data.myLogInStandardOutput = h->GetStandardOutputLog(); h_data.myRemoveLogOnSuccess = h->GetRemoveLogOnSuccess(); + h_data.myUseNumOfThreads = h->GetUseNumOfThreads(); + h_data.myNumOfThreads = h->GetNumOfThreads(); + h_data.myPthreadMode = h->GetPthreadMode(); + h_data.myParallelMode = h->GetParallelMode(); GHS3DPluginGUI_HypothesisCreator* that = (GHS3DPluginGUI_HypothesisCreator*)this; that->myOptions = h->GetOptionValues(); @@ -1791,6 +1921,7 @@ bool GHS3DPluginGUI_HypothesisCreator::storeParamsToHypo( const GHS3DHypothesisD if( isCreation() ) SMESH::SetName( SMESH::FindSObject( h ), h_data.myName.toLatin1().constData() ); + h->SetAlgorithm ((CORBA::Short) h_data.myAlgorithm ); h->SetOptimizationLevel ((CORBA::Short) h_data.myOptimizationLevel ); h->SetMinSize ( h_data.myUseMinSize ? h_data.myMinSize : 0 ); h->SetMaxSize ( h_data.myUseMaxSize ? h_data.myMaxSize : 0 ); @@ -1812,6 +1943,10 @@ bool GHS3DPluginGUI_HypothesisCreator::storeParamsToHypo( const GHS3DHypothesisD //h->SetFEMCorrection ( h_data.myFEMCorrection ); h->SetStandardOutputLog ( h_data.myLogInStandardOutput ); h->SetRemoveLogOnSuccess ( h_data.myRemoveLogOnSuccess ); + h->SetUseNumOfThreads ( h_data.myUseNumOfThreads ); + h->SetNumOfThreads ( (CORBA::Short) h_data.myNumOfThreads ); + h->SetPthreadMode ( (CORBA::Short) h_data.myPthreadMode ); + h->SetParallelMode ( (CORBA::Short) h_data.myParallelMode ); if ( !opt->_is_nil() ) { @@ -1915,6 +2050,11 @@ bool GHS3DPluginGUI_HypothesisCreator::readParamsFromWidgets( GHS3DHypothesisDat h_data.myNbProximityLayers = myNbProximityLayers->value(); h_data.myToMeshHoles = myToMeshHolesCheck->isChecked(); h_data.myToMakeGroupsOfDomains = myToMakeGroupsOfDomains->isChecked(); + h_data.myAlgorithm = myRadioBottomGroup->checkedId(); + h_data.myUseNumOfThreads = myNumOfThreadsCheck->isChecked(); + h_data.myNumOfThreads = myNumOfThreadsSpin->value(); + h_data.myPthreadMode = myPthreadMode->currentIndex(); + h_data.myParallelMode = myParallelMode->currentIndex(); } h_data.myMaximumMemory = float( myAdvWidget->maxMemoryCheck->isChecked() ? myAdvWidget->maxMemorySpin->value() : -1 ); h_data.myInitialMemory = float( myAdvWidget->initialMemoryCheck->isChecked() ? myAdvWidget->initialMemorySpin->value() : -1 ); diff --git a/src/GUI/GHS3DPluginGUI_HypothesisCreator.h b/src/GUI/GHS3DPluginGUI_HypothesisCreator.h index 2212dc5..b7cb887 100644 --- a/src/GUI/GHS3DPluginGUI_HypothesisCreator.h +++ b/src/GUI/GHS3DPluginGUI_HypothesisCreator.h @@ -49,6 +49,7 @@ #include CORBA_SERVER_HEADER(SMESH_Mesh) class QWidget; +class QButtonGroup; class QComboBox; class QCheckBox; class QLineEdit; @@ -156,6 +157,8 @@ typedef struct short myVerboseLevel; TEnfVertexList myEnforcedVertices; TEnfMeshList myEnforcedMeshes; + short myAlgorithm, myNumOfThreads, myPthreadMode, myParallelMode; + bool myUseNumOfThreads; int myOptimization, mySplitOverConstrained, myPThreadsMode, myNumberOfThreads; bool mySmoothOffSlivers; @@ -208,6 +211,8 @@ protected slots: void onRemoveEnforcedMesh(); //void synchronizeEnforcedMesh(); void checkEnfMeshIsDefined(); + void onRadioButtomSelect(); + void onNumOfThreadsCheck(); signals: void vertexDefined(bool); @@ -230,6 +235,11 @@ private: QCheckBox* myMaxSizeCheck; SMESHGUI_SpinBox* myMinSizeSpin; SMESHGUI_SpinBox* myMaxSizeSpin; + QButtonGroup* myRadioBottomGroup; + QComboBox* myPthreadMode; + QComboBox* myParallelMode; + QCheckBox* myNumOfThreadsCheck; + SalomeApp_IntSpinBox* myNumOfThreadsSpin; mutable double myMinSizeDefault, myMaxSizeDefault; // proximity QCheckBox* myGradationCheck; diff --git a/src/GUI/GHS3DPlugin_msg_en.ts b/src/GUI/GHS3DPlugin_msg_en.ts index 5271493..d01899e 100644 --- a/src/GUI/GHS3DPlugin_msg_en.ts +++ b/src/GUI/GHS3DPlugin_msg_en.ts @@ -59,6 +59,50 @@ LEVEL_LIGHT Light + + GHS3D_PTHREAD_MODE + Pthread Mode + + + GHS3D_PARALLE_STRAT + Paralle Stategy (HPC) + + + MODE_NONE + None + + + MODE_AGGRESSIVE + Aggressive + + + MODE_SAFE + Safe + + + MODE_REPRODUCIBLE + Reproducible + + + MODE_REPRODUCIBLE_GIVEN_MAX_THREADS + Reproducible Given Max Number of Threads + + + GHS3D_ALGO_SELECTION + Algorithm selection + + + GHS3D_ALGO_MGTETRA + MG-Tetra + + + GHS3D_ALGO_MGTETRAHPC + MG-Tetra HPC + + + GHS3D_THREADS_SIZE + Maximal number of threads + LEVEL_MEDIUM Medium (standard)