Salome HOME
Merge from V5_1_3_BR branch (07/12/09)
[modules/smesh.git] / src / DriverMED / DriverMED_W_SMESHDS_Mesh.cxx
1 //  Copyright (C) 2007-2008  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 //  SMESH DriverMED : driver to read and write 'med' files
23 //  File   : DriverMED_W_SMESHDS_Mesh.cxx
24 //  Module : SMESH
25 //
26 #include <sstream>
27
28 #include "DriverMED_W_SMESHDS_Mesh.h"
29 #include "DriverMED_W_SMDS_Mesh.h"
30 #include "DriverMED_Family.h"
31
32 #include "SMESHDS_Mesh.hxx"
33 #include "SMDS_MeshElement.hxx"
34 #include "SMDS_MeshNode.hxx"
35 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
36
37 #include "utilities.h"
38
39 #include "MED_Utilities.hxx"
40
41 #define _EDF_NODE_IDS_
42 //#define _ELEMENTS_BY_DIM_
43
44 using namespace std;
45 using namespace MED;
46
47
48 DriverMED_W_SMESHDS_Mesh::DriverMED_W_SMESHDS_Mesh():
49   myAllSubMeshes (false),
50   myDoGroupOfNodes (false),
51   myDoGroupOfEdges (false),
52   myDoGroupOfFaces (false),
53   myDoGroupOfVolumes (false)
54 {}
55
56 void DriverMED_W_SMESHDS_Mesh::SetFile(const std::string& theFileName, 
57                                        MED::EVersion theId)
58 {
59   myMed = CrWrapper(theFileName,theId);
60   Driver_SMESHDS_Mesh::SetFile(theFileName);
61 }
62
63 void DriverMED_W_SMESHDS_Mesh::SetFile(const std::string& theFileName)
64 {
65   return SetFile(theFileName,MED::eV2_2);
66 }
67
68 string DriverMED_W_SMESHDS_Mesh::GetVersionString(const MED::EVersion theVersion, int theNbDigits)
69 {
70   TInt majeur, mineur, release;
71   majeur =  mineur = release = 0;
72   if ( theVersion == eV2_1 )
73     MED::GetVersionRelease<eV2_1>(majeur, mineur, release);
74   else
75     MED::GetVersionRelease<eV2_2>(majeur, mineur, release);
76   ostringstream name;
77   if ( theNbDigits > 0 )
78     name << majeur;
79   if ( theNbDigits > 1 )
80     name << "." << mineur;
81   if ( theNbDigits > 2 )
82     name << "." << release;
83   return name.str();
84 }
85
86 void DriverMED_W_SMESHDS_Mesh::SetMeshName(const std::string& theMeshName)
87 {
88   myMeshName = theMeshName;
89 }
90
91 void DriverMED_W_SMESHDS_Mesh::AddGroup(SMESHDS_GroupBase* theGroup)
92 {
93   myGroups.push_back(theGroup);
94 }
95
96 void DriverMED_W_SMESHDS_Mesh::AddAllSubMeshes()
97 {
98   myAllSubMeshes = true;
99 }
100
101 void DriverMED_W_SMESHDS_Mesh::AddSubMesh(SMESHDS_SubMesh* theSubMesh, int theID)
102 {
103   mySubMeshes[theID] = theSubMesh;
104 }
105
106 void DriverMED_W_SMESHDS_Mesh::AddGroupOfNodes()
107 {
108   myDoGroupOfNodes = true;
109 }
110
111 void DriverMED_W_SMESHDS_Mesh::AddGroupOfEdges()
112 {
113   myDoGroupOfEdges = true;
114 }
115
116 void DriverMED_W_SMESHDS_Mesh::AddGroupOfFaces()
117 {
118   myDoGroupOfFaces = true;
119 }
120
121 void DriverMED_W_SMESHDS_Mesh::AddGroupOfVolumes()
122 {
123   myDoGroupOfVolumes = true;
124 }
125
126 namespace{
127   typedef double (SMDS_MeshNode::* TGetCoord)() const;
128   typedef const char* TName;
129   typedef const char* TUnit;
130
131   // name length in a mesh must be equal to 16 :
132   //         1234567890123456
133   TName M = "m               ";
134   TName X = "x               ";
135   TName Y = "y               ";
136   TName Z = "z               ";
137
138   TUnit aUnit[3] = {M,M,M};
139
140   // 3 dim
141   TGetCoord aXYZGetCoord[3] = {
142     &SMDS_MeshNode::X, 
143     &SMDS_MeshNode::Y, 
144     &SMDS_MeshNode::Z
145   };
146   TName aXYZName[3] = {X,Y,Z};
147   
148   // 2 dim
149   TGetCoord aXYGetCoord[2] = {
150     &SMDS_MeshNode::X, 
151     &SMDS_MeshNode::Y
152   };
153   TName aXYName[2] = {X,Y};
154
155   TGetCoord aYZGetCoord[2] = {
156     &SMDS_MeshNode::Y, 
157     &SMDS_MeshNode::Z
158   };
159   TName aYZName[2] = {Y,Z};
160
161   TGetCoord aXZGetCoord[2] = {
162     &SMDS_MeshNode::X, 
163     &SMDS_MeshNode::Z
164   };
165   TName aXZName[2] = {X,Z};
166
167   // 1 dim
168   TGetCoord aXGetCoord[1] = {
169     &SMDS_MeshNode::X
170   };
171   TName aXName[1] = {X};
172
173   TGetCoord aYGetCoord[1] = {
174     &SMDS_MeshNode::Y
175   };
176   TName aYName[1] = {Y};
177
178   TGetCoord aZGetCoord[1] = {
179     &SMDS_MeshNode::Z
180   };
181   TName aZName[1] = {Z};
182
183
184   class TCoordHelper{
185     SMDS_NodeIteratorPtr myNodeIter;
186     const SMDS_MeshNode* myCurrentNode;
187     TGetCoord* myGetCoord;
188     TName* myName;
189     TUnit* myUnit;
190   public:
191     TCoordHelper(const SMDS_NodeIteratorPtr& theNodeIter,
192                  TGetCoord* theGetCoord,
193                  TName* theName,
194                  TUnit* theUnit = aUnit):
195       myNodeIter(theNodeIter),
196       myGetCoord(theGetCoord),
197       myName(theName),
198       myUnit(theUnit)
199     {}
200     virtual ~TCoordHelper(){}
201     bool Next(){ 
202       return myNodeIter->more() && 
203         (myCurrentNode = myNodeIter->next());
204     }
205     const SMDS_MeshNode* GetNode(){
206       return myCurrentNode;
207     }
208     MED::TIntVector::value_type GetID(){
209       return myCurrentNode->GetID();
210     }
211     MED::TFloatVector::value_type GetCoord(TInt theCoodId){
212       return (myCurrentNode->*myGetCoord[theCoodId])();
213     }
214     MED::TStringVector::value_type GetName(TInt theDimId){
215       return myName[theDimId];
216     }
217     MED::TStringVector::value_type GetUnit(TInt theDimId){
218       return myUnit[theDimId];
219     }
220   };
221   typedef boost::shared_ptr<TCoordHelper> TCoordHelperPtr;
222
223
224   //-------------------------------------------------------
225   /*!
226    * \brief Class helping to use either SMDS_0DElementIterator,
227    * SMDS_EdgeIterator, SMDS_FaceIterator or SMDS_VolumeIterator
228    * in the same code
229    */
230   //-------------------------------------------------------
231   struct TElemIterator
232   {
233     virtual const SMDS_MeshElement* next() = 0;
234     virtual ~TElemIterator() {}
235   };
236   typedef boost::shared_ptr<TElemIterator> PElemIterator;
237
238   template< class SMDSIteratorPtr > class TypedElemIterator: public TElemIterator
239   {
240     SMDSIteratorPtr myItPtr;
241   public:
242     TypedElemIterator(SMDSIteratorPtr it): myItPtr(it) {}
243     virtual const SMDS_MeshElement* next() {
244       if ( myItPtr->more() ) return myItPtr->next();
245       else                   return 0;
246     }
247   };
248   typedef TypedElemIterator< SMDS_0DElementIteratorPtr > T0DElementIterator;
249   typedef TypedElemIterator< SMDS_EdgeIteratorPtr > TEdgeIterator;
250   typedef TypedElemIterator< SMDS_FaceIteratorPtr > TFaceIterator;
251   typedef TypedElemIterator< SMDS_VolumeIteratorPtr > TVolumeIterator;
252
253   //-------------------------------------------------------
254   /*!
255    * \brief Structure describing element type
256    */
257   //-------------------------------------------------------
258   struct TElemTypeData
259   {
260     EEntiteMaillage     _entity;
261     EGeometrieElement   _geomType;
262     TInt                _nbElems;
263     SMDSAbs_ElementType _smdsType;
264
265     TElemTypeData (EEntiteMaillage entity, EGeometrieElement geom, TInt nb, SMDSAbs_ElementType type)
266       : _entity(entity), _geomType(geom), _nbElems( nb ), _smdsType( type ) {}
267   };
268
269
270   typedef NCollection_DataMap< Standard_Address, int > TElemFamilyMap;
271   //typedef map<const SMDS_MeshElement *, int> TElemFamilyMap;
272
273   //================================================================================
274   /*!
275    * \brief Fills element to famaly ID map for element type.
276    * Removes all families of anElemType
277    */
278   //================================================================================
279
280   void fillElemFamilyMap( TElemFamilyMap &            anElemFamMap,
281                           list<DriverMED_FamilyPtr> & aFamilies,
282                           const SMDSAbs_ElementType   anElemType)
283   {
284     anElemFamMap.Clear();
285     //anElemFamMap.clear();
286     list<DriverMED_FamilyPtr>::iterator aFamsIter = aFamilies.begin();
287     while ( aFamsIter != aFamilies.end() )
288     {
289       if ((*aFamsIter)->GetType() != anElemType) {
290         aFamsIter++;
291       }
292       else {
293         int aFamId = (*aFamsIter)->GetId();
294         const set<const SMDS_MeshElement *>& anElems = (*aFamsIter)->GetElements();
295         set<const SMDS_MeshElement *>::const_iterator anElemsIter = anElems.begin();
296         for (; anElemsIter != anElems.end(); anElemsIter++)
297         {
298           anElemFamMap.Bind( (Standard_Address)*anElemsIter, aFamId );
299           //anElemFamMap[*anElemsIter] = aFamId;
300         }
301         // remove a family from the list
302         aFamilies.erase( aFamsIter++ );
303       }
304     }
305   }
306
307   //================================================================================
308   /*!
309    * \brief For an element, return family ID found in the map or a default one
310    */
311   //================================================================================
312
313   int getFamilyId( const TElemFamilyMap &  anElemFamMap,
314                    const SMDS_MeshElement* anElement,
315                    const int               aDefaultFamilyId)
316   {
317     if ( anElemFamMap.IsBound( (Standard_Address) anElement ))
318       return anElemFamMap( (Standard_Address) anElement );
319 //     TElemFamilyMap::iterator elem_famNum = anElemFamMap.find( anElement );
320 //     if ( elem_famNum != anElemFamMap.end() )
321 //       return elem_famNum->second;
322     return aDefaultFamilyId;
323   }
324 }
325
326 Driver_Mesh::Status DriverMED_W_SMESHDS_Mesh::Perform()
327 {
328   Status aResult = DRS_OK;
329   if (myMesh->hasConstructionEdges() || myMesh->hasConstructionFaces()) {
330     INFOS("SMDS_MESH with hasConstructionEdges() or hasConstructionFaces() do not supports!!!");
331     return DRS_FAIL;
332   }
333   try {
334     MESSAGE("Perform - myFile : "<<myFile);
335
336     // Creating the MED mesh for corresponding SMDS structure
337     //-------------------------------------------------------
338     string aMeshName;
339     if (myMeshId != -1) {
340       ostringstream aMeshNameStr;
341       aMeshNameStr<<myMeshId;
342       aMeshName = aMeshNameStr.str();
343     } else {
344       aMeshName = myMeshName;
345     }
346
347     // Mesh dimension definition
348     TInt aMeshDimension;
349     TCoordHelperPtr aCoordHelperPtr;
350     {  
351       bool anIsXDimension = false;
352       bool anIsYDimension = false;
353       bool anIsZDimension = false;
354       {
355         SMDS_NodeIteratorPtr aNodesIter = myMesh->nodesIterator();
356         double aBounds[6];
357         if(aNodesIter->more()){
358           const SMDS_MeshNode* aNode = aNodesIter->next();
359           aBounds[0] = aBounds[1] = aNode->X();
360           aBounds[2] = aBounds[3] = aNode->Y();
361           aBounds[4] = aBounds[5] = aNode->Z();
362         }
363         while(aNodesIter->more()){
364           const SMDS_MeshNode* aNode = aNodesIter->next();
365           aBounds[0] = min(aBounds[0],aNode->X());
366           aBounds[1] = max(aBounds[1],aNode->X());
367           
368           aBounds[2] = min(aBounds[2],aNode->Y());
369           aBounds[3] = max(aBounds[3],aNode->Y());
370           
371           aBounds[4] = min(aBounds[4],aNode->Z());
372           aBounds[5] = max(aBounds[5],aNode->Z());
373         }
374
375         double EPS = 1.0E-7;
376         anIsXDimension = (aBounds[1] - aBounds[0]) + abs(aBounds[1]) + abs(aBounds[0]) > EPS;
377         anIsYDimension = (aBounds[3] - aBounds[2]) + abs(aBounds[3]) + abs(aBounds[2]) > EPS;
378         anIsZDimension = (aBounds[5] - aBounds[4]) + abs(aBounds[5]) + abs(aBounds[4]) > EPS;
379         aMeshDimension = anIsXDimension + anIsYDimension + anIsZDimension;
380         if(!aMeshDimension)
381           aMeshDimension = 3;
382         // PAL16857(SMESH not conform to the MED convention):
383         if ( aMeshDimension == 2 && anIsZDimension ) // 2D only if mesh is in XOY plane
384           aMeshDimension = 3;
385         // PAL18941(a saved study with a mesh belong Z is opened and the mesh is belong X)
386         if ( aMeshDimension == 1 && !anIsXDimension ) // 1D only if mesh is along OX
387           if ( anIsYDimension ) {
388             aMeshDimension = 2;
389             anIsXDimension = true;
390           } else {
391             aMeshDimension = 3;
392           }
393       }
394
395       SMDS_NodeIteratorPtr aNodesIter = myMesh->nodesIterator();
396       switch(aMeshDimension){
397       case 3:
398         aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aXYZGetCoord,aXYZName));
399         break;
400       case 2:
401         if(anIsXDimension && anIsYDimension)
402           aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aXYGetCoord,aXYName));
403         if(anIsYDimension && anIsZDimension)
404           aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aYZGetCoord,aYZName));
405         if(anIsXDimension && anIsZDimension)
406           aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aXZGetCoord,aXZName));
407         break;
408       case 1:
409         if(anIsXDimension)
410           aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aXGetCoord,aXName));
411         if(anIsYDimension)
412           aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aYGetCoord,aYName));
413         if(anIsZDimension)
414           aCoordHelperPtr.reset(new TCoordHelper(aNodesIter,aZGetCoord,aZName));
415         break;
416       }
417     }
418
419     
420     PMeshInfo aMeshInfo = myMed->CrMeshInfo(aMeshDimension,aMeshName);
421     MESSAGE("Add - aMeshName : "<<aMeshName<<"; "<<aMeshInfo->GetName());
422     myMed->SetMeshInfo(aMeshInfo);
423
424     // Storing SMDS groups and sub-meshes as med families
425     //----------------------------------------------------
426     int myNodesDefaultFamilyId   = 0;
427     int my0DElementsDefaultFamilyId = 0;
428     int myEdgesDefaultFamilyId   = 0;
429     int myFacesDefaultFamilyId   = 0;
430     int myVolumesDefaultFamilyId = 0;
431     int nbNodes   = myMesh->NbNodes();
432     int nb0DElements = myMesh->Nb0DElements();
433     int nbEdges   = myMesh->NbEdges();
434     int nbFaces   = myMesh->NbFaces();
435     int nbVolumes = myMesh->NbVolumes();
436     if (myDoGroupOfNodes && nbNodes)
437       myNodesDefaultFamilyId = REST_NODES_FAMILY;
438     if (myDoGroupOfEdges && nbEdges)
439       myEdgesDefaultFamilyId = REST_EDGES_FAMILY;
440     if (myDoGroupOfFaces && nbFaces)
441       myFacesDefaultFamilyId = REST_FACES_FAMILY;
442     if (myDoGroupOfVolumes && nbVolumes)
443       myVolumesDefaultFamilyId = REST_VOLUMES_FAMILY;
444
445     MESSAGE("Perform - aFamilyInfo");
446     //cout << " DriverMED_Family::MakeFamilies() " << endl;
447     list<DriverMED_FamilyPtr> aFamilies;
448     if (myAllSubMeshes) {
449       aFamilies = DriverMED_Family::MakeFamilies
450         (myMesh->SubMeshes(), myGroups,
451          myDoGroupOfNodes   && nbNodes,
452          myDoGroupOfEdges   && nbEdges,
453          myDoGroupOfFaces   && nbFaces,
454          myDoGroupOfVolumes && nbVolumes);
455     } else {
456       aFamilies = DriverMED_Family::MakeFamilies
457         (mySubMeshes, myGroups,
458          myDoGroupOfNodes   && nbNodes,
459          myDoGroupOfEdges   && nbEdges,
460          myDoGroupOfFaces   && nbFaces,
461          myDoGroupOfVolumes && nbVolumes);
462     }
463     //cout << " myMed->SetFamilyInfo() " << endl;
464     list<DriverMED_FamilyPtr>::iterator aFamsIter;
465     for (aFamsIter = aFamilies.begin(); aFamsIter != aFamilies.end(); aFamsIter++)
466     {
467       PFamilyInfo aFamilyInfo = (*aFamsIter)->GetFamilyInfo(myMed,aMeshInfo);
468       myMed->SetFamilyInfo(aFamilyInfo);
469     }
470
471     // Storing SMDS nodes to the MED file for the MED mesh
472     //----------------------------------------------------
473 #ifdef _EDF_NODE_IDS_
474     typedef map<TInt,TInt> TNodeIdMap;
475     TNodeIdMap aNodeIdMap;
476 #endif
477     const EModeSwitch   theMode        = eFULL_INTERLACE;
478     const ERepere       theSystem      = eCART;
479     const EBooleen      theIsElemNum   = eVRAI;
480     const EBooleen      theIsElemNames = eFAUX;
481     const EConnectivite theConnMode    = eNOD;
482
483     TInt aNbNodes = myMesh->NbNodes();
484     //cout << " myMed->CrNodeInfo() aNbNodes = " << aNbNodes << endl;
485     PNodeInfo aNodeInfo = myMed->CrNodeInfo(aMeshInfo, aNbNodes,
486                                             theMode, theSystem, theIsElemNum, theIsElemNames);
487
488     //cout << " fillElemFamilyMap( SMDSAbs_Node )" << endl;
489     // find family numbers for nodes
490     TElemFamilyMap anElemFamMap;
491     fillElemFamilyMap( anElemFamMap, aFamilies, SMDSAbs_Node );
492
493     for (TInt iNode = 0; aCoordHelperPtr->Next(); iNode++)
494     {
495       // coordinates
496       TCoordSlice aTCoordSlice = aNodeInfo->GetCoordSlice( iNode );
497       for(TInt iCoord = 0; iCoord < aMeshDimension; iCoord++){
498         aTCoordSlice[iCoord] = aCoordHelperPtr->GetCoord(iCoord);
499       }
500       // node number
501       int aNodeID = aCoordHelperPtr->GetID();
502       aNodeInfo->SetElemNum( iNode, aNodeID );
503 #ifdef _EDF_NODE_IDS_
504       aNodeIdMap[aNodeID] = iNode+1;
505 #endif
506       // family number
507       const SMDS_MeshNode* aNode = aCoordHelperPtr->GetNode();
508       int famNum = getFamilyId( anElemFamMap, aNode, myNodesDefaultFamilyId );
509       aNodeInfo->SetFamNum( iNode, famNum );
510     }
511     anElemFamMap.Clear();
512
513     // coordinate names and units
514     for (TInt iCoord = 0; iCoord < aMeshDimension; iCoord++) {
515       aNodeInfo->SetCoordName( iCoord, aCoordHelperPtr->GetName(iCoord));
516       aNodeInfo->SetCoordUnit( iCoord, aCoordHelperPtr->GetUnit(iCoord));
517     }
518
519     //cout << " SetNodeInfo(aNodeInfo)" << endl;
520     MESSAGE("Perform - aNodeInfo->GetNbElem() = "<<aNbNodes);
521     myMed->SetNodeInfo(aNodeInfo);
522     aNodeInfo.reset(); // free memory used for arrays
523
524
525     // Storing SMDS elements to the MED file for the MED mesh
526     //-------------------------------------------------------
527     // Write one element type at once in order to minimize memory usage (PAL19276)
528
529     const SMDS_MeshInfo& nbElemInfo = myMesh->GetMeshInfo();
530
531     // poly elements are not supported by med-2.1
532     bool polyTypesSupported = myMed->CrPolygoneInfo(aMeshInfo,eMAILLE,ePOLYGONE,0,0);
533     TInt nbPolygonNodes = 0, nbPolyhedronNodes = 0, nbPolyhedronFaces = 0;
534
535     // collect info on all geom types
536
537     list< TElemTypeData > aTElemTypeDatas;
538
539     EEntiteMaillage anEntity = eMAILLE;
540 #ifdef _ELEMENTS_BY_DIM_
541     anEntity = eNOEUD_ELEMENT;
542 #endif
543     aTElemTypeDatas.push_back(TElemTypeData(anEntity,
544                                             ePOINT1,
545                                             nbElemInfo.Nb0DElements(),
546                                             SMDSAbs_0DElement));
547 #ifdef _ELEMENTS_BY_DIM_
548     anEntity = eARETE;
549 #endif
550     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
551                                             eSEG2,
552                                             nbElemInfo.NbEdges( ORDER_LINEAR ),
553                                             SMDSAbs_Edge));
554     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
555                                             eSEG3,
556                                             nbElemInfo.NbEdges( ORDER_QUADRATIC ),
557                                             SMDSAbs_Edge));
558 #ifdef _ELEMENTS_BY_DIM_
559     anEntity = eFACE;
560 #endif
561     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
562                                             eTRIA3,
563                                             nbElemInfo.NbTriangles( ORDER_LINEAR ),
564                                             SMDSAbs_Face));
565     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
566                                             eTRIA6,
567                                             nbElemInfo.NbTriangles( ORDER_QUADRATIC ),
568                                             SMDSAbs_Face));
569     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
570                                             eQUAD4,
571                                             nbElemInfo.NbQuadrangles( ORDER_LINEAR ),
572                                             SMDSAbs_Face));
573     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
574                                             eQUAD8,
575                                             nbElemInfo.NbQuadrangles( ORDER_QUADRATIC ),
576                                             SMDSAbs_Face));
577     if ( polyTypesSupported ) {
578       aTElemTypeDatas.push_back( TElemTypeData(anEntity,
579                                                ePOLYGONE,
580                                                nbElemInfo.NbPolygons(),
581                                                SMDSAbs_Face));
582       // we need one more loop on poly elements to count nb of their nodes
583       aTElemTypeDatas.push_back( TElemTypeData(anEntity,
584                                                ePOLYGONE,
585                                                nbElemInfo.NbPolygons(),
586                                                SMDSAbs_Face));
587     }
588 #ifdef _ELEMENTS_BY_DIM_
589     anEntity = eMAILLE;
590 #endif
591     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
592                                             eTETRA4,
593                                             nbElemInfo.NbTetras( ORDER_LINEAR ),
594                                             SMDSAbs_Volume));
595     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
596                                             eTETRA10,
597                                             nbElemInfo.NbTetras( ORDER_QUADRATIC ),
598                                             SMDSAbs_Volume));
599     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
600                                             ePYRA5,
601                                             nbElemInfo.NbPyramids( ORDER_LINEAR ),
602                                             SMDSAbs_Volume));
603     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
604                                             ePYRA13,
605                                             nbElemInfo.NbPyramids( ORDER_QUADRATIC ),
606                                             SMDSAbs_Volume));
607     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
608                                             ePENTA6,
609                                             nbElemInfo.NbPrisms( ORDER_LINEAR ),
610                                             SMDSAbs_Volume));
611     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
612                                              ePENTA15,
613                                              nbElemInfo.NbPrisms( ORDER_QUADRATIC ),
614                                              SMDSAbs_Volume));
615     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
616                                              eHEXA8,
617                                              nbElemInfo.NbHexas( ORDER_LINEAR ),
618                                              SMDSAbs_Volume));
619     aTElemTypeDatas.push_back( TElemTypeData(anEntity,
620                                              eHEXA20,
621                                              nbElemInfo.NbHexas( ORDER_QUADRATIC ),
622                                              SMDSAbs_Volume));
623     if ( polyTypesSupported ) {
624       aTElemTypeDatas.push_back( TElemTypeData(anEntity,
625                                                ePOLYEDRE,
626                                                nbElemInfo.NbPolyhedrons(),
627                                                SMDSAbs_Volume));
628       // we need one more loop on poly elements to count nb of their nodes
629       aTElemTypeDatas.push_back( TElemTypeData(anEntity,
630                                                ePOLYEDRE,
631                                                nbElemInfo.NbPolyhedrons(),
632                                                SMDSAbs_Volume));
633     }
634
635     vector< bool > isElemFamMapBuilt( SMDSAbs_NbElementTypes, false );
636
637     // loop on all geom types of elements
638
639     list< TElemTypeData >::iterator aElemTypeData = aTElemTypeDatas.begin();
640     for ( ; aElemTypeData != aTElemTypeDatas.end(); ++aElemTypeData )
641     {
642       if ( aElemTypeData->_nbElems == 0 )
643         continue;
644
645       // iterator on elements of a current type
646       PElemIterator elemIterator;
647       int defaultFamilyId = 0;
648       switch ( aElemTypeData->_smdsType ) {
649       case SMDSAbs_0DElement:
650         elemIterator = PElemIterator( new T0DElementIterator( myMesh->elements0dIterator() ));
651         defaultFamilyId = my0DElementsDefaultFamilyId;
652         break;
653       case SMDSAbs_Edge:
654         elemIterator = PElemIterator( new TEdgeIterator( myMesh->edgesIterator() ));
655         defaultFamilyId = myEdgesDefaultFamilyId;
656         break;
657       case SMDSAbs_Face:
658         elemIterator = PElemIterator( new TFaceIterator( myMesh->facesIterator() ));
659         defaultFamilyId = myFacesDefaultFamilyId;
660         break;
661       case SMDSAbs_Volume:
662         elemIterator = PElemIterator( new TVolumeIterator( myMesh->volumesIterator() ));
663         defaultFamilyId = myVolumesDefaultFamilyId;
664         break;
665       default:
666         continue;
667       }
668       int iElem = 0;
669
670       //cout << " Treat type " << aElemTypeData->_geomType << " nb = " <<aElemTypeData->_nbElems<< endl;
671       // Treat POLYGONs
672       // ---------------
673       if ( aElemTypeData->_geomType == ePOLYGONE )
674       {
675         if ( nbPolygonNodes == 0 ) {
676           // Count nb of nodes
677           while ( const SMDS_MeshElement* anElem = elemIterator->next() ) {
678             if ( anElem->IsPoly() ) {
679               nbPolygonNodes += anElem->NbNodes();
680               if ( ++iElem == aElemTypeData->_nbElems )
681                 break;
682             }
683           }
684         }
685         else {
686           // Store in med file
687           PPolygoneInfo aPolygoneInfo = myMed->CrPolygoneInfo(aMeshInfo,
688                                                               aElemTypeData->_entity,
689                                                               aElemTypeData->_geomType,
690                                                               aElemTypeData->_nbElems,
691                                                               nbPolygonNodes,
692                                                               theConnMode, theIsElemNum,
693                                                               theIsElemNames);
694           TElemNum & index = *(aPolygoneInfo->myIndex.get());
695           index[0] = 1;
696
697           while ( const SMDS_MeshElement* anElem = elemIterator->next() )
698           {
699             if ( !anElem->IsPoly() )
700               continue;
701
702             // index
703             TInt aNbNodes = anElem->NbNodes();
704             index[ iElem+1 ] = index[ iElem ] + aNbNodes;
705
706             // connectivity
707             TConnSlice aTConnSlice = aPolygoneInfo->GetConnSlice( iElem );
708             for(TInt iNode = 0; iNode < aNbNodes; iNode++) {
709               const SMDS_MeshElement* aNode = anElem->GetNode( iNode );
710 #ifdef _EDF_NODE_IDS_
711               aTConnSlice[ iNode ] = aNodeIdMap[aNode->GetID()];
712 #else
713               aTConnSlice[ iNode ] = aNode->GetID();
714 #endif
715             }
716             // element number
717             aPolygoneInfo->SetElemNum( iElem, anElem->GetID() );
718
719             // family number
720             int famNum = getFamilyId( anElemFamMap, anElem, defaultFamilyId );
721             aPolygoneInfo->SetFamNum( iElem, famNum );
722
723             if ( ++iElem == aPolygoneInfo->GetNbElem() )
724               break;
725           }
726           //       if(TInt aNbElems = aPolygoneElemNums.size())
727           //         // add one element in connectivities,
728           //         // referenced by the last element in indices
729           //         aPolygoneConn.push_back(0);
730           //cout << " SetPolygoneInfo(aPolygoneInfo)" << endl;
731           myMed->SetPolygoneInfo(aPolygoneInfo);
732         }
733
734       } 
735
736       // Treat POLYEDREs
737       // ----------------
738       else if (aElemTypeData->_geomType == ePOLYEDRE )
739       {
740         if ( nbPolyhedronNodes == 0 ) {
741           // Count nb of nodes
742           while ( const SMDS_MeshElement* anElem = elemIterator->next() ) {
743             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
744               dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( anElem );
745             if ( aPolyedre ) {
746               nbPolyhedronNodes += aPolyedre->NbNodes();
747               nbPolyhedronFaces += aPolyedre->NbFaces();
748               if ( ++iElem == aElemTypeData->_nbElems )
749                 break;
750             }
751           }
752         }
753         else {
754           // Store in med file
755           PPolyedreInfo aPolyhInfo = myMed->CrPolyedreInfo(aMeshInfo,
756                                                            aElemTypeData->_entity,
757                                                            aElemTypeData->_geomType,
758                                                            aElemTypeData->_nbElems,
759                                                            nbPolyhedronFaces+1,
760                                                            nbPolyhedronNodes,
761                                                            theConnMode,
762                                                            theIsElemNum,
763                                                            theIsElemNames);
764           TElemNum & index = *(aPolyhInfo->myIndex.get());
765           TElemNum & faces = *(aPolyhInfo->myFaces.get());
766           TElemNum & conn  = *(aPolyhInfo->myConn.get());
767           index[0] = 1;
768           faces[0] = 1;
769
770           TInt iFace = 0, iNode = 0;
771           while ( const SMDS_MeshElement* anElem = elemIterator->next() )
772           {
773             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
774               dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( anElem );
775             if ( !aPolyedre )
776               continue;
777
778             // index
779             TInt aNbFaces = aPolyedre->NbFaces();
780             index[ iElem+1 ] = index[ iElem ] + aNbFaces;
781
782             // face index
783             for (TInt f = 1; f <= aNbFaces; ++f, ++iFace ) {
784               int aNbFaceNodes = aPolyedre->NbFaceNodes( f );
785               faces[ iFace+1 ] = faces[ iFace ] + aNbFaceNodes;
786             }
787             // connectivity
788             SMDS_ElemIteratorPtr nodeIt = anElem->nodesIterator();
789             while ( nodeIt->more() ) {
790               const SMDS_MeshElement* aNode = nodeIt->next();
791 #ifdef _EDF_NODE_IDS_
792               conn[ iNode ] = aNodeIdMap[aNode->GetID()];
793 #else
794               conn[ iNode ] = aNode->GetID();
795 #endif
796               ++iNode;
797             }
798             // element number
799             aPolyhInfo->SetElemNum( iElem, anElem->GetID() );
800
801             // family number
802             int famNum = getFamilyId( anElemFamMap, anElem, defaultFamilyId );
803             aPolyhInfo->SetFamNum( iElem, famNum );
804
805             if ( ++iElem == aPolyhInfo->GetNbElem() )
806               break;
807           }
808           //cout << " SetPolyedreInfo(aPolyhInfo )" << endl;
809           myMed->SetPolyedreInfo(aPolyhInfo);
810         }
811       } // if (aElemTypeData->_geomType == ePOLYEDRE )
812
813       else
814       {
815         // Treat standard types
816         // ---------------------
817
818         // allocate data arrays
819         PCellInfo aCellInfo = myMed->CrCellInfo( aMeshInfo,
820                                                  aElemTypeData->_entity,
821                                                  aElemTypeData->_geomType,
822                                                  aElemTypeData->_nbElems,
823                                                  theConnMode,
824                                                  theIsElemNum,
825                                                  theIsElemNames);
826         // build map of family numbers for this type
827         if ( !isElemFamMapBuilt[ aElemTypeData->_smdsType ])
828         {
829           //cout << " fillElemFamilyMap()" << endl;
830           fillElemFamilyMap( anElemFamMap, aFamilies, aElemTypeData->_smdsType );
831           isElemFamMapBuilt[ aElemTypeData->_smdsType ] = true;
832         }
833
834         TInt aNbNodes = MED::GetNbNodes(aElemTypeData->_geomType);
835         while ( const SMDS_MeshElement* anElem = elemIterator->next() )
836         {
837           if ( anElem->NbNodes() != aNbNodes || anElem->IsPoly() )
838             continue; // other geometry
839
840           // connectivity
841           TConnSlice aTConnSlice = aCellInfo->GetConnSlice( iElem );
842           for (TInt iNode = 0; iNode < aNbNodes; iNode++) {
843             const SMDS_MeshElement* aNode = anElem->GetNode( iNode );
844 #ifdef _EDF_NODE_IDS_
845             aTConnSlice[ iNode ] = aNodeIdMap[aNode->GetID()];
846 #else
847             aTConnSlice[ iNode ] = aNode->GetID();
848 #endif
849           }
850           // element number
851           aCellInfo->SetElemNum( iElem, anElem->GetID() );
852
853           // family number
854           int famNum = getFamilyId( anElemFamMap, anElem, defaultFamilyId );
855           aCellInfo->SetFamNum( iElem, famNum );
856
857           if ( ++iElem == aCellInfo->GetNbElem() )
858             break;
859         }
860         // store data in a file
861         //cout << " SetCellInfo(aCellInfo)" << endl;
862         myMed->SetCellInfo(aCellInfo);
863       }
864
865     } // loop on geom types
866
867
868   }
869   catch(const std::exception& exc) {
870     INFOS("Follow exception was cought:\n\t"<<exc.what());
871     throw;
872   }
873   catch(...) {
874     INFOS("Unknown exception was cought !!!");
875     throw;
876   }
877
878   myMeshId = -1;
879   myGroups.clear();
880   mySubMeshes.clear();
881   return aResult;
882 }