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