Salome HOME
bos #32737 Allow to choose between MG-Tetra and MG-Tetra_HPC multithread
[plugins/ghs3dplugin.git] / src / GHS3DPlugin / GHS3DPlugin_Hypothesis.cxx
index 6b6cc2534547655efea7993b52750b22dc839976..989eea6d0dbbe391f08c9d205d3b96b98d6028c0 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2004-2016  CEA/DEN, EDF R&D
+// 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
@@ -25,7 +25,9 @@
 //
 #include "GHS3DPlugin_Hypothesis.hxx"
 
+#include <Basics_DirUtils.hxx>
 #include <SMESHDS_Mesh.hxx>
+#include <SMESH_File.hxx>
 
 #include <TCollection_AsciiString.hxx>
 
 
 using namespace std;
 
+namespace
+{
+  struct GET_DEFAULT // struct used to get default value from GetOptionValue()
+  {
+    bool isDefault;
+    operator bool* () { return &isDefault; }
+  };
+}
+
 //=======================================================================
 //function : GHS3DPlugin_Hypothesis
 //=======================================================================
@@ -57,21 +68,85 @@ GHS3DPlugin_Hypothesis::GHS3DPlugin_Hypothesis(int hypId, SMESH_Gen * gen)
     myLogInStandardOutput(DefaultStandardOutputLog()),
     myRemoveLogOnSuccess( DefaultRemoveLogOnSuccess() ),
     myGradation(DefaultGradation()),
-    _enfVertexList(DefaultGHS3DEnforcedVertexList()),
-    _enfVertexCoordsSizeList(DefaultGHS3DEnforcedVertexCoordsValues()),
-    _enfVertexEntrySizeList(DefaultGHS3DEnforcedVertexEntryValues()),
-    _coordsEnfVertexMap(DefaultCoordsGHS3DEnforcedVertexMap()),
-    _geomEntryEnfVertexMap(DefaultGeomEntryGHS3DEnforcedVertexMap()),
-    _enfMeshList(DefaultGHS3DEnforcedMeshList()),
-    _entryEnfMeshMap(DefaultEntryGHS3DEnforcedMeshListMap()),
-    _enfNodes(TIDSortedNodeGroupMap()),
-    _enfEdges(TIDSortedElemGroupMap()),
-    _enfTriangles(TIDSortedElemGroupMap()),
-    _nodeIDToSizeMap(DefaultID2SizeMap()),
-    _groupsToRemove(DefaultGroupsToRemove())
+    myUseVolumeProximity(DefaultUseVolumeProximity()),
+    myNbVolumeProximityLayers(DefaultNbVolumeProximityLayers()),
+    myAlgorithm(DefaultAlgorithm()),    
+    myNumOfThreads(DefaultNumOfThreads()),
+    myUseNumOfThreads(DefaultUseNumOfThreads()),
+    myPthreadModeMG(DefaultMyPthreadMode()),
+    myPthreadModeMGHPC(DefaultMyPthreadModeHPC()),
+    myMinSize(0),
+    myMinSizeDefault(0),
+    myMaxSize(0),
+    myMaxSizeDefault(0)
 {
   _name = GetHypType();
   _param_algo_dim = 3;
+
+  const char* boolOptionNames[] = { "no_initial_central_point",                          // no
+                                    "force_max_size",                                    // no
+                                    "apply_gradation_on_skin_vertex_sizes",              // yes
+                                    "optimise_worst_elements",                           // no
+                                    "force_output_quadratic_mesh",                       // no
+                                    "rectify_jacobian",                                  // yes
+                                    "jacobian_rectification_respect_input_surface_mesh", // yes
+                                    "" // mark of end
+  };
+  const char* intOptionNames[] = { "max_number_of_errors_printed", // 1
+                                   "" // mark of end
+  };
+  const char* doubleOptionNames[] = { "target_quality",  // 0
+                                      "sliver_angle",    // 5
+                                      "" // mark of end
+  };
+  const char* charOptionNames[] = { "boundary_regeneration",            // standard
+                                    "split_overconstrained_tetrahedra", // no
+                                    "" // mark of end
+  };
+
+  int i = 0;
+  while (boolOptionNames[i][0])
+  {
+    _boolOptions.insert( boolOptionNames[i] );
+    _option2value[boolOptionNames[i++]].clear();
+  }
+  i = 0;
+  while (intOptionNames[i][0])
+    _option2value[intOptionNames[i++]].clear();
+  
+  i = 0;
+  while (doubleOptionNames[i][0]) {
+    _doubleOptions.insert(doubleOptionNames[i]);
+    _option2value[doubleOptionNames[i++]].clear();
+  }
+  i = 0;
+  while (charOptionNames[i][0]) {
+    _charOptions.insert(charOptionNames[i]);
+    _option2value[charOptionNames[i++]].clear();
+  }
+
+  // default values to be used while MG meshing
+
+  _defaultOptionValues["no_initial_central_point"                         ] = "no";
+  _defaultOptionValues["force_max_size"                                   ] = "no";
+  _defaultOptionValues["apply_gradation_on_skin_vertex_sizes"             ] = "yes";
+  _defaultOptionValues["optimise_worst_elements"                          ] = "no";
+  _defaultOptionValues["force_output_quadratic_mesh"                      ] = "no";
+  _defaultOptionValues["rectify_jacobian"                                 ] = "yes";
+  _defaultOptionValues["jacobian_rectification_respect_input_surface_mesh"] = "yes";
+  _defaultOptionValues["max_number_of_errors_printed"                     ] = "1";
+  _defaultOptionValues["target_quality"                                   ] = "";//NoValue();
+  _defaultOptionValues["sliver_angle"                                     ] = "5";
+  _defaultOptionValues["boundary_regeneration"                            ] = "standard";
+  _defaultOptionValues["split_overconstrained_tetrahedra"                 ] = "no";
+
+#ifdef _DEBUG_
+  // check validity of option names of _defaultOptionValues
+  TOptionValues::iterator n2v = _defaultOptionValues.begin();
+  for ( ; n2v != _defaultOptionValues.end(); ++n2v )
+    ASSERT( _option2value.count( n2v->first ));
+  ASSERT( _option2value.size() == _defaultOptionValues.size() );
+#endif
 }
 
 //=======================================================================
@@ -92,11 +167,17 @@ void GHS3DPlugin_Hypothesis::SetToMeshHoles(bool toMesh)
 
 bool GHS3DPlugin_Hypothesis::GetToMeshHoles(bool checkFreeOption) const
 {
-  if (checkFreeOption && !myTextOption.empty()) {
-    if ( myTextOption.find("--components all"))
-      return true;
-    if ( myTextOption.find("--components outside_components"))
-      return false;
+  if ( checkFreeOption )
+  {
+    std::string optionName = "components";
+    TOptionValues::const_iterator op_val = _customOption2value.find(optionName);
+    if ( op_val != _customOption2value.end())
+    {
+      if ( op_val->second.find("all"))
+        return true;
+      if ( op_val->second.find("outside_components"))
+        return false;
+    }
   }
   return myToMeshHoles;
 }
@@ -274,9 +355,108 @@ void GHS3DPlugin_Hypothesis::SetToCreateNewNodes(bool toCreate)
 }
 
 //=======================================================================
-//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;
@@ -330,10 +510,8 @@ bool GHS3DPlugin_Hypothesis::GetFEMCorrection() const
 
 void GHS3DPlugin_Hypothesis::SetToRemoveCentralPoint(bool toRemove)
 {
-  if ( myToRemoveCentralPoint != toRemove ) {
-    myToRemoveCentralPoint = toRemove;
-    NotifySubMeshesHypothesisModification();
-  }
+  SetOptionValue( "no_initial_central_point", toRemove ? "yes" : "no" );
+  myToRemoveCentralPoint = toRemove;
 }
 
 //=======================================================================
@@ -351,9 +529,16 @@ bool GHS3DPlugin_Hypothesis::GetToRemoveCentralPoint() const
 
 void GHS3DPlugin_Hypothesis::SetAdvancedOption(const std::string& option)
 {
-  if ( myTextOption != option ) {
-    myTextOption = option;
-    NotifySubMeshesHypothesisModification();
+  size_t wsPos = option.find(' ');
+  if ( wsPos == string::npos )
+  {
+    SetOptionValue( option, "" );
+  }
+  else
+  {
+    std::string opt( option, 0, wsPos );
+    std::string val( option, wsPos + 1 );
+    SetOptionValue( opt, val );
   }
 }
 
@@ -363,7 +548,23 @@ void GHS3DPlugin_Hypothesis::SetAdvancedOption(const std::string& option)
 
 std::string GHS3DPlugin_Hypothesis::GetAdvancedOption() const
 {
-  return myTextOption;
+  SMESH_Comment txt;
+
+  TOptionValues::const_iterator o2v = _option2value.begin();
+  for ( ; o2v != _option2value.end(); ++o2v )
+    if ( !o2v->second.empty() )
+    {
+      if ( !txt.empty() )
+        txt << " ";
+      txt << o2v->first << " " << o2v->second;
+    }
+  for ( o2v = _customOption2value.begin(); o2v != _customOption2value.end(); ++o2v )
+  {
+    if ( !txt.empty() )
+      txt << " ";
+    txt << o2v->first << " " << o2v->second;
+  }
+  return txt;
 }
 
 //=======================================================================
@@ -387,6 +588,46 @@ double GHS3DPlugin_Hypothesis::GetGradation() const
   return myGradation;
 }
 
+//=============================================================================
+void GHS3DPlugin_Hypothesis::SetMinSize(double theMinSize)
+{
+  if ( theMinSize != myMinSize )
+  {
+    myMinSize = theMinSize;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//=============================================================================
+void GHS3DPlugin_Hypothesis::SetMaxSize(double theMaxSize)
+{
+  if ( theMaxSize != myMaxSize )
+  {
+    myMaxSize = theMaxSize;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//=============================================================================
+void GHS3DPlugin_Hypothesis::SetUseVolumeProximity( bool toUse )
+{
+  if ( myUseVolumeProximity != toUse )
+  {
+    myUseVolumeProximity = toUse;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//=============================================================================
+void GHS3DPlugin_Hypothesis::SetNbVolumeProximityLayers( int nbLayers )
+{
+  if ( myNbVolumeProximityLayers != nbLayers )
+  {
+    myNbVolumeProximityLayers = nbLayers;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
 //=======================================================================
 //function : SetStandardOutputLog
 //=======================================================================
@@ -554,13 +795,13 @@ bool GHS3DPlugin_Hypothesis::SetEnforcedMesh(SMESH_Mesh& theMesh, SMESH::Element
 //=======================================================================
 //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);
@@ -679,7 +920,6 @@ bool GHS3DPlugin_Hypothesis::SetEnforcedElements(TIDSortedElemSet theElemSet, SM
 //=======================================================================
 
 GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertex* GHS3DPlugin_Hypothesis::GetEnforcedVertex(double x, double y, double z)
-  throw (std::invalid_argument)
 {
   std::vector<double> coord(3);
   coord[0] = x;
@@ -693,7 +933,6 @@ GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertex* GHS3DPlugin_Hypothesis::GetEnforce
 }
 
 GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertex* GHS3DPlugin_Hypothesis::GetEnforcedVertex(const std::string theEntry)
-  throw (std::invalid_argument)
 {
   if (_geomEntryEnfVertexMap.count(theEntry)>0)
     return _geomEntryEnfVertexMap[theEntry];
@@ -708,7 +947,6 @@ GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertex* GHS3DPlugin_Hypothesis::GetEnforce
 //=======================================================================
 
 bool GHS3DPlugin_Hypothesis::RemoveEnforcedVertex(double x, double y, double z, const std::string theEntry)
-  throw (std::invalid_argument)
 {
   bool toNotify = false;
   std::ostringstream msg;
@@ -865,15 +1103,15 @@ float GHS3DPlugin_Hypothesis::DefaultMaximumMemory()
   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;
@@ -983,15 +1221,6 @@ bool GHS3DPlugin_Hypothesis::DefaultToRemoveCentralPoint()
   return false;
 }
 
-//=======================================================================
-//function : DefaultGradation
-//=======================================================================
-
-double GHS3DPlugin_Hypothesis::DefaultGradation()
-{
-  return 1.05;
-}
-
 //=======================================================================
 //function : DefaultStandardOutputLog
 //=======================================================================
@@ -1030,11 +1259,11 @@ std::ostream & GHS3DPlugin_Hypothesis::SaveTo(std::ostream & save)
   save << (int)myToRemoveCentralPoint         << " ";
   save << myGradation                         << " ";
   save << myToMakeGroupsOfDomains             << " ";
-  if (!myTextOption.empty()) {
-    save << "__OPTIONS_BEGIN__ ";
-    save << myTextOption                      << " ";
-    save << "__OPTIONS_END__ ";
-  }
+  // if (!myTextOption.empty()) {
+  //   save << "__OPTIONS_BEGIN__ ";
+  //   save << myTextOption                      << " ";
+  //   save << "__OPTIONS_END__ ";
+  // }
   
 
   TGHS3DEnforcedVertexList::iterator it  = _enfVertexList.begin();
@@ -1104,6 +1333,32 @@ std::ostream & GHS3DPlugin_Hypothesis::SaveTo(std::ostream & save)
     }
     save << " "  << "__ENFORCED_MESHES_END__ ";
   }
+
+  // New options in 2.9.6 (issue #17784)
+
+  save << " " << myUseVolumeProximity;
+  save << " " << myNbVolumeProximityLayers;
+  save << " " << myMinSize;
+  save << " " << myMaxSize;
+  save << " " << myMinSizeDefault;
+  save << " " << myMaxSizeDefault;
+
+  save << " " << _option2value.size();
+  TOptionValues::iterator o2v = _option2value.begin();
+  for ( ; o2v != _option2value.end(); ++o2v )
+    save << " -" << o2v->first << " -" << o2v->second;
+  
+  save << " " << _customOption2value.size();
+  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;
 }
 
@@ -1125,19 +1380,19 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
 
   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());
 
@@ -1226,15 +1481,15 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
       isOK = static_cast<bool>(load >> txt);
       if (isOK) {
         if (txt == "__OPTIONS_END__") {
-          if (!myTextOption.empty()) {
-            // Remove last space
-            myTextOption.erase(myTextOption.end()-1);
-          }
+          // if (!myTextOption.empty()) {
+          //   // Remove last space
+          //   myTextOption.erase(myTextOption.end()-1);
+          // }
           isOK = false;
           break;
         }
-        myTextOption += txt;
-        myTextOption += " ";
+        // myTextOption += txt;
+        // myTextOption += " ";
       }
     }
   }
@@ -1427,6 +1682,69 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
     } // while
   } // if
 
+  // New options in 2.9.6 (issue #17784)
+
+  if ( ! hasOptions && ! hasEnforcedVertices && ! hasEnforcedMeshes )
+    myUseVolumeProximity = ( separator == "1" );
+  else if ( static_cast<bool>( load >> i ))
+    myUseVolumeProximity = (bool) i;
+
+  if ( static_cast<bool>( load >> myNbVolumeProximityLayers ))
+  {
+    load >> myMinSize;
+    load >> myMaxSize;
+    load >> myMinSizeDefault;
+    load >> myMaxSizeDefault;
+
+    std::string option, value;
+    if ( static_cast<bool>( load >> i ) && i >= 0 )
+    {
+      for ( int nbRead = 0; nbRead < i; ++nbRead )
+      {
+        load >> option >> value;
+        _option2value[ std::string( option, 1 )] = std::string( value, 1 );
+      }
+    }
+    if ( static_cast<bool>( load >> i ) && i >= 0 )
+    {
+      for ( int nbRead = 0; nbRead < i; ++nbRead )
+      {
+        load >> option >> value;
+        _customOption2value[ std::string( option, 1 )] = std::string( value, 1 );
+      }
+    }
+  }
+
+  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;
 }
 
@@ -1450,31 +1768,76 @@ bool GHS3DPlugin_Hypothesis::SetParametersByDefaults(const TDefaults&  dflts,
                                                      const SMESH_Mesh* /*theMesh*/)
 {
   myToMakeGroupsOfDomains = ( !dflts._shape || dflts._shape->IsNull() );
+
+  double diagonal = dflts._elemLength * _gen->GetBoundaryBoxSegmentation();
+  myMinSizeDefault = 1e-3 * diagonal;
+  myMaxSizeDefault = diagonal / 5.;
+
   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->myTextOption.find("--max_memory")  == std::string::npos ) : true;
-  bool auto_memory   = hyp ? ( hyp->myTextOption.find("--automatic_memory")  == std::string::npos ) : true;
-  bool comp   = hyp ? ( hyp->myTextOption.find("--components")  == std::string::npos ) : true;
-  bool optim_level   = hyp ? ( hyp->myTextOption.find("--optimisation_level")  == std::string::npos ) : true;
-  bool no_int_points  = hyp ? ( hyp->myTextOption.find("--no_internal_points") == std::string::npos ) : true;
-  bool C   = hyp ? ( hyp->myTextOption.find("-C")  == std::string::npos ) : true;
-  bool verbose   = hyp ? ( hyp->myTextOption.find("--verbose")  == std::string::npos ) : true;
-  bool fem = hyp ? ( hyp->myTextOption.find("-FEM")== std::string::npos ) : true;
-  bool rem = hyp ? ( hyp->myTextOption.find("--no_initial_central_point")== std::string::npos ) : true;
-  bool gra = hyp ? ( hyp->myTextOption.find("-Dcpropa")== std::string::npos ) : true;
+  bool max_memory     = hyp ? !hyp->HasOptionDefined("max_memory")               : true;
+  bool auto_memory    = hyp ? !hyp->HasOptionDefined("automatic_memory")         : true;
+  bool comp           = hyp ? !hyp->HasOptionDefined("components")               : true;
+  bool optim_level    = hyp ? !hyp->HasOptionDefined("optimisation_level")       : true;
+  bool no_int_points  = hyp ? !hyp->HasOptionDefined("no_internal_points")       : true;
+  bool C              = hyp ? !hyp->HasOptionDefined("-C")                       : true;
+  bool verbose        = hyp ? !hyp->HasOptionDefined("verbose")                  : true;
+  bool gra            = hyp ? !hyp->HasOptionDefined("-Dcpropa")                 : true;
+  bool rem            = hyp ? !hyp->HasOptionDefined("no_initial_central_point") : true;
+  //bool fem            = hyp ? !hyp->HasOptionDefined("-FEM")                     : true;
 
   // if use boundary recovery version, few options are allowed
   bool useBndRecovery = !C;
@@ -1482,20 +1845,20 @@ std::string GHS3DPlugin_Hypothesis::CommandToRun(const GHS3DPlugin_Hypothesis* h
     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( DefaultMaximumMemory() );
-    else                      cmd += SMESH_Comment( aMaximumMemory );
+    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( aInitialMemory );
+    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)
@@ -1514,11 +1877,13 @@ std::string GHS3DPlugin_Hypothesis::CommandToRun(const GHS3DPlugin_Hypothesis* h
     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
@@ -1529,58 +1894,75 @@ std::string GHS3DPlugin_Hypothesis::CommandToRun(const GHS3DPlugin_Hypothesis* h
       cmd += " --internalpoints no";
   }
 
-  // verbose mode
-  if ( verbose && hyp ) {
-    cmd += " --verbose " + SMESH_Comment( hyp->myVerboseLevel );
-  }
-
-  // boundary recovery version
-  if ( useBndRecovery ) {
-    cmd += " -C";
-  }
+  if ( hyp ) 
+  {
+    // verbose mode
+    if ( verbose ) {
+      cmd += " --verbose " + SMESH_Comment( hyp->myVerboseLevel );
+    }
 
-  // to use FEM correction
-  if ( fem && hyp && hyp->myToUseFemCorrection) {
-    cmd += " -FEM";
-  }
+    // to remove initial central point.
+    if ( rem && hyp->myToRemoveCentralPoint ) {
+      if ( forExecutable )
+        cmd += " --no_initial_central_point";
+      else
+        cmd += " --centralpoint no";
+    }
 
-  // to remove initial central point.
-  if ( rem && hyp && hyp->myToRemoveCentralPoint) {
-    if ( forExecutable )
-      cmd += " --no_initial_central_point";
-    else
-      cmd += " --centralpoint no";
-  }
+    if ( hyp->GetMinSize() > 0 )
+      cmd += " --min_size " + SMESH_Comment( hyp->GetMinSize() );
 
-  // options as text
-  if ( hyp && !hyp->myTextOption.empty() ) {
-    cmd += " " + hyp->myTextOption;
-  }
+    if ( hyp->GetMaxSize() > 0 )
+      cmd += " --max_size " + SMESH_Comment( hyp->GetMaxSize() );
 
-  // to define volumic gradation.
-  if ( gra && hyp ) {
-    if ( forExecutable )
-      cmd += " -Dcpropa=" + SMESH_Comment( hyp->myGradation );
-    else
+    // 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 ];
+      }
+    }
+
+    // proximity
+    if ( hyp->GetUseVolumeProximity() )
+    {
+      cmd += " --volume_proximity_layers " + SMESH_Comment( hyp->GetNbVolumeProximityLayers() );
+    }
+    
+    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+='\\';
@@ -1597,15 +1979,51 @@ 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
  */
 //================================================================================
 
-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: ");
+  }
 }
 
 //================================================================================
@@ -1616,50 +2034,259 @@ std::string GHS3DPlugin_Hypothesis::GetExeName()
 
 GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexList GHS3DPlugin_Hypothesis::GetEnforcedVertices(const GHS3DPlugin_Hypothesis* hyp)
 {
-  return hyp ? hyp->_GetEnforcedVertices():DefaultGHS3DEnforcedVertexList();
+  return hyp ? hyp->_GetEnforcedVertices(): TGHS3DEnforcedVertexList();
 }
 
 GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexCoordsValues GHS3DPlugin_Hypothesis::GetEnforcedVerticesCoordsSize (const GHS3DPlugin_Hypothesis* hyp)
 {  
-  return hyp ? hyp->_GetEnforcedVerticesCoordsSize(): DefaultGHS3DEnforcedVertexCoordsValues();
+  return hyp ? hyp->_GetEnforcedVerticesCoordsSize(): TGHS3DEnforcedVertexCoordsValues();
 }
 
 GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexEntryValues GHS3DPlugin_Hypothesis::GetEnforcedVerticesEntrySize (const GHS3DPlugin_Hypothesis* hyp)
 {  
-  return hyp ? hyp->_GetEnforcedVerticesEntrySize(): DefaultGHS3DEnforcedVertexEntryValues();
+  return hyp ? hyp->_GetEnforcedVerticesEntrySize(): TGHS3DEnforcedVertexEntryValues();
 }
 
 GHS3DPlugin_Hypothesis::TCoordsGHS3DEnforcedVertexMap GHS3DPlugin_Hypothesis::GetEnforcedVerticesByCoords (const GHS3DPlugin_Hypothesis* hyp)
 {  
-  return hyp ? hyp->_GetEnforcedVerticesByCoords(): DefaultCoordsGHS3DEnforcedVertexMap();
+  return hyp ? hyp->_GetEnforcedVerticesByCoords(): TCoordsGHS3DEnforcedVertexMap();
 }
 
 GHS3DPlugin_Hypothesis::TGeomEntryGHS3DEnforcedVertexMap GHS3DPlugin_Hypothesis::GetEnforcedVerticesByEntry (const GHS3DPlugin_Hypothesis* hyp)
 {  
-  return hyp ? hyp->_GetEnforcedVerticesByEntry(): DefaultGeomEntryGHS3DEnforcedVertexMap();
+  return hyp ? hyp->_GetEnforcedVerticesByEntry(): TGeomEntryGHS3DEnforcedVertexMap();
 }
 
 GHS3DPlugin_Hypothesis::TIDSortedNodeGroupMap GHS3DPlugin_Hypothesis::GetEnforcedNodes(const GHS3DPlugin_Hypothesis* hyp)
 {
-  return hyp ? hyp->_GetEnforcedNodes():DefaultIDSortedNodeGroupMap();
+  return hyp ? hyp->_GetEnforcedNodes():TIDSortedNodeGroupMap();
 }
 
 GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap GHS3DPlugin_Hypothesis::GetEnforcedEdges(const GHS3DPlugin_Hypothesis* hyp)
 {
-  return hyp ? hyp->_GetEnforcedEdges():DefaultIDSortedElemGroupMap();
+  return hyp ? hyp->_GetEnforcedEdges():TIDSortedElemGroupMap();
 }
 
 GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap GHS3DPlugin_Hypothesis::GetEnforcedTriangles(const GHS3DPlugin_Hypothesis* hyp)
 {
-  return hyp ? hyp->_GetEnforcedTriangles():DefaultIDSortedElemGroupMap();
+  return hyp ? hyp->_GetEnforcedTriangles():TIDSortedElemGroupMap();
 }
 
 GHS3DPlugin_Hypothesis::TID2SizeMap GHS3DPlugin_Hypothesis::GetNodeIDToSizeMap(const GHS3DPlugin_Hypothesis* hyp)
 {
-  return hyp ? hyp->_GetNodeIDToSizeMap(): DefaultID2SizeMap();
+  return hyp ? hyp->_GetNodeIDToSizeMap(): TID2SizeMap();
 }
 
 GHS3DPlugin_Hypothesis::TSetStrings GHS3DPlugin_Hypothesis::GetGroupsToRemove(const GHS3DPlugin_Hypothesis* hyp)
 {
-  return hyp ? hyp->_GetGroupsToRemove(): DefaultGroupsToRemove();
+  return hyp ? hyp->_GetGroupsToRemove(): TSetStrings();
+}
+
+
+//=============================================================================
+void GHS3DPlugin_Hypothesis::SetOptionValue(const std::string& optionName,
+                                            const std::string& optionValue)
+{
+  TOptionValues::iterator op_val = _option2value.find(optionName);
+  if (op_val == _option2value.end())
+  {
+    op_val = _customOption2value.find( optionName );
+    if ( op_val != _customOption2value.end() && op_val->second != optionValue )
+      NotifySubMeshesHypothesisModification();
+    _customOption2value[ optionName ] = optionValue;
+    return;
+  }
+
+  if (op_val->second != optionValue)
+  {
+    const char* ptr = optionValue.c_str();
+    // strip white spaces
+    while (ptr[0] == ' ')
+      ptr++;
+    size_t i = strlen(ptr);
+    while (i != 0 && ptr[i - 1] == ' ')
+      i--;
+    // check value type
+    bool typeOk = true;
+    std::string typeName;
+    if (i == 0) {
+      // empty string
+    } else if (_charOptions.count(optionName)) {
+      // do not check strings
+    } else if (_doubleOptions.count(optionName)) {
+      // check if value is double
+      ToDbl(ptr, &typeOk);
+      typeName = "real";
+    } else if (_boolOptions.count(optionName)) {
+      // check if value is bool
+      ToBool(ptr, &typeOk);
+      typeName = "bool";
+    } else {
+      // check if value is int
+      ToInt(ptr, &typeOk);
+      typeName = "integer";
+    }
+    if ( typeOk ) // check some specific values ?
+    {
+    }
+    if ( !typeOk )
+    {
+      std::string msg = "Advanced option '" + optionName + "' = '" + optionValue + "' but must be " + typeName;
+      throw std::invalid_argument(msg);
+    }
+    std::string value( ptr, i );
+    if ( _defaultOptionValues[ optionName ] == value )
+      value.clear();
+
+    op_val->second = value;
+
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//=============================================================================
+//! Return option value. If isDefault provided, it can be a default value,
+//  then *isDefault == true. If isDefault is not provided, the value will be
+//  empty if it equals a default one.
+std::string GHS3DPlugin_Hypothesis::GetOptionValue(const std::string& optionName,
+                                                   bool*              isDefault) const
+{
+  TOptionValues::const_iterator op_val = _option2value.find(optionName);
+  if (op_val == _option2value.end())
+  {
+    op_val = _customOption2value.find(optionName);
+    if (op_val == _customOption2value.end())
+    {
+      std::string msg = "Unknown MG-Tetra option: <" + optionName + ">";
+      throw std::invalid_argument(msg);
+    }
+  }
+  std::string val = op_val->second;
+  if ( isDefault ) *isDefault = ( val.empty() );
+
+  if ( val.empty() && isDefault )
+  {
+    op_val = _defaultOptionValues.find( optionName );
+    if (op_val != _defaultOptionValues.end())
+      val = op_val->second;
+  }
+  return val;
+}
+
+
+//=============================================================================
+bool GHS3DPlugin_Hypothesis::HasOptionDefined( const std::string& optionName ) const
+{
+  bool isDefault = false;
+  try
+  {
+    GetOptionValue( optionName, &isDefault );
+  }
+  catch ( std::invalid_argument& )
+  {
+    return false;
+  }
+  return !isDefault;
+}
+
+//=============================================================================
+void GHS3DPlugin_Hypothesis::ClearOption(const std::string& optionName)
+{
+  TOptionValues::iterator op_val = _customOption2value.find(optionName);
+  if (op_val != _customOption2value.end())
+   _customOption2value.erase(op_val);
+  else {
+    op_val = _option2value.find(optionName);
+    if (op_val != _option2value.end())
+      op_val->second.clear();
+  }
+}
+
+//=============================================================================
+GHS3DPlugin_Hypothesis::TOptionValues GHS3DPlugin_Hypothesis::GetOptionValues() const
+{
+  TOptionValues vals;
+  TOptionValues::const_iterator op_val = _option2value.begin();
+  for ( ; op_val != _option2value.end(); ++op_val )
+    vals.insert( make_pair( op_val->first, GetOptionValue( op_val->first, GET_DEFAULT() )));
+
+  return vals;
+}
+
+//================================================================================
+/*!
+ * \brief Converts a string to a bool
+ */
+//================================================================================
+
+bool GHS3DPlugin_Hypothesis::ToBool(const std::string& str, bool* isOk )
+{
+  std::string s = str;
+  if ( isOk ) *isOk = true;
+
+  for ( size_t i = 0; i <= s.size(); ++i )
+    s[i] = (char) tolower( s[i] );
+
+  if ( s == "1" || s == "true" || s == "active" || s == "yes" )
+    return true;
+
+  if ( s == "0" || s == "false" || s == "inactive" || s == "no" )
+    return false;
+
+  if ( isOk )
+    *isOk = false;
+  else {
+    std::string msg = "Not a Boolean value:'" + str + "'";
+    throw std::invalid_argument(msg);
+  }
+  return false;
 }
+
+//================================================================================
+/*!
+ * \brief Converts a string to a real value
+ */
+//================================================================================
+
+double GHS3DPlugin_Hypothesis::ToDbl(const std::string& str, bool* isOk )
+{
+  if ( str.empty() ) throw std::invalid_argument("Empty value provided");
+
+  char * endPtr;
+  double val = strtod(&str[0], &endPtr);
+  bool ok = (&str[0] != endPtr);
+
+  if ( isOk ) *isOk = ok;
+
+  if ( !ok )
+  {
+    std::string msg = "Not a real value:'" + str + "'";
+    throw std::invalid_argument(msg);
+  }
+  return val;
+}
+
+//================================================================================
+/*!
+ * \brief Converts a string to a integer value
+ */
+//================================================================================
+
+int GHS3DPlugin_Hypothesis::ToInt(const std::string& str, bool* isOk )
+{
+  if ( str.empty() ) throw std::invalid_argument("Empty value provided");
+
+  char * endPtr;
+  int val = (int)strtol( &str[0], &endPtr, 10);
+  bool ok = (&str[0] != endPtr);
+
+  if ( isOk ) *isOk = ok;
+
+  if ( !ok )
+  {
+    std::string msg = "Not an integer value:'" + str + "'";
+    throw std::invalid_argument(msg);
+  }
+  return val;
+}
+