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