]> SALOME platform Git repositories - tools/medcoupling.git/blob - src/MEDLoader/SauvMedConvertor.cxx
Salome HOME
0022211: [CEA 810] Error "NULL field support" when opening sauv files with MEDLoader
[tools/medcoupling.git] / src / MEDLoader / SauvMedConvertor.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // File      : SauvMedConvertor.cxx
20 // Created   : Tue Aug 16 14:43:20 2011
21 // Author    : Edward AGAPOV (eap)
22 //
23
24 #include "SauvMedConvertor.hxx"
25
26 #include "CellModel.hxx"
27 #include "MEDFileMesh.hxx"
28 #include "MEDFileField.hxx"
29 #include "MEDFileData.hxx"
30 #include "MEDCouplingFieldDouble.hxx"
31
32 #include <iostream>
33 #include <cassert>
34 #include <cmath>
35 #include <queue>
36 #include <limits>
37
38 #include <cstdlib>
39 #include <cstring>
40 #include <fcntl.h>
41
42 #ifdef WIN32
43 #include <io.h>
44 #endif
45
46 #ifndef WIN32
47 #define HAS_XDR
48 #include <unistd.h>
49 #endif
50
51 #ifdef HAS_XDR
52 #include <rpc/xdr.h>
53 #endif
54
55 using namespace SauvUtilities;
56 using namespace ParaMEDMEM;
57 using namespace std;
58
59 namespace
60 {
61   // for ASCII file reader
62   const int GIBI_MaxOutputLen = 150; // max length of a line in the sauve file
63   const int GIBI_BufferSize   = 16184; // for buffered reading
64
65   using namespace INTERP_KERNEL;
66
67   const size_t MaxMedCellType = NORM_ERROR;
68   const size_t NbGibiCellTypes = 47;
69   const TCellType GibiTypeToMed[NbGibiCellTypes] =
70     {
71       /*1 */ NORM_POINT1 ,/*2 */ NORM_SEG2   ,/*3 */ NORM_SEG3   ,/*4 */ NORM_TRI3   ,/*5 */ NORM_ERROR  ,
72       /*6 */ NORM_TRI6   ,/*7 */ NORM_ERROR  ,/*8 */ NORM_QUAD4  ,/*9 */ NORM_ERROR  ,/*10*/ NORM_QUAD8  ,
73       /*11*/ NORM_ERROR  ,/*12*/ NORM_ERROR  ,/*13*/ NORM_ERROR  ,/*14*/ NORM_HEXA8  ,/*15*/ NORM_HEXA20 ,
74       /*16*/ NORM_PENTA6 ,/*17*/ NORM_PENTA15,/*18*/ NORM_ERROR  ,/*19*/ NORM_ERROR  ,/*20*/ NORM_ERROR  ,
75       /*21*/ NORM_ERROR  ,/*22*/ NORM_ERROR  ,/*23*/ NORM_TETRA4 ,/*24*/ NORM_TETRA10,/*25*/ NORM_PYRA5  ,
76       /*26*/ NORM_PYRA13 ,/*27*/ NORM_ERROR  ,/*28*/ NORM_ERROR  ,/*29*/ NORM_ERROR  ,/*30*/ NORM_ERROR  ,
77       /*31*/ NORM_ERROR  ,/*32*/ NORM_ERROR  ,/*33*/ NORM_ERROR  ,/*34*/ NORM_ERROR  ,/*35*/ NORM_ERROR  ,
78       /*36*/ NORM_ERROR  ,/*37*/ NORM_ERROR  ,/*38*/ NORM_ERROR  ,/*39*/ NORM_ERROR  ,/*40*/ NORM_ERROR  ,
79       /*41*/ NORM_ERROR  ,/*42*/ NORM_ERROR  ,/*43*/ NORM_ERROR  ,/*44*/ NORM_ERROR  ,/*45*/ NORM_ERROR  ,
80       /*46*/ NORM_ERROR  ,/*47*/ NORM_ERROR
81     };
82
83   //================================================================================
84   /*!
85    * \brief Return dimension of a group
86    */
87   //================================================================================
88
89   unsigned getDim( const Group* grp )
90   {
91     return SauvUtilities::getDimension( grp->_groups.empty() ? grp->_cellType : grp->_groups[0]->_cellType );
92   }
93
94   //================================================================================
95   /*!
96    * \brief Converts connectivity of quadratic elements
97    */
98   //================================================================================
99
100   inline void ConvertQuadratic( const INTERP_KERNEL::NormalizedCellType type,
101                                 const Cell &                            aCell )
102   {
103     if ( const int * conn = getGibi2MedQuadraticInterlace( type ))
104       {
105         Cell* ma = const_cast<Cell*>(&aCell);
106         vector< Node* > new_nodes( ma->_nodes.size() );
107         for ( size_t i = 0; i < new_nodes.size(); ++i )
108           new_nodes[ i ] = ma->_nodes[ conn[ i ]];
109         ma->_nodes.swap( new_nodes );
110       }
111   }
112
113   //================================================================================
114   /*!
115    * \brief Returns a vector of pairs of node indices to inverse a med volume element
116    */
117   //================================================================================
118
119   void getReverseVector (const INTERP_KERNEL::NormalizedCellType type,
120                          vector<pair<int,int> > &                swapVec )
121   {
122     swapVec.clear();
123
124     switch ( type )
125       {
126       case NORM_TETRA4:
127         swapVec.resize(1);
128         swapVec[0] = make_pair( 1, 2 );
129         break;
130       case NORM_PYRA5:
131         swapVec.resize(1);
132         swapVec[0] = make_pair( 1, 3 );
133         break;
134       case NORM_PENTA6:
135         swapVec.resize(2);
136         swapVec[0] = make_pair( 1, 2 );
137         swapVec[1] = make_pair( 4, 5 );
138         break;
139       case NORM_HEXA8:
140         swapVec.resize(2);
141         swapVec[0] = make_pair( 1, 3 );
142         swapVec[1] = make_pair( 5, 7 );
143         break;
144       case NORM_TETRA10:
145         swapVec.resize(3);
146         swapVec[0] = make_pair( 1, 2 );
147         swapVec[1] = make_pair( 4, 6 );
148         swapVec[2] = make_pair( 8, 9 );
149         break;
150       case NORM_PYRA13:
151         swapVec.resize(4);
152         swapVec[0] = make_pair( 1, 3 );
153         swapVec[1] = make_pair( 5, 8 );
154         swapVec[2] = make_pair( 6, 7 );
155         swapVec[3] = make_pair( 10, 12 );
156         break;
157       case NORM_PENTA15:
158         swapVec.resize(4);
159         swapVec[0] = make_pair( 1, 2 );
160         swapVec[1] = make_pair( 4, 5 );
161         swapVec[2] = make_pair( 6, 8 );
162         swapVec[3] = make_pair( 9, 11 );
163         break;
164       case NORM_HEXA20:
165         swapVec.resize(7);
166         swapVec[0] = make_pair( 1, 3 );
167         swapVec[1] = make_pair( 5, 7 );
168         swapVec[2] = make_pair( 8, 11 );
169         swapVec[3] = make_pair( 9, 10 );
170         swapVec[4] = make_pair( 12, 15 );
171         swapVec[5] = make_pair( 13, 14 );
172         swapVec[6] = make_pair( 17, 19 );
173         break;
174         //   case NORM_SEG3: no need to reverse edges
175         //     swapVec.resize(1);
176         //     swapVec[0] = make_pair( 1, 2 );
177         //     break;
178       case NORM_TRI6:
179         swapVec.resize(2);
180         swapVec[0] = make_pair( 1, 2 );
181         swapVec[1] = make_pair( 3, 5 );
182         break;
183       case NORM_QUAD8:
184         swapVec.resize(3);
185         swapVec[0] = make_pair( 1, 3 );
186         swapVec[1] = make_pair( 4, 7 );
187         swapVec[2] = make_pair( 5, 6 );
188         break;
189       default:;
190       }
191   }
192
193   //================================================================================
194   /*!
195    * \brief Inverses element orientation using vector of indices to swap
196    */
197   //================================================================================
198
199   inline void reverse(const Cell & aCell, const vector<pair<int,int> > & swapVec )
200   {
201     Cell* ma = const_cast<Cell*>(&aCell);
202     for ( unsigned i = 0; i < swapVec.size(); ++i )
203       std::swap( ma->_nodes[ swapVec[i].first ],
204                  ma->_nodes[ swapVec[i].second ]);
205     if ( swapVec.empty() )
206       ma->_reverse = true;
207     else
208       ma->_reverse = false;
209   }
210   //================================================================================
211   /*!
212    * \brief Comparator of cells by number used for ordering cells within a med group
213    */
214   struct TCellByIDCompare
215   {
216     bool operator () (const Cell* i1, const Cell* i2)
217     {
218       return i1->_number < i2->_number;
219     }
220   };
221   typedef map< const Cell*, unsigned, TCellByIDCompare > TCellToOrderMap;
222
223   //================================================================================
224   /*!
225    * \brief Fill Group::_relocTable if necessary
226    */
227   //================================================================================
228
229   void setRelocationTable( Group* grp, TCellToOrderMap& cell2order )
230   {
231     if ( !grp->_isProfile ) return;
232
233     // check if relocation table is necessary
234     bool isRelocated = false;
235     unsigned newOrder = 0;
236     TCellToOrderMap::iterator c2oIt = cell2order.begin(), c2oEnd = cell2order.end();
237     for ( ; !isRelocated && c2oIt != c2oEnd; ++c2oIt, ++newOrder )
238       isRelocated = ( c2oIt->second != newOrder );
239
240     if ( isRelocated )
241     {
242       grp->_relocTable.resize( cell2order.size() );
243       for ( newOrder = 0, c2oIt = cell2order.begin(); c2oIt != c2oEnd; ++c2oIt, ++newOrder )
244         grp->_relocTable[ c2oIt->second ] = newOrder;
245     }
246   }
247 }
248
249 //================================================================================
250 /*!
251  * \brief Return dimension for the given cell type
252  */
253 //================================================================================
254
255 unsigned SauvUtilities::getDimension( INTERP_KERNEL::NormalizedCellType type )
256 {
257   return type == NORM_ERROR ? -1 : INTERP_KERNEL::CellModel::GetCellModel( type ).getDimension();
258 }
259
260 //================================================================================
261 /*!
262  * \brief Returns interlace array to transform a quadratic GIBI element to a MED one.
263  *        i-th array item gives node index in GIBI connectivity for i-th MED node
264  */
265 //================================================================================
266
267 const int * SauvUtilities::getGibi2MedQuadraticInterlace( INTERP_KERNEL::NormalizedCellType type )
268 {
269   static vector<const int*> conn;
270   static const int hexa20 [] = {0,6,4,2, 12,18,16,14, 7,5,3,1, 19,17,15,13, 8,11,10,9};
271   static const int penta15[] = {0,2,4, 9,11,13, 1,3,5, 10,12,14, 6,8,7};
272   static const int pyra13 [] = {0,2,4,6, 12, 1,3,5,7, 8,9,10,11};
273   static const int tetra10[] = {0,2,4, 9, 1,3,5, 6,7,8};
274   static const int quad8  [] = {0,2,4,6, 1,3,5,7};
275   static const int tria6  [] = {0,2,4, 1,3,5};
276   static const int seg3   [] = {0,2,1};
277   if ( conn.empty() )
278   {
279     conn.resize( MaxMedCellType + 1, 0 );
280     conn[ NORM_HEXA20 ] = hexa20;
281     conn[ NORM_PENTA15] = penta15;
282     conn[ NORM_PYRA13 ] = pyra13;
283     conn[ NORM_TETRA10] = tetra10;
284     conn[ NORM_SEG3   ] = seg3;
285     conn[ NORM_TRI6   ] = tria6;
286     conn[ NORM_QUAD8  ] = quad8;
287   }
288   return conn[ type ];
289 }
290
291 //================================================================================
292 /*!
293  * \brief Avoid coping sortedNodeIDs
294  */
295 //================================================================================
296
297 Cell::Cell(const Cell& ma)
298   : _nodes(ma._nodes), _reverse(ma._reverse), _sortedNodeIDs(0), _number(ma._number)
299 {
300   if ( ma._sortedNodeIDs )
301     {
302       _sortedNodeIDs = new int[ _nodes.size() ];
303       std::copy( ma._sortedNodeIDs, ma._sortedNodeIDs + _nodes.size(), _sortedNodeIDs );
304     }
305 }
306
307 //================================================================================
308 /*!
309  * \brief Rerturn the i-th link of face
310  */
311 //================================================================================
312
313 SauvUtilities::Link Cell::link(int i) const
314 {
315   int i2 = ( i + 1 ) % _nodes.size();
316   if ( _reverse )
317     return make_pair( _nodes[i2]->_number, _nodes[i]->_number );
318   else
319     return make_pair( _nodes[i]->_number, _nodes[i2]->_number );
320 }
321
322 //================================================================================
323 /*!
324  * \brief creates if needed and return _sortedNodeIDs
325  */
326 //================================================================================
327
328 const TID* Cell::getSortedNodes() const
329 {
330   if ( !_sortedNodeIDs )
331   {
332     size_t l=_nodes.size();
333     _sortedNodeIDs = new int[ l ];
334
335     for (size_t i=0; i!=l; ++i)
336       _sortedNodeIDs[i]=_nodes[i]->_number;
337     std::sort( _sortedNodeIDs, _sortedNodeIDs + l );
338   }
339   return _sortedNodeIDs;
340 }
341
342 //================================================================================
343 /*!
344  * \brief Compare sorted ids of cell nodes
345  */
346 //================================================================================
347
348 bool Cell::operator< (const Cell& ma) const
349 {
350   if ( _nodes.size() == 1 )
351     return _nodes[0] < ma._nodes[0];
352
353   const int* v1 = getSortedNodes();
354   const int* v2 = ma.getSortedNodes();
355   for ( const int* vEnd = v1 + _nodes.size(); v1 < vEnd; ++v1, ++v2 )
356     if(*v1 != *v2)
357       return *v1 < *v2;
358   return false;
359 }
360
361 //================================================================================
362 /*!
363  * \brief Dump a Cell
364  */
365 //================================================================================
366
367 std::ostream& SauvUtilities::operator<< (std::ostream& os, const SauvUtilities::Cell& ma)
368 {
369   os << "cell " << ma._number << " (" << ma._nodes.size() << " nodes) : < " << ma._nodes[0]->_number;
370   for( size_t i=1; i!=ma._nodes.size(); ++i)
371     os << ", " << ma._nodes[i]->_number;
372 #ifdef _DEBUG_
373   os << " > sortedNodes: ";
374   if ( ma._sortedNodeIDs ) {
375     os << "< ";
376     for( size_t i=0; i!=ma._nodes.size(); ++i)
377       os << ( i ? ", " : "" ) << ma._sortedNodeIDs[i];
378     os << " >";
379   }
380   else {
381     os << "NULL";
382   }
383 #endif
384   return os;
385 }
386
387 //================================================================================
388 /*!
389  * \brief Return nb of elements in the group
390  */
391 //================================================================================
392
393 int Group::size() const
394 {
395   int sizze = 0;
396   if ( !_relocTable.empty() )
397     sizze =  _relocTable.size();
398   else if ( _medGroup )
399     sizze = _medGroup->getNumberOfTuples();
400   else if ( !_cells.empty() )
401     sizze = _cells.size();
402   else
403     for ( size_t i = 0; i < _groups.size(); ++i )
404       sizze += _groups[i]->size();
405   return sizze;
406 }
407
408 //================================================================================
409 /*!
410  * \brief Conver gibi element type to med one
411  */
412 //================================================================================
413
414 INTERP_KERNEL::NormalizedCellType SauvUtilities::gibi2medGeom( size_t gibiType )
415 {
416   if ( gibiType < 1 || gibiType > NbGibiCellTypes )
417     return NORM_ERROR;
418
419   return GibiTypeToMed[ gibiType - 1 ];
420 }
421
422 //================================================================================
423 /*!
424  * \brief Conver med element type to gibi one
425  */
426 //================================================================================
427
428 int SauvUtilities::med2gibiGeom( INTERP_KERNEL::NormalizedCellType medGeomType )
429 {
430   for ( unsigned int i = 0; i < NbGibiCellTypes; i++ )
431     if ( GibiTypeToMed[ i ] == medGeomType )
432       return i + 1;
433
434   return -1;
435 }
436
437 //================================================================================
438 /*!
439  * \brief Remember the file name
440  */
441 //================================================================================
442
443 FileReader::FileReader(const char* fileName):_fileName(fileName),_iRead(0),_nbToRead(0)
444 {
445 }
446
447 //================================================================================
448 /*!
449  * \brief Constructor of ASCII sauve file reader
450  */
451 //================================================================================
452
453 ASCIIReader::ASCIIReader(const char* fileName)
454   :FileReader(fileName),
455    _file(-1)
456 {
457 }
458
459 //================================================================================
460 /*!
461  * \brief Return true
462  */
463 //================================================================================
464
465 bool ASCIIReader::isASCII() const
466 {
467   return true;
468 }
469
470 //================================================================================
471 /*!
472  * \brief Try to open an ASCII file
473  */
474 //================================================================================
475
476 bool ASCIIReader::open()
477 {
478 #ifdef WIN32
479   _file = ::_open (_fileName.c_str(), _O_RDONLY|_O_BINARY);
480 #else
481   _file = ::open (_fileName.c_str(), O_RDONLY);
482 #endif
483   if (_file >= 0)
484     {
485       _start  = new char [GIBI_BufferSize]; // working buffer beginning
486       //_tmpBuf = new char [GIBI_MaxOutputLen];
487       _ptr    = _start;
488       _eptr   = _start;
489       _lineNb = 0;
490     }
491   else
492     {
493       //THROW_IK_EXCEPTION("Can't open file "<<_fileName << " fd: " << _file);
494     }
495   return (_file >= 0);
496 }
497
498 //================================================================================
499 /*!
500  * \brief Close the file
501  */
502 //================================================================================
503
504 ASCIIReader::~ASCIIReader()
505 {
506   if (_file >= 0)
507     {
508       ::close (_file);
509       if (_start != 0L)
510         {
511           delete [] _start;
512           //delete [] _tmpBuf;
513           _start = 0;
514         }
515       _file = -1;
516     }
517 }
518
519 //================================================================================
520 /*!
521  * \brief Return a next line of the file
522  */
523 //================================================================================
524
525 bool ASCIIReader::getNextLine (char* & line, bool raiseOEF /*= true*/ )
526 {
527   if ( getLine( line )) return true;
528   if ( raiseOEF )
529     THROW_IK_EXCEPTION("Unexpected EOF on ln "<<_lineNb);
530   return false;
531 }
532
533 //================================================================================
534 /*!
535  * \brief Read a next line of the file if necessary
536  */
537 //================================================================================
538
539 bool ASCIIReader::getLine(char* & line)
540 {
541   bool aResult = true;
542   // Check the state of the buffer;
543   // if there is too little left, read the next portion of data
544   int nBytesRest = _eptr - _ptr;
545   if (nBytesRest < GIBI_MaxOutputLen)
546     {
547       if (nBytesRest > 0)
548         {
549           // move the remaining portion to the buffer beginning
550           for ( int i = 0; i < nBytesRest; ++i )
551             _start[i] = _ptr[i];
552           //memcpy (_tmpBuf, _ptr, nBytesRest);
553           //memcpy (_start, _tmpBuf, nBytesRest);
554         }
555       else
556         {
557           nBytesRest = 0;
558         }
559       _ptr = _start;
560       const int nBytesRead = ::read (_file,
561                                      &_start [nBytesRest],
562                                      GIBI_BufferSize - nBytesRest);
563       nBytesRest += nBytesRead;
564       _eptr = &_start [nBytesRest];
565     }
566   // Check the buffer for the end-of-line
567   char * ptr = _ptr;
568   while (true)
569     {
570       // Check for end-of-the-buffer, the ultimate criterion for termination
571       if (ptr >= _eptr)
572         {
573           if (nBytesRest <= 0)
574             aResult = false;
575           else
576             _eptr[-1] = '\0';
577           break;
578         }
579       // seek the line-feed character
580       if (ptr[0] == '\n')
581         {
582           if (ptr[-1] == '\r')
583             ptr[-1] = '\0';
584           ptr[0] = '\0';
585           ++ptr;
586           break;
587         }
588       ++ptr;
589     }
590   // Output the result
591   line = _ptr;
592   _ptr = ptr;
593   _lineNb++;
594
595   return aResult;
596 }
597
598 //================================================================================
599 /*!
600  * \brief Prepare for iterating over given nb of values
601  *  \param nbToRead - nb of fields to read
602  *  \param nbPosInLine - nb of fields in one line
603  *  \param width - field width
604  *  \param shift - shift from line beginning to the field start
605  */
606 //================================================================================
607
608 void ASCIIReader::init( int nbToRead, int nbPosInLine, int width, int shift /*= 0*/ )
609 {
610   _nbToRead    = nbToRead;
611   _nbPosInLine = nbPosInLine;
612   _width       = width;
613   _shift       = shift;
614   _iPos = _iRead = 0;
615   if ( _nbToRead )
616     {
617       getNextLine( _curPos );
618       _curPos = _curPos + _shift;
619     }
620   else
621     {
622       _curPos = 0;
623     }
624   _curLocale.clear();
625 }
626
627 //================================================================================
628 /*!
629  * \brief Prepare for iterating over given nb of string values
630  */
631 //================================================================================
632
633 void ASCIIReader::initNameReading(int nbValues, int width /*= 8*/)
634 {
635   init( nbValues, 72 / ( width + 1 ), width, 1 );
636 }
637
638 //================================================================================
639 /*!
640  * \brief Prepare for iterating over given nb of integer values
641  */
642 //================================================================================
643
644 void ASCIIReader::initIntReading(int nbValues)
645 {
646   init( nbValues, 10, 8 );
647 }
648
649 //================================================================================
650 /*!
651  * \brief Prepare for iterating over given nb of real values
652  */
653 //================================================================================
654
655 void ASCIIReader::initDoubleReading(int nbValues)
656 {
657   init( nbValues, 3, 22 );
658
659   // Correction 2 of getDouble(): set "C" numeric locale to read numbers
660   // with dot decimal point separator, as it is in SAUVE files
661   _curLocale = setlocale(LC_NUMERIC, "C");
662 }
663
664 //================================================================================
665 /*!
666  * \brief Return true if not all values have been read
667  */
668 //================================================================================
669
670 bool ASCIIReader::more() const
671 {
672   bool result = false;
673   if ( _iRead < _nbToRead)
674     {
675       if ( _curPos ) result = true;
676     }
677   return result;
678 }
679
680 //================================================================================
681 /*!
682  * \brief Go to the nex value
683  */
684 //================================================================================
685
686 void ASCIIReader::next()
687 {
688   if ( !more() )
689     THROW_IK_EXCEPTION("SauvUtilities::ASCIIReader::next(): no more() values to read");
690   ++_iRead;
691   ++_iPos;
692   if ( _iRead < _nbToRead )
693     {
694       if ( _iPos >= _nbPosInLine )
695         {
696           getNextLine( _curPos );
697           _curPos = _curPos + _shift;
698           _iPos = 0;
699         }
700       else
701         {
702           _curPos = _curPos + _width + _shift;
703         }
704     }
705   else
706     {
707       _curPos = 0;
708       if ( !_curLocale.empty() )
709         {
710           setlocale(LC_NUMERIC, _curLocale.c_str());
711           _curLocale.clear();
712         }
713     }
714 }
715
716 //================================================================================
717 /*!
718  * \brief Return the current integer value
719  */
720 //================================================================================
721
722 int ASCIIReader::getInt() const
723 {
724   // fix for two glued ints (issue 0021009):
725   // Line nb    |   File contents
726   // ------------------------------------------------------------------------------------
727   // 53619905   |       1       2       6       8
728   // 53619906   |                                                                SCALAIRE
729   // 53619907   |    -63312600499       1       0       0       0      -2       0       2
730   //   where -63312600499 is actualy -633 and 12600499
731   char hold=_curPos[_width];
732   _curPos[_width] = '\0';
733   int result = atoi( _curPos );
734   _curPos[_width] = hold;
735   return result;
736   //return atoi(str());
737 }
738
739 //================================================================================
740 /*!
741  * \brief Return the current float value
742  */
743 //================================================================================
744
745 float ASCIIReader::getFloat() const
746 {
747   return getDouble();
748 }
749
750 //================================================================================
751 /*!
752  * \brief Return the current double value
753  */
754 //================================================================================
755
756 double ASCIIReader::getDouble() const
757 {
758   //std::string aStr (_curPos);
759
760   // Correction: add missing 'E' specifier
761   // int aPosStart = aStr.find_first_not_of(" \t");
762   // if (aPosStart < (int)aStr.length()) {
763   //   int aPosSign = aStr.find_first_of("+-", aPosStart + 1); // pass the leading symbol, as it can be a sign
764   //   if (aPosSign < (int)aStr.length()) {
765   //     if (aStr[aPosSign - 1] != 'e' && aStr[aPosSign - 1] != 'E')
766   //       aStr.insert(aPosSign, "E", 1);
767   //   }
768   // }
769
770   // Different Correction (more optimal)
771   // Sample:
772   //  0.00000000000000E+00 -2.37822406690632E+01  6.03062748797469E+01
773   //  7.70000000000000-100  7.70000000000000+100  7.70000000000000+100
774   //0123456789012345678901234567890123456789012345678901234567890123456789
775   const size_t posE = 18;
776   std::string aStr (_curPos);
777   if ( aStr.find('E') < 0 && aStr.find('e') < 0 )
778     {
779       if ( aStr.size() < posE+1 )
780         THROW_IK_EXCEPTION("No more doubles (line #" << lineNb() << ")");
781       aStr.insert( posE, "E", 1 );
782       return atof(aStr.c_str());
783     }
784   return atof( _curPos );
785 }
786
787 //================================================================================
788 /*!
789  * \brief Return the current string value
790  */
791 //================================================================================
792
793 string ASCIIReader::getName() const
794 {
795   int len = _width;
796   while (( _curPos[len-1] == ' ' || _curPos[len-1] == 0) && len > 0 )
797     len--;
798   return string( _curPos, len );
799 }
800
801 //================================================================================
802 /*!
803  * \brief Constructor of a binary sauve file reader
804  */
805 //================================================================================
806
807 XDRReader::XDRReader(const char* fileName) :FileReader(fileName), _xdrs_file(NULL)
808 {
809 }
810
811 //================================================================================
812 /*!
813  * \brief Close the XDR sauve file
814  */
815 //================================================================================
816
817 XDRReader::~XDRReader()
818 {
819 #ifdef HAS_XDR  
820   if ( _xdrs_file )
821     {
822       xdr_destroy((XDR*)_xdrs);
823       free((XDR*)_xdrs);
824       ::fclose(_xdrs_file);
825       _xdrs_file = NULL;
826     }
827 #endif
828 }
829
830 //================================================================================
831 /*!
832  * \brief Return false
833  */
834 //================================================================================
835
836 bool XDRReader::isASCII() const
837 {
838   return false;
839 }
840
841 //================================================================================
842 /*!
843  * \brief Try to open an XRD file
844  */
845 //================================================================================
846
847 bool XDRReader::open()
848 {
849   bool xdr_ok = false;
850 #ifdef HAS_XDR
851   if ((_xdrs_file = ::fopen(_fileName.c_str(), "r")))
852     {
853       _xdrs = (XDR *)malloc(sizeof(XDR));
854       xdrstdio_create((XDR*)_xdrs, _xdrs_file, XDR_DECODE);
855
856       const int maxsize = 10;
857       char icha[maxsize+1];
858       char* icha2 = icha;
859       if (( xdr_ok = xdr_string((XDR*)_xdrs, &icha2, maxsize)))
860         {
861           icha[maxsize] = '\0';
862           xdr_ok = (strcmp(icha, "CASTEM XDR") == 0);
863         }
864       if ( !xdr_ok )
865         {
866           xdr_destroy((XDR*)_xdrs);
867           free((XDR*)_xdrs);
868           fclose(_xdrs_file);
869           _xdrs_file = NULL;
870         }
871     }
872 #endif
873   return xdr_ok;
874 }
875
876 //================================================================================
877 /*!
878  * \brief A stub
879  */
880 //================================================================================
881
882 bool XDRReader::getNextLine (char* &, bool )
883 {
884   return true;
885 }
886
887 //================================================================================
888 /*!
889  * \brief Prepare for iterating over given nb of values
890  *  \param nbToRead - nb of fields to read
891  *  \param width - field width
892  */
893 //================================================================================
894
895 void XDRReader::init( int nbToRead, int width/*=0*/ )
896 {
897   if(_iRead < _nbToRead)
898     {
899       cout << "_iRead, _nbToRead : " << _iRead << " " << _nbToRead << endl;
900       cout << "Unfinished iteration before new one !" << endl;
901       THROW_IK_EXCEPTION("SauvUtilities::XDRReader::init(): Unfinished iteration before new one !");
902     }
903   _iRead    = 0;
904   _nbToRead = nbToRead;
905   _width    = width;
906 }
907
908 //================================================================================
909 /*!
910  * \brief Prepare for iterating over given nb of string values
911  */
912 //================================================================================
913
914 void XDRReader::initNameReading(int nbValues, int width)
915 {
916   init( nbValues, width );
917   _xdr_kind = _xdr_kind_char;
918   if(nbValues*width)
919     {
920       unsigned int nels = nbValues*width;
921       _xdr_cvals = (char*)malloc((nels+1)*sizeof(char));
922 #ifdef HAS_XDR
923       xdr_string((XDR*)_xdrs, &_xdr_cvals, nels);
924 #endif
925       _xdr_cvals[nels] = '\0';
926     }
927 }
928
929 //================================================================================
930 /*!
931  * \brief Prepare for iterating over given nb of integer values
932  */
933 //================================================================================
934
935 void XDRReader::initIntReading(int nbValues)
936 {
937   init( nbValues );
938   _xdr_kind = _xdr_kind_int;
939   if(nbValues)
940     {
941 #ifdef HAS_XDR
942       unsigned int nels = nbValues;
943       unsigned int actual_nels;
944       _xdr_ivals = (int*)malloc(nels*sizeof(int));
945       xdr_array((XDR*)_xdrs, (char **)&_xdr_ivals, &actual_nels, nels, sizeof(int), (xdrproc_t)xdr_int);
946 #endif
947     }
948 }
949
950 //================================================================================
951 /*!
952  * \brief Prepare for iterating over given nb of real values
953  */
954 //================================================================================
955
956 void XDRReader::initDoubleReading(int nbValues)
957 {
958   init( nbValues );
959   _xdr_kind = _xdr_kind_double;
960   if(nbValues)
961     {
962 #ifdef HAS_XDR
963       unsigned int nels = nbValues;
964       unsigned int actual_nels;
965       _xdr_dvals = (double*)malloc(nels*sizeof(double));
966       xdr_array((XDR*)_xdrs, (char **)&_xdr_dvals, &actual_nels, nels, sizeof(double), (xdrproc_t)xdr_double);
967 #endif
968     }
969 }
970
971 //================================================================================
972 /*!
973  * \brief Return true if not all values have been read
974  */
975 //================================================================================
976
977 bool XDRReader::more() const
978 {
979   return _iRead < _nbToRead;
980 }
981
982 //================================================================================
983 /*!
984  * \brief Go to the nex value
985  */
986 //================================================================================
987
988 void XDRReader::next()
989 {
990   if ( !more() )
991     THROW_IK_EXCEPTION("SauvUtilities::XDRReader::next(): no more() values to read");
992
993   ++_iRead;
994   if ( _iRead < _nbToRead )
995     {
996     }
997   else
998     {
999       if(_xdr_kind == _xdr_kind_char) free(_xdr_cvals);
1000       if(_xdr_kind == _xdr_kind_int) free(_xdr_ivals);
1001       if(_xdr_kind == _xdr_kind_double) free(_xdr_dvals);
1002       _xdr_kind = _xdr_kind_null;
1003     }
1004 }
1005
1006 //================================================================================
1007 /*!
1008  * \brief Return the current integer value
1009  */
1010 //================================================================================
1011
1012 int XDRReader::getInt() const
1013 {
1014   if(_iRead < _nbToRead)
1015     {
1016       return _xdr_ivals[_iRead];
1017     }
1018   else
1019     {
1020       int result = 0;
1021 #ifdef HAS_XDR
1022       xdr_int((XDR*)_xdrs, &result);
1023 #endif
1024       return result;
1025     }
1026 }
1027
1028 //================================================================================
1029 /*!
1030  * \brief Return the current float value
1031  */
1032 //================================================================================
1033
1034 float  XDRReader::getFloat() const
1035 {
1036   float result = 0;
1037 #ifdef HAS_XDR
1038   xdr_float((XDR*)_xdrs, &result);
1039 #endif
1040   return result;
1041 }
1042
1043 //================================================================================
1044 /*!
1045  * \brief Return the current double value
1046  */
1047 //================================================================================
1048
1049 double XDRReader::getDouble() const
1050 {
1051   if(_iRead < _nbToRead)
1052     {
1053       return _xdr_dvals[_iRead];
1054     }
1055   else
1056     {
1057       double result = 0;
1058 #ifdef HAS_XDR
1059       xdr_double((XDR*)_xdrs, &result);
1060 #endif
1061       return result;
1062     }
1063 }
1064
1065 //================================================================================
1066 /*!
1067  * \brief Return the current string value
1068  */
1069 //================================================================================
1070
1071 std::string XDRReader::getName() const
1072 {
1073   int len = _width;
1074   char* s = _xdr_cvals + _iRead*_width;
1075   while (( s[len-1] == ' ' || s[len-1] == 0) && len > 0 )
1076     len--;
1077   return string( s, len );
1078 }
1079
1080 //================================================================================
1081 /*!
1082  * \brief Throw an exception if not all needed data is present
1083  */
1084 //================================================================================
1085
1086 void IntermediateMED::checkDataAvailability() const throw(INTERP_KERNEL::Exception)
1087 {
1088   if ( _spaceDim == 0 )
1089     THROW_IK_EXCEPTION("Wrong file format"); // it is the first record in the sauve file
1090
1091   if ( _groups.empty() )
1092     THROW_IK_EXCEPTION("No elements have been read");
1093
1094   if ( _points.empty() || _nbNodes == 0 )
1095     THROW_IK_EXCEPTION("Nodes of elements are not filled");
1096
1097   if ( _coords.empty() )
1098     THROW_IK_EXCEPTION("Node coordinates are missing");
1099
1100   if ( _coords.size() < _nbNodes * _spaceDim )
1101     THROW_IK_EXCEPTION("Nodes and coordinates mismatch");
1102 }
1103
1104 //================================================================================
1105 /*!
1106  * \brief Makes ParaMEDMEM::MEDFileData from self
1107  */
1108 //================================================================================
1109
1110 ParaMEDMEM::MEDFileData* IntermediateMED::convertInMEDFileDS()
1111 {
1112   MEDCouplingAutoRefCountObjectPtr< MEDFileUMesh >  mesh   = makeMEDFileMesh();
1113   MEDCouplingAutoRefCountObjectPtr< MEDFileFields > fields = makeMEDFileFields(mesh);
1114
1115   MEDCouplingAutoRefCountObjectPtr< MEDFileMeshes > meshes = MEDFileMeshes::New();
1116   MEDCouplingAutoRefCountObjectPtr< MEDFileData >  medData = MEDFileData::New();
1117   meshes->pushMesh( mesh );
1118   medData->setMeshes( meshes );
1119   if ( fields ) medData->setFields( fields );
1120
1121   return medData.retn();
1122 }
1123
1124 //================================================================================
1125 /*!
1126  * \brief Creates ParaMEDMEM::MEDFileUMesh from its data
1127  */
1128 //================================================================================
1129
1130 ParaMEDMEM::MEDFileUMesh* IntermediateMED::makeMEDFileMesh()
1131 {
1132   // check if all needed piles are present
1133   checkDataAvailability();
1134
1135   // set long names
1136   setGroupLongNames();
1137
1138   // fix element orientation
1139   if ( _spaceDim == 2 || _spaceDim == 1 )
1140     orientElements2D();
1141   else if ( _spaceDim == 3 )
1142     orientElements3D();
1143
1144   // process groups
1145   decreaseHierarchicalDepthOfSubgroups();
1146   eraseUselessGroups();
1147   //detectMixDimGroups();
1148
1149   // assign IDs
1150   _points.numberNodes();
1151   numberElements();
1152
1153   // make the med mesh
1154
1155   MEDFileUMesh* mesh = MEDFileUMesh::New();
1156
1157   DataArrayDouble *coords = getCoords();
1158   setConnectivity( mesh, coords );
1159   setGroups( mesh );
1160
1161   coords->decrRef();
1162
1163   if ( !mesh->getName() || strlen( mesh->getName() ) == 0 )
1164     mesh->setName( "MESH" );
1165
1166   return mesh;
1167 }
1168
1169 //================================================================================
1170 /*!
1171  * \brief Set long names to groups
1172  */
1173 //================================================================================
1174
1175 void IntermediateMED::setGroupLongNames()
1176 {
1177   // IMP 0020434: mapping GIBI names to MED names
1178   // set med names to objects (mesh, fields, support, group or other)
1179
1180   set<int> treatedGroups;
1181
1182   list<nameGIBItoMED>::iterator itGIBItoMED = _listGIBItoMED_mail.begin();
1183   for (; itGIBItoMED != _listGIBItoMED_mail.end(); itGIBItoMED++)
1184     {
1185       if ( (int)_groups.size() < itGIBItoMED->gibi_id ) continue;
1186
1187       SauvUtilities::Group & grp = _groups[itGIBItoMED->gibi_id - 1];
1188
1189       // if there are several names for grp then the 1st name is the name
1190       // of grp and the rest ones are names of groups referring grp (issue 0021311)
1191       const bool isRefName = !treatedGroups.insert( itGIBItoMED->gibi_id ).second;
1192       if ( !isRefName )
1193         {
1194           grp._name = _mapStrings[ itGIBItoMED->med_id ];
1195         }
1196       else if ( !grp._refNames.empty() && grp._refNames.back().empty() )
1197         {
1198           for ( unsigned i = 0; i < grp._refNames.size(); ++i )
1199             if ( grp._refNames[i].empty() )
1200               grp._refNames[i] = _mapStrings[ (*itGIBItoMED).med_id ];
1201         }
1202       else
1203         {
1204           grp._refNames.push_back( _mapStrings[ (*itGIBItoMED).med_id ]);
1205         }
1206     }
1207 }
1208
1209 //================================================================================
1210 /*!
1211  * \brief Set long names to fields
1212  */
1213 //================================================================================
1214
1215 void IntermediateMED::setFieldLongNames(set< string >& usedNames)
1216 {
1217   list<nameGIBItoMED>::iterator itGIBItoMED = _listGIBItoMED_cham.begin();
1218   for (; itGIBItoMED != _listGIBItoMED_cham.end(); itGIBItoMED++)
1219     {
1220       if (itGIBItoMED->gibi_pile == PILE_FIELD)
1221         {
1222           _cellFields[itGIBItoMED->gibi_id - 1]->_name = _mapStrings[itGIBItoMED->med_id];
1223         }
1224       else if (itGIBItoMED->gibi_pile == PILE_NODES_FIELD)
1225         {
1226           _nodeFields[itGIBItoMED->gibi_id - 1]->_name = _mapStrings[itGIBItoMED->med_id];
1227         }
1228     } // iterate on _listGIBItoMED_cham
1229
1230   for (itGIBItoMED =_listGIBItoMED_comp.begin(); itGIBItoMED != _listGIBItoMED_comp.end(); itGIBItoMED++)
1231     {
1232       string medName  = _mapStrings[itGIBItoMED->med_id];
1233       string gibiName = _mapStrings[itGIBItoMED->gibi_id];
1234
1235       bool name_found = false;
1236       for ( int isNodal = 0; isNodal < 2 && !name_found; ++isNodal )
1237         {
1238           vector<DoubleField* > & fields = isNodal ? _nodeFields : _cellFields;
1239           for ( size_t ifi = 0; ifi < fields.size() && !name_found; ifi++)
1240             {
1241               if (medName.find( fields[ifi]->_name + "." ) == 0 )
1242                 {
1243                   vector<DoubleField::_Sub_data>& aSubDs = fields[ifi]->_sub;
1244                   int nbSub = aSubDs.size();
1245                   for (int isu = 0; isu < nbSub; isu++)
1246                     for (int ico = 0; ico < aSubDs[isu].nbComponents(); ico++)
1247                       {
1248                         if (aSubDs[isu].compName(ico) == gibiName)
1249                           {
1250                             string medNameCompo = medName.substr( fields[ifi]->_name.size() + 1 );
1251                             fields[ifi]->_sub[isu].compName(ico) = medNameCompo;
1252                           }
1253                       }
1254                 }
1255             }
1256         }
1257     } // iterate on _listGIBItoMED_comp
1258
1259   for ( size_t i = 0; i < _nodeFields.size() ; i++)
1260     usedNames.insert( _nodeFields[i]->_name );
1261   for ( size_t i = 0; i < _cellFields.size() ; i++)
1262     usedNames.insert( _cellFields[i]->_name );
1263 }
1264
1265 //================================================================================
1266 /*!
1267  * \brief Decrease hierarchical depth of subgroups
1268  */
1269 //================================================================================
1270
1271 void IntermediateMED::decreaseHierarchicalDepthOfSubgroups()
1272 {
1273   for (size_t i=0; i!=_groups.size(); ++i)
1274   {
1275     Group& grp = _groups[i];
1276     for (size_t j = 0; j < grp._groups.size(); ++j )
1277     {
1278       Group & sub_grp = *grp._groups[j];
1279       if ( !sub_grp._groups.empty() )
1280       {
1281         // replace j with its 1st subgroup
1282         grp._groups[j] = sub_grp._groups[0];
1283         // push back the rest subs
1284         grp._groups.insert( grp._groups.end(), ++sub_grp._groups.begin(), sub_grp._groups.end() );
1285       }
1286     }
1287     // remove empty sub-_groups
1288     vector< Group* > newSubGroups;
1289     newSubGroups.reserve( grp._groups.size() );
1290     for (size_t j = 0; j < grp._groups.size(); ++j )
1291       if ( !grp._groups[j]->empty() )
1292         newSubGroups.push_back( grp._groups[j] );
1293     if ( newSubGroups.size() < grp._groups.size() )
1294       grp._groups.swap( newSubGroups );
1295   }
1296 }
1297
1298 //================================================================================
1299 /*!
1300  * \brief Erase _groups that won't be converted
1301  */
1302 //================================================================================
1303
1304 void IntermediateMED::eraseUselessGroups()
1305 {
1306   // propagate _isProfile=true to sub-groups of composite groups
1307   // for (size_t int i=0; i!=_groups.size(); ++i)
1308   // {
1309   //   Group* grp = _groups[i];
1310   //   if ( grp->_isProfile && !grp->_groups.empty() )
1311   //     for (size_t j = 0; j < grp->_groups.size(); ++j )
1312   //       grp->_groups[j]->_isProfile=true;
1313   // }
1314   std::set<Group*> groups2convert;
1315   // keep not named sub-groups of field supports
1316   for (size_t i=0; i!=_groups.size(); ++i)
1317   {
1318     Group& grp = _groups[i];
1319     if ( grp._isProfile && !grp._groups.empty() )
1320       groups2convert.insert( grp._groups.begin(), grp._groups.end() );
1321   }
1322
1323   // keep named groups and their subgroups
1324   for (size_t i=0; i!=_groups.size(); ++i)
1325   {
1326     Group& grp = _groups[i];
1327     if ( !grp._name.empty() && !grp.empty() )
1328     {
1329       groups2convert.insert( &grp );
1330       groups2convert.insert( grp._groups.begin(), grp._groups.end() );
1331     }
1332   }
1333   // erase groups that are not in groups2convert and not _isProfile
1334   for (size_t i=0; i!=_groups.size(); ++i)
1335   {
1336     Group* grp = &_groups[i];
1337     if ( !grp->_isProfile && !groups2convert.count( grp ) )
1338     {
1339       grp->_cells.clear();
1340       grp->_groups.clear();
1341     }
1342   }
1343 }
1344
1345 //================================================================================
1346 /*!
1347  * \brief Detect _groups of mixed dimension
1348  */
1349 //================================================================================
1350
1351 void IntermediateMED::detectMixDimGroups()
1352 {
1353   //hasMixedCells = false;
1354   for ( size_t i=0; i < _groups.size(); ++i )
1355   {
1356     Group& grp = _groups[i];
1357     if ( grp._groups.size() < 2 )
1358       continue;
1359
1360     // check if sub-groups have different dimension
1361     unsigned dim1 = getDim( &grp );
1362     for ( size_t j = 1; j  < grp._groups.size(); ++j )
1363     {
1364       unsigned dim2 = getDim( grp._groups[j] );
1365       if ( dim1 != dim2 )
1366       {
1367         grp._cells.clear();
1368         grp._groups.clear();
1369         if ( !grp._name.empty() )
1370           cout << "Erase a group with elements of different dim |" << grp._name << "|"<< endl;
1371         break;
1372       }
1373     }
1374   }
1375 }
1376
1377 //================================================================================
1378 /*!
1379  * \brief Fix connectivity of elements in 2D space
1380  */
1381 //================================================================================
1382
1383 void IntermediateMED::orientElements2D()
1384 {
1385   set<Cell>::const_iterator elemIt, elemEnd;
1386   vector< pair<int,int> > swapVec;
1387
1388   // ------------------------------------
1389   // fix connectivity of quadratic edges
1390   // ------------------------------------
1391   set<Cell>& quadEdges = _cellsByType[ INTERP_KERNEL::NORM_SEG3 ];
1392   if ( !quadEdges.empty() )
1393     {
1394       elemIt = quadEdges.begin(), elemEnd = quadEdges.end();
1395       for ( ; elemIt != elemEnd; ++elemIt )
1396         ConvertQuadratic( INTERP_KERNEL::NORM_SEG3, *elemIt );
1397     }
1398
1399   CellsByDimIterator faceIt( *this, 2 );
1400   while ( const set<Cell > * faces = faceIt.nextType() )
1401     {
1402       TCellType cellType = faceIt.type();
1403       bool isQuadratic = getGibi2MedQuadraticInterlace( cellType );
1404
1405       getReverseVector( cellType, swapVec );
1406
1407       // ------------------------------------
1408       // fix connectivity of quadratic faces
1409       // ------------------------------------
1410       if ( isQuadratic )
1411         for ( elemIt = faces->begin(), elemEnd = faces->end(); elemIt != elemEnd; elemIt++ )
1412           ConvertQuadratic( cellType, *elemIt );
1413
1414       // --------------------------
1415       // orient faces clockwise
1416       // --------------------------
1417       int iQuad = isQuadratic ? 2 : 1;
1418       for ( elemIt = faces->begin(), elemEnd = faces->end(); elemIt != elemEnd; elemIt++ )
1419         {
1420           // look for index of the most left node
1421           int iLeft = 0, iNode, nbNodes = elemIt->_nodes.size() / iQuad;
1422           double x, minX = nodeCoords( elemIt->_nodes[0] )[0];
1423           for ( iNode = 1; iNode < nbNodes; ++iNode )
1424             if (( x = nodeCoords( elemIt->_nodes[ iNode ])[ 0 ]) < minX )
1425               minX = x, iLeft = iNode;
1426
1427           // indeces of the nodes neighboring the most left one
1428           int iPrev = ( iLeft - 1 < 0 ) ? nbNodes - 1 : iLeft - 1;
1429           int iNext = ( iLeft + 1 == nbNodes ) ? 0 : iLeft + 1;
1430           // find components of prev-left and left-next vectors
1431           double xP = nodeCoords( elemIt->_nodes[ iPrev ])[ 0 ];
1432           double yP = nodeCoords( elemIt->_nodes[ iPrev ])[ 1 ];
1433           double xN = nodeCoords( elemIt->_nodes[ iNext ])[ 0 ];
1434           double yN = nodeCoords( elemIt->_nodes[ iNext ])[ 1 ];
1435           double xL = nodeCoords( elemIt->_nodes[ iLeft ])[ 0 ];
1436           double yL = nodeCoords( elemIt->_nodes[ iLeft ])[ 1 ];
1437           double xPL = xL - xP, yPL = yL - yP; // components of prev-left vector
1438           double xLN = xN - xL, yLN = yN - yL; // components of left-next vector
1439           // normalise y of the vectors
1440           double modPL = sqrt ( xPL * xPL + yPL * yPL );
1441           double modLN = sqrt ( xLN * xLN + yLN * yLN );
1442           if ( modLN > std::numeric_limits<double>::min() &&
1443                modPL > std::numeric_limits<double>::min() )
1444             {
1445               yPL /= modPL;
1446               yLN /= modLN;
1447               // summary direction of neighboring links must be positive
1448               bool clockwise = ( yPL + yLN > 0 );
1449               if ( !clockwise )
1450                 reverse( *elemIt, swapVec );
1451             }
1452         }
1453     }
1454 }
1455
1456 //================================================================================
1457 /*!
1458  * \brief Fix connectivity of elements in 3D space
1459  */
1460 //================================================================================
1461
1462 void IntermediateMED::orientElements3D()
1463 {
1464   // set _reverse flags of faces
1465   orientFaces3D();
1466
1467   // -----------------
1468   // fix connectivity
1469   // -----------------
1470
1471   set<Cell>::const_iterator elemIt, elemEnd;
1472   vector< pair<int,int> > swapVec;
1473
1474   for ( int dim = 1; dim <= 3; ++dim )
1475   {
1476     CellsByDimIterator cellsIt( *this, dim );
1477     while ( const set<Cell > * elems = cellsIt.nextType() )
1478     {
1479       TCellType cellType = cellsIt.type();
1480       bool isQuadratic = getGibi2MedQuadraticInterlace( cellType );
1481       getReverseVector( cellType, swapVec );
1482
1483       elemIt = elems->begin(), elemEnd = elems->end();
1484       for ( ; elemIt != elemEnd; elemIt++ )
1485       {
1486         // GIBI connectivity -> MED one
1487         if( isQuadratic )
1488           ConvertQuadratic( cellType, *elemIt );
1489
1490         // reverse faces
1491         if ( elemIt->_reverse )
1492           reverse ( *elemIt, swapVec );
1493       }
1494     }
1495   }
1496
1497   orientVolumes();
1498 }
1499
1500 //================================================================================
1501 /*!
1502  * \brief Orient equally (by setting _reverse flag) all connected faces in 3D space
1503  */
1504 //================================================================================
1505
1506 void IntermediateMED::orientFaces3D()
1507 {
1508   // fill map of links and their faces
1509   set<const Cell*> faces;
1510   map<const Cell*, Group*> fgm;
1511   map<Link, list<const Cell*> > linkFacesMap;
1512   map<Link, list<const Cell*> >::iterator lfIt, lfIt2;
1513
1514   for (size_t i=0; i!=_groups.size(); ++i)
1515     {
1516       Group& grp = _groups[i];
1517       if ( !grp._cells.empty() && getDimension( grp._cellType ) == 2 )
1518         for ( size_t j = 0; j < grp._cells.size(); ++j )
1519           if ( faces.insert( grp._cells[j] ).second )
1520             {
1521               for ( size_t k = 0; k < grp._cells[j]->_nodes.size(); ++k )
1522                 linkFacesMap[ grp._cells[j]->link( k ) ].push_back( grp._cells[j] );
1523               fgm.insert( make_pair( grp._cells[j], &grp ));
1524             }
1525     }
1526   // dump linkFacesMap
1527   //     for ( lfIt = linkFacesMap.begin(); lfIt!=linkFacesMap.end(); lfIt++) {
1528   //       cout<< "LINK: " << lfIt->first.first << "-" << lfIt->first.second << endl;
1529   //       list<const Cell*> & fList = lfIt->second;
1530   //       list<const Cell*>::iterator fIt = fList.begin();
1531   //       for ( ; fIt != fList.end(); fIt++ )
1532   //         cout << "\t" << **fIt << fgm[*fIt]->nom << endl;
1533   //     }
1534
1535   // Each oriented link must appear in one face only, else a face is reversed.
1536
1537   queue<const Cell*> faceQueue; /* the queue contains well oriented faces
1538                                      whose neighbors orientation is to be checked */
1539   bool manifold = true;
1540   while ( !linkFacesMap.empty() )
1541     {
1542       if ( faceQueue.empty() )
1543         {
1544           assert( !linkFacesMap.begin()->second.empty() );
1545           faceQueue.push( linkFacesMap.begin()->second.front() );
1546         }
1547       while ( !faceQueue.empty() )
1548         {
1549           const Cell* face = faceQueue.front();
1550           faceQueue.pop();
1551
1552           // loop on links of <face>
1553           for ( int i = 0; i < (int)face->_nodes.size(); ++i )
1554             {
1555               Link link = face->link( i );
1556               // find the neighbor faces
1557               lfIt = linkFacesMap.find( link );
1558               int nbFaceByLink = 0;
1559               list< const Cell* > ml;
1560               if ( lfIt != linkFacesMap.end() )
1561                 {
1562                   list<const Cell*> & fList = lfIt->second;
1563                   list<const Cell*>::iterator fIt = fList.begin();
1564                   assert( fIt != fList.end() );
1565                   for ( ; fIt != fList.end(); fIt++, nbFaceByLink++ )
1566                     {
1567                       ml.push_back( *fIt );
1568                       if ( *fIt != face ) // wrongly oriented neighbor face
1569                         {
1570                           const Cell* badFace = *fIt;
1571                           // reverse and remove badFace from linkFacesMap
1572                           for ( int j = 0; j < (int)badFace->_nodes.size(); ++j )
1573                             {
1574                               Link badlink = badFace->link( j );
1575                               if ( badlink == link ) continue;
1576                               lfIt2 = linkFacesMap.find( badlink );
1577                               if ( lfIt2 != linkFacesMap.end() )
1578                                 {
1579                                   list<const Cell*> & ff = lfIt2->second;
1580                                   list<const Cell*>::iterator lfIt3 = find( ff.begin(), ff.end(), badFace );
1581                                   // check if badFace has been found,
1582                                   // else we can't erase it
1583                                   // case of degenerated face in edge
1584                                   if (lfIt3 != ff.end())
1585                                     {
1586                                       ff.erase( lfIt3 );
1587                                       if ( ff.empty() )
1588                                         linkFacesMap.erase( lfIt2 );
1589                                     }
1590                                 }
1591                             }
1592                           badFace->_reverse = true; // reverse
1593                           //INFOS_MED( "REVERSE " << *badFace );
1594                           faceQueue.push( badFace );
1595                         }
1596                     }
1597                   linkFacesMap.erase( lfIt );
1598                 }
1599               // add good neighbors to the queue
1600               Link revLink( link.second, link.first );
1601               lfIt = linkFacesMap.find( revLink );
1602               if ( lfIt != linkFacesMap.end() )
1603                 {
1604                   list<const Cell*> & fList = lfIt->second;
1605                   list<const Cell*>::iterator fIt = fList.begin();
1606                   for ( ; fIt != fList.end(); fIt++, nbFaceByLink++ )
1607                     {
1608                       ml.push_back( *fIt );
1609                       if ( *fIt != face )
1610                         faceQueue.push( *fIt );
1611                     }
1612                   linkFacesMap.erase( lfIt );
1613                 }
1614               if ( nbFaceByLink > 2 )
1615                 {
1616                   if ( manifold )
1617                     {
1618                       list<const Cell*>::iterator ii = ml.begin();
1619                       cout << nbFaceByLink << " faces by 1 link:" << endl;
1620                       for( ; ii!= ml.end(); ii++ )
1621                         cout << "in sub-mesh <" << fgm[ *ii ]->_name << "> " << **ii << endl;
1622                     }
1623                   manifold = false;
1624                 }
1625             } // loop on links of the being checked face
1626         } // loop on the face queue
1627     } // while ( !linkFacesMap.empty() )
1628
1629   if ( !manifold )
1630     cout << " -> Non manifold mesh, faces orientation may be incorrect" << endl;
1631 }
1632
1633 //================================================================================
1634 /*!
1635  * \brief Orient volumes according to MED conventions:
1636  * normal of a bottom (first) face should be outside
1637  */
1638 //================================================================================
1639
1640 void IntermediateMED::orientVolumes()
1641 {
1642   set<Cell>::const_iterator elemIt, elemEnd;
1643   vector< pair<int,int> > swapVec;
1644
1645   CellsByDimIterator cellsIt( *this, 3 );
1646   while ( const set<Cell > * elems = cellsIt.nextType() )
1647     {
1648       TCellType cellType = cellsIt.type();
1649       elemIt = elems->begin(), elemEnd = elems->end();
1650       int nbBottomNodes = 0;
1651       switch ( cellType )
1652         {
1653         case NORM_TETRA4:
1654         case NORM_TETRA10:
1655         case NORM_PENTA6:
1656         case NORM_PENTA15:
1657           nbBottomNodes = 3; break;
1658         case NORM_PYRA5:
1659         case NORM_PYRA13:
1660         case NORM_HEXA8:
1661         case NORM_HEXA20:
1662           nbBottomNodes = 4; break;
1663         default: continue;
1664         }
1665       getReverseVector( cellType, swapVec );
1666
1667       for ( ; elemIt != elemEnd; elemIt++ )
1668         {
1669           // find a normal to the bottom face
1670           const double* n[4];
1671           n[0] = nodeCoords( elemIt->_nodes[0]); // 3 bottom nodes
1672           n[1] = nodeCoords( elemIt->_nodes[1]);
1673           n[2] = nodeCoords( elemIt->_nodes[2]);
1674           n[3] = nodeCoords( elemIt->_nodes[nbBottomNodes]); // a top node
1675           double vec01[3]; // vector n[0]-n[1]
1676           vec01[0] = n[1][0] - n[0][0];
1677           vec01[1] = n[1][1] - n[0][1];
1678           vec01[2] = n[1][2] - n[0][2];
1679           double vec02 [3]; // vector n[0]-n[2]
1680           vec02[0] = n[2][0] - n[0][0];
1681           vec02[1] = n[2][1] - n[0][1];
1682           vec02[2] = n[2][2] - n[0][2];
1683           double normal [3]; // vec01 ^ vec02
1684           normal[0] = vec01[1] * vec02[2] - vec01[2] * vec02[1];
1685           normal[1] = vec01[2] * vec02[0] - vec01[0] * vec02[2];
1686           normal[2] = vec01[0] * vec02[1] - vec01[1] * vec02[0];
1687           // check if the 102 angle is convex
1688           if ( nbBottomNodes > 3 )
1689             {
1690               const double* n3 = nodeCoords( elemIt->_nodes[nbBottomNodes-1] );// last bottom node
1691               double vec03 [3];  // vector n[0]-n3
1692               vec03[0] = n3[0] - n[0][0];
1693               vec03[1] = n3[1] - n[0][1];
1694               vec03[2] = n3[2] - n[0][2];
1695               if ( fabs( normal[0]+normal[1]+normal[2] ) <= numeric_limits<double>::max() ) // vec01 || vec02
1696                 {
1697                   normal[0] = vec01[1] * vec03[2] - vec01[2] * vec03[1]; // vec01 ^ vec03
1698                   normal[1] = vec01[2] * vec03[0] - vec01[0] * vec03[2];
1699                   normal[2] = vec01[0] * vec03[1] - vec01[1] * vec03[0];
1700                 }
1701               else
1702                 {
1703                   double vec [3]; // normal ^ vec01
1704                   vec[0] = normal[1] * vec01[2] - normal[2] * vec01[1];
1705                   vec[1] = normal[2] * vec01[0] - normal[0] * vec01[2];
1706                   vec[2] = normal[0] * vec01[1] - normal[1] * vec01[0];
1707                   double dot2 = vec[0]*vec03[0] + vec[1]*vec03[1] + vec[2]*vec03[2]; // vec*vec03
1708                   if ( dot2 < 0 ) // concave -> reverse normal
1709                     {
1710                       normal[0] *= -1;
1711                       normal[1] *= -1;
1712                       normal[2] *= -1;
1713                     }
1714                 }
1715             }
1716           // direction from top to bottom
1717           double tbDir[3];
1718           tbDir[0] = n[0][0] - n[3][0];
1719           tbDir[1] = n[0][1] - n[3][1];
1720           tbDir[2] = n[0][2] - n[3][2];
1721
1722           // compare 2 directions: normal and top-bottom
1723           double dot = normal[0]*tbDir[0] + normal[1]*tbDir[1] + normal[2]*tbDir[2];
1724           if ( dot < 0. ) // need reverse
1725             reverse( *elemIt, swapVec );
1726
1727         } // loop on volumes of one geometry
1728     } // loop on 3D geometry types
1729
1730 }
1731
1732 //================================================================================
1733 /*!
1734  * \brief Assign new IDs to nodes by skipping not used nodes and return their number
1735  */
1736 //================================================================================
1737
1738 int NodeContainer::numberNodes()
1739 {
1740   int id = 1;
1741   for ( size_t i = 0; i < _nodes.size(); ++i )
1742     for ( size_t j = 0; j < _nodes[i].size(); ++j )
1743       if ( _nodes[i][j].isUsed() )
1744         _nodes[i][j]._number = id++;
1745   return id-1;
1746 }
1747
1748
1749 //================================================================================
1750 /*!
1751  * \brief Assign new IDs to elements
1752  */
1753 //================================================================================
1754
1755 void IntermediateMED::numberElements()
1756 {
1757   set<Cell>::const_iterator elemIt, elemEnd;
1758
1759   // numbering _cells of type NORM_POINT1 by node number
1760   {
1761     const set<Cell>& points = _cellsByType[ INTERP_KERNEL::NORM_POINT1 ];
1762     elemIt = points.begin(), elemEnd = points.end();
1763     for ( ; elemIt != elemEnd; ++elemIt )
1764       elemIt->_number = elemIt->_nodes[0]->_number;
1765   }
1766
1767   // numbering 1D-3D _cells
1768   for ( int dim = 1; dim <= 3; ++dim )
1769     {
1770       // check if re-numeration is needed (to try to keep elem oreder as in sauve file )
1771       bool ok = true, renumEntity = false;
1772       CellsByDimIterator cellsIt( *this, dim );
1773       int prevNbElems = 0;
1774       while ( const set<Cell> * typeCells = cellsIt.nextType() )
1775         {
1776           TID minNumber = std::numeric_limits<TID>::max(), maxNumber = 0;
1777           for ( elemIt = typeCells->begin(), elemEnd = typeCells->end(); elemIt!=elemEnd; ++elemIt)
1778             {
1779               if ( elemIt->_number < minNumber ) minNumber = elemIt->_number;
1780               if ( elemIt->_number > maxNumber ) maxNumber = elemIt->_number;
1781             }
1782           TID typeSize = typeCells->size();
1783           if ( typeSize != maxNumber - minNumber + 1 )
1784             ok = false;
1785           if ( prevNbElems != 0 ) {
1786             if ( minNumber == 1 )
1787               renumEntity = true;
1788             else if ( prevNbElems+1 != (int)minNumber )
1789               ok = false;
1790           }
1791           prevNbElems += typeSize;
1792         }
1793
1794       if ( ok && renumEntity ) // each geom type was numerated separately
1795         {
1796           cellsIt.init( dim );
1797           prevNbElems = cellsIt.nextType()->size(); // no need to renumber the first type
1798           while ( const set<Cell> * typeCells = cellsIt.nextType() )
1799             {
1800               for ( elemIt = typeCells->begin(), elemEnd = typeCells->end(); elemIt!=elemEnd; ++elemIt)
1801                 elemIt->_number += prevNbElems;
1802               prevNbElems += typeCells->size();
1803             }
1804         }
1805       if ( !ok )
1806         {
1807           int cellID=1;
1808           cellsIt.init( dim );
1809           while ( const set<Cell> * typeCells = cellsIt.nextType() )
1810             for ( elemIt = typeCells->begin(), elemEnd = typeCells->end(); elemIt!=elemEnd; ++elemIt)
1811               elemIt->_number = cellID++;
1812         }
1813     }
1814 }
1815
1816 //================================================================================
1817 /*!
1818  * \brief Creates coord array
1819  */
1820 //================================================================================
1821
1822 ParaMEDMEM::DataArrayDouble * IntermediateMED::getCoords()
1823 {
1824   DataArrayDouble* coordArray = DataArrayDouble::New();
1825   coordArray->alloc( _nbNodes, _spaceDim );
1826   double * coordPrt = coordArray->getPointer();
1827   for ( int i = 0, nb = _points.size(); i < nb; ++i )
1828     {
1829       Node* n = getNode( i+1 );
1830       if ( n->isUsed() )
1831         {
1832           const double* nCoords = nodeCoords( n );
1833           std::copy( nCoords, nCoords+_spaceDim, coordPrt );
1834           coordPrt += _spaceDim;
1835         }
1836     }
1837   return coordArray;
1838 }
1839
1840 //================================================================================
1841 /*!
1842  * \brief Sets connectivity of elements to the mesh
1843  *  \param mesh - mesh to fill in
1844  *  \param coords - coordinates that must be shared by all meshes of different dim
1845  */
1846 //================================================================================
1847
1848 void IntermediateMED::setConnectivity( ParaMEDMEM::MEDFileUMesh*    mesh,
1849                                        ParaMEDMEM::DataArrayDouble* coords )
1850 {
1851   int meshDim = 0;
1852
1853   mesh->setCoords( coords );
1854
1855   set<Cell>::const_iterator elemIt, elemEnd;
1856   for ( int dim = 3; dim > 0; --dim )
1857   {
1858     CellsByDimIterator dimCells( *this, dim );
1859
1860     int nbOfCells = 0;
1861     while ( const std::set<Cell > * cells = dimCells.nextType() )
1862       nbOfCells += cells->size();
1863     if ( nbOfCells == 0 )
1864       continue;
1865
1866     if ( !meshDim ) meshDim = dim;
1867
1868     MEDCouplingUMesh* dimMesh = MEDCouplingUMesh::New();
1869     dimMesh->setCoords( coords );
1870     dimMesh->setMeshDimension( dim );
1871     dimMesh->allocateCells( nbOfCells );
1872
1873     int prevNbCells = 0;
1874     dimCells.init( dim );
1875     while ( const std::set<Cell > * cells = dimCells.nextType() )
1876       {
1877         // fill connectivity array to take into account order of elements in the sauv file
1878         const int nbCellNodes = cells->begin()->_nodes.size();
1879         vector< TID > connectivity( cells->size() * nbCellNodes );
1880         int * nodalConnOfCell;
1881         for ( elemIt = cells->begin(), elemEnd = cells->end(); elemIt != elemEnd; ++elemIt )
1882           {
1883             const Cell& cell = *elemIt;
1884             const int index = cell._number - 1 - prevNbCells;
1885             nodalConnOfCell = &connectivity[ index * nbCellNodes ];
1886             if ( cell._reverse )
1887               for ( int i = nbCellNodes-1; i >= 0; --i )
1888                 *nodalConnOfCell++ = cell._nodes[i]->_number - 1;
1889             else
1890               for ( int i = 0; i < nbCellNodes; ++i )
1891                 *nodalConnOfCell++ = cell._nodes[i]->_number - 1;
1892           }
1893         prevNbCells += cells->size();
1894
1895         // fill dimMesh
1896         TCellType cellType = dimCells.type();
1897         nodalConnOfCell = &connectivity[0];
1898         for ( size_t i = 0; i < cells->size(); ++i, nodalConnOfCell += nbCellNodes )
1899           dimMesh->insertNextCell( cellType, nbCellNodes, nodalConnOfCell );
1900       }
1901     dimMesh->finishInsertingCells();
1902     mesh->setMeshAtLevel( dim - meshDim, dimMesh );
1903     dimMesh->decrRef();
1904   }
1905 }
1906
1907 //================================================================================
1908 /*!
1909  * \brief Fill in the mesh with groups
1910  *  \param mesh - mesh to fill in
1911  */
1912 //================================================================================
1913
1914 void IntermediateMED::setGroups( ParaMEDMEM::MEDFileUMesh* mesh )
1915 {
1916   bool isMeshNameSet = false;
1917   const int meshDim = mesh->getMeshDimension();
1918   for ( int dim = 0; dim <= meshDim; ++dim )
1919     {
1920       const int meshDimRelToMaxExt = ( dim == 0 ? 1 : dim - meshDim );
1921
1922       vector<const DataArrayInt *> medGroups;
1923       vector<MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > refGroups;
1924       for ( size_t i = 0; i < _groups.size(); ++i )
1925         {
1926           Group& grp = _groups[i];
1927           if ( (int)getDim( &grp ) != dim &&
1928                grp._groups.empty() ) // to allow groups on diff dims
1929             continue;
1930           // convert only named groups or field supports
1931           if ( grp.empty() || (grp._name.empty() && !grp._isProfile ))
1932             continue;
1933           //if ( grp._medGroup ) continue; // already converted
1934
1935           // sort cells by ID and remember their initial order in the group
1936           TCellToOrderMap cell2order;
1937           unsigned orderInGroup = 0;
1938           vector< Group* > groupVec;
1939           if ( grp._groups.empty() ) groupVec.push_back( & grp );
1940           else                       groupVec = grp._groups;
1941           for ( size_t iG = 0; iG < groupVec.size(); ++iG )
1942             {
1943               Group* aG = groupVec[ iG ];
1944               if ( (int)getDim( aG ) != dim )
1945                 continue;
1946               for ( size_t iC = 0; iC < aG->_cells.size(); ++iC )
1947                 cell2order.insert( cell2order.end(), make_pair( aG->_cells[iC], orderInGroup++ ));
1948             }
1949           if ( cell2order.empty() )
1950             continue;
1951           bool isSelfIntersect = ( orderInGroup != cell2order.size() );
1952           if ( isSelfIntersect ) // self intersecting group
1953             {
1954               ostringstream msg;
1955               msg << "Self intersecting sub-mesh: id = " << i+1
1956                   << ", name = |" << grp._name << "|" << endl
1957                   << " nb unique elements = " << cell2order.size() << endl
1958                   << " total nb elements  = " << orderInGroup;
1959               if ( grp._isProfile )
1960                 {
1961                   THROW_IK_EXCEPTION( msg.str() );
1962                 }
1963               else
1964                 {
1965                   cout << msg.str() << endl;
1966                 }
1967             }
1968           // create a med group
1969           grp._medGroup = DataArrayInt::New();
1970           grp._medGroup->setName( grp._name.c_str() );
1971           grp._medGroup->alloc( cell2order.size(), /*nbOfCompo=*/1 );
1972           int * idsPrt = grp._medGroup->getPointer();
1973           TCellToOrderMap::iterator cell2orderIt, cell2orderEnd = cell2order.end();
1974           for ( cell2orderIt = cell2order.begin(); cell2orderIt != cell2orderEnd; ++cell2orderIt )
1975             *idsPrt++ = (*cell2orderIt).first->_number - 1;
1976
1977           // try to set the mesh name
1978           if ( !isMeshNameSet &&
1979                dim == meshDim &&
1980                !grp._name.empty() &&
1981                grp.size() == mesh->getSizeAtLevel( meshDimRelToMaxExt ))
1982             {
1983               mesh->setName( grp._name.c_str() );
1984               isMeshNameSet = true;
1985             }
1986           if ( !grp._name.empty() )
1987             {
1988               medGroups.push_back( grp._medGroup );
1989             }
1990           // set relocation table
1991           setRelocationTable( &grp, cell2order );
1992
1993           // Issue 0021311. Use case: a gibi group has references (recorded in pile 1)
1994           // and several names (pile 27) refer (pile 10) to this group.
1995           // We create a copy of this group per each named reference
1996           for ( unsigned iRef = 0 ; iRef < grp._refNames.size(); ++iRef )
1997             if ( !grp._refNames[ iRef ].empty() )
1998               {
1999                 refGroups.push_back( grp._medGroup->deepCpy() );
2000                 refGroups.back()->setName( grp._refNames[ iRef ].c_str() );
2001                 medGroups.push_back( refGroups.back() );
2002               }
2003         }
2004       mesh->setGroupsAtLevel( meshDimRelToMaxExt, medGroups );
2005     }
2006 }
2007
2008 //================================================================================
2009 /*!
2010  * \brief Return true if the group is on all elements and return its relative dimension
2011  */
2012 //================================================================================
2013
2014 bool IntermediateMED::isOnAll( const Group* grp, int & dimRel ) const
2015 {
2016   int dim = getDim( grp );
2017
2018   int nbElems = 0;
2019   CellsByDimIterator dimCells( *this, dim );
2020   while ( const set<Cell > * cells = dimCells.nextType() )
2021     nbElems += cells->size();
2022
2023   const bool onAll = ( nbElems == grp->size() );
2024
2025   if ( dim == 0 )
2026     dimRel = 0;
2027   else
2028     {
2029       int meshDim = 3;
2030       for ( ; meshDim > 0; --meshDim )
2031         {
2032           dimCells.init( meshDim );
2033           if ( dimCells.nextType() )
2034             break;
2035         }
2036       dimRel = dim - meshDim;
2037     }
2038   return onAll;
2039 }
2040
2041 //================================================================================
2042 /*!
2043  * \brief Makes fields from own data
2044  */
2045 //================================================================================
2046
2047 ParaMEDMEM::MEDFileFields * IntermediateMED::makeMEDFileFields(ParaMEDMEM::MEDFileUMesh* mesh)
2048 {
2049   if ( _nodeFields.empty() && _cellFields.empty() ) return 0;
2050
2051   // set long names
2052   set< string > usedFieldNames;
2053   setFieldLongNames(usedFieldNames);
2054
2055   MEDFileFields* fields = MEDFileFields::New();
2056
2057   for ( size_t i = 0; i < _nodeFields.size(); ++i )
2058     setFields( _nodeFields[i], fields, mesh, i+1, usedFieldNames );
2059
2060   for ( size_t i = 0; i < _cellFields.size(); ++i )
2061     setFields( _cellFields[i], fields, mesh, i+1, usedFieldNames );
2062
2063   return fields;
2064 }
2065
2066 //================================================================================
2067 /*!
2068  * \brief Make med fields from a SauvUtilities::DoubleField
2069  */
2070 //================================================================================
2071
2072 void IntermediateMED::setFields( SauvUtilities::DoubleField* fld,
2073                                  ParaMEDMEM::MEDFileFields*  medFields,
2074                                  ParaMEDMEM::MEDFileUMesh*   mesh,
2075                                  const TID                   castemID,
2076                                  set< string >&              usedFieldNames)
2077 {
2078   if ( !fld || !fld->isMedCompatible() ) return;
2079
2080   // if ( !fld->hasCommonSupport() ):
2081   //     each sub makes MEDFileFieldMultiTS
2082   // else:
2083   //     unite several subs into a MEDCouplingFieldDouble
2084
2085   const bool uniteSubs = fld->hasCommonSupport();
2086   if ( !uniteSubs )
2087     cout << "Castem field #" << castemID << " " << fld->_name
2088          << " is incompatible with MED format, so we split it into several fields" << endl;
2089
2090   for ( size_t iSub = 0; iSub < fld->_sub.size(); )
2091     {
2092       // set field name
2093       if ( !uniteSubs || fld->_name.empty() )
2094         makeFieldNewName( usedFieldNames, fld );
2095
2096       // allocate values
2097       DataArrayDouble * values = DataArrayDouble::New();
2098       values->alloc( fld->getNbTuples(iSub), fld->_sub[iSub].nbComponents() );
2099
2100       // set values
2101       double * valPtr = values->getPointer();
2102       if ( uniteSubs )
2103         {
2104           int nbElems = fld->_group->size();
2105           for ( int elemShift = 0; elemShift < nbElems; )
2106             elemShift += fld->setValues( valPtr, iSub++, elemShift );
2107           setTS( fld, values, medFields, mesh );
2108         }
2109       else
2110         {
2111           fld->setValues( valPtr, iSub );
2112           setTS( fld, values, medFields, mesh, iSub++ );
2113         }
2114     }
2115 }
2116
2117 //================================================================================
2118 /*!
2119  * \brief Store value array of a field into med fields
2120  */
2121 //================================================================================
2122
2123 void IntermediateMED::setTS( SauvUtilities::DoubleField*  fld,
2124                              ParaMEDMEM::DataArrayDouble* values,
2125                              ParaMEDMEM::MEDFileFields*   medFields,
2126                              ParaMEDMEM::MEDFileUMesh*    mesh,
2127                              const int                    iSub)
2128 {
2129   // analyze a field support
2130   const Group* support = fld->getSupport( iSub );
2131   int dimRel;
2132   const bool onAll = isOnAll( support, dimRel );
2133   if ( !onAll && support->_name.empty() )
2134     {
2135       const_cast<Group*>(support)->_name += "PFL_" + fld->_name;
2136       support->_medGroup->setName( support->_name.c_str() );
2137     }
2138
2139   // make a time-stamp
2140   MEDCouplingFieldDouble * timeStamp = MEDCouplingFieldDouble::New( fld->getMedType(),
2141                                                                     fld->getMedTimeDisc() );
2142   timeStamp->setName( fld->_name.c_str() );
2143   timeStamp->setDescription( fld->_description.c_str() );
2144   MEDCouplingAutoRefCountObjectPtr< MEDCouplingUMesh > dimMesh = mesh->getMeshAtLevel( dimRel );
2145   timeStamp->setMesh( dimMesh );
2146   for ( size_t i = 0; i < (size_t)fld->_sub[iSub].nbComponents(); ++i )
2147     values->setInfoOnComponent( i, fld->_sub[iSub]._comp_names[ i ].c_str() );
2148   timeStamp->setArray( values );
2149   values->decrRef();
2150
2151   // get a field to add the time-stamp
2152   bool isNewMedField = false;
2153   if ( !fld->_curMedField || fld->_name != fld->_curMedField->getName() )
2154     {
2155       fld->_curMedField = MEDFileFieldMultiTS::New();
2156       isNewMedField = true;
2157     }
2158
2159   // set an order
2160   timeStamp->setOrder( fld->_curMedField->getNumberOfTS() );
2161
2162   // add the time-stamp
2163   if ( onAll )
2164     fld->_curMedField->appendFieldNoProfileSBT( timeStamp );
2165   else
2166     fld->_curMedField->appendFieldProfile( timeStamp, mesh, dimRel, support->_medGroup );
2167   timeStamp->decrRef();
2168
2169   if ( isNewMedField ) // timeStamp must be added before this
2170     {
2171       medFields->pushField( fld->_curMedField );
2172     }
2173 }
2174
2175 //================================================================================
2176 /*!
2177  * \brief Make a new unique name for a field
2178  */
2179 //================================================================================
2180
2181 void IntermediateMED::makeFieldNewName(std::set< std::string >&    usedNames,
2182                                        SauvUtilities::DoubleField* fld )
2183 {
2184   string base = fld->_name;
2185   if ( base.empty() )
2186     {
2187       base = "F_";
2188     }
2189   else
2190     {
2191       string::size_type pos = base.rfind('_');
2192       if ( pos != string::npos )
2193         base = base.substr( 0, pos+1 );
2194       else
2195         base += '_';
2196     }
2197
2198   int i = 1;
2199   do
2200     {
2201       fld->_name = base + SauvUtilities::toString( i++ );
2202     }
2203   while( !usedNames.insert( fld->_name ).second );
2204 }
2205
2206 //================================================================================
2207 /*!
2208  * \brief Return a vector ready to fill in
2209  */
2210 //================================================================================
2211
2212 std::vector< double >& DoubleField::addComponent( int nb_values )
2213 {
2214   _comp_values.push_back( std::vector< double >() );
2215   std::vector< double >& res = _comp_values.back();
2216   res.resize( nb_values );
2217   return res;
2218 }
2219
2220 DoubleField::~DoubleField()
2221 {
2222   if(_curMedField)
2223     _curMedField->decrRef();
2224 }
2225
2226 //================================================================================
2227 /*!
2228  * \brief Returns a supporting group
2229  */
2230 //================================================================================
2231
2232 const Group* DoubleField::getSupport( const int iSub ) const
2233 {
2234   return _group ? _group : _sub[iSub]._support;
2235 }
2236
2237 //================================================================================
2238 /*!
2239  * \brief Return true if each sub-component is a time stamp
2240  */
2241 //================================================================================
2242
2243 bool DoubleField::isMultiTimeStamps() const
2244 {
2245   if ( _sub.size() < 2 )
2246     return false;
2247   bool sameSupports = true;
2248   Group* grp1 = _sub[0]._support;
2249   for ( size_t i = 1; i < _sub.size() && sameSupports; ++i )
2250     sameSupports = ( grp1 == _sub[i]._support );
2251
2252   return sameSupports;
2253 }
2254
2255 //================================================================================
2256 /*!
2257  * \brief True if the field can be converted into the med field
2258  */
2259 //================================================================================
2260
2261 bool DoubleField::isMedCompatible() const
2262 {
2263   for ( size_t iSub = 0; iSub < _sub.size(); ++iSub )
2264     {
2265       if ( !getSupport(iSub) || !getSupport(iSub)->_medGroup )
2266         THROW_IK_EXCEPTION("SauvReader INTERNAL ERROR: NULL field support");
2267
2268       if ( !_sub[iSub].isValidNbGauss() )
2269         {
2270           cout << "Skip field <" << _name << "> : different nb of gauss points in components" <<endl;
2271           return false;
2272         }
2273     }
2274   // check if there are no gauss or nbGauss() == nbCellNodes,
2275   // else we lack info on gauss point localization
2276   // TODO?
2277   return true;
2278 }
2279
2280 //================================================================================
2281 /*!
2282  * \brief return true if all sub-components has same components and same nbGauss
2283  */
2284 //================================================================================
2285
2286 bool DoubleField::hasSameComponentsBySupport() const
2287 {
2288   vector< _Sub_data >::const_iterator sub_data = _sub.begin();
2289   const _Sub_data& first_sub_data = *sub_data;
2290   for ( ++sub_data ; sub_data != _sub.end(); ++sub_data )
2291   {
2292     if ( first_sub_data._comp_names != sub_data->_comp_names )
2293       return false; // diff names of components
2294
2295     if ( first_sub_data._nb_gauss != sub_data->_nb_gauss &&
2296          first_sub_data._support->_cellType == sub_data->_support->_cellType)
2297       return false; // diff nb of gauss points on same cell type
2298   }
2299   return true;
2300 }
2301
2302 //================================================================================
2303 /*!
2304  * \brief Return type of MEDCouplingFieldDouble
2305  */
2306 //================================================================================
2307
2308 ParaMEDMEM::TypeOfField DoubleField::getMedType( const int iSub ) const
2309 {
2310   using namespace INTERP_KERNEL;
2311
2312   const Group* grp = hasCommonSupport() ? _group : _sub[iSub]._support;
2313   if ( _sub[iSub].nbGauss() > 1 )
2314     {
2315       const CellModel& cm = CellModel::GetCellModel( _sub[iSub]._support->_cellType );
2316       return (int) cm.getNumberOfNodes() == _sub[iSub].nbGauss() ? ON_GAUSS_NE : ON_GAUSS_PT;
2317     }
2318   else
2319     {
2320       return getDim( grp ) == 0 ? ON_NODES : ON_CELLS;
2321     }
2322 }
2323
2324 //================================================================================
2325 /*!
2326  * \brief Return TypeOfTimeDiscretization
2327  */
2328 //================================================================================
2329
2330 ParaMEDMEM::TypeOfTimeDiscretization DoubleField::getMedTimeDisc() const
2331 {
2332   return ONE_TIME;
2333   // NO_TIME = 4,
2334   // ONE_TIME = 5,
2335   // LINEAR_TIME = 6,
2336   // CONST_ON_TIME_INTERVAL = 7
2337 }
2338
2339 //================================================================================
2340 /*!
2341  * \brief Return nb tuples to be used to allocate DataArrayDouble
2342  */
2343 //================================================================================
2344
2345 int DoubleField::getNbTuples( const int iSub ) const
2346 {
2347   int nb = 0;
2348   if ( hasCommonSupport() && !_group->_groups.empty() )
2349     for ( size_t i = 0; i < _group->_groups.size(); ++i )
2350       nb += _sub[i].nbGauss() * _sub[i]._support->size();
2351   else
2352     nb = _sub[iSub].nbGauss() * getSupport(iSub)->size();
2353   return nb;
2354 }
2355
2356 //================================================================================
2357 /*!
2358  * \brief Store values of a sub-component and return nb of elements in the iSub
2359  */
2360 //================================================================================
2361
2362 int DoubleField::setValues( double * valPtr, const int iSub, const int elemShift ) const
2363 {
2364   // find values for iSub
2365   int iComp = 0;
2366   for ( int iS = 0; iS < iSub; ++iS )
2367     iComp += _sub[iS].nbComponents();
2368   const vector< double > * compValues = &_comp_values[ iComp ];
2369
2370   const vector< unsigned >& relocTable = getSupport( iSub )->_relocTable;
2371
2372   // Set values
2373
2374   const int nbElems      = _sub[iSub]._support->size();
2375   const int nbGauss      = _sub[iSub].nbGauss();
2376   const int nbComponents = _sub[iSub].nbComponents();
2377   const int nbValsByElem = nbComponents * nbGauss;
2378   // check nb values
2379   int nbVals = 0;
2380   for ( iComp = 0; iComp < nbComponents; ++iComp )
2381     nbVals += compValues[iComp].size();
2382   if ( nbVals != nbElems * nbValsByElem )
2383     THROW_IK_EXCEPTION("SauvMedConvertor.cxx: support size mismatches field size");
2384   // compute nb values in previous subs
2385   int valsShift = 0;
2386   for ( int iS = iSub-1, shift = elemShift; shift > 0; --iS)
2387   {
2388     int nbE = _sub[iS]._support->size();
2389     shift -= nbE;
2390     valsShift += nbE * _sub[iS].nbComponents() * _sub[iS].nbGauss();
2391   }
2392   for ( int iE = 0; iE < nbElems; ++iE )
2393     {
2394       int iMed = valsShift + nbValsByElem * ( relocTable.empty() ? iE : relocTable[iE+elemShift]-elemShift );
2395       for ( iComp = 0; iComp < nbComponents; ++iComp )
2396         for ( int iG = 0; iG < nbGauss; ++iG )
2397           valPtr[ iMed + iG * nbComponents + iComp ] = compValues[iComp][ iE * nbGauss + iG ];
2398     }
2399   return nbElems;
2400 }
2401
2402 //================================================================================
2403 /*!
2404  * \brief Destructor of IntermediateMED
2405  */
2406 //================================================================================
2407
2408 IntermediateMED::~IntermediateMED()
2409 {
2410   for ( size_t i = 0; i < _nodeFields.size(); ++i )
2411     if ( _nodeFields[i] )
2412       delete _nodeFields[i];
2413   _nodeFields.clear();
2414
2415   for ( size_t i = 0; i < _cellFields.size(); ++i )
2416     if ( _cellFields[i] )
2417       delete _cellFields[i];
2418   _cellFields.clear();
2419
2420   for ( size_t i = 0; i < _groups.size(); ++i )
2421     if ( _groups[i]._medGroup )
2422       _groups[i]._medGroup->decrRef();
2423 }
2424
2425 //================================================================================
2426 /*!
2427  * \brief CellsByDimIterator constructor
2428  */
2429 CellsByDimIterator::CellsByDimIterator( const IntermediateMED & medi, int dimm)
2430 {
2431   myImed = & medi;
2432   init( dimm );
2433 }
2434 /*!
2435  * \brief Initialize iteration on cells of given dimention
2436  */
2437 void CellsByDimIterator::init(const int  dimm)
2438 {
2439   myCurType = -1;
2440   myTypeEnd = INTERP_KERNEL::NORM_HEXA20 + 1;
2441   myDim = dimm;
2442 }
2443 /*!
2444  * \brief return next set of Cell's of required dimension
2445  */
2446 const std::set< Cell > * CellsByDimIterator::nextType()
2447 {
2448   while ( ++myCurType < myTypeEnd )
2449     if ( !myImed->_cellsByType[myCurType].empty() && ( myDim < 0 || dim(false) == myDim ))
2450       return & myImed->_cellsByType[myCurType];
2451   return 0;
2452 }
2453 /*!
2454  * \brief return dimension of cells returned by the last or further next()
2455  */
2456 int CellsByDimIterator::dim(const bool last) const
2457 {
2458   int typp = myCurType;
2459   if ( !last )
2460     while ( typp < myTypeEnd && myImed->_cellsByType[typp].empty() )
2461       ++typp;
2462   return typp < myTypeEnd ? getDimension( TCellType( typp )) : 4;
2463 }
2464 // END CellsByDimIterator ========================================================
2465