-// Copyright (C) 2004-2020 CEA/DEN, EDF R&D
+// Copyright (C) 2004-2023 CEA, EDF
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
//
#include "GHS3DPlugin_Hypothesis.hxx"
+#include <Basics_DirUtils.hxx>
#include <SMESHDS_Mesh.hxx>
+#include <SMESH_File.hxx>
#include <TCollection_AsciiString.hxx>
myGradation(DefaultGradation()),
myUseVolumeProximity(DefaultUseVolumeProximity()),
myNbVolumeProximityLayers(DefaultNbVolumeProximityLayers()),
+ myAlgorithm(DefaultAlgorithm()),
+ myNumOfThreads(DefaultNumOfThreads()),
+ myUseNumOfThreads(DefaultUseNumOfThreads()),
+ myPthreadModeMG(DefaultMyPthreadMode()),
+ myPthreadModeMGHPC(DefaultMyPthreadModeHPC()),
myMinSize(0),
myMinSizeDefault(0),
myMaxSize(0),
"" // mark of end
};
const char* intOptionNames[] = { "max_number_of_errors_printed", // 1
- "max_number_of_threads", // 4
"" // mark of end
};
const char* doubleOptionNames[] = { "target_quality", // 0
"sliver_angle", // 5
"" // mark of end
};
- const char* charOptionNames[] = { "pthreads_mode", // ""
- "boundary_regeneration", // standard
+ const char* charOptionNames[] = { "boundary_regeneration", // standard
"split_overconstrained_tetrahedra", // no
"" // mark of end
};
_defaultOptionValues["rectify_jacobian" ] = "yes";
_defaultOptionValues["jacobian_rectification_respect_input_surface_mesh"] = "yes";
_defaultOptionValues["max_number_of_errors_printed" ] = "1";
- _defaultOptionValues["max_number_of_threads" ] = "4";
_defaultOptionValues["target_quality" ] = "";//NoValue();
_defaultOptionValues["sliver_angle" ] = "5";
- _defaultOptionValues["pthreads_mode" ] = "";//NoValue();
_defaultOptionValues["boundary_regeneration" ] = "standard";
_defaultOptionValues["split_overconstrained_tetrahedra" ] = "no";
}
//=======================================================================
-//function : GetToCreateNewNodes
+//function : SetAlgorithm
+//=======================================================================
+void GHS3DPlugin_Hypothesis::SetAlgorithm(ImplementedAlgorithms algoId)
+{
+ if ( myAlgorithm != algoId ) {
+ myAlgorithm = algoId;
+ NotifySubMeshesHypothesisModification();
+ }
+}
+
+//=======================================================================
+//function : short GetAlgorithm() const;
+
+//=======================================================================
+GHS3DPlugin_Hypothesis::ImplementedAlgorithms GHS3DPlugin_Hypothesis::GetAlgorithm() const
+{
+ return (ImplementedAlgorithms) myAlgorithm;
+}
+
+//=======================================================================
+//function : SetPthreadMode
+//=======================================================================
+void GHS3DPlugin_Hypothesis::SetPthreadMode(PThreadMode pThreadsMode )
+{
+ if ( myPthreadModeMG != pThreadsMode ) {
+ myPthreadModeMG = pThreadsMode;
+ NotifySubMeshesHypothesisModification();
+ }
+}
+
+//=======================================================================
+//function : short GetPthreadMode() const;
+
+//=======================================================================
+GHS3DPlugin_Hypothesis::PThreadMode GHS3DPlugin_Hypothesis::GetPthreadMode() const
+{
+ return (PThreadMode)myPthreadModeMG;
+}
+
+//=======================================================================
+//function : SetParallelMode
+//=======================================================================
+void GHS3DPlugin_Hypothesis::SetParallelMode(ParallelMode parallelMode )
+{
+ if ( myPthreadModeMGHPC != parallelMode ) {
+ myPthreadModeMGHPC = parallelMode;
+ NotifySubMeshesHypothesisModification();
+ }
+}
+
+//=======================================================================
+//function : short GetParallelMode() const;
+
+//=======================================================================
+GHS3DPlugin_Hypothesis::ParallelMode GHS3DPlugin_Hypothesis::GetParallelMode() const
+{
+ return (ParallelMode)myPthreadModeMGHPC;
+}
+
+//=======================================================================
+//function : SetUseNumOfThreads
+//=======================================================================
+void GHS3DPlugin_Hypothesis::SetUseNumOfThreads(bool setUseOfThreads)
+{
+ if ( myUseNumOfThreads != setUseOfThreads ) {
+ myUseNumOfThreads = setUseOfThreads;
+ NotifySubMeshesHypothesisModification();
+ }
+}
+
+//=======================================================================
+//function : bool GetUseNumOfThreads() const;
+
+//=======================================================================
+bool GHS3DPlugin_Hypothesis::GetUseNumOfThreads() const
+{
+ return myUseNumOfThreads;
+}
+
+//=======================================================================
+//function : SetNumOfThreads
//=======================================================================
+void GHS3DPlugin_Hypothesis::SetNumOfThreads(short numOfThreads)
+{
+ if ( myNumOfThreads != numOfThreads ) {
+ myNumOfThreads = numOfThreads;
+ NotifySubMeshesHypothesisModification();
+ }
+}
+//=======================================================================
+//function : short GetUseNumOfThreads() const;
+
+//=======================================================================
+short GHS3DPlugin_Hypothesis::GetNumOfThreads() const
+{
+ return myNumOfThreads;
+}
+
+//=======================================================================
+//function : GetToCreateNewNodes
+//=======================================================================
bool GHS3DPlugin_Hypothesis::GetToCreateNewNodes() const
{
return myToCreateNewNodes;
//=======================================================================
//function : SetEnforcedGroup
//=======================================================================
-bool GHS3DPlugin_Hypothesis::SetEnforcedGroup(const SMESHDS_Mesh* theMeshDS, SMESH::long_array_var theIDs, SMESH::ElementType elementType, std::string name, std::string entry, std::string groupName)
+bool GHS3DPlugin_Hypothesis::SetEnforcedGroup(const SMESHDS_Mesh* theMeshDS, SMESH::smIdType_array_var theIDs, SMESH::ElementType elementType, std::string name, std::string entry, std::string groupName)
{
MESSAGE("GHS3DPlugin_Hypothesis::SetEnforcedGroup");
TIDSortedElemSet theElemSet;
if ( theIDs->length() == 0 ){MESSAGE("The source group is empty");}
- for ( CORBA::ULong i=0; i < theIDs->length(); i++) {
- CORBA::Long ind = theIDs[i];
+ for ( CORBA::ULong i = 0; i < theIDs->length(); i++) {
+ SMESH::smIdType ind = theIDs[i];
if (elementType == SMESH::NODE)
{
const SMDS_MeshNode * node = theMeshDS->FindNode(ind);
statex.dwLength = sizeof (statex);
long err = GlobalMemoryStatusEx (&statex);
if (err != 0) {
- double totMB = (double)statex.ullAvailPhys / 1024. / 1024.;
- return (float)( 0.7 * totMB );
+ double totMB = double( statex.ullAvailPhys ) / 1024. / 1024.;
+ return float( 0.7 * totMB );
}
#elif !defined(__APPLE__)
struct sysinfo si;
long err = sysinfo( &si );
if ( err == 0 ) {
- long ramMB = si.totalram * si.mem_unit / 1024 / 1024;
- return ( 0.7 * ramMB );
+ double ramMB = double( si.totalram * si.mem_unit / 1024 / 1024 );
+ return float( 0.7 * ramMB );
}
#endif
return 1024;
for ( o2v = _customOption2value.begin(); o2v != _customOption2value.end(); ++o2v )
save << " -" << o2v->first << " -" << o2v->second;
+ // New options (issue #32737)
+ save << " " << myAlgorithm;
+ save << " " << myUseNumOfThreads;
+ save << " " << myNumOfThreads;
+ save << " " << myPthreadModeMG;
+ save << " " << myPthreadModeMGHPC;
+
return save;
}
isOK = static_cast<bool>(load >> d);
if (isOK)
- myMaximumMemory = d;
+ myMaximumMemory = float( d );
else
load.clear(ios::badbit | load.rdstate());
isOK = static_cast<bool>(load >> d);
if (isOK)
- myInitialMemory = d;
+ myInitialMemory = float( d );
else
load.clear(ios::badbit | load.rdstate());
isOK = static_cast<bool>(load >> i);
if (isOK)
- myOptimizationLevel = i;
+ myOptimizationLevel = (short int) i;
else
load.clear(ios::badbit | load.rdstate());
}
}
+ isOK = static_cast<bool>(load >> i);
+ if (isOK)
+ myAlgorithm = (short) i;
+ else
+ load.clear(ios::badbit | load.rdstate());
+
+ isOK = static_cast<bool>(load >> i);
+ if (isOK)
+ myUseNumOfThreads = (short) i;
+ else
+ load.clear(ios::badbit | load.rdstate());
+
+ isOK = static_cast<bool>(load >> i);
+ if (isOK)
+ myNumOfThreads = (short) i;
+ else
+ load.clear(ios::badbit | load.rdstate());
+
+ isOK = static_cast<bool>(load >> i);
+ if (isOK)
+ myPthreadModeMG = (short) i;
+ else
+ load.clear(ios::badbit | load.rdstate());
+
+ isOK = static_cast<bool>(load >> i);
+ if (isOK)
+ myPthreadModeMGHPC = (short) i;
+ else
+ load.clear(ios::badbit | load.rdstate());
+
return load;
}
return true;
}
+void GHS3DPlugin_Hypothesis::SetAdvancedOptionsInCommandLine( std::string & cmd ) const
+{
+ std::string option, value;
+ bool isDefault;
+ const TOptionValues* options[] = { & this->_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 );
+
+ 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)
*/
//================================================================================
-
std::string GHS3DPlugin_Hypothesis::CommandToRun(const GHS3DPlugin_Hypothesis* hyp,
const bool hasShapeToMesh,
const bool forExecutable)
{
- std::string cmd = GetExeName();
+ GHS3DPlugin_Hypothesis::ImplementedAlgorithms algoId = hyp ? (ImplementedAlgorithms) hyp->myAlgorithm : MGTetra;
+ std::string cmd = GetExeName( algoId );
+
// check if any option is overridden by hyp->myTextOption
bool max_memory = hyp ? !hyp->HasOptionDefined("max_memory") : true;
bool auto_memory = hyp ? !hyp->HasOptionDefined("automatic_memory") : true;
useBndRecovery = hyp->myToUseBoundaryRecoveryVersion;
// MG-Tetra needs to know amount of memory it may use (MB).
- // Default memory is defined at MG-Tetra installation but it may be not enough,
- // so allow to use about all available memory
- if ( max_memory ) {
+ // Default memory is defined at MG-Tetra installation but it may be not enough, // so allow to use about all available memory
+ if ( algoId == MGTetra && max_memory ) {
float aMaximumMemory = hyp ? hyp->myMaximumMemory : -1;
cmd += " --max_memory ";
if ( aMaximumMemory < 0 ) cmd += SMESH_Comment( int( DefaultMaximumMemory() ));
else cmd += SMESH_Comment( int( aMaximumMemory ));
}
- if ( auto_memory && !useBndRecovery ) {
+ if ( algoId == MGTetra && ( auto_memory && !useBndRecovery ) ) {
float aInitialMemory = hyp ? hyp->myInitialMemory : -1;
cmd += " --automatic_memory ";
if ( aInitialMemory > 0 ) cmd += SMESH_Comment( int( aInitialMemory ));
else cmd += "100";
}
+
// component to mesh
if ( comp && !useBndRecovery ) {
// We always run MG-Tetra with "to mesh holes'==TRUE (see PAL19680)
cmd += " --optimisation_level none"; // issue 22608
}
else if ( optim_level && hyp && !useBndRecovery ) {
- if ( hyp->myOptimizationLevel >= 0 && hyp->myOptimizationLevel < 5 ) {
- const char* level[] = { "none" , "light" , "standard" , "standard+" , "strong" };
- cmd += " --optimisation_level ";
- cmd += level[ hyp->myOptimizationLevel ];
- }
+ const char* level[] = { "none" , "light" , "standard" , "standard+" , "strong" };
+ const short myOpt = hyp->myOptimizationLevel;
+
+ if ( myOpt >= 0 && myOpt < 5 && ( algoId == MGTetra || ( algoId == MGTetraHPC && myOpt != 3 ) ) ) {
+ cmd += " --optimisation_level ";
+ cmd += level[ myOpt ];
+ }
}
// to create internal nodes
cmd += " --internalpoints no";
}
- // verbose mode
- if ( verbose && hyp ) {
- cmd += " --verbose " + SMESH_Comment( hyp->myVerboseLevel );
- }
-
- // boundary recovery version
- // if ( useBndRecovery ) {
- // cmd += " -C";
- // }
-
- // 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";
- }
+ if ( hyp )
+ {
+ // verbose mode
+ if ( verbose ) {
+ cmd += " --verbose " + SMESH_Comment( hyp->myVerboseLevel );
+ }
- // options as text
- // if ( hyp && !hyp->myTextOption.empty() ) {
- // cmd += " " + hyp->myTextOption;
- // }
+ // to remove initial central point.
+ if ( rem && hyp->myToRemoveCentralPoint ) {
+ if ( forExecutable )
+ cmd += " --no_initial_central_point";
+ else
+ cmd += " --centralpoint no";
+ }
- // 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->GetUseNumOfThreads() )
+ {
+ cmd += " --max_number_of_threads " + SMESH_Comment( hyp->GetNumOfThreads() );
+ const char* pthreadMode[] = { "none" , "aggressive" , "safe" };
+ const char* parallelMode[] = { "none", "reproducible_given_max_number_of_threads", "reproducible", "aggressive" };
+
+ if ( algoId == MGTetra && hyp->myPthreadModeMG >= 1 && hyp->myPthreadModeMG < 3 ) {
+ cmd += " --pthreads_mode ";
+ cmd += pthreadMode[ hyp->myPthreadModeMG ];
+ }
+ else if ( algoId == MGTetraHPC && hyp->myPthreadModeMGHPC >= 1 && hyp->myPthreadModeMGHPC < 4 )
+ {
+ cmd += " --parallel_strategy ";
+ cmd += parallelMode[ hyp->myPthreadModeMGHPC ];
+ }
+ }
- if ( hyp )
- {
// proximity
if ( hyp->GetUseVolumeProximity() )
{
cmd += " --volume_proximity_layers " + SMESH_Comment( hyp->GetNbVolumeProximityLayers() );
}
-
- std::string option, value;
- bool isDefault;
- const TOptionValues* options[] = { & hyp->_option2value, & hyp->_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 = 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;
- }
- }
+
+ hyp->SetAdvancedOptionsInCommandLine( cmd );
}
#ifdef WIN32
cmd += " < NUL";
#endif
-
return cmd;
}
//================================================================================
/*!
- * \brief Return a unique file name
+ * \brief Return a unique file name for MGTetra
*/
//================================================================================
std::string GHS3DPlugin_Hypothesis::GetFileName(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+='\\';
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
*/
//================================================================================
-std::string GHS3DPlugin_Hypothesis::GetExeName()
+std::string GHS3DPlugin_Hypothesis::GetExeName( ImplementedAlgorithms algoId )
{
- return "mg-tetra.exe";
+ switch ( algoId )
+ {
+ case MGTetra:
+ return "mg-tetra.exe";
+ case MGTetraHPC:
+ return "mg-tetra_hpc.exe";
+ default:
+ throw( "Undefined algorithm id: ");
+ }
}
//================================================================================
// strip white spaces
while (ptr[0] == ' ')
ptr++;
- int i = strlen(ptr);
+ size_t i = strlen(ptr);
while (i != 0 && ptr[i - 1] == ' ')
i--;
// check value type
if ( isOk ) *isOk = true;
for ( size_t i = 0; i <= s.size(); ++i )
- s[i] = tolower( s[i] );
+ s[i] = (char) tolower( s[i] );
if ( s == "1" || s == "true" || s == "active" || s == "yes" )
return true;