Salome HOME
updated copyright message
[plugins/ghs3dplugin.git] / src / GHS3DPlugin / GHS3DPlugin_Hypothesis.cxx
index 29cd1e16fb30e0979a1fce5556d17dac68ad210c..45d4d9249765195029c218c9412739ed9c27ef8e 100644 (file)
@@ -1,9 +1,9 @@
-// Copyright (C) 2004-2013  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
 // License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// 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
 //=============================================================================
 //
 #include "GHS3DPlugin_Hypothesis.hxx"
-#include <SMESH_ProxyMesh.hxx>
-#include <SMESH_Group.hxx>
-#include <StdMeshers_QuadToTriaAdaptor.hxx>
+
+#include <Basics_DirUtils.hxx>
+#include <SMESHDS_Mesh.hxx>
+#include <SMESH_File.hxx>
 
 #include <TCollection_AsciiString.hxx>
 
-#ifdef WNT
+#ifdef WIN32
 #include <process.h>
 #define getpid _getpid
 #endif
 
+using namespace std;
+
+namespace
+{
+  struct GET_DEFAULT // struct used to get default value from GetOptionValue()
+  {
+    bool isDefault;
+    operator bool* () { return &isDefault; }
+  };
+}
+
 //=======================================================================
 //function : GHS3DPlugin_Hypothesis
 //=======================================================================
 
-GHS3DPlugin_Hypothesis::GHS3DPlugin_Hypothesis(int hypId, int studyId, SMESH_Gen * gen)
-  : SMESH_Hypothesis(hypId, studyId, gen),
-  myToMeshHoles(DefaultMeshHoles()),
-  myToMakeGroupsOfDomains(DefaultToMakeGroupsOfDomains()),
-  myMaximumMemory(-1),
-  myInitialMemory(-1),
-  myOptimizationLevel(DefaultOptimizationLevel()),
-  myWorkingDirectory(DefaultWorkingDirectory()),
-  myKeepFiles(DefaultKeepFiles()),
-  myVerboseLevel(DefaultVerboseLevel()),
-  myToCreateNewNodes(DefaultToCreateNewNodes()),
-  myToUseBoundaryRecoveryVersion(DefaultToUseBoundaryRecoveryVersion()),
-  myToUseFemCorrection(DefaultToUseFEMCorrection()),
-  myToRemoveCentralPoint(DefaultToRemoveCentralPoint()),
-  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())
-{
-  _name = "GHS3D_Parameters";
+GHS3DPlugin_Hypothesis::GHS3DPlugin_Hypothesis(int hypId, SMESH_Gen * gen)
+  : SMESH_Hypothesis(hypId, gen),
+    myToMeshHoles(DefaultMeshHoles()),
+    myToMakeGroupsOfDomains(DefaultToMakeGroupsOfDomains()),
+    myMaximumMemory(-1),
+    myInitialMemory(-1),
+    myOptimizationLevel(DefaultOptimizationLevel()),
+    myKeepFiles(DefaultKeepFiles()),
+    myWorkingDirectory(DefaultWorkingDirectory()),
+    myVerboseLevel(DefaultVerboseLevel()),
+    myToCreateNewNodes(DefaultToCreateNewNodes()),
+    myToUseBoundaryRecoveryVersion(DefaultToUseBoundaryRecoveryVersion()),
+    myToUseFemCorrection(DefaultToUseFEMCorrection()),
+    myToRemoveCentralPoint(DefaultToRemoveCentralPoint()),
+    myLogInStandardOutput(DefaultStandardOutputLog()),
+    myRemoveLogOnSuccess( DefaultRemoveLogOnSuccess() ),
+    myGradation(DefaultGradation()),
+    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
 }
 
 //=======================================================================
@@ -89,11 +167,17 @@ void GHS3DPlugin_Hypothesis::SetToMeshHoles(bool toMesh)
 
 bool GHS3DPlugin_Hypothesis::GetToMeshHoles(bool checkFreeOption) const
 {
-  if (checkFreeOption && !myTextOption.empty()) {
-    if ( myTextOption.find("-c 0"))
-      return true;
-    if ( myTextOption.find("-c 1"))
-      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;
 }
@@ -135,7 +219,7 @@ bool GHS3DPlugin_Hypothesis::GetToMakeGroupsOfDomains(const GHS3DPlugin_Hypothes
 //function : SetMaximumMemory
 //=======================================================================
 
-void GHS3DPlugin_Hypothesis::SetMaximumMemory(short MB)
+void GHS3DPlugin_Hypothesis::SetMaximumMemory(float MB)
 {
   if ( myMaximumMemory != MB ) {
     myMaximumMemory = MB;
@@ -148,7 +232,7 @@ void GHS3DPlugin_Hypothesis::SetMaximumMemory(short MB)
 //           * automatic memory adjustment mode. Default is zero
 //=======================================================================
 
-short GHS3DPlugin_Hypothesis::GetMaximumMemory() const
+float GHS3DPlugin_Hypothesis::GetMaximumMemory() const
 {
   return myMaximumMemory;
 }
@@ -157,7 +241,7 @@ short GHS3DPlugin_Hypothesis::GetMaximumMemory() const
 //function : SetInitialMemory
 //=======================================================================
 
-void GHS3DPlugin_Hypothesis::SetInitialMemory(short MB)
+void GHS3DPlugin_Hypothesis::SetInitialMemory(float MB)
 {
   if ( myInitialMemory != MB ) {
     myInitialMemory = MB;
@@ -169,7 +253,7 @@ void GHS3DPlugin_Hypothesis::SetInitialMemory(short MB)
 //function : GetInitialMemory
 //=======================================================================
 
-short GHS3DPlugin_Hypothesis::GetInitialMemory() const
+float GHS3DPlugin_Hypothesis::GetInitialMemory() const
 {
   return myInitialMemory;
 }
@@ -271,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;
@@ -327,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;
 }
 
 //=======================================================================
@@ -343,24 +524,47 @@ bool GHS3DPlugin_Hypothesis::GetToRemoveCentralPoint() const
 }
 
 //=======================================================================
-//function : SetTextOption
+//function : SetAdvancedOption
 //=======================================================================
 
-void GHS3DPlugin_Hypothesis::SetTextOption(const std::string& option)
+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 );
   }
 }
 
 //=======================================================================
-//function : GetTextOption
+//function : GetAdvancedOption
 //=======================================================================
 
-std::string GHS3DPlugin_Hypothesis::GetTextOption() const
+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;
 }
 
 //=======================================================================
@@ -384,12 +588,98 @@ 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
+//=======================================================================
+
+void GHS3DPlugin_Hypothesis::SetStandardOutputLog(bool logInStandardOutput)
+{
+  if ( myLogInStandardOutput != logInStandardOutput ) {
+    myLogInStandardOutput = logInStandardOutput;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//=======================================================================
+//function : GetStandardOutputLog
+//=======================================================================
+
+bool GHS3DPlugin_Hypothesis::GetStandardOutputLog() const
+{
+  return myLogInStandardOutput;
+}
+
+//=======================================================================
+//function : SetRemoveLogOnSuccess
+//=======================================================================
+
+void GHS3DPlugin_Hypothesis::SetRemoveLogOnSuccess(bool removeLogOnSuccess)
+{
+  if ( myRemoveLogOnSuccess != removeLogOnSuccess ) {
+    myRemoveLogOnSuccess = removeLogOnSuccess;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//=======================================================================
+//function : GetRemoveLogOnSuccess
+//=======================================================================
+
+bool GHS3DPlugin_Hypothesis::GetRemoveLogOnSuccess() const
+{
+  return myRemoveLogOnSuccess;
+}
+
 //=======================================================================
 //function : SetEnforcedVertex
 //=======================================================================
 
-bool GHS3DPlugin_Hypothesis::SetEnforcedVertex(std::string theName, std::string theEntry, std::string theGroupName,
-                                               double size, double x, double y, double z, bool isCompound)
+bool GHS3DPlugin_Hypothesis::SetEnforcedVertex(std::string theName,
+                                               std::string theEntry,
+                                               std::string theGroupName,
+                                               double      size,
+                                               double x, double y, double z,
+                                               bool        isCompound)
 {
   MESSAGE("GHS3DPlugin_Hypothesis::SetEnforcedVertex(\""<< theName << "\", \""<< theEntry << "\", \"" << theGroupName << "\", "
                                                       << size << ", " << x << ", " << y << ", " << z  << ", "<< isCompound << ")");
@@ -505,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 (int 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);
@@ -580,7 +870,6 @@ bool GHS3DPlugin_Hypothesis::SetEnforcedElements(TIDSortedElemSet theElemSet, SM
             nodeRet = _enfNodes.insert(make_pair(node,groupName));
             added = added && nodeRet.second;
           }
-//          added = true;s
         }
         break;
       case SMESH::EDGE:
@@ -589,12 +878,12 @@ bool GHS3DPlugin_Hypothesis::SetEnforcedElements(TIDSortedElemSet theElemSet, SM
           added = added && elemRet.second;
         }
         else if (elem->GetType() > SMDSAbs_Edge) {
-          SMDS_ElemIteratorPtr it = elem->edgesIterator();
-          for (;it->more();) {
-            const SMDS_MeshElement* anEdge = it->next();
-            elemRet = _enfEdges.insert(make_pair(anEdge,groupName));
-            added = added && elemRet.second;
-          }
+          // SMDS_ElemIteratorPtr it = elem->edgesIterator();
+          // for (;it->more();) {
+          //   const SMDS_MeshElement* anEdge = it->next();
+          //   elemRet = _enfEdges.insert(make_pair(anEdge,groupName));
+          //   added = added && elemRet.second;
+          // }
         }
         break;
       case SMESH::FACE:
@@ -606,14 +895,14 @@ bool GHS3DPlugin_Hypothesis::SetEnforcedElements(TIDSortedElemSet theElemSet, SM
           }
         }
         else if (elem->GetType() > SMDSAbs_Face) { // Group of faces
-          SMDS_ElemIteratorPtr it = elem->facesIterator();
-          for (;it->more();) {
-            const SMDS_MeshElement* aFace = it->next();
-            if (aFace->NbCornerNodes() == 3) {
-              elemRet = _enfTriangles.insert(make_pair(aFace,groupName));
-              added = added && elemRet.second;
-            }
-          }
+          // SMDS_ElemIteratorPtr it = elem->facesIterator();
+          // for (;it->more();) {
+          //   const SMDS_MeshElement* aFace = it->next();
+          //   if (aFace->NbCornerNodes() == 3) {
+          //     elemRet = _enfTriangles.insert(make_pair(aFace,groupName));
+          //     added = added && elemRet.second;
+          //   }
+          // }
         }
         break;
       default:
@@ -631,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;
@@ -645,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];
@@ -660,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;
@@ -796,39 +1082,36 @@ bool GHS3DPlugin_Hypothesis::DefaultMeshHoles()
 
 bool GHS3DPlugin_Hypothesis::DefaultToMakeGroupsOfDomains()
 {
-  return true; // issue 0022172
+  return false; // issue 0022172
 }
 
 //=======================================================================
 //function : DefaultMaximumMemory
 //=======================================================================
 
-#ifndef WIN32
-#include <sys/sysinfo.h>
-#else
+#if defined(WIN32)
 #include <windows.h>
+#elif !defined(__APPLE__)
+#include <sys/sysinfo.h>
 #endif
 
-short  GHS3DPlugin_Hypothesis::DefaultMaximumMemory()
+float GHS3DPlugin_Hypothesis::DefaultMaximumMemory()
 {
-#ifndef WIN32
-  struct sysinfo si;
-  int err = sysinfo( &si );
-  if ( err == 0 ) {
-    int ramMB = si.totalram * si.mem_unit / 1024 / 1024;
-    return (int) ( 0.7 * ramMB );
-  }
-#else
+#if defined(WIN32)
   // See http://msdn.microsoft.com/en-us/library/aa366589.aspx
   MEMORYSTATUSEX statex;
   statex.dwLength = sizeof (statex);
-  int err = GlobalMemoryStatusEx (&statex);
+  long err = GlobalMemoryStatusEx (&statex);
   if (err != 0) {
-    int totMB = 
-      statex.ullTotalPhys / 1024 / 1024 +
-      statex.ullTotalPageFile / 1024 / 1024 +
-      statex.ullTotalVirtual / 1024 / 1024;
-    return (int) ( 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 ) {
+    double ramMB = double( si.totalram * si.mem_unit / 1024 / 1024 );
+    return float( 0.7 * ramMB );
   }
 #endif
   return 1024;
@@ -838,7 +1121,7 @@ short  GHS3DPlugin_Hypothesis::DefaultMaximumMemory()
 //function : DefaultInitialMemory
 //=======================================================================
 
-short  GHS3DPlugin_Hypothesis::DefaultInitialMemory()
+float GHS3DPlugin_Hypothesis::DefaultInitialMemory()
 {
   return DefaultMaximumMemory();
 }
@@ -847,7 +1130,7 @@ short  GHS3DPlugin_Hypothesis::DefaultInitialMemory()
 //function : DefaultOptimizationLevel
 //=======================================================================
 
-short  GHS3DPlugin_Hypothesis::DefaultOptimizationLevel()
+short GHS3DPlugin_Hypothesis::DefaultOptimizationLevel()
 {
   return Medium;
 }
@@ -883,6 +1166,16 @@ bool   GHS3DPlugin_Hypothesis::DefaultKeepFiles()
   return false;
 }
 
+//=======================================================================
+//function : DefaultRemoveLogOnSuccess
+//=======================================================================
+
+bool   GHS3DPlugin_Hypothesis::DefaultRemoveLogOnSuccess()
+{
+  return false;
+}
+
+
 //=======================================================================
 //function : DefaultVerboseLevel
 //=======================================================================
@@ -929,12 +1222,12 @@ bool GHS3DPlugin_Hypothesis::DefaultToRemoveCentralPoint()
 }
 
 //=======================================================================
-//function : DefaultGradation
+//function : DefaultStandardOutputLog
 //=======================================================================
 
-double GHS3DPlugin_Hypothesis::DefaultGradation()
+bool GHS3DPlugin_Hypothesis::DefaultStandardOutputLog()
 {
-  return 1.05;
+  return false;
 }
 
 // //=======================================================================
@@ -966,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();
@@ -997,7 +1290,7 @@ std::ostream & GHS3DPlugin_Hypothesis::SaveTo(std::ostream & save)
       }
       if (enfVertex->coords.size()) {
         save << " " << "__BEGIN_COORDS__";
-        for (int i=0;i<enfVertex->coords.size();i++)
+        for ( size_t i = 0; i < enfVertex->coords.size(); i++ )
           save << " " << enfVertex->coords[i];
         save << " " << "__END_COORDS__";
       }
@@ -1040,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;
 }
 
@@ -1053,31 +1372,31 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
   int i;
   double d;
 
-  isOK = (load >> i);
+  isOK = static_cast<bool>(load >> i);
   if (isOK)
     myToMeshHoles = i;
   else
     load.clear(ios::badbit | load.rdstate());
 
-  isOK = (load >> i);
+  isOK = static_cast<bool>(load >> d);
   if (isOK)
-    myMaximumMemory = i;
+    myMaximumMemory = float( d );
   else
     load.clear(ios::badbit | load.rdstate());
 
-  isOK = (load >> i);
+  isOK = static_cast<bool>(load >> d);
   if (isOK)
-    myInitialMemory = i;
+    myInitialMemory = float( d );
   else
     load.clear(ios::badbit | load.rdstate());
 
-  isOK = (load >> i);
+  isOK = static_cast<bool>(load >> i);
   if (isOK)
-    myOptimizationLevel = i;
+    myOptimizationLevel = (short int) i;
   else
     load.clear(ios::badbit | load.rdstate());
 
-  isOK = (load >> myWorkingDirectory);
+  isOK = static_cast<bool>(load >> myWorkingDirectory);
   if (isOK) {
     if ( myWorkingDirectory == "0") { // myWorkingDirectory was empty
       myKeepFiles = false;
@@ -1092,44 +1411,44 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
     load.clear(ios::badbit | load.rdstate());
 
   if ( !myWorkingDirectory.empty() ) {
-    isOK = (load >> i);
+    isOK = static_cast<bool>(load >> i);
     if (isOK)
       myKeepFiles = i;
     else
       load.clear(ios::badbit | load.rdstate());
   }
 
-  isOK = (load >> i);
+  isOK = static_cast<bool>(load >> i);
   if (isOK)
     myVerboseLevel = (short) i;
   else
     load.clear(ios::badbit | load.rdstate());
 
-  isOK = (load >> i);
+  isOK = static_cast<bool>(load >> i);
   if (isOK)
     myToCreateNewNodes = (bool) i;
   else
     load.clear(ios::badbit | load.rdstate());
 
-  isOK = (load >> i);
+  isOK = static_cast<bool>(load >> i);
   if (isOK)
     myToUseBoundaryRecoveryVersion = (bool) i;
   else
     load.clear(ios::badbit | load.rdstate());
 
-  isOK = (load >> i);
+  isOK = static_cast<bool>(load >> i);
   if (isOK)
     myToUseFemCorrection = (bool) i;
   else
     load.clear(ios::badbit | load.rdstate());
 
-  isOK = (load >> i);
+  isOK = static_cast<bool>(load >> i);
   if (isOK)
     myToRemoveCentralPoint = (bool) i;
   else
     load.clear(ios::badbit | load.rdstate());
 
-  isOK = (load >> d);
+  isOK = static_cast<bool>(load >> d);
   if (isOK)
     myGradation = d;
   else
@@ -1139,12 +1458,12 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
   bool hasOptions = false;
   bool hasEnforcedVertices = false;
   bool hasEnforcedMeshes = false;
-  isOK = (load >> separator);
+  isOK = static_cast<bool>(load >> separator);
 
   if ( isOK && ( separator == "0" || separator == "1" ))
   {
     myToMakeGroupsOfDomains = ( separator == "1" );
-    isOK = (load >> separator);
+    isOK = static_cast<bool>(load >> separator);
   }
 
   if (isOK) {
@@ -1159,24 +1478,24 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
   if (hasOptions) {
     std::string txt;
     while (isOK) {
-      isOK = (load >> txt);
+      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 += " ";
       }
     }
   }
 
   if (hasOptions) {
-    isOK = (load >> separator);
+    isOK = static_cast<bool>(load >> separator);
     if (isOK && separator == "__ENFORCED_VERTICES_BEGIN__")
       hasEnforcedVertices = true;
     if (isOK && separator == "__ENFORCED_MESHES_BEGIN__")
@@ -1188,14 +1507,16 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
     double size, coords[3];
     bool isCompound;
     bool hasCoords = false;
-    isOK = (load >> txt);  // __BEGIN_VERTEX__
+    isOK = static_cast<bool>(load >> txt);  // __BEGIN_VERTEX__
     while (isOK) {
-      if (txt == "__ENFORCED_VERTICES_END__")
-        isOK = false;
-
+      if (txt == "__ENFORCED_VERTICES_END__") {
+        //isOK = false;
+        break;
+      }
+      
       TGHS3DEnforcedVertex *enfVertex = new TGHS3DEnforcedVertex();
       while (isOK) {
-        isOK = (load >> txt);
+        isOK = static_cast<bool>(load >> txt);
         if (txt == "__END_VERTEX__") {
           enfVertex->name = name;
           enfVertex->geomEntry = entry;
@@ -1221,7 +1542,7 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
 
         if (txt == "__BEGIN_NAME__") {  // __BEGIN_NAME__
           while (isOK && (txt != "__END_NAME__")) {
-            isOK = (load >> txt);
+            isOK = static_cast<bool>(load >> txt);
             if (txt != "__END_NAME__") {
               if (!name.empty())
                 name += " ";
@@ -1232,9 +1553,9 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
         }
 
         if (txt == "__BEGIN_ENTRY__") {  // __BEGIN_ENTRY__
-          isOK = (load >> entry);
-          isOK = (load >> isCompound);
-          isOK = (load >> txt); // __END_ENTRY__
+          isOK = static_cast<bool>(load >> entry);
+          isOK = static_cast<bool>(load >> isCompound);
+          isOK = static_cast<bool>(load >> txt); // __END_ENTRY__
           if (txt != "__END_ENTRY__")
             throw std::exception();
           MESSAGE("entry: " << entry);
@@ -1242,7 +1563,7 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
 
         if (txt == "__BEGIN_GROUP__") {  // __BEGIN_GROUP__
           while (isOK && (txt != "__END_GROUP__")) {
-            isOK = (load >> txt);
+            isOK = static_cast<bool>(load >> txt);
             if (txt != "__END_GROUP__") {
               if (!groupName.empty())
                 groupName += " ";
@@ -1254,28 +1575,28 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
 
         if (txt == "__BEGIN_COORDS__") {  // __BEGIN_COORDS__
           hasCoords = true;
-          isOK = (load >> coords[0] >> coords[1] >> coords[2]);
-          isOK = (load >> txt); // __END_COORDS__
+          isOK = static_cast<bool>(load >> coords[0] >> coords[1] >> coords[2]);
+          isOK = static_cast<bool>(load >> txt); // __END_COORDS__
           if (txt != "__END_COORDS__")
             throw std::exception();
           MESSAGE("coords: " << coords[0] <<","<< coords[1] <<","<< coords[2]);
         }
 
         if (txt == "__BEGIN_SIZE__") {  // __BEGIN_ENTRY__
-          isOK = (load >> size);
-          isOK = (load >> txt); // __END_ENTRY__
+          isOK = static_cast<bool>(load >> size);
+          isOK = static_cast<bool>(load >> txt); // __END_ENTRY__
           if (txt != "__END_SIZE__") {
             throw std::exception();
           }
           MESSAGE("size: " << size);
         }
       }
-      isOK = (load >> txt);  // __BEGIN_VERTEX__
+      isOK = static_cast<bool>(load >> txt);  // __BEGIN_VERTEX__
     }
   }
 
   if (hasEnforcedVertices) {
-    isOK = (load >> separator);
+    isOK = static_cast<bool>(load >> separator);
     if (isOK && separator == "__ENFORCED_MESHES_BEGIN__")
       hasEnforcedMeshes = true;
   }
@@ -1283,7 +1604,7 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
   if (hasEnforcedMeshes) {
     std::string txt, name, entry, groupName;
     int elementType = -1, persistID = -1;
-    isOK = (load >> txt);  // __BEGIN_ENF_MESH__
+    isOK = static_cast<bool>(load >> txt);  // __BEGIN_ENF_MESH__
     while (isOK) {
       //                if (isOK) {
       if (txt == "__ENFORCED_MESHES_END__")
@@ -1291,7 +1612,7 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
 
       TGHS3DEnforcedMesh *enfMesh = new TGHS3DEnforcedMesh();
       while (isOK) {
-        isOK = (load >> txt);
+        isOK = static_cast<bool>(load >> txt);
         if (txt == "__END_ENF_MESH__") {
           enfMesh->name = name;
           enfMesh->entry = entry;
@@ -1300,7 +1621,7 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
           enfMesh->persistID = persistID;
 
           _enfMeshList.insert(enfMesh);
-          std::cout << "Restoring of enforced mesh " <<name  << " done" << std::endl;
+          //std::cout << "Restoring of enforced mesh " <<name  << " done" << std::endl;
 
           name.clear();
           entry.clear();
@@ -1312,7 +1633,7 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
 
         if (txt == "__BEGIN_NAME__") {  // __BEGIN_NAME__
           while (isOK && (txt != "__END_NAME__")) {
-            isOK = (load >> txt);
+            isOK = static_cast<bool>(load >> txt);
             if (txt != "__END_NAME__") {
               if (!name.empty())
                 name += " ";
@@ -1323,16 +1644,16 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
         }
 
         if (txt == "__BEGIN_ENTRY__") {  // __BEGIN_ENTRY__
-          isOK = (load >> entry);
-          isOK = (load >> txt); // __END_ENTRY__
+          isOK = static_cast<bool>(load >> entry);
+          isOK = static_cast<bool>(load >> txt); // __END_ENTRY__
           if (txt != "__END_ENTRY__")
             throw std::exception();
           MESSAGE("entry: " << entry);
         }
 
         if (txt == "__BEGIN_ELEM_TYPE__") {  // __BEGIN_ELEM_TYPE__
-          isOK = (load >> elementType);
-          isOK = (load >> txt); // __END_ELEM_TYPE__
+          isOK = static_cast<bool>(load >> elementType);
+          isOK = static_cast<bool>(load >> txt); // __END_ELEM_TYPE__
           if (txt != "__END_ELEM_TYPE__")
             throw std::exception();
           MESSAGE("elementType: " << elementType);
@@ -1340,7 +1661,7 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
 
         if (txt == "__BEGIN_GROUP__") {  // __BEGIN_GROUP__
           while (isOK && (txt != "__END_GROUP__")) {
-            isOK = (load >> txt);
+            isOK = static_cast<bool>(load >> txt);
             if (txt != "__END_GROUP__") {
               if (!groupName.empty())
                 groupName += " ";
@@ -1351,16 +1672,79 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
         } // if
 
         if (txt == "__PERSIST_ID__") {
-          isOK = (load >> persistID);
+          isOK = static_cast<bool>(load >> persistID);
           MESSAGE("persistID: " << persistID);
         }
-        std::cout << "isOK: " << isOK << std::endl;
+        //std::cout << "isOK: " << isOK << std::endl;
       } // while
       //                } // if
-      isOK = (load >> txt);  // __BEGIN_ENF_MESH__
+      isOK = static_cast<bool>(load >> txt);  // __BEGIN_ENF_MESH__
     } // 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;
 }
 
@@ -1380,138 +1764,205 @@ bool GHS3DPlugin_Hypothesis::SetParametersByMesh(const SMESH_Mesh* ,const TopoDS
  */
 //================================================================================
 
-bool GHS3DPlugin_Hypothesis::SetParametersByDefaults(const TDefaults&  /*dflts*/,
-                                                     const SMESH_Mesh* theMesh)
+bool GHS3DPlugin_Hypothesis::SetParametersByDefaults(const TDefaults&  dflts,
+                                                     const SMESH_Mesh* /*theMesh*/)
 {
-  myToMakeGroupsOfDomains = ( !theMesh || !theMesh->HasShapeToMesh() );
+  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 ghs3d mesher excluding file prefix (-f)
+ * \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                    hasShapeToMesh,
+                                                 const bool                    forExecutable)
 {
-  TCollection_AsciiString cmd = GetExeName().c_str();
+  GHS3DPlugin_Hypothesis::ImplementedAlgorithms algoId = hyp ? (ImplementedAlgorithms) hyp->myAlgorithm : MGTetra;
+  std::string cmd = GetExeName( algoId );
+  
   // check if any option is overridden by hyp->myTextOption
-  bool m   = hyp ? ( hyp->myTextOption.find("-m")  == std::string::npos ) : true;
-  bool M   = hyp ? ( hyp->myTextOption.find("-M")  == std::string::npos ) : true;
-  bool c   = hyp ? ( hyp->myTextOption.find("-c")  == std::string::npos ) : true;
-  bool o   = hyp ? ( hyp->myTextOption.find("-o")  == std::string::npos ) : true;
-  bool p0  = hyp ? ( hyp->myTextOption.find("-p0") == std::string::npos ) : true;
-  bool C   = hyp ? ( hyp->myTextOption.find("-C")  == std::string::npos ) : true;
-  bool v   = hyp ? ( hyp->myTextOption.find("-v")  == 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;
   if ( !useBndRecovery && hyp )
     useBndRecovery = hyp->myToUseBoundaryRecoveryVersion;
 
-  // ghs3d needs to know amount of memory it may use (MB).
-  // Default memory is defined at ghs3d installation but it may be not enough,
-  // so allow to use about all available memory
-  if ( m ) {
-    short aMaximumMemory = hyp ? hyp->myMaximumMemory : -1;
-    cmd += " -m ";
-    if ( aMaximumMemory < 0 )
-      cmd += DefaultMaximumMemory();
-    else
-      cmd += aMaximumMemory;
+  // 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 ( 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 ( M && !useBndRecovery ) {
-    short aInitialMemory = hyp ? hyp->myInitialMemory : -1;
-    cmd += " -M ";
-    if ( aInitialMemory > 0 )
-      cmd += aInitialMemory;
-    else
-      cmd += "100";
+  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
-  // 0 , all components to be meshed
-  // 1 , only the main ( outermost ) component to be meshed
-  if ( c && !useBndRecovery ) {
-    // We always run GHS3D with "to mesh holes'==TRUE (see PAL19680)
+  if ( comp && !useBndRecovery ) {
+    // We always run MG-Tetra with "to mesh holes'==TRUE (see PAL19680)
     if ( hasShapeToMesh )
-      cmd += " -c 0";
+      cmd += " --components all";
     else {
       bool aToMeshHoles = hyp ? hyp->myToMeshHoles : DefaultMeshHoles();
-      if ( aToMeshHoles )
-        cmd += " -c 0";
-      else
-        cmd += " -c 1";
+      if ( aToMeshHoles ) cmd += " --components all";
+      else                cmd += " --components outside_components";
     }
   }
+  const bool toCreateNewNodes = ( no_int_points && ( !hyp || hyp->myToCreateNewNodes ));
 
   // optimization level
-  if ( o && hyp && !useBndRecovery ) {
-    if ( hyp->myOptimizationLevel >= 0 && hyp->myOptimizationLevel < 5 ) {
-      const char* level[] = { "none" , "light" , "standard" , "standard+" , "strong" };
-      cmd += " -o ";
-      cmd += level[ hyp->myOptimizationLevel ];
-    }
+  if ( !toCreateNewNodes ) {
+    cmd += " --optimisation_level none"; // issue 22608
+  }
+  else if ( optim_level && hyp && !useBndRecovery ) {
+    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
-  if ( p0 && hyp && !hyp->myToCreateNewNodes ) {
-    cmd += " -p0";
+  if ( no_int_points && !toCreateNewNodes ) {
+    if ( forExecutable )
+      cmd += " --no_internal_points";
+    else
+      cmd += " --internalpoints no";
   }
 
-  // verbose mode
-  if ( v && hyp ) {
-    cmd += " -v ";
-    cmd += hyp->myVerboseLevel;
-  }
+  if ( hyp ) 
+  {
+    // verbose mode
+    if ( verbose ) {
+      cmd += " --verbose " + SMESH_Comment( hyp->myVerboseLevel );
+    }
 
-  // boundary recovery version
-  if ( useBndRecovery ) {
-    cmd += " -C";
-  }
+    // to remove initial central point.
+    if ( rem && hyp->myToRemoveCentralPoint ) {
+      if ( forExecutable )
+        cmd += " --no_initial_central_point";
+      else
+        cmd += " --centralpoint no";
+    }
 
-  // to use FEM correction
-  if ( fem && hyp && hyp->myToUseFemCorrection) {
-    cmd += " -FEM";
-  }
+    if ( hyp->GetMinSize() > 0 )
+      cmd += " --min_size " + SMESH_Comment( hyp->GetMinSize() );
 
-  // to remove initial central point.
-  if ( rem && hyp && hyp->myToRemoveCentralPoint) {
-    cmd += " -no_initial_central_point";
-  }
+    if ( hyp->GetMaxSize() > 0 )
+      cmd += " --max_size " + SMESH_Comment( hyp->GetMaxSize() );
 
-  // options as text
-  if ( hyp && !hyp->myTextOption.empty() ) {
-    cmd += " ";
-    cmd += (char*) hyp->myTextOption.c_str();
-  }
+    // 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 ];
+      }
+    }
 
-  // to define volumic gradation.
-  if ( gra && hyp) {
-    cmd += " -Dcpropa=";
-    cmd += hyp->myGradation;
+    // proximity
+    if ( hyp->GetUseVolumeProximity() )
+    {
+      cmd += " --volume_proximity_layers " + SMESH_Comment( hyp->GetNbVolumeProximityLayers() );
+    }
+    
+    hyp->SetAdvancedOptionsInCommandLine( cmd );
   }
 
-#ifdef WNT
+#ifdef WIN32
   cmd += " < NUL";
 #endif
-
-  return cmd.ToCString();
+  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+='\\';
@@ -1528,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: ");
+  }
 }
 
 //================================================================================
@@ -1547,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;
+}
+