Salome HOME
31cd9aeb783702992df00d8484d42bb9fbc473d1
[modules/smesh.git] / src / SMESH_I / SMESH_PreMeshInfo.cxx
1 // Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File      : SMESH_PreMeshInfo.cxx
23 // Created   : Fri Feb 10 17:36:39 2012
24 // Author    : Edward AGAPOV (eap)
25 //
26
27 #include "SMESH_PreMeshInfo.hxx"
28
29 #include "DriverMED_R_SMESHDS_Mesh.h"
30 #include "SMDS_EdgePosition.hxx"
31 #include "SMDS_FacePosition.hxx"
32 #include "SMDS_SpacePosition.hxx"
33 #include "SMDS_VertexPosition.hxx"
34 #include "SMESHDS_Group.hxx"
35 #include "SMESHDS_GroupOnFilter.hxx"
36 #include "SMESH_Gen_i.hxx"
37 #include "SMESH_Group_i.hxx"
38 #include "SMESH_Mesh_i.hxx"
39 #include "SMESH_subMesh_i.hxx"
40
41 #include <HDFarray.hxx>
42 #include <HDFdataset.hxx>
43 #include <HDFfile.hxx>
44 #include <HDFgroup.hxx>
45 #include <MED_Factory.hxx>
46 #include <SALOMEDS_Tool.hxx>
47
48 #include <Standard_ErrorHandler.hxx>
49 #include <Standard_Failure.hxx>
50 #include <TopoDS_Iterator.hxx>
51 #include <TopoDS_Shape.hxx>
52
53 #include CORBA_SERVER_HEADER(SALOME_Session)
54
55 #define MYDEBUGOUT(msg) //std::cout << msg << std::endl;
56
57 //================================================================================
58 #define PreMeshInfo_TRY \
59   try { OCC_CATCH_SIGNALS
60 //================================================================================
61 #define PreMeshInfo_CATCH }                                             \
62   catch (Standard_Failure& ex) {                                        \
63     onExceptionCaught(SMESH_Comment("OCC Exception caught: \t")<<ex.GetMessageString()); \
64   }                                                                     \
65   catch ( const std::exception& ex) {                                   \
66     onExceptionCaught(SMESH_Comment("Exception caught: \t")<<ex.what()); \
67   }                                                                     \
68   catch (...) {                                                         \
69     onExceptionCaught("Unknown Exception caught");                      \
70   }
71 //================================================================================
72
73 namespace
74 {
75   enum {  GroupOnFilter_OutOfDate = -1 };
76
77   // a map to count not yet loaded meshes 
78   static map< int, int > theStudyIDToMeshCounter;
79
80   //================================================================================
81   /*!
82    * \brief Counts not fully loaded meshes
83    */
84   //================================================================================
85
86   void meshInfoLoaded( SMESH_Mesh_i* mesh )
87   {
88     map< int, int >::iterator id2counter =
89       theStudyIDToMeshCounter.insert( make_pair( (int) mesh->GetStudyId(), 0 )).first;
90     id2counter->second++;
91   }
92   //================================================================================
93   /*!
94    * \brief Removes temporary files if none of meshes needs them
95    */
96   //================================================================================
97
98   void filesNoMoreNeeded(SMESH_Mesh_i* mesh,
99                          std::string   medFile,
100                          std::string   hdfFile)
101   {
102     if ( --theStudyIDToMeshCounter[ (int) mesh->GetStudyId() ] == 0 )
103     {
104       string tmpDir = SALOMEDS_Tool::GetDirFromPath( hdfFile );
105
106       SALOMEDS::ListOfFileNames_var aFiles = new SALOMEDS::ListOfFileNames;
107       aFiles->length(2);
108       medFile = SALOMEDS_Tool::GetNameFromPath( medFile ) + ".med";
109       hdfFile = SALOMEDS_Tool::GetNameFromPath( hdfFile ) + ".hdf";
110       aFiles[0] = medFile.c_str();
111       aFiles[1] = hdfFile.c_str();
112
113       SALOMEDS_Tool::RemoveTemporaryFiles( tmpDir.c_str(), aFiles.in(), true );
114     }
115   }
116
117   //================================================================================
118   /*!
119    * \brief Method useful only to set a breakpoint to debug in case of exception
120    */
121   //================================================================================
122
123   void onExceptionCaught(const string& msg)
124   {
125     INFOS( msg );
126     MYDEBUGOUT( msg );
127   }
128
129   //=============================================================================
130   /*!
131    * \brief Class sending signals on start and finish of loading
132    */
133   //=============================================================================
134
135   class SignalToGUI
136   {
137     string              _messagePrefix;
138     SALOME::Session_var _session;
139   public:
140     SignalToGUI( SMESH_Mesh_i* mesh )
141     {
142       SMESH_Gen_i* gen = SMESH_Gen_i::GetSMESHGen();
143       SALOMEDS::Study_var study = gen->GetCurrentStudy();
144       if ( !study->_is_nil() && study->StudyId() == mesh->GetStudyId() )
145       {
146         SALOMEDS::SObject_var meshSO = gen->ObjectToSObject(study, mesh->_this() );
147         CORBA::Object_var obj = gen->GetNS()->Resolve( "/Kernel/Session" );
148         _session = SALOME::Session::_narrow( obj );
149         if ( !meshSO->_is_nil() && !_session->_is_nil() )
150         {
151           CORBA::String_var meshEntry = meshSO->GetID();
152           _messagePrefix = "mesh_loading/";
153           _messagePrefix += meshEntry.in();
154
155           string msgToGUI = _messagePrefix + "/";
156           msgToGUI += SMESH_Comment( mesh->NbNodes() );
157           msgToGUI += "/";
158           msgToGUI += SMESH_Comment( mesh->NbElements() );
159
160           _session->emitMessageOneWay( msgToGUI.c_str());
161         }
162       }
163     }
164     void sendStop()
165     {
166       if ( !_messagePrefix.empty() )
167       {
168         string msgToGUI = _messagePrefix + "/stop";
169         _session->emitMessageOneWay( msgToGUI.c_str());
170         _messagePrefix.clear();
171       }
172     }
173     ~SignalToGUI() { sendStop(); }
174   };
175
176   //=============================================================================
177   /*!
178    * \brief Creates SMDS_Position according to shape type
179    */
180   //=============================================================================
181
182   class PositionCreator {
183   public:
184     SMDS_PositionPtr MakePosition(const TopAbs_ShapeEnum type) {
185       return (this->*myFuncTable[ type ])();
186     }
187     PositionCreator() {
188       myFuncTable.resize( (size_t) TopAbs_SHAPE, & PositionCreator::defaultPosition );
189       myFuncTable[ TopAbs_SOLID  ] = & PositionCreator::volumePosition;
190       myFuncTable[ TopAbs_FACE   ] = & PositionCreator::facePosition;
191       myFuncTable[ TopAbs_EDGE   ] = & PositionCreator::edgePosition;
192       myFuncTable[ TopAbs_VERTEX ] = & PositionCreator::vertexPosition;
193     }
194   private:
195     SMDS_PositionPtr edgePosition()    const { return SMDS_PositionPtr( new SMDS_EdgePosition  ); }
196     SMDS_PositionPtr facePosition()    const { return SMDS_PositionPtr( new SMDS_FacePosition  ); }
197     SMDS_PositionPtr volumePosition()  const { return SMDS_PositionPtr( new SMDS_SpacePosition ); }
198     SMDS_PositionPtr vertexPosition()  const { return SMDS_PositionPtr( new SMDS_VertexPosition); }
199     SMDS_PositionPtr defaultPosition() const { return SMDS_SpacePosition::originSpacePosition();  }
200     typedef SMDS_PositionPtr (PositionCreator:: * FmakePos)() const;
201     vector<FmakePos> myFuncTable;
202   };
203
204   //================================================================================
205   /*!
206    * \brief Returns ids of simple shapes composing a complex one
207    */
208   //================================================================================
209
210   vector<int> getSimpleSubMeshIds( SMESHDS_Mesh* meshDS, int shapeId )
211   {
212     vector<int> ids;
213
214     list<TopoDS_Shape> shapeQueue( 1, meshDS->IndexToShape( shapeId ));
215     list<TopoDS_Shape>::iterator shape = shapeQueue.begin();
216     for ( ; shape != shapeQueue.end(); ++shape )
217     {
218       if ( shape->IsNull() ) continue;
219       if ( shape->ShapeType() == TopAbs_COMPOUND ||
220            shape->ShapeType() == TopAbs_COMPSOLID )
221       {
222         for ( TopoDS_Iterator it( *shape ); it.More(); it.Next() )
223           shapeQueue.push_back( it.Value() );
224       }
225       else
226       {
227         ids.push_back( meshDS->ShapeToIndex( *shape ));
228       }
229     }
230     return ids;
231   }
232
233   //================================================================================
234   /*!
235    * \brief Return a map< EGeometrieElement, SMDSAbs_EntityType >
236    */
237   //================================================================================
238
239   typedef map< MED::EGeometrieElement, SMDSAbs_EntityType > Tmed2smeshElemTypeMap;
240   const Tmed2smeshElemTypeMap& med2smeshElemTypeMap()
241   {
242     static map< MED::EGeometrieElement, SMDSAbs_EntityType> med2smeshTypes;
243     if ( med2smeshTypes.empty() )
244     {
245       med2smeshTypes[ MED::ePOINT1   ] = SMDSEntity_0D                ;
246       med2smeshTypes[ MED::eSEG2     ] = SMDSEntity_Edge              ;
247       med2smeshTypes[ MED::eSEG3     ] = SMDSEntity_Quad_Edge         ;
248       med2smeshTypes[ MED::eTRIA3    ] = SMDSEntity_Triangle          ;
249       med2smeshTypes[ MED::eTRIA6    ] = SMDSEntity_Quad_Triangle     ;
250       med2smeshTypes[ MED::eQUAD4    ] = SMDSEntity_Quadrangle        ;
251       med2smeshTypes[ MED::eQUAD8    ] = SMDSEntity_Quad_Quadrangle   ;
252       med2smeshTypes[ MED::eQUAD9    ] = SMDSEntity_BiQuad_Quadrangle ;
253       med2smeshTypes[ MED::eTETRA4   ] = SMDSEntity_Tetra             ;
254       med2smeshTypes[ MED::ePYRA5    ] = SMDSEntity_Pyramid           ;
255       med2smeshTypes[ MED::ePENTA6   ] = SMDSEntity_Penta             ;
256       med2smeshTypes[ MED::eHEXA8    ] = SMDSEntity_Hexa              ;
257       med2smeshTypes[ MED::eOCTA12   ] = SMDSEntity_Hexagonal_Prism   ;
258       med2smeshTypes[ MED::eTETRA10  ] = SMDSEntity_Quad_Tetra        ;
259       med2smeshTypes[ MED::ePYRA13   ] = SMDSEntity_Quad_Pyramid      ;
260       med2smeshTypes[ MED::ePENTA15  ] = SMDSEntity_Quad_Penta        ;
261       med2smeshTypes[ MED::eHEXA20   ] = SMDSEntity_Quad_Hexa         ;
262       med2smeshTypes[ MED::eHEXA27   ] = SMDSEntity_TriQuad_Hexa      ;
263       med2smeshTypes[ MED::ePOLYGONE ] = SMDSEntity_Polygon           ;
264       med2smeshTypes[ MED::ePOLYEDRE ] = SMDSEntity_Polyhedra         ;
265       med2smeshTypes[ MED::eNONE     ] = SMDSEntity_Node              ;
266     }
267     return med2smeshTypes;
268   }
269
270   //================================================================================
271   /*!
272    * \brief Return a vector<MED::EGeometrieElement> intended to retrieve
273    *        MED::EGeometrieElement by SMDSAbs_EntityType
274    */
275   //================================================================================
276
277   const vector<MED::EGeometrieElement>& mesh2medElemType()
278   {
279     static vector<MED::EGeometrieElement> mesh2medElemTypes;
280     if ( mesh2medElemTypes.empty() )
281     {
282       mesh2medElemTypes.resize( SMDSEntity_Last + 1 );
283       Tmed2smeshElemTypeMap::const_iterator me2sme    = med2smeshElemTypeMap().begin();
284       Tmed2smeshElemTypeMap::const_iterator me2smeEnd = med2smeshElemTypeMap().end();
285       for ( ; me2sme != me2smeEnd; ++me2sme )
286         mesh2medElemTypes[ me2sme->second ] = me2sme->first;
287     }
288     return mesh2medElemTypes;
289   }
290
291   //================================================================================
292   /*!
293    * \brief Writes meshInfo into a HDF file
294    */
295   //================================================================================
296
297   void meshInfo2hdf( SMESH::long_array_var meshInfo,
298                      const std::string&    name,
299                      HDFgroup*             hdfGroup)
300   {
301     // we use med identification of element (MED::EGeometrieElement>) types
302     // but not enum SMDSAbs_EntityType because values of SMDSAbs_EntityType may
303     // change at insertion of new items in the middle.
304     const vector<MED::EGeometrieElement>& medTypes = mesh2medElemType();
305
306     vector<int> data;
307
308     for ( size_t i = 0; i < meshInfo->length(); ++i )
309       if ( meshInfo[i] > 0 )
310       {
311         data.push_back( medTypes[ i ] );
312         data.push_back( meshInfo[ i ] );
313       }
314
315     if ( !data.empty() )
316     {
317       hdf_size datasetSize[] = { data.size() };
318       HDFarray* anArray = new HDFarray(0, HDF_INT32, 1, datasetSize);
319       anArray->CreateOnDisk();
320       datasetSize[0] = 1;
321       HDFdataset* dataset = new HDFdataset( name.c_str(), hdfGroup, HDF_ARRAY, datasetSize, 1 );
322       dataset->SetArrayId(anArray->GetId());
323       dataset->CreateOnDisk();
324       dataset->WriteOnDisk( & data[0]  );
325       dataset->CloseOnDisk();
326       anArray->CloseOnDisk();
327     }
328   }
329 }
330
331 //================================================================================
332 /*!
333  * \brief Reads meshInfo from a HDF file
334  */
335 //================================================================================
336
337 void SMESH_PreMeshInfo::hdf2meshInfo( const std::string& name,
338                                       HDFgroup*          hdfGroup)
339 {
340   if ( hdfGroup->ExistInternalObject( name.c_str()) )
341   {
342     HDFdataset* dataset = new HDFdataset( name.c_str(), hdfGroup );
343     dataset->OpenOnDisk();
344
345     // hdf_size datasetSize[ 1 ];
346     // HDFarray *array = new HDFarray(dataset);
347     // array->GetDim( datasetSize );
348     int size = dataset->GetSize();
349
350     int info[ SMDSEntity_Last * 2 ];
351     dataset->ReadFromDisk( info );
352     dataset->CloseOnDisk();
353
354     const Tmed2smeshElemTypeMap& med2smesh = med2smeshElemTypeMap();
355     Tmed2smeshElemTypeMap::const_iterator me2sme, me2smeEnd = med2smesh.end();
356     for ( int i = 0; i < size /**datasetSize*/;  )
357     {
358       int medType = info[i++];
359       int nbElems = info[i++];
360       me2sme = med2smesh.find( (MED::EGeometrieElement) medType );
361       if ( me2sme != me2smeEnd )
362         setNb( me2sme->second, nbElems );
363     }
364   }
365   _isInfoOk = true;
366
367   if ( NbNodes() == GroupOnFilter_OutOfDate ) // case of !SMESHDS_GroupOnFilter::IsUpToDate()
368   {
369     _isInfoOk = false;
370     setNb( SMDSEntity_Node, 0 );
371   }
372 }
373
374 //================================================================================
375 /*!
376  * \brief Constructor callable by SMESH_PreMeshInfo only
377  */
378 //================================================================================
379
380 SMESH_PreMeshInfo::SMESH_PreMeshInfo(SMESH_Mesh_i*      mesh,
381                                      const int          meshID,
382                                      const std::string& medFile,
383                                      const std::string& hdfFile)
384   : _medFileName( medFile ),
385     _hdfFileName( hdfFile ),
386     _toRemoveFiles( false ),
387     _meshID( meshID ),
388     _mesh( mesh ),
389     _isInfoOk( false ),
390     _elemCounter( 0 )
391 {
392 }
393
394 //================================================================================
395 /*!
396  * \brief Release temporary files
397  */
398 //================================================================================
399
400 SMESH_PreMeshInfo::~SMESH_PreMeshInfo()
401 {
402   if ( _toRemoveFiles ) // it can be true only for SMESH_PreMeshInfo of the mesh
403     filesNoMoreNeeded( _mesh, _medFileName, _hdfFileName );
404
405   _toRemoveFiles = false;
406 }
407
408 //================================================================================
409 /*!
410  * \brief fills SMESH_PreMeshInfo field of all objects of mesh
411  */
412 //================================================================================
413
414 void SMESH_PreMeshInfo::LoadFromFile( SMESH_Mesh_i*      mesh,
415                                       const int          meshID,
416                                       const std::string& medFile,
417                                       const std::string& hdfFile,
418                                       const bool         toRemoveFiles)
419 {
420   PreMeshInfo_TRY;
421
422   SMESH_PreMeshInfo* meshPreInfo = new SMESH_PreMeshInfo( mesh,meshID,medFile,hdfFile );
423   mesh->changePreMeshInfo() = meshPreInfo;
424
425   meshPreInfo->_toRemoveFiles = toRemoveFiles;
426   if ( toRemoveFiles )
427     meshInfoLoaded( mesh );
428
429   if ( meshPreInfo->readPreInfoFromHDF() )
430     // all SMESH_PreMeshInfo's are stored in HDF file (written after
431     // implementing SMESH_PreMeshInfo)
432     return;
433
434   // try to read SMESH_PreMeshInfo from med file (as study is older than SMESH_PreMeshInfo)
435   if ( meshPreInfo->readMeshInfo() )
436   {
437     meshPreInfo->readGroupInfo();
438     meshPreInfo->readSubMeshInfo();
439   }
440   else
441   {
442     meshPreInfo->FullLoadFromFile();
443   }
444   PreMeshInfo_CATCH;
445 }
446
447 //================================================================================
448 /*!
449  * \brief Tries to read all SMESH_PreMeshInfo from a HDF file
450  *  \retval bool - true if succeeded
451  *
452  * This method is symmetrical to SaveToFile()
453  */
454 //================================================================================
455
456 bool SMESH_PreMeshInfo::readPreInfoFromHDF()
457 {
458   HDFfile* aFile = new HDFfile( (char*) _hdfFileName.c_str() );
459   aFile->OpenOnDisk( HDF_RDONLY );
460
461   SMESH_Comment hdfGroupName("SMESH_PreMeshInfo"); hdfGroupName << _meshID;
462   const bool infoAvailable = aFile->ExistInternalObject( hdfGroupName );
463   if ( infoAvailable )
464   {
465
466     HDFgroup* infoHdfGroup = new HDFgroup( hdfGroupName, aFile );
467     infoHdfGroup->OpenOnDisk();
468
469     _mesh->changePreMeshInfo()->hdf2meshInfo( "Mesh", infoHdfGroup );
470
471     // read SMESH_PreMeshInfo of groups
472     map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i2group = _mesh->_mapGroups.begin();
473     for ( ; i2group != _mesh->_mapGroups.end(); ++i2group )
474     {
475       if ( SMESH_GroupBase_i* group_i =
476            SMESH::DownCast<SMESH_GroupBase_i*>( i2group->second ))
477       {
478         group_i->changePreMeshInfo() = newInstance();
479         if ( SMESHDS_GroupBase* group = group_i->GetGroupDS() )
480         {
481           const string name = group->GetStoreName();
482           group_i->changePreMeshInfo()->hdf2meshInfo( name, infoHdfGroup );
483         }
484       }
485     }
486
487     // read SMESH_PreMeshInfo of sub-meshes
488     map<int, SMESH::SMESH_subMesh_ptr>::iterator id2sm = _mesh->_mapSubMeshIor.begin();
489     for ( ; id2sm != _mesh->_mapSubMeshIor.end(); ++id2sm )
490     {
491       if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( id2sm->second ))
492       {
493         sm->changePreMeshInfo() = newInstance();
494         sm->changePreMeshInfo()->hdf2meshInfo( SMESH_Comment( sm->GetId()), infoHdfGroup );
495       }
496     }
497   }
498
499   aFile->CloseOnDisk();
500   delete aFile;
501
502   return infoAvailable;
503 }
504
505 //================================================================================
506 /*!
507  * \brief Reads mesh info of mesh from the med file
508  */
509 //================================================================================
510
511 bool SMESH_PreMeshInfo::readMeshInfo()
512 {
513   _isInfoOk = true;
514
515   MED::PWrapper aMed = MED::CrWrapper(_medFileName,true);
516   // if ( aMed->GetVersion() != MED::eV2_2 )
517   //   return false;
518
519   MED::PMeshInfo medMeshInfo = aMed->CrMeshInfo(3,3,SMESH_Comment( _meshID ));
520
521   // read nb nodes
522   int nbNodes = std::max( 0, aMed->GetNbNodes( medMeshInfo ));
523   if ( nbNodes > 0 )
524   {
525     setNb( SMDSEntity_Node, nbNodes);
526
527     // read nb of elements
528     Tmed2smeshElemTypeMap::const_iterator me2sme    = med2smeshElemTypeMap().begin();
529     Tmed2smeshElemTypeMap::const_iterator me2smeEnd = med2smeshElemTypeMap().end();
530     for ( ; me2sme != me2smeEnd; ++me2sme )
531     {
532       int nbElems = aMed->GetNbCells( medMeshInfo, MED::eMAILLE, me2sme->first );
533       if ( nbElems > 0 )
534         setNb( me2sme->second, nbElems );
535     }
536   }
537   return true;
538 }
539
540 //================================================================================
541 /*!
542  * \brief Reads info of groups from the med file
543  */
544 //================================================================================
545
546 void SMESH_PreMeshInfo::readGroupInfo()
547 {
548   if ( _mesh->_mapGroups.empty() ) return;
549
550   // make SMESH_PreMeshInfo of groups
551   map< string, SMESH_PreMeshInfo* > name2GroupInfo;
552   map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i2group = _mesh->_mapGroups.begin();
553   for ( ; i2group != _mesh->_mapGroups.end(); ++i2group )
554   {
555     if ( SMESH_GroupBase_i* group_i =
556          SMESH::DownCast<SMESH_GroupBase_i*>( i2group->second ))
557     {
558       SMESH_PreMeshInfo* info = newInstance();
559       group_i->changePreMeshInfo() = info;
560       if ( SMESHDS_Group* group = dynamic_cast< SMESHDS_Group* >( group_i->GetGroupDS() ))
561       {
562         string name = group->GetStoreName();
563         name2GroupInfo.insert( make_pair( name, info ));
564         info->_isInfoOk = true;
565       }
566     }
567   }
568
569   map< int, vector< SMESH_PreMeshInfo* > > famId2grInfo;
570
571   MED::PWrapper aMed = MED::CrWrapper(_medFileName,false);
572   MED::PMeshInfo medMeshInfo = aMed->CrMeshInfo(3,3,SMESH_Comment( _meshID ));
573
574   // read families to fill in famId2grInfo
575   int nbFams = aMed->GetNbFamilies( medMeshInfo );
576   if ( nbFams <= 1 ) return; // zero family is always present
577   for ( int iF = 0; iF <= nbFams; ++iF )
578   {
579     int nbGroups = aMed->GetNbFamGroup( iF, medMeshInfo );
580     if ( nbGroups < 1 ) continue;
581     MED::PFamilyInfo medFamInfo = aMed->CrFamilyInfo( medMeshInfo, nbGroups, nbGroups );
582     aMed->GetFamilyInfo( iF, medFamInfo ); // read groups of a family
583     vector< SMESH_PreMeshInfo* >& grInfoVec = famId2grInfo[ medFamInfo->GetId() ];
584     for ( int iG = 0; iG < nbGroups; ++iG )
585     {
586       const string grName = medFamInfo->GetGroupName( iG );
587       map< string, SMESH_PreMeshInfo* >::iterator n2i = name2GroupInfo.find( grName );
588       if ( n2i != name2GroupInfo.end() )
589         grInfoVec.push_back( n2i->second );
590     }
591   }
592
593   // read family numbers of elements
594   Tmed2smeshElemTypeMap::const_iterator me2sme    = med2smeshElemTypeMap().begin();
595   Tmed2smeshElemTypeMap::const_iterator me2smeEnd = med2smeshElemTypeMap().end();
596   MED::PElemInfo medElemInfo = aMed->CrElemInfo( medMeshInfo, 0 );
597   MED::TIntVector& famNums = medElemInfo->myFamNum;
598   for ( ; me2sme != me2smeEnd; ++me2sme ) // loop on elem types
599   {
600     famNums.resize( NbEntities( me2sme->second ));
601     if ( famNums.empty() ) continue;
602     aMed->GetFamilies( medElemInfo, famNums.size(), MED::eMAILLE, me2sme->first );
603     // distribute elements of a type among groups
604     map< int, vector< SMESH_PreMeshInfo* > >::iterator f2infos = famId2grInfo.begin();
605     for ( size_t i = 0; i < famNums.size(); ++i )
606     {
607       if ( famNums[i] != f2infos->first )
608       {
609         f2infos = famId2grInfo.find( famNums[i] );
610         if ( f2infos == famId2grInfo.end() )
611           f2infos = famId2grInfo.insert
612             ( make_pair( famNums[i], vector< SMESH_PreMeshInfo*>())).first;
613       }
614       vector< SMESH_PreMeshInfo* >& infoVec = f2infos->second ;
615       for ( size_t j = 0; j < infoVec.size(); ++j )
616         infoVec[j]->_elemCounter++;
617     }
618     // pass _elemCounter to a real elem type
619     map< string, SMESH_PreMeshInfo* >::iterator n2i = name2GroupInfo.begin();
620     for ( ; n2i != name2GroupInfo.end(); ++n2i )
621     {
622       SMESH_PreMeshInfo* info = n2i->second;
623       info->setNb( me2sme->second, info->_elemCounter );
624       info->_elemCounter = 0;
625     }
626   }
627 }
628
629 //================================================================================
630 /*!
631  * \brief Reads info of sub-meshes from hdf file of old study
632  */
633 //================================================================================
634
635 void SMESH_PreMeshInfo::readSubMeshInfo()
636 {
637   if ( _mesh->_mapSubMeshIor.empty() ) return;
638
639   // create SMESH_PreMeshInfo of sub-meshes
640   map<int, SMESH::SMESH_subMesh_ptr>::iterator id2sm = _mesh->_mapSubMeshIor.begin();
641   for ( ; id2sm != _mesh->_mapSubMeshIor.end(); ++id2sm )
642   {
643     if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( id2sm->second ))
644     {
645       sm->changePreMeshInfo() = newInstance();
646       sm->changePreMeshInfo()->_isInfoOk = true;
647     }
648   }
649
650   // try to read 
651   HDFfile* aFile = new HDFfile( (char*) _hdfFileName.c_str() );
652   aFile->OpenOnDisk( HDF_RDONLY );
653
654   char meshGrpName[ 30 ];
655   sprintf( meshGrpName, "Mesh %d", _meshID );
656   if ( aFile->ExistInternalObject( meshGrpName ) )
657   {
658     HDFgroup* aTopGroup = new HDFgroup( meshGrpName, aFile );
659     aTopGroup->OpenOnDisk();
660     if ( aTopGroup->ExistInternalObject( "Submeshes" ))
661     {
662       HDFgroup* aGroup = new HDFgroup( "Submeshes", aTopGroup );
663       aGroup->OpenOnDisk();
664
665       SMESHDS_Mesh* meshDS = _mesh->GetImpl().GetMeshDS();
666       int maxSmId = Max( meshDS->MaxSubMeshIndex(), meshDS->MaxShapeIndex() );
667
668       for ( int isNode = 0; isNode < 2; ++isNode )
669       {
670         string aDSName( isNode ? "Node Submeshes" : "Element Submeshes");
671         if ( aGroup->ExistInternalObject( (char*) aDSName.c_str() ))
672         {
673           // read sub-mesh id of all nodes or elems
674           HDFdataset* aDataset = new HDFdataset( (char*) aDSName.c_str(), aGroup );
675           aDataset->OpenOnDisk();
676           int nbElems = aDataset->GetSize();
677           int* smIDs = new int [ nbElems ];
678           aDataset->ReadFromDisk( smIDs );
679           aDataset->CloseOnDisk();
680           // count nb elems in each sub-mesh
681           vector<int> nbBySubmeshId( maxSmId + 1, 0 );
682           for ( int i = 0; i < nbElems; ++i )
683           {
684             const int smID = smIDs[ i ];
685             if ( smID < (int) nbBySubmeshId.size() )
686               nbBySubmeshId[ smID ]++;
687           }
688           delete [] smIDs;
689
690           // store nb elems in SMESH_PreMeshInfo of sub-meshes
691           map<int, SMESH::SMESH_subMesh_ptr>::iterator id2sm = _mesh->_mapSubMeshIor.begin();
692           for ( ; id2sm != _mesh->_mapSubMeshIor.end(); ++id2sm )
693           {
694             if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( id2sm->second ))
695             {
696               SMESH_PreMeshInfo* & info = sm->changePreMeshInfo();
697
698               vector<int> smIds = getSimpleSubMeshIds( meshDS, id2sm->first );
699               for ( size_t i = 0; i < smIds.size(); ++i )
700                 info->_elemCounter += nbBySubmeshId[ smIds[i] ];
701
702               SMDSAbs_EntityType elemType;
703               if ( isNode )
704               {
705                 elemType = SMDSEntity_Node;
706               }
707               else
708               {
709                 bool koElemType = false;
710                 const TopoDS_Shape& shape = meshDS->IndexToShape( smIds[0] );
711                 elemType = getElemType( shape.ShapeType(), info->_elemCounter, koElemType );
712                 info->_isInfoOk = !koElemType;
713               }
714               info->setNb( elemType, info->_elemCounter );
715             }
716           }
717         } // if ( aGroup->ExistInternalObject( aDSName ))
718       } // for ( int isNode = 0; isNode < 2; ++isNode )
719
720       aGroup->CloseOnDisk();
721     } // if ( aTopGroup->ExistInternalObject( "Submeshes" ))
722
723     aTopGroup->CloseOnDisk();
724   } // if ( aFile->ExistInternalObject( meshGrpName ) )
725
726   aFile->CloseOnDisk();
727   delete aFile;
728 }
729
730 //================================================================================
731 /*!
732  * \brief Return type of element for sub-mesh on a shape of given type
733  */
734 //================================================================================
735
736 SMDSAbs_EntityType SMESH_PreMeshInfo::getElemType( const TopAbs_ShapeEnum shapeType,
737                                                    const int              nbElemsInSubMesh,
738                                                    bool&                  isKoType) const
739 {
740   isKoType = false;
741   int type, typeEnd;
742   SMESH_PreMeshInfo* meshInfo = _mesh->changePreMeshInfo();
743
744   switch ( shapeType )
745   {
746   case TopAbs_SOLID:
747     type = SMDSEntity_Tetra;
748     typeEnd = SMDSEntity_Last;
749     isKoType = ( meshInfo->NbVolumes() != nbElemsInSubMesh );
750     break;
751   case TopAbs_FACE:
752   case TopAbs_SHELL:  
753     type = SMDSEntity_Triangle;
754     typeEnd = SMDSEntity_Tetra;
755     isKoType = ( meshInfo->NbFaces() != nbElemsInSubMesh );
756     break;
757   case TopAbs_WIRE:
758   case TopAbs_EDGE:   return SMDSEntity_Edge;
759   case TopAbs_VERTEX: return SMDSEntity_0D;
760   default:            return SMDSEntity_Last;
761   }
762
763   if ( !isKoType )
764   {
765     for ( int t = type; t < typeEnd; ++t )
766       if ( nbElemsInSubMesh == meshInfo->NbEntities( SMDSAbs_EntityType( t )))
767         return SMDSAbs_EntityType( t );
768   }
769   isKoType = true;
770   return SMDSAbs_EntityType( type );
771 }
772
773 //================================================================================
774 /*!
775  * \brief Saves SMESH_PreMeshInfo to the study file
776  */
777 //================================================================================
778
779 void SMESH_PreMeshInfo::SaveToFile( SMESH_Mesh_i* mesh,
780                                     const int     meshID,
781                                     HDFfile*      hdfFile)
782 {
783   // create a HDF group for SMESH_PreMeshInfo of this mesh
784   SMESH_Comment hdfGroupName("SMESH_PreMeshInfo"); hdfGroupName << meshID;
785   HDFgroup* infoHdfGroup = new HDFgroup( hdfGroupName, hdfFile );
786   infoHdfGroup->CreateOnDisk();
787
788   PreMeshInfo_TRY;
789
790   // info of mesh
791   meshInfo2hdf( mesh->GetMeshInfo(), "Mesh", infoHdfGroup );
792   
793   // info of groups
794   SMESH_PreMeshInfo incompleteInfo( 0,0,"","");
795   incompleteInfo.setNb( SMDSEntity_Node, GroupOnFilter_OutOfDate );
796   SMESHDS_Mesh* meshDS = mesh->GetImpl().GetMeshDS();
797
798   map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i2group = mesh->_mapGroups.begin();
799   for ( ; i2group != mesh->_mapGroups.end(); ++i2group )
800   {
801     if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( i2group->second ))
802     {
803       SMESHDS_GroupBase * group = group_i->GetGroupDS();
804       if ( SMESHDS_GroupOnFilter* gof = dynamic_cast<SMESHDS_GroupOnFilter*>(group))
805       {
806         // prevent too long storage time due to applying filter to many elements
807         if ( !gof->IsUpToDate() && meshDS->GetMeshInfo().NbElements( gof->GetType() ) > 1e5 )
808         {
809           meshInfo2hdf( incompleteInfo.GetMeshInfo(),
810                         group->GetStoreName(),
811                         infoHdfGroup);
812           continue;
813         }
814       }
815       meshInfo2hdf( group_i->GetMeshInfo(), group->GetStoreName(), infoHdfGroup);
816     }
817   }
818
819   // info of sub-meshes
820   map<int, SMESH::SMESH_subMesh_ptr>::iterator id2sm = mesh->_mapSubMeshIor.begin();
821   for ( ; id2sm != mesh->_mapSubMeshIor.end(); ++id2sm )
822   {
823     if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( id2sm->second ))
824     {
825       meshInfo2hdf( sm->GetMeshInfo(),
826                     SMESH_Comment( sm->GetId() ),
827                     infoHdfGroup);
828     }
829   }
830
831   PreMeshInfo_CATCH;
832
833   infoHdfGroup->CloseOnDisk();
834 }
835
836 //================================================================================
837 /*!
838  * \brief Reads all data and remove all SMESH_PreMeshInfo fields from objects
839  */
840 //================================================================================
841
842 void SMESH_PreMeshInfo::FullLoadFromFile() const
843 {
844   SignalToGUI signalOnLoading( _mesh );
845
846   SMESH_PreMeshInfo* meshInfo = _mesh->changePreMeshInfo();
847   _mesh->changePreMeshInfo() = NULL; // to allow GUI accessing to real info
848
849   ::SMESH_Mesh& mesh = _mesh->GetImpl();
850   SMESHDS_Mesh* meshDS = mesh.GetMeshDS();
851
852   PreMeshInfo_TRY;
853
854   MYDEBUGOUT( "BEG FullLoadFromFile() " << _meshID );
855
856   // load mesh
857   DriverMED_R_SMESHDS_Mesh myReader;
858   myReader.SetFile( _medFileName.c_str() );
859   myReader.SetMesh( meshDS );
860   myReader.SetMeshId( _meshID );
861   myReader.Perform();
862
863   // load groups
864   const set<SMESHDS_GroupBase*>& groups = meshDS->GetGroups();
865   set<SMESHDS_GroupBase*>::const_iterator groupIt = groups.begin();
866   for ( ; groupIt != groups.end(); ++groupIt )
867     if ( SMESHDS_Group* aGrp = dynamic_cast<SMESHDS_Group*>( *groupIt ))
868       myReader.GetGroup( aGrp );
869
870   // load sub-meshes
871   readSubMeshes( &myReader );
872
873   PreMeshInfo_CATCH;
874
875   _mesh->changePreMeshInfo() = meshInfo;
876
877   ForgetAllData();
878
879   signalOnLoading.sendStop();
880
881   meshDS->Modified();
882
883   // load dependent meshes referring/referred via hypotheses
884   mesh.GetSubMesh( mesh.GetShapeToMesh() )->
885     ComputeStateEngine (SMESH_subMesh::SUBMESH_LOADED);
886
887   MYDEBUGOUT( "END FullLoadFromFile()" );
888 }
889
890 //================================================================================
891 /*!
892  * \brief Reads full data of sub-meshes
893  */
894 //================================================================================
895
896 void SMESH_PreMeshInfo::readSubMeshes(DriverMED_R_SMESHDS_Mesh* reader) const
897 {
898   HDFfile* aFile = new HDFfile( (char*) _hdfFileName.c_str() );
899   aFile->OpenOnDisk( HDF_RDONLY );
900
901   char meshGrpName[ 30 ];
902   sprintf( meshGrpName, "Mesh %d", _meshID );
903   if ( aFile->ExistInternalObject( meshGrpName ) )
904   {
905     HDFgroup* aTopGroup = new HDFgroup( meshGrpName, aFile );
906     aTopGroup->OpenOnDisk();
907
908     SMESHDS_Mesh* meshDS = _mesh->GetImpl().GetMeshDS();
909
910     bool submeshesInFamilies = ( ! aTopGroup->ExistInternalObject( "Submeshes" ));
911     if ( submeshesInFamilies ) // from MED
912     {
913       // old way working before fix of PAL 12992
914       reader->CreateAllSubMeshes();
915     }
916     else
917     {
918       // open a group
919       HDFgroup* aGroup = new HDFgroup( "Submeshes", aTopGroup );
920       aGroup->OpenOnDisk();
921
922       int maxID = Max( meshDS->MaxSubMeshIndex(), meshDS->MaxShapeIndex() );
923       vector< SMESHDS_SubMesh * > subMeshes( maxID + 1, (SMESHDS_SubMesh*) 0 );
924       vector< TopAbs_ShapeEnum  > smType   ( maxID + 1, TopAbs_SHAPE );
925
926       PositionCreator aPositionCreator;
927
928       SMDS_NodeIteratorPtr nIt = meshDS->nodesIterator();
929       SMDS_ElemIteratorPtr eIt = meshDS->elementsIterator();
930       for ( int isNode = 0; isNode < 2; ++isNode )
931       {
932         string aDSName( isNode ? "Node Submeshes" : "Element Submeshes");
933         if ( aGroup->ExistInternalObject( (char*) aDSName.c_str() ))
934         {
935           HDFdataset* aDataset = new HDFdataset( (char*) aDSName.c_str(), aGroup );
936           aDataset->OpenOnDisk();
937           // read submesh IDs for all elements sorted by ID
938           int nbElems = aDataset->GetSize();
939           int* smIDs = new int [ nbElems ];
940           aDataset->ReadFromDisk( smIDs );
941           aDataset->CloseOnDisk();
942
943           // get elements sorted by ID
944           TIDSortedElemSet elemSet;
945           if ( isNode )
946             while ( nIt->more() ) elemSet.insert( elemSet.end(), nIt->next() );
947           else
948             while ( eIt->more() ) elemSet.insert( elemSet.end(), eIt->next() );
949           //ASSERT( elemSet.size() == nbElems ); -- issue 20182
950           // -- Most probably a bad study was saved when there were
951           // not fixed bugs in SMDS_MeshInfo
952           if ( elemSet.size() < nbElems ) {
953 #ifdef _DEBUG_
954             cout << "SMESH_Gen_i::Load(), warning: Node position data is invalid" << endl;
955 #endif
956             nbElems = elemSet.size();
957           }
958           // add elements to submeshes
959           TIDSortedElemSet::iterator iE = elemSet.begin();
960           for ( int i = 0; i < nbElems; ++i, ++iE )
961           {
962             int smID = smIDs[ i ];
963             if ( smID == 0 ) continue;
964             const SMDS_MeshElement* elem = *iE;
965             if ( smID > maxID ) {
966               // corresponding subshape no longer exists: maybe geom group has been edited
967               if ( _mesh->GetImpl().HasShapeToMesh() )
968                 meshDS->RemoveElement( elem );
969               continue;
970             }
971             // get or create submesh
972             SMESHDS_SubMesh* & sm = subMeshes[ smID ];
973             if ( ! sm ) {
974               sm = meshDS->NewSubMesh( smID );
975               smType[ smID ] = meshDS->IndexToShape( smID ).ShapeType();
976             }
977             // add
978             if ( isNode ) {
979               SMDS_PositionPtr pos = aPositionCreator.MakePosition( smType[ smID ]);
980               SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( static_cast<const SMDS_MeshNode*>( elem ));
981               node->SetPosition( pos );
982               sm->AddNode( node );
983             } else {
984               sm->AddElement( elem );
985             }
986           }
987           delete [] smIDs;
988         }
989       }
990     } // end reading submeshes
991
992     // Read node positions on sub-shapes (SMDS_Position)
993
994     if ( aTopGroup->ExistInternalObject( "Node Positions" ))
995     {
996       // There are 5 datasets to read:
997       // "Nodes on Edges" - ID of node on edge
998       // "Edge positions" - U parameter on node on edge
999       // "Nodes on Faces" - ID of node on face
1000       // "Face U positions" - U parameter of node on face
1001       // "Face V positions" - V parameter of node on face
1002       const char* aEid_DSName = "Nodes on Edges";
1003       const char* aEu_DSName  = "Edge positions";
1004       const char* aFu_DSName  = "Face U positions";
1005       //char* aFid_DSName = "Nodes on Faces";
1006       //char* aFv_DSName  = "Face V positions";
1007
1008       // data to retrieve
1009       int nbEids = 0, nbFids = 0;
1010       int *aEids = 0, *aFids  = 0;
1011       double *aEpos = 0, *aFupos = 0, *aFvpos = 0;
1012
1013       // open a group
1014       HDFgroup* aGroup = new HDFgroup( "Node Positions", aTopGroup );
1015       aGroup->OpenOnDisk();
1016
1017       // loop on 5 data sets
1018       int aNbObjects = aGroup->nInternalObjects();
1019       for ( int i = 0; i < aNbObjects; i++ )
1020       {
1021         // identify dataset
1022         char aDSName[ HDF_NAME_MAX_LEN+1 ];
1023         aGroup->InternalObjectIndentify( i, aDSName );
1024         // read data
1025         HDFdataset* aDataset = new HDFdataset( aDSName, aGroup );
1026         aDataset->OpenOnDisk();
1027         if ( aDataset->GetType() == HDF_FLOAT64 ) // Positions
1028         {
1029           double* pos = new double [ aDataset->GetSize() ];
1030           aDataset->ReadFromDisk( pos );
1031           // which one?
1032           if ( strncmp( aDSName, aEu_DSName, strlen( aEu_DSName )) == 0 )
1033             aEpos = pos;
1034           else if ( strncmp( aDSName, aFu_DSName, strlen( aFu_DSName )) == 0 )
1035             aFupos = pos;
1036           else
1037             aFvpos = pos;
1038         }
1039         else // NODE IDS
1040         {
1041           int aSize = aDataset->GetSize();
1042
1043           // for reading files, created from 18.07.2005 till 10.10.2005
1044           if (aDataset->GetType() == HDF_STRING)
1045             aSize /= sizeof(int);
1046
1047           int* ids = new int [aSize];
1048           aDataset->ReadFromDisk( ids );
1049           // on face or nodes?
1050           if ( strncmp( aDSName, aEid_DSName, strlen( aEid_DSName )) == 0 ) {
1051             aEids = ids;
1052             nbEids = aSize;
1053           }
1054           else {
1055             aFids = ids;
1056             nbFids = aSize;
1057           }
1058         }
1059         aDataset->CloseOnDisk();
1060       } // loop on 5 datasets
1061
1062       // Set node positions on edges or faces
1063       for ( int onFace = 0; onFace < 2; onFace++ )
1064       {
1065         int nbNodes = ( onFace ? nbFids : nbEids );
1066         if ( nbNodes == 0 ) continue;
1067         int* aNodeIDs = ( onFace ? aFids : aEids );
1068         double* aUPos = ( onFace ? aFupos : aEpos );
1069         double* aVPos = ( onFace ? aFvpos : 0 );
1070         // loop on node IDs
1071         for ( int iNode = 0; iNode < nbNodes; iNode++ )
1072         {
1073           const SMDS_MeshNode* node = meshDS->FindNode( aNodeIDs[ iNode ]);
1074           if ( !node ) continue; // maybe removed while Loading() if geometry changed
1075           SMDS_PositionPtr aPos = node->GetPosition();
1076           ASSERT( aPos );
1077           if ( onFace ) {
1078             // ASSERT( aPos->GetTypeOfPosition() == SMDS_TOP_FACE );-- issue 20182
1079             // -- Most probably a bad study was saved when there were
1080             // not fixed bugs in SMDS_MeshInfo
1081             if ( aPos->GetTypeOfPosition() == SMDS_TOP_FACE ) {
1082               SMDS_FacePosition* fPos = const_cast<SMDS_FacePosition*>
1083                 ( static_cast<const SMDS_FacePosition*>( aPos ));
1084               fPos->SetUParameter( aUPos[ iNode ]);
1085               fPos->SetVParameter( aVPos[ iNode ]);
1086             }
1087           }
1088           else {
1089             // ASSERT( aPos->GetTypeOfPosition() == SMDS_TOP_EDGE );-- issue 20182
1090             if ( aPos->GetTypeOfPosition() == SMDS_TOP_EDGE ) {
1091               SMDS_EdgePosition* fPos = const_cast<SMDS_EdgePosition*>
1092                 ( static_cast<const SMDS_EdgePosition*>( aPos ));
1093               fPos->SetUParameter( aUPos[ iNode ]);
1094             }
1095           }
1096         }
1097       }
1098       if ( aEids ) delete [] aEids;
1099       if ( aFids ) delete [] aFids;
1100       if ( aEpos ) delete [] aEpos;
1101       if ( aFupos ) delete [] aFupos;
1102       if ( aFvpos ) delete [] aFvpos;
1103
1104       aGroup->CloseOnDisk();
1105
1106     } // if ( aTopGroup->ExistInternalObject( "Node Positions" ) )
1107
1108     aTopGroup->CloseOnDisk();
1109   } // if ( aFile->ExistInternalObject( meshGrpName ) )
1110   
1111   aFile->CloseOnDisk();
1112   delete aFile;
1113 }
1114
1115 //================================================================================
1116 /*!
1117  * \brief Remove all SMESH_PreMeshInfo fields from objects w/o data loading
1118  */
1119 //================================================================================
1120
1121 void SMESH_PreMeshInfo::ForgetAllData() const
1122 {
1123   PreMeshInfo_TRY;
1124
1125   if ( _mesh->changePreMeshInfo() != this )
1126     return _mesh->changePreMeshInfo()->ForgetAllData();
1127
1128   // remove SMESH_PreMeshInfo from groups
1129   map<int, SMESH::SMESH_GroupBase_ptr>::const_iterator i2group = _mesh->_mapGroups.begin();
1130   for ( ; i2group != _mesh->_mapGroups.end(); ++i2group )
1131   {
1132     if ( SMESH_GroupBase_i* group_i =
1133          SMESH::DownCast<SMESH_GroupBase_i*>( i2group->second ))
1134     {
1135       SMESH_PreMeshInfo* & info = group_i->changePreMeshInfo();
1136       delete info;
1137       info = NULL;
1138     }
1139   }
1140   // remove SMESH_PreMeshInfo from sub-meshes
1141   map<int, SMESH::SMESH_subMesh_ptr>::iterator id2sm = _mesh->_mapSubMeshIor.begin();
1142   for ( ; id2sm != _mesh->_mapSubMeshIor.end(); ++id2sm )
1143   {
1144     if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( id2sm->second ))
1145     {
1146       SMESH_PreMeshInfo* & info = sm->changePreMeshInfo();
1147       delete info;
1148       info = NULL;
1149     }
1150   }
1151   // remove SMESH_PreMeshInfo from the mesh
1152   _mesh->changePreMeshInfo() = NULL;
1153   delete this;
1154
1155   PreMeshInfo_CATCH;
1156
1157
1158   // Finalize loading
1159
1160   // PreMeshInfo_TRY;
1161
1162   // ::SMESH_Mesh& mesh = _mesh->GetImpl();
1163
1164   // // update hyps needing full mesh data restored (issue 20918)
1165   // // map<int, SMESH::SMESH_Hypothesis_ptr>::iterator id2hyp= _mesh->_mapHypo.begin();
1166   // // for ( ; id2hyp != _mesh->_mapHypo.end(); ++id2hyp )
1167   // //   if ( SMESH_Hypothesis_i* hyp = SMESH::DownCast<SMESH_Hypothesis_i*>( id2hyp->second ))
1168   // //     hyp->UpdateAsMeshesRestored();
1169
1170
1171   // PreMeshInfo_CATCH;
1172 }
1173
1174 //================================================================================
1175 /*!
1176  * \brief Calls either FullLoadFromFile() or ForgetAllData() depending on preferences
1177  */
1178 //================================================================================
1179
1180 void SMESH_PreMeshInfo::ForgetOrLoad() const
1181 {
1182   if ( SMESH_Gen_i::GetSMESHGen()->ToForgetMeshDataOnHypModif() &&
1183        _mesh->HasShapeToMesh())
1184     ForgetAllData();
1185   else
1186     FullLoadFromFile();
1187 }
1188
1189 //================================================================================
1190 /*!
1191  * \brief Method of SMESH_IDSource interface
1192  */
1193 //================================================================================
1194
1195 SMESH::array_of_ElementType* SMESH_PreMeshInfo::GetTypes() const
1196 {
1197   SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
1198
1199   types->length( 4 );
1200   int nbTypes = 0;
1201   if (NbEdges())
1202     types[nbTypes++] = SMESH::EDGE;
1203   if (NbFaces())
1204     types[nbTypes++] = SMESH::FACE;
1205   if (NbVolumes())
1206     types[nbTypes++] = SMESH::VOLUME;
1207   if (Nb0DElements())
1208     types[nbTypes++] = SMESH::ELEM0D;
1209   types->length( nbTypes );
1210
1211   return types._retn();
1212 }
1213
1214 //================================================================================
1215 /*!
1216  * \brief Method of SMESH_IDSource interface returning nb elements by element type
1217  */
1218 //================================================================================
1219
1220 SMESH::long_array* SMESH_PreMeshInfo::GetMeshInfo() const
1221 {
1222   SMESH::long_array_var aRes = new SMESH::long_array();
1223   aRes->length(SMESH::Entity_Last);
1224   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
1225     aRes[i] = 0;
1226
1227   for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++)
1228     aRes[i] = NbEntities((SMDSAbs_EntityType)i);
1229   return aRes._retn();
1230 }
1231
1232 //================================================================================
1233 /*!
1234  * Returns false if GetMeshInfo() returns incorrect information that may
1235  * happen if mesh data is not yet fully loaded from the file of study.
1236  */
1237 //================================================================================
1238
1239 bool SMESH_PreMeshInfo::IsMeshInfoCorrect() const
1240 {
1241   return _isInfoOk;
1242 }
1243
1244 //================================================================================
1245 /*!
1246  * \brief TEMPORARY method to remove study files on closing study;
1247  * RIGHT WAY: study files are remove automatically when meshes are destroyed
1248  */
1249 //================================================================================
1250
1251 void SMESH_PreMeshInfo::RemoveStudyFiles_TMP_METHOD(SALOMEDS::SComponent_ptr smeshComp)
1252 {
1253   SALOMEDS::Study_var study = smeshComp->GetStudy();
1254   if ( theStudyIDToMeshCounter[ (int) study->StudyId() ] > 0 )
1255   {
1256     SALOMEDS::ChildIterator_var itBig = study->NewChildIterator( smeshComp );
1257     for ( ; itBig->More(); itBig->Next() ) {
1258       SALOMEDS::SObject_var gotBranch = itBig->Value();
1259       CORBA::Object_var anObject = SMESH_Gen_i::SObjectToObject( gotBranch );
1260       if ( SMESH_Mesh_i* mesh = SMESH::DownCast<SMESH_Mesh_i*>( anObject ))
1261       {
1262         if ( mesh->changePreMeshInfo() )
1263         {
1264           mesh->changePreMeshInfo()->ForgetAllData();
1265         }
1266       }
1267     }
1268   }
1269 }