Salome HOME
0021897: EDF 1495 SMESH : Problem with groups when building a compound with medballs
[modules/smesh.git] / src / SMESH_I / SMESH_Gen_i.cxx
index 7112663e507c22d77b8cc9d5b37fc2306611be34..00cc36bee86238e73b45f83ae3f43fd5e0f2aeee 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2012  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 <TCollection_AsciiString.hxx>
 #include <OSD.hxx>
 
-#include "Utils_CorbaException.hxx"
-
-#include "utilities.h"
-#include <fstream>
-#include <stdio.h>
-
 #ifdef WNT
  #include <windows.h>
  #include <process.h>
  #define UnLoadLib( handle ) dlclose( handle );
 #endif
 
-#include <HDFOI.hxx>
-
 #include "SMESH_Gen_i.hxx"
-#include "SMESH_Mesh_i.hxx"
-#include "SMESH_Hypothesis_i.hxx"
-#include "SMESH_Algo_i.hxx"
-#include "SMESH_Group_i.hxx"
-#include "SMESH_PythonDump.hxx"
-
-#include "SMESHDS_Document.hxx"
-#include "SMESHDS_Group.hxx"
-#include "SMESHDS_GroupOnGeom.hxx"
-#include "SMESH_Mesh.hxx"
-#include "SMESH_Hypothesis.hxx"
-#include "SMESH_Group.hxx"
-#include "SMESH_MeshEditor.hxx"
 
 #include "SMDS_EdgePosition.hxx"
 #include "SMDS_FacePosition.hxx"
 #include "SMDS_SetIterator.hxx"
 #include "SMDS_SpacePosition.hxx"
 #include "SMDS_VertexPosition.hxx"
+#include "SMESHDS_Document.hxx"
+#include "SMESHDS_Group.hxx"
+#include "SMESHDS_GroupOnGeom.hxx"
+#include "SMESH_Algo_i.hxx"
+#include "SMESH_File.hxx"
+#include "SMESH_Group.hxx"
+#include "SMESH_Group_i.hxx"
+#include "SMESH_Hypothesis.hxx"
+#include "SMESH_Hypothesis_i.hxx"
+#include "SMESH_Mesh.hxx"
+#include "SMESH_MeshEditor.hxx"
+#include "SMESH_Mesh_i.hxx"
+#include "SMESH_PreMeshInfo.hxx"
+#include "SMESH_PythonDump.hxx"
 
 #include CORBA_SERVER_HEADER(SMESH_Group)
 #include CORBA_SERVER_HEADER(SMESH_Filter)
 #ifdef WITH_CGNS
 #include "DriverCGNS_Read.hxx"
 #endif
+#include "memoire.h"
+
+#include <GEOM_Client.hxx>
 
-#include "SALOMEDS_Tool.hxx"
-#include "SALOME_NamingService.hxx"
-#include "SALOME_LifeCycleCORBA.hxx"
-#include "Utils_SINGLETON.hxx"
-#include "OpUtil.hxx"
+#include <Basics_Utils.hxx>
+#include <HDFOI.hxx>
+#include <OpUtil.hxx>
+#include <SALOMEDS_Tool.hxx>
+#include <SALOME_Container_i.hxx>
+#include <SALOME_LifeCycleCORBA.hxx>
+#include <SALOME_NamingService.hxx>
+#include <Utils_CorbaException.hxx>
+#include <Utils_ExceptHandlers.hxx>
+#include <Utils_SINGLETON.hxx>
+#include <utilities.h>
 
 #include CORBA_CLIENT_HEADER(SALOME_ModuleCatalog)
 #include CORBA_CLIENT_HEADER(SALOME_Session)
 
-#include "GEOM_Client.hxx"
-#include "Utils_ExceptHandlers.hxx"
-#include "memoire.h"
-#include "Basics_Utils.hxx"
-
 #include <map>
+#include <fstream>
+#include <cstdio>
+#include <stdlib.h>
 
 using namespace std;
 using SMESH::TPythonDump;
+using SMESH::TVar;
 
 #define NUM_TMP_FILES 2
 
@@ -283,6 +284,8 @@ SMESH_Gen_i::SMESH_Gen_i( CORBA::ORB_ptr            orb,
   myIsEmbeddedMode = false;
   myShapeReader = NULL;  // shape reader
   mySMESHGen = this;
+  myIsHistoricalPythonDump = true;
+  myToForgetMeshDataOnHypModif = false;
 
   // set it in standalone mode only
   //OSD::SetSignal( true );
@@ -589,6 +592,12 @@ CORBA::Boolean SMESH_Gen_i::IsEmbeddedMode()
 //=============================================================================
 
 void SMESH_Gen_i::SetCurrentStudy( SALOMEDS::Study_ptr theStudy )
+{
+  setCurrentStudy( theStudy );
+}
+
+void SMESH_Gen_i::setCurrentStudy( SALOMEDS::Study_ptr theStudy,
+                                   bool                theStudyIsBeingClosed)
 {
   int curStudyId = GetCurrentStudyID();
   myCurrentStudy = SALOMEDS::Study::_duplicate( theStudy );
@@ -599,7 +608,7 @@ void SMESH_Gen_i::SetCurrentStudy( SALOMEDS::Study_ptr theStudy )
   }
 
   // myCurrentStudy may be nil
-  if ( !CORBA::is_nil( myCurrentStudy ) ) {
+  if ( !theStudyIsBeingClosed && !CORBA::is_nil( myCurrentStudy ) ) {
     SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder();
     if( !myCurrentStudy->FindComponent( "GEOM" )->_is_nil() )
       aStudyBuilder->LoadWith( myCurrentStudy->FindComponent( "GEOM" ), GetGeomEngine() );
@@ -805,6 +814,63 @@ void SMESH_Gen_i::SetDefaultNbSegments(CORBA::Long theNbSegments)
     THROW_SALOME_CORBA_EXCEPTION( "non-positive number of segments", SALOME::BAD_PARAM );
 }
 
+//=============================================================================
+/*!
+  Set an option value
+*/
+//=============================================================================
+
+void SMESH_Gen_i::SetOption(const char* name, const char* value)
+{
+  if ( name && value && strlen( value ) > 0 )
+  {
+    string msgToGUI; 
+    if ( strcmp(name, "historical_python_dump") == 0 )
+    {
+      myIsHistoricalPythonDump = ( value[0] == '1' || toupper(value[0]) == 'T' ); // 1 || true
+      msgToGUI = "preferences/SMESH/historical_python_dump/";
+      msgToGUI += myIsHistoricalPythonDump ? "true" : "false";
+    }
+    else if ( strcmp(name, "forget_mesh_on_hyp_modif") == 0 )
+    {
+      myToForgetMeshDataOnHypModif = ( value[0] == '1' || toupper(value[0]) == 'T' ); // 1 || true
+      msgToGUI = "preferences/SMESH/forget_mesh_on_hyp_modif/";
+      msgToGUI += myToForgetMeshDataOnHypModif ? "true" : "false";
+    }
+
+    // update preferences in case if SetOption() is invoked from python console
+    if ( !msgToGUI.empty() )
+    {
+      CORBA::Object_var obj = SMESH_Gen_i::GetNS()->Resolve( "/Kernel/Session" );
+      SALOME::Session_var session = SALOME::Session::_narrow( obj );
+      if ( !CORBA::is_nil( session ) )
+        session->emitMessageOneWay(msgToGUI.c_str());
+    }
+  }
+}
+
+//=============================================================================
+/*!
+  Return an option value
+*/
+//=============================================================================
+
+char* SMESH_Gen_i::GetOption(const char* name)
+{
+  if ( name )
+  {
+    if ( strcmp(name, "historical_python_dump") == 0 )
+    {
+      return CORBA::string_dup( myIsHistoricalPythonDump ? "true" : "false" );
+    }
+    if ( strcmp(name, "forget_mesh_on_hyp_modif") == 0 )
+    {
+      return CORBA::string_dup( myToForgetMeshDataOnHypModif ? "true" : "false" );
+    }
+  }
+  return CORBA::string_dup( "" );
+}
+
 //=============================================================================
 /*!
  *  SMESH_Gen_i::CreateMesh
@@ -895,7 +961,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMeshesFromUNV( const char* theFileName
     aStudyBuilder->CommitCommand();
     if ( !aSO->_is_nil() ) {
       // Update Python script
-      TPythonDump() << aSO << " = smeshgen.CreateMeshesFromUNV(r'" << theFileName << "')";
+      TPythonDump() << aSO << " = " << this << ".CreateMeshesFromUNV(r'" << theFileName << "')";
     }
   }
 
@@ -1157,6 +1223,47 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromCGNS( const char* theFileName,
   return aResult._retn();
 }
 
+//================================================================================
+/*!
+ * \brief Create a mesh and import data from a GMF file
+ */
+//================================================================================
+
+SMESH::SMESH_Mesh_ptr
+SMESH_Gen_i::CreateMeshesFromGMF( const char*             theFileName,
+                                  SMESH::ComputeError_out theError)
+    throw ( SALOME::SALOME_Exception )
+{
+  Unexpect aCatch(SALOME_SalomeException);
+
+  SMESH::SMESH_Mesh_var aMesh = createMesh();
+#ifdef WIN32
+  char bname[ _MAX_FNAME ];
+  _splitpath( theFileName, NULL, NULL, bname, NULL );
+  string aFileName = bname;
+#else
+  string aFileName = basename( theFileName );
+#endif
+  // publish mesh in the study
+  if ( CanPublishInStudy( aMesh ) ) {
+    SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder();
+    aStudyBuilder->NewCommand();  // There is a transaction
+    SALOMEDS::SObject_var aSO = PublishInStudy
+      ( myCurrentStudy, SALOMEDS::SObject::_nil(), aMesh.in(), aFileName.c_str() );
+    aStudyBuilder->CommitCommand();
+    if ( !aSO->_is_nil() ) {
+      // Update Python script
+      TPythonDump() << "("<< aSO << ", error) = " << this << ".CreateMeshesFromGMF(r'" << theFileName << "')";
+    }
+  }
+  SMESH_Mesh_i* aServant = dynamic_cast<SMESH_Mesh_i*>( GetServant( aMesh ).in() );
+  ASSERT( aServant );
+  theError = aServant->ImportGMFFile( theFileName );
+  aServant->GetImpl().GetMeshDS()->Modified();
+  return aMesh._retn();
+}
+
+
 //=============================================================================
 /*!
  *  SMESH_Gen_i::IsReadyToCompute
@@ -1555,6 +1662,7 @@ CORBA::Boolean SMESH_Gen_i::Compute( SMESH::SMESH_Mesh_ptr theMesh,
   try {
     // get mesh servant
     SMESH_Mesh_i* meshServant = dynamic_cast<SMESH_Mesh_i*>( GetServant( theMesh ).in() );
+    meshServant->Load();
     ASSERT( meshServant );
     if ( meshServant ) {
       // NPAL16168: "geometrical group edition from a submesh don't modifiy mesh computation"
@@ -1640,6 +1748,7 @@ SMESH::MeshPreviewStruct* SMESH_Gen_i::Precompute( SMESH::SMESH_Mesh_ptr theMesh
   try {
     // get mesh servant
     SMESH_Mesh_i* meshServant = dynamic_cast<SMESH_Mesh_i*>( GetServant( theMesh ).in() );
+    meshServant->Load();
     ASSERT( meshServant );
     if ( meshServant ) {
       // NPAL16168: "geometrical group edition from a submesh don't modifiy mesh computation"
@@ -2104,6 +2213,7 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
           SMESH_Mesh_i* anInitImpl = dynamic_cast<SMESH_Mesh_i*>( GetServant( anInitMesh ).in() );
           if ( anInitImpl ) {
             ::SMESH_Mesh& aInitLocMesh = anInitImpl->GetImpl();
+            aInitLocMesh.Load();
             SMESHDS_Mesh* anInitMeshDS = aInitLocMesh.GetMeshDS();
 
             TIDsMap nodesMap;
@@ -2119,17 +2229,20 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
             int anNbEdges   = 0;
             int anNbFaces   = 0;
             int anNbVolumes = 0;
+            int aNbBalls    = 0;
 
             SMESH::long_array_var anIDsNodes   = new SMESH::long_array();
             SMESH::long_array_var anIDsEdges   = new SMESH::long_array();
             SMESH::long_array_var anIDsFaces   = new SMESH::long_array();
             SMESH::long_array_var anIDsVolumes = new SMESH::long_array();
+            SMESH::long_array_var anIDsBalls   = new SMESH::long_array();
 
             if( theCommonGroups ) {
               anIDsNodes->length(   anInitMeshDS->NbNodes()   );
               anIDsEdges->length(   anInitMeshDS->NbEdges()   );
               anIDsFaces->length(   anInitMeshDS->NbFaces()   );
               anIDsVolumes->length( anInitMeshDS->NbVolumes() );
+              anIDsBalls->length(   anInitMeshDS->NbBalls() );
             }
 
             for ( int j = 0; itElems->more(); j++) {
@@ -2157,34 +2270,47 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
               }//nodes loop
 
               // creates a corresponding element on existent nodes in new mesh
-              if ( anElem->IsPoly() && anElemType == SMDSAbs_Volume )
+              switch ( anElem->GetEntityType() ) {
+              case SMDSEntity_Polyhedra:
+                if ( const SMDS_VtkVolume* aVolume =
+                     dynamic_cast<const SMDS_VtkVolume*> (anElem))
+                {
+                  aNewElem = aNewMeshDS->AddPolyhedralVolume(aNodesArray,
+                                                             aVolume->GetQuantities());
+                  elemsMap.insert(make_pair(anElem->GetID(), aNewElem->GetID()));
+                  if( theCommonGroups )
+                    anIDsVolumes[anNbVolumes++] = aNewElem->GetID();
+                }
+                break;
+              case SMDSEntity_Ball:
+                if ( const SMDS_BallElement* aBall =
+                     dynamic_cast<const SMDS_BallElement*> (anElem))
+                {
+                  aNewElem = aNewEditor.AddElement(aNodesArray, SMDSAbs_Ball,
+                                                   /*isPoly=*/false, /*id=*/0,
+                                                   aBall->GetDiameter() );
+                  elemsMap.insert(make_pair(anElem->GetID(), aNewElem->GetID()));
+                  if( theCommonGroups )
+                    anIDsBalls[aNbBalls++] = aNewElem->GetID();
+                }
+                break;
+              default:
                 {
-                  const SMDS_VtkVolume* aVolume =
-                    dynamic_cast<const SMDS_VtkVolume*> (anElem);
-                  if ( aVolume ) {
-                    aNewElem = aNewMeshDS->AddPolyhedralVolume(aNodesArray,
-                                                               aVolume->GetQuantities());
-                    elemsMap.insert(make_pair(anElem->GetID(), aNewElem->GetID()));
-                    if( theCommonGroups )
+                  aNewElem = aNewEditor.AddElement(aNodesArray,
+                                                   anElemType,
+                                                   anElem->IsPoly());
+                  elemsMap.insert(make_pair(anElem->GetID(), aNewElem->GetID()));
+                  if( theCommonGroups ) {
+                    if( anElemType == SMDSAbs_Edge )
+                      anIDsEdges[anNbEdges++] = aNewElem->GetID();
+                    else if( anElemType == SMDSAbs_Face )
+                      anIDsFaces[anNbFaces++] = aNewElem->GetID();
+                    else if( anElemType == SMDSAbs_Volume )
                       anIDsVolumes[anNbVolumes++] = aNewElem->GetID();
                   }
                 }
-              else {
-
-                aNewElem = aNewEditor.AddElement(aNodesArray,
-                                                 anElemType,
-                                                 anElem->IsPoly());
-                elemsMap.insert(make_pair(anElem->GetID(), aNewElem->GetID()));
-                if( theCommonGroups ) {
-                  if( anElemType == SMDSAbs_Edge )
-                    anIDsEdges[anNbEdges++] = aNewElem->GetID();
-                  else if( anElemType == SMDSAbs_Face )
-                    anIDsFaces[anNbFaces++] = aNewElem->GetID();
-                  else if( anElemType == SMDSAbs_Volume )
-                    anIDsVolumes[anNbVolumes++] = aNewElem->GetID();
-                }
               }
-            }//elems loop
+            } //elems loop
 
             // copy orphan nodes
             SMDS_NodeIteratorPtr  itNodes = anInitMeshDS->nodesIterator();
@@ -2213,7 +2339,7 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
             SMESH::ElementType aGroupType;
             CORBA::String_var aGroupName;
             if ( theCommonGroups ) {
-              for(aGroupType=SMESH::NODE;aGroupType<=SMESH::VOLUME;aGroupType=(SMESH::ElementType)(aGroupType+1)) {
+              for(aGroupType=SMESH::NODE;aGroupType<=SMESH::BALL;aGroupType=(SMESH::ElementType)(aGroupType+1)) {
                 string str = "Gr";
                 SALOMEDS::SObject_var aMeshSObj = ObjectToSObject( myCurrentStudy, anInitMesh );
                 if(aMeshSObj)
@@ -2243,6 +2369,11 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
                   anIDsVolumes->length(anNbVolumes);
                   anLen = anNbVolumes;
                   break;
+                case SMESH::BALL:
+                  str += "Balls";
+                  anIDsBalls->length(aNbBalls);
+                  anLen = aNbBalls;
+                  break;
                 default:
                   break;
                 }
@@ -2266,6 +2397,9 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
                   case SMESH::VOLUME:
                     aNewGroup->Add( anIDsVolumes );
                     break;
+                  case SMESH::BALL:
+                    aNewGroup->Add( anIDsBalls );
+                    break;
                   default:
                     break;
                   }
@@ -2278,8 +2412,8 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
             }
 
             // check that current group name and type don't have identical ones in union mesh
-            for (int i = 0; i < aListOfGroups->length(); i++) {
-              aGroup = aListOfGroups[i];
+            for (int iG = 0; iG < aListOfGroups->length(); iG++) {
+              aGroup = aListOfGroups[iG];
               aListOfNewGroups.clear();
               aGroupType = aGroup->GetType();
               aGroupName = aGroup->GetName();
@@ -2363,7 +2497,7 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
   aPythonDump << "], ";
   aPythonDump << theUniteIdenticalGroups << ", "
               << theMergeNodesAndElements << ", "
-              << theMergeTolerance << ")";
+              << TVar( theMergeTolerance ) << ")";
 
   delete pPythonDump; // enable python dump from GetGroups()
 
@@ -2375,13 +2509,8 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray,
 
   // IPAL21468 Change icon of compound because it need not be computed.
   SALOMEDS::SObject_var aMeshSObj = ObjectToSObject( myCurrentStudy, aNewMesh );
-  if( !aMeshSObj->_is_nil() ) {
-    SALOMEDS::GenericAttribute_var anAttr;
-    SALOMEDS::StudyBuilder_var aBuilder = myCurrentStudy->NewBuilder();
-    anAttr = aBuilder->FindOrCreateAttribute( aMeshSObj,"AttributePixMap" );
-    SALOMEDS::AttributePixMap_var aPixmap = SALOMEDS::AttributePixMap::_narrow(anAttr);
-    aPixmap->SetPixMap("ICON_SMESH_TREE_MESH");
-  }
+  SetPixMap( aMeshSObj, "ICON_SMESH_TREE_MESH" );
+
   if (aNewMeshDS)
     aNewMeshDS->Modified();
   return aNewMesh._retn();
@@ -2477,6 +2606,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CopyMesh(SMESH::SMESH_IDSource_ptr meshPart,
   while ( srcElemIt->more() )
   {
     const SMDS_MeshElement * elem = srcElemIt->next();
+    // find / add nodes
     nodes.resize( elem->NbNodes());
     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
     if ( toKeepIDs ) {
@@ -2499,22 +2629,30 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CopyMesh(SMESH::SMESH_IDSource_ptr meshPart,
         nodes[ iN ] = (const SMDS_MeshNode*) n2n->second;
       }
     }
+    // add elements
     if ( elem->GetType() != SMDSAbs_Node )
     {
       int ID = toKeepIDs ? elem->GetID() : 0;
       const SMDS_MeshElement * newElem;
-      if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
+      switch ( elem->GetEntityType() ) {
+      case SMDSEntity_Polyhedra:
         newElem = editor.GetMeshDS()->
           AddPolyhedralVolumeWithID( nodes,
                                      static_cast<const SMDS_VtkVolume*>(elem)->GetQuantities(),
-                                     elem->GetID());
-      else
+                                     ID);
+        break;
+      case SMDSEntity_Ball:
+        newElem = editor.AddElement( nodes, SMDSAbs_Ball, false, ID,
+                                     static_cast<const SMDS_BallElement*>(elem)->GetDiameter());
+        break;
+      default:
         newElem = editor.AddElement( nodes,elem->GetType(),elem->IsPoly(),ID);
 
       if ( toCopyGroups && !toKeepIDs )
         e2eMapByType[ elem->GetType() ].insert( make_pair( elem, newElem ));
+      }
     }
-  }
+  } // while ( srcElemIt->more() )
 
   // 4(b). Copy free nodes
 
@@ -2749,6 +2887,7 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
         if ( !CORBA::is_nil( anObject ) ) {
           SMESH::SMESH_Mesh_var myMesh = SMESH::SMESH_Mesh::_narrow( anObject ) ;
           if ( !myMesh->_is_nil() ) {
+            myMesh->Load(); // load from study file if not yet done
             TPythonDump pd; // not to dump GetGroups()
             SMESH::ListOfGroups_var groups = myMesh->GetGroups();
             pd << ""; // to avoid optimizing pd out
@@ -3300,7 +3439,7 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
 
             // groups root sub-branch
             SALOMEDS::SObject_var myGroupsBranch;
-            for ( int i = GetNodeGroupsTag(); i <= Get0DElementsGroupsTag(); i++ ) {
+            for ( int i = GetNodeGroupsTag(); i <= GetBallElementsGroupsTag(); i++ ) {
               found = gotBranch->FindSubObject( i, myGroupsBranch );
               if ( found ) {
                 char name_group[ 30 ];
@@ -3314,6 +3453,8 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
                   strcpy( name_group, "Groups of Volumes" );
                 else if ( i == Get0DElementsGroupsTag() )
                   strcpy( name_group, "Groups of 0D Elements" );
+                else if ( i == GetBallElementsGroupsTag() )
+                  strcpy( name_group, "Groups of Balls" );
 
                 aGroup = new HDFgroup( name_group, aTopGroup );
                 aGroup->CreateOnDisk();
@@ -3414,6 +3555,9 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
               // Flush current mesh information into MED file
               myWriter.Perform();
 
+              // save info on nb of elements
+              SMESH_PreMeshInfo::SaveToFile( myImpl, id, aFile );
+
               // maybe a shape was deleted in the study
               if ( !shapeRefFound && !mySMESHDSMesh->ShapeToMesh().IsNull() && hasShape) {
                 TopoDS_Shape nullShape;
@@ -3697,33 +3841,6 @@ void SMESH_Gen_i::loadGeomData( SALOMEDS::SComponent_ptr theCompRoot )
   SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
   aStudyBuilder->LoadWith( theCompRoot, GetGeomEngine() );
 }
-//=============================================================================
-/*!
- * \brief Creates SMDS_Position according to shape type
- */
-//=============================================================================
-
-class PositionCreator {
-public:
-  SMDS_PositionPtr MakePosition(const TopAbs_ShapeEnum type) {
-    return (this->*myFuncTable[ type ])();
-  }
-  PositionCreator() {
-    myFuncTable.resize( (size_t) TopAbs_SHAPE, & PositionCreator::defaultPosition );
-    myFuncTable[ TopAbs_SOLID  ] = & PositionCreator::volumePosition;
-    myFuncTable[ TopAbs_FACE   ] = & PositionCreator::facePosition;
-    myFuncTable[ TopAbs_EDGE   ] = & PositionCreator::edgePosition;
-    myFuncTable[ TopAbs_VERTEX ] = & PositionCreator::vertexPosition;
-  }
-private:
-  SMDS_PositionPtr edgePosition()    const { return SMDS_PositionPtr( new SMDS_EdgePosition  ); }
-  SMDS_PositionPtr facePosition()    const { return SMDS_PositionPtr( new SMDS_FacePosition  ); }
-  SMDS_PositionPtr volumePosition()  const { return SMDS_PositionPtr( new SMDS_SpacePosition ); }
-  SMDS_PositionPtr vertexPosition()  const { return SMDS_PositionPtr( new SMDS_VertexPosition); }
-  SMDS_PositionPtr defaultPosition() const { return SMDS_SpacePosition::originSpacePosition();  }
-  typedef SMDS_PositionPtr (PositionCreator:: * FmakePos)() const;
-  vector<FmakePos> myFuncTable;
-};
 
 //=============================================================================
 /*!
@@ -3793,8 +3910,10 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
     return false;
   }
 
-  DriverMED_R_SMESHDS_Mesh myReader;
-  myReader.SetFile( meshfile.ToCString() );
+  TPythonDump pd; // prevent dump during loading
+
+  // DriverMED_R_SMESHDS_Mesh myReader;
+  // myReader.SetFile( meshfile.ToCString() );
 
   // For PAL13473 ("Repetitive mesh") implementation.
   // New dependencies between SMESH objects are established:
@@ -4082,18 +4201,6 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
             }
           }
 
-          // issue 0020693. Restore _isModified flag
-          if( aTopGroup->ExistInternalObject( "_isModified" ) )
-          {
-            aDataset = new HDFdataset( "_isModified", aTopGroup );
-            aDataset->OpenOnDisk();
-            size = aDataset->GetSize();
-            int* isModified = new int[ size ];
-            aDataset->ReadFromDisk( isModified );
-            aDataset->CloseOnDisk();
-            myNewMeshImpl->GetImpl().SetIsModified( bool(*isModified));
-          }
-
           // issue 20918. Restore Persistent Id of SMESHDS_Mesh
           if( aTopGroup->ExistInternalObject( "meshPersistentId" ) )
           {
@@ -4107,7 +4214,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
           }
         }
       }
-    }
+    } // reading MESHes
 
     // As all object that can be referred by hypothesis are created,
     // we can restore hypothesis data
@@ -4127,8 +4234,8 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
     {
       aTopGroup                   = meshi_group->second;
       SMESH_Mesh_i* myNewMeshImpl = meshi_group->first;
-      ::SMESH_Mesh& myLocMesh     = myNewMeshImpl->GetImpl();
-      SMESHDS_Mesh* mySMESHDSMesh = myLocMesh.GetMeshDS();
+      //::SMESH_Mesh& myLocMesh     = myNewMeshImpl->GetImpl();
+      //SMESHDS_Mesh* mySMESHDSMesh = myLocMesh.GetMeshDS();
 
       GEOM::GEOM_Object_var aShapeObject = myNewMeshImpl->GetShapeToMesh();
       bool hasData = false;
@@ -4149,9 +4256,9 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
         aDataset->CloseOnDisk();
         if ( strcmp( strHasData, "1") == 0 ) {
           // read mesh data from MED file
-          myReader.SetMesh( mySMESHDSMesh );
-          myReader.SetMeshId( id );
-          myReader.Perform();
+          // myReader.SetMesh( mySMESHDSMesh );
+          // myReader.SetMeshId( id );
+          // myReader.Perform();
           hasData = true;
         }
       }
@@ -4175,9 +4282,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
             char* refFromFile = new char[ size ];
             aDataset->ReadFromDisk( refFromFile );
             aDataset->CloseOnDisk();
-
             // san - it is impossible to recover applied algorithms using their entries within Load() method
-
             //SALOMEDS::SObject_var hypSO = myCurrentStudy->FindObjectID( refFromFile );
             //CORBA::Object_var hypObject = SObjectToObject( hypSO );
             int id = atoi( refFromFile );
@@ -4213,9 +4318,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
             char* refFromFile = new char[ size ];
             aDataset->ReadFromDisk( refFromFile );
             aDataset->CloseOnDisk();
-
             // san - it is impossible to recover applied hypotheses using their entries within Load() method
-
             //SALOMEDS::SObject_var hypSO = myCurrentStudy->FindObjectID( refFromFile );
             //CORBA::Object_var hypObject = SObjectToObject( hypSO );
             int id = atoi( refFromFile );
@@ -4234,7 +4337,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
         aGroup->CloseOnDisk();
       }
 
-      // --> try to find submeshes containers for each type of submesh
+      // --> try to find SUB-MESHES containers for each type of submesh
       for ( int j = GetSubMeshOnVertexTag(); j <= GetSubMeshOnCompoundTag(); j++ ) {
         char name_meshgroup[ 30 ];
         if ( j == GetSubMeshOnVertexTag() )
@@ -4371,225 +4474,21 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
                     }
                   }
                 }
-                // close "applied hypotheses" HDF group
+                // close "APPLIED HYPOTHESES" hdf group
                 aSubSubGroup->CloseOnDisk();
               }
 
-              // close submesh HDF group
+              // close SUB-MESH hdf group
               aSubGroup->CloseOnDisk();
             }
           }
-          // close submeshes containers HDF group
+          // close SUB-MESHES containers hdf group
           aGroup->CloseOnDisk();
         }
       }
 
-      if(hasData) {
-
-        // Read sub-meshes
-        // ----------------
-        if(MYDEBUG) MESSAGE("Create all sub-meshes");
-        bool submeshesInFamilies = ( ! aTopGroup->ExistInternalObject( "Submeshes" ));
-        if ( submeshesInFamilies ) // from MED
-        {
-          // old way working before fix of PAL 12992
-          myReader.CreateAllSubMeshes();
-        }
-        else
-        {
-          // open a group
-          aGroup = new HDFgroup( "Submeshes", aTopGroup );
-          aGroup->OpenOnDisk();
-
-          int maxID = Max( mySMESHDSMesh->MaxSubMeshIndex(), mySMESHDSMesh->MaxShapeIndex() );
-          vector< SMESHDS_SubMesh * > subMeshes( maxID + 1, (SMESHDS_SubMesh*) 0 );
-          vector< TopAbs_ShapeEnum  > smType   ( maxID + 1, TopAbs_SHAPE );
-
-          PositionCreator aPositionCreator;
-
-          SMDS_NodeIteratorPtr nIt = mySMESHDSMesh->nodesIterator();
-          SMDS_ElemIteratorPtr eIt = mySMESHDSMesh->elementsIterator();
-          for ( int isNode = 0; isNode < 2; ++isNode )
-          {
-            string aDSName( isNode ? "Node Submeshes" : "Element Submeshes");
-            if ( aGroup->ExistInternalObject( (char*) aDSName.c_str() ))
-            {
-              aDataset = new HDFdataset( (char*) aDSName.c_str(), aGroup );
-              aDataset->OpenOnDisk();
-              // read submesh IDs for all elements sorted by ID
-              int nbElems = aDataset->GetSize();
-              int* smIDs = new int [ nbElems ];
-              aDataset->ReadFromDisk( smIDs );
-              aDataset->CloseOnDisk();
-
-              // get elements sorted by ID
-              TIDSortedElemSet elemSet;
-              if ( isNode )
-                while ( nIt->more() ) elemSet.insert( nIt->next() );
-              else
-                while ( eIt->more() ) elemSet.insert( eIt->next() );
-              //ASSERT( elemSet.size() == nbElems ); -- issue 20182
-              // -- Most probably a bad study was saved when there were
-              // not fixed bugs in SMDS_MeshInfo
-              if ( elemSet.size() < nbElems ) {
-#ifdef _DEBUG_
-                cout << "SMESH_Gen_i::Load(), warning: Node position data is invalid" << endl;
-#endif
-                nbElems = elemSet.size();
-              }
-              // add elements to submeshes
-              TIDSortedElemSet::iterator iE = elemSet.begin();
-              for ( int i = 0; i < nbElems; ++i, ++iE )
-              {
-                int smID = smIDs[ i ];
-                if ( smID == 0 ) continue;
-                const SMDS_MeshElement* elem = *iE;
-                if( smID > maxID ) {
-                  // corresponding subshape no longer exists: maybe geom group has been edited
-                  if ( myNewMeshImpl->HasShapeToMesh() )
-                    mySMESHDSMesh->RemoveElement( elem );
-                  continue;
-                }
-                // get or create submesh
-                SMESHDS_SubMesh* & sm = subMeshes[ smID ];
-                if ( ! sm ) {
-                  sm = mySMESHDSMesh->NewSubMesh( smID );
-                  smType[ smID ] = mySMESHDSMesh->IndexToShape( smID ).ShapeType();
-                }
-                // add
-                if ( isNode ) {
-                  SMDS_PositionPtr pos = aPositionCreator.MakePosition( smType[ smID ]);
-                  SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( static_cast<const SMDS_MeshNode*>( elem ));
-                  node->SetPosition( pos );
-                  sm->AddNode( node );
-                } else {
-                  sm->AddElement( elem );
-                }
-              }
-              delete [] smIDs;
-            }
-          }
-        } // end reading submeshes
-
-        // Read node positions on sub-shapes (SMDS_Position)
-
-        if ( aTopGroup->ExistInternalObject( "Node Positions" ))
-        {
-          // There are 5 datasets to read:
-          // "Nodes on Edges" - ID of node on edge
-          // "Edge positions" - U parameter on node on edge
-          // "Nodes on Faces" - ID of node on face
-          // "Face U positions" - U parameter of node on face
-          // "Face V positions" - V parameter of node on face
-          const char* aEid_DSName = "Nodes on Edges";
-          const char* aEu_DSName  = "Edge positions";
-          const char* aFu_DSName  = "Face U positions";
-          //char* aFid_DSName = "Nodes on Faces";
-          //char* aFv_DSName  = "Face V positions";
-
-          // data to retrieve
-          int nbEids = 0, nbFids = 0;
-          int *aEids = 0, *aFids  = 0;
-          double *aEpos = 0, *aFupos = 0, *aFvpos = 0;
-
-          // open a group
-          aGroup = new HDFgroup( "Node Positions", aTopGroup );
-          aGroup->OpenOnDisk();
-
-          // loop on 5 data sets
-          int aNbObjects = aGroup->nInternalObjects();
-          for ( int i = 0; i < aNbObjects; i++ )
-          {
-            // identify dataset
-            char aDSName[ HDF_NAME_MAX_LEN+1 ];
-            aGroup->InternalObjectIndentify( i, aDSName );
-            // read data
-            aDataset = new HDFdataset( aDSName, aGroup );
-            aDataset->OpenOnDisk();
-            if ( aDataset->GetType() == HDF_FLOAT64 ) // Positions
-            {
-              double* pos = new double [ aDataset->GetSize() ];
-              aDataset->ReadFromDisk( pos );
-              // which one?
-              if ( strncmp( aDSName, aEu_DSName, strlen( aEu_DSName )) == 0 )
-                aEpos = pos;
-              else if ( strncmp( aDSName, aFu_DSName, strlen( aFu_DSName )) == 0 )
-                aFupos = pos;
-              else
-                aFvpos = pos;
-            }
-            else // NODE IDS
-            {
-              int aSize = aDataset->GetSize();
-
-              // for reading files, created from 18.07.2005 till 10.10.2005
-              if (aDataset->GetType() == HDF_STRING)
-                aSize /= sizeof(int);
-
-              int* ids = new int [aSize];
-              aDataset->ReadFromDisk( ids );
-              // on face or nodes?
-              if ( strncmp( aDSName, aEid_DSName, strlen( aEid_DSName )) == 0 ) {
-                aEids = ids;
-                nbEids = aSize;
-              }
-              else {
-                aFids = ids;
-                nbFids = aSize;
-              }
-            }
-            aDataset->CloseOnDisk();
-          } // loop on 5 datasets
-
-          // Set node positions on edges or faces
-          for ( int onFace = 0; onFace < 2; onFace++ )
-          {
-            int nbNodes = ( onFace ? nbFids : nbEids );
-            if ( nbNodes == 0 ) continue;
-            int* aNodeIDs = ( onFace ? aFids : aEids );
-            double* aUPos = ( onFace ? aFupos : aEpos );
-            double* aVPos = ( onFace ? aFvpos : 0 );
-            // loop on node IDs
-            for ( int iNode = 0; iNode < nbNodes; iNode++ )
-            {
-              const SMDS_MeshNode* node = mySMESHDSMesh->FindNode( aNodeIDs[ iNode ]);
-              if ( !node ) continue; // maybe removed while Loading() if geometry changed
-              SMDS_PositionPtr aPos = node->GetPosition();
-              ASSERT( aPos );
-              if ( onFace ) {
-                // ASSERT( aPos->GetTypeOfPosition() == SMDS_TOP_FACE );-- issue 20182
-                // -- Most probably a bad study was saved when there were
-                // not fixed bugs in SMDS_MeshInfo
-                if ( aPos->GetTypeOfPosition() == SMDS_TOP_FACE ) {
-                  SMDS_FacePosition* fPos = const_cast<SMDS_FacePosition*>
-                    ( static_cast<const SMDS_FacePosition*>( aPos ));
-                  fPos->SetUParameter( aUPos[ iNode ]);
-                  fPos->SetVParameter( aVPos[ iNode ]);
-                }
-              }
-              else {
-                // ASSERT( aPos->GetTypeOfPosition() == SMDS_TOP_EDGE );-- issue 20182
-                if ( aPos->GetTypeOfPosition() == SMDS_TOP_EDGE ) {
-                  SMDS_EdgePosition* fPos = const_cast<SMDS_EdgePosition*>
-                    ( static_cast<const SMDS_EdgePosition*>( aPos ));
-                  fPos->SetUParameter( aUPos[ iNode ]);
-                }
-              }
-            }
-          }
-          if ( aEids ) delete [] aEids;
-          if ( aFids ) delete [] aFids;
-          if ( aEpos ) delete [] aEpos;
-          if ( aFupos ) delete [] aFupos;
-          if ( aFvpos ) delete [] aFvpos;
-
-          aGroup->CloseOnDisk();
-
-        } // if ( aTopGroup->ExistInternalObject( "Node Positions" ) )
-      } // if ( hasData )
-
-      // try to get groups
-      for ( int ii = GetNodeGroupsTag(); ii <= Get0DElementsGroupsTag(); ii++ ) {
+      // try to get GROUPS
+      for ( int ii = GetNodeGroupsTag(); ii <= GetBallElementsGroupsTag(); ii++ ) {
         char name_group[ 30 ];
         if ( ii == GetNodeGroupsTag() )
           strcpy( name_group, "Groups of Nodes" );
@@ -4601,6 +4500,8 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
           strcpy( name_group, "Groups of Volumes" );
         else if ( ii == Get0DElementsGroupsTag() )
           strcpy( name_group, "Groups of 0D Elements" );
+        else if ( ii == GetBallElementsGroupsTag() )
+          strcpy( name_group, "Groups of Balls" );
 
         if ( aTopGroup->ExistInternalObject( name_group ) ) {
           aGroup = new HDFgroup( name_group, aTopGroup );
@@ -4708,16 +4609,25 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
               }
 
               // Fill group with contents from MED file
-              SMESHDS_Group* aGrp = dynamic_cast<SMESHDS_Group*>( aGroupBaseDS );
-              if ( aGrp )
-                myReader.GetGroup( aGrp );
+              // SMESHDS_Group* aGrp = dynamic_cast<SMESHDS_Group*>( aGroupBaseDS );
+              // if ( aGrp )
+              //   myReader.GetGroup( aGrp );
             }
           }
           aGroup->CloseOnDisk();
         }
+      } // reading GROUPs
+
+      // instead of reading mesh data, we read only brief information of all
+      // objects: mesh, groups, sub-meshes (issue 0021208 )
+      if ( hasData )
+      {
+        SMESH_PreMeshInfo::LoadFromFile( myNewMeshImpl, id,
+                                         meshfile.ToCString(), filename.ToCString(),
+                                         !isMultiFile );
       }
 
-      // read submeh order if any
+      // read Sub-Mesh ORDER if any
       if( aTopGroup->ExistInternalObject( "Mesh Order" ) ) {
         aDataset = new HDFdataset( "Mesh Order", aTopGroup );
         aDataset->OpenOnDisk();
@@ -4744,7 +4654,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
       hyp->UpdateAsMeshesRestored();
     }
 
-    // notify algos on completed restoration
+    // notify algos on completed restoration to set sub-mesh event listeners
     for ( meshi_group = meshGroupList.begin(); meshi_group != meshGroupList.end(); ++meshi_group )
     {
       SMESH_Mesh_i* myNewMeshImpl = meshi_group->first;
@@ -4770,7 +4680,24 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
 
   // Remove temporary files created from the stream
   if ( !isMultiFile )
-    SALOMEDS_Tool::RemoveTemporaryFiles( tmpDir.ToCString(), aFileSeq.in(), true );
+  {
+    SMESH_File meshFile( meshfile.ToCString() );
+    if ( !meshFile ) // no meshfile exists
+    {
+      SALOMEDS_Tool::RemoveTemporaryFiles( tmpDir.ToCString(), aFileSeq.in(), true );
+    }
+    else
+    {
+      Engines::Container_var container = GetContainerRef();
+      if ( Engines_Container_i* container_i = SMESH::DownCast<Engines_Container_i*>( container ))
+      {
+        container_i->registerTemporaryFile( filename.ToCString() );
+        container_i->registerTemporaryFile( meshfile.ToCString() );
+        container_i->registerTemporaryFile( tmpDir.ToCString() );
+      }
+    }
+  }
+  pd << ""; // prevent optimizing pd out
 
   INFOS( "SMESH_Gen_i::Load completed" );
   return true;
@@ -4828,8 +4755,9 @@ void SMESH_Gen_i::Close( SALOMEDS::SComponent_ptr theComponent )
   if(MYDEBUG) MESSAGE( "SMESH_Gen_i::Close" );
 
   // set correct current study
-  if (theComponent->GetStudy()->StudyId() != GetCurrentStudyID())
-    SetCurrentStudy(theComponent->GetStudy());
+  SALOMEDS::Study_var study = theComponent->GetStudy();
+  if ( study->StudyId() != GetCurrentStudyID())
+    setCurrentStudy( study, /*IsBeingClosed=*/true );
 
   // Clear study contexts data
   int studyId = GetCurrentStudyID();
@@ -4856,6 +4784,9 @@ void SMESH_Gen_i::Close( SALOMEDS::SComponent_ptr theComponent )
 //     context->myDocument = 0;
 //   }
 
+  // remove the tmp files meshes are loaded from
+  SMESH_PreMeshInfo::RemoveStudyFiles_TMP_METHOD( theComponent );
+
   myCurrentStudy = SALOMEDS::Study::_nil();
   return;
 }