Salome HOME
Merge branch 'occ/shaper2smesh'
[modules/smesh.git] / src / SMESH_I / SMESH_Mesh_i.cxx
index 1390b2276a3b59a58c9ae6062688e5d2aa4c8ba5..d4e396cbdfacd0556715d974ba7d7b1d655a9077 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2019  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
 #include "DriverMED_W_Field.h"
 #include "DriverMED_W_SMESHDS_Mesh.h"
 #include "MED_Factory.hxx"
+#include "SMDS_LinearEdge.hxx"
 #include "SMDS_EdgePosition.hxx"
 #include "SMDS_ElemIterator.hxx"
 #include "SMDS_FacePosition.hxx"
 #include "SMDS_IteratorOnIterators.hxx"
 #include "SMDS_MeshGroup.hxx"
 #include "SMDS_SetIterator.hxx"
+#include "SMDS_StdIterator.hxx"
 #include "SMDS_VolumeTool.hxx"
 #include "SMESHDS_Command.hxx"
 #include "SMESHDS_CommandType.hxx"
@@ -70,6 +72,7 @@
 #include <TColStd_MapOfInteger.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
+#include <TopTools_DataMapOfShapeShape.hxx>
 #include <TopTools_MapIteratorOfMapOfShape.hxx>
 #include <TopTools_MapOfShape.hxx>
 #include <TopoDS_Compound.hxx>
@@ -94,6 +97,7 @@ static int MYDEBUG = 0;
 
 using namespace std;
 using SMESH::TPythonDump;
+using SMESH::TVar;
 
 int SMESH_Mesh_i::_idGenerator = 0;
 
@@ -104,15 +108,13 @@ int SMESH_Mesh_i::_idGenerator = 0;
 //=============================================================================
 
 SMESH_Mesh_i::SMESH_Mesh_i( PortableServer::POA_ptr thePOA,
-                            SMESH_Gen_i*            gen_i,
-                            CORBA::Long             studyId )
+                            SMESH_Gen_i*            gen_i )
 : SALOME::GenericObj_i( thePOA )
 {
-  MESSAGE("SMESH_Mesh_i");
   _impl          = NULL;
   _gen_i         = gen_i;
   _id            = _idGenerator++;
-  _studyId       = studyId;
+  _nbInvalidHypos= -1;
   _editor        = NULL;
   _previewEditor = NULL;
   _preMeshInfo   = NULL;
@@ -127,8 +129,6 @@ SMESH_Mesh_i::SMESH_Mesh_i( PortableServer::POA_ptr thePOA,
 
 SMESH_Mesh_i::~SMESH_Mesh_i()
 {
-  MESSAGE("~SMESH_Mesh_i");
-
   // destroy groups
   map<int, SMESH::SMESH_GroupBase_ptr>::iterator itGr;
   for (itGr = _mapGroups.begin(); itGr != _mapGroups.end(); itGr++)
@@ -161,7 +161,7 @@ SMESH_Mesh_i::~SMESH_Mesh_i()
   }
   _mapHypo.clear();
 
-  // clear cashed shapes if no more meshes remain; (the cash is blame,
+  // clear cached shapes if no more meshes remain; (the cache is blame,
   // together with publishing, of spent time increasing in issue 22874)
   if ( _impl->NbMeshes() == 1 )
     _gen_i->GetShapeReader()->ClearClientBuffer();
@@ -242,9 +242,7 @@ GEOM::GEOM_Object_ptr SMESH_Mesh_i::GetShapeToMesh()
         for ( ; data != _geomGroupData.end(); ++data )
           if ( data->_smeshObject->_is_equivalent( _this() ))
           {
-            SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
-            if ( study->_is_nil() ) break;
-            SALOMEDS::SObject_wrap so = study->FindObjectID( data->_groupEntry.c_str() );
+            SALOMEDS::SObject_wrap so = _gen_i->getStudyServant()->FindObjectID( data->_groupEntry.c_str() );
             CORBA::Object_var     obj = _gen_i->SObjectToObject( so );
             aShapeObj = GEOM::GEOM_Object::_narrow( obj );
             break;
@@ -258,6 +256,47 @@ GEOM::GEOM_Object_ptr SMESH_Mesh_i::GetShapeToMesh()
   return aShapeObj._retn();
 }
 
+//================================================================================
+/*!
+* \brief Replaces a shape in the mesh
+*/
+//================================================================================
+void SMESH_Mesh_i::ReplaceShape(GEOM::GEOM_Object_ptr theNewGeom)
+  throw (SALOME::SALOME_Exception)
+{
+  TopoDS_Shape S = _impl->GetShapeToMesh();
+  GEOM_Client* geomClient = _gen_i->GetShapeReader();
+  TCollection_AsciiString aIOR;
+  if (geomClient->Find(S, aIOR)) {
+    geomClient->RemoveShapeFromBuffer(aIOR);
+  }
+
+  // update the reference to theNewGeom (needed for correct execution of a dumped python script)
+  SMESH::SMESH_Mesh_var   me = _this();
+  SALOMEDS::SObject_wrap aSO = _gen_i->ObjectToSObject( me );
+  CORBA::String_var    entry = theNewGeom->GetStudyEntry();
+  if ( !aSO->_is_nil() )
+  {
+    SALOMEDS::SObject_wrap aShapeRefSO;
+    if ( aSO->FindSubObject( _gen_i->GetRefOnShapeTag(), aShapeRefSO.inout() ))
+    {
+      SALOMEDS::SObject_wrap    aShapeSO = _gen_i->getStudyServant()->FindObjectID( entry );
+      SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
+      builder->Addreference( aShapeRefSO, aShapeSO );
+    }
+  }
+
+  // re-assign global hypotheses to the new shape
+  _mainShapeTick = -1;
+  CheckGeomModif( true );
+
+  TPythonDump() << "SHAPERSTUDY.breakLinkForSubElements(salome.ObjectToSObject("
+                << me <<".GetMesh()), " << entry.in() << ")";
+
+  TPythonDump() <<  me << ".ReplaceShape( " << entry.in() << " )";
+
+}
+
 //================================================================================
 /*!
  * \brief Return false if the mesh is not yet fully loaded from the study file
@@ -302,9 +341,11 @@ void SMESH_Mesh_i::Clear() throw (SALOME::SALOME_Exception)
   catch(SALOME_Exception & S_ex) {
     THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM);
   }
-  _impl->GetMeshDS()->Modified();
 
   TPythonDump() <<  SMESH::SMESH_Mesh_var(_this()) << ".Clear()";
+
+  SMESH::SMESH_Mesh_var mesh = _this();
+  _gen_i->UpdateIcons( mesh );
 }
 
 //================================================================================
@@ -410,8 +451,8 @@ SMESH_Mesh_i::ImportMEDFile( const char* theFileName, const char* theMeshName )
   CreateGroupServants();
 
   int major, minor, release;
-  if( !MED::getMEDVersion( theFileName, major, minor, release ) )
-    major = minor = release = -1;
+  major = minor = release = 0;
+  MED::GetMEDVersion(theFileName, major, minor, release);
   _medFileInfo           = new SMESH::MedFileInfo();
   _medFileInfo->fileName = theFileName;
   _medFileInfo->fileSize = 0;
@@ -448,6 +489,13 @@ SMESH::DriverMED_ReadStatus SMESH_Mesh_i::ImportCGNSFile( const char*  theFileNa
 
   CreateGroupServants();
 
+  _medFileInfo           = new SMESH::MedFileInfo();
+  _medFileInfo->fileName = theFileName;
+  _medFileInfo->major    = 0;
+  _medFileInfo->minor    = 0;
+  _medFileInfo->release  = 0;
+  _medFileInfo->fileSize = SMESH_File( theFileName ).size();
+
   return ConvertDriverMEDReadStatus(status);
 }
 
@@ -457,13 +505,30 @@ SMESH::DriverMED_ReadStatus SMESH_Mesh_i::ImportCGNSFile( const char*  theFileNa
  */
 //================================================================================
 
-char* SMESH_Mesh_i::GetVersionString(SMESH::MED_VERSION version, CORBA::Short nbDigits)
+char* SMESH_Mesh_i::GetVersionString(CORBA::Long minor, CORBA::Short nbDigits)
 {
-  string ver = DriverMED_W_SMESHDS_Mesh::GetVersionString(MED::EVersion(version),
+  string ver = DriverMED_W_SMESHDS_Mesh::GetVersionString(minor,
                                                           nbDigits);
   return CORBA::string_dup( ver.c_str() );
 }
 
+//================================================================================
+/*!
+ *  Return the list of med versions compatibles for write/append,
+ *  encoded in 10*major+minor (for instance, code for med 3.2.1 is 32)
+ */
+//================================================================================
+SMESH::long_array* SMESH_Mesh_i::GetMEDVersionsCompatibleForAppend()
+{
+  SMESH::long_array_var aResult = new SMESH::long_array();
+  std::vector<int> mvok = MED::GetMEDVersionsAppendCompatible();
+  long nbver = mvok.size();
+  aResult->length( nbver );
+  for ( int i = 0; i < nbver; i++ )
+    aResult[i] = mvok[i];
+  return aResult._retn();
+}
+
 //=============================================================================
 /*!
  *  ImportUNVFile
@@ -482,6 +547,13 @@ int SMESH_Mesh_i::ImportUNVFile( const char* theFileName )
 
   CreateGroupServants();
 
+  _medFileInfo           = new SMESH::MedFileInfo();
+  _medFileInfo->fileName = theFileName;
+  _medFileInfo->major    = 0;
+  _medFileInfo->minor    = 0;
+  _medFileInfo->release  = 0;
+  _medFileInfo->fileSize = SMESH_File( theFileName ).size();
+
   SMESH_CATCH( SMESH::throwCorbaException );
 
   return 1;
@@ -500,7 +572,18 @@ int SMESH_Mesh_i::ImportSTLFile( const char* theFileName )
   SMESH_TRY;
 
   // Read mesh with name = <theMeshName> into SMESH_Mesh
-  _impl->STLToMesh( theFileName );
+  std::string name = _impl->STLToMesh( theFileName );
+  if ( !name.empty() )
+  {
+    SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( _this() );
+    _gen_i->SetName( meshSO, name.c_str() );
+  }
+  _medFileInfo           = new SMESH::MedFileInfo();
+  _medFileInfo->fileName = theFileName;
+  _medFileInfo->major    = 0;
+  _medFileInfo->minor    = 0;
+  _medFileInfo->release  = 0;
+  _medFileInfo->fileSize = SMESH_File( theFileName ).size();
 
   SMESH_CATCH( SMESH::throwCorbaException );
 
@@ -539,6 +622,13 @@ SMESH::ComputeError* SMESH_Mesh_i::ImportGMFFile( const char* theFileName,
 
   error = _impl->GMFToMesh( theFileName, theMakeRequiredGroups );
 
+  _medFileInfo           = new SMESH::MedFileInfo();
+  _medFileInfo->fileName = theFileName;
+  _medFileInfo->major    = 0;
+  _medFileInfo->minor    = 0;
+  _medFileInfo->release  = 0;
+  _medFileInfo->fileSize = SMESH_File( theFileName ).size();
+
   SMESH_CATCH( exceptionToComputeError );
 #undef SMESH_CAUGHT
 #define SMESH_CAUGHT
@@ -562,7 +652,7 @@ SMESH::Hypothesis_Status SMESH_Mesh_i::ConvertHypothesisStatus
   switch (theStatus) {
   RETURNCASE( HYP_OK            );
   RETURNCASE( HYP_MISSING       );
-  RETURNCASE( HYP_CONCURENT     );
+  RETURNCASE( HYP_CONCURRENT    );
   RETURNCASE( HYP_BAD_PARAMETER );
   RETURNCASE( HYP_HIDDEN_ALGO   );
   RETURNCASE( HYP_HIDING_ALGO   );
@@ -600,6 +690,8 @@ SMESH_Mesh_i::AddHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
   if ( _preMeshInfo )
     _preMeshInfo->ForgetOrLoad();
 
+  const int prevNbMeshEnt = _impl->NbNodes() + _impl->GetMeshDS()->NbElements();
+
   std::string error;
   SMESH_Hypothesis::Hypothesis_Status status = addHypothesis( aSubShape, anHyp, &error );
   anErrorText = error.c_str();
@@ -607,8 +699,11 @@ SMESH_Mesh_i::AddHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
   SMESH::SMESH_Mesh_var mesh( _this() );
   if ( !SMESH_Hypothesis::IsStatusFatal(status) )
   {
-    SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
-    _gen_i->AddHypothesisToShape( study, mesh, aSubShape, anHyp );
+    _gen_i->AddHypothesisToShape( mesh, aSubShape, anHyp );
+
+    int newNbMeshEnt = _impl->NbNodes() + _impl->GetMeshDS()->NbElements();
+    if ( newNbMeshEnt != prevNbMeshEnt )
+      _gen_i->UpdateIcons( mesh );
   }
   if(MYDEBUG) MESSAGE( " AddHypothesis(): status = " << status );
 
@@ -645,9 +740,9 @@ SMESH_Mesh_i::addHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
     //use PseudoShape in case if mesh has no shape
     if(HasShapeToMesh())
       myLocSubShape = _gen_i->GeomObjectToShape( aSubShape);
-    else              
+    else
       myLocSubShape = _impl->GetShapeToMesh();
-    
+
     const int hypId = anHyp->GetId();
     std::string error;
     status = _impl->AddHypothesis( myLocSubShape, hypId, &error );
@@ -693,8 +788,8 @@ SMESH::Hypothesis_Status SMESH_Mesh_i::RemoveHypothesis(GEOM::GEOM_Object_ptr aS
 
   if ( !SMESH_Hypothesis::IsStatusFatal(status) )
   {
-    SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
-    _gen_i->RemoveHypothesisFromShape( study, mesh, aSubShape, anHyp );
+    _gen_i->RemoveHypothesisFromShape( mesh, aSubShape, anHyp );
+    _gen_i->UpdateIcons( mesh );
   }
   // Update Python script
   if(_impl->HasShapeToMesh())
@@ -725,6 +820,9 @@ SMESH_Mesh_i::removeHypothesis(GEOM::GEOM_Object_ptr       aSubShape,
   if (CORBA::is_nil( anHyp ))
     THROW_SALOME_CORBA_EXCEPTION("bad hypothesis reference", SALOME::BAD_PARAM);
 
+  if ( _preMeshInfo )
+    _preMeshInfo->ForgetOrLoad();
+
   SMESH_Hypothesis::Hypothesis_Status status = SMESH_Hypothesis::HYP_OK;
   try
   {
@@ -864,9 +962,8 @@ SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::GetSubMesh(GEOM::GEOM_Object_ptr aSubShap
       subMesh = createSubMesh( aSubShape );
     if ( _gen_i->CanPublishInStudy( subMesh ))
     {
-      SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
       SALOMEDS::SObject_wrap aSO =
-        _gen_i->PublishSubMesh( study, aMesh, subMesh, aSubShape, theName );
+        _gen_i->PublishSubMesh( aMesh, subMesh, aSubShape, theName );
       if ( !aSO->_is_nil()) {
         // Update Python script
         TPythonDump() << aSO << " = " << aMesh << ".GetSubMesh( "
@@ -895,28 +992,25 @@ void SMESH_Mesh_i::RemoveSubMesh( SMESH::SMESH_subMesh_ptr theSubMesh )
     return;
 
   GEOM::GEOM_Object_var aSubShape;
-  SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy();
-  if ( !aStudy->_is_nil() )  {
-    // Remove submesh's SObject
-    SALOMEDS::SObject_wrap anSO = _gen_i->ObjectToSObject( aStudy, theSubMesh );
-    if ( !anSO->_is_nil() ) {
-      long aTag = SMESH_Gen_i::GetRefOnShapeTag();
-      SALOMEDS::SObject_wrap anObj, aRef;
-      if ( anSO->FindSubObject( aTag, anObj.inout() ) &&
-           anObj->ReferencedObject( aRef.inout() ))
-      {
-        CORBA::Object_var obj = aRef->GetObject();
-        aSubShape = GEOM::GEOM_Object::_narrow( obj );
-      }
-      // if ( aSubShape->_is_nil() ) // not published shape (IPAL13617)
-      //   aSubShape = theSubMesh->GetSubShape();
+  // Remove submesh's SObject
+  SALOMEDS::SObject_wrap anSO = _gen_i->ObjectToSObject( theSubMesh );
+  if ( !anSO->_is_nil() ) {
+    long aTag = SMESH_Gen_i::GetRefOnShapeTag();
+    SALOMEDS::SObject_wrap anObj, aRef;
+    if ( anSO->FindSubObject( aTag, anObj.inout() ) &&
+         anObj->ReferencedObject( aRef.inout() ))
+    {
+      CORBA::Object_var obj = aRef->GetObject();
+      aSubShape = GEOM::GEOM_Object::_narrow( obj );
+    }
+    // if ( aSubShape->_is_nil() ) // not published shape (IPAL13617)
+    //   aSubShape = theSubMesh->GetSubShape();
 
-      SALOMEDS::StudyBuilder_var builder = aStudy->NewBuilder();
-      builder->RemoveObjectWithChildren( anSO );
+    SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
+    builder->RemoveObjectWithChildren( anSO );
 
-      // Update Python script
-      TPythonDump() << SMESH::SMESH_Mesh_var( _this() ) << ".RemoveSubMesh( " << anSO << " )";
-    }
+    // Update Python script
+    TPythonDump() << SMESH::SMESH_Mesh_var( _this() ) << ".RemoveSubMesh( " << anSO << " )";
   }
 
   if ( removeSubMesh( theSubMesh, aSubShape.in() ))
@@ -946,9 +1040,8 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::CreateGroup( SMESH::ElementType theElemType
   if ( _gen_i->CanPublishInStudy( aNewGroup ) )
   {
     SMESH::SMESH_Mesh_var mesh = _this();
-    SALOMEDS::Study_var  study = _gen_i->GetCurrentStudy();
     SALOMEDS::SObject_wrap aSO =
-      _gen_i->PublishGroup( study, mesh, aNewGroup, GEOM::GEOM_Object::_nil(), theName);
+      _gen_i->PublishGroup( mesh, aNewGroup, GEOM::GEOM_Object::_nil(), theName);
     if ( !aSO->_is_nil())
       // Update Python script
       TPythonDump() << aSO << " = " << mesh << ".CreateGroup( "
@@ -977,15 +1070,14 @@ SMESH_Mesh_i::CreateGroupFromGEOM (SMESH::ElementType    theElemType,
   TopoDS_Shape aShape = _gen_i->GeomObjectToShape( theGeomObj );
   if ( !aShape.IsNull() )
   {
-    aNewGroup = 
-      SMESH::SMESH_GroupOnGeom::_narrow( createGroup( theElemType, theName, aShape ));
+    aNewGroup =
+      SMESH::SMESH_GroupOnGeom::_narrow( createGroup( theElemType, theName, /*id=*/-1, aShape ));
 
     if ( _gen_i->CanPublishInStudy( aNewGroup ) )
     {
       SMESH::SMESH_Mesh_var mesh = _this();
-      SALOMEDS::Study_var  study = _gen_i->GetCurrentStudy();
       SALOMEDS::SObject_wrap aSO =
-        _gen_i->PublishGroup( study, mesh, aNewGroup, theGeomObj, theName );
+        _gen_i->PublishGroup( mesh, aNewGroup, theGeomObj, theName );
       if ( !aSO->_is_nil())
         TPythonDump() << aSO << " = " << mesh << ".CreateGroupFromGEOM( "
                       << theElemType << ", '" << theName << "', " << theGeomObj << " )";
@@ -1023,7 +1115,7 @@ SMESH_Mesh_i::CreateGroupFromFilter(SMESH::ElementType theElemType,
     THROW_SALOME_CORBA_EXCEPTION("Invalid filter", SALOME::BAD_PARAM);
 
   SMESH::SMESH_GroupOnFilter_var aNewGroup = SMESH::SMESH_GroupOnFilter::_narrow
-    ( createGroup( theElemType, theName, TopoDS_Shape(), predicate ));
+    ( createGroup( theElemType, theName, /*id=*/-1, TopoDS_Shape(), predicate ));
 
   TPythonDump pd;
   if ( !aNewGroup->_is_nil() )
@@ -1032,9 +1124,8 @@ SMESH_Mesh_i::CreateGroupFromFilter(SMESH::ElementType theElemType,
   if ( _gen_i->CanPublishInStudy( aNewGroup ) )
   {
     SMESH::SMESH_Mesh_var mesh = _this();
-    SALOMEDS::Study_var  study = _gen_i->GetCurrentStudy();
     SALOMEDS::SObject_wrap aSO =
-      _gen_i->PublishGroup( study, mesh, aNewGroup, GEOM::GEOM_Object::_nil(), theName );
+      _gen_i->PublishGroup( mesh, aNewGroup, GEOM::GEOM_Object::_nil(), theName );
 
     if ( !aSO->_is_nil())
       pd << aSO << " = " << mesh << ".CreateGroupFromFilter( "
@@ -1061,19 +1152,19 @@ void SMESH_Mesh_i::RemoveGroup( SMESH::SMESH_GroupBase_ptr theGroup )
   if ( !aGroup )
     return;
 
-  SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy();
-  if ( !aStudy->_is_nil() )
+  if ( aGroup->GetMeshServant() != this )
+    THROW_SALOME_CORBA_EXCEPTION( "RemoveGroup(): group does not belong to this mesh",
+                                  SALOME::BAD_PARAM );
+
+  SALOMEDS::SObject_wrap aGroupSO = _gen_i->ObjectToSObject( theGroup );
+  if ( !aGroupSO->_is_nil() )
   {
-    SALOMEDS::SObject_wrap aGroupSO = _gen_i->ObjectToSObject( aStudy, theGroup );
-    if ( !aGroupSO->_is_nil() )
-    {
-      // Update Python script
-      TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".RemoveGroup( " << aGroupSO << " )";
+    // Update Python script
+    TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".RemoveGroup( " << aGroupSO << " )";
 
-      // Remove group's SObject
-      SALOMEDS::StudyBuilder_var builder = aStudy->NewBuilder();
-      builder->RemoveObjectWithChildren( aGroupSO );
-    }
+    // Remove group's SObject
+    SALOMEDS::StudyBuilder_var builder = SMESH_Gen_i::getStudyServant()->NewBuilder();
+    builder->RemoveObjectWithChildren( aGroupSO );
   }
   aGroup->Modified(/*removed=*/true); // notify dependent Filter with FT_BelongToMeshGroup criterion
 
@@ -1099,8 +1190,14 @@ void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup
   if ( theGroup->_is_nil() )
     return;
 
+  SMESH_GroupBase_i* groupImpl = SMESH::DownCast< SMESH_GroupBase_i* >( theGroup );
+  if ( !groupImpl || groupImpl->GetMeshServant() != this )
+    THROW_SALOME_CORBA_EXCEPTION( "RemoveGroupWithContents(): group does not belong to this mesh",
+                                  SALOME::BAD_PARAM);
+
   vector<int> nodeIds; // to remove nodes becoming free
-  if ( !theGroup->IsEmpty() )
+  bool isNodal = ( theGroup->GetType() == SMESH::NODE );
+  if ( !isNodal && !theGroup->IsEmpty() )
   {
     CORBA::Long elemID = theGroup->GetID( 1 );
     int nbElemNodes = GetElemNbNodes( elemID );
@@ -1108,36 +1205,46 @@ void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup
       nodeIds.reserve( theGroup->Size() * nbElemNodes );
   }
 
-  // Remove contents
+  // Retrieve contents
   SMESH::SMESH_IDSource_var idSrc = SMESH::SMESH_IDSource::_narrow( theGroup );
   SMDS_ElemIteratorPtr     elemIt = GetElements( idSrc, theGroup->GetType() );
-  while ( elemIt->more() )
-  {
-    const SMDS_MeshElement* e = elemIt->next();
+  SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > elemBeg( elemIt ), elemEnd;
+  std::vector< const SMDS_MeshElement* > elems( theGroup->Size() );
+  elems.assign( elemBeg, elemEnd );
+
+  TPythonDump pyDump; // Suppress dump from RemoveGroup()
 
-    SMDS_ElemIteratorPtr nIt = e->nodesIterator();
-    while ( nIt->more() )
-      nodeIds.push_back( nIt->next()->GetID() );
+  // Remove group
+  RemoveGroup( theGroup );
+
+  // Remove contents
+  for ( size_t i = 0; i < elems.size(); ++i )
+  {
+    // if ( !_impl->GetMeshDS()->Contains( elems[i] ))
+    //   continue;
+    if ( !isNodal )
+    {
+      for ( SMDS_ElemIteratorPtr nIt = elems[i]->nodesIterator(); nIt->more(); )
+        nodeIds.push_back( nIt->next()->GetID() );
 
-    _impl->GetMeshDS()->RemoveElement( e );
+      _impl->GetMeshDS()->RemoveFreeElement( elems[i], /*sm=*/0 );
+    }
+    else
+    {
+      _impl->GetMeshDS()->RemoveElement( elems[i] );
+    }
   }
 
   // Remove free nodes
-  if ( theGroup->GetType() != SMESH::NODE )
-    for ( size_t i = 0 ; i < nodeIds.size(); ++i )
-      if ( const SMDS_MeshNode* n = _impl->GetMeshDS()->FindNode( nodeIds[i] ))
-        if ( n->NbInverseElements() == 0 )
-          _impl->GetMeshDS()->RemoveFreeNode( n, /*sm=*/0 );
-
-  TPythonDump pyDump; // Supress dump from RemoveGroup()
+  for ( size_t i = 0 ; i < nodeIds.size(); ++i )
+    if ( const SMDS_MeshNode* n = _impl->GetMeshDS()->FindNode( nodeIds[i] ))
+      if ( n->NbInverseElements() == 0 )
+        _impl->GetMeshDS()->RemoveFreeNode( n, /*sm=*/0 );
 
   // Update Python script (theGroup must be alive for this)
   pyDump << SMESH::SMESH_Mesh_var(_this())
          << ".RemoveGroupWithContents( " << theGroup << " )";
 
-  // Remove group
-  RemoveGroup( theGroup );
-
   SMESH_CATCH( SMESH::throwCorbaException );
 }
 
@@ -1364,7 +1471,7 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::IntersectGroups( SMESH::SMESH_GroupBase_ptr
 
 //=============================================================================
 /*!
-  \brief Intersect list of groups. New group is created. All mesh elements that 
+  \brief Intersect list of groups. New group is created. All mesh elements that
   are present in all initial groups simultaneously are added to the new one.
   \param theGroups list of groups
   \param theName name of group to be created
@@ -1449,7 +1556,7 @@ SMESH_Mesh_i::IntersectListOfGroups(const SMESH::ListOfGroups& theGroups,
 }
 
 //=============================================================================
-/*! 
+/*!
  *  New group is created. All mesh elements that are present in
  *  a main group but is not present in a tool group are added to the new one
  */
@@ -1512,7 +1619,7 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutGroups( SMESH::SMESH_GroupBase_ptr theGr
 
 //=============================================================================
 /*!
-  \brief Cut lists of groups. New group is created. All mesh elements that are 
+  \brief Cut lists of groups. New group is created. All mesh elements that are
   present in main groups but do not present in tool groups are added to the new one
   \param theMainGroups list of main groups
   \param theToolGroups list of tool groups
@@ -1521,8 +1628,8 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutGroups( SMESH::SMESH_GroupBase_ptr theGr
 */
 //=============================================================================
 SMESH::SMESH_Group_ptr
-SMESH_Mesh_i::CutListOfGroups(const SMESH::ListOfGroups& theMainGroups, 
-                              const SMESH::ListOfGroups& theToolGroups, 
+SMESH_Mesh_i::CutListOfGroups(const SMESH::ListOfGroups& theMainGroups,
+                              const SMESH::ListOfGroups& theToolGroups,
                               const char*                theName )
   throw (SALOME::SALOME_Exception)
 {
@@ -1822,6 +1929,89 @@ SMESH_Mesh_i::CreateDimGroup(const SMESH::ListOfIDSources& theGroups,
   return aResGrp._retn();
 }
 
+//================================================================================
+/*!
+ * \brief Distribute all faces of the mesh between groups using sharp edges and optionally
+ *        existing 1D elements as group boundaries.
+ *  \param [in] theSharpAngle - edge is considered sharp if an angle between normals of
+ *              adjacent faces is more than \a sharpAngle in degrees.
+ *  \param [in] theCreateEdges - to create 1D elements for detected sharp edges.
+ *  \param [in] theUseExistingEdges - to use existing edges as group boundaries
+ *  \return ListOfGroups - the created groups
+ */
+//================================================================================
+
+SMESH::ListOfGroups*
+SMESH_Mesh_i::FaceGroupsSeparatedByEdges( CORBA::Double  theSharpAngle,
+                                          CORBA::Boolean theCreateEdges,
+                                          CORBA::Boolean theUseExistingEdges )
+  throw (SALOME::SALOME_Exception)
+{
+  if ( theSharpAngle < 0 || theSharpAngle > 180 )
+    THROW_SALOME_CORBA_EXCEPTION("Invalid sharp angle, it must be between 0 and 180 degrees",
+                                 SALOME::BAD_PARAM);
+
+  SMESH::ListOfGroups_var resultGroups = new SMESH::ListOfGroups;
+
+  TPythonDump pyDump;
+
+  SMESH_TRY;
+  if ( _preMeshInfo )
+    _preMeshInfo->FullLoadFromFile();
+
+  SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
+
+  std::vector< SMESH_MeshAlgos::Edge > edges =
+    SMESH_MeshAlgos::FindSharpEdges( meshDS, theSharpAngle, theUseExistingEdges );
+
+  if ( theCreateEdges )
+  {
+    std::vector<const SMDS_MeshNode *> nodes(2);
+    for ( size_t i = 0; i < edges.size(); ++i )
+    {
+      nodes[0] = edges[i]._node1;
+      nodes[1] = edges[i]._node2;
+      if ( meshDS->FindElement( nodes, SMDSAbs_Edge ))
+        continue;
+      if ( edges[i]._medium )
+        meshDS->AddEdge( edges[i]._node1, edges[i]._node2, edges[i]._medium );
+      else
+        meshDS->AddEdge( edges[i]._node1, edges[i]._node2 );
+    }
+  }
+
+  std::vector< std::vector< const SMDS_MeshElement* > > faceGroups =
+    SMESH_MeshAlgos::SeparateFacesByEdges( meshDS, edges );
+
+  SMESH::SMESH_MeshEditor_var editor = GetMeshEditor(); // create _editor
+
+  resultGroups->length( faceGroups.size() );
+  for ( size_t iG = 0; iG < faceGroups.size(); ++iG )
+  {
+    SMESH::SMESH_Group_var group = CreateGroup( SMESH::FACE,
+                                                _editor->GenerateGroupName("Group").c_str());
+    resultGroups[iG] = SMESH::SMESH_Group::_duplicate( group );
+
+    SMESHDS_GroupBase* groupBaseDS =
+      SMESH::DownCast<SMESH_GroupBase_i*>( group )->GetGroupDS();
+    SMDS_MeshGroup& groupCore = static_cast< SMESHDS_Group* >( groupBaseDS )->SMDSGroup();
+
+    std::vector< const SMDS_MeshElement* >& faces = faceGroups[ iG ];
+    for ( size_t i = 0; i < faces.size(); ++i )
+      groupCore.Add( faces[i] );
+  }
+
+  pyDump << resultGroups << " = " << SMESH::SMESH_Mesh_var(_this())
+         << ".FaceGroupsSeparatedByEdges( "
+         << TVar( theSharpAngle ) << ", "
+         << theCreateEdges << ", "
+         << theUseExistingEdges << " )";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return resultGroups._retn();
+
+}
+
 //================================================================================
 /*!
  * \brief Remember GEOM group data
@@ -1834,14 +2024,12 @@ void SMESH_Mesh_i::addGeomGroupData(GEOM::GEOM_Object_ptr theGeomObj,
   if ( CORBA::is_nil( theGeomObj ) || theGeomObj->GetType() != GEOM_GROUP )
     return;
   // group SO
-  SALOMEDS::Study_var    study   = _gen_i->GetCurrentStudy();
-  SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( study, theGeomObj );
+  SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( theGeomObj );
   if ( groupSO->_is_nil() )
     return;
   // group indices
-  GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine();
-  GEOM::GEOM_IGroupOperations_wrap groupOp =
-    geomGen->GetIGroupOperations( _gen_i->GetCurrentStudyID() );
+  GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine( theGeomObj );
+  GEOM::GEOM_IGroupOperations_ptr groupOp = geomGen->GetIGroupOperations();
   GEOM::ListOfLong_var ids = groupOp->GetObjects( theGeomObj );
 
   // store data
@@ -1883,43 +2071,58 @@ void SMESH_Mesh_i::removeGeomGroupData(CORBA::Object_ptr theSmeshObj)
  * \brief Return new group contents if it has been changed and update group data
  */
 //================================================================================
+enum { ONLY_IF_CHANGED, IS_BREAK_LINK, MAIN_TRANSFORMED };
 
-TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData)
+TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData, int how )
 {
   TopoDS_Shape newShape;
 
-  // get geom group
-  SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
-  if ( study->_is_nil() ) return newShape; // means "not changed"
-  SALOMEDS::SObject_wrap groupSO = study->FindObjectID( groupData._groupEntry.c_str() );
-  if ( !groupSO->_is_nil() )
+  if ( how == IS_BREAK_LINK )
   {
-    CORBA::Object_var groupObj = _gen_i->SObjectToObject( groupSO );
-    if ( CORBA::is_nil( groupObj )) return newShape;
-    GEOM::GEOM_Object_var geomGroup = GEOM::GEOM_Object::_narrow( groupObj );
-
-    // get indices of group items
-    set<int> curIndices;
-    GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine();
-    GEOM::GEOM_IGroupOperations_wrap groupOp =
-      geomGen->GetIGroupOperations( _gen_i->GetCurrentStudyID() );
-    GEOM::ListOfLong_var   ids = groupOp->GetObjects( geomGroup );
-    for ( CORBA::ULong i = 0; i < ids->length(); ++i )
-      curIndices.insert( ids[i] );
-
-    if ( groupData._indices == curIndices )
-      return newShape; // group not changed
-
-    // update data
-    groupData._indices = curIndices;
-
-    GEOM_Client* geomClient = _gen_i->GetShapeReader();
-    if ( !geomClient ) return newShape;
-    CORBA::String_var groupIOR = geomGen->GetStringFromIOR( geomGroup );
-    geomClient->RemoveShapeFromBuffer( groupIOR.in() );
-    newShape = _gen_i->GeomObjectToShape( geomGroup );
+    SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( groupData._smeshObject );
+    SALOMEDS::SObject_wrap geomRefSO, geomSO;
+    if ( !meshSO->_is_nil() &&
+         meshSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
+         geomRefSO->ReferencedObject( geomSO.inout() ))
+    {
+      CORBA::Object_var  geomObj = _gen_i->SObjectToObject( geomSO );
+      GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( geomObj );
+      newShape = _gen_i->GeomObjectToShape( geom );
+      CORBA::String_var entry = geom->GetStudyEntry();
+      groupData._groupEntry = entry.in();
+    }
+  }
+  else
+  {
+    // get geom group
+    SALOMEDS::SObject_wrap groupSO = SMESH_Gen_i::getStudyServant()->FindObjectID( groupData._groupEntry.c_str() );
+    if ( !groupSO->_is_nil() )
+    {
+      CORBA::Object_var groupObj = _gen_i->SObjectToObject( groupSO );
+      if ( CORBA::is_nil( groupObj )) return newShape;
+      GEOM::GEOM_Object_var geomGroup = GEOM::GEOM_Object::_narrow( groupObj );
+
+      // get indices of group items
+      set<int> curIndices;
+      GEOM::GEOM_Gen_var              geomGen = _gen_i->GetGeomEngine( geomGroup );
+      GEOM::GEOM_IGroupOperations_ptr groupOp = geomGen->GetIGroupOperations();
+      GEOM::ListOfLong_var                ids = groupOp->GetObjects( geomGroup );
+      for ( CORBA::ULong i = 0; i < ids->length(); ++i )
+        curIndices.insert( ids[i] );
+
+      if ( how == ONLY_IF_CHANGED && groupData._indices == curIndices )
+        return newShape; // group not changed
+
+      // update data
+      groupData._indices = curIndices;
+
+      GEOM_Client* geomClient = _gen_i->GetShapeReader();
+      if ( !geomClient ) return newShape;
+      CORBA::String_var groupIOR = geomGen->GetStringFromIOR( geomGroup );
+      geomClient->RemoveShapeFromBuffer( groupIOR.in() );
+      newShape = _gen_i->GeomObjectToShape( geomGroup );
+    }
   }
-
   if ( newShape.IsNull() ) {
     // geom group becomes empty - return empty compound
     TopoDS_Compound compound;
@@ -1948,11 +2151,66 @@ namespace
   struct TGroupOnGeomData
   {
     int                 _oldID;
-    int                 _shapeID;
+    TopoDS_Shape        _shape;
     SMDSAbs_ElementType _type;
     std::string         _name;
     Quantity_Color      _color;
+
+    TGroupOnGeomData( const SMESHDS_GroupOnGeom* group )
+    {
+      _oldID = group->GetID();
+      _type  = group->GetType();
+      _name  = group->GetStoreName();
+      _color = group->GetColor();
+    }
   };
+
+  //-----------------------------------------------------------------------------
+  /*!
+   * \brief Check if a filter is still valid after geometry removal
+   */
+  bool isValidGeomFilter( SMESH::Filter_var theFilter )
+  {
+    if ( theFilter->_is_nil() )
+      return false;
+    SMESH::Filter::Criteria_var criteria;
+    theFilter->GetCriteria( criteria.out() );
+
+    for ( CORBA::ULong iCr = 0; iCr < criteria->length(); ++iCr )
+    {
+      const char* thresholdID = criteria[ iCr ].ThresholdID.in();
+      std::string entry;
+      switch ( criteria[ iCr ].Type )
+      {
+      case SMESH::FT_BelongToGeom:
+      case SMESH::FT_BelongToPlane:
+      case SMESH::FT_BelongToCylinder:
+      case SMESH::FT_BelongToGenSurface:
+      case SMESH::FT_LyingOnGeom:
+        entry = thresholdID;
+        break;
+      case SMESH::FT_ConnectedElements:
+        if ( thresholdID )
+        {
+          entry = thresholdID;
+          break;
+        }
+      default:
+        continue;
+      }
+      SMESH_Gen_i*           gen = SMESH_Gen_i::GetSMESHGen();
+      SALOMEDS::SObject_wrap  so = gen->getStudyServant()->FindObjectID( entry.c_str() );
+      if ( so->_is_nil() )
+        return false;
+      CORBA::Object_var      obj = so->GetObject();
+      GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( obj );
+      if ( gen->GeomObjectToShape( geom ).IsNull() )
+        return false;
+
+    } // loop on criteria
+
+    return true;
+  }
 }
 
 //=============================================================================
@@ -1963,41 +2221,93 @@ namespace
  */
 //=============================================================================
 
-void SMESH_Mesh_i::CheckGeomModif()
+void SMESH_Mesh_i::CheckGeomModif( bool isBreakLink )
 {
-  if ( !_impl->HasShapeToMesh() ) return;
+  SMESH::SMESH_Mesh_var me = _this();
+  GEOM::GEOM_Object_var mainGO = GetShapeToMesh();
+
+  TPythonDump dumpNothing; // prevent any dump
+
+  //bool removedFromClient = false;
+
+  if ( mainGO->_is_nil() ) // GEOM_Client cleared or geometry removed? (IPAL52735, PAL23636)
+  {
+    //removedFromClient = _impl->HasShapeToMesh();
+
+    // try to find geometry by study reference
+    SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( me );
+    SALOMEDS::SObject_wrap geomRefSO, geomSO;
+    if ( !meshSO->_is_nil() &&
+         meshSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
+         geomRefSO->ReferencedObject( geomSO.inout() ))
+    {
+      CORBA::Object_var geomObj = _gen_i->SObjectToObject( geomSO );
+      mainGO = GEOM::GEOM_Object::_narrow( geomObj );
+    }
 
-  SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
-  if ( study->_is_nil() ) return;
+    if ( mainGO->_is_nil() &&    // geometry removed ==>
+         !geomRefSO->_is_nil() ) // remove geom dependent data: sub-meshes etc.
+    {
+      // convert geom dependent groups into standalone ones
+      CheckGeomGroupModif();
+
+      _impl->ShapeToMesh( TopoDS_Shape() );
+
+      // remove sub-meshes
+      std::map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
+      while ( i_sm != _mapSubMeshIor.end() )
+      {
+        SMESH::SMESH_subMesh_ptr sm = i_sm->second;
+        ++i_sm;
+        RemoveSubMesh( sm );
+      }
+      // remove all children except groups in the study
+      SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
+      SALOMEDS::SObject_wrap so;
+      for ( CORBA::Long tag = SMESH::Tag_RefOnShape; tag <= SMESH::Tag_LastSubMesh; ++tag )
+        if ( meshSO->FindSubObject( tag, so.inout() ))
+          builder->RemoveObjectWithChildren( so );
+
+      _gen_i->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED" );
+
+      return;
+    }
+  }
+
+  if ( !_impl->HasShapeToMesh() ) return;
 
-  GEOM::GEOM_Object_var mainGO = _gen_i->ShapeToGeomObject( _impl->GetShapeToMesh() );
-  //if ( mainGO->_is_nil() ) return;
 
   // Update after group modification
 
-  if ( mainGO->_is_nil() || /* shape was removed from GEOM_Client by newGroupShape()
-                               called by other mesh (IPAL52735) */
-       mainGO->GetType() == GEOM_GROUP ||
+  if ( mainGO->GetType() == GEOM_GROUP ||    // is group or not modified
        mainGO->GetTick() == _mainShapeTick )
   {
+    int nb = NbNodes() + NbElements();
     CheckGeomGroupModif();
+    if ( nb != NbNodes() + NbElements() ) // something removed due to hypotheses change
+      _gen_i->UpdateIcons( me );
     return;
   }
 
-  // Update after shape transformation like Translate
+  // Update after shape modification
 
   GEOM_Client* geomClient = _gen_i->GetShapeReader();
   if ( !geomClient ) return;
-  GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine();
+  GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine( mainGO );
   if ( geomGen->_is_nil() ) return;
 
   CORBA::String_var ior = geomGen->GetStringFromIOR( mainGO );
   geomClient->RemoveShapeFromBuffer( ior.in() );
 
-  // Update data taking into account that
+  // Update data taking into account that if topology doesn't change
   // all sub-shapes change but IDs of sub-shapes remain (except for geom groups)
 
-  _impl->Clear();
+  if ( _preMeshInfo )
+    _preMeshInfo->ForgetAllData();
+
+  
+  if (isBreakLink)
+    _impl->Clear();
   TopoDS_Shape newShape = _gen_i->GeomObjectToShape( mainGO );
   if ( newShape.IsNull() )
     return;
@@ -2007,23 +2317,58 @@ void SMESH_Mesh_i::CheckGeomModif()
   SMESHDS_Mesh * meshDS = _impl->GetMeshDS();
 
   // store data of groups on geometry
-  vector< TGroupOnGeomData > groupsData;
-  const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
+  std::vector< TGroupOnGeomData > groupsData;
+  const std::set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
   groupsData.reserve( groups.size() );
-  set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
+  TopTools_DataMapOfShapeShape old2newShapeMap;
+  std::set<SMESHDS_GroupBase*>::const_iterator g = groups.begin();
   for ( ; g != groups.end(); ++g )
+  {
     if ( const SMESHDS_GroupOnGeom* group = dynamic_cast< SMESHDS_GroupOnGeom* >( *g ))
     {
-      TGroupOnGeomData data;
-      data._oldID   = group->GetID();
-      data._shapeID = meshDS->ShapeToIndex( group->GetShape() );
-      data._type    = group->GetType();
-      data._name    = group->GetStoreName();
-      data._color   = group->GetColor();
-      groupsData.push_back( data );
+      groupsData.push_back( TGroupOnGeomData( group ));
+
+      // get a new shape
+      SMESH::SMESH_GroupOnGeom_var gog;
+      std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_grp = _mapGroups.find( group->GetID() );
+      if ( i_grp != _mapGroups.end() )
+        gog = SMESH::SMESH_GroupOnGeom::_narrow( i_grp->second );
+
+      GEOM::GEOM_Object_var geom;
+      if ( !gog->_is_nil() )
+      {
+        if ( isBreakLink )
+        {
+          SALOMEDS::SObject_wrap grpSO = _gen_i->ObjectToSObject( gog );
+          SALOMEDS::SObject_wrap geomRefSO, geomSO;
+          if ( !grpSO->_is_nil() &&
+               grpSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
+               geomRefSO->ReferencedObject( geomSO.inout() ))
+          {
+            CORBA::Object_var geomObj = _gen_i->SObjectToObject( geomSO );
+            geom = GEOM::GEOM_Object::_narrow( geomObj );
+          }
+        }
+        else
+        {
+          geom = gog->GetShape();
+        }
+      }
+      if ( !geom->_is_nil() )
+      {
+        CORBA::String_var ior = geomGen->GetStringFromIOR( geom );
+        geomClient->RemoveShapeFromBuffer( ior.in() );
+        groupsData.back()._shape = _gen_i->GeomObjectToShape( geom );
+        old2newShapeMap.Bind( group->GetShape(), groupsData.back()._shape );
+      }
+      else if ( old2newShapeMap.IsBound( group->GetShape() ))
+      {
+        groupsData.back()._shape = old2newShapeMap( group->GetShape() );
+      }
     }
+  }
   // store assigned hypotheses
-  vector< pair< int, THypList > > ids2Hyps;
+  std::vector< pair< int, THypList > > ids2Hyps;
   const ShapeToHypothesis & hyps = meshDS->GetHypotheses();
   for ( ShapeToHypothesis::Iterator s2hyps( hyps ); s2hyps.More(); s2hyps.Next() )
   {
@@ -2032,16 +2377,50 @@ void SMESH_Mesh_i::CheckGeomModif()
     ids2Hyps.push_back( make_pair( meshDS->ShapeToIndex( s ), hyps ));
   }
 
-  // change shape to mesh
+  std::map< std::set<int>, int > ii2iMap; // group sub-ids to group id in SMESHDS
+
+  // count shapes excluding compounds corresponding to geom groups
   int oldNbSubShapes = meshDS->MaxShapeIndex();
+  for ( ; oldNbSubShapes > 0; --oldNbSubShapes )
+  {
+    const TopoDS_Shape& s = meshDS->IndexToShape( oldNbSubShapes );
+    if ( s.IsNull() || s.ShapeType() != TopAbs_COMPOUND )
+      break;
+    // fill ii2iMap
+    std::set<int> subIds;
+    for ( TopoDS_Iterator it( s ); it.More(); it.Next() )
+      subIds.insert( meshDS->ShapeToIndex( it.Value() ));
+    ii2iMap.insert( std::make_pair( subIds, oldNbSubShapes ));
+  }
+
+  // check if shape topology changes - save shape type per shape ID
+  std::vector< TopAbs_ShapeEnum > shapeTypes( Max( oldNbSubShapes + 1, 1 ));
+  for ( int shapeID = oldNbSubShapes; shapeID > 0; --shapeID )
+    shapeTypes[ shapeID ] = meshDS->IndexToShape( shapeID ).ShapeType();
+
+  // change shape to mesh
   _impl->ShapeToMesh( TopoDS_Shape() );
   _impl->ShapeToMesh( newShape );
 
-  // re-add shapes of geom groups
-  list<TGeomGroupData>::iterator data = _geomGroupData.begin();
+  // check if shape topology changes - check new shape types
+  bool sameTopology = ( oldNbSubShapes == meshDS->MaxShapeIndex() );
+  for ( int shapeID = oldNbSubShapes; shapeID > 0 &&  sameTopology; --shapeID )
+  {
+    const TopoDS_Shape& s = meshDS->IndexToShape( shapeID );
+    sameTopology = ( !s.IsNull() && s.ShapeType() == shapeTypes[ shapeID ]);
+  }
+
+  // re-add shapes (compounds) of geom groups
+  std::map< int, int > old2newIDs; // group IDs
+  std::list<TGeomGroupData>::iterator data = _geomGroupData.begin();
   for ( ; data != _geomGroupData.end(); ++data )
   {
-    TopoDS_Shape newShape = newGroupShape( *data );
+    int oldID = 0;
+    std::map< std::set<int>, int >::iterator ii2i = ii2iMap.find( data->_indices );
+    if ( ii2i != ii2iMap.end() )
+      oldID = ii2i->second;
+
+    TopoDS_Shape newShape = newGroupShape( *data, isBreakLink ? IS_BREAK_LINK : MAIN_TRANSFORMED );
     if ( !newShape.IsNull() )
     {
       if ( meshDS->ShapeToIndex( newShape ) > 0 ) // a group reduced to one sub-shape
@@ -2051,73 +2430,194 @@ void SMESH_Mesh_i::CheckGeomModif()
         BRep_Builder().Add( compound, newShape );
         newShape = compound;
       }
-      _impl->GetSubMesh( newShape );
+      int newID = _impl->GetSubMesh( newShape )->GetId();
+      if ( oldID && oldID != newID )
+        old2newIDs.insert( std::make_pair( oldID, newID ));
     }
   }
-  if ( oldNbSubShapes != meshDS->MaxShapeIndex() )
-    THROW_SALOME_CORBA_EXCEPTION( "SMESH_Mesh_i::CheckGeomModif() bug",
-                                  SALOME::INTERNAL_ERROR );
 
   // re-assign hypotheses
   for ( size_t i = 0; i < ids2Hyps.size(); ++i )
   {
-    const TopoDS_Shape& s = meshDS->IndexToShape( ids2Hyps[i].first );
+    if ( !sameTopology && ids2Hyps[i].first != 1 )
+      continue; // assign only global hypos
+    int sID = ids2Hyps[i].first;
+    std::map< int, int >::iterator o2n = old2newIDs.find( sID );
+    if ( o2n != old2newIDs.end() )
+      sID = o2n->second;
+    const TopoDS_Shape& s = meshDS->IndexToShape( sID );
     const THypList&  hyps = ids2Hyps[i].second;
     THypList::const_iterator h = hyps.begin();
     for ( ; h != hyps.end(); ++h )
       _impl->AddHypothesis( s, (*h)->GetID() );
   }
 
-  // restore groups
-  for ( size_t i = 0; i < groupsData.size(); ++i )
+  if ( !sameTopology )
   {
-    const TGroupOnGeomData& data = groupsData[i];
+    // remove invalid study sub-objects
+    CheckGeomGroupModif();
+  }
+  else
+  {
+    // restore groups on geometry
+    for ( size_t i = 0; i < groupsData.size(); ++i )
+    {
+      const TGroupOnGeomData& data = groupsData[i];
+      if ( data._shape.IsNull() )
+        continue;
 
-    map<int, SMESH::SMESH_GroupBase_ptr>::iterator i2g = _mapGroups.find( data._oldID );
-    if ( i2g == _mapGroups.end() ) continue;
+      std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i2g = _mapGroups.find( data._oldID );
+      if ( i2g == _mapGroups.end() ) continue;
 
-    SMESH_GroupBase_i* gr_i = SMESH::DownCast<SMESH_GroupBase_i*>( i2g->second );
-    if ( !gr_i ) continue;
+      SMESH_GroupBase_i* gr_i = SMESH::DownCast<SMESH_GroupBase_i*>( i2g->second );
+      if ( !gr_i ) continue;
 
-    int id;
-    SMESH_Group* g = _impl->AddGroup( data._type, data._name.c_str(), id,
-                                      meshDS->IndexToShape( data._shapeID ));
-    if ( !g )
-    {
-      _mapGroups.erase( i2g );
+      SMESH_Group* g = _impl->AddGroup( data._type, data._name.c_str(), data._oldID, data._shape );
+      if ( !g )
+        _mapGroups.erase( i2g );
+      else
+        g->GetGroupDS()->SetColor( data._color );
     }
-    else
+
+    std::map< int, int >::iterator o2n = old2newIDs.begin();
+    for ( ; o2n != old2newIDs.end(); ++o2n )
     {
-      g->GetGroupDS()->SetColor( data._color );
-      gr_i->changeLocalId( id );
-      _mapGroups[ id ] = i2g->second;
-      if ( data._oldID != id )
-        _mapGroups.erase( i2g );
+      int newID = o2n->second, oldID = o2n->first;
+      if ( !_mapSubMesh.count( oldID ))
+        continue;
+      if ( newID > 0 )
+      {
+        _mapSubMesh   [ newID ] = _impl->GetSubMeshContaining( newID );
+        _mapSubMesh_i [ newID ] = _mapSubMesh_i [ oldID ];
+        _mapSubMeshIor[ newID ] = _mapSubMeshIor[ oldID ];
+      }
+      _mapSubMesh.   erase(oldID);
+      _mapSubMesh_i. erase(oldID);
+      _mapSubMeshIor.erase(oldID);
+      if ( newID > 0 )
+        _mapSubMesh_i [ newID ]->changeLocalId( newID );
     }
+
+    // update _mapSubMesh
+    std::map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
+    for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
+      i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
   }
 
-  // update _mapSubMesh
-  map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
-  for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
-    i_sm->second = _impl->GetSubMesh( meshDS->IndexToShape( i_sm->first ));
+  _gen_i->UpdateIcons( me );
 
+  if ( !isBreakLink )
+  {
+    SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( me );
+    if ( !meshSO->_is_nil() )
+      _gen_i->SetPixMap(meshSO, "ICON_SMESH_TREE_GEOM_MODIF");
+  }
 }
 
 //=============================================================================
 /*!
  * \brief Update objects depending on changed geom groups
  *
- * NPAL16168: geometrical group edition from a submesh don't modifiy mesh computation
+ * NPAL16168: geometrical group edition from a submesh don't modify mesh computation
  * issue 0020210: Update of a smesh group after modification of the associated geom group
  */
 //=============================================================================
 
 void SMESH_Mesh_i::CheckGeomGroupModif()
 {
-  if ( !_impl->HasShapeToMesh() ) return;
+  // remove sub-meshes referring a removed sub-shapes (if main shape still exists)
+  SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
+  GEOM::GEOM_Object_var  mainGO = GetShapeToMesh();
+  SALOMEDS::SObject_wrap meshSO = _gen_i->ObjectToSObject( SMESH::SMESH_Mesh_var( _this() ));
+  if ( !mainGO->_is_nil() && !meshSO->_is_nil() )
+  {
+    SALOMEDS::SObject_wrap rootSO, geomRefSO, geomSO;
+    for ( CORBA::Long tag = SMESH::Tag_FirstSubMesh; tag <= SMESH::Tag_LastSubMesh; ++tag )
+      if ( meshSO->FindSubObject( tag, rootSO.inout() ))
+      {
+        int nbValid = 0, nbRemoved = 0;
+        SALOMEDS::ChildIterator_wrap chItr = _gen_i->getStudyServant()->NewChildIterator( rootSO );
+        for ( ; chItr->More(); chItr->Next() )
+        {
+          SALOMEDS::SObject_wrap smSO = chItr->Value(); // sub-mesh SO
+          if ( !smSO->_is_nil() &&
+               smSO->FindSubObject( SMESH::Tag_RefOnShape, geomRefSO.inout() ) &&
+               geomRefSO->ReferencedObject( geomSO.inout() )) // find geometry by reference
+          {
+            CORBA::Object_var  geomObj = _gen_i->SObjectToObject( geomSO );
+            GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( geomObj );
+            if ( !geom->_non_existent() )
+            {
+              ++nbValid;
+              continue; // keep the sub-mesh
+            }
+          }
+          CORBA::Object_var     smObj = _gen_i->SObjectToObject( smSO );
+          SMESH::SMESH_subMesh_var sm = SMESH::SMESH_subMesh::_narrow( smObj );
+          if ( !sm->_is_nil() && !sm->_non_existent() )
+          {
+            GEOM::GEOM_Object_var smGeom = sm->GetSubShape();
+            if ( smGeom->_is_nil() )
+            {
+              RemoveSubMesh( sm );
+              ++nbRemoved;
+            }
+          }
+          else
+          {
+            if ( _preMeshInfo )
+              _preMeshInfo->ForgetAllData(); // unknown hypothesis modified
+            builder->RemoveObjectWithChildren( smSO ); // sub-shape removed before loading SMESH
+            ++nbRemoved;
+          }
+        }
+        if ( /*nbRemoved > 0 &&*/ nbValid == 0 )
+          builder->RemoveObjectWithChildren( rootSO );
+      }
+  }
 
-  SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
-  if ( study->_is_nil() ) return;
+  // check for removed sub-shapes and convert geom dependent groups into standalone ones
+  std::map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
+  while ( i_gr != _mapGroups.end())
+  {
+    SMESH::SMESH_GroupBase_ptr group = i_gr->second;
+    ++i_gr;
+    SALOMEDS::SObject_wrap        groupSO = _gen_i->ObjectToSObject( group ), refSO;
+    SMESH::SMESH_GroupOnGeom_var   onGeom = SMESH::SMESH_GroupOnGeom::_narrow  ( group );
+    SMESH::SMESH_GroupOnFilter_var onFilt = SMESH::SMESH_GroupOnFilter::_narrow( group );
+    bool isValidGeom = false;
+    if ( !onGeom->_is_nil() )
+    {
+      isValidGeom = ( ! GEOM::GEOM_Object_var( onGeom->GetShape() )->_is_nil() );
+    }
+    else if ( !onFilt->_is_nil() )
+    {
+      isValidGeom = isValidGeomFilter( onFilt->GetFilter() );
+    }
+    else // standalone
+    {
+      isValidGeom = ( !groupSO->_is_nil() &&
+                      !groupSO->FindSubObject( SMESH::Tag_RefOnShape, refSO.inout() ));
+    }
+    if ( !isValidGeom )
+    {
+      if ( !IsLoaded() || group->IsEmpty() )
+      {
+        RemoveGroup( group );
+      }
+      else if ( !onGeom->_is_nil() || !onFilt->_is_nil() )
+      {
+        SMESH::SMESH_Group_var ( ConvertToStandalone( group ));
+      }
+      else // is it possible?
+      {
+        builder->RemoveObjectWithChildren( refSO );
+      }
+    }
+  }
+
+
+  if ( !_impl->HasShapeToMesh() ) return;
 
   CORBA::Long nbEntities = NbNodes() + NbElements();
 
@@ -2135,7 +2635,7 @@ void SMESH_Mesh_i::CheckGeomGroupModif()
     bool processedGroup    = !it_new.second;
     TopoDS_Shape& newShape = it_new.first->second;
     if ( !processedGroup )
-      newShape = newGroupShape( *data );
+      newShape = newGroupShape( *data, ONLY_IF_CHANGED );
     if ( newShape.IsNull() )
       continue; // no changes
 
@@ -2263,7 +2763,7 @@ void SMESH_Mesh_i::CheckGeomGroupModif()
           groupData.push_back
             ( make_pair( TIndexedShape( gog->GetID(),gog->GetShape()), gog->GetType()));
       }
-      // set new shape to mesh -> DS of sub-meshes and geom groups are deleted
+      // set new shape to mesh -> DS of sub-meshes and geom groups is deleted
       _impl->Clear();
       _impl->ShapeToMesh( TopoDS_Shape() ); // IPAL52730
       _impl->ShapeToMesh( newShape );
@@ -2305,13 +2805,13 @@ void SMESH_Mesh_i::CheckGeomGroupModif()
         if ( _mapGroups.find( oldID ) == _mapGroups.end() )
           continue;
         // get group name
-        SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( study,_mapGroups[oldID] );
+        SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( _mapGroups[oldID] );
         CORBA::String_var      name    = groupSO->GetName();
         // update
-        SMESH_GroupBase_i*  group_i    = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID] );
-        int newID;
-        if ( group_i && _impl->AddGroup( geomType->second, name.in(), newID, geom._shape ))
-          group_i->changeLocalId( newID );
+        if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID]))
+          if ( SMESH_Group* group = _impl->AddGroup( geomType->second, name.in(),
+                                                     /*id=*/-1, geom._shape ))
+            group_i->changeLocalId( group->GetID() );
       }
 
       break; // everything has been updated
@@ -2326,15 +2826,15 @@ void SMESH_Mesh_i::CheckGeomGroupModif()
   if ( newNbEntities != nbEntities )
   {
     // Add all SObjects with icons to soToUpdateIcons
-    soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, _this() )); // mesh
+    soToUpdateIcons.push_back( _gen_i->ObjectToSObject( _this() )); // mesh
 
     for (map<int, SMESH::SMESH_subMesh_ptr>::iterator i_sm = _mapSubMeshIor.begin();
          i_sm != _mapSubMeshIor.end(); ++i_sm ) // submeshes
-      soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, i_sm->second ));
+      soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_sm->second ));
 
     for ( map<int, SMESH::SMESH_GroupBase_ptr>::iterator i_gr = _mapGroups.begin();
           i_gr != _mapGroups.end(); ++i_gr ) // groups
-      soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, i_gr->second ));
+      soToUpdateIcons.push_back( _gen_i->ObjectToSObject( i_gr->second ));
   }
 
   list< SALOMEDS::SObject_wrap >::iterator so = soToUpdateIcons.begin();
@@ -2380,18 +2880,20 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase
 
   SALOMEDS::StudyBuilder_var builder;
   SALOMEDS::SObject_wrap     aGroupSO;
-  SALOMEDS::Study_var        aStudy = _gen_i->GetCurrentStudy();
+  SALOMEDS::Study_var        aStudy = SMESH_Gen_i::getStudyServant();
   if ( !aStudy->_is_nil() ) {
     builder  = aStudy->NewBuilder();
-    aGroupSO = _gen_i->ObjectToSObject( aStudy, theGroup );
+    aGroupSO = _gen_i->ObjectToSObject( theGroup );
     if ( !aGroupSO->_is_nil() )
     {
       // remove reference to geometry
       SALOMEDS::ChildIterator_wrap chItr = aStudy->NewChildIterator(aGroupSO);
       for ( ; chItr->More(); chItr->Next() )
+      {
         // Remove group's child SObject
-        builder->RemoveObject( chItr->Value() );
-
+        SALOMEDS::SObject_wrap so = chItr->Value();
+        builder->RemoveObject( so );
+      }
       // Update Python script
       TPythonDump() << aGroupSO << " = " << SMESH::SMESH_Mesh_var(_this())
                     << ".ConvertToStandalone( " << aGroupSO << " )";
@@ -2399,9 +2901,9 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase
       // change icon of Group on Filter
       if ( isOnFilter )
       {
-        SMESH::array_of_ElementType_var elemTypes = aGroupImpl->GetTypes();
-        const int isEmpty = ( elemTypes->length() == 0 );
-        if ( !isEmpty )
+        // SMESH::array_of_ElementType_var elemTypes = aGroupImpl->GetTypes();
+        // const int isEmpty = ( elemTypes->length() == 0 );
+        // if ( !isEmpty )
         {
           SALOMEDS::GenericAttribute_wrap anAttr =
             builder->FindOrCreateAttribute( aGroupSO, "AttributePixMap" );
@@ -2440,9 +2942,25 @@ SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::createSubMesh( GEOM::GEOM_Object_ptr theS
   if(MYDEBUG) MESSAGE( "createSubMesh" );
   TopoDS_Shape  myLocSubShape = _gen_i->GeomObjectToShape(theSubShapeObject);
   ::SMESH_subMesh * mySubMesh = _impl->GetSubMesh(myLocSubShape);
-  const int         subMeshId = mySubMesh->GetId();
+  int               subMeshId = 0;
+
+  SMESH_subMesh_i * subMeshServant;
+  if ( mySubMesh )
+  {
+    subMeshId = mySubMesh->GetId();
+    subMeshServant = new SMESH_subMesh_i(myPOA, _gen_i, this, subMeshId);
+  }
+  else // "invalid sub-mesh"
+  {
+    // The invalid sub-mesh is created for the case where a valid sub-shape not found
+    // by SMESH_Gen_i::CopyMeshWithGeom(). The invalid sub-mesh has GetId() < 0.
+    if ( _mapSubMesh.empty() )
+      subMeshId = -1;
+    else
+      subMeshId = _mapSubMesh.begin()->first - 1;
+    subMeshServant = new SMESH_Invalid_subMesh_i(myPOA, _gen_i, this, subMeshId, theSubShapeObject);
+  }
 
-  SMESH_subMesh_i * subMeshServant = new SMESH_subMesh_i(myPOA, _gen_i, this, subMeshId);
   SMESH::SMESH_subMesh_var subMesh = subMeshServant->_this();
 
   _mapSubMesh   [subMeshId] = mySubMesh;
@@ -2457,7 +2975,8 @@ SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::createSubMesh( GEOM::GEOM_Object_ptr theS
   else        { nextId = 0; } // avoid "unused variable" warning
 
   // to track changes of GEOM groups
-  addGeomGroupData( theSubShapeObject, subMesh );
+  if ( subMeshId > 0 )
+    addGeomGroupData( theSubShapeObject, subMesh );
 
   return subMesh._retn();
 }
@@ -2493,13 +3012,17 @@ bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
 
   if ( theSubShapeObject->_is_nil() )  // not published shape (IPAL13617)
   {
-    if ( _mapSubMesh.find( subMeshId ) != _mapSubMesh.end())
+    SMESH_subMesh* sm;
+    if (( _mapSubMesh.count( subMeshId )) &&
+        ( sm = _impl->GetSubMeshContaining( subMeshId )))
     {
-      TopoDS_Shape S = _mapSubMesh[ subMeshId ]->GetSubShape();
+      TopoDS_Shape S = sm->GetSubShape();
       if ( !S.IsNull() )
       {
         list<const SMESHDS_Hypothesis*> hyps = _impl->GetHypothesisList( S );
         isHypChanged = !hyps.empty();
+        if ( isHypChanged && _preMeshInfo )
+          _preMeshInfo->ForgetOrLoad();
         list<const SMESHDS_Hypothesis*>::const_iterator hyp = hyps.begin();
         for ( ; hyp != hyps.end(); ++hyp )
           _impl->RemoveHypothesis(S, (*hyp)->GetID());
@@ -2546,11 +3069,12 @@ bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
 
 SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType        theElemType,
                                                       const char*               theName,
+                                                      const int                 theID,
                                                       const TopoDS_Shape&       theShape,
                                                       const SMESH_PredicatePtr& thePredicate )
 {
   std::string newName;
-  if ( !theName || strlen( theName ) == 0 )
+  if ( !theName || !theName[0] )
   {
     std::set< std::string > presentNames;
     std::map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i_gr = _mapGroups.begin();
@@ -2564,10 +3088,11 @@ SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType
     } while ( !presentNames.insert( newName ).second );
     theName = newName.c_str();
   }
-  int anId;
   SMESH::SMESH_GroupBase_var aGroup;
-  if ( _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName, anId, theShape, thePredicate ))
+  if ( SMESH_Group* g = _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName,
+                                         theID, theShape, thePredicate ))
   {
+    int anId = g->GetID();
     SMESH_GroupBase_i* aGroupImpl;
     if ( !theShape.IsNull() )
       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
@@ -2583,7 +3108,7 @@ SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType
     // register CORBA object for persistence
     int nextId = _gen_i->RegisterObject( aGroup );
     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
-    else        { nextId = 0; } // avoid "unused variable" warning in release mode
+    else        { nextId = ( nextId > 0 ); } // avoid "unused variable" warning in release mode
 
     // to track changes of GEOM groups
     if ( !theShape.IsNull() ) {
@@ -2704,17 +3229,6 @@ CORBA::Long SMESH_Mesh_i::GetId()throw(SALOME::SALOME_Exception)
   return _id;
 }
 
-//=============================================================================
-/*!
- *
- */
-//=============================================================================
-
-CORBA::Long SMESH_Mesh_i::GetStudyId()throw(SALOME::SALOME_Exception)
-{
-  return _studyId;
-}
-
 //=============================================================================
 namespace
 {
@@ -2726,21 +3240,56 @@ namespace
     SMESH_Mesh_i* _mesh;
     TCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {}
     virtual void RemoveGroup (const int theGroupID) { _mesh->removeGroup( theGroupID ); }
-    virtual void HypothesisModified ()              { _mesh->onHypothesisModified(); }
+    virtual void HypothesisModified( int hypID,
+                                     bool updIcons) { _mesh->onHypothesisModified( hypID,
+                                                                                   updIcons ); }
     virtual void Load ()                            { _mesh->Load(); }
+    virtual bool IsLoaded()                         { return _mesh->IsLoaded(); }
   };
 }
 
 //================================================================================
 /*!
- * \brief callback from _impl to forget not loaded mesh data (issue 0021208)
+ * \brief callback from _impl to
+ *     1) forget not loaded mesh data (issue 0021208)
+ *     2) mark hypothesis as valid
  */
 //================================================================================
 
-void SMESH_Mesh_i::onHypothesisModified()
+void SMESH_Mesh_i::onHypothesisModified(int theHypID, bool theUpdateIcons)
 {
   if ( _preMeshInfo )
     _preMeshInfo->ForgetOrLoad();
+
+  if ( theUpdateIcons )
+  {
+    SMESH::SMESH_Mesh_var mesh = _this();
+    _gen_i->UpdateIcons( mesh );
+  }
+
+  if ( _nbInvalidHypos != 0 )
+  {
+    // mark a hypothesis as valid after edition
+    int nbInvalid = 0;
+    SALOMEDS::SComponent_wrap smeshComp = _gen_i->PublishComponent();
+    SALOMEDS::SObject_wrap hypRoot;
+    if ( !smeshComp->_is_nil() &&
+         smeshComp->FindSubObject( _gen_i->GetHypothesisRootTag(), hypRoot.inout() ))
+    {
+      SALOMEDS::ChildIterator_wrap anIter = _gen_i->getStudyServant()->NewChildIterator( hypRoot );
+      for ( ; anIter->More(); anIter->Next() )
+      {
+        SALOMEDS::SObject_wrap    hypSO = anIter->Value();
+        CORBA::Object_var           obj = _gen_i->SObjectToObject( hypSO );
+        SMESH::SMESH_Hypothesis_var hyp = SMESH::SMESH_Hypothesis::_narrow( obj );
+        if ( !hyp->_is_nil() && hyp->GetId() == theHypID )
+          _gen_i->HighLightInvalid( hyp, false );
+        else
+          nbInvalid += _gen_i->IsInvalid( hypSO );
+      }
+    }
+    _nbInvalidHypos = nbInvalid;
+  }
 }
 
 //=============================================================================
@@ -2926,9 +3475,9 @@ CORBA::Boolean SMESH_Mesh_i::HasDuplicatedGroupNamesMED()
 
 void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
 {
-  SMESH_File aFile( file );
+  SMESH_File aFile( file, false );
   SMESH_Comment msg;
-  if (aFile.exists()) {
+  if ( aFile.exists() ) {
     // existing filesystem node
     if ( !aFile.isDirectory() ) {
       if ( aFile.openForWriting() ) {
@@ -2947,7 +3496,7 @@ void SMESH_Mesh_i::PrepareForWriting (const char* file, bool overwrite)
     if ( !aFile.openForWriting() ) {
       msg << "You cannot create the file "
           << aFile.getName()
-          << ". Check the directory existance and access rights";
+          << ". Check the directory existence and access rights";
     }
     aFile.remove();
   }
@@ -2974,9 +3523,9 @@ string SMESH_Mesh_i::prepareMeshNameAndGroups(const char*    file,
   // Perform Export
   PrepareForWriting(file, overwrite);
   string aMeshName = "Mesh";
-  SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy();
+  SALOMEDS::Study_var aStudy = SMESH_Gen_i::getStudyServant();
   if ( !aStudy->_is_nil() ) {
-    SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject( aStudy, _this() );
+    SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject(  _this() );
     if ( !aMeshSO->_is_nil() ) {
       CORBA::String_var name = aMeshSO->GetName();
       aMeshName = name;
@@ -3009,59 +3558,36 @@ string SMESH_Mesh_i::prepareMeshNameAndGroups(const char*    file,
 
 //================================================================================
 /*!
- * \brief Export to med file
+ * \brief Export to MED file
  */
 //================================================================================
 
-void SMESH_Mesh_i::ExportToMEDX (const char*        file,
-                                 CORBA::Boolean     auto_groups,
-                                 SMESH::MED_VERSION theVersion,
-                                 CORBA::Boolean     overwrite,
-                                 CORBA::Boolean     autoDimension)
+void SMESH_Mesh_i::ExportMED(const char*        file,
+                             CORBA::Boolean     auto_groups,
+                             CORBA::Long        version,
+                             CORBA::Boolean     overwrite,
+                             CORBA::Boolean     autoDimension)
   throw(SALOME::SALOME_Exception)
 {
+  //MESSAGE("MED minor version: "<< minor);
   SMESH_TRY;
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
 
   string aMeshName = prepareMeshNameAndGroups(file, overwrite);
-  _impl->ExportMED( file, aMeshName.c_str(), auto_groups, theVersion, 0, autoDimension );
+  _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version, 0, autoDimension );
 
-  TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportToMEDX( r'"
-                << file << "', " << auto_groups << ", "
-                << theVersion << ", " << overwrite << ", "
-                << autoDimension << " )";
+  TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportMED( r'"
+                << file << "', "
+                << "auto_groups=" <<auto_groups << ", "
+                << "minor=" << version <<  ", "
+                << "overwrite=" << overwrite << ", "
+                << "meshPart=None, "
+                << "autoDimension=" << autoDimension << " )";
 
   SMESH_CATCH( SMESH::throwCorbaException );
 }
 
-//================================================================================
-/*!
- * \brief Export a mesh to a med file
- */
-//================================================================================
-
-void SMESH_Mesh_i::ExportToMED (const char*        file,
-                                CORBA::Boolean     auto_groups,
-                                SMESH::MED_VERSION theVersion)
-  throw(SALOME::SALOME_Exception)
-{
-  ExportToMEDX(file,auto_groups,theVersion,true);
-}
-
-//================================================================================
-/*!
- * \brief Export a mesh to a med file
- */
-//================================================================================
-
-void SMESH_Mesh_i::ExportMED (const char* file,
-                              CORBA::Boolean auto_groups)
-  throw(SALOME::SALOME_Exception)
-{
-  ExportToMEDX(file,auto_groups,SMESH::MED_V2_2,true);
-}
-
 //================================================================================
 /*!
  * \brief Export a mesh to a SAUV file
@@ -3148,9 +3674,14 @@ void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
   TPythonDump() << SMESH::SMESH_Mesh_var(_this())
                 << ".ExportSTL( r'" << file << "', " << isascii << " )";
 
+  CORBA::String_var name;
+  SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( _this() );
+  if ( !so->_is_nil() )
+    name = so->GetName();
+
   // Perform Export
-  PrepareForWriting(file);
-  _impl->ExportSTL(file, isascii);
+  PrepareForWriting( file );
+  _impl->ExportSTL( file, isascii, name.in() );
 }
 
 //================================================================================
@@ -3162,13 +3693,15 @@ void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii)
 void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
                                    const char*               file,
                                    CORBA::Boolean            auto_groups,
-                                   SMESH::MED_VERSION        version,
+                                   CORBA::Long               version,
                                    CORBA::Boolean            overwrite,
                                    CORBA::Boolean            autoDimension,
                                    const GEOM::ListOfFields& fields,
-                                   const char*               geomAssocFields)
+                                   const char*               geomAssocFields,
+                                   CORBA::Double             ZTolerance)
   throw (SALOME::SALOME_Exception)
 {
+  MESSAGE("MED version: "<< version);
   SMESH_TRY;
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
@@ -3215,8 +3748,9 @@ void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
        SMESH::DownCast< SMESH_Mesh_i* >( meshPart ))
   {
     aMeshName = prepareMeshNameAndGroups(file, overwrite);
-    _impl->ExportMED( file, aMeshName.c_str(), auto_groups,
-                      version, 0, autoDimension, /*addODOnVertices=*/have0dField);
+    _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
+                      0, autoDimension, /*addODOnVertices=*/have0dField,
+                      ZTolerance);
     meshDS = _impl->GetMeshDS();
   }
   else
@@ -3226,17 +3760,15 @@ void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
 
     PrepareForWriting(file, overwrite);
 
-    SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy();
-    if ( !aStudy->_is_nil() ) {
-      SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( aStudy, meshPart );
-      if ( !SO->_is_nil() ) {
-        CORBA::String_var name = SO->GetName();
-        aMeshName = name;
-      }
+    SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( meshPart );
+    if ( !SO->_is_nil() ) {
+      CORBA::String_var name = SO->GetName();
+      aMeshName = name;
     }
+
     SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
-    _impl->ExportMED( file, aMeshName.c_str(), auto_groups,
-                      version, partDS, autoDimension, /*addODOnVertices=*/have0dField);
+    _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
+                      partDS, autoDimension, /*addODOnVertices=*/have0dField, ZTolerance);
     meshDS = tmpDSDeleter._obj = partDS;
   }
 
@@ -3261,10 +3793,16 @@ void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
     goList[i] = gbo;
   }
   TPythonDump() << _this() << ".ExportPartToMED( "
-                << meshPart << ", r'" << file << "', "
-                << auto_groups << ", " << version << ", " << overwrite << ", "
-                << autoDimension << ", " << goList
-                << ", '" << ( geomAssocFields ? geomAssocFields : "" ) << "'" << " )";
+                << meshPart << ", r'"
+                << file << "', "
+                << auto_groups << ", "
+                << version << ", "
+                << overwrite << ", "
+                << autoDimension << ", "
+                << goList << ", '"
+                << ( geomAssocFields ? geomAssocFields : "" ) << "',"
+                << TVar( ZTolerance )
+                << " )";
 
   SMESH_CATCH( SMESH::throwCorbaException );
 }
@@ -3286,9 +3824,9 @@ void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
       ( !geomAssocFields || !geomAssocFields[0] ))
     return;
 
-  std::vector< double > dblVals( meshDS->MaxShapeIndex()+1 );
-  std::vector< int >    intVals( meshDS->MaxShapeIndex()+1 );
-  std::vector< int >    subIdsByDim[ 4 ];
+  std::vector< std::vector< double > > dblVals;
+  std::vector< std::vector< int > >    intVals;
+  std::vector< int >                   subIdsByDim[ 4 ];
   const double noneDblValue = 0.;
   const double noneIntValue = 0;
 
@@ -3328,6 +3866,9 @@ void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
     for ( size_t iC = 0; iC < comps->length(); ++iC )
       fieldWriter.SetCompName( iC, comps[ iC ].in() );
 
+    dblVals.resize( comps->length() );
+    intVals.resize( comps->length() );
+
     // find sub-shape IDs
 
     std::vector< int >& subIds = subIdsByDim[ dim ];
@@ -3353,6 +3894,17 @@ void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
       fieldWriter.SetDtIt( int( stamp ), int( id ));
 
       // fill dblVals or intVals
+      for ( size_t iC = 0; iC < comps->length(); ++iC )
+        if ( dataType == GEOM::FDT_Double )
+        {
+          dblVals[ iC ].clear();
+          dblVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
+        }
+        else
+        {
+          intVals[ iC ].clear();
+          intVals[ iC ].resize( meshDS->MaxShapeIndex()+1, 0 );
+        }
       switch ( dataType )
       {
       case GEOM::FDT_Double:
@@ -3360,10 +3912,11 @@ void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
         GEOM::GEOM_DoubleFieldStep_var dblStep = GEOM::GEOM_DoubleFieldStep::_narrow( step );
         if ( dblStep->_is_nil() ) continue;
         GEOM::ListOfDouble_var vv = dblStep->GetValues();
-        if ( vv->length() != subIds.size() )
+        if ( vv->length() != subIds.size() * comps->length() )
           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
-        for ( size_t i = 0; i < vv->length(); ++i )
-          dblVals[ subIds[ i ]] = vv[ i ];
+        for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
+          for ( size_t iC = 0; iC < comps->length(); ++iC )
+            dblVals[ iC ][ subIds[ iS ]] = vv[ iV++ ];
         break;
       }
       case GEOM::FDT_Int:
@@ -3371,10 +3924,11 @@ void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
         GEOM::GEOM_IntFieldStep_var intStep = GEOM::GEOM_IntFieldStep::_narrow( step );
         if ( intStep->_is_nil() ) continue;
         GEOM::ListOfLong_var vv = intStep->GetValues();
-        if ( vv->length() != subIds.size() )
+        if ( vv->length() != subIds.size() * comps->length() )
           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
-        for ( size_t i = 0; i < vv->length(); ++i )
-          intVals[ subIds[ i ]] = (int) vv[ i ];
+        for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
+          for ( size_t iC = 0; iC < comps->length(); ++iC )
+            intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
         break;
       }
       case GEOM::FDT_Bool:
@@ -3382,10 +3936,11 @@ void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
         GEOM::GEOM_BoolFieldStep_var boolStep = GEOM::GEOM_BoolFieldStep::_narrow( step );
         if ( boolStep->_is_nil() ) continue;
         GEOM::short_array_var vv = boolStep->GetValues();
-        if ( vv->length() != subIds.size() )
+        if ( vv->length() != subIds.size() * comps->length() )
           THROW_SALOME_CORBA_EXCEPTION( METH "BUG: wrong nb subIds", SALOME::INTERNAL_ERROR );
-        for ( size_t i = 0; i < vv->length(); ++i )
-          intVals[ subIds[ i ]] = (int) vv[ i ];
+        for ( size_t iS = 0, iV = 0; iS < subIds.size(); ++iS )
+          for ( size_t iC = 0; iC < comps->length(); ++iC )
+            intVals[ iC ][ subIds[ iS ]] = (int) vv[ iV++ ];
         break;
       }
       default: continue;
@@ -3398,20 +3953,24 @@ void SMESH_Mesh_i::exportMEDFields( DriverMED_W_Field&        fieldWriter,
         {
           const SMDS_MeshElement* e = elemIt->next();
           const int shapeID = e->getshapeId();
-          if ( shapeID < 1 || shapeID >= (int) dblVals.size() )
-            fieldWriter.AddValue( noneDblValue );
+          if ( shapeID < 1 || shapeID >= (int) dblVals[0].size() )
+            for ( size_t iC = 0; iC < comps->length(); ++iC )
+              fieldWriter.AddValue( noneDblValue );
           else
-            fieldWriter.AddValue( dblVals[ shapeID ]);
+            for ( size_t iC = 0; iC < comps->length(); ++iC )
+              fieldWriter.AddValue( dblVals[ iC ][ shapeID ]);
         }
       else
         while ( elemIt->more() )
         {
           const SMDS_MeshElement* e = elemIt->next();
           const int shapeID = e->getshapeId();
-          if ( shapeID < 1 || shapeID >= (int) intVals.size() )
-            fieldWriter.AddValue( (double) noneIntValue );
+          if ( shapeID < 1 || shapeID >= (int) intVals[0].size() )
+            for ( size_t iC = 0; iC < comps->length(); ++iC )
+              fieldWriter.AddValue( (double) noneIntValue );
           else
-            fieldWriter.AddValue( (double) intVals[ shapeID ]);
+            for ( size_t iC = 0; iC < comps->length(); ++iC )
+              fieldWriter.AddValue( (double) intVals[ iC ][ shapeID ]);
         }
 
       // write a step
@@ -3578,8 +4137,13 @@ void SMESH_Mesh_i::ExportPartToSTL(::SMESH::SMESH_IDSource_ptr meshPart,
 
   PrepareForWriting(file);
 
+  CORBA::String_var name;
+  SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
+  if ( !so->_is_nil() )
+    name = so->GetName();
+
   SMESH_MeshPartDS partDS( meshPart );
-  _impl->ExportSTL(file, isascii, &partDS);
+  _impl->ExportSTL( file, isascii, name.in(), &partDS );
 
   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportPartToSTL( "
                 << meshPart<< ", r'" << file << "', " << isascii << ")";
@@ -3593,7 +4157,8 @@ void SMESH_Mesh_i::ExportPartToSTL(::SMESH::SMESH_IDSource_ptr meshPart,
 
 void SMESH_Mesh_i::ExportCGNS(::SMESH::SMESH_IDSource_ptr meshPart,
                               const char*                 file,
-                              CORBA::Boolean              overwrite)
+                              CORBA::Boolean              overwrite,
+                              CORBA::Boolean              groupElemsByType)
   throw (SALOME::SALOME_Exception)
 {
 #ifdef WITH_CGNS
@@ -3604,15 +4169,18 @@ void SMESH_Mesh_i::ExportCGNS(::SMESH::SMESH_IDSource_ptr meshPart,
   PrepareForWriting(file,overwrite);
 
   std::string meshName("");
-  SALOMEDS::Study_var study = _gen_i->GetCurrentStudy();
-  SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( study, meshPart );
+  SALOMEDS::SObject_wrap so = _gen_i->ObjectToSObject( meshPart );
   if ( !so->_is_nil() )
   {
     CORBA::String_var name = so->GetName();
     meshName = name.in();
   }
+  SMESH_TRY;
+
   SMESH_MeshPartDS partDS( meshPart );
-  _impl->ExportCGNS(file, &partDS, meshName.c_str() );
+  _impl->ExportCGNS(file, &partDS, meshName.c_str(), groupElemsByType );
+
+  SMESH_CATCH( SMESH::throwCorbaException );
 
   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportCGNS( "
                 << meshPart<< ", r'" << file << "', " << overwrite << ")";
@@ -4056,14 +4624,14 @@ SMESH::long_array* SMESH_Mesh_i::GetNodesId()
     _preMeshInfo->FullLoadFromFile();
 
   SMESH::long_array_var aResult = new SMESH::long_array();
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
 
-  if ( aSMESHDS_Mesh == NULL )
+  if ( aMeshDS == NULL )
     return aResult._retn();
 
   long nbNodes = NbNodes();
   aResult->length( nbNodes );
-  SMDS_NodeIteratorPtr anIt = aSMESHDS_Mesh->nodesIterator(/*idInceasingOrder=*/true);
+  SMDS_NodeIteratorPtr anIt = aMeshDS->nodesIterator();
   for ( int i = 0, n = nbNodes; i < n && anIt->more(); i++ )
     aResult[i] = anIt->next()->GetID();
 
@@ -4079,7 +4647,7 @@ SMESH::long_array* SMESH_Mesh_i::GetNodesId()
 SMESH::ElementType SMESH_Mesh_i::GetElementType( const CORBA::Long id, const bool iselem )
   throw (SALOME::SALOME_Exception)
 {
-  SMESH::ElementType type;
+  SMESH::ElementType type = SMESH::ALL;
   SMESH_TRY;
 
   if ( _preMeshInfo )
@@ -4217,7 +4785,7 @@ SMESH::long_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID,
 
   return aResult._retn();
 }
-  
+
 //=============================================================================
 /*!
  * Returns type of elements for given submesh
@@ -4227,7 +4795,7 @@ SMESH::long_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID,
 SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID)
   throw (SALOME::SALOME_Exception)
 {
-  SMESH::ElementType type;
+  SMESH::ElementType type = SMESH::ALL;
 
   SMESH_TRY;
   if ( _preMeshInfo )
@@ -4249,9 +4817,9 @@ SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID
 
   SMESH_CATCH( SMESH::throwCorbaException );
 
-  return type; 
+  return type;
 }
-  
+
 
 //=============================================================================
 /*!
@@ -4265,8 +4833,7 @@ CORBA::LongLong SMESH_Mesh_i::GetMeshPtr()
     _preMeshInfo->FullLoadFromFile();
 
   CORBA::LongLong pointeur = CORBA::LongLong(_impl);
-  if ( MYDEBUG )
-    MESSAGE("CORBA::LongLong SMESH_Mesh_i::GetMeshPtr() "<<pointeur);
+  if ( MYDEBUG ) MESSAGE("CORBA::LongLong SMESH_Mesh_i::GetMeshPtr() "<<pointeur);
   return pointeur;
 }
 
@@ -4284,12 +4851,12 @@ SMESH::double_array* SMESH_Mesh_i::GetNodeXYZ(const CORBA::Long id)
     _preMeshInfo->FullLoadFromFile();
 
   SMESH::double_array_var aResult = new SMESH::double_array();
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL )
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL )
     return aResult._retn();
 
   // find node
-  const SMDS_MeshNode* aNode = aSMESHDS_Mesh->FindNode(id);
+  const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
   if(!aNode)
     return aResult._retn();
 
@@ -4309,24 +4876,26 @@ SMESH::double_array* SMESH_Mesh_i::GetNodeXYZ(const CORBA::Long id)
  */
 //=============================================================================
 
-SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long id)
+SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long  id,
+                                                        SMESH::ElementType elemType)
 {
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
 
   SMESH::long_array_var aResult = new SMESH::long_array();
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL )
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL )
     return aResult._retn();
 
   // find node
-  const SMDS_MeshNode* aNode = aSMESHDS_Mesh->FindNode(id);
-  if(!aNode)
+  const SMDS_MeshNode* aNode = aMeshDS->FindNode( id );
+  if ( !aNode )
     return aResult._retn();
 
   // find inverse elements
-  SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator();
-  aResult->length( aNode->NbInverseElements() );  
+  SMDSAbs_ElementType type = SMDSAbs_ElementType( elemType );
+  SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator( type );
+  aResult->length( aNode->NbInverseElements( type ));
   for( int i = 0; eIt->more(); ++i )
   {
     const SMDS_MeshElement* elem = eIt->next();
@@ -4362,17 +4931,16 @@ SMESH::NodePosition* SMESH_Mesh_i::GetNodePosition(CORBA::Long NodeID)
       case SMDS_TOP_EDGE:
         aNodePosition->shapeType = GEOM::EDGE;
         aNodePosition->params.length(1);
-        aNodePosition->params[0] =
-          static_cast<SMDS_EdgePosition*>( pos )->GetUParameter();
+        aNodePosition->params[0] = SMDS_EdgePositionPtr( pos )->GetUParameter();
         break;
-      case SMDS_TOP_FACE:
+      case SMDS_TOP_FACE: {
+        SMDS_FacePositionPtr fPos = pos;
         aNodePosition->shapeType = GEOM::FACE;
         aNodePosition->params.length(2);
-        aNodePosition->params[0] =
-          static_cast<SMDS_FacePosition*>( pos )->GetUParameter();
-        aNodePosition->params[1] =
-          static_cast<SMDS_FacePosition*>( pos )->GetVParameter();
+        aNodePosition->params[0] = fPos->GetUParameter();
+        aNodePosition->params[1] = fPos->GetVParameter();
         break;
+      }
       case SMDS_TOP_VERTEX:
         aNodePosition->shapeType = GEOM::VERTEX;
         break;
@@ -4447,12 +5015,12 @@ CORBA::Long SMESH_Mesh_i::GetShapeID(const CORBA::Long id)
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
 
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL )
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL )
     return -1;
 
   // try to find node
-  const SMDS_MeshNode* aNode = aSMESHDS_Mesh->FindNode(id);
+  const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
   if(aNode) {
     return aNode->getshapeId();
   }
@@ -4463,7 +5031,7 @@ CORBA::Long SMESH_Mesh_i::GetShapeID(const CORBA::Long id)
 
 //=============================================================================
 /*!
- * For given element returns ID of result shape after 
+ * For given element returns ID of result shape after
  * ::FindShape() from SMESH_MeshEditor
  * If there is not element for given ID - returns -1
  */
@@ -4474,12 +5042,12 @@ CORBA::Long SMESH_Mesh_i::GetShapeIDForElem(const CORBA::Long id)
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
 
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL )
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL )
     return -1;
 
   // try to find element
-  const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
+  const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
   if(!elem)
     return -1;
 
@@ -4504,10 +5072,10 @@ CORBA::Long SMESH_Mesh_i::GetElemNbNodes(const CORBA::Long id)
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
 
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL ) return -1;
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL ) return -1;
   // try to find element
-  const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
+  const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
   if(!elem) return -1;
   return elem->NbNodes();
 }
@@ -4526,9 +5094,9 @@ CORBA::Long SMESH_Mesh_i::GetElemNode(const CORBA::Long id, const CORBA::Long in
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
 
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL ) return -1;
-  const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL ) return -1;
+  const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
   if(!elem) return -1;
   if( index>=elem->NbNodes() || index<0 ) return -1;
   return elem->GetNode(index)->GetID();
@@ -4546,13 +5114,14 @@ SMESH::long_array* SMESH_Mesh_i::GetElemNodes(const CORBA::Long id)
     _preMeshInfo->FullLoadFromFile();
 
   SMESH::long_array_var aResult = new SMESH::long_array();
-  if ( SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS() )
+  if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
   {
-    if ( const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id) )
+    if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(id) )
     {
       aResult->length( elem->NbNodes() );
-      for ( int i = 0; i < elem->NbNodes(); ++i )
-        aResult[ i ] = elem->GetNode( i )->GetID();
+      for ( CORBA::ULong i = 0; i < aResult->length(); ++i )
+        if ( const SMDS_MeshNode* n = elem->GetNode( i ))
+          aResult[ i ] = n->GetID();
     }
   }
   return aResult._retn();
@@ -4570,13 +5139,13 @@ CORBA::Boolean SMESH_Mesh_i::IsMediumNode(const CORBA::Long ide, const CORBA::Lo
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
 
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL ) return false;
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL ) return false;
   // try to find node
-  const SMDS_MeshNode* aNode = aSMESHDS_Mesh->FindNode(idn);
+  const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
   if(!aNode) return false;
   // try to find element
-  const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(ide);
+  const SMDS_MeshElement* elem = aMeshDS->FindElement(ide);
   if(!elem) return false;
 
   return elem->IsMediumNode(aNode);
@@ -4596,11 +5165,11 @@ CORBA::Boolean SMESH_Mesh_i::IsMediumNodeOfAnyElem(const CORBA::Long idn,
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
 
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL ) return false;
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL ) return false;
 
   // try to find node
-  const SMDS_MeshNode* aNode = aSMESHDS_Mesh->FindNode(idn);
+  const SMDS_MeshNode* aNode = aMeshDS->FindNode(idn);
   if(!aNode) return false;
 
   SMESH_MesherHelper aHelper( *(_impl) );
@@ -4626,9 +5195,9 @@ CORBA::Long SMESH_Mesh_i::ElemNbEdges(const CORBA::Long id)
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
 
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL ) return -1;
-  const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL ) return -1;
+  const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
   if(!elem) return -1;
   return elem->NbEdges();
 }
@@ -4645,9 +5214,9 @@ CORBA::Long SMESH_Mesh_i::ElemNbFaces(const CORBA::Long id)
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
 
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL ) return -1;
-  const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL ) return -1;
+  const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
   if(!elem) return -1;
   return elem->NbFaces();
 }
@@ -4664,11 +5233,11 @@ SMESH::long_array* SMESH_Mesh_i::GetElemFaceNodes(CORBA::Long  elemId,
     _preMeshInfo->FullLoadFromFile();
 
   SMESH::long_array_var aResult = new SMESH::long_array();
-  if ( SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS() )
+  if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() )
   {
-    if ( const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(elemId) )
+    if ( const SMDS_MeshElement* elem = aMeshDS->FindElement(elemId) )
     {
-      SMDS_VolumeTool vtool( elem );
+      SMDS_VolumeTool vtool( elem, /*skipCentralNodes = */false );
       if ( faceIndex < vtool.NbFaces() )
       {
         aResult->length( vtool.NbFaceNodes( faceIndex ));
@@ -4682,7 +5251,7 @@ SMESH::long_array* SMESH_Mesh_i::GetElemFaceNodes(CORBA::Long  elemId,
 }
 
 //=======================================================================
-//function : GetElemFaceNodes
+//function : GetFaceNormal
 //purpose  : Returns three components of normal of given mesh face.
 //=======================================================================
 
@@ -4737,6 +5306,35 @@ CORBA::Long SMESH_Mesh_i::FindElementByNodes(const SMESH::long_array& nodes)
   return elemID;
 }
 
+//================================================================================
+/*!
+ * \brief Return elements including all given nodes.
+ */
+//================================================================================
+
+SMESH::long_array* SMESH_Mesh_i::GetElementsByNodes(const SMESH::long_array& nodes,
+                                                    SMESH::ElementType       elemType)
+{
+  if ( _preMeshInfo )
+    _preMeshInfo->FullLoadFromFile();
+
+  SMESH::long_array_var result = new SMESH::long_array();
+
+  if ( SMESHDS_Mesh* mesh = _impl->GetMeshDS() )
+  {
+    vector< const SMDS_MeshNode * > nn( nodes.length() );
+    for ( CORBA::ULong i = 0; i < nodes.length(); ++i )
+      nn[i] = mesh->FindNode( nodes[i] );
+
+    std::vector<const SMDS_MeshElement *> elems;
+    mesh->GetElementsByNodes( nn, elems, (SMDSAbs_ElementType) elemType );
+    result->length( elems.size() );
+    for ( size_t i = 0; i < elems.size(); ++i )
+      result[i] = elems[i]->GetID();
+  }
+  return result._retn();
+}
+
 //=============================================================================
 /*!
  * Returns true if given element is polygon
@@ -4748,9 +5346,9 @@ CORBA::Boolean SMESH_Mesh_i::IsPoly(const CORBA::Long id)
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
 
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL ) return false;
-  const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL ) return false;
+  const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
   if(!elem) return false;
   return elem->IsPoly();
 }
@@ -4767,9 +5365,9 @@ CORBA::Boolean SMESH_Mesh_i::IsQuadratic(const CORBA::Long id)
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
 
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL ) return false;
-  const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL ) return false;
+  const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
   if(!elem) return false;
   return elem->IsQuadratic();
 }
@@ -4786,7 +5384,7 @@ CORBA::Double SMESH_Mesh_i::GetBallDiameter(CORBA::Long id)
     _preMeshInfo->FullLoadFromFile();
 
   if ( const SMDS_BallElement* ball =
-       dynamic_cast<const SMDS_BallElement*>( _impl->GetMeshDS()->FindElement( id )))
+       SMDS_Mesh::DownCast<SMDS_BallElement>( _impl->GetMeshDS()->FindElement( id )))
     return ball->GetDiameter();
 
   return 0;
@@ -4804,11 +5402,11 @@ SMESH::double_array* SMESH_Mesh_i::BaryCenter(const CORBA::Long id)
     _preMeshInfo->FullLoadFromFile();
 
   SMESH::double_array_var aResult = new SMESH::double_array();
-  SMESHDS_Mesh* aSMESHDS_Mesh = _impl->GetMeshDS();
-  if ( aSMESHDS_Mesh == NULL )
+  SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS();
+  if ( aMeshDS == NULL )
     return aResult._retn();
 
-  const SMDS_MeshElement* elem = aSMESHDS_Mesh->FindElement(id);
+  const SMDS_MeshElement* elem = aMeshDS->FindElement(id);
   if(!elem)
     return aResult._retn();
 
@@ -4868,12 +5466,14 @@ SMESH_Mesh_i::MakeGroupsOfBadInputElements( int         theSubShapeID,
   {
     // compute error
     SMESH_ComputeErrorPtr error = sm->GetComputeError();
-    if ( error && !error->myBadElements.empty())
+    if ( error && error->HasBadElems() )
     {
       // sort bad elements by type
       vector< const SMDS_MeshElement* > elemsByType[ SMDSAbs_NbElementTypes ];
-      list<const SMDS_MeshElement*>::iterator elemIt  = error->myBadElements.begin();
-      list<const SMDS_MeshElement*>::iterator elemEnd = error->myBadElements.end();
+      const list<const SMDS_MeshElement*>& badElems =
+        static_cast<SMESH_BadInputElements*>( error.get() )->myBadElements;
+      list<const SMDS_MeshElement*>::const_iterator elemIt  = badElems.begin();
+      list<const SMDS_MeshElement*>::const_iterator elemEnd = badElems.end();
       for ( ; elemIt != elemEnd; ++elemIt )
       {
         const SMDS_MeshElement* elem = *elemIt;
@@ -4915,10 +5515,9 @@ SMESH_Mesh_i::MakeGroupsOfBadInputElements( int         theSubShapeID,
         groups[ ++iG ] = createGroup( SMESH::ElementType(i), theGroupName );
         if ( _gen_i->CanPublishInStudy( groups[ iG ] ))
         {
-          SALOMEDS::Study_var  study = _gen_i->GetCurrentStudy();
           SMESH::SMESH_Mesh_var mesh = _this();
           SALOMEDS::SObject_wrap aSO =
-            _gen_i->PublishGroup( study, mesh, groups[ iG ],
+            _gen_i->PublishGroup( mesh, groups[ iG ],
                                  GEOM::GEOM_Object::_nil(), theGroupName);
         }
         SMESH_GroupBase_i* grp_i = SMESH::DownCast< SMESH_GroupBase_i* >( groups[ iG ]);
@@ -4942,7 +5541,6 @@ SMESH_Mesh_i::MakeGroupsOfBadInputElements( int         theSubShapeID,
 
 void SMESH_Mesh_i::CreateGroupServants()
 {
-  SALOMEDS::Study_var  aStudy = _gen_i->GetCurrentStudy();
   SMESH::SMESH_Mesh_var aMesh = _this();
 
   set<int> addedIDs;
@@ -4950,7 +5548,7 @@ void SMESH_Mesh_i::CreateGroupServants()
   while ( groupIt->more() )
   {
     ::SMESH_Group* group = groupIt->next();
-    int            anId = group->GetGroupDS()->GetID();
+    int             anId = group->GetID();
 
     map<int, SMESH::SMESH_GroupBase_ptr>::iterator it = _mapGroups.find(anId);
     if ( it != _mapGroups.end() && !CORBA::is_nil( it->second ))
@@ -4979,10 +5577,8 @@ void SMESH_Mesh_i::CreateGroupServants()
     else        { nextId = 0; } // avoid "unused variable" warning in release mode
 
     // publishing the groups in the study
-    if ( !aStudy->_is_nil() ) {
-      GEOM::GEOM_Object_var shapeVar = _gen_i->ShapeToGeomObject( shape );
-      _gen_i->PublishGroup( aStudy, aMesh, groupVar, shapeVar, group->GetName());
-    }
+    GEOM::GEOM_Object_var shapeVar = _gen_i->ShapeToGeomObject( shape );
+    _gen_i->PublishGroup( aMesh, groupVar, shapeVar, group->GetName());
   }
   if ( !addedIDs.empty() )
   {
@@ -4997,6 +5593,17 @@ void SMESH_Mesh_i::CreateGroupServants()
   }
 }
 
+//=============================================================================
+/*!
+ * \brief Return true if all sub-meshes are computed OK - to update an icon
+ */
+//=============================================================================
+
+bool SMESH_Mesh_i::IsComputedOK()
+{
+  return _impl->IsComputedOK();
+}
+
 //=============================================================================
 /*!
  * \brief Return groups cantained in _mapGroups by their IDs
@@ -5037,6 +5644,48 @@ SMESH::MedFileInfo* SMESH_Mesh_i::GetMEDFileInfo()
   return res._retn();
 }
 
+//=======================================================================
+//function : FileInfoToString
+//purpose  : Persistence of file info
+//=======================================================================
+
+std::string SMESH_Mesh_i::FileInfoToString()
+{
+  std::string s;
+  if ( &_medFileInfo.in() && _medFileInfo->fileName[0] )
+  {
+    s = SMESH_Comment( _medFileInfo->fileSize )
+      << " " << _medFileInfo->major
+      << " " << _medFileInfo->minor
+      << " " << _medFileInfo->release
+      << " " << _medFileInfo->fileName;
+  }
+  return s;
+}
+
+//=======================================================================
+//function : FileInfoFromString
+//purpose  : Persistence of file info
+//=======================================================================
+
+void SMESH_Mesh_i::FileInfoFromString(const std::string& info)
+{
+  std::string size, major, minor, release, fileName;
+  std::istringstream is(info);
+  is >> size >> major >> minor >> release;
+  fileName = info.data() + ( size.size()   + 1 +
+                             major.size()  + 1 +
+                             minor.size()  + 1 +
+                             release.size()+ 1 );
+
+  _medFileInfo           = new SMESH::MedFileInfo();
+  _medFileInfo->fileName = fileName.c_str();
+  _medFileInfo->fileSize = atoi( size.c_str() );
+  _medFileInfo->major    = atoi( major.c_str() );
+  _medFileInfo->minor    = atoi( minor.c_str() );
+  _medFileInfo->release  = atoi( release.c_str() );
+}
+
 //=============================================================================
 /*!
  * \brief Pass names of mesh groups from study to mesh DS
@@ -5049,10 +5698,6 @@ void SMESH_Mesh_i::checkGroupNames()
   if ( !nbGrp )
     return;
 
-  SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy();
-  if ( aStudy->_is_nil() )
-    return; // nothing to do
-  
   SMESH::ListOfGroups* grpList = 0;
   // avoid dump of "GetGroups"
   {
@@ -5065,7 +5710,7 @@ void SMESH_Mesh_i::checkGroupNames()
     SMESH::SMESH_GroupBase_ptr aGrp = (*grpList)[ gIndx ];
     if ( !aGrp )
       continue;
-    SALOMEDS::SObject_wrap aGrpSO = _gen_i->ObjectToSObject( aStudy, aGrp );
+    SALOMEDS::SObject_wrap aGrpSO = _gen_i->ObjectToSObject( aGrp );
     if ( aGrpSO->_is_nil() )
       continue;
     // correct name of the mesh group if necessary
@@ -5108,15 +5753,12 @@ SMESH::string_array* SMESH_Mesh_i::GetLastParameters()
   SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen();
   if(gen) {
     CORBA::String_var aParameters = GetParameters();
-    SALOMEDS::Study_var    aStudy = gen->GetCurrentStudy();
-    if ( !aStudy->_is_nil()) {
-      SALOMEDS::ListOfListOfStrings_var aSections = aStudy->ParseVariables(aParameters); 
-      if ( aSections->length() > 0 ) {
-        SALOMEDS::ListOfStrings aVars = aSections[ aSections->length() - 1 ];
-        aResult->length( aVars.length() );
-        for ( CORBA::ULong i = 0;i < aVars.length(); i++ )
-          aResult[i] = CORBA::string_dup( aVars[i] );
-      }
+    SALOMEDS::ListOfListOfStrings_var aSections = SMESH_Gen_i::getStudyServant()->ParseVariables(aParameters);
+    if ( aSections->length() > 0 ) {
+      SALOMEDS::ListOfStrings aVars = aSections[ aSections->length() - 1 ];
+      aResult->length( aVars.length() );
+      for ( CORBA::ULong i = 0;i < aVars.length(); i++ )
+        aResult[i] = CORBA::string_dup( aVars[i] );
     }
   }
   return aResult._retn();
@@ -5242,7 +5884,7 @@ SALOMEDS::TMPFile* SMESH_Mesh_i::GetVtkUgStream()
 {
   SALOMEDS::TMPFile_var SeqFile;
   if ( SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS() ) {
-    SMDS_UnstructuredGrid* aGrid = aMeshDS->getGrid();
+    SMDS_UnstructuredGrid* aGrid = aMeshDS->GetGrid();
     if(aGrid) {
       vtkUnstructuredGridWriter* aWriter = vtkUnstructuredGridWriter::New();
       aWriter->WriteToOutputStringOn();
@@ -5251,10 +5893,10 @@ SALOMEDS::TMPFile* SMESH_Mesh_i::GetVtkUgStream()
       aWriter->Write();
       char* str = aWriter->GetOutputString();
       int size = aWriter->GetOutputStringLength();
-      
-      //Allocate octect buffer of required size
+
+      //Allocate octet buffer of required size
       CORBA::Octet* OctetBuf = SALOMEDS::TMPFile::allocbuf(size);
-      //Copy ostrstream content to the octect buffer
+      //Copy ostrstream content to the octet buffer
       memcpy(OctetBuf, str, size);
       //Create and return TMPFile
       SeqFile = new SALOMEDS::TMPFile(size, size, OctetBuf, 1);
@@ -5275,10 +5917,12 @@ namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_v
     SMDS_ElemIteratorPtr    _elemIter;
     PredicatePtr            _predicate;
     const SMDS_MeshElement* _elem;
+    SMDSAbs_ElementType     _type;
 
-    PredicateIterator( SMDS_ElemIteratorPtr   iterator,
-                       PredicatePtr predicate):
-      _elemIter(iterator), _predicate(predicate)
+    PredicateIterator( SMDS_ElemIteratorPtr iterator,
+                       PredicatePtr         predicate,
+                       SMDSAbs_ElementType  type):
+      _elemIter(iterator), _predicate(predicate), _type(type)
     {
       next();
     }
@@ -5292,8 +5936,9 @@ namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_v
       _elem = 0;
       while ( _elemIter->more() && !_elem )
       {
-        _elem = _elemIter->next();
-        if ( _elem && ( !_predicate->IsSatisfy( _elem->GetID() )))
+        if ((_elem = _elemIter->next()) &&
+            (( _type != SMDSAbs_All && _type != _elem->GetType() ) ||
+             ( !_predicate->IsSatisfy( _elem->GetID() ))))
           _elem = 0;
       }
       return res;
@@ -5379,7 +6024,7 @@ namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_v
     {
       const SMDS_MeshElement* res = _node;
       _node = 0;
-      while (( _elemIter->more() || _nodeIter->more() ) && !_node )
+      while ( !_node && ( _elemIter->more() || _nodeIter->more() ))
       {
         if ( _nodeIter->more() )
         {
@@ -5447,6 +6092,7 @@ SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObje
   else if ( SMESH::Filter_i* filter_i = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
   {
     if ( filter_i->GetElementType() == theType ||
+         filter_i->GetElementType() == SMESH::ALL ||
          elemType == SMDSAbs_Node ||
          elemType == SMDSAbs_All)
     {
@@ -5455,8 +6101,10 @@ SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObje
       {
         SMDSAbs_ElementType filterType = SMDSAbs_ElementType( filter_i->GetElementType() );
         SMDS_ElemIteratorPtr allElemIt = meshDS->elementsIterator( filterType );
-        elemIt = SMDS_ElemIteratorPtr( new PredicateIterator( allElemIt, pred_i->GetPredicate() ));
-        typeOK = ( filterType == elemType || elemType == SMDSAbs_All );
+        SMDSAbs_ElementType   iterType = elemType == SMDSAbs_Node ? filterType : elemType;
+        elemIt = SMDS_ElemIteratorPtr
+          ( new PredicateIterator( allElemIt, pred_i->GetPredicate(), iterType ));
+        typeOK = ( elemType == SMDSAbs_Node ? filterType == SMDSAbs_Node : elemIt->more() );
       }
     }
   }
@@ -5466,16 +6114,17 @@ SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObje
     const bool                    isNodes = ( types->length() == 1 && types[0] == SMESH::NODE );
     if ( isNodes && elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
       return elemIt;
+    SMDSAbs_ElementType iterType = isNodes ? SMDSAbs_Node : elemType;
     if ( SMESH_MeshEditor_i::IsTemporaryIDSource( theObject ))
     {
       int nbIds;
       if ( CORBA::Long* ids = SMESH_MeshEditor_i::GetTemporaryIDs( theObject, nbIds ))
-        elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, elemType ));
+        elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, iterType ));
     }
     else
     {
       SMESH::long_array_var ids = theObject->GetIDs();
-      elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), elemType ));
+      elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), iterType ));
     }
     typeOK = ( isNodes == ( elemType == SMDSAbs_Node )) || ( elemType == SMDSAbs_All );
   }
@@ -5517,17 +6166,17 @@ TopAbs_ShapeEnum shapeTypeByDim(const int theDim)
 
 //-----------------------------------------------------------------------------
 /*!
- * \brief Internal structure used to find concurent submeshes
+ * \brief Internal structure used to find concurrent submeshes
  *
- * It represents a pair < submesh, concurent dimension >, where
- * 'concurrent dimension' is dimension of shape where the submesh can concurent
+ * It represents a pair < submesh, concurrent dimension >, where
+ * 'concurrent dimension' is dimension of shape where the submesh can concurrent
  *  with another submesh. In other words, it is dimension of a hypothesis assigned
  *  to submesh.
  */
 class SMESH_DimHyp
 {
  public:
-  //! fileds
+  //! fields
   int _dim;    //!< a dimension the algo can build (concurrent dimension)
   int _ownDim; //!< dimension of shape of _subMesh (>=_dim)
   TopTools_MapOfShape _shapeMap;
@@ -5585,7 +6234,7 @@ class SMESH_DimHyp
     }
     return isShared;
   }
-  
+
   //-----------------------------------------------------------------------------
   //! check algorithms
   static bool checkAlgo(const SMESHDS_Hypothesis* theA1,
@@ -5599,7 +6248,7 @@ class SMESH_DimHyp
     return strcmp( theA1->GetName(), theA2->GetName() ) == 0;
   }
 
-  
+
   //-----------------------------------------------------------------------------
   //! Check if sub-shape hypotheses are concurrent
   bool IsConcurrent(const SMESH_DimHyp* theOther) const
@@ -5617,19 +6266,23 @@ class SMESH_DimHyp
     if ( (_ownDim == _dim  || theOther->_ownDim == _dim ) && (!meIsCompound || !otherIsCompound))
       return false;
 
-//     bool checkSubShape = ( _dim >= theOther->_dim )
-//       ? isShareSubShapes( _shapeMap, theOther->_shapeMap, shapeTypeByDim(theOther->_dim) )
-//       : isShareSubShapes( theOther->_shapeMap, _shapeMap, shapeTypeByDim(_dim) ) ;
     bool checkSubShape = isShareSubShapes( _shapeMap, theOther->_shapeMap, shapeTypeByDim(_dim));
     if ( !checkSubShape )
-        return false;
+      return false;
 
     // check algorithms to be same
-    if ( !checkAlgo( this->GetAlgo(), theOther->GetAlgo() ))
-      return true; // different algorithms -> concurrency !
+    const SMESH_Algo* a1 = this->GetAlgo();
+    const SMESH_Algo* a2 = theOther->GetAlgo();
+    bool isSame = checkAlgo( a1, a2 );
+    if ( !isSame )
+    {
+      if ( !a1 || !a2 )
+        return false; // pb?
+      return a1->GetDim() == a2->GetDim(); // different algorithms of same dim -> concurrency !
+    }
 
     // check hypothesises for concurrence (skip first as algorithm)
-    int nbSame = 0;
+    size_t nbSame = 0;
     // pointers should be same, because it is referened from mesh hypothesis partition
     list <const SMESHDS_Hypothesis*>::const_iterator hypIt = _hypotheses.begin();
     list <const SMESHDS_Hypothesis*>::const_iterator otheEndIt = theOther->_hypotheses.end();
@@ -5637,7 +6290,7 @@ class SMESH_DimHyp
       if ( find( theOther->_hypotheses.begin(), otheEndIt, *hypIt ) != otheEndIt )
         nbSame++;
     // the submeshes are concurrent if their algorithms has different parameters
-    return nbSame != (int)theOther->_hypotheses.size() - 1;
+    return nbSame != theOther->_hypotheses.size() - 1;
   }
 
   // Return true if algorithm of this SMESH_DimHyp is used if no
@@ -5651,7 +6304,7 @@ class SMESH_DimHyp
 
     return ( this->_subMesh->GetId() < theOther->_subMesh->GetId() );
   }
-  
+
 }; // end of SMESH_DimHyp
 //-----------------------------------------------------------------------------
 
@@ -5659,7 +6312,7 @@ typedef list<const SMESH_DimHyp*> TDimHypList;
 
 //-----------------------------------------------------------------------------
 
-void addDimHypInstance(const int                               theDim, 
+void addDimHypInstance(const int                               theDim,
                        const TopoDS_Shape&                     theShape,
                        const SMESH_Algo*                       theAlgo,
                        const SMESH_subMesh*                    theSubMesh,
@@ -5672,7 +6325,7 @@ void addDimHypInstance(const int                               theDim,
     dimHyp->_hypotheses.push_front(theAlgo);
     listOfdimHyp.push_back( dimHyp );
   }
-  
+
   SMESH_DimHyp* dimHyp = const_cast<SMESH_DimHyp*>( listOfdimHyp.back() );
   dimHyp->_hypotheses.insert( dimHyp->_hypotheses.end(),
                               theHypList.begin(), theHypList.end() );
@@ -5731,7 +6384,7 @@ void unionLists(TListOfInt&       theListOfId,
     if ( find_first_of( theListOfId.begin(), theListOfId.end(),
                         otherListOfId.begin(), otherListOfId.end() ) == theListOfId.end() )
       continue;
-         
+
     // union two lists (from source into target)
     TListOfInt::iterator it2 = otherListOfId.begin();
     for ( ; it2 != otherListOfId.end(); it2++ ) {
@@ -5884,7 +6537,7 @@ TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes()
           addDimHypInstance( j, aSubMeshShape, anAlgo, sm, hypList, dimHypListArr );
       }
     } // end iterations on submesh
-    
+
     // iterate on created dimension-hypotheses and check for concurrents
     for ( int i = 0; i < 4; i++ ) {
       const TDimHypList& listOfDimHyp = dimHypListArr[i];
@@ -5909,10 +6562,10 @@ TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes()
         }
       }
     }
-    
+
     removeDimHyps(dimHypListArr);
-    
-    // now, minimise the number of concurrent groups
+
+    // now, minimize the number of concurrent groups
     // Here we assume that lists of submeshes can have same submesh
     // in case of multi-dimension algorithms, as result
     //  list with common submesh has to be united into one list
@@ -5970,17 +6623,24 @@ TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes()
     aPythonDump << " ]";
     subMeshOrder.push_back( subMeshIds );
 
-    // clear collected submeshes
+    // clear collected sub-meshes
     set<const SMESH_subMesh*>::iterator clrIt = subMeshToClear.begin();
     for ( ; clrIt != subMeshToClear.end(); clrIt++ )
       if ( SMESH_subMesh* sm = (SMESH_subMesh*)*clrIt )
+      {
         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
+        if ( SMESH_Algo* algo = sm->GetAlgo() ) // #16748
+          sm->AlgoStateEngine( SMESH_subMesh::MODIF_HYP, algo ); // to clear a cached algo
+      }
   }
   aPythonDump << " ])";
 
   mesh.SetMeshOrder( subMeshOrder );
   res = true;
-  
+
+  SMESH::SMESH_Mesh_var me = _this();
+  _gen_i->UpdateIcons( me );
+
   return res;
 }
 
@@ -6009,7 +6669,7 @@ void SMESH_Mesh_i::convertMeshOrder (const TListOfListOfInt&     theIdsOrder,
       continue;
     if ( theIsDump )
       aPythonDump << "[ ";
-    // convert shape indeces into interfaces
+    // convert shape indices into interfaces
     SMESH::submesh_array_var aResSubSet = new SMESH::submesh_array();
     aResSubSet->length(aSubOrder.size());
     TListOfInt::const_iterator subIt = aSubOrder.begin();
@@ -6041,6 +6701,24 @@ void SMESH_Mesh_i::convertMeshOrder (const TListOfListOfInt&     theIdsOrder,
   }
 }
 
+namespace // utils used by SMESH_MeshPartDS
+{
+  /*!
+   * \brief Class used to access to protected data of SMDS_MeshInfo
+   */
+  struct TMeshInfo : public SMDS_MeshInfo
+  {
+    void Add(const SMDS_MeshElement* e) { SMDS_MeshInfo::addWithPoly( e ); }
+  };
+  /*!
+   * \brief Element holing its ID only
+   */
+  struct TElemID : public SMDS_LinearEdge
+  {
+    TElemID(int ID) : SMDS_LinearEdge(0,0) { setID( ID ); }
+  };
+}
+
 //================================================================================
 //
 // Implementation of SMESH_MeshPartDS
@@ -6051,6 +6729,7 @@ SMESH_MeshPartDS::SMESH_MeshPartDS(SMESH::SMESH_IDSource_ptr meshPart):
   SMESH::SMESH_Mesh_var mesh = meshPart->GetMesh();
   SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
 
+  mesh_i->Load();
   _meshDS = mesh_i->GetImpl().GetMeshDS();
 
   SetPersistentId( _meshDS->GetPersistentId() );
@@ -6120,6 +6799,63 @@ SMESH_MeshPartDS::SMESH_MeshPartDS(const std::list< const SMDS_MeshElement* > &
   myInfo = tmpInfo;
 }
 // -------------------------------------------------------------------------------------
+const SMDS_MeshElement * SMESH_MeshPartDS::FindElement(int IDelem) const
+{
+  if ( _meshDS ) return _meshDS->FindElement( IDelem );
+
+  TElemID elem( IDelem );
+  for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
+    if ( !_elements[ iType ].empty() )
+    {
+      TIDSortedElemSet::const_iterator it = _elements[ iType ].find( &elem );
+      if ( it != _elements[ iType ].end() )
+        return *it;
+    }
+  return 0;
+}
+// -------------------------------------------------------------------------------------
+bool SMESH_MeshPartDS::HasNumerationHoles()
+{
+  if ( _meshDS ) return _meshDS->HasNumerationHoles();
+
+  return ( MinNodeID() != 1 ||
+           MaxNodeID() != NbNodes() ||
+           MinElementID() != 1 ||
+           MaxElementID() != NbElements() );
+}
+// -------------------------------------------------------------------------------------
+int SMESH_MeshPartDS::MaxNodeID() const
+{
+  if ( _meshDS ) return _meshDS->MaxNodeID();
+  return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].rbegin())->GetID();
+}
+// -------------------------------------------------------------------------------------
+int SMESH_MeshPartDS::MinNodeID() const
+{
+  if ( _meshDS ) return _meshDS->MinNodeID();
+  return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].begin())->GetID();
+}  
+// -------------------------------------------------------------------------------------
+int SMESH_MeshPartDS::MaxElementID() const
+{
+  if ( _meshDS ) return _meshDS->MaxElementID();
+  int maxID = 0;
+  for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
+    if ( !_elements[ iType ].empty() )
+      maxID = Max( maxID, (*_elements[ iType ].rbegin())->GetID() );
+  return maxID;
+}
+// -------------------------------------------------------------------------------------
+int SMESH_MeshPartDS::MinElementID() const
+{
+  if ( _meshDS ) return _meshDS->MinElementID();
+  int minID = 0;
+  for ( int iType = SMDSAbs_Edge; iType < SMDSAbs_NbElementTypes; ++iType )
+    if ( !_elements[ iType ].empty() )
+      minID = Min( minID, (*_elements[ iType ].begin())->GetID() );
+  return minID;
+}
+// -------------------------------------------------------------------------------------
 SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementGeomIterator(SMDSAbs_GeometryType geomType) const
 {
   if ( _meshDS ) return _meshDS->elementGeomIterator( geomType );
@@ -6131,7 +6867,7 @@ SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementGeomIterator(SMDSAbs_GeometryType
     SMDS_MeshElement::GeomFilter
     > TIter;
 
-  SMDSAbs_ElementType type = SMDS_MeshCell::toSmdsType( geomType );
+  SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( geomType );
 
   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
                                           _elements[type].end(),
@@ -6149,7 +6885,7 @@ SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementEntityIterator(SMDSAbs_EntityType
     SMDS_MeshElement::EntityFilter
     > TIter;
 
-  SMDSAbs_ElementType type = SMDS_MeshCell::toSmdsType( entity );
+  SMDSAbs_ElementType type = SMDS_MeshCell::ElemType( entity );
 
   return SMDS_ElemIteratorPtr( new TIter( _elements[type].begin(),
                                           _elements[type].end(),
@@ -6176,10 +6912,10 @@ SMDS_ElemIteratorPtr SMESH_MeshPartDS::elementsIterator(SMDSAbs_ElementType type
 }
 // -------------------------------------------------------------------------------------
 #define _GET_ITER_DEFINE( iterType, methName, elem, elemType)                       \
-  iterType SMESH_MeshPartDS::methName( bool idInceasingOrder) const                 \
+  iterType SMESH_MeshPartDS::methName() const                 \
   {                                                                                 \
     typedef SMDS_SetIterator<const elem*, TIDSortedElemSet::const_iterator > TIter; \
-    return _meshDS ? _meshDS->methName(idInceasingOrder) : iterType                 \
+    return _meshDS ? _meshDS->methName() : iterType                 \
       ( new TIter( _elements[elemType].begin(), _elements[elemType].end() ));       \
   }
 // -------------------------------------------------------------------------------------
@@ -6192,5 +6928,3 @@ _GET_ITER_DEFINE( SMDS_VolumeIteratorPtr, volumesIterator, SMDS_MeshVolume, SMDS
 // END Implementation of SMESH_MeshPartDS
 //
 //================================================================================
-
-