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