Salome HOME
0022172: [CEA 790] create the groups corresponding to domains
[plugins/hybridplugin.git] / src / GHS3DPlugin / GHS3DPlugin_GHS3D.cxx
index 68d805e965c000b3be4ac26f6181901c39b76677..76629fa055851e50dd8b946edba74175447097b5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2004-2012  CEA/DEN, EDF R&D
+// Copyright (C) 2004-2013  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
 
 #include <Basics_Utils.hxx>
 
-//#include "SMESH_Gen.hxx"
+//#include <SMESH_Gen.hxx>
 #include <SMESH_Client.hxx>
-#include "SMESH_Mesh.hxx"
-#include "SMESH_Comment.hxx"
-#include "SMESH_MesherHelper.hxx"
-#include "SMESH_MeshEditor.hxx"
-#include "SMESH_OctreeNode.hxx"
-#include "SMESH_Group.hxx"
-
-#include "SMDS_MeshElement.hxx"
-#include "SMDS_MeshNode.hxx"
-#include "SMDS_FaceOfNodes.hxx"
-#include "SMDS_VolumeOfNodes.hxx"
-
-#include "SMESHDS_Group.hxx"
+#include <SMESH_Mesh.hxx>
+#include <SMESH_Comment.hxx>
+#include <SMESH_MesherHelper.hxx>
+#include <SMESH_MeshEditor.hxx>
+#include <SMESH_OctreeNode.hxx>
+#include <SMESH_Group.hxx>
+#include <SMESH_subMeshEventListener.hxx>
+#include <SMESH_HypoFilter.hxx>
+#include <SMESH_MeshAlgos.hxx>
+
+#include <SMDS_MeshElement.hxx>
+#include <SMDS_MeshNode.hxx>
+#include <SMDS_FaceOfNodes.hxx>
+#include <SMDS_VolumeOfNodes.hxx>
+
+#include <SMESHDS_Group.hxx>
 
 #include <StdMeshers_QuadToTriaAdaptor.hxx>
 #include <StdMeshers_ViscousLayers.hxx>
@@ -74,7 +77,7 @@
 #include <TopoDS_Shape.hxx>
 #include <TopoDS_Solid.hxx>
 
-#include "utilities.h"
+#include <utilities.h>
 
 #ifdef WIN32
 #include <io.h>
@@ -107,12 +110,10 @@ extern "C"
 
 #define HOLE_ID -1
 
-#ifndef GHS3D_VERSION
-#define GHS3D_VERSION 41
-#endif
-
 typedef const list<const SMDS_MeshFace*> TTriaList;
 
+static const char theDomainGroupNamePrefix[] = "Domain_";
+
 static void removeFile( const TCollection_AsciiString& fileName )
 {
   try {
@@ -133,7 +134,7 @@ GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D(int hypId, int studyId, SMESH_Gen* gen)
   : SMESH_3D_Algo(hypId, studyId, gen)
 {
   MESSAGE("GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D");
-  _name = "GHS3D_3D";
+  _name = Name();
   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type
   _onlyUnaryInput = false; // Compute() will be called on a compound of solids
   _iShape=0;
@@ -153,9 +154,7 @@ GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D(int hypId, int studyId, SMESH_Gen* gen)
   if (myStudy)
     MESSAGE("myStudy->StudyId() = " << myStudy->StudyId());
   
-#ifdef WITH_SMESH_CANCEL_COMPUTE
   _compute_canceled = false;
-#endif
 }
 
 //=============================================================================
@@ -213,13 +212,10 @@ TopoDS_Shape GHS3DPlugin_GHS3D::entryToShape(std::string entry)
   GEOM::GEOM_Object_var aGeomObj;
   TopoDS_Shape S = TopoDS_Shape();
   SALOMEDS::SObject_var aSObj = myStudy->FindObjectID( entry.c_str() );
-  SALOMEDS::GenericAttribute_var anAttr;
-
-  if (!aSObj->_is_nil() && aSObj->FindAttribute(anAttr, "AttributeIOR")) {
-    SALOMEDS::AttributeIOR_var anIOR = SALOMEDS::AttributeIOR::_narrow(anAttr);
-    CORBA::String_var aVal = anIOR->Value();
-    CORBA::Object_var obj = myStudy->ConvertIORToObject(aVal);
+  if (!aSObj->_is_nil() ) {
+    CORBA::Object_var obj = aSObj->GetObject();
     aGeomObj = GEOM::GEOM_Object::_narrow(obj);
+    aSObj->UnRegister();
   }
   if ( !aGeomObj->_is_nil() )
     S = smeshGen_i->GeomObjectToShape( aGeomObj.in() );
@@ -479,11 +475,11 @@ static int findShapeID(SMESH_Mesh&          mesh,
     return meshDS->ShapeToIndex( solids(2) );
 }
 
-//=======================================================================
-//function : countShape
-//purpose  :
-//=======================================================================
-
+// //=======================================================================
+// //function : countShape
+// //purpose  :
+// //=======================================================================
+// 
 // template < class Mesh, class Shape >
 // static int countShape( Mesh* mesh, Shape shape ) {
 //   TopExp_Explorer expShape ( mesh->ShapeToMesh(), shape );
@@ -496,12 +492,12 @@ static int findShapeID(SMESH_Mesh&          mesh,
 //   }
 //   return nbShape;
 // }
-
-//=======================================================================
-//function : getShape
-//purpose  :
-//=======================================================================
-
+// 
+// //=======================================================================
+// //function : getShape
+// //purpose  :
+// //=======================================================================
+// 
 // template < class Mesh, class Shape, class Tab >
 // void getShape(Mesh* mesh, Shape shape, Tab *t_Shape) {
 //   TopExp_Explorer expShape ( mesh->ShapeToMesh(), shape );
@@ -514,11 +510,11 @@ static int findShapeID(SMESH_Mesh&          mesh,
 //   }
 //   return;
 // }
-
-// //=======================================================================
-// //function : findEdgeID
-// //purpose  :
-// //=======================================================================
+// 
+// // //=======================================================================
+// // //function : findEdgeID
+// // //purpose  :
+// // //=======================================================================
 // 
 // static int findEdgeID(const SMDS_MeshNode* aNode,
 //                       const SMESHDS_Mesh*  theMesh,
@@ -552,16 +548,14 @@ static int findShapeID(SMESH_Mesh&          mesh,
 //   delete [] t_Dist;
 //   return theMesh->ShapeToIndex( foundEdge );
 // }
-
-
-//=======================================================================
-//function : readGMFFile
-//purpose  : read GMF file with geometry associated to mesh
-// TODO
-//=======================================================================
-
-// static bool readGMFFile(
-//                         const int                       fileOpen,
+// 
+// 
+// // =======================================================================
+// // function : readGMFFile
+// // purpose  : read GMF file with geometry associated to mesh
+// // =======================================================================
+// 
+// static bool readGMFFile(const int                       fileOpen,
 //                         const char*                     theFileName, 
 //                         SMESH_Mesh&                     theMesh,
 //                         const int                       nbShape,
@@ -644,7 +638,7 @@ static int findShapeID(SMESH_Mesh&          mesh,
 // 
 //   
 //   // The keyword does not exist yet => to update when it is created
-// //   int nbTriangle = GmfStatKwd(InpMsh, GmfSubdomain);
+// //   int nbSubdomains = GmfStatKwd(InpMsh, GmfSubdomain);
 // //   int id_tri[3];
 // 
 // 
@@ -828,11 +822,11 @@ static int findShapeID(SMESH_Mesh&          mesh,
 // //     case GmfHexahedra:
 //     {
 //       int nodeDim, shapeID, *nodeID;
-//       SMDS_MeshNode** node;
+//       const SMDS_MeshNode** node;
 // //       std::vector< SMDS_MeshNode* > enfNode( nbRef );
 //       SMDS_MeshElement * aGMFElement;
 //       
-//       node    = new SMDS_MeshNode*[nbRef];
+//       node    = new const SMDS_MeshNode*[nbRef];
 //       nodeID  = new int[ nbRef ];
 // 
 //       for ( int iElem = 0; iElem < nbElem; iElem++ )
@@ -1061,15 +1055,45 @@ static void updateMeshGroups(SMESH_Mesh* theMesh, std::set<std::string> groupsTo
   }
 }
 
+//=======================================================================
+//function : removeEmptyGroupsOfDomains
+//purpose  : remove empty groups named "Domain_nb" created due to
+//           "To make groups of domains" option.
+//=======================================================================
+
+static void removeEmptyGroupsOfDomains(SMESH_Mesh* mesh,
+                                       bool        notEmptyAsWell = false)
+{
+  const char* refName = theDomainGroupNamePrefix;
+  const size_t refLen = strlen( theDomainGroupNamePrefix );
+
+  std::list<int> groupIDs = mesh->GetGroupIds();
+  std::list<int>::const_iterator id = groupIDs.begin();
+  for ( ; id != groupIDs.end(); ++id )
+  {
+    SMESH_Group* group = mesh->GetGroup( *id );
+    if ( !group || ( !group->GetGroupDS()->IsEmpty() && !notEmptyAsWell ))
+      continue;
+    const char* name = group->GetName();
+    char* end;
+    // check the name
+    if ( strncmp( name, refName, refLen ) == 0 && // starts from refName;
+         isdigit( *( name + refLen )) &&          // refName is followed by a digit;
+         strtol( name + refLen, &end, 10) &&      // there are only digits ...
+         *end == '\0')                            // ... till a string end.
+    {
+      mesh->RemoveGroup( *id );
+    }
+  }
+}
+
 //=======================================================================
 //function : readGMFFile
 //purpose  : read GMF file w/o geometry associated to mesh
 //=======================================================================
 
 static bool readGMFFile(const char*                     theFile,
-#ifdef WITH_SMESH_CANCEL_COMPUTE
                         GHS3DPlugin_GHS3D*              theAlgo,
-#endif 
                         SMESH_MesherHelper*             theHelper,
                         TopoDS_Shape                    theSolid,
                         vector <const SMDS_MeshNode*> & theNodeByGhs3dId,
@@ -1077,8 +1101,8 @@ static bool readGMFFile(const char*                     theFile,
                         std::vector<std::string> &      aNodeGroupByGhs3dId,
                         std::vector<std::string> &      anEdgeGroupByGhs3dId,
                         std::vector<std::string> &      aFaceGroupByGhs3dId,
-                        std::set<std::string> &         groupsToRemove
-                       )
+                        std::set<std::string> &         groupsToRemove,
+                        bool                            toMakeGroupsOfDomains=false)
 {
   std::string tmpStr;
   SMESHDS_Mesh* theMeshDS = theHelper->GetMeshDS();
@@ -1105,13 +1129,14 @@ static bool readGMFFile(const char*                     theFile,
   // ---------------------------------
 
   int nbElem = 0, nbRef = 0;
-  int aGMFNodeID = 0/*, shapeID*/;
-  //int *nodeAssigne;
+  int aGMFNodeID = 0;
   const SMDS_MeshNode** GMFNode;
 #ifdef _DEBUG_
   std::map<int, std::set<int> > subdomainId2tetraId;
 #endif
   std::map <GmfKwdCod,int> tabRef;
+  const bool force3d = true; // since there is no geometry
+  const int  noID  = 0;
 
   tabRef[GmfVertices]       = 3; // for new nodes and enforced nodes
   tabRef[GmfCorners]        = 1;
@@ -1132,28 +1157,27 @@ static bool readGMFFile(const char*                     theFile,
   // Issue 0020682. Avoid creating nodes and tetras at place where
   // volumic elements already exist
   SMESH_ElementSearcher* elemSearcher = 0;
-  vector< const SMDS_MeshElement* > foundVolumes;
+  std::vector< const SMDS_MeshElement* > foundVolumes;
   if ( theHelper->GetMesh()->NbVolumes() > 0 )
-    elemSearcher = SMESH_MeshEditor( theHelper->GetMesh() ).GetElementSearcher();
+    elemSearcher = SMESH_MeshAlgos::GetElementSearcher( *theHelper->GetMeshDS() );
+
+  // IMP 0022172: [CEA 790] create the groups corresponding to domains
+  std::vector< std::vector< const SMDS_MeshElement* > > elemsOfDomain;
 
   int nbVertices = GmfStatKwd(InpMsh, GmfVertices) - nbInitialNodes;
   GMFNode = new const SMDS_MeshNode*[ nbVertices + 1 ];
-  //nodeAssigne = new int[ nbVertices + 1 ];
 
   std::map <GmfKwdCod,int>::const_iterator it = tabRef.begin();
   for ( ; it != tabRef.end() ; ++it)
   {
-#ifdef WITH_SMESH_CANCEL_COMPUTE
     if(theAlgo->computeCanceled()) {
       GmfCloseMesh(InpMsh);
       delete [] GMFNode;
-      //delete [] nodeAssigne;
       return false;
     }
-#endif
     int dummy;
     GmfKwdCod token = it->first;
-    nbRef    = it->second;
+    nbRef           = it->second;
 
     nbElem = GmfStatKwd(InpMsh, token);
     if (nbElem > 0) {
@@ -1164,6 +1188,7 @@ static bool readGMFFile(const char*                     theFile,
       continue;
 
     std::vector<int> id (nbElem*tabRef[token]); // node ids
+    std::vector<int> domainID( nbElem ); // domain
 
     if (token == GmfVertices) {
       (nbElem <= 1) ? tmpStr = " vertex" : tmpStr = " vertices";
@@ -1188,16 +1213,12 @@ static bool readGMFFile(const char*                     theFile,
       double x, y, z;
       const SMDS_MeshNode * aGMFNode;
 
-      //shapeID = theMeshDS->ShapeToIndex( theSolid );
       for ( int iElem = 0; iElem < nbElem; iElem++ ) {
-#ifdef WITH_SMESH_CANCEL_COMPUTE
         if(theAlgo->computeCanceled()) {
           GmfCloseMesh(InpMsh);
           delete [] GMFNode;
-          //delete [] nodeAssigne;
           return false;
         }
-#endif
         if (ver == GmfFloat) {
           GmfGetLin(InpMsh, token, &VerTab_f[0], &VerTab_f[1], &VerTab_f[2], &dummy);
           x = VerTab_f[0];
@@ -1216,7 +1237,6 @@ static bool readGMFFile(const char*                     theFile,
           
           aGMFID = iElem -nbInitialNodes +1;
           GMFNode[ aGMFID ] = aGMFNode;
-          //nodeAssigne[ aGMFID ] = 0;
           if (aGMFID-1 < aNodeGroupByGhs3dId.size() && !aNodeGroupByGhs3dId.at(aGMFID-1).empty())
             addElemInMeshGroup(theHelper->GetMesh(), aGMFNode, aNodeGroupByGhs3dId.at(aGMFID-1), groupsToRemove);
         }
@@ -1235,22 +1255,22 @@ static bool readGMFFile(const char*                     theFile,
     else if (token == GmfEdges && nbElem > 0) {
       (nbElem <= 1) ? tmpStr = " edge" : tmpStr = " edges";
       for ( int iElem = 0; iElem < nbElem; iElem++ )
-        GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &dummy);
+        GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &domainID[iElem]);
     }
     else if (token == GmfTriangles && nbElem > 0) {
       (nbElem <= 1) ? tmpStr = " triangle" : tmpStr = " triangles";
       for ( int iElem = 0; iElem < nbElem; iElem++ )
-        GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &dummy);
+        GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &domainID[iElem]);
     }
     else if (token == GmfQuadrilaterals && nbElem > 0) {
       (nbElem <= 1) ? tmpStr = " Quadrilateral" : tmpStr = " Quadrilaterals";
       for ( int iElem = 0; iElem < nbElem; iElem++ )
-        GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &id[iElem*tabRef[token]+3], &dummy);
+        GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &id[iElem*tabRef[token]+3], &domainID[iElem]);
     }
     else if (token == GmfTetrahedra && nbElem > 0) {
       (nbElem <= 1) ? tmpStr = " Tetrahedron" : tmpStr = " Tetrahedra";
       for ( int iElem = 0; iElem < nbElem; iElem++ ) {
-        GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &id[iElem*tabRef[token]+3], &dummy);
+        GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &id[iElem*tabRef[token]+3], &domainID[iElem]);
 #ifdef _DEBUG_
         subdomainId2tetraId[dummy].insert(iElem+1);
 //         MESSAGE("subdomainId2tetraId["<<dummy<<"].insert("<<iElem+1<<")");
@@ -1261,7 +1281,7 @@ static bool readGMFFile(const char*                     theFile,
       (nbElem <= 1) ? tmpStr = " Hexahedron" : tmpStr = " Hexahedra";
       for ( int iElem = 0; iElem < nbElem; iElem++ )
         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &id[iElem*tabRef[token]+3],
-                  &id[iElem*tabRef[token]+4], &id[iElem*tabRef[token]+5], &id[iElem*tabRef[token]+6], &id[iElem*tabRef[token]+7], &dummy);
+                  &id[iElem*tabRef[token]+4], &id[iElem*tabRef[token]+5], &id[iElem*tabRef[token]+6], &id[iElem*tabRef[token]+7], &domainID[iElem]);
     }
     std::cout << tmpStr << std::endl;
     std::cout << std::endl;
@@ -1282,14 +1302,11 @@ static bool readGMFFile(const char*                     theFile,
 
       for ( int iElem = 0; iElem < nbElem; iElem++ )
       {
-#ifdef WITH_SMESH_CANCEL_COMPUTE
         if(theAlgo->computeCanceled()) {
           GmfCloseMesh(InpMsh);
           delete [] GMFNode;
-          //delete [] nodeAssigne;
           return false;
         }
-#endif
         // Check if elem is already in input mesh. If yes => skip
         bool fullyCreatedElement = false; // if at least one of the nodes was created
         for ( int iRef = 0; iRef < nbRef; iRef++ )
@@ -1308,30 +1325,26 @@ static bool readGMFFile(const char*                     theFile,
             node  [ iRef ] = GMFNode[ aGMFNodeID ];
           }
         }
-
+        aCreatedElem = 0;
         switch (token)
         {
         case GmfEdges:
           if (fullyCreatedElement) {
-            aCreatedElem = theHelper->AddEdge( node[0], node[1], /*id =*/0, /*force3d =*/false );
+            aCreatedElem = theHelper->AddEdge( node[0], node[1], noID, force3d );
             if (anEdgeGroupByGhs3dId.size() && !anEdgeGroupByGhs3dId[iElem].empty())
               addElemInMeshGroup(theHelper->GetMesh(), aCreatedElem, anEdgeGroupByGhs3dId[iElem], groupsToRemove);
           }
           break;
         case GmfTriangles:
           if (fullyCreatedElement) {
-            aCreatedElem = theHelper->AddFace( node[0], node[1], node[2], /*id =*/0, /*force3d =*/false );
-            // for ( int iRef = 0; iRef < nbRef; iRef++ )
-            //   nodeAssigne[ nodeID[ iRef ]] = 1;
+            aCreatedElem = theHelper->AddFace( node[0], node[1], node[2], noID, force3d );
             if (aFaceGroupByGhs3dId.size() && !aFaceGroupByGhs3dId[iElem].empty())
               addElemInMeshGroup(theHelper->GetMesh(), aCreatedElem, aFaceGroupByGhs3dId[iElem], groupsToRemove);
           }
           break;
         case GmfQuadrilaterals:
           if (fullyCreatedElement) {
-            theHelper->AddFace( node[0], node[1], node[2], node[3], /*id =*/0, /*force3d =*/false );
-            // for ( int iRef = 0; iRef < nbRef; iRef++ )
-            //   nodeAssigne[ nodeID[ iRef ]] = 1;
+            aCreatedElem = theHelper->AddFace( node[0], node[1], node[2], node[3], noID, force3d );
           }
           break;
         case GmfTetrahedra:
@@ -1347,8 +1360,7 @@ static bool readGMFFile(const char*                     theFile,
                                                     SMDSAbs_Volume, foundVolumes ))
             break;
           }
-          theHelper->AddVolume( node[1], node[0], node[2], node[3], /*id =*/0, /*force3d =*/false );
-//           theMeshDS->SetMeshElementOnShape( aTet, shapeID );
+          aCreatedElem = theHelper->AddVolume( node[1], node[0], node[2], node[3], noID, force3d );
           break;
         case GmfHexahedra:
           if ( elemSearcher ) {
@@ -1367,27 +1379,70 @@ static bool readGMFFile(const char*                     theFile,
                                                     SMDSAbs_Volume, foundVolumes ))
             break;
           }
-          theHelper->AddVolume( node[0], node[3], node[2], node[1],
-                                node[4], node[7], node[6], node[5], /*id =*/0, /*force3d =*/false );
-//           theMeshDS->SetMeshElementOnShape( aTet, shapeID );
+          aCreatedElem = theHelper->AddVolume( node[0], node[3], node[2], node[1],
+                                               node[4], node[7], node[6], node[5], noID, force3d );
           break;
         default: continue;
         }
-      }
+        if ( aCreatedElem && toMakeGroupsOfDomains )
+        {
+          if ( domainID[iElem] >= (int) elemsOfDomain.size() )
+            elemsOfDomain.resize( domainID[iElem] + 1 );
+          elemsOfDomain[ domainID[iElem] ].push_back( aCreatedElem );
+        }
+      } // loop on elements of one type
       break;
-    }
-    }
-  }
-
-  // for ( int i = 0; i < nbVertices; ++i ) {
-  //   if ( !nodeAssigne[ i+1 ])
-  //     theMeshDS->SetNodeInVolume( GMFNode[ i+1 ], shapeID );
-  // }
+    } // case ...
+    } // switch (token)
+  } // loop on tabRef
 
   GmfCloseMesh(InpMsh);
   delete [] GMFNode;
-  //delete [] nodeAssigne;
-#ifdef _DEBUG_  
+
+  // 0022172: [CEA 790] create the groups corresponding to domains
+  if ( toMakeGroupsOfDomains )
+  {
+    int nbDomains = 0;
+    for ( size_t i = 0; i < elemsOfDomain.size(); ++i )
+      nbDomains += ( elemsOfDomain[i].size() > 0 );
+
+    if ( nbDomains > 1 )
+      for ( size_t iDomain = 0; iDomain < elemsOfDomain.size(); ++iDomain )
+      {
+        std::vector< const SMDS_MeshElement* > & elems = elemsOfDomain[ iDomain ];
+        if ( elems.empty() ) continue;
+
+        // find existing groups
+        std::vector< SMESH_Group* > groupOfType( SMDSAbs_NbElementTypes, (SMESH_Group*)NULL );
+        const std::string domainName = ( SMESH_Comment( theDomainGroupNamePrefix ) << iDomain );
+        SMESH_Mesh::GroupIteratorPtr groupIt = theHelper->GetMesh()->GetGroups();
+        while ( groupIt->more() )
+        {
+          SMESH_Group* group = groupIt->next();
+          if ( domainName == group->GetName() &&
+               dynamic_cast< SMESHDS_Group* >( group->GetGroupDS()) )
+            groupOfType[ group->GetGroupDS()->GetType() ] = group;
+        }
+        // create and fill the groups
+        size_t iElem = 0;
+        int groupID;
+        do
+        {
+          SMESH_Group* group = groupOfType[ elems[ iElem ]->GetType() ];
+          if ( !group )
+            group = theHelper->GetMesh()->AddGroup( elems[ iElem ]->GetType(),
+                                                    domainName.c_str(), groupID );
+          SMDS_MeshGroup& groupDS =
+            static_cast< SMESHDS_Group* >( group->GetGroupDS() )->SMDSGroup();
+
+          while ( iElem < elems.size() && groupDS.Add( elems[iElem] ))
+            ++iElem;
+
+        } while ( iElem < elems.size() );
+      }
+  }
+
+#ifdef _DEBUG_
   MESSAGE("Nb subdomains " << subdomainId2tetraId.size());
   std::map<int, std::set<int> >::const_iterator subdomainIt = subdomainId2tetraId.begin();
   TCollection_AsciiString aSubdomainFileName = theFile;
@@ -1445,7 +1500,8 @@ static bool writeGMFFile(const char*                                     theMesh
   GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap::iterator elemIt;
   TIDSortedElemSet::iterator elemSetIt;
   bool isOK;
-  auto_ptr< SMESH_ElementSearcher > pntCls ( SMESH_MeshEditor( theMesh ).GetElementSearcher());
+  auto_ptr< SMESH_ElementSearcher > pntCls
+    ( SMESH_MeshAlgos::GetElementSearcher(*theMesh->GetMeshDS()));
   
   int nbEnforcedVertices = theEnforcedVertices.size();
   
@@ -2812,9 +2868,7 @@ static bool readResultFile(const int                       fileOpen,
 #ifdef WNT
                            const char*                     fileName,
 #endif
-#ifdef WITH_SMESH_CANCEL_COMPUTE
                            GHS3DPlugin_GHS3D*              theAlgo,
-#endif
                            SMESH_MesherHelper&             theHelper,
                            TopoDS_Shape                    tabShape[],
                            double**                        tabBox,
@@ -2901,10 +2955,8 @@ static bool readResultFile(const int                       fileOpen,
   MESSAGE("nbEnforcedNodes: "<<nbEnforcedNodes);
   // Reading the nodeCoor and update the nodeMap
   for (int iNode=1; iNode <= nbNodes; iNode++) {
-#ifdef WITH_SMESH_CANCEL_COMPUTE
     if(theAlgo->computeCanceled())
       return false;
-#endif
     for (int iCoor=0; iCoor < 3; iCoor++)
       coord[ iCoor ] = strtod(ptr, &ptr);
     nodeAssigne[ iNode ] = 1;
@@ -2924,10 +2976,8 @@ static bool readResultFile(const int                       fileOpen,
 
   tabID = new int[nbTriangle];
   for (int i=0; i < nbTriangle; i++) {
-#ifdef WITH_SMESH_CANCEL_COMPUTE
     if(theAlgo->computeCanceled())
       return false;
-#endif
     tabID[i] = 0;
     // find the solid corresponding to GHS3D sub-domain following
     // the technique proposed in GHS3D manual in chapter
@@ -2984,10 +3034,8 @@ static bool readResultFile(const int                       fileOpen,
   // Associating the tetrahedrons to the shapes
   shapeID = compoundID;
   for (int iElem = 0; iElem < nbElems; iElem++) {
-#ifdef WITH_SMESH_CANCEL_COMPUTE
     if(theAlgo->computeCanceled())
       return false;
-#endif
     for (int iNode = 0; iNode < 4; iNode++) {
       ID = strtol(tetraPtr, &tetraPtr, 10);
       itOnNode = theGhs3dIdToNodeMap.find(ID);
@@ -3368,9 +3416,7 @@ bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
   std::cout << "Ghs3d execution..." << std::endl;
   std::cout << cmd << std::endl;
 
-#ifdef WITH_SMESH_CANCEL_COMPUTE
   _compute_canceled = false;
-#endif
 
   system( cmd.ToCString() ); // run
 
@@ -3402,9 +3448,7 @@ bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
 #ifdef WNT
                          aResultFileName.ToCString(),
 #endif
-#ifdef WITH_SMESH_CANCEL_COMPUTE
                          this,
-#endif
                          /*theMesh, */helper, tabShape, tabBox, _nbShape, 
                          aGhs3dIdToNodeMap, aNodeId2NodeIndexMap,
                          toMeshHoles, 
@@ -3432,6 +3476,9 @@ bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
   {
     if ( !_keepFiles )
       removeFile( aLogFileName );
+
+    if ( _hyp && _hyp->GetToMakeGroupsOfDomains() )
+      error( COMPERR_WARNING, "'toMakeGroupsOfDomains' is ignored since the mesh is on shape" );
   }
   else if ( OSD_File( aLogFileName ).Size() > 0 )
   {
@@ -3448,11 +3495,9 @@ bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
   }
 
   if ( !_keepFiles ) {
-#ifdef WITH_SMESH_CANCEL_COMPUTE
     if (! Ok)
       if(_compute_canceled)
         removeFile( aLogFileName );
-#endif
     removeFile( aFacesFileName );
     removeFile( aPointsFileName );
     removeFile( aResultFileName );
@@ -3634,9 +3679,7 @@ bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
   std::cout << "Ghs3d execution..." << std::endl;
   std::cout << cmd << std::endl;
 
-#ifdef WITH_SMESH_CANCEL_COMPUTE
   _compute_canceled = false;
-#endif
 
   system( cmd.ToCString() ); // run
 
@@ -3647,16 +3690,16 @@ bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
   // read a result
   // --------------
   GHS3DPlugin_Hypothesis::TSetStrings groupsToRemove = GHS3DPlugin_Hypothesis::GetGroupsToRemove(_hyp);
+  const bool toMakeGroupsOfDomains = GHS3DPlugin_Hypothesis::GetToMakeGroupsOfDomains( _hyp );
 
   Ok = readGMFFile(aResultFileName.ToCString(),
-#ifdef WITH_SMESH_CANCEL_COMPUTE
                    this,
-#endif
                    theHelper, theShape, aNodeByGhs3dId, aNodeToGhs3dIdMap,
                    aNodeGroupByGhs3dId, anEdgeGroupByGhs3dId, aFaceGroupByGhs3dId,
-                   groupsToRemove);
+                   groupsToRemove, toMakeGroupsOfDomains);
 
   updateMeshGroups(theHelper->GetMesh(), groupsToRemove);
+  removeEmptyGroupsOfDomains( theHelper->GetMesh() );
 
   if ( Ok ) {
     GHS3DPlugin_Hypothesis* that = (GHS3DPlugin_Hypothesis*)this->_hyp;
@@ -3671,6 +3714,9 @@ bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
   {
     if ( !_keepFiles )
       removeFile( aLogFileName );
+
+    if ( !toMakeGroupsOfDomains && _hyp && _hyp->GetToMakeGroupsOfDomains() )
+      error( COMPERR_WARNING, "'toMakeGroupsOfDomains' is ignored since 'toMeshHoles' is OFF." );
   }
   else if ( OSD_File( aLogFileName ).Size() > 0 )
   {
@@ -3687,11 +3733,9 @@ bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
 
   if ( !_keepFiles )
   {
-#ifdef WITH_SMESH_CANCEL_COMPUTE
     if (! Ok)
       if(_compute_canceled)
         removeFile( aLogFileName );
-#endif
     removeFile( aGMFFileName );
     removeFile( aResultFileName );
     removeFile( aRequiredVerticesFileName );
@@ -3700,7 +3744,6 @@ bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
   return Ok;
 }
 
-#ifdef WITH_SMESH_CANCEL_COMPUTE
 void GHS3DPlugin_GHS3D::CancelCompute()
 {
   _compute_canceled = true;
@@ -3714,7 +3757,6 @@ void GHS3DPlugin_GHS3D::CancelCompute()
   system( cmd.ToCString() );
 #endif
 }
-#endif
 
 //================================================================================
 /*!
@@ -3901,10 +3943,8 @@ static char* getIds( char* ptr, int nbIds, vector<int>& ids )
 bool GHS3DPlugin_GHS3D::storeErrorDescription(const TCollection_AsciiString& logFile,
                                               const _Ghs2smdsConvertor &     toSmdsConvertor )
 {
-#ifdef WITH_SMESH_CANCEL_COMPUTE
   if(_compute_canceled)
     return error(SMESH_Comment("interruption initiated by user"));
-#endif
   // open file
 #ifdef WNT
   int file = ::_open (logFile.ToCString(), _O_RDONLY|_O_BINARY);
@@ -4309,10 +4349,132 @@ bool GHS3DPlugin_GHS3D::importGMFMesh(const char* theGMFFileName, SMESH_Mesh& th
   std::set<std::string> dummyGroupsToRemove;
 
   bool ok = readGMFFile(theGMFFileName,
-#ifdef WITH_SMESH_CANCEL_COMPUTE
                         this,
-#endif
                         helper, theMesh.GetShapeToMesh(), dummyNodeVector, dummyNodeMap, dummyElemGroup, dummyElemGroup, dummyElemGroup, dummyGroupsToRemove);
   theMesh.GetMeshDS()->Modified();
   return ok;
 }
+
+namespace
+{
+  //================================================================================
+  /*!
+   * \brief Sub-mesh event listener setting enforced elements as soon as an enforced
+   *        mesh is loaded
+   */
+  struct _EnforcedMeshRestorer : public SMESH_subMeshEventListener
+  {
+    _EnforcedMeshRestorer():
+      SMESH_subMeshEventListener( /*isDeletable = */true, Name() )
+    {}
+
+    //================================================================================
+    /*!
+     * \brief Returns an ID of listener
+     */
+    static const char* Name() { return "GHS3DPlugin_GHS3D::_EnforcedMeshRestorer"; }
+
+    //================================================================================
+    /*!
+     * \brief Treat events of the subMesh
+     */
+    void ProcessEvent(const int                       event,
+                      const int                       eventType,
+                      SMESH_subMesh*                  subMesh,
+                      SMESH_subMeshEventListenerData* data,
+                      const SMESH_Hypothesis*         hyp)
+    {
+      if ( SMESH_subMesh::SUBMESH_LOADED == event &&
+           SMESH_subMesh::COMPUTE_EVENT  == eventType &&
+           data &&
+           !data->mySubMeshes.empty() )
+      {
+        // An enforced mesh (subMesh->_father) has been loaded from hdf file
+        if ( GHS3DPlugin_Hypothesis* hyp = GetGHSHypothesis( data->mySubMeshes.front() ))
+          hyp->RestoreEnfElemsByMeshes();
+      }
+    }
+    //================================================================================
+    /*!
+     * \brief Returns GHS3DPlugin_Hypothesis used to compute a subMesh
+     */
+    static GHS3DPlugin_Hypothesis* GetGHSHypothesis( SMESH_subMesh* subMesh )
+    {
+      SMESH_HypoFilter ghsHypFilter( SMESH_HypoFilter::HasName( "GHS3D_Parameters" ));
+      return (GHS3DPlugin_Hypothesis* )
+        subMesh->GetFather()->GetHypothesis( subMesh->GetSubShape(),
+                                             ghsHypFilter,
+                                             /*visitAncestors=*/true);
+    }
+  };
+
+  //================================================================================
+  /*!
+   * \brief Sub-mesh event listener removing empty groups created due to "To make
+   *        groups of domains".
+   */
+  struct _GroupsOfDomainsRemover : public SMESH_subMeshEventListener
+  {
+    _GroupsOfDomainsRemover():
+      SMESH_subMeshEventListener( /*isDeletable = */true,
+                                  "GHS3DPlugin_GHS3D::_GroupsOfDomainsRemover" ) {}
+    /*!
+     * \brief Treat events of the subMesh
+     */
+    void ProcessEvent(const int                       event,
+                      const int                       eventType,
+                      SMESH_subMesh*                  subMesh,
+                      SMESH_subMeshEventListenerData* data,
+                      const SMESH_Hypothesis*         hyp)
+    {
+      if (SMESH_subMesh::ALGO_EVENT == eventType &&
+          !subMesh->GetAlgo() )
+      {
+        removeEmptyGroupsOfDomains( subMesh->GetFather(), /*notEmptyAsWell=*/true );
+      }
+    }
+  };
+}
+
+//================================================================================
+/*!
+ * \brief Set an event listener to set enforced elements as soon as an enforced
+ *        mesh is loaded
+ */
+//================================================================================
+
+void GHS3DPlugin_GHS3D::SubmeshRestored(SMESH_subMesh* subMesh)
+{
+  if ( GHS3DPlugin_Hypothesis* hyp = _EnforcedMeshRestorer::GetGHSHypothesis( subMesh ))
+  {
+    GHS3DPlugin_Hypothesis::TGHS3DEnforcedMeshList enfMeshes = hyp->_GetEnforcedMeshes();
+    GHS3DPlugin_Hypothesis::TGHS3DEnforcedMeshList::iterator it = enfMeshes.begin();
+    for(;it != enfMeshes.end();++it) {
+      GHS3DPlugin_Hypothesis::TGHS3DEnforcedMesh* enfMesh = *it;
+      if ( SMESH_Mesh* mesh = GetMeshByPersistentID( enfMesh->persistID ))
+      {
+        SMESH_subMesh* smToListen = mesh->GetSubMesh( mesh->GetShapeToMesh() );
+        // a listener set to smToListen will care of hypothesis stored in SMESH_EventListenerData
+        subMesh->SetEventListener( new _EnforcedMeshRestorer(),
+                                   SMESH_subMeshEventListenerData::MakeData( subMesh ),
+                                   smToListen);
+      }
+    }
+  }
+}
+
+//================================================================================
+/*!
+ * \brief Sets an event listener removing empty groups created due to "To make
+ *        groups of domains".
+ * \param subMesh - submesh where algo is set
+ *
+ * This method is called when a submesh gets HYP_OK algo_state.
+ * After being set, event listener is notified on each event of a submesh.
+ */
+//================================================================================
+
+void GHS3DPlugin_GHS3D::SetEventListener(SMESH_subMesh* subMesh)
+{
+  subMesh->SetEventListener( new _GroupsOfDomainsRemover(), 0, subMesh );
+}