Salome HOME
Merge from V5_1_main 10/12/2010
[modules/smesh.git] / src / SMESH_I / SMESH_Gen_i.cxx
index cfe99e65d1e297e972f858cf0ab6f04ec7e187a1..41aa724c5e9ec5768ffb0b96973b7933a8a4e4d2 100644 (file)
@@ -1,4 +1,4 @@
-//  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
+//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -19,6 +19,7 @@
 //
 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
+
 //  SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses
 //  File   : SMESH_Gen_i.cxx
 //  Author : Paul RASCLE, EDF
@@ -54,6 +55,7 @@
 
 #ifdef WNT
  #include <windows.h>
+ #include <process.h>
 #else
  #include <dlfcn.h>
 #endif
 
 #include "SMDS_EdgePosition.hxx"
 #include "SMDS_FacePosition.hxx"
-#include "SMDS_VertexPosition.hxx"
-#include "SMDS_SpacePosition.hxx"
 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
+#include "SMDS_SetIterator.hxx"
+#include "SMDS_SpacePosition.hxx"
+#include "SMDS_VertexPosition.hxx"
 
 #include CORBA_SERVER_HEADER(SMESH_Group)
 #include CORBA_SERVER_HEADER(SMESH_Filter)
 #include "OpUtil.hxx"
 
 #include CORBA_CLIENT_HEADER(SALOME_ModuleCatalog)
+#include CORBA_CLIENT_HEADER(SALOME_Session)
 
 #include "GEOM_Client.hxx"
 #include "Utils_ExceptHandlers.hxx"
+#include "memoire.h"
+#include "Basics_Utils.hxx"
 
 #include <map>
 
@@ -172,11 +178,11 @@ CORBA::Object_var SMESH_Gen_i::SObjectToObject( SALOMEDS::SObject_ptr theSObject
   if ( !theSObject->_is_nil() ) {
     try {
       if( theSObject->FindAttribute( anAttr, "AttributeIOR" ) ) {
-       SALOMEDS::AttributeIOR_var anIOR  = SALOMEDS::AttributeIOR::_narrow( anAttr );
-       CORBA::String_var aValue = anIOR->Value();
-       if( strcmp( aValue, "" ) != 0 )
-         anObj = GetORB()->string_to_object( aValue );
-       }
+        SALOMEDS::AttributeIOR_var anIOR  = SALOMEDS::AttributeIOR::_narrow( anAttr );
+        CORBA::String_var aValue = anIOR->Value();
+        if( strcmp( aValue, "" ) != 0 )
+          anObj = GetORB()->string_to_object( aValue );
+        }
     }
     catch( ... ) {
       INFOS( "SObjectToObject - Unknown exception was caught!!!" );
@@ -259,9 +265,9 @@ SMESH_Gen_i::SMESH_Gen_i()
 //=============================================================================
 
 SMESH_Gen_i::SMESH_Gen_i( CORBA::ORB_ptr            orb,
-                         PortableServer::POA_ptr   poa,
-                         PortableServer::ObjectId* contId, 
-                         const char*               instanceName, 
+                          PortableServer::POA_ptr   poa,
+                          PortableServer::ObjectId* contId, 
+                          const char*               instanceName, 
                           const char*               interfaceName )
      : Engines_Component_i( orb, poa, contId, instanceName, interfaceName )
 {
@@ -279,6 +285,28 @@ SMESH_Gen_i::SMESH_Gen_i( CORBA::ORB_ptr            orb,
 
   // set it in standalone mode only
   //OSD::SetSignal( true );
+
+  // 0020605: EDF 1190 SMESH: Display performance. 80 seconds for 52000 cells.
+  // find out mode (embedded or standalone) here else
+  // meshes created before calling SMESH_Client::GetSMESHGen(), which calls
+  // SMESH_Gen_i::SetEmbeddedMode(), have wrong IsEmbeddedMode flag
+  if ( SALOME_NamingService* ns = GetNS() )
+  {
+    CORBA::Object_var obj = ns->Resolve( "/Kernel/Session" );
+    SALOME::Session_var session = SALOME::Session::_narrow( obj ) ;
+    if ( !session->_is_nil() )
+    {
+      CORBA::String_var s_host = session->getHostname();
+      CORBA::Long        s_pid = session->getPID();
+      string my_host = Kernel_Utils::GetHostname();
+#ifdef WNT
+      long    my_pid = (long)_getpid();
+#else
+      long    my_pid = (long) getpid();
+#endif
+      SetEmbeddedMode( s_pid == my_pid && my_host == s_host.in() );
+    }
+  }
 }
 
 //=============================================================================
@@ -458,6 +486,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::createMesh()
     // create a new mesh object servant, store it in a map in study context
     SMESH_Mesh_i* meshServant = new SMESH_Mesh_i( GetPOA(), this, GetCurrentStudyID() );
     // create a new mesh object
+    MESSAGE("myIsEmbeddedMode " << myIsEmbeddedMode);
     meshServant->SetImpl( myGen.CreateMesh( GetCurrentStudyID(), myIsEmbeddedMode ));
 
     // activate the CORBA servant of Mesh
@@ -515,6 +544,7 @@ void SMESH_Gen_i::SetGeomEngine( GEOM::GEOM_Gen_ptr geomcompo )
 void SMESH_Gen_i::SetEmbeddedMode( CORBA::Boolean theMode )
 {
   myIsEmbeddedMode = theMode;
+  MESSAGE("myIsEmbeddedMode " << myIsEmbeddedMode);
 
   if ( !myIsEmbeddedMode ) {
     //PAL10867: disable signals catching with "noexcepthandler" option
@@ -559,12 +589,10 @@ CORBA::Boolean SMESH_Gen_i::IsEmbeddedMode()
 
 void SMESH_Gen_i::SetCurrentStudy( SALOMEDS::Study_ptr theStudy )
 {
-  //if(MYDEBUG)
-  //MESSAGE( "SMESH_Gen_i::SetCurrentStudy" );
+  int curStudyId = GetCurrentStudyID();
   myCurrentStudy = SALOMEDS::Study::_duplicate( theStudy );
   // create study context, if it doesn't exist and set current study
   int studyId = GetCurrentStudyID();
-  if(MYDEBUG) MESSAGE( "SMESH_Gen_i::SetCurrentStudy: study Id = " << studyId );
   if ( myStudyContextMap.find( studyId ) == myStudyContextMap.end() ) {
     myStudyContextMap[ studyId ] = new StudyContext;      
   }
@@ -575,9 +603,23 @@ void SMESH_Gen_i::SetCurrentStudy( SALOMEDS::Study_ptr theStudy )
     if( !myCurrentStudy->FindComponent( "GEOM" )->_is_nil() )
       aStudyBuilder->LoadWith( myCurrentStudy->FindComponent( "GEOM" ), GetGeomEngine() );
 
-  // set current study for geom engine
-  //if ( !CORBA::is_nil( GetGeomEngine() ) )
-  //  GetGeomEngine()->GetCurrentStudy( myCurrentStudy->StudyId() );
+    // NPAL16168, issue 0020210
+    // Let meshes update their data depending on GEOM groups that could change
+    if ( curStudyId != studyId )
+    {
+      //SALOMEDS::SComponent_var me =  PublishComponent( myCurrentStudy );
+      SALOMEDS::SComponent_var me = SALOMEDS::SComponent::_narrow
+        ( myCurrentStudy->FindComponent( ComponentDataType() ) );
+      if ( !me->_is_nil() ) {
+        SALOMEDS::ChildIterator_var anIter = myCurrentStudy->NewChildIterator( me );
+        for ( ; anIter->More(); anIter->Next() ) {
+          SALOMEDS::SObject_var so = anIter->Value();
+          CORBA::Object_var    ior = SObjectToObject( so );
+          if ( SMESH_Mesh_i*  mesh = SMESH::DownCast<SMESH_Mesh_i*>( ior ))
+            mesh->CheckGeomGroupModif();
+        }
+      }
+    }
   }
 }
 
@@ -755,7 +797,7 @@ void SMESH_Gen_i::SetBoundaryBoxSegmentation( CORBA::Long theNbSegments )
 void SMESH_Gen_i::SetDefaultNbSegments(CORBA::Long theNbSegments)
   throw ( SALOME::SALOME_Exception )
 {
-  if ( theNbSegments )
+  if ( theNbSegments > 0 )
     myGen.SetDefaultNbSegments( int(theNbSegments) );
   else
     THROW_SALOME_CORBA_EXCEPTION( "non-positive number of segments", SALOME::BAD_PARAM );
@@ -851,7 +893,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMeshesFromUNV( const char* theFileName
     aStudyBuilder->CommitCommand();
     if ( !aSO->_is_nil() ) {
       // Update Python script
-      TPythonDump() << aSO << " = smeshgen.CreateMeshesFromUNV('" << theFileName << "')";
+      TPythonDump() << aSO << " = smeshgen.CreateMeshesFromUNV(r'" << theFileName << "')";
     }
   }
 
@@ -860,8 +902,9 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMeshesFromUNV( const char* theFileName
   aServant->ImportUNVFile( theFileName );
 
   // Dump creation of groups
-  aServant->GetGroups();
+  SMESH::ListOfGroups_var groups = aServant->GetGroups();
 
+  aServant->GetImpl().GetMeshDS()->Modified();
   return aMesh._retn();
 }
 
@@ -894,7 +937,6 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName,
   // Python Dump
   TPythonDump aPythonDump;
   aPythonDump << "([";
-  //TCollection_AsciiString aStr ("([");
 
   if (theStatus == SMESH::DRS_OK) {
     SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder();
@@ -905,7 +947,6 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName,
     // Iterate through all meshes and create mesh objects
     for ( list<string>::iterator it = aNames.begin(); it != aNames.end(); it++ ) {
       // Python Dump
-      //if (i > 0) aStr += ", ";
       if (i > 0) aPythonDump << ", ";
 
       // create mesh
@@ -918,33 +959,31 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName,
       if ( !aSO->_is_nil() ) {
         // Python Dump
         aPythonDump << aSO;
-        //aStr += aSO->GetID();
       } else {
         // Python Dump
         aPythonDump << "mesh_" << i;
-//         aStr += "mesh_";
-//         aStr += TCollection_AsciiString(i);
       }
 
       // Read mesh data (groups are published automatically by ImportMEDFile())
       SMESH_Mesh_i* meshServant = dynamic_cast<SMESH_Mesh_i*>( GetServant( mesh ).in() );
       ASSERT( meshServant );
       SMESH::DriverMED_ReadStatus status1 =
-       meshServant->ImportMEDFile( theFileName, (*it).c_str() );
+        meshServant->ImportMEDFile( theFileName, (*it).c_str() );
       if (status1 > theStatus)
-       theStatus = status1;
+        theStatus = status1;
 
       aResult[i++] = SMESH::SMESH_Mesh::_duplicate( mesh );
+      meshServant->GetImpl().GetMeshDS()->Modified();
     }
     aStudyBuilder->CommitCommand();
   }
 
   // Update Python script
-  aPythonDump << "], status) = " << this << ".CreateMeshesFromMED('" << theFileName << "')";
+  aPythonDump << "], status) = " << this << ".CreateMeshesFromMED(r'" << theFileName << "')";
   }
   // Dump creation of groups
   for ( int i = 0; i < aResult->length(); ++i )
-    aResult[ i ]->GetGroups();
+    SMESH::ListOfGroups_var groups = aResult[ i ]->GetGroups();
 
   return aResult._retn();
 }
@@ -974,13 +1013,14 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMeshesFromSTL( const char* theFileName
     aStudyBuilder->CommitCommand();
     if ( !aSO->_is_nil() ) {
       // Update Python script
-      TPythonDump() << aSO << " = " << this << ".CreateMeshesFromSTL('" << theFileName << "')";
+      TPythonDump() << aSO << " = " << this << ".CreateMeshesFromSTL(r'" << theFileName << "')";
     }
   }
 
   SMESH_Mesh_i* aServant = dynamic_cast<SMESH_Mesh_i*>( GetServant( aMesh ).in() );
   ASSERT( aServant );
   aServant->ImportSTLFile( theFileName );
+  aServant->GetImpl().GetMeshDS()->Modified();
   return aMesh._retn();
 }
 
@@ -1285,7 +1325,7 @@ SMESH::algo_error_array* SMESH_Gen_i::GetAlgoState( SMESH::SMESH_Mesh_ptr theMes
 //=============================================================================
 
 SMESH::long_array* SMESH_Gen_i::GetSubShapesId( GEOM::GEOM_Object_ptr theMainShapeObject,
-                                           const SMESH::object_array& theListOfSubShapeObject )
+                                            const SMESH::object_array& theListOfSubShapeObject )
      throw ( SALOME::SALOME_Exception )
 {
   Unexpect aCatch(SALOME_SalomeException);
@@ -1305,43 +1345,43 @@ SMESH::long_array* SMESH_Gen_i::GetSubShapesId( GEOM::GEOM_Object_ptr theMainSha
       TopExp::MapShapes(myMainShape,myIndexToShape);
 
       for ( int i = 0; i < theListOfSubShapeObject.length(); i++ )
-       {
-         GEOM::GEOM_Object_var aShapeObject
-           = GEOM::GEOM_Object::_narrow(theListOfSubShapeObject[i]);
-         if ( CORBA::is_nil( aShapeObject ) )
-           THROW_SALOME_CORBA_EXCEPTION ("bad shape object reference", \
-                                       SALOME::BAD_PARAM );
-
-         TopoDS_Shape locShape  = GeomObjectToShape(aShapeObject);
-         for (TopExp_Explorer exp(locShape,TopAbs_FACE); exp.More(); exp.Next())
-           {
-             const TopoDS_Face& F = TopoDS::Face(exp.Current());
-             setId.insert(myIndexToShape.FindIndex(F));
-             if(MYDEBUG) SCRUTE(myIndexToShape.FindIndex(F));
-           }
-         for (TopExp_Explorer exp(locShape,TopAbs_EDGE); exp.More(); exp.Next())
-           {
-             const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
-             setId.insert(myIndexToShape.FindIndex(E));
-             if(MYDEBUG) SCRUTE(myIndexToShape.FindIndex(E));
-           }
-         for (TopExp_Explorer exp(locShape,TopAbs_VERTEX); exp.More(); exp.Next())
-           {
-             const TopoDS_Vertex& V = TopoDS::Vertex(exp.Current());
-             setId.insert(myIndexToShape.FindIndex(V));
-             if(MYDEBUG) SCRUTE(myIndexToShape.FindIndex(V));
-           }
-       }
+        {
+          GEOM::GEOM_Object_var aShapeObject
+            = GEOM::GEOM_Object::_narrow(theListOfSubShapeObject[i]);
+          if ( CORBA::is_nil( aShapeObject ) )
+            THROW_SALOME_CORBA_EXCEPTION ("bad shape object reference", \
+                                        SALOME::BAD_PARAM );
+
+          TopoDS_Shape locShape  = GeomObjectToShape(aShapeObject);
+          for (TopExp_Explorer exp(locShape,TopAbs_FACE); exp.More(); exp.Next())
+            {
+              const TopoDS_Face& F = TopoDS::Face(exp.Current());
+              setId.insert(myIndexToShape.FindIndex(F));
+              if(MYDEBUG) SCRUTE(myIndexToShape.FindIndex(F));
+            }
+          for (TopExp_Explorer exp(locShape,TopAbs_EDGE); exp.More(); exp.Next())
+            {
+              const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
+              setId.insert(myIndexToShape.FindIndex(E));
+              if(MYDEBUG) SCRUTE(myIndexToShape.FindIndex(E));
+            }
+          for (TopExp_Explorer exp(locShape,TopAbs_VERTEX); exp.More(); exp.Next())
+            {
+              const TopoDS_Vertex& V = TopoDS::Vertex(exp.Current());
+              setId.insert(myIndexToShape.FindIndex(V));
+              if(MYDEBUG) SCRUTE(myIndexToShape.FindIndex(V));
+            }
+        }
       shapesId->length(setId.size());
       set<int>::iterator iind;
       int i=0;
       for (iind = setId.begin(); iind != setId.end(); iind++)
-       {
-         if(MYDEBUG) SCRUTE((*iind));
-         shapesId[i] = (*iind);
-         if(MYDEBUG) SCRUTE(shapesId[i]);
-         i++;
-       }
+        {
+          if(MYDEBUG) SCRUTE((*iind));
+          shapesId[i] = (*iind);
+          if(MYDEBUG) SCRUTE(shapesId[i]);
+          i++;
+        }
     }
   catch (SALOME_Exception& S_ex)
     {
@@ -1363,6 +1403,7 @@ CORBA::Boolean SMESH_Gen_i::Compute( SMESH::SMESH_Mesh_ptr theMesh,
                                      GEOM::GEOM_Object_ptr theShapeObject )
      throw ( SALOME::SALOME_Exception )
 {
+  MEMOSTAT;
   Unexpect aCatch(SALOME_SalomeException);
   if(MYDEBUG) MESSAGE( "SMESH_Gen_i::Compute" );
 
@@ -1393,7 +1434,10 @@ CORBA::Boolean SMESH_Gen_i::Compute( SMESH::SMESH_Mesh_ptr theMesh,
         myLocShape = SMESH_Mesh::PseudoShape();
       // call implementation compute
       ::SMESH_Mesh& myLocMesh = meshServant->GetImpl();
-      return myGen.Compute( myLocMesh, myLocShape);
+      bool ok = myGen.Compute( myLocMesh, myLocShape);
+      meshServant->CreateGroupServants(); // algos can create groups (issue 0020918)
+      myLocMesh.GetMeshDS()->Modified();
+      return ok;
     }
   }
   catch ( std::bad_alloc ) {
@@ -1417,9 +1461,9 @@ CORBA::Boolean SMESH_Gen_i::Compute( SMESH::SMESH_Mesh_ptr theMesh,
 //=============================================================================
 
 SMESH::MeshPreviewStruct* SMESH_Gen_i::Precompute( SMESH::SMESH_Mesh_ptr theMesh,
-                                                  GEOM::GEOM_Object_ptr theShapeObject,
-                                                  SMESH::Dimension      theDimension,
-                                                  SMESH::long_array&    theShapesId)
+                                                   GEOM::GEOM_Object_ptr theShapeObject,
+                                                   SMESH::Dimension      theDimension,
+                                                   SMESH::long_array&    theShapesId)
      throw ( SALOME::SALOME_Exception )
 {
   Unexpect aCatch(SALOME_SalomeException);
@@ -1446,7 +1490,7 @@ SMESH::MeshPreviewStruct* SMESH_Gen_i::Precompute( SMESH::SMESH_Mesh_ptr theMesh
       if(theMesh->HasShapeToMesh())
         myLocShape = GeomObjectToShape( theShapeObject );
       else
-       return result._retn();;
+        return result._retn();;
 
       // call implementation compute
       ::SMESH_Mesh& myLocMesh = meshServant->GetImpl();
@@ -1454,132 +1498,132 @@ SMESH::MeshPreviewStruct* SMESH_Gen_i::Precompute( SMESH::SMESH_Mesh_ptr theMesh
       ::MeshDimension aDim = (MeshDimension)theDimension;
       if ( myGen.Compute( myLocMesh, myLocShape, false, aDim, &shapeIds ) )
       {
-       int nbShapeId = shapeIds.size();
-       theShapesId.length( nbShapeId );
-       // iterates on shapes and collect mesh entities into mesh preview
-       TSetOfInt::const_iterator idIt = shapeIds.begin();
-       TSetOfInt::const_iterator idEnd = shapeIds.end();
-       std::map< int, int > mapOfShIdNb;
-       std::set< SMESH_TLink > setOfEdge;
-       std::list< SMDSAbs_ElementType > listOfElemType;
-       typedef map<const SMDS_MeshElement*, int > TNode2LocalIDMap;
-       typedef TNode2LocalIDMap::iterator         TNodeLocalID;
-       TNode2LocalIDMap mapNode2LocalID;
-       list< TNodeLocalID > connectivity;
-       int i, nbConnNodes = 0;
-       std::set< const SMESH_subMesh* > setOfVSubMesh;
-       // iterates on shapes
-       for ( ; idIt != idEnd; idIt++ )
-       {
-         if ( mapOfShIdNb.find( *idIt ) != mapOfShIdNb.end() )
-           continue;
-         SMESH_subMesh* sm = myLocMesh.GetSubMeshContaining(*idIt);
-         if ( !sm || !sm->IsMeshComputed() )
-           continue;
-         
-         const TopoDS_Shape& aSh = sm->GetSubShape();
-         const int shDim = myGen.GetShapeDim( aSh );
-         if ( shDim < 1 || shDim > theDimension )
-           continue;
-
-         mapOfShIdNb[ *idIt ] = 0;
-         theShapesId[ mapOfShIdNb.size() - 1 ] = *idIt;
-
-         SMESHDS_SubMesh* smDS = sm->GetSubMeshDS();
-         if ( !smDS ) continue;
-
-         if ( theDimension == SMESH::DIM_2D )
-         {
-           SMDS_ElemIteratorPtr faceIt = smDS->GetElements();
-           while ( faceIt->more() )
-           {
-             const SMDS_MeshElement* face = faceIt->next();
-             int aNbNode = face->NbNodes();
-             if ( aNbNode > 4 )
-               aNbNode /= 2; // do not take into account additional middle nodes
-
-             SMDS_MeshNode* node1 = (SMDS_MeshNode*)face->GetNode( 1 );
-             for ( int nIndx = 1; nIndx <= aNbNode; nIndx++ )
-             {
-               SMDS_MeshNode* node2 = (SMDS_MeshNode*)face->GetNode( nIndx < aNbNode ? nIndx+1 : 1 );
-               if ( setOfEdge.insert( SMESH_TLink ( node1, node2 ) ).second )
-               {
-                 listOfElemType.push_back( SMDSAbs_Edge );
-                 connectivity.push_back
-                   ( mapNode2LocalID.insert( make_pair( node1, ++nbConnNodes)).first );
-                 connectivity.push_back
-                   ( mapNode2LocalID.insert( make_pair( node2, ++nbConnNodes)).first );
-               }
-               node1 = node2;
-             }
-           }
-         }
-         else if ( theDimension == SMESH::DIM_1D )
-         {
-           SMDS_NodeIteratorPtr nodeIt = smDS->GetNodes();
-           while ( nodeIt->more() )
-           {
-             listOfElemType.push_back( SMDSAbs_Node );
-             connectivity.push_back
-               ( mapNode2LocalID.insert( make_pair( nodeIt->next(), ++nbConnNodes)).first );
-           }
-           // add corner nodes by first vertex from edge
-           SMESH_subMeshIteratorPtr edgeSmIt =
-             sm->getDependsOnIterator(/*includeSelf*/false,
-                                      /*complexShapeFirst*/false);
-           while ( edgeSmIt->more() )
-           {
-             SMESH_subMesh* vertexSM = edgeSmIt->next();
-             // check that vertex is not already treated
-             if ( !setOfVSubMesh.insert( vertexSM ).second )
-               continue;
-             if ( vertexSM->GetSubShape().ShapeType() != TopAbs_VERTEX )
-               continue;
-
-             const SMESHDS_SubMesh* vertexSmDS = vertexSM->GetSubMeshDS();
-             SMDS_NodeIteratorPtr nodeIt = vertexSmDS->GetNodes();
-             while ( nodeIt->more() )
-             {
-               listOfElemType.push_back( SMDSAbs_Node );
-               connectivity.push_back
-                 ( mapNode2LocalID.insert( make_pair( nodeIt->next(), ++nbConnNodes)).first );
-             }
-           }
-         }
-       }
-
-       // fill node coords and assign local ids to the nodes
-       int nbNodes = mapNode2LocalID.size();
-       result->nodesXYZ.length( nbNodes );
-       TNodeLocalID node2ID = mapNode2LocalID.begin();
-       for ( i = 0; i < nbNodes; ++i, ++node2ID ) {
-         node2ID->second = i;
-         const SMDS_MeshNode* node = (const SMDS_MeshNode*) node2ID->first;
-         result->nodesXYZ[i].x = node->X();
-         result->nodesXYZ[i].y = node->Y();
-         result->nodesXYZ[i].z = node->Z();
-       }
-       // fill connectivity
-       result->elementConnectivities.length( nbConnNodes );
-       list< TNodeLocalID >::iterator connIt = connectivity.begin();
-       for ( i = 0; i < nbConnNodes; ++i, ++connIt ) {
-         result->elementConnectivities[i] = (*connIt)->second;
-       }
-
-       // fill element types
-       result->elementTypes.length( listOfElemType.size() );
-       std::list< SMDSAbs_ElementType >::const_iterator typeIt = listOfElemType.begin();
-       std::list< SMDSAbs_ElementType >::const_iterator typeEnd = listOfElemType.end();
-       for ( i = 0; typeIt != typeEnd; ++i, ++typeIt )
+        int nbShapeId = shapeIds.size();
+        theShapesId.length( nbShapeId );
+        // iterates on shapes and collect mesh entities into mesh preview
+        TSetOfInt::const_iterator idIt = shapeIds.begin();
+        TSetOfInt::const_iterator idEnd = shapeIds.end();
+        std::map< int, int > mapOfShIdNb;
+        std::set< SMESH_TLink > setOfEdge;
+        std::list< SMDSAbs_ElementType > listOfElemType;
+        typedef map<const SMDS_MeshElement*, int > TNode2LocalIDMap;
+        typedef TNode2LocalIDMap::iterator         TNodeLocalID;
+        TNode2LocalIDMap mapNode2LocalID;
+        list< TNodeLocalID > connectivity;
+        int i, nbConnNodes = 0;
+        std::set< const SMESH_subMesh* > setOfVSubMesh;
+        // iterates on shapes
+        for ( ; idIt != idEnd; idIt++ )
+        {
+          if ( mapOfShIdNb.find( *idIt ) != mapOfShIdNb.end() )
+            continue;
+          SMESH_subMesh* sm = myLocMesh.GetSubMeshContaining(*idIt);
+          if ( !sm || !sm->IsMeshComputed() )
+            continue;
+          
+          const TopoDS_Shape& aSh = sm->GetSubShape();
+          const int shDim = myGen.GetShapeDim( aSh );
+          if ( shDim < 1 || shDim > theDimension )
+            continue;
+
+          mapOfShIdNb[ *idIt ] = 0;
+          theShapesId[ mapOfShIdNb.size() - 1 ] = *idIt;
+
+          SMESHDS_SubMesh* smDS = sm->GetSubMeshDS();
+          if ( !smDS ) continue;
+
+          if ( theDimension == SMESH::DIM_2D )
+          {
+            SMDS_ElemIteratorPtr faceIt = smDS->GetElements();
+            while ( faceIt->more() )
+            {
+              const SMDS_MeshElement* face = faceIt->next();
+              int aNbNode = face->NbNodes();
+              if ( aNbNode > 4 )
+                aNbNode /= 2; // do not take into account additional middle nodes
+
+              SMDS_MeshNode* node1 = (SMDS_MeshNode*)face->GetNode( 0 );
+              for ( int nIndx = 0; nIndx < aNbNode; nIndx++ )
+              {
+                SMDS_MeshNode* node2 = (SMDS_MeshNode*)face->GetNode( nIndx+1 < aNbNode ? nIndx+1 : 0 );
+                if ( setOfEdge.insert( SMESH_TLink ( node1, node2 ) ).second )
+                {
+                  listOfElemType.push_back( SMDSAbs_Edge );
+                  connectivity.push_back
+                    ( mapNode2LocalID.insert( make_pair( node1, ++nbConnNodes)).first );
+                  connectivity.push_back
+                    ( mapNode2LocalID.insert( make_pair( node2, ++nbConnNodes)).first );
+                }
+                node1 = node2;
+              }
+            }
+          }
+          else if ( theDimension == SMESH::DIM_1D )
+          {
+            SMDS_NodeIteratorPtr nodeIt = smDS->GetNodes();
+            while ( nodeIt->more() )
+            {
+              listOfElemType.push_back( SMDSAbs_Node );
+              connectivity.push_back
+                ( mapNode2LocalID.insert( make_pair( nodeIt->next(), ++nbConnNodes)).first );
+            }
+            // add corner nodes by first vertex from edge
+            SMESH_subMeshIteratorPtr edgeSmIt =
+              sm->getDependsOnIterator(/*includeSelf*/false,
+                                       /*complexShapeFirst*/false);
+            while ( edgeSmIt->more() )
+            {
+              SMESH_subMesh* vertexSM = edgeSmIt->next();
+              // check that vertex is not already treated
+              if ( !setOfVSubMesh.insert( vertexSM ).second )
+                continue;
+              if ( vertexSM->GetSubShape().ShapeType() != TopAbs_VERTEX )
+                continue;
+
+              const SMESHDS_SubMesh* vertexSmDS = vertexSM->GetSubMeshDS();
+              SMDS_NodeIteratorPtr nodeIt = vertexSmDS->GetNodes();
+              while ( nodeIt->more() )
+              {
+                listOfElemType.push_back( SMDSAbs_Node );
+                connectivity.push_back
+                  ( mapNode2LocalID.insert( make_pair( nodeIt->next(), ++nbConnNodes)).first );
+              }
+            }
+          }
+        }
+
+        // fill node coords and assign local ids to the nodes
+        int nbNodes = mapNode2LocalID.size();
+        result->nodesXYZ.length( nbNodes );
+        TNodeLocalID node2ID = mapNode2LocalID.begin();
+        for ( i = 0; i < nbNodes; ++i, ++node2ID ) {
+          node2ID->second = i;
+          const SMDS_MeshNode* node = (const SMDS_MeshNode*) node2ID->first;
+          result->nodesXYZ[i].x = node->X();
+          result->nodesXYZ[i].y = node->Y();
+          result->nodesXYZ[i].z = node->Z();
+        }
+        // fill connectivity
+        result->elementConnectivities.length( nbConnNodes );
+        list< TNodeLocalID >::iterator connIt = connectivity.begin();
+        for ( i = 0; i < nbConnNodes; ++i, ++connIt ) {
+          result->elementConnectivities[i] = (*connIt)->second;
+        }
+
+        // fill element types
+        result->elementTypes.length( listOfElemType.size() );
+        std::list< SMDSAbs_ElementType >::const_iterator typeIt = listOfElemType.begin();
+        std::list< SMDSAbs_ElementType >::const_iterator typeEnd = listOfElemType.end();
+        for ( i = 0; typeIt != typeEnd; ++i, ++typeIt )
         {
-         SMDSAbs_ElementType elemType = *typeIt;
-         result->elementTypes[i].SMDS_ElementType = (SMESH::ElementType)elemType;
-         result->elementTypes[i].isPoly           = false;
-         result->elementTypes[i].nbNodesInElement = elemType == SMDSAbs_Edge ? 2 : 1;
-       }
-
-       // correct number of shapes
-       theShapesId.length( mapOfShIdNb.size() );
+          SMDSAbs_ElementType elemType = *typeIt;
+          result->elementTypes[i].SMDS_ElementType = (SMESH::ElementType)elemType;
+          result->elementTypes[i].isPoly           = false;
+          result->elementTypes[i].nbNodesInElement = elemType == SMDSAbs_Edge ? 2 : 1;
+        }
+
+        // correct number of shapes
+        theShapesId.length( mapOfShIdNb.size() );
       }
     }
   }
@@ -1595,6 +1639,93 @@ SMESH::MeshPreviewStruct* SMESH_Gen_i::Precompute( SMESH::SMESH_Mesh_ptr theMesh
   return result._retn();
 }
 
+
+//=============================================================================
+/*!
+ *  SMESH_Gen_i::Evaluate
+ *
+ *  Evaluate mesh on a shape
+ */
+//=============================================================================
+
+SMESH::long_array* SMESH_Gen_i::Evaluate(SMESH::SMESH_Mesh_ptr theMesh,
+                                         GEOM::GEOM_Object_ptr theShapeObject)
+//                                     SMESH::long_array& theNbElems)
+     throw ( SALOME::SALOME_Exception )
+{
+  Unexpect aCatch(SALOME_SalomeException);
+  if(MYDEBUG) MESSAGE( "SMESH_Gen_i::Evaluate" );
+
+  if ( CORBA::is_nil( theShapeObject ) && theMesh->HasShapeToMesh())
+    THROW_SALOME_CORBA_EXCEPTION( "bad shape object reference", 
+                                  SALOME::BAD_PARAM );
+
+  if ( CORBA::is_nil( theMesh ) )
+    THROW_SALOME_CORBA_EXCEPTION( "bad Mesh reference",
+                                  SALOME::BAD_PARAM );
+
+  SMESH::long_array_var nbels = new SMESH::long_array;
+  nbels->length(SMESH::Entity_Last);
+  int i = SMESH::Entity_Node;
+  for (; i < SMESH::Entity_Last; i++)
+    nbels[i] = 0;
+
+  // Update Python script
+  TPythonDump() << "theNbElems = " << this << ".Evaluate( "
+                << theMesh << ", " << theShapeObject << ")";
+
+  try {
+    // get mesh servant
+    SMESH_Mesh_i* meshServant = dynamic_cast<SMESH_Mesh_i*>( GetServant( theMesh ).in() );
+    ASSERT( meshServant );
+    if ( meshServant ) {
+      // NPAL16168: "geometrical group edition from a submesh don't modifiy mesh computation"
+      meshServant->CheckGeomGroupModif();
+      // get local TopoDS_Shape
+      TopoDS_Shape myLocShape;
+      if(theMesh->HasShapeToMesh())
+        myLocShape = GeomObjectToShape( theShapeObject );
+      else
+        myLocShape = SMESH_Mesh::PseudoShape();
+      // call implementation compute
+      ::SMESH_Mesh& myLocMesh = meshServant->GetImpl();
+      MapShapeNbElems aResMap;
+      /*CORBA::Boolean ret =*/ myGen.Evaluate( myLocMesh, myLocShape, aResMap);
+      MapShapeNbElemsItr anIt = aResMap.begin();
+      for(; anIt!=aResMap.end(); anIt++) {
+        const vector<int>& aVec = (*anIt).second;
+        for(i = SMESH::Entity_Node; i < aVec.size(); i++) {
+          int nbElem = aVec[i];
+          if ( nbElem < 0 ) // algo failed, check that it has reported a message
+          {
+            SMESH_subMesh* sm = anIt->first;
+            SMESH_ComputeErrorPtr& error = sm->GetComputeError();
+            const SMESH_Algo* algo = myGen.GetAlgo( myLocMesh, sm->GetSubShape());
+            if ( algo && !error.get() || error->IsOK() )
+              error.reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED,"Failed to evaluate",algo));
+          }
+          else
+          {
+            nbels[i] += aVec[i];
+          }
+        }
+      }
+      return nbels._retn();
+    }
+  }
+  catch ( std::bad_alloc ) {
+    INFOS( "Evaluate(): lack of memory" );
+  }
+  catch ( SALOME_Exception& S_ex ) {
+    INFOS( "Evaluate(): catch exception "<< S_ex.what() );
+  }
+  catch ( ... ) {
+    INFOS( "Evaluate(): unknown exception " );
+  }
+
+  return nbels._retn();
+}
+
 //================================================================================
 /*!
  * \brief Return geometrical object the given element is built on
@@ -1716,7 +1847,7 @@ SMESH_Gen_i::FindGeometryByMeshElement( SMESH::SMESH_Mesh_ptr  theMesh,
         }
         if ( !geom->_is_nil() ) {
           GeomObjectToShape( geom ); // let geom client remember the found shape
-         return geom._retn();
+          return geom._retn();
         }
       }
     }
@@ -1733,16 +1864,16 @@ SMESH_Gen_i::FindGeometryByMeshElement( SMESH::SMESH_Mesh_ptr  theMesh,
 //================================================================================
 
 SMESH::SMESH_Mesh_ptr SMESH_Gen_i::Concatenate(const SMESH::mesh_array& theMeshesArray,
-                                              CORBA::Boolean           theUniteIdenticalGroups, 
-                                              CORBA::Boolean           theMergeNodesAndElements, 
-                                              CORBA::Double            theMergeTolerance)
+                                               CORBA::Boolean           theUniteIdenticalGroups, 
+                                               CORBA::Boolean           theMergeNodesAndElements, 
+                                               CORBA::Double            theMergeTolerance)
   throw ( SALOME::SALOME_Exception )
 {
   return ConcatenateCommon(theMeshesArray,
-                          theUniteIdenticalGroups,
-                          theMergeNodesAndElements,
-                          theMergeTolerance,
-                          false);
+                           theUniteIdenticalGroups,
+                           theMergeNodesAndElements,
+                           theMergeTolerance,
+                           false);
 }
 
 //================================================================================
@@ -1756,7 +1887,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::Concatenate(const SMESH::mesh_array& theMeshe
 
 SMESH::SMESH_Mesh_ptr
 SMESH_Gen_i::ConcatenateWithGroups(const SMESH::mesh_array& theMeshesArray,
-                                  CORBA::Boolean           theUniteIdenticalGroups, 
+                                   CORBA::Boolean           theUniteIdenticalGroups, 
                                    CORBA::Boolean           theMergeNodesAndElements, 
                                    CORBA::Double            theMergeTolerance)
   throw ( SALOME::SALOME_Exception )
@@ -1765,7 +1896,7 @@ SMESH_Gen_i::ConcatenateWithGroups(const SMESH::mesh_array& theMeshesArray,
                            theUniteIdenticalGroups,
                            theMergeNodesAndElements,
                            theMergeTolerance,
-                          true);
+                           true);
 }
 
 //================================================================================
@@ -1778,10 +1909,10 @@ SMESH_Gen_i::ConcatenateWithGroups(const SMESH::mesh_array& theMeshesArray,
 
 SMESH::SMESH_Mesh_ptr
 SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
-                              CORBA::Boolean           theUniteIdenticalGroups, 
+                               CORBA::Boolean           theUniteIdenticalGroups, 
                                CORBA::Boolean           theMergeNodesAndElements, 
                                CORBA::Double            theMergeTolerance,
-                              CORBA::Boolean           theCommonGroups)
+                               CORBA::Boolean           theCommonGroups)
   throw ( SALOME::SALOME_Exception )
 {
   typedef map<int, int> TIDsMap;
@@ -1789,16 +1920,18 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
   typedef map< pair<string, SMESH::ElementType>, TListOfNewGroups > TGroupsMap;
   typedef std::set<SMESHDS_GroupBase*> TGroups;
 
-  TPythonDump aPythonDump; // prevent dump of called methods
+  TPythonDump* pPythonDump = new TPythonDump;
+  TPythonDump& aPythonDump = *pPythonDump; // prevent dump of called methods
 
   // create mesh
   SMESH::SMESH_Mesh_var aNewMesh = CreateEmptyMesh();
   
+  SMESHDS_Mesh* aNewMeshDS = 0;
   if ( !aNewMesh->_is_nil() ) {
     SMESH_Mesh_i* aNewImpl = dynamic_cast<SMESH_Mesh_i*>( GetServant( aNewMesh ).in() );
     if ( aNewImpl ) {
       ::SMESH_Mesh& aLocMesh = aNewImpl->GetImpl();
-      SMESHDS_Mesh* aNewMeshDS = aLocMesh.GetMeshDS();
+      aNewMeshDS = aLocMesh.GetMeshDS();
 
       TGroupsMap aGroupsMap;
       TListOfNewGroups aListOfNewGroups;
@@ -1807,236 +1940,236 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
 
       // loop on meshes
       for ( int i = 0; i < theMeshesArray.length(); i++) {
-       SMESH::SMESH_Mesh_var anInitMesh = theMeshesArray[i];
-       if ( !anInitMesh->_is_nil() ) {
-         SMESH_Mesh_i* anInitImpl = dynamic_cast<SMESH_Mesh_i*>( GetServant( anInitMesh ).in() );
-         if ( anInitImpl ) {
-           ::SMESH_Mesh& aInitLocMesh = anInitImpl->GetImpl();
-           SMESHDS_Mesh* anInitMeshDS = aInitLocMesh.GetMeshDS();
-
-           TIDsMap nodesMap;
-           TIDsMap elemsMap;
-
-           // loop on elements of mesh
-           SMDS_ElemIteratorPtr itElems = anInitMeshDS->elementsIterator();
-           const SMDS_MeshElement* anElem = 0;
-           const SMDS_MeshElement* aNewElem = 0;
-           int anElemNbNodes = 0;
-
-           int anNbNodes   = 0;
-           int anNbEdges   = 0;
-           int anNbFaces   = 0;
-           int anNbVolumes = 0;
-
-           SMESH::long_array_var anIDsNodes   = new SMESH::long_array();
-           SMESH::long_array_var anIDsEdges   = new SMESH::long_array();
-           SMESH::long_array_var anIDsFaces   = new SMESH::long_array();
-           SMESH::long_array_var anIDsVolumes = new SMESH::long_array();
-
-           if( theCommonGroups ) {
-             anIDsNodes->length(   anInitMeshDS->NbNodes()   );
-             anIDsEdges->length(   anInitMeshDS->NbEdges()   );
-             anIDsFaces->length(   anInitMeshDS->NbFaces()   );
-             anIDsVolumes->length( anInitMeshDS->NbVolumes() );
-           }
-
-           for ( int j = 0; itElems->more(); j++) {
-             anElem = itElems->next();
-             SMDSAbs_ElementType anElemType = anElem->GetType();
-             anElemNbNodes = anElem->NbNodes();
-             std::vector<const SMDS_MeshNode*> aNodesArray (anElemNbNodes);
-
-             // loop on nodes of element
-             const SMDS_MeshNode* aNode = 0;
-             const SMDS_MeshNode* aNewNode = 0;
-             SMDS_ElemIteratorPtr itNodes = anElem->nodesIterator();
-
-             for ( int k = 0; itNodes->more(); k++) {
-               aNode = static_cast<const SMDS_MeshNode*>(itNodes->next());
-               if ( nodesMap.find(aNode->GetID()) == nodesMap.end() ) {
-                 aNewNode = aNewMeshDS->AddNode(aNode->X(), aNode->Y(), aNode->Z());
-                 nodesMap.insert( make_pair(aNode->GetID(), aNewNode->GetID()) );
-                 if( theCommonGroups )
-                   anIDsNodes[anNbNodes++] = aNewNode->GetID();
-               }
-               else
-                 aNewNode = aNewMeshDS->FindNode( nodesMap.find(aNode->GetID())->second );
-               aNodesArray[k] = aNewNode;
-             }//nodes loop
-
-             // creates a corresponding element on existent nodes in new mesh
-             if ( anElem->IsPoly() && anElemType == SMDSAbs_Volume )
-               {
-                 const SMDS_PolyhedralVolumeOfNodes* aVolume =
-                   dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*> (anElem);
-                 if ( aVolume ) {
-                   aNewElem = aNewMeshDS->AddPolyhedralVolume(aNodesArray, 
-                                                              aVolume->GetQuanities());
-                   elemsMap.insert(make_pair(anElem->GetID(), aNewElem->GetID()));
-                   if( theCommonGroups )
-                     anIDsVolumes[anNbVolumes++] = aNewElem->GetID();
-                 }
-               }
-             else {
-               
-               aNewElem = aNewEditor.AddElement(aNodesArray,
-                                                anElemType,
-                                                anElem->IsPoly());
-               elemsMap.insert(make_pair(anElem->GetID(), aNewElem->GetID()));
-               if( theCommonGroups ) {
-                 if( anElemType == SMDSAbs_Edge )
-                   anIDsEdges[anNbEdges++] = aNewElem->GetID();
-                 else if( anElemType == SMDSAbs_Face )
-                   anIDsFaces[anNbFaces++] = aNewElem->GetID();
-                 else if( anElemType == SMDSAbs_Volume )
-                   anIDsVolumes[anNbVolumes++] = aNewElem->GetID();
-               }
-             } 
-           }//elems loop
-           
-           aListOfGroups = anInitImpl->GetGroups();
-           SMESH::SMESH_GroupBase_ptr aGroup;
-
-           // loop on groups of mesh
-           SMESH::long_array_var anInitIDs = new SMESH::long_array();
-           SMESH::long_array_var anNewIDs = new SMESH::long_array();
-           SMESH::SMESH_Group_var aNewGroup;
-
-           SMESH::ElementType aGroupType;
-           CORBA::String_var aGroupName;
-           if ( theCommonGroups ) {
-             for(aGroupType=SMESH::NODE;aGroupType<=SMESH::VOLUME;aGroupType=(SMESH::ElementType)(aGroupType+1)) {
-               string str = "Gr";
-               SALOMEDS::SObject_var aMeshSObj = ObjectToSObject( myCurrentStudy, anInitMesh );
-               if(aMeshSObj)
-                 str += aMeshSObj->GetName();
-               str += "_";
-
-               int anLen = 0;
-
-               switch(aGroupType) {
-               case SMESH::NODE:
-                 str += "Nodes";
-                 anIDsNodes->length(anNbNodes);
-                 anLen = anNbNodes;
-                 break;
-               case SMESH::EDGE:
-                 str += "Edges";
-                 anIDsEdges->length(anNbEdges);
-                 anLen = anNbEdges;
-                 break;
-               case SMESH::FACE:
-                 str += "Faces";
-                 anIDsFaces->length(anNbFaces);
-                 anLen = anNbFaces;
-                 break;
-               case SMESH::VOLUME:
-                 str += "Volumes";
-                 anIDsVolumes->length(anNbVolumes);
-                 anLen = anNbVolumes;
-                 break;
-               default:
-                 break;
-               }
-
-               if(anLen) {
-                 aGroupName = str.c_str();
-
-                 // add a new group in the mesh
-                 aNewGroup = aNewImpl->CreateGroup(aGroupType, aGroupName);
-
-                 switch(aGroupType) {
-                 case SMESH::NODE:
-                   aNewGroup->Add( anIDsNodes );
-                   break;
-                 case SMESH::EDGE:
-                   aNewGroup->Add( anIDsEdges );
-                   break;
-                 case SMESH::FACE:
-                   aNewGroup->Add( anIDsFaces );
-                   break;
-                 case SMESH::VOLUME:
-                   aNewGroup->Add( anIDsVolumes );
-                   break;
-                 default:
-                   break;
-                 }
-               
-                 aListOfNewGroups.clear();
-                 aListOfNewGroups.push_back(aNewGroup);
-                 aGroupsMap.insert(make_pair( make_pair(aGroupName, aGroupType), aListOfNewGroups ));
-               }
-             }
-           }
-
-           // check that current group name and type don't have identical ones in union mesh
-           for (int i = 0; i < aListOfGroups->length(); i++) {
-             aGroup = aListOfGroups[i];
-             aListOfNewGroups.clear();
-             aGroupType = aGroup->GetType();
-             aGroupName = aGroup->GetName();
-
-             TGroupsMap::iterator anIter = aGroupsMap.find(make_pair(aGroupName, aGroupType));
-
-             // convert a list of IDs
-             anInitIDs = aGroup->GetListOfID();
-             anNewIDs->length(anInitIDs->length());
-             if ( aGroupType == SMESH::NODE )
-               for (int j = 0; j < anInitIDs->length(); j++) {
-                 anNewIDs[j] = nodesMap.find(anInitIDs[j])->second;
-               }
-             else
-               for (int j = 0; j < anInitIDs->length(); j++) {
-                 anNewIDs[j] = elemsMap.find(anInitIDs[j])->second;
-               }
-             
-             // check that current group name and type don't have identical ones in union mesh
-             if ( anIter == aGroupsMap.end() ) {
-               // add a new group in the mesh
-               aNewGroup = aNewImpl->CreateGroup(aGroupType, aGroupName);
-               // add elements into new group
-               aNewGroup->Add( anNewIDs );
-               
-               aListOfNewGroups.push_back(aNewGroup);
-               aGroupsMap.insert(make_pair( make_pair(aGroupName, aGroupType), aListOfNewGroups ));
-             }
-
-             else if ( theUniteIdenticalGroups ) {
-               // unite identical groups
-               TListOfNewGroups& aNewGroups = anIter->second;
-               aNewGroups.front()->Add( anNewIDs );
-             }
-
-             else {
-               // rename identical groups
-               aNewGroup = aNewImpl->CreateGroup(aGroupType, aGroupName);
-               aNewGroup->Add( anNewIDs );
-               
-               TListOfNewGroups& aNewGroups = anIter->second;
-               string aNewGroupName;
-               if (aNewGroups.size() == 1) {
-                 aNewGroupName = string(aGroupName) + "_1";
-                 aNewGroups.front()->SetName(aNewGroupName.c_str());
-               }
-               char aGroupNum[128];
-               sprintf(aGroupNum, "%u", aNewGroups.size()+1);
-               aNewGroupName = string(aGroupName) + "_" + string(aGroupNum);
-               aNewGroup->SetName(aNewGroupName.c_str());
-               aNewGroups.push_back(aNewGroup);
-             }
-           }//groups loop
-         }
-       }
+        SMESH::SMESH_Mesh_var anInitMesh = theMeshesArray[i];
+        if ( !anInitMesh->_is_nil() ) {
+          SMESH_Mesh_i* anInitImpl = dynamic_cast<SMESH_Mesh_i*>( GetServant( anInitMesh ).in() );
+          if ( anInitImpl ) {
+            ::SMESH_Mesh& aInitLocMesh = anInitImpl->GetImpl();
+            SMESHDS_Mesh* anInitMeshDS = aInitLocMesh.GetMeshDS();
+
+            TIDsMap nodesMap;
+            TIDsMap elemsMap;
+
+            // loop on elements of mesh
+            SMDS_ElemIteratorPtr itElems = anInitMeshDS->elementsIterator();
+            const SMDS_MeshElement* anElem = 0;
+            const SMDS_MeshElement* aNewElem = 0;
+            int anElemNbNodes = 0;
+
+            int anNbNodes   = 0;
+            int anNbEdges   = 0;
+            int anNbFaces   = 0;
+            int anNbVolumes = 0;
+
+            SMESH::long_array_var anIDsNodes   = new SMESH::long_array();
+            SMESH::long_array_var anIDsEdges   = new SMESH::long_array();
+            SMESH::long_array_var anIDsFaces   = new SMESH::long_array();
+            SMESH::long_array_var anIDsVolumes = new SMESH::long_array();
+
+            if( theCommonGroups ) {
+              anIDsNodes->length(   anInitMeshDS->NbNodes()   );
+              anIDsEdges->length(   anInitMeshDS->NbEdges()   );
+              anIDsFaces->length(   anInitMeshDS->NbFaces()   );
+              anIDsVolumes->length( anInitMeshDS->NbVolumes() );
+            }
+
+            for ( int j = 0; itElems->more(); j++) {
+              anElem = itElems->next();
+              SMDSAbs_ElementType anElemType = anElem->GetType();
+              anElemNbNodes = anElem->NbNodes();
+              std::vector<const SMDS_MeshNode*> aNodesArray (anElemNbNodes);
+
+              // loop on nodes of element
+              const SMDS_MeshNode* aNode = 0;
+              const SMDS_MeshNode* aNewNode = 0;
+              SMDS_ElemIteratorPtr itNodes = anElem->nodesIterator();
+
+              for ( int k = 0; itNodes->more(); k++) {
+                aNode = static_cast<const SMDS_MeshNode*>(itNodes->next());
+                if ( nodesMap.find(aNode->GetID()) == nodesMap.end() ) {
+                  aNewNode = aNewMeshDS->AddNode(aNode->X(), aNode->Y(), aNode->Z());
+                  nodesMap.insert( make_pair(aNode->GetID(), aNewNode->GetID()) );
+                  if( theCommonGroups )
+                    anIDsNodes[anNbNodes++] = aNewNode->GetID();
+                }
+                else
+                  aNewNode = aNewMeshDS->FindNode( nodesMap.find(aNode->GetID())->second );
+                aNodesArray[k] = aNewNode;
+              }//nodes loop
+
+              // creates a corresponding element on existent nodes in new mesh
+              if ( anElem->IsPoly() && anElemType == SMDSAbs_Volume )
+                {
+                  const SMDS_VtkVolume* aVolume =
+                    dynamic_cast<const SMDS_VtkVolume*> (anElem);
+                  if ( aVolume ) {
+                    aNewElem = aNewMeshDS->AddPolyhedralVolume(aNodesArray, 
+                                                               aVolume->GetQuantities());
+                    elemsMap.insert(make_pair(anElem->GetID(), aNewElem->GetID()));
+                    if( theCommonGroups )
+                      anIDsVolumes[anNbVolumes++] = aNewElem->GetID();
+                  }
+                }
+              else {
+                
+                aNewElem = aNewEditor.AddElement(aNodesArray,
+                                                 anElemType,
+                                                 anElem->IsPoly());
+                elemsMap.insert(make_pair(anElem->GetID(), aNewElem->GetID()));
+                if( theCommonGroups ) {
+                  if( anElemType == SMDSAbs_Edge )
+                    anIDsEdges[anNbEdges++] = aNewElem->GetID();
+                  else if( anElemType == SMDSAbs_Face )
+                    anIDsFaces[anNbFaces++] = aNewElem->GetID();
+                  else if( anElemType == SMDSAbs_Volume )
+                    anIDsVolumes[anNbVolumes++] = aNewElem->GetID();
+                }
+              
+            }//elems loop
+            
+            aListOfGroups = anInitImpl->GetGroups();
+            SMESH::SMESH_GroupBase_ptr aGroup;
+
+            // loop on groups of mesh
+            SMESH::long_array_var anInitIDs = new SMESH::long_array();
+            SMESH::long_array_var anNewIDs = new SMESH::long_array();
+            SMESH::SMESH_Group_var aNewGroup;
+
+            SMESH::ElementType aGroupType;
+            CORBA::String_var aGroupName;
+            if ( theCommonGroups ) {
+              for(aGroupType=SMESH::NODE;aGroupType<=SMESH::VOLUME;aGroupType=(SMESH::ElementType)(aGroupType+1)) {
+                string str = "Gr";
+                SALOMEDS::SObject_var aMeshSObj = ObjectToSObject( myCurrentStudy, anInitMesh );
+                if(aMeshSObj)
+                  str += aMeshSObj->GetName();
+                str += "_";
+
+                int anLen = 0;
+
+                switch(aGroupType) {
+                case SMESH::NODE:
+                  str += "Nodes";
+                  anIDsNodes->length(anNbNodes);
+                  anLen = anNbNodes;
+                  break;
+                case SMESH::EDGE:
+                  str += "Edges";
+                  anIDsEdges->length(anNbEdges);
+                  anLen = anNbEdges;
+                  break;
+                case SMESH::FACE:
+                  str += "Faces";
+                  anIDsFaces->length(anNbFaces);
+                  anLen = anNbFaces;
+                  break;
+                case SMESH::VOLUME:
+                  str += "Volumes";
+                  anIDsVolumes->length(anNbVolumes);
+                  anLen = anNbVolumes;
+                  break;
+                default:
+                  break;
+                }
+
+                if(anLen) {
+                  aGroupName = str.c_str();
+
+                  // add a new group in the mesh
+                  aNewGroup = aNewImpl->CreateGroup(aGroupType, aGroupName);
+
+                  switch(aGroupType) {
+                  case SMESH::NODE:
+                    aNewGroup->Add( anIDsNodes );
+                    break;
+                  case SMESH::EDGE:
+                    aNewGroup->Add( anIDsEdges );
+                    break;
+                  case SMESH::FACE:
+                    aNewGroup->Add( anIDsFaces );
+                    break;
+                  case SMESH::VOLUME:
+                    aNewGroup->Add( anIDsVolumes );
+                    break;
+                  default:
+                    break;
+                  }
+                
+                  aListOfNewGroups.clear();
+                  aListOfNewGroups.push_back(aNewGroup);
+                  aGroupsMap.insert(make_pair( make_pair(aGroupName, aGroupType), aListOfNewGroups ));
+                }
+              }
+            }
+
+            // check that current group name and type don't have identical ones in union mesh
+            for (int i = 0; i < aListOfGroups->length(); i++) {
+              aGroup = aListOfGroups[i];
+              aListOfNewGroups.clear();
+              aGroupType = aGroup->GetType();
+              aGroupName = aGroup->GetName();
+
+              TGroupsMap::iterator anIter = aGroupsMap.find(make_pair(aGroupName, aGroupType));
+
+              // convert a list of IDs
+              anInitIDs = aGroup->GetListOfID();
+              anNewIDs->length(anInitIDs->length());
+              if ( aGroupType == SMESH::NODE )
+                for (int j = 0; j < anInitIDs->length(); j++) {
+                  anNewIDs[j] = nodesMap.find(anInitIDs[j])->second;
+                }
+              else
+                for (int j = 0; j < anInitIDs->length(); j++) {
+                  anNewIDs[j] = elemsMap.find(anInitIDs[j])->second;
+                }
+              
+              // check that current group name and type don't have identical ones in union mesh
+              if ( anIter == aGroupsMap.end() ) {
+                // add a new group in the mesh
+                aNewGroup = aNewImpl->CreateGroup(aGroupType, aGroupName);
+                // add elements into new group
+                aNewGroup->Add( anNewIDs );
+                
+                aListOfNewGroups.push_back(aNewGroup);
+                aGroupsMap.insert(make_pair( make_pair(aGroupName, aGroupType), aListOfNewGroups ));
+              }
+
+              else if ( theUniteIdenticalGroups ) {
+                // unite identical groups
+                TListOfNewGroups& aNewGroups = anIter->second;
+                aNewGroups.front()->Add( anNewIDs );
+              }
+
+              else {
+                // rename identical groups
+                aNewGroup = aNewImpl->CreateGroup(aGroupType, aGroupName);
+                aNewGroup->Add( anNewIDs );
+                
+                TListOfNewGroups& aNewGroups = anIter->second;
+                string aNewGroupName;
+                if (aNewGroups.size() == 1) {
+                  aNewGroupName = string(aGroupName) + "_1";
+                  aNewGroups.front()->SetName(aNewGroupName.c_str());
+                }
+                char aGroupNum[128];
+                sprintf(aGroupNum, "%u", aNewGroups.size()+1);
+                aNewGroupName = string(aGroupName) + "_" + string(aGroupNum);
+                aNewGroup->SetName(aNewGroupName.c_str());
+                aNewGroups.push_back(aNewGroup);
+              }
+            }//groups loop
+          }
+        }
       }//meshes loop
 
       if (theMergeNodesAndElements) {
-       // merge nodes
-       set<const SMDS_MeshNode*> aMeshNodes; // no input nodes
-       SMESH_MeshEditor::TListOfListOfNodes aGroupsOfNodes;
-       aNewEditor.FindCoincidentNodes( aMeshNodes, theMergeTolerance, aGroupsOfNodes );
-       aNewEditor.MergeNodes( aGroupsOfNodes );
-       // merge elements
-       aNewEditor.MergeEqualElements();
+        // merge nodes
+        TIDSortedNodeSet aMeshNodes; // no input nodes
+        SMESH_MeshEditor::TListOfListOfNodes aGroupsOfNodes;
+        aNewEditor.FindCoincidentNodes( aMeshNodes, theMergeTolerance, aGroupsOfNodes );
+        aNewEditor.MergeNodes( aGroupsOfNodes );
+        // merge elements
+        aNewEditor.MergeEqualElements();
       }
     }
   }
@@ -2054,12 +2187,280 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
   }
   aPythonDump << "], ";
   aPythonDump << theUniteIdenticalGroups << ", "
-             << theMergeNodesAndElements << ", "
+              << theMergeNodesAndElements << ", "
               << theMergeTolerance << ")";
 
+  delete pPythonDump; // enable python dump from GetGroups()
+
+  // 0020577: EDF 1164 SMESH: Bad dump of concatenate with create common groups
+  if ( !aNewMesh->_is_nil() )
+  {
+    SMESH::ListOfGroups_var groups = aNewMesh->GetGroups();
+  }
+
+  // IPAL21468 Change icon of compound because it need not be computed.
+  SALOMEDS::SObject_var aMeshSObj = ObjectToSObject( myCurrentStudy, aNewMesh );
+  if( !aMeshSObj->_is_nil() ) {
+    SALOMEDS::GenericAttribute_var anAttr;
+    SALOMEDS::StudyBuilder_var aBuilder = myCurrentStudy->NewBuilder();
+    anAttr = aBuilder->FindOrCreateAttribute( aMeshSObj,"AttributePixMap" );
+    SALOMEDS::AttributePixMap_var aPixmap = SALOMEDS::AttributePixMap::_narrow(anAttr);
+    aPixmap->SetPixMap("ICON_SMESH_TREE_MESH");
+  }
+  if (aNewMeshDS)
+    aNewMeshDS->Modified();
   return aNewMesh._retn();
 }
 
+//================================================================================
+/*!
+ * \brief Create a mesh by copying a part of another mesh
+ *  \param meshPart - a part of mesh to copy
+ *  \param toCopyGroups - to create in the new mesh groups
+ *                        the copied elements belongs to
+ *  \param toKeepIDs - to preserve IDs of the copied elements or not
+ *  \retval SMESH::SMESH_Mesh_ptr - the new mesh
+ */
+//================================================================================
+
+SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CopyMesh(SMESH::SMESH_IDSource_ptr meshPart,
+                                            const char*               meshName,
+                                            CORBA::Boolean            toCopyGroups,
+                                            CORBA::Boolean            toKeepIDs)
+{
+  Unexpect aCatch(SALOME_SalomeException);
+
+  TPythonDump* pyDump = new TPythonDump; // prevent dump from CreateMesh()
+
+  // 1. Get source mesh
+
+  if ( CORBA::is_nil( meshPart ))
+    THROW_SALOME_CORBA_EXCEPTION( "bad IDSource", SALOME::BAD_PARAM );
+
+  SMESH::SMESH_Mesh_var srcMesh = meshPart->GetMesh();
+  SMESH_Mesh_i*       srcMesh_i = SMESH::DownCast<SMESH_Mesh_i*>( srcMesh );
+  if ( !srcMesh_i )
+    THROW_SALOME_CORBA_EXCEPTION( "bad mesh of IDSource", SALOME::BAD_PARAM );
+  
+  SMESHDS_Mesh* srcMeshDS = srcMesh_i->GetImpl().GetMeshDS();
+
+  // 2. Make a new mesh
+
+  SMESH::SMESH_Mesh_var newMesh = CreateMesh(GEOM::GEOM_Object::_nil());
+  SMESH_Mesh_i*       newMesh_i = SMESH::DownCast<SMESH_Mesh_i*>( newMesh );
+  if ( !newMesh_i )
+    THROW_SALOME_CORBA_EXCEPTION( "can't create a mesh", SALOME::INTERNAL_ERROR );
+  SALOMEDS::SObject_var meshSO = ObjectToSObject(myCurrentStudy, newMesh );
+  if ( !meshSO->_is_nil() )
+  {
+    SetName( meshSO, meshName, "Mesh" );
+    SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
+  }
+  SMESHDS_Mesh* newMeshDS = newMesh_i->GetImpl().GetMeshDS();
+  ::SMESH_MeshEditor editor( &newMesh_i->GetImpl() );
+
+  // 3. Get elements to copy
+
+  SMDS_ElemIteratorPtr srcElemIt;
+  TIDSortedElemSet srcElems;
+  SMESH::array_of_ElementType_var srcElemTypes = meshPart->GetTypes();
+  if ( SMESH::DownCast<SMESH_Mesh_i*>( meshPart ))
+  {
+    srcElemIt = srcMeshDS->elementsIterator();
+  }
+  else
+  {
+    SMESH::long_array_var ids = meshPart->GetIDs();
+    if ( srcElemTypes->length() == 1 && srcElemTypes[0] == SMESH::NODE ) // group of nodes
+    {
+      for (int i=0; i < ids->length(); i++)
+        if ( const SMDS_MeshElement * elem = srcMeshDS->FindNode( ids[i] ))
+          srcElems.insert( elem );
+    }
+    else
+    {
+      for (int i=0; i < ids->length(); i++)
+        if ( const SMDS_MeshElement * elem = srcMeshDS->FindElement( ids[i] ))
+          srcElems.insert( elem );
+    }
+    if ( srcElems.empty() )
+      return newMesh._retn();
+
+    typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator > ElIter;
+    srcElemIt = SMDS_ElemIteratorPtr( new ElIter( srcElems.begin(), srcElems.end() ));
+  }
+
+  // 4. Copy elements
+
+  typedef map<SMDS_pElement, SMDS_pElement, TIDCompare> TE2EMap;
+  TE2EMap e2eMapByType[ SMDSAbs_NbElementTypes ];
+  TE2EMap& n2nMap = e2eMapByType[ SMDSAbs_Node ];
+  int iN;
+  const SMDS_MeshNode *nSrc, *nTgt;
+  vector< const SMDS_MeshNode* > nodes;
+  while ( srcElemIt->more() )
+  {
+    const SMDS_MeshElement * elem = srcElemIt->next();
+    nodes.resize( elem->NbNodes());
+    SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
+    if ( toKeepIDs ) {
+      for ( iN = 0; nIt->more(); ++iN )
+      {
+        nSrc = static_cast<const SMDS_MeshNode*>( nIt->next() );
+        nTgt = newMeshDS->FindNode( nSrc->GetID());
+        if ( !nTgt )
+          nTgt = newMeshDS->AddNodeWithID( nSrc->X(), nSrc->Y(), nSrc->Z(), nSrc->GetID());
+        nodes[ iN ] = nTgt;
+      }
+    }
+    else {
+      for ( iN = 0; nIt->more(); ++iN )
+      {
+        nSrc = static_cast<const SMDS_MeshNode*>( nIt->next() );
+        TE2EMap::iterator n2n = n2nMap.insert( make_pair( nSrc, SMDS_pNode(0) )).first;
+        if ( !n2n->second )
+          n2n->second = newMeshDS->AddNode( nSrc->X(), nSrc->Y(), nSrc->Z() );
+        nodes[ iN ] = (const SMDS_MeshNode*) n2n->second;
+      }
+    }
+    if ( elem->GetType() != SMDSAbs_Node )
+    {
+      int ID = toKeepIDs ? elem->GetID() : 0;
+      const SMDS_MeshElement * newElem = editor.AddElement( nodes,
+                                                            elem->GetType(),
+                                                            elem->IsPoly(),
+                                                            ID);
+      if ( toCopyGroups && !toKeepIDs )
+        e2eMapByType[ elem->GetType() ].insert( make_pair( elem, newElem ));
+    }
+  }
+
+  // 5. Copy groups
+
+  int nbNewGroups = 0;
+  if ( toCopyGroups )
+  {
+    SMESH_Mesh::GroupIteratorPtr gIt = srcMesh_i->GetImpl().GetGroups();
+    while ( gIt->more() )
+    {
+      SMESH_Group* group = gIt->next();
+      const SMESHDS_GroupBase* groupDS = group->GetGroupDS();
+
+      // Check group type. We copy nodal groups containing nodes of copied element
+      SMDSAbs_ElementType groupType = groupDS->GetType();
+      if ( groupType != SMDSAbs_Node &&
+           newMeshDS->GetMeshInfo().NbElements( groupType ) == 0 )
+        continue; // group type differs from types of meshPart
+
+      // Find copied elements in the group
+      vector< const SMDS_MeshElement* > groupElems;
+      SMDS_ElemIteratorPtr eIt = groupDS->GetElements();
+      if ( toKeepIDs )
+      {
+        const SMDS_MeshElement* foundElem;
+        if ( groupType == SMDSAbs_Node )
+        {
+          while ( eIt->more() )
+            if (( foundElem = newMeshDS->FindNode( eIt->next()->GetID() )))
+              groupElems.push_back( foundElem );
+        }
+        else
+        {
+          while ( eIt->more() )
+            if (( foundElem = newMeshDS->FindElement( eIt->next()->GetID() )))
+              groupElems.push_back( foundElem );
+        }
+      }
+      else
+      {
+        TE2EMap & e2eMap = e2eMapByType[ groupDS->GetType() ];
+        if ( e2eMap.empty() ) continue;
+        int minID = e2eMap.begin()->first->GetID();
+        int maxID = e2eMap.rbegin()->first->GetID();
+        TE2EMap::iterator e2e;
+        while ( eIt->more() && groupElems.size() < e2eMap.size())
+        {
+          const SMDS_MeshElement* e = eIt->next();
+          if ( e->GetID() < minID || e->GetID() > maxID ) continue;
+          if ((e2e = e2eMap.find( e )) != e2eMap.end())
+            groupElems.push_back( e2e->second );
+        }
+      }
+      // Make a new group
+      if ( !groupElems.empty() )
+      {
+        SMESH::SMESH_Group_var newGroupObj =
+          newMesh->CreateGroup( SMESH::ElementType(groupType), group->GetName() );
+        if ( SMESH_GroupBase_i* newGroup_i = SMESH::DownCast<SMESH_GroupBase_i*>( newGroupObj))
+        {
+          SMESHDS_GroupBase * newGroupDS = newGroup_i->GetGroupDS();
+          SMDS_MeshGroup& smdsGroup = ((SMESHDS_Group*)newGroupDS)->SMDSGroup();
+          for ( unsigned i = 0; i < groupElems.size(); ++i )
+            smdsGroup.Add( groupElems[i] );
+
+          nbNewGroups++;
+        }
+      }
+    }
+  }
+
+  *pyDump << newMesh << " = " << this
+          << ".CopyMesh( " << meshPart << ", "
+          << "'" << meshName << "', "
+          << toCopyGroups << ", "
+          << toKeepIDs << ")";
+
+  delete pyDump; pyDump = 0; // allow dump in GetGroups()
+
+  if ( nbNewGroups > 0 ) // dump created groups
+    SMESH::ListOfGroups_var groups = newMesh->GetGroups();
+
+  return newMesh._retn();
+}
+
+//================================================================================
+/*!
+ *  SMESH_Gen_i::GetMEDVersion
+ *
+ *  Get MED version of the file by its name
+ */
+//================================================================================
+CORBA::Boolean SMESH_Gen_i::GetMEDVersion(const char* theFileName,
+                                          SMESH::MED_VERSION& theVersion)
+{
+  theVersion = SMESH::MED_V2_1;
+  MED::EVersion aVersion = MED::GetVersionId( theFileName );
+  switch( aVersion ) {
+    case MED::eV2_1     : theVersion = SMESH::MED_V2_1; return true;
+    case MED::eV2_2     : theVersion = SMESH::MED_V2_2; return true;
+    case MED::eVUnknown : return false;
+  }
+  return false;
+}
+
+//================================================================================
+/*!
+ *  SMESH_Gen_i::GetMeshNames
+ *
+ *  Get names of meshes defined in file with the specified name
+ */
+//================================================================================
+SMESH::string_array* SMESH_Gen_i::GetMeshNames(const char* theFileName)
+{
+  SMESH::string_array_var aResult = new SMESH::string_array();
+  MED::PWrapper aMed = MED::CrWrapper( theFileName );
+  MED::TErr anErr;
+  MED::TInt aNbMeshes = aMed->GetNbMeshes( &anErr );
+  if( anErr >= 0 ) {
+    aResult->length( aNbMeshes );
+    for( MED::TInt i = 0; i < aNbMeshes; i++ ) {
+      MED::PMeshInfo aMeshInfo = aMed->GetPMeshInfo( i+1 );
+      aResult[i] = CORBA::string_dup( aMeshInfo->GetName().c_str() );
+    }
+  }
+  return aResult._retn();
+}
+
 //=============================================================================
 /*!
  *  SMESH_Gen_i::Save
@@ -2136,6 +2537,38 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
   DriverMED_W_SMESHDS_Mesh myWriter;
   myWriter.SetFile( meshfile.ToCString() );
 
+  // IMP issue 20918
+  // SetStoreName() to groups before storing hypotheses to let them refer to
+  // groups using "store name", which is "Group <group_persistent_id>"
+  {
+    SALOMEDS::ChildIterator_var itBig = myCurrentStudy->NewChildIterator( theComponent );
+    for ( ; itBig->More(); itBig->Next() ) {
+      SALOMEDS::SObject_var gotBranch = itBig->Value();
+      if ( gotBranch->Tag() > GetAlgorithmsRootTag() ) {
+        CORBA::Object_var anObject = SObjectToObject( gotBranch );
+        if ( !CORBA::is_nil( anObject ) ) {
+          SMESH::SMESH_Mesh_var myMesh = SMESH::SMESH_Mesh::_narrow( anObject ) ;
+          if ( !myMesh->_is_nil() ) {
+            SMESH::ListOfGroups_var groups = myMesh->GetGroups();
+            for ( int i = 0; i < groups->length(); ++i )
+            {
+              SMESH_GroupBase_i* grImpl = SMESH::DownCast<SMESH_GroupBase_i*>( groups[i]);
+              if ( grImpl )
+              {
+                CORBA::String_var objStr = GetORB()->object_to_string( grImpl->_this() );
+                int anId = myStudyContext->findId( string( objStr.in() ) );
+                char grpName[ 30 ];
+                sprintf( grpName, "Group %d", anId );
+                SMESHDS_GroupBase* aGrpBaseDS = grImpl->GetGroupDS();
+                aGrpBaseDS->SetStoreName( grpName );
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
   // Write data
   // ---> create HDF file
   aFile = new HDFfile( (char*) filename.ToCString() );
@@ -2319,17 +2752,33 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
             aDataset->WriteOnDisk( ( char* )( strHasData.c_str() ) );
             aDataset->CloseOnDisk();
 
-           // ouv : NPAL12872
+            // ouv : NPAL12872
             // for each mesh open the HDF group basing on its auto color parameter
-           char meshAutoColorName[ 30 ];
-           sprintf( meshAutoColorName, "AutoColorMesh %d", id );
-           int anAutoColor[1];
-           anAutoColor[0] = myImpl->GetAutoColor();
-           aSize[ 0 ] = 1;
-           aDataset = new HDFdataset( meshAutoColorName, aTopGroup, HDF_INT32, aSize, 1 );
-           aDataset->CreateOnDisk();
-           aDataset->WriteOnDisk( anAutoColor );
-           aDataset->CloseOnDisk();
+            char meshAutoColorName[ 30 ];
+            sprintf( meshAutoColorName, "AutoColorMesh %d", id );
+            int anAutoColor[1];
+            anAutoColor[0] = myImpl->GetAutoColor();
+            aSize[ 0 ] = 1;
+            aDataset = new HDFdataset( meshAutoColorName, aTopGroup, HDF_INT32, aSize, 1 );
+            aDataset->CreateOnDisk();
+            aDataset->WriteOnDisk( anAutoColor );
+            aDataset->CloseOnDisk();
+
+            // issue 0020693. Store _isModified flag
+            int isModified = myLocMesh.GetIsModified();
+            aSize[ 0 ] = 1;
+            aDataset = new HDFdataset( "_isModified", aTopGroup, HDF_INT32, aSize, 1 );
+            aDataset->CreateOnDisk();
+            aDataset->WriteOnDisk( &isModified );
+            aDataset->CloseOnDisk();
+
+            // issue 20918. Store Persistent Id of SMESHDS_Mesh
+            int meshPersistentId = mySMESHDSMesh->GetPersistentId();
+            aSize[ 0 ] = 1;
+            aDataset = new HDFdataset( "meshPersistentId", aTopGroup, HDF_INT32, aSize, 1 );
+            aDataset->CreateOnDisk();
+            aDataset->WriteOnDisk( &meshPersistentId );
+            aDataset->CloseOnDisk();
 
             // write reference on a shape if exists
             SALOMEDS::SObject_var myRef;
@@ -2613,328 +3062,356 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
             //if ( shapeRefFound )
             //myWriter.AddAllSubMeshes();
 
-           // groups root sub-branch
-           SALOMEDS::SObject_var myGroupsBranch;
-           for ( int i = GetNodeGroupsTag(); i <= GetVolumeGroupsTag(); i++ ) {
-             found = gotBranch->FindSubObject( i, myGroupsBranch );
-             if ( found ) {
-               char name_group[ 30 ];
-               if ( i == GetNodeGroupsTag() )
-                 strcpy( name_group, "Groups of Nodes" );
-               else if ( i == GetEdgeGroupsTag() )
-                 strcpy( name_group, "Groups of Edges" );
-               else if ( i == GetFaceGroupsTag() )
-                 strcpy( name_group, "Groups of Faces" );
-               else if ( i == GetVolumeGroupsTag() )
-                 strcpy( name_group, "Groups of Volumes" );
-
-               aGroup = new HDFgroup( name_group, aTopGroup );
-               aGroup->CreateOnDisk();
-
-               SALOMEDS::ChildIterator_var it = myCurrentStudy->NewChildIterator( myGroupsBranch );
-               for ( ; it->More(); it->Next() ) {
-                 SALOMEDS::SObject_var mySObject = it->Value();
-                 CORBA::Object_var aSubObject = SObjectToObject( mySObject );
-                 if ( !CORBA::is_nil( aSubObject ) ) {
-                   SMESH_GroupBase_i* myGroupImpl =
-                     dynamic_cast<SMESH_GroupBase_i*>( GetServant( aSubObject ).in() );
-                   if ( !myGroupImpl )
-                     continue;
-                   
-                   CORBA::String_var objStr = GetORB()->object_to_string( aSubObject );
-                   int anId = myStudyContext->findId( string( objStr.in() ) );
-                   
-                   // For each group, create a dataset named "Group <group_persistent_id>"
-                   // and store the group's user name into it
-                   char grpName[ 30 ];
-                   sprintf( grpName, "Group %d", anId );
-                   char* aUserName = myGroupImpl->GetName();
-                   aSize[ 0 ] = strlen( aUserName ) + 1;
-                   
-                   aDataset = new HDFdataset( grpName, aGroup, HDF_STRING, aSize, 1 );
-                   aDataset->CreateOnDisk();
-                   aDataset->WriteOnDisk( aUserName );
-                   aDataset->CloseOnDisk();
-
-                   // ouv : NPAL12872
-                   // For each group, create a dataset named "Group <group_persistent_id> Color"
-                   // and store the group's color into it
-                   char grpColorName[ 30 ];
-                   sprintf( grpColorName, "ColorGroup %d", anId );
-                   SALOMEDS::Color aColor = myGroupImpl->GetColor();
-                   double anRGB[3];
-                   anRGB[ 0 ] = aColor.R;
-                   anRGB[ 1 ] = aColor.G;
-                   anRGB[ 2 ] = aColor.B;
-                   aSize[ 0 ] = 3;
-                   aDataset = new HDFdataset( grpColorName, aGroup, HDF_FLOAT64, aSize, 1 );
-                   aDataset->CreateOnDisk();
-                   aDataset->WriteOnDisk( anRGB );
-                   aDataset->CloseOnDisk();
-
-                   // Store the group contents into MED file
-                   if ( myLocMesh.GetGroup( myGroupImpl->GetLocalID() ) ) {
-                     
-                     if(MYDEBUG) MESSAGE( "VSR - SMESH_Gen_i::Save(): saving group with StoreName = "
-                                         << grpName << " to MED file" );
-                     SMESHDS_GroupBase* aGrpBaseDS =
-                       myLocMesh.GetGroup( myGroupImpl->GetLocalID() )->GetGroupDS();
-                     aGrpBaseDS->SetStoreName( grpName );
-
-                     // Pass SMESHDS_Group to MED writer 
-                     SMESHDS_Group* aGrpDS = dynamic_cast<SMESHDS_Group*>( aGrpBaseDS );
-                     if ( aGrpDS )
-                       myWriter.AddGroup( aGrpDS );
-                     
-                     // write reference on a shape if exists
-                     SMESHDS_GroupOnGeom* aGeomGrp =
-                       dynamic_cast<SMESHDS_GroupOnGeom*>( aGrpBaseDS );
-                     if ( aGeomGrp ) {
-                       SALOMEDS::SObject_var mySubRef, myShape;
-                       if (mySObject->FindSubObject( GetRefOnShapeTag(), mySubRef ) &&
-                           mySubRef->ReferencedObject( myShape ) &&
-                           !CORBA::is_nil( myShape->GetObject() ))
-                       {
-                         string myRefOnObject = myShape->GetID();
-                         if ( myRefOnObject.length() > 0 ) {
-                           char aRefName[ 30 ];
-                           sprintf( aRefName, "Ref on shape %d", anId);
-                           aSize[ 0 ] = myRefOnObject.length() + 1;
-                           aDataset = new HDFdataset(aRefName, aGroup, HDF_STRING, aSize, 1);
-                           aDataset->CreateOnDisk();
-                           aDataset->WriteOnDisk( ( char* )( myRefOnObject.c_str() ) );
-                           aDataset->CloseOnDisk();
-                         }
-                       }
-                       else // shape ref is invalid:
-                       {
-                         // save a group on geometry as ordinary group
-                         myWriter.AddGroup( aGeomGrp );
-                       }
-                     }
-                   }
-                 }
-               }
-               aGroup->CloseOnDisk();
-             }
-           } // loop on groups 
-           
-           if ( strcmp( strHasData.c_str(), "1" ) == 0 )
-           {
-             // Flush current mesh information into MED file
-             myWriter.Perform();
-             
-             // maybe a shape was deleted in the study
-             if ( !shapeRefFound && !mySMESHDSMesh->ShapeToMesh().IsNull() && hasShape) {
-               TopoDS_Shape nullShape;
-               myLocMesh.ShapeToMesh( nullShape ); // remove shape referring data
-             }
-             
-             if ( !mySMESHDSMesh->SubMeshes().empty() )
-             {
-               // Store submeshes
-               // ----------------
-               aGroup = new HDFgroup( "Submeshes", aTopGroup );
-               aGroup->CreateOnDisk();
-               
-               // each element belongs to one or none submesh,
-               // so for each node/element, we store a submesh ID
-               
-               // Make maps of submesh IDs of elements sorted by element IDs
-               typedef int TElemID;
-               typedef int TSubMID;
-               map< TElemID, TSubMID > eId2smId, nId2smId;
-               map< TElemID, TSubMID >::iterator hint; // insertion to map is done before hint
-               const map<int,SMESHDS_SubMesh*>& aSubMeshes = mySMESHDSMesh->SubMeshes();
-               map<int,SMESHDS_SubMesh*>::const_iterator itSubM ( aSubMeshes.begin() );
-               SMDS_NodeIteratorPtr itNode;
-               SMDS_ElemIteratorPtr itElem;
-               for ( itSubM = aSubMeshes.begin(); itSubM != aSubMeshes.end() ; itSubM++ )
-               {
-                 TSubMID          aSubMeID = itSubM->first;
-                 SMESHDS_SubMesh* aSubMesh = itSubM->second;
-                 if ( aSubMesh->IsComplexSubmesh() )
-                   continue; // submesh containing other submeshs
-                 // nodes
-                 hint = nId2smId.begin(); // optimize insertion basing on increasing order of elem Ids in submesh
-                 for ( itNode = aSubMesh->GetNodes(); itNode->more(); ++hint)
-                   hint = nId2smId.insert( hint, make_pair( itNode->next()->GetID(), aSubMeID ));
+            // store submesh order if any
+            const TListOfListOfInt& theOrderIds = myLocMesh.GetMeshOrder();
+            if ( theOrderIds.size() ) {
+              char order_list[ 30 ];
+              strcpy( order_list, "Mesh Order" );
+              // count number of submesh ids
+              int nbIDs = 0;
+              TListOfListOfInt::const_iterator idIt = theOrderIds.begin();
+              for ( ; idIt != theOrderIds.end(); idIt++ )
+                nbIDs += (*idIt).size();
+              // number of values = number of IDs +
+              //                    number of lists (for separators) - 1
+              int* smIDs = new int [ nbIDs + theOrderIds.size() - 1 ];
+              idIt = theOrderIds.begin();
+              for ( int i = 0; idIt != theOrderIds.end(); idIt++ ) {
+                const TListOfInt& idList = *idIt;
+                if (idIt != theOrderIds.begin()) // not first list
+                  smIDs[ i++ ] = -1/* *idList.size()*/; // separator between lists
+                // dump submesh ids from current list
+                TListOfInt::const_iterator id_smId = idList.begin();
+                for( ; id_smId != idList.end(); id_smId++ )
+                  smIDs[ i++ ] = *id_smId;
+              }
+              // write HDF group
+              aSize[ 0 ] = nbIDs + theOrderIds.size() - 1;
+
+              aDataset = new HDFdataset( order_list, aTopGroup, HDF_INT32, aSize, 1 );
+              aDataset->CreateOnDisk();
+              aDataset->WriteOnDisk( smIDs );
+              aDataset->CloseOnDisk();
+              //
+              delete[] smIDs;
+            }
+
+            // groups root sub-branch
+            SALOMEDS::SObject_var myGroupsBranch;
+            for ( int i = GetNodeGroupsTag(); i <= GetVolumeGroupsTag(); i++ ) {
+              found = gotBranch->FindSubObject( i, myGroupsBranch );
+              if ( found ) {
+                char name_group[ 30 ];
+                if ( i == GetNodeGroupsTag() )
+                  strcpy( name_group, "Groups of Nodes" );
+                else if ( i == GetEdgeGroupsTag() )
+                  strcpy( name_group, "Groups of Edges" );
+                else if ( i == GetFaceGroupsTag() )
+                  strcpy( name_group, "Groups of Faces" );
+                else if ( i == GetVolumeGroupsTag() )
+                  strcpy( name_group, "Groups of Volumes" );
+
+                aGroup = new HDFgroup( name_group, aTopGroup );
+                aGroup->CreateOnDisk();
+
+                SALOMEDS::ChildIterator_var it = myCurrentStudy->NewChildIterator( myGroupsBranch );
+                for ( ; it->More(); it->Next() ) {
+                  SALOMEDS::SObject_var mySObject = it->Value();
+                  CORBA::Object_var aSubObject = SObjectToObject( mySObject );
+                  if ( !CORBA::is_nil( aSubObject ) ) {
+                    SMESH_GroupBase_i* myGroupImpl =
+                      dynamic_cast<SMESH_GroupBase_i*>( GetServant( aSubObject ).in() );
+                    if ( !myGroupImpl )
+                      continue;
+                    SMESHDS_GroupBase* aGrpBaseDS = myGroupImpl->GetGroupDS();
+                    if ( !aGrpBaseDS )
+                      continue;
+                    
+                    CORBA::String_var objStr = GetORB()->object_to_string( aSubObject );
+                    int anId = myStudyContext->findId( string( objStr.in() ) );
+
+                    // For each group, create a dataset named "Group <group_persistent_id>"
+                    // and store the group's user name into it
+                    const char* grpName = aGrpBaseDS->GetStoreName();
+                    char* aUserName = myGroupImpl->GetName();
+                    aSize[ 0 ] = strlen( aUserName ) + 1;
+
+                    aDataset = new HDFdataset( grpName, aGroup, HDF_STRING, aSize, 1 );
+                    aDataset->CreateOnDisk();
+                    aDataset->WriteOnDisk( aUserName );
+                    aDataset->CloseOnDisk();
+
+                    // ouv : NPAL12872
+                    // For each group, create a dataset named "Group <group_persistent_id> Color"
+                    // and store the group's color into it
+                    char grpColorName[ 30 ];
+                    sprintf( grpColorName, "ColorGroup %d", anId );
+                    SALOMEDS::Color aColor = myGroupImpl->GetColor();
+                    double anRGB[3];
+                    anRGB[ 0 ] = aColor.R;
+                    anRGB[ 1 ] = aColor.G;
+                    anRGB[ 2 ] = aColor.B;
+                    aSize[ 0 ] = 3;
+                    aDataset = new HDFdataset( grpColorName, aGroup, HDF_FLOAT64, aSize, 1 );
+                    aDataset->CreateOnDisk();
+                    aDataset->WriteOnDisk( anRGB );
+                    aDataset->CloseOnDisk();
+
+                    // Pass SMESHDS_Group to MED writer 
+                    SMESHDS_Group* aGrpDS = dynamic_cast<SMESHDS_Group*>( aGrpBaseDS );
+                    if ( aGrpDS )
+                      myWriter.AddGroup( aGrpDS );
+
+                    // write reference on a shape if exists
+                    SMESHDS_GroupOnGeom* aGeomGrp =
+                      dynamic_cast<SMESHDS_GroupOnGeom*>( aGrpBaseDS );
+                    if ( aGeomGrp ) {
+                      SALOMEDS::SObject_var mySubRef, myShape;
+                      if (mySObject->FindSubObject( GetRefOnShapeTag(), mySubRef ) &&
+                          mySubRef->ReferencedObject( myShape ) &&
+                          !CORBA::is_nil( myShape->GetObject() ))
+                      {
+                        string myRefOnObject = myShape->GetID();
+                        if ( myRefOnObject.length() > 0 ) {
+                          char aRefName[ 30 ];
+                          sprintf( aRefName, "Ref on shape %d", anId);
+                          aSize[ 0 ] = myRefOnObject.length() + 1;
+                          aDataset = new HDFdataset(aRefName, aGroup, HDF_STRING, aSize, 1);
+                          aDataset->CreateOnDisk();
+                          aDataset->WriteOnDisk( ( char* )( myRefOnObject.c_str() ) );
+                          aDataset->CloseOnDisk();
+                        }
+                      }
+                      else // shape ref is invalid:
+                      {
+                        // save a group on geometry as ordinary group
+                        myWriter.AddGroup( aGeomGrp );
+                      }
+                    }
+                  }
+                }
+                aGroup->CloseOnDisk();
+              }
+            } // loop on groups 
+            
+            if ( strcmp( strHasData.c_str(), "1" ) == 0 )
+            {
+              // Flush current mesh information into MED file
+              myWriter.Perform();
+              
+              // maybe a shape was deleted in the study
+              if ( !shapeRefFound && !mySMESHDSMesh->ShapeToMesh().IsNull() && hasShape) {
+                TopoDS_Shape nullShape;
+                myLocMesh.ShapeToMesh( nullShape ); // remove shape referring data
+              }
+              
+              if ( !mySMESHDSMesh->SubMeshes().empty() )
+              {
+                // Store submeshes
+                // ----------------
+                aGroup = new HDFgroup( "Submeshes", aTopGroup );
+                aGroup->CreateOnDisk();
+                
+                // each element belongs to one or none submesh,
+                // so for each node/element, we store a submesh ID
+                
+                // Make maps of submesh IDs of elements sorted by element IDs
+                typedef int TElemID;
+                typedef int TSubMID;
+                map< TElemID, TSubMID > eId2smId, nId2smId;
+                map< TElemID, TSubMID >::iterator hint; // insertion to map is done before hint
+                const map<int,SMESHDS_SubMesh*>& aSubMeshes = mySMESHDSMesh->SubMeshes();
+                map<int,SMESHDS_SubMesh*>::const_iterator itSubM ( aSubMeshes.begin() );
+                SMDS_NodeIteratorPtr itNode;
+                SMDS_ElemIteratorPtr itElem;
+                for ( itSubM = aSubMeshes.begin(); itSubM != aSubMeshes.end() ; itSubM++ )
+                {
+                  TSubMID          aSubMeID = itSubM->first;
+                  SMESHDS_SubMesh* aSubMesh = itSubM->second;
+                  if ( aSubMesh->IsComplexSubmesh() )
+                    continue; // submesh containing other submeshs
+                  // nodes
+                  hint = nId2smId.begin(); // optimize insertion basing on increasing order of elem Ids in submesh
+                  for ( itNode = aSubMesh->GetNodes(); itNode->more(); ++hint)
+                    hint = nId2smId.insert( hint, make_pair( itNode->next()->GetID(), aSubMeID ));
                   // elements
-                 hint = eId2smId.begin();
-                 for ( itElem = aSubMesh->GetElements(); itElem->more(); ++hint)
-                   hint = eId2smId.insert( hint, make_pair( itElem->next()->GetID(), aSubMeID ));
-               }
-               
-               // Care of elements that are not on submeshes
-               if ( mySMESHDSMesh->NbNodes() != nId2smId.size() ) {
-                 for ( itNode = mySMESHDSMesh->nodesIterator(); itNode->more(); )
-                   /*  --- stl_map.h says : */
-                   /*  A %map relies on unique keys and thus a %pair is only inserted if its */
-                   /*  first element (the key) is not already present in the %map.           */
-                   nId2smId.insert( make_pair( itNode->next()->GetID(), 0 ));
-               }
-               int nbElems = mySMESHDSMesh->NbEdges() + mySMESHDSMesh->NbFaces() + mySMESHDSMesh->NbVolumes();
-               if ( nbElems != eId2smId.size() ) {
-                 for ( itElem = mySMESHDSMesh->elementsIterator(); itElem->more(); )
-                   eId2smId.insert( make_pair( itElem->next()->GetID(), 0 ));
-               }
-               
-               // Store submesh IDs
-               for ( int isNode = 0; isNode < 2; ++isNode )
-               {
-                 map< TElemID, TSubMID >& id2smId = isNode ? nId2smId : eId2smId;
-                 if ( id2smId.empty() ) continue;
-                 map< TElemID, TSubMID >::const_iterator id_smId = id2smId.begin();
-                 // make and fill array of submesh IDs
-                 int* smIDs = new int [ id2smId.size() ];
-                 for ( int i = 0; id_smId != id2smId.end(); ++id_smId, ++i )
-                   smIDs[ i ] = id_smId->second;
-                 // write HDF group
-                 aSize[ 0 ] = id2smId.size();
-                 string aDSName( isNode ? "Node Submeshes" : "Element Submeshes");
-                 aDataset = new HDFdataset( (char*)aDSName.c_str(), aGroup, HDF_INT32, aSize, 1 );
-                 aDataset->CreateOnDisk();
-                 aDataset->WriteOnDisk( smIDs );
-                 aDataset->CloseOnDisk();
-                 //
-                 delete smIDs;
-               }
+                  hint = eId2smId.begin();
+                  for ( itElem = aSubMesh->GetElements(); itElem->more(); ++hint)
+                    hint = eId2smId.insert( hint, make_pair( itElem->next()->GetID(), aSubMeID ));
+                }
                 
-               // Store node positions on sub-shapes (SMDS_Position):
-               // ----------------------------------------------------
-               
-               aGroup = new HDFgroup( "Node Positions", aTopGroup );
-               aGroup->CreateOnDisk();
-               
-               // in aGroup, create 5 datasets to contain:
-               // "Nodes on Edges" - ID of node on edge
-               // "Edge positions" - U parameter on node on edge
-               // "Nodes on Faces" - ID of node on face
-               // "Face U positions" - U parameter of node on face
-               // "Face V positions" - V parameter of node on face
-               
-               // Find out nb of nodes on edges and faces
-               // Collect corresponing sub-meshes
-               int nbEdgeNodes = 0, nbFaceNodes = 0;
-               list<SMESHDS_SubMesh*> aEdgeSM, aFaceSM;
-               // loop on SMESHDS_SubMesh'es
-               for ( itSubM = aSubMeshes.begin(); itSubM != aSubMeshes.end() ; itSubM++ )
-               {
-                 SMESHDS_SubMesh* aSubMesh = (*itSubM).second;
-                 if ( aSubMesh->IsComplexSubmesh() )
-                   continue; // submesh containing other submeshs
-                 int nbNodes = aSubMesh->NbNodes();
-                 if ( nbNodes == 0 ) continue;
-                 
-                 int aShapeID = (*itSubM).first;
-                 int aShapeType = mySMESHDSMesh->IndexToShape( aShapeID ).ShapeType();
-                 // write only SMDS_FacePosition and SMDS_EdgePosition
-                 switch ( aShapeType ) {
-                 case TopAbs_FACE:
-                   nbFaceNodes += nbNodes;
-                   aFaceSM.push_back( aSubMesh );
-                   break;
-                 case TopAbs_EDGE:
-                   nbEdgeNodes += nbNodes;
-                   aEdgeSM.push_back( aSubMesh );
-                   break;
-                 default:
-                   continue;
-                 }
-               }
-               // Treat positions on edges or faces
-               for ( int onFace = 0; onFace < 2; onFace++ )
-               {
-                 // Create arrays to store in datasets
-                 int iNode = 0, nbNodes = ( onFace ? nbFaceNodes : nbEdgeNodes );
-                 if (!nbNodes) continue;
-                 int* aNodeIDs = new int [ nbNodes ];
-                 double* aUPos = new double [ nbNodes ];
-                 double* aVPos = ( onFace ? new double[ nbNodes ] : 0 );
-                 
-                 // Fill arrays
-                 // loop on sub-meshes
-                 list<SMESHDS_SubMesh*> * pListSM = ( onFace ? &aFaceSM : &aEdgeSM );
-                 list<SMESHDS_SubMesh*>::iterator itSM = pListSM->begin();
-                 for ( ; itSM != pListSM->end(); itSM++ )
-                 {
-                   SMESHDS_SubMesh* aSubMesh = (*itSM);
-                   
-                   SMDS_NodeIteratorPtr itNode = aSubMesh->GetNodes();
-                   // loop on nodes in aSubMesh
-                   while ( itNode->more() )
-                   {
-                     //node ID
-                     const SMDS_MeshNode* node = itNode->next();
-                     aNodeIDs [ iNode ] = node->GetID();
-                     
-                     // Position
-                     const SMDS_PositionPtr pos = node->GetPosition();
-                     if ( onFace ) { // on FACE
-                       const SMDS_FacePosition* fPos =
-                         dynamic_cast<const SMDS_FacePosition*>( pos.get() );
-                       if ( fPos ) {
-                         aUPos[ iNode ] = fPos->GetUParameter();
-                         aVPos[ iNode ] = fPos->GetVParameter();
-                         iNode++;
-                       }
-                       else
-                         nbNodes--;
-                     }
-                     else { // on EDGE
-                       const SMDS_EdgePosition* ePos =
-                         dynamic_cast<const SMDS_EdgePosition*>( pos.get() );
-                       if ( ePos ) {
-                         aUPos[ iNode ] = ePos->GetUParameter();
-                         iNode++;
-                       }
-                       else
-                         nbNodes--;
-                     }
-                   } // loop on nodes in aSubMesh
-                 } // loop on sub-meshes
-                 
-                 // Write datasets
-                 if ( nbNodes )
-                 {
-                   aSize[ 0 ] = nbNodes;
-                   // IDS
-                   string aDSName( onFace ? "Nodes on Faces" : "Nodes on Edges");
-                   aDataset = new HDFdataset( (char*)aDSName.c_str(), aGroup, HDF_INT32, aSize, 1 );
-                   aDataset->CreateOnDisk();
-                   aDataset->WriteOnDisk( aNodeIDs );
-                   aDataset->CloseOnDisk();
-               
-                   // U Positions
-                   aDSName = ( onFace ? "Face U positions" : "Edge positions");
-                   aDataset = new HDFdataset( (char*)aDSName.c_str(), aGroup, HDF_FLOAT64, aSize, 1);
-                   aDataset->CreateOnDisk();
-                   aDataset->WriteOnDisk( aUPos );
-                   aDataset->CloseOnDisk();
-                   // V Positions
-                   if ( onFace ) {
-                     aDataset = new HDFdataset( "Face V positions", aGroup, HDF_FLOAT64, aSize, 1);
-                     aDataset->CreateOnDisk();
-                     aDataset->WriteOnDisk( aVPos );
-                     aDataset->CloseOnDisk();
-                   }
-                 }
-                 delete [] aNodeIDs;
-                 delete [] aUPos;
-                 if ( aVPos ) delete [] aVPos;
-                 
-               } // treat positions on edges or faces
-               
-               // close "Node Positions" group
-               aGroup->CloseOnDisk(); 
-               
-             } // if ( there are submeshes in SMESHDS_Mesh )
-           } // if ( hasData )
-           
-           // close mesh HDF group
-           aTopGroup->CloseOnDisk();
-         }
-       }
+                // Care of elements that are not on submeshes
+                if ( mySMESHDSMesh->NbNodes() != nId2smId.size() ) {
+                  for ( itNode = mySMESHDSMesh->nodesIterator(); itNode->more(); )
+                    /*  --- stl_map.h says : */
+                    /*  A %map relies on unique keys and thus a %pair is only inserted if its */
+                    /*  first element (the key) is not already present in the %map.           */
+                    nId2smId.insert( make_pair( itNode->next()->GetID(), 0 ));
+                }
+                int nbElems = mySMESHDSMesh->NbEdges() + mySMESHDSMesh->NbFaces() + mySMESHDSMesh->NbVolumes();
+                if ( nbElems != eId2smId.size() ) {
+                  for ( itElem = mySMESHDSMesh->elementsIterator(); itElem->more(); )
+                    eId2smId.insert( make_pair( itElem->next()->GetID(), 0 ));
+                }
+                
+                // Store submesh IDs
+                for ( int isNode = 0; isNode < 2; ++isNode )
+                {
+                  map< TElemID, TSubMID >& id2smId = isNode ? nId2smId : eId2smId;
+                  if ( id2smId.empty() ) continue;
+                  map< TElemID, TSubMID >::const_iterator id_smId = id2smId.begin();
+                  // make and fill array of submesh IDs
+                  int* smIDs = new int [ id2smId.size() ];
+                  for ( int i = 0; id_smId != id2smId.end(); ++id_smId, ++i )
+                    smIDs[ i ] = id_smId->second;
+                  // write HDF group
+                  aSize[ 0 ] = id2smId.size();
+                  string aDSName( isNode ? "Node Submeshes" : "Element Submeshes");
+                  aDataset = new HDFdataset( (char*)aDSName.c_str(), aGroup, HDF_INT32, aSize, 1 );
+                  aDataset->CreateOnDisk();
+                  aDataset->WriteOnDisk( smIDs );
+                  aDataset->CloseOnDisk();
+                  //
+                  delete[] smIDs;
+                }
+                
+                // Store node positions on sub-shapes (SMDS_Position):
+                // ----------------------------------------------------
+                
+                aGroup = new HDFgroup( "Node Positions", aTopGroup );
+                aGroup->CreateOnDisk();
+                
+                // in aGroup, create 5 datasets to contain:
+                // "Nodes on Edges" - ID of node on edge
+                // "Edge positions" - U parameter on node on edge
+                // "Nodes on Faces" - ID of node on face
+                // "Face U positions" - U parameter of node on face
+                // "Face V positions" - V parameter of node on face
+                
+                // Find out nb of nodes on edges and faces
+                // Collect corresponing sub-meshes
+                int nbEdgeNodes = 0, nbFaceNodes = 0;
+                list<SMESHDS_SubMesh*> aEdgeSM, aFaceSM;
+                // loop on SMESHDS_SubMesh'es
+                for ( itSubM = aSubMeshes.begin(); itSubM != aSubMeshes.end() ; itSubM++ )
+                {
+                  SMESHDS_SubMesh* aSubMesh = (*itSubM).second;
+                  if ( aSubMesh->IsComplexSubmesh() )
+                    continue; // submesh containing other submeshs
+                  int nbNodes = aSubMesh->NbNodes();
+                  if ( nbNodes == 0 ) continue;
+                  
+                  int aShapeID = (*itSubM).first;
+                  if ( aShapeID < 1 || aShapeID > mySMESHDSMesh->MaxShapeIndex() )
+                    continue;
+                  int aShapeType = mySMESHDSMesh->IndexToShape( aShapeID ).ShapeType();
+                  // write only SMDS_FacePosition and SMDS_EdgePosition
+                  switch ( aShapeType ) {
+                  case TopAbs_FACE:
+                    nbFaceNodes += nbNodes;
+                    aFaceSM.push_back( aSubMesh );
+                    break;
+                  case TopAbs_EDGE:
+                    nbEdgeNodes += nbNodes;
+                    aEdgeSM.push_back( aSubMesh );
+                    break;
+                  default:
+                    continue;
+                  }
+                }
+                // Treat positions on edges or faces
+                for ( int onFace = 0; onFace < 2; onFace++ )
+                {
+                  // Create arrays to store in datasets
+                  int iNode = 0, nbNodes = ( onFace ? nbFaceNodes : nbEdgeNodes );
+                  if (!nbNodes) continue;
+                  int* aNodeIDs = new int [ nbNodes ];
+                  double* aUPos = new double [ nbNodes ];
+                  double* aVPos = ( onFace ? new double[ nbNodes ] : 0 );
+                  
+                  // Fill arrays
+                  // loop on sub-meshes
+                  list<SMESHDS_SubMesh*> * pListSM = ( onFace ? &aFaceSM : &aEdgeSM );
+                  list<SMESHDS_SubMesh*>::iterator itSM = pListSM->begin();
+                  for ( ; itSM != pListSM->end(); itSM++ )
+                  {
+                    SMESHDS_SubMesh* aSubMesh = (*itSM);
+                    
+                    SMDS_NodeIteratorPtr itNode = aSubMesh->GetNodes();
+                    // loop on nodes in aSubMesh
+                    while ( itNode->more() )
+                    {
+                      //node ID
+                      const SMDS_MeshNode* node = itNode->next();
+                      aNodeIDs [ iNode ] = node->GetID();
+                      
+                      // Position
+                      const SMDS_PositionPtr pos = node->GetPosition();
+                      if ( onFace ) { // on FACE
+                        const SMDS_FacePosition* fPos =
+                          dynamic_cast<const SMDS_FacePosition*>( pos );
+                        if ( fPos ) {
+                          aUPos[ iNode ] = fPos->GetUParameter();
+                          aVPos[ iNode ] = fPos->GetVParameter();
+                          iNode++;
+                        }
+                        else
+                          nbNodes--;
+                      }
+                      else { // on EDGE
+                        const SMDS_EdgePosition* ePos =
+                          dynamic_cast<const SMDS_EdgePosition*>( pos );
+                        if ( ePos ) {
+                          aUPos[ iNode ] = ePos->GetUParameter();
+                          iNode++;
+                        }
+                        else
+                          nbNodes--;
+                      }
+                    } // loop on nodes in aSubMesh
+                  } // loop on sub-meshes
+                  
+                  // Write datasets
+                  if ( nbNodes )
+                  {
+                    aSize[ 0 ] = nbNodes;
+                    // IDS
+                    string aDSName( onFace ? "Nodes on Faces" : "Nodes on Edges");
+                    aDataset = new HDFdataset( (char*)aDSName.c_str(), aGroup, HDF_INT32, aSize, 1 );
+                    aDataset->CreateOnDisk();
+                    aDataset->WriteOnDisk( aNodeIDs );
+                    aDataset->CloseOnDisk();
+                
+                    // U Positions
+                    aDSName = ( onFace ? "Face U positions" : "Edge positions");
+                    aDataset = new HDFdataset( (char*)aDSName.c_str(), aGroup, HDF_FLOAT64, aSize, 1);
+                    aDataset->CreateOnDisk();
+                    aDataset->WriteOnDisk( aUPos );
+                    aDataset->CloseOnDisk();
+                    // V Positions
+                    if ( onFace ) {
+                      aDataset = new HDFdataset( "Face V positions", aGroup, HDF_FLOAT64, aSize, 1);
+                      aDataset->CreateOnDisk();
+                      aDataset->WriteOnDisk( aVPos );
+                      aDataset->CloseOnDisk();
+                    }
+                  }
+                  delete [] aNodeIDs;
+                  delete [] aUPos;
+                  if ( aVPos ) delete [] aVPos;
+                  
+                } // treat positions on edges or faces
+                
+                // close "Node Positions" group
+                aGroup->CloseOnDisk(); 
+                
+              } // if ( there are submeshes in SMESHDS_Mesh )
+            } // if ( hasData )
+            
+            // close mesh HDF group
+            aTopGroup->CloseOnDisk();
+          }
+        }
       }
     }
   }
@@ -2963,8 +3440,8 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
 //=============================================================================
 
 SALOMEDS::TMPFile* SMESH_Gen_i::SaveASCII( SALOMEDS::SComponent_ptr theComponent,
-                                          const char*              theURL,
-                                          bool                     isMultiFile ) {
+                                           const char*              theURL,
+                                           bool                     isMultiFile ) {
   if(MYDEBUG) MESSAGE( "SMESH_Gen_i::SaveASCII" );
   SALOMEDS::TMPFile_var aStreamFile = Save( theComponent, theURL, isMultiFile );
   return aStreamFile._retn();
@@ -3016,13 +3493,15 @@ public:
   }
   PositionCreator() {
     myFuncTable.resize( (size_t) TopAbs_SHAPE, & PositionCreator::defaultPosition );
-    myFuncTable[ TopAbs_FACE ] = & PositionCreator::facePosition;
-    myFuncTable[ TopAbs_EDGE ] = & PositionCreator::edgePosition;
+    myFuncTable[ TopAbs_SOLID  ] = & PositionCreator::volumePosition;
+    myFuncTable[ TopAbs_FACE   ] = & PositionCreator::facePosition;
+    myFuncTable[ TopAbs_EDGE   ] = & PositionCreator::edgePosition;
     myFuncTable[ TopAbs_VERTEX ] = & PositionCreator::vertexPosition;
   }
 private:
   SMDS_PositionPtr edgePosition()    const { return SMDS_PositionPtr( new SMDS_EdgePosition  ); }
   SMDS_PositionPtr facePosition()    const { return SMDS_PositionPtr( new SMDS_FacePosition  ); }
+  SMDS_PositionPtr volumePosition()  const { return SMDS_PositionPtr( new SMDS_SpacePosition ); }
   SMDS_PositionPtr vertexPosition()  const { return SMDS_PositionPtr( new SMDS_VertexPosition); }
   SMDS_PositionPtr defaultPosition() const { return SMDS_SpacePosition::originSpacePosition();  }
   typedef SMDS_PositionPtr (PositionCreator:: * FmakePos)() const;
@@ -3038,9 +3517,9 @@ private:
 //=============================================================================
 
 bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
-                       const SALOMEDS::TMPFile& theStream,
-                       const char*              theURL,
-                       bool                     isMultiFile )
+                        const SALOMEDS::TMPFile& theStream,
+                        const char*              theURL,
+                        bool                     isMultiFile )
 {
   INFOS( "SMESH_Gen_i::Load" );
 
@@ -3069,7 +3548,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
   // Convert the stream into sequence of files to process
   SALOMEDS::ListOfFileNames_var aFileSeq = SALOMEDS_Tool::PutStreamToFiles( theStream,
                                                                             tmpDir.ToCString(),
-                                                                           isMultiFile );
+                                                                            isMultiFile );
   TCollection_AsciiString aStudyName( "" );
   if ( isMultiFile ) 
     aStudyName = ( (char*)SALOMEDS_Tool::GetNameFromPath( myCurrentStudy->URL() ).c_str() );
@@ -3125,88 +3604,88 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
       // get number of hypotheses
       int aNbObjects = aTopGroup->nInternalObjects(); 
       for ( int j = 0; j < aNbObjects; j++ ) {
-       // try to identify hypothesis
-       char hypGrpName[ HDF_NAME_MAX_LEN+1 ];
+        // try to identify hypothesis
+        char hypGrpName[ HDF_NAME_MAX_LEN+1 ];
         aTopGroup->InternalObjectIndentify( j, hypGrpName );
 
-       if ( string( hypGrpName ).substr( 0, 10 ) == string( "Hypothesis" ) ) {
-         // open hypothesis group
-         aGroup = new HDFgroup( hypGrpName, aTopGroup ); 
-         aGroup->OpenOnDisk();
-
-         // --> get hypothesis id
-         int    id = atoi( string( hypGrpName ).substr( 10 ).c_str() );
-         string hypname;
-         string libname;
-         string hypdata;
-
-         // get number of datasets
-         int aNbSubObjects = aGroup->nInternalObjects();
-         for ( int k = 0; k < aNbSubObjects; k++ ) {
-           // identify dataset
-           char name_of_subgroup[ HDF_NAME_MAX_LEN+1 ];
-           aGroup->InternalObjectIndentify( k, name_of_subgroup );
-           // --> get hypothesis name
-           if ( strcmp( name_of_subgroup, "Name"  ) == 0 ) {
-             aDataset = new HDFdataset( name_of_subgroup, aGroup );
-             aDataset->OpenOnDisk();
-             size = aDataset->GetSize();
-             char* hypname_str = new char[ size ];
-             aDataset->ReadFromDisk( hypname_str );
-             hypname = string( hypname_str );
-             delete [] hypname_str;
-             aDataset->CloseOnDisk();
-           }
-           // --> get hypothesis plugin library name
-           if ( strcmp( name_of_subgroup, "LibName"  ) == 0 ) {
-             aDataset = new HDFdataset( name_of_subgroup, aGroup );
-             aDataset->OpenOnDisk();
-             size = aDataset->GetSize();
-             char* libname_str = new char[ size ];
-             aDataset->ReadFromDisk( libname_str );
-             if(MYDEBUG) SCRUTE( libname_str );
-             libname = string( libname_str );
-             delete [] libname_str;
-             aDataset->CloseOnDisk();
-           }
-           // --> get hypothesis data
-           if ( strcmp( name_of_subgroup, "Data"  ) == 0 ) {
-             aDataset = new HDFdataset( name_of_subgroup, aGroup );
-             aDataset->OpenOnDisk();
-             size = aDataset->GetSize();
-             char* hypdata_str = new char[ size ];
-             aDataset->ReadFromDisk( hypdata_str );
-             hypdata = string( hypdata_str );
-             delete [] hypdata_str;
-             aDataset->CloseOnDisk();
-           }
-         }
-         // close hypothesis HDF group
-         aGroup->CloseOnDisk();
-
-         // --> restore hypothesis from data
-         if ( id > 0 && !hypname.empty()/* && !hypdata.empty()*/ ) { // VSR : persistent data can be empty
-           if(MYDEBUG) MESSAGE("VSR - load hypothesis : id = " << id <<
+        if ( string( hypGrpName ).substr( 0, 10 ) == string( "Hypothesis" ) ) {
+          // open hypothesis group
+          aGroup = new HDFgroup( hypGrpName, aTopGroup ); 
+          aGroup->OpenOnDisk();
+
+          // --> get hypothesis id
+          int    id = atoi( string( hypGrpName ).substr( 10 ).c_str() );
+          string hypname;
+          string libname;
+          string hypdata;
+
+          // get number of datasets
+          int aNbSubObjects = aGroup->nInternalObjects();
+          for ( int k = 0; k < aNbSubObjects; k++ ) {
+            // identify dataset
+            char name_of_subgroup[ HDF_NAME_MAX_LEN+1 ];
+            aGroup->InternalObjectIndentify( k, name_of_subgroup );
+            // --> get hypothesis name
+            if ( strcmp( name_of_subgroup, "Name"  ) == 0 ) {
+              aDataset = new HDFdataset( name_of_subgroup, aGroup );
+              aDataset->OpenOnDisk();
+              size = aDataset->GetSize();
+              char* hypname_str = new char[ size ];
+              aDataset->ReadFromDisk( hypname_str );
+              hypname = string( hypname_str );
+              delete [] hypname_str;
+              aDataset->CloseOnDisk();
+            }
+            // --> get hypothesis plugin library name
+            if ( strcmp( name_of_subgroup, "LibName"  ) == 0 ) {
+              aDataset = new HDFdataset( name_of_subgroup, aGroup );
+              aDataset->OpenOnDisk();
+              size = aDataset->GetSize();
+              char* libname_str = new char[ size ];
+              aDataset->ReadFromDisk( libname_str );
+              if(MYDEBUG) SCRUTE( libname_str );
+              libname = string( libname_str );
+              delete [] libname_str;
+              aDataset->CloseOnDisk();
+            }
+            // --> get hypothesis data
+            if ( strcmp( name_of_subgroup, "Data"  ) == 0 ) {
+              aDataset = new HDFdataset( name_of_subgroup, aGroup );
+              aDataset->OpenOnDisk();
+              size = aDataset->GetSize();
+              char* hypdata_str = new char[ size ];
+              aDataset->ReadFromDisk( hypdata_str );
+              hypdata = string( hypdata_str );
+              delete [] hypdata_str;
+              aDataset->CloseOnDisk();
+            }
+          }
+          // close hypothesis HDF group
+          aGroup->CloseOnDisk();
+
+          // --> restore hypothesis from data
+          if ( id > 0 && !hypname.empty()/* && !hypdata.empty()*/ ) { // VSR : persistent data can be empty
+            if(MYDEBUG) MESSAGE("VSR - load hypothesis : id = " << id <<
                                 ", name = " << hypname.c_str() << ", persistent string = " << hypdata.c_str());
             SMESH::SMESH_Hypothesis_var myHyp;
 
-           try { // protect persistence mechanism against exceptions
-             myHyp = this->createHypothesis( hypname.c_str(), libname.c_str() );
-           }
-           catch (...) {
-             INFOS( "Exception during hypothesis creation" );
-           }
+            try { // protect persistence mechanism against exceptions
+              myHyp = this->createHypothesis( hypname.c_str(), libname.c_str() );
+            }
+            catch (...) {
+              INFOS( "Exception during hypothesis creation" );
+            }
 
-           SMESH_Hypothesis_i* myImpl = dynamic_cast<SMESH_Hypothesis_i*>( GetServant( myHyp ).in() );
-           if ( myImpl ) {
-             // myImpl->LoadFrom( hypdata.c_str() );
+            SMESH_Hypothesis_i* myImpl = dynamic_cast<SMESH_Hypothesis_i*>( GetServant( myHyp ).in() );
+            if ( myImpl ) {
+              // myImpl->LoadFrom( hypdata.c_str() );
               hypDataList.push_back( make_pair( myImpl, hypdata ));
-             string iorString = GetORB()->object_to_string( myHyp );
-             int newId = myStudyContext->findId( iorString );
-             myStudyContext->mapOldToNew( id, newId );
-           }
-           else
-             if(MYDEBUG) MESSAGE( "VSR - SMESH_Gen::Load - can't get servant" );
+              string iorString = GetORB()->object_to_string( myHyp );
+              int newId = myStudyContext->findId( iorString );
+              myStudyContext->mapOldToNew( id, newId );
+            }
+            else
+              if(MYDEBUG) MESSAGE( "VSR - SMESH_Gen::Load - can't get servant" );
           }
         }
       }
@@ -3224,89 +3703,89 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
       // get number of algorithms
       int aNbObjects = aTopGroup->nInternalObjects(); 
       for ( int j = 0; j < aNbObjects; j++ ) {
-       // try to identify algorithm
-       char hypGrpName[ HDF_NAME_MAX_LEN+1 ];
+        // try to identify algorithm
+        char hypGrpName[ HDF_NAME_MAX_LEN+1 ];
         aTopGroup->InternalObjectIndentify( j, hypGrpName );
 
-       if ( string( hypGrpName ).substr( 0, 9 ) == string( "Algorithm" ) ) {
-         // open algorithm group
-         aGroup = new HDFgroup( hypGrpName, aTopGroup ); 
-         aGroup->OpenOnDisk();
-
-         // --> get algorithm id
-         int    id = atoi( string( hypGrpName ).substr( 9 ).c_str() );
-         string hypname;
-         string libname;
-         string hypdata;
-
-         // get number of datasets
-         int aNbSubObjects = aGroup->nInternalObjects();
-         for ( int k = 0; k < aNbSubObjects; k++ ) {
-           // identify dataset
-           char name_of_subgroup[ HDF_NAME_MAX_LEN+1 ];
-           aGroup->InternalObjectIndentify( k, name_of_subgroup );
-           // --> get algorithm name
-           if ( strcmp( name_of_subgroup, "Name"  ) == 0 ) {
-             aDataset = new HDFdataset( name_of_subgroup, aGroup );
-             aDataset->OpenOnDisk();
-             size = aDataset->GetSize();
-             char* hypname_str = new char[ size ];
-             aDataset->ReadFromDisk( hypname_str );
-             hypname = string( hypname_str );
-             delete [] hypname_str;
-             aDataset->CloseOnDisk();
-           }
-           // --> get algorithm plugin library name
-           if ( strcmp( name_of_subgroup, "LibName"  ) == 0 ) {
-             aDataset = new HDFdataset( name_of_subgroup, aGroup );
-             aDataset->OpenOnDisk();
-             size = aDataset->GetSize();
-             char* libname_str = new char[ size ];
-             aDataset->ReadFromDisk( libname_str );
-             if(MYDEBUG) SCRUTE( libname_str );
-             libname = string( libname_str );
-             delete [] libname_str;
-             aDataset->CloseOnDisk();
-           }
-           // --> get algorithm data
-           if ( strcmp( name_of_subgroup, "Data"  ) == 0 ) {
-             aDataset = new HDFdataset( name_of_subgroup, aGroup );
-             aDataset->OpenOnDisk();
-             size = aDataset->GetSize();
-             char* hypdata_str = new char[ size ];
-             aDataset->ReadFromDisk( hypdata_str );
-             if(MYDEBUG) SCRUTE( hypdata_str );
-             hypdata = string( hypdata_str );
-             delete [] hypdata_str;
-             aDataset->CloseOnDisk();
-           }
-         }
-         // close algorithm HDF group
-         aGroup->CloseOnDisk();
-
-         // --> restore algorithm from data
-         if ( id > 0 && !hypname.empty()/* && !hypdata.empty()*/ ) { // VSR : persistent data can be empty
-           if(MYDEBUG) MESSAGE("VSR - load algo : id = " << id <<
+        if ( string( hypGrpName ).substr( 0, 9 ) == string( "Algorithm" ) ) {
+          // open algorithm group
+          aGroup = new HDFgroup( hypGrpName, aTopGroup ); 
+          aGroup->OpenOnDisk();
+
+          // --> get algorithm id
+          int    id = atoi( string( hypGrpName ).substr( 9 ).c_str() );
+          string hypname;
+          string libname;
+          string hypdata;
+
+          // get number of datasets
+          int aNbSubObjects = aGroup->nInternalObjects();
+          for ( int k = 0; k < aNbSubObjects; k++ ) {
+            // identify dataset
+            char name_of_subgroup[ HDF_NAME_MAX_LEN+1 ];
+            aGroup->InternalObjectIndentify( k, name_of_subgroup );
+            // --> get algorithm name
+            if ( strcmp( name_of_subgroup, "Name"  ) == 0 ) {
+              aDataset = new HDFdataset( name_of_subgroup, aGroup );
+              aDataset->OpenOnDisk();
+              size = aDataset->GetSize();
+              char* hypname_str = new char[ size ];
+              aDataset->ReadFromDisk( hypname_str );
+              hypname = string( hypname_str );
+              delete [] hypname_str;
+              aDataset->CloseOnDisk();
+            }
+            // --> get algorithm plugin library name
+            if ( strcmp( name_of_subgroup, "LibName"  ) == 0 ) {
+              aDataset = new HDFdataset( name_of_subgroup, aGroup );
+              aDataset->OpenOnDisk();
+              size = aDataset->GetSize();
+              char* libname_str = new char[ size ];
+              aDataset->ReadFromDisk( libname_str );
+              if(MYDEBUG) SCRUTE( libname_str );
+              libname = string( libname_str );
+              delete [] libname_str;
+              aDataset->CloseOnDisk();
+            }
+            // --> get algorithm data
+            if ( strcmp( name_of_subgroup, "Data"  ) == 0 ) {
+              aDataset = new HDFdataset( name_of_subgroup, aGroup );
+              aDataset->OpenOnDisk();
+              size = aDataset->GetSize();
+              char* hypdata_str = new char[ size ];
+              aDataset->ReadFromDisk( hypdata_str );
+              if(MYDEBUG) SCRUTE( hypdata_str );
+              hypdata = string( hypdata_str );
+              delete [] hypdata_str;
+              aDataset->CloseOnDisk();
+            }
+          }
+          // close algorithm HDF group
+          aGroup->CloseOnDisk();
+
+          // --> restore algorithm from data
+          if ( id > 0 && !hypname.empty()/* && !hypdata.empty()*/ ) { // VSR : persistent data can be empty
+            if(MYDEBUG) MESSAGE("VSR - load algo : id = " << id <<
                                 ", name = " << hypname.c_str() << ", persistent string = " << hypdata.c_str());
             SMESH::SMESH_Hypothesis_var myHyp;
 
-           try { // protect persistence mechanism against exceptions
-             myHyp = this->createHypothesis( hypname.c_str(), libname.c_str() );
-           }
-           catch (...) {
-             INFOS( "Exception during hypothesis creation" );
-           }
+            try { // protect persistence mechanism against exceptions
+              myHyp = this->createHypothesis( hypname.c_str(), libname.c_str() );
+            }
+            catch (...) {
+              INFOS( "Exception during hypothesis creation" );
+            }
 
-           SMESH_Hypothesis_i* myImpl = dynamic_cast<SMESH_Hypothesis_i*>( GetServant( myHyp ).in() );
-           if ( myImpl ) {
-             //myImpl->LoadFrom( hypdata.c_str() );
+            SMESH_Hypothesis_i* myImpl = dynamic_cast<SMESH_Hypothesis_i*>( GetServant( myHyp ).in() );
+            if ( myImpl ) {
+              //myImpl->LoadFrom( hypdata.c_str() );
               hypDataList.push_back( make_pair( myImpl, hypdata ));
-             string iorString = GetORB()->object_to_string( myHyp );
-             int newId = myStudyContext->findId( iorString );
-             myStudyContext->mapOldToNew( id, newId );
-           }
-           else
-             if(MYDEBUG) MESSAGE( "VSR - SMESH_Gen::Load - can't get servant" );
+              string iorString = GetORB()->object_to_string( myHyp );
+              int newId = myStudyContext->findId( iorString );
+              myStudyContext->mapOldToNew( id, newId );
+            }
+            else
+              if(MYDEBUG) MESSAGE( "VSR - SMESH_Gen::Load - can't get servant" );
           }
         }
       }
@@ -3322,44 +3801,44 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
       aFile->InternalObjectIndentify( i, meshName );
 
       if ( string( meshName ).substr( 0, 4 ) == string( "Mesh" ) ) {
-       // --> get mesh id
-       int id = atoi( string( meshName ).substr( 4 ).c_str() );
-       if ( id <= 0 )
-         continue;
-
-       // open mesh HDF group
-       aTopGroup = new HDFgroup( meshName, aFile ); 
-       aTopGroup->OpenOnDisk();
-
-       // get number of child HDF objects
-       int aNbObjects = aTopGroup->nInternalObjects(); 
-       if ( aNbObjects > 0 ) {
-         // create mesh
-         if(MYDEBUG) MESSAGE( "VSR - load mesh : id = " << id );
-         SMESH::SMESH_Mesh_var myNewMesh = this->createMesh();
-         SMESH_Mesh_i* myNewMeshImpl = dynamic_cast<SMESH_Mesh_i*>( GetServant( myNewMesh ).in() );
+        // --> get mesh id
+        int id = atoi( string( meshName ).substr( 4 ).c_str() );
+        if ( id <= 0 )
+          continue;
+
+        // open mesh HDF group
+        aTopGroup = new HDFgroup( meshName, aFile ); 
+        aTopGroup->OpenOnDisk();
+
+        // get number of child HDF objects
+        int aNbObjects = aTopGroup->nInternalObjects(); 
+        if ( aNbObjects > 0 ) {
+          // create mesh
+          if(MYDEBUG) MESSAGE( "VSR - load mesh : id = " << id );
+          SMESH::SMESH_Mesh_var myNewMesh = this->createMesh();
+          SMESH_Mesh_i* myNewMeshImpl = dynamic_cast<SMESH_Mesh_i*>( GetServant( myNewMesh ).in() );
           if ( !myNewMeshImpl )
-           continue;
+            continue;
           meshGroupList.push_back( make_pair( myNewMeshImpl, aTopGroup ));
 
-         string iorString = GetORB()->object_to_string( myNewMesh );
-         int newId = myStudyContext->findId( iorString );
-         myStudyContext->mapOldToNew( id, newId );
-
-         // ouv : NPAL12872
-         // try to read and set auto color flag
-         char aMeshAutoColorName[ 30 ];
-         sprintf( aMeshAutoColorName, "AutoColorMesh %d", id);
-         if( aTopGroup->ExistInternalObject( aMeshAutoColorName ) )
-         {
-           aDataset = new HDFdataset( aMeshAutoColorName, aTopGroup );
-           aDataset->OpenOnDisk();
-           size = aDataset->GetSize();
-           int* anAutoColor = new int[ size ];
-           aDataset->ReadFromDisk( anAutoColor );
-           aDataset->CloseOnDisk();
-           myNewMeshImpl->SetAutoColor( (bool)anAutoColor[0] );
-         }
+          string iorString = GetORB()->object_to_string( myNewMesh );
+          int newId = myStudyContext->findId( iorString );
+          myStudyContext->mapOldToNew( id, newId );
+
+          // ouv : NPAL12872
+          // try to read and set auto color flag
+          char aMeshAutoColorName[ 30 ];
+          sprintf( aMeshAutoColorName, "AutoColorMesh %d", id);
+          if( aTopGroup->ExistInternalObject( aMeshAutoColorName ) )
+          {
+            aDataset = new HDFdataset( aMeshAutoColorName, aTopGroup );
+            aDataset->OpenOnDisk();
+            size = aDataset->GetSize();
+            int* anAutoColor = new int[ size ];
+            aDataset->ReadFromDisk( anAutoColor );
+            aDataset->CloseOnDisk();
+            myNewMeshImpl->SetAutoColor( (bool)anAutoColor[0] );
+          }
 
           // try to read and set reference to shape
           GEOM::GEOM_Object_var aShapeObject;
@@ -3386,6 +3865,29 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
             }
           }
 
+          // issue 0020693. Restore _isModified flag
+          if( aTopGroup->ExistInternalObject( "_isModified" ) )
+          {
+            aDataset = new HDFdataset( "_isModified", aTopGroup );
+            aDataset->OpenOnDisk();
+            size = aDataset->GetSize();
+            int* isModified = new int[ size ];
+            aDataset->ReadFromDisk( isModified );
+            aDataset->CloseOnDisk();
+            myNewMeshImpl->GetImpl().SetIsModified( bool(*isModified));
+          }
+
+          // issue 20918. Restore Persistent Id of SMESHDS_Mesh
+          if( aTopGroup->ExistInternalObject( "meshPersistentId" ) )
+          {
+            aDataset = new HDFdataset( "meshPersistentId", aTopGroup );
+            aDataset->OpenOnDisk();
+            size = aDataset->GetSize();
+            int* meshPersistentId = new int[ size ];
+            aDataset->ReadFromDisk( meshPersistentId );
+            aDataset->CloseOnDisk();
+            myNewMeshImpl->GetImpl().GetMeshDS()->SetPersistentId( *meshPersistentId );
+          }
         }
       }
     }
@@ -3700,7 +4202,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
           aGroup = new HDFgroup( "Submeshes", aTopGroup ); 
           aGroup->OpenOnDisk();
 
-          int maxID = mySMESHDSMesh->MaxShapeIndex();
+          int maxID = Max( mySMESHDSMesh->MaxSubMeshIndex(), mySMESHDSMesh->MaxShapeIndex() );
           vector< SMESHDS_SubMesh * > subMeshes( maxID + 1, (SMESHDS_SubMesh*) 0 );
           vector< TopAbs_ShapeEnum  > smType   ( maxID + 1, TopAbs_SHAPE ); 
 
@@ -3731,7 +4233,9 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
               // -- Most probably a bad study was saved when there were
               // not fixed bugs in SMDS_MeshInfo
               if ( elemSet.size() < nbElems ) {
-                cout << "Warning: Node position data is invalid" << endl;
+#ifdef _DEBUG_
+                cout << "SMESH_Gen_i::Load(), warning: Node position data is invalid" << endl;
+#endif
                 nbElems = elemSet.size();
               }
               // add elements to submeshes
@@ -3740,8 +4244,13 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
               {
                 int smID = smIDs[ i ];
                 if ( smID == 0 ) continue;
-                ASSERT( smID <= maxID );
                 const SMDS_MeshElement* elem = *iE;
+                if( smID > maxID ) {
+                  // corresponding subshape no longer exists: maybe geom group has been edited
+                  if ( myNewMeshImpl->HasShapeToMesh() )
+                    mySMESHDSMesh->RemoveElement( elem );
+                  continue;
+                }
                 // get or create submesh
                 SMESHDS_SubMesh* & sm = subMeshes[ smID ];
                 if ( ! sm ) {
@@ -3751,7 +4260,6 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
                 // add
                 if ( isNode ) {
                   SMDS_PositionPtr pos = aPositionCreator.MakePosition( smType[ smID ]);
-                  pos->SetShapeId( smID );
                   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( static_cast<const SMDS_MeshNode*>( elem ));
                   node->SetPosition( pos );
                   sm->AddNode( node );
@@ -3846,28 +4354,28 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
             for ( int iNode = 0; iNode < nbNodes; iNode++ )
             {
               const SMDS_MeshNode* node = mySMESHDSMesh->FindNode( aNodeIDs[ iNode ]);
-              ASSERT( node );
+              if ( !node ) continue; // maybe removed while Loading() if geometry changed
               SMDS_PositionPtr aPos = node->GetPosition();
-              ASSERT( aPos )
-                if ( onFace ) {
-                  // ASSERT( aPos->GetTypeOfPosition() == SMDS_TOP_FACE );-- issue 20182
-                  // -- Most probably a bad study was saved when there were
-                  // not fixed bugs in SMDS_MeshInfo
-                  if ( aPos->GetTypeOfPosition() == SMDS_TOP_FACE ) {
-                    SMDS_FacePosition* fPos = const_cast<SMDS_FacePosition*>
-                      ( static_cast<const SMDS_FacePosition*>( aPos.get() ));
-                    fPos->SetUParameter( aUPos[ iNode ]);
-                    fPos->SetVParameter( aVPos[ iNode ]);
-                  }
+              ASSERT( aPos );
+              if ( onFace ) {
+                // ASSERT( aPos->GetTypeOfPosition() == SMDS_TOP_FACE );-- issue 20182
+                // -- Most probably a bad study was saved when there were
+                // not fixed bugs in SMDS_MeshInfo
+                if ( aPos->GetTypeOfPosition() == SMDS_TOP_FACE ) {
+                  SMDS_FacePosition* fPos = const_cast<SMDS_FacePosition*>
+                    ( static_cast<const SMDS_FacePosition*>( aPos ));
+                  fPos->SetUParameter( aUPos[ iNode ]);
+                  fPos->SetVParameter( aVPos[ iNode ]);
                 }
-                else {
-                  // ASSERT( aPos->GetTypeOfPosition() == SMDS_TOP_EDGE );-- issue 20182
-                  if ( aPos->GetTypeOfPosition() == SMDS_TOP_EDGE ) {
-                    SMDS_EdgePosition* fPos = const_cast<SMDS_EdgePosition*>
-                      ( static_cast<const SMDS_EdgePosition*>( aPos.get() ));
-                    fPos->SetUParameter( aUPos[ iNode ]);
-                  }
+              }
+              else {
+                // ASSERT( aPos->GetTypeOfPosition() == SMDS_TOP_EDGE );-- issue 20182
+                if ( aPos->GetTypeOfPosition() == SMDS_TOP_EDGE ) {
+                  SMDS_EdgePosition* fPos = const_cast<SMDS_EdgePosition*>
+                    ( static_cast<const SMDS_EdgePosition*>( aPos ));
+                  fPos->SetUParameter( aUPos[ iNode ]);
                 }
+              }
             }
           }
           if ( aEids ) delete [] aEids;
@@ -3881,20 +4389,6 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
         } // if ( aTopGroup->ExistInternalObject( "Node Positions" ) )
       } // if ( hasData )
 
-      // Recompute State (as computed sub-meshes are restored from MED)
-      if ( !aShapeObject->_is_nil() || !myNewMeshImpl->HasShapeToMesh()) {
-        MESSAGE("Compute State Engine ...");
-        TopoDS_Shape myLocShape;
-        if(myNewMeshImpl->HasShapeToMesh())
-          myLocShape = GeomObjectToShape( aShapeObject );
-        else
-          myLocShape = SMESH_Mesh::PseudoShape();
-        
-        myNewMeshImpl->GetImpl().GetSubMesh(myLocShape)->ComputeStateEngine
-          (SMESH_subMesh::SUBMESH_RESTORED);
-        MESSAGE("Compute State Engine finished");
-      }
-
       // try to get groups
       for ( int ii = GetNodeGroupsTag(); ii <= GetVolumeGroupsTag(); ii++ ) {
         char name_group[ 30 ];
@@ -3976,21 +4470,21 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
               SMESHDS_GroupBase* aGroupBaseDS = aLocalGroup->GetGroupDS();
               aGroupBaseDS->SetStoreName( name_dataset );
 
-             // ouv : NPAL12872
-             // Read color of the group
+              // ouv : NPAL12872
+              // Read color of the group
               char aGroupColorName[ 30 ];
               sprintf( aGroupColorName, "ColorGroup %d", subid);
               if ( aGroup->ExistInternalObject( aGroupColorName ) )
-             {
-               aDataset = new HDFdataset( aGroupColorName, aGroup );
-               aDataset->OpenOnDisk();
-               size = aDataset->GetSize();
-               double* anRGB = new double[ size ];
-               aDataset->ReadFromDisk( anRGB );
-               aDataset->CloseOnDisk();
-               Quantity_Color aColor( anRGB[0], anRGB[1], anRGB[2], Quantity_TOC_RGB );
-               aGroupBaseDS->SetColor( aColor );
-             }
+              {
+                aDataset = new HDFdataset( aGroupColorName, aGroup );
+                aDataset->OpenOnDisk();
+                size = aDataset->GetSize();
+                double* anRGB = new double[ size ];
+                aDataset->ReadFromDisk( anRGB );
+                aDataset->CloseOnDisk();
+                Quantity_Color aColor( anRGB[0], anRGB[1], anRGB[2], Quantity_TOC_RGB );
+                aGroupBaseDS->SetColor( aColor );
+              }
 
               // Fill group with contents from MED file
               SMESHDS_Group* aGrp = dynamic_cast<SMESHDS_Group*>( aGroupBaseDS );
@@ -4001,7 +4495,49 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
           aGroup->CloseOnDisk();
         }
       }
+
+      // read submeh order if any
+      if( aTopGroup->ExistInternalObject( "Mesh Order" ) ) {
+        aDataset = new HDFdataset( "Mesh Order", aTopGroup );
+        aDataset->OpenOnDisk();
+        size = aDataset->GetSize();
+        int* smIDs = new int[ size ];
+        aDataset->ReadFromDisk( smIDs );
+        aDataset->CloseOnDisk();
+        TListOfListOfInt anOrderIds;
+        anOrderIds.push_back( TListOfInt() );
+        for ( int i = 0; i < size; i++ )
+          if ( smIDs[ i ] < 0 ) // is separator
+            anOrderIds.push_back( TListOfInt() );
+          else
+            anOrderIds.back().push_back(smIDs[ i ]);
+        
+        myNewMeshImpl->GetImpl().SetMeshOrder( anOrderIds );
+      }
+    } // loop on meshes
+
+    // notify algos on completed restoration
+    for ( meshi_group = meshGroupList.begin(); meshi_group != meshGroupList.end(); ++meshi_group )
+    {
+      SMESH_Mesh_i* myNewMeshImpl = meshi_group->first;
+      ::SMESH_Mesh& myLocMesh     = myNewMeshImpl->GetImpl();
+
+      TopoDS_Shape myLocShape;
+      if(myLocMesh.HasShapeToMesh())
+        myLocShape = myLocMesh.GetShapeToMesh();
+      else
+        myLocShape = SMESH_Mesh::PseudoShape();
+        
+      myLocMesh.GetSubMesh(myLocShape)->
+        ComputeStateEngine (SMESH_subMesh::SUBMESH_RESTORED);
     }
+
+    for ( hyp_data = hypDataList.begin(); hyp_data != hypDataList.end(); ++hyp_data )
+    {
+      SMESH_Hypothesis_i* hyp  = hyp_data->first;
+      hyp->UpdateAsMeshesRestored(); // for hyps needing full mesh data restored (issue 20918)
+    }
+
     // close mesh group
     if(aTopGroup)
       aTopGroup->CloseOnDisk();   
@@ -4027,9 +4563,9 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
 //=============================================================================
 
 bool SMESH_Gen_i::LoadASCII( SALOMEDS::SComponent_ptr theComponent,
-                            const SALOMEDS::TMPFile& theStream,
-                            const char*              theURL,
-                            bool                     isMultiFile ) {
+                             const SALOMEDS::TMPFile& theStream,
+                             const char*              theURL,
+                             bool                     isMultiFile ) {
   if(MYDEBUG) MESSAGE( "SMESH_Gen_i::LoadASCII" );
   return Load( theComponent, theStream, theURL, isMultiFile );
 
@@ -4098,6 +4634,7 @@ void SMESH_Gen_i::Close( SALOMEDS::SComponent_ptr theComponent )
 //     context->myDocument = 0;
 //   }
   
+  myCurrentStudy = SALOMEDS::Study::_nil();
   return;
 }
 
@@ -4125,9 +4662,9 @@ char* SMESH_Gen_i::ComponentDataType()
 //=============================================================================
 
 char* SMESH_Gen_i::IORToLocalPersistentID( SALOMEDS::SObject_ptr /*theSObject*/,
-                                          const char*           IORString,
-                                          CORBA::Boolean        /*isMultiFile*/,
-                                          CORBA::Boolean        /*isASCII*/ )
+                                           const char*           IORString,
+                                           CORBA::Boolean        /*isMultiFile*/,
+                                           CORBA::Boolean        /*isASCII*/ )
 {
   if(MYDEBUG) MESSAGE( "SMESH_Gen_i::IORToLocalPersistentID" );
   StudyContext* myStudyContext = GetCurrentStudyContext();
@@ -4153,9 +4690,9 @@ char* SMESH_Gen_i::IORToLocalPersistentID( SALOMEDS::SObject_ptr /*theSObject*/,
 //=============================================================================
 
 char* SMESH_Gen_i::LocalPersistentIDToIOR( SALOMEDS::SObject_ptr /*theSObject*/,
-                                          const char*           aLocalPersistentID,
-                                          CORBA::Boolean        /*isMultiFile*/,
-                                          CORBA::Boolean        /*isASCII*/ )
+                                           const char*           aLocalPersistentID,
+                                           CORBA::Boolean        /*isMultiFile*/,
+                                           CORBA::Boolean        /*isASCII*/ )
 {
   if(MYDEBUG) MESSAGE( "SMESH_Gen_i::LocalPersistentIDToIOR(): id = " << aLocalPersistentID );
   StudyContext* myStudyContext = GetCurrentStudyContext();
@@ -4219,6 +4756,11 @@ void SMESH_Gen_i::SetName(const char* theIOR,
   }
 }
 
+int SMESH_Gen_i::GetCurrentStudyID()
+{
+  return myCurrentStudy->_is_nil() || myCurrentStudy->_non_existent() ? -1 : myCurrentStudy->StudyId();
+}
+    
 //=============================================================================
 /*! 
  *  SMESHEngine_factory
@@ -4230,10 +4772,10 @@ void SMESH_Gen_i::SetName(const char* theIOR,
 extern "C"
 { SMESH_I_EXPORT
   PortableServer::ObjectId* SMESHEngine_factory( CORBA::ORB_ptr            orb,
-                                                PortableServer::POA_ptr   poa, 
-                                                PortableServer::ObjectId* contId,
-                                                const char*               instanceName, 
-                                                const char*               interfaceName )
+                                                 PortableServer::POA_ptr   poa, 
+                                                 PortableServer::ObjectId* contId,
+                                                 const char*               instanceName, 
+                                                 const char*               interfaceName )
   {
     if(MYDEBUG) MESSAGE( "PortableServer::ObjectId* SMESHEngine_factory()" );
     if(MYDEBUG) SCRUTE(interfaceName);