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