Salome HOME
54416: Extrusion 3D algo is not applicable to a prismatic shape
[modules/smesh.git] / src / SMESH_I / SMESH_Mesh_i.cxx
index 540211542cc35aa31e3e95769d6296654a72dd5d..082f2914ad400880c7910dc29c7e6c5c973fd6de 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
@@ -96,6 +96,7 @@ static int MYDEBUG = 0;
 
 using namespace std;
 using SMESH::TPythonDump;
+using SMESH::TVar;
 
 int SMESH_Mesh_i::_idGenerator = 0;
 
@@ -239,7 +240,7 @@ GEOM::GEOM_Object_ptr SMESH_Mesh_i::GetShapeToMesh()
         for ( ; data != _geomGroupData.end(); ++data )
           if ( data->_smeshObject->_is_equivalent( _this() ))
           {
-            SALOMEDS::SObject_wrap so = SMESH_Gen_i::getStudyServant()->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;
@@ -691,9 +692,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 );
@@ -771,6 +772,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
   {
@@ -954,7 +958,7 @@ void SMESH_Mesh_i::RemoveSubMesh( SMESH::SMESH_subMesh_ptr theSubMesh )
     // if ( aSubShape->_is_nil() ) // not published shape (IPAL13617)
     //   aSubShape = theSubMesh->GetSubShape();
 
-    SALOMEDS::StudyBuilder_var builder = SMESH_Gen_i::getStudyServant()->NewBuilder();
+    SALOMEDS::StudyBuilder_var builder = _gen_i->getStudyServant()->NewBuilder();
     builder->RemoveObjectWithChildren( anSO );
 
     // Update Python script
@@ -1018,8 +1022,8 @@ 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 ) )
     {
@@ -1063,7 +1067,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() )
@@ -1100,6 +1104,10 @@ void SMESH_Mesh_i::RemoveGroup( SMESH::SMESH_GroupBase_ptr theGroup )
   if ( !aGroup )
     return;
 
+  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() )
   {
@@ -1134,6 +1142,11 @@ 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
   bool isNodal = ( theGroup->GetType() == SMESH::NODE );
   if ( !isNodal && !theGroup->IsEmpty() )
@@ -1410,7 +1423,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
@@ -1495,7 +1508,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
  */
@@ -1558,7 +1571,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
@@ -1567,8 +1580,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)
 {
@@ -1868,6 +1881,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
@@ -1991,11 +2087,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;
+  }
 }
 
 //=============================================================================
@@ -2008,19 +2159,67 @@ namespace
 
 void SMESH_Mesh_i::CheckGeomModif()
 {
+  SMESH::SMESH_Mesh_var me = _this();
+  GEOM::GEOM_Object_var mainGO = GetShapeToMesh();
+
+  //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 );
+    }
+
+    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;
   }
 
@@ -2047,23 +2246,35 @@ 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();
+  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() )
+        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 );
+      }
     }
+  }
   // 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() )
   {
@@ -2078,7 +2289,7 @@ void SMESH_Mesh_i::CheckGeomModif()
   _impl->ShapeToMesh( newShape );
 
   // re-add shapes of geom groups
-  list<TGeomGroupData>::iterator data = _geomGroupData.begin();
+  std::list<TGeomGroupData>::iterator data = _geomGroupData.begin();
   for ( ; data != _geomGroupData.end(); ++data )
   {
     TopoDS_Shape newShape = newGroupShape( *data );
@@ -2108,36 +2319,28 @@ void SMESH_Mesh_i::CheckGeomModif()
       _impl->AddHypothesis( s, (*h)->GetID() );
   }
 
-  // restore groups
+  // 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 );
+    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;
 
-    int id;
-    SMESH_Group* g = _impl->AddGroup( data._type, data._name.c_str(), id,
-                                      meshDS->IndexToShape( data._shapeID ));
+    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 );
-      gr_i->changeLocalId( id );
-      _mapGroups[ id ] = i2g->second;
-      if ( data._oldID != id )
-        _mapGroups.erase( i2g );
-    }
   }
 
   // update _mapSubMesh
-  map<int, ::SMESH_subMesh*>::iterator i_sm = _mapSubMesh.begin();
+  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 ));
 
@@ -2154,6 +2357,98 @@ void SMESH_Mesh_i::CheckGeomModif()
 
 void SMESH_Mesh_i::CheckGeomGroupModif()
 {
+  // 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 );
+      }
+  }
+
+  // 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();
@@ -2300,7 +2595,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 );
@@ -2345,10 +2640,10 @@ void SMESH_Mesh_i::CheckGeomGroupModif()
         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
@@ -2426,9 +2721,11 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase
       // 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 << " )";
@@ -2436,9 +2733,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" );
@@ -2547,14 +2844,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() &&
-         _mapSubMesh[ subMeshId ])
+    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());
@@ -2601,6 +2901,7 @@ 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 )
 {
@@ -2619,10 +2920,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 );
@@ -2638,7 +2940,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() ) {
@@ -2990,9 +3292,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() ) {
@@ -3079,7 +3381,7 @@ string SMESH_Mesh_i::prepareMeshNameAndGroups(const char*    file,
 
 void SMESH_Mesh_i::ExportMED(const char*        file,
                              CORBA::Boolean     auto_groups,
-                             CORBA::Long        minor,
+                             CORBA::Long        version,
                              CORBA::Boolean     overwrite,
                              CORBA::Boolean     autoDimension)
   throw(SALOME::SALOME_Exception)
@@ -3090,12 +3392,12 @@ void SMESH_Mesh_i::ExportMED(const char*        file,
     _preMeshInfo->FullLoadFromFile();
 
   string aMeshName = prepareMeshNameAndGroups(file, overwrite);
-  _impl->ExportMED( file, aMeshName.c_str(), auto_groups, minor, 0, autoDimension );
+  _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version, 0, autoDimension );
 
   TPythonDump() << SMESH::SMESH_Mesh_var(_this()) << ".ExportMED( r'"
                 << file << "', "
                 << "auto_groups=" <<auto_groups << ", "
-                << "minor=" << minor <<  ", "
+                << "minor=" << version <<  ", "
                 << "overwrite=" << overwrite << ", "
                 << "meshPart=None, "
                 << "autoDimension=" << autoDimension << " )";
@@ -3208,14 +3510,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,
-                                   CORBA::Long               minor,
+                                   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 minor version: "<< minor);
+  MESSAGE("MED version: "<< version);
   SMESH_TRY;
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
@@ -3262,8 +3565,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, minor,
-                      0, autoDimension, /*addODOnVertices=*/have0dField);
+    _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
+                      0, autoDimension, /*addODOnVertices=*/have0dField,
+                      ZTolerance);
     meshDS = _impl->GetMeshDS();
   }
   else
@@ -3280,8 +3584,8 @@ void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
     }
 
     SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
-    _impl->ExportMED( file, aMeshName.c_str(), auto_groups, minor,
-                      partDS, autoDimension, /*addODOnVertices=*/have0dField);
+    _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
+                      partDS, autoDimension, /*addODOnVertices=*/have0dField, ZTolerance);
     meshDS = tmpDSDeleter._obj = partDS;
   }
 
@@ -3309,11 +3613,13 @@ void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
                 << meshPart << ", r'"
                 << file << "', "
                 << auto_groups << ", "
-                << minor << ", "
+                << version << ", "
                 << overwrite << ", "
                 << autoDimension << ", "
                 << goList << ", '"
-                << ( geomAssocFields ? geomAssocFields : "" ) << "'" << " )";
+                << ( geomAssocFields ? geomAssocFields : "" ) << "',"
+                << TVar( ZTolerance )
+                << " )";
 
   SMESH_CATCH( SMESH::throwCorbaException );
 }
@@ -4296,7 +4602,7 @@ SMESH::long_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID,
 
   return aResult._retn();
 }
-  
+
 //=============================================================================
 /*!
  * Returns type of elements for given submesh
@@ -4328,9 +4634,9 @@ SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID
 
   SMESH_CATCH( SMESH::throwCorbaException );
 
-  return type; 
+  return type;
 }
-  
+
 
 //=============================================================================
 /*!
@@ -4387,7 +4693,8 @@ 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();
@@ -4398,13 +4705,14 @@ SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long id)
     return aResult._retn();
 
   // find node
-  const SMDS_MeshNode* aNode = aMeshDS->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();
@@ -4540,7 +4848,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
  */
@@ -4628,8 +4936,9 @@ SMESH::long_array* SMESH_Mesh_i::GetElemNodes(const CORBA::Long 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();
@@ -4745,7 +5054,7 @@ SMESH::long_array* SMESH_Mesh_i::GetElemFaceNodes(CORBA::Long  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 ));
@@ -4759,7 +5068,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.
 //=======================================================================
 
@@ -5056,7 +5365,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 ))
@@ -5205,7 +5514,7 @@ void SMESH_Mesh_i::checkGroupNames()
   int nbGrp = NbGroups();
   if ( !nbGrp )
     return;
-  
+
   SMESH::ListOfGroups* grpList = 0;
   // avoid dump of "GetGroups"
   {
@@ -5401,10 +5710,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);
@@ -5425,10 +5734,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();
     }
@@ -5442,8 +5753,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;
@@ -5597,6 +5909,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)
     {
@@ -5605,8 +5918,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() );
       }
     }
   }
@@ -5616,16 +5931,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 );
   }
@@ -5735,7 +6051,7 @@ class SMESH_DimHyp
     }
     return isShared;
   }
-  
+
   //-----------------------------------------------------------------------------
   //! check algorithms
   static bool checkAlgo(const SMESHDS_Hypothesis* theA1,
@@ -5749,7 +6065,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
@@ -5767,19 +6083,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();
@@ -5787,7 +6107,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
@@ -5801,7 +6121,7 @@ class SMESH_DimHyp
 
     return ( this->_subMesh->GetId() < theOther->_subMesh->GetId() );
   }
-  
+
 }; // end of SMESH_DimHyp
 //-----------------------------------------------------------------------------
 
@@ -5809,7 +6129,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,
@@ -5822,7 +6142,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() );
@@ -5881,7 +6201,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++ ) {
@@ -6034,7 +6354,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];
@@ -6059,9 +6379,9 @@ TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes()
         }
       }
     }
-    
+
     removeDimHyps(dimHypListArr);
-    
+
     // 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
@@ -6120,17 +6440,21 @@ 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 );
 
@@ -6379,5 +6703,3 @@ _GET_ITER_DEFINE( SMDS_VolumeIteratorPtr, volumesIterator, SMDS_MeshVolume, SMDS
 // END Implementation of SMESH_MeshPartDS
 //
 //================================================================================
-
-