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