Salome HOME
1ce5d818c9e790ca34a4e15254bbeca2dbeda652
[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                                   ff.erase( find( ff.begin(), ff.end(), badFace ));
1581                                   if ( ff.empty() )
1582                                     linkFacesMap.erase( lfIt2 );
1583                                 }
1584                             }
1585                           badFace->_reverse = true; // reverse
1586                           //INFOS_MED( "REVERSE " << *badFace );
1587                           faceQueue.push( badFace );
1588                         }
1589                     }
1590                   linkFacesMap.erase( lfIt );
1591                 }
1592               // add good neighbors to the queue
1593               Link revLink( link.second, link.first );
1594               lfIt = linkFacesMap.find( revLink );
1595               if ( lfIt != linkFacesMap.end() )
1596                 {
1597                   list<const Cell*> & fList = lfIt->second;
1598                   list<const Cell*>::iterator fIt = fList.begin();
1599                   for ( ; fIt != fList.end(); fIt++, nbFaceByLink++ )
1600                     {
1601                       ml.push_back( *fIt );
1602                       if ( *fIt != face )
1603                         faceQueue.push( *fIt );
1604                     }
1605                   linkFacesMap.erase( lfIt );
1606                 }
1607               if ( nbFaceByLink > 2 )
1608                 {
1609                   if ( manifold )
1610                     {
1611                       list<const Cell*>::iterator ii = ml.begin();
1612                       cout << nbFaceByLink << " faces by 1 link:" << endl;
1613                       for( ; ii!= ml.end(); ii++ )
1614                         cout << "in sub-mesh <" << fgm[ *ii ]->_name << "> " << **ii << endl;
1615                     }
1616                   manifold = false;
1617                 }
1618             } // loop on links of the being checked face
1619         } // loop on the face queue
1620     } // while ( !linkFacesMap.empty() )
1621
1622   if ( !manifold )
1623     cout << " -> Non manifold mesh, faces orientation may be incorrect" << endl;
1624 }
1625
1626 //================================================================================
1627 /*!
1628  * \brief Orient volumes according to MED conventions:
1629  * normal of a bottom (first) face should be outside
1630  */
1631 //================================================================================
1632
1633 void IntermediateMED::orientVolumes()
1634 {
1635   set<Cell>::const_iterator elemIt, elemEnd;
1636   vector< pair<int,int> > swapVec;
1637
1638   CellsByDimIterator cellsIt( *this, 3 );
1639   while ( const set<Cell > * elems = cellsIt.nextType() )
1640     {
1641       TCellType cellType = cellsIt.type();
1642       elemIt = elems->begin(), elemEnd = elems->end();
1643       int nbBottomNodes = 0;
1644       switch ( cellType )
1645         {
1646         case NORM_TETRA4:
1647         case NORM_TETRA10:
1648         case NORM_PENTA6:
1649         case NORM_PENTA15:
1650           nbBottomNodes = 3; break;
1651         case NORM_PYRA5:
1652         case NORM_PYRA13:
1653         case NORM_HEXA8:
1654         case NORM_HEXA20:
1655           nbBottomNodes = 4; break;
1656         default: continue;
1657         }
1658       getReverseVector( cellType, swapVec );
1659
1660       for ( ; elemIt != elemEnd; elemIt++ )
1661         {
1662           // find a normal to the bottom face
1663           const double* n[4];
1664           n[0] = nodeCoords( elemIt->_nodes[0]); // 3 bottom nodes
1665           n[1] = nodeCoords( elemIt->_nodes[1]);
1666           n[2] = nodeCoords( elemIt->_nodes[2]);
1667           n[3] = nodeCoords( elemIt->_nodes[nbBottomNodes]); // a top node
1668           double vec01[3]; // vector n[0]-n[1]
1669           vec01[0] = n[1][0] - n[0][0];
1670           vec01[1] = n[1][1] - n[0][1];
1671           vec01[2] = n[1][2] - n[0][2];
1672           double vec02 [3]; // vector n[0]-n[2]
1673           vec02[0] = n[2][0] - n[0][0];
1674           vec02[1] = n[2][1] - n[0][1];
1675           vec02[2] = n[2][2] - n[0][2];
1676           double normal [3]; // vec01 ^ vec02
1677           normal[0] = vec01[1] * vec02[2] - vec01[2] * vec02[1];
1678           normal[1] = vec01[2] * vec02[0] - vec01[0] * vec02[2];
1679           normal[2] = vec01[0] * vec02[1] - vec01[1] * vec02[0];
1680           // check if the 102 angle is convex
1681           if ( nbBottomNodes > 3 )
1682             {
1683               const double* n3 = nodeCoords( elemIt->_nodes[nbBottomNodes-1] );// last bottom node
1684               double vec03 [3];  // vector n[0]-n3
1685               vec03[0] = n3[0] - n[0][0];
1686               vec03[1] = n3[1] - n[0][1];
1687               vec03[2] = n3[2] - n[0][2];
1688               if ( fabs( normal[0]+normal[1]+normal[2] ) <= numeric_limits<double>::max() ) // vec01 || vec02
1689                 {
1690                   normal[0] = vec01[1] * vec03[2] - vec01[2] * vec03[1]; // vec01 ^ vec03
1691                   normal[1] = vec01[2] * vec03[0] - vec01[0] * vec03[2];
1692                   normal[2] = vec01[0] * vec03[1] - vec01[1] * vec03[0];
1693                 }
1694               else
1695                 {
1696                   double vec [3]; // normal ^ vec01
1697                   vec[0] = normal[1] * vec01[2] - normal[2] * vec01[1];
1698                   vec[1] = normal[2] * vec01[0] - normal[0] * vec01[2];
1699                   vec[2] = normal[0] * vec01[1] - normal[1] * vec01[0];
1700                   double dot2 = vec[0]*vec03[0] + vec[1]*vec03[1] + vec[2]*vec03[2]; // vec*vec03
1701                   if ( dot2 < 0 ) // concave -> reverse normal
1702                     {
1703                       normal[0] *= -1;
1704                       normal[1] *= -1;
1705                       normal[2] *= -1;
1706                     }
1707                 }
1708             }
1709           // direction from top to bottom
1710           double tbDir[3];
1711           tbDir[0] = n[0][0] - n[3][0];
1712           tbDir[1] = n[0][1] - n[3][1];
1713           tbDir[2] = n[0][2] - n[3][2];
1714
1715           // compare 2 directions: normal and top-bottom
1716           double dot = normal[0]*tbDir[0] + normal[1]*tbDir[1] + normal[2]*tbDir[2];
1717           if ( dot < 0. ) // need reverse
1718             reverse( *elemIt, swapVec );
1719
1720         } // loop on volumes of one geometry
1721     } // loop on 3D geometry types
1722
1723 }
1724
1725 //================================================================================
1726 /*!
1727  * \brief Assign new IDs to nodes by skipping not used nodes and return their number
1728  */
1729 //================================================================================
1730
1731 int NodeContainer::numberNodes()
1732 {
1733   int id = 1;
1734   for ( size_t i = 0; i < _nodes.size(); ++i )
1735     for ( size_t j = 0; j < _nodes[i].size(); ++j )
1736       if ( _nodes[i][j].isUsed() )
1737         _nodes[i][j]._number = id++;
1738   return id-1;
1739 }
1740
1741
1742 //================================================================================
1743 /*!
1744  * \brief Assign new IDs to elements
1745  */
1746 //================================================================================
1747
1748 void IntermediateMED::numberElements()
1749 {
1750   set<Cell>::const_iterator elemIt, elemEnd;
1751
1752   // numbering _cells of type NORM_POINT1 by node number
1753   {
1754     const set<Cell>& points = _cellsByType[ INTERP_KERNEL::NORM_POINT1 ];
1755     elemIt = points.begin(), elemEnd = points.end();
1756     for ( ; elemIt != elemEnd; ++elemIt )
1757       elemIt->_number = elemIt->_nodes[0]->_number;
1758   }
1759
1760   // numbering 1D-3D _cells
1761   for ( int dim = 1; dim <= 3; ++dim )
1762     {
1763       // check if re-numeration is needed (to try to keep elem oreder as in sauve file )
1764       bool ok = true, renumEntity = false;
1765       CellsByDimIterator cellsIt( *this, dim );
1766       int prevNbElems = 0;
1767       while ( const set<Cell> * typeCells = cellsIt.nextType() )
1768         {
1769           TID minNumber = std::numeric_limits<TID>::max(), maxNumber = 0;
1770           for ( elemIt = typeCells->begin(), elemEnd = typeCells->end(); elemIt!=elemEnd; ++elemIt)
1771             {
1772               if ( elemIt->_number < minNumber ) minNumber = elemIt->_number;
1773               if ( elemIt->_number > maxNumber ) maxNumber = elemIt->_number;
1774             }
1775           TID typeSize = typeCells->size();
1776           if ( typeSize != maxNumber - minNumber + 1 )
1777             ok = false;
1778           if ( prevNbElems != 0 ) {
1779             if ( minNumber == 1 )
1780               renumEntity = true;
1781             else if ( prevNbElems+1 != (int)minNumber )
1782               ok = false;
1783           }
1784           prevNbElems += typeSize;
1785         }
1786
1787       if ( ok && renumEntity ) // each geom type was numerated separately
1788         {
1789           cellsIt.init( dim );
1790           prevNbElems = cellsIt.nextType()->size(); // no need to renumber the first type
1791           while ( const set<Cell> * typeCells = cellsIt.nextType() )
1792             {
1793               for ( elemIt = typeCells->begin(), elemEnd = typeCells->end(); elemIt!=elemEnd; ++elemIt)
1794                 elemIt->_number += prevNbElems;
1795               prevNbElems += typeCells->size();
1796             }
1797         }
1798       if ( !ok )
1799         {
1800           int cellID=1;
1801           cellsIt.init( dim );
1802           while ( const set<Cell> * typeCells = cellsIt.nextType() )
1803             for ( elemIt = typeCells->begin(), elemEnd = typeCells->end(); elemIt!=elemEnd; ++elemIt)
1804               elemIt->_number = cellID++;
1805         }
1806     }
1807 }
1808
1809 //================================================================================
1810 /*!
1811  * \brief Creates coord array
1812  */
1813 //================================================================================
1814
1815 ParaMEDMEM::DataArrayDouble * IntermediateMED::getCoords()
1816 {
1817   DataArrayDouble* coordArray = DataArrayDouble::New();
1818   coordArray->alloc( _nbNodes, _spaceDim );
1819   double * coordPrt = coordArray->getPointer();
1820   for ( int i = 0, nb = _points.size(); i < nb; ++i )
1821     {
1822       Node* n = getNode( i+1 );
1823       if ( n->isUsed() )
1824         {
1825           const double* nCoords = nodeCoords( n );
1826           std::copy( nCoords, nCoords+_spaceDim, coordPrt );
1827           coordPrt += _spaceDim;
1828         }
1829     }
1830   return coordArray;
1831 }
1832
1833 //================================================================================
1834 /*!
1835  * \brief Sets connectivity of elements to the mesh
1836  *  \param mesh - mesh to fill in
1837  *  \param coords - coordinates that must be shared by all meshes of different dim
1838  */
1839 //================================================================================
1840
1841 void IntermediateMED::setConnectivity( ParaMEDMEM::MEDFileUMesh*    mesh,
1842                                        ParaMEDMEM::DataArrayDouble* coords )
1843 {
1844   int meshDim = 0;
1845
1846   mesh->setCoords( coords );
1847
1848   set<Cell>::const_iterator elemIt, elemEnd;
1849   for ( int dim = 3; dim > 0; --dim )
1850   {
1851     CellsByDimIterator dimCells( *this, dim );
1852
1853     int nbOfCells = 0;
1854     while ( const std::set<Cell > * cells = dimCells.nextType() )
1855       nbOfCells += cells->size();
1856     if ( nbOfCells == 0 )
1857       continue;
1858
1859     if ( !meshDim ) meshDim = dim;
1860
1861     MEDCouplingUMesh* dimMesh = MEDCouplingUMesh::New();
1862     dimMesh->setCoords( coords );
1863     dimMesh->setMeshDimension( dim );
1864     dimMesh->allocateCells( nbOfCells );
1865
1866     int prevNbCells = 0;
1867     dimCells.init( dim );
1868     while ( const std::set<Cell > * cells = dimCells.nextType() )
1869       {
1870         // fill connectivity array to take into account order of elements in the sauv file
1871         const int nbCellNodes = cells->begin()->_nodes.size();
1872         vector< TID > connectivity( cells->size() * nbCellNodes );
1873         int * nodalConnOfCell;
1874         for ( elemIt = cells->begin(), elemEnd = cells->end(); elemIt != elemEnd; ++elemIt )
1875           {
1876             const Cell& cell = *elemIt;
1877             const int index = cell._number - 1 - prevNbCells;
1878             nodalConnOfCell = &connectivity[ index * nbCellNodes ];
1879             if ( cell._reverse )
1880               for ( int i = nbCellNodes-1; i >= 0; --i )
1881                 *nodalConnOfCell++ = cell._nodes[i]->_number - 1;
1882             else
1883               for ( int i = 0; i < nbCellNodes; ++i )
1884                 *nodalConnOfCell++ = cell._nodes[i]->_number - 1;
1885           }
1886         prevNbCells += cells->size();
1887
1888         // fill dimMesh
1889         TCellType cellType = dimCells.type();
1890         nodalConnOfCell = &connectivity[0];
1891         for ( size_t i = 0; i < cells->size(); ++i, nodalConnOfCell += nbCellNodes )
1892           dimMesh->insertNextCell( cellType, nbCellNodes, nodalConnOfCell );
1893       }
1894     dimMesh->finishInsertingCells();
1895     mesh->setMeshAtLevel( dim - meshDim, dimMesh );
1896     dimMesh->decrRef();
1897   }
1898 }
1899
1900 //================================================================================
1901 /*!
1902  * \brief Fill in the mesh with groups
1903  *  \param mesh - mesh to fill in
1904  */
1905 //================================================================================
1906
1907 void IntermediateMED::setGroups( ParaMEDMEM::MEDFileUMesh* mesh )
1908 {
1909   bool isMeshNameSet = false;
1910   const int meshDim = mesh->getMeshDimension();
1911   for ( int dim = 0; dim <= meshDim; ++dim )
1912     {
1913       const int meshDimRelToMaxExt = ( dim == 0 ? 1 : dim - meshDim );
1914
1915       vector<const DataArrayInt *> medGroups;
1916       vector<MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > refGroups;
1917       for ( size_t i = 0; i < _groups.size(); ++i )
1918         {
1919           Group& grp = _groups[i];
1920           if ( (int)getDim( &grp ) != dim &&
1921                grp._groups.empty() ) // to allow groups on diff dims
1922             continue;
1923           // convert only named groups or field supports
1924           if ( grp.empty() || (grp._name.empty() && !grp._isProfile ))
1925             continue;
1926           //if ( grp._medGroup ) continue; // already converted
1927
1928           // sort cells by ID and remember their initial order in the group
1929           TCellToOrderMap cell2order;
1930           unsigned orderInGroup = 0;
1931           vector< Group* > groupVec;
1932           if ( grp._groups.empty() ) groupVec.push_back( & grp );
1933           else                       groupVec = grp._groups;
1934           for ( size_t iG = 0; iG < groupVec.size(); ++iG )
1935             {
1936               Group* aG = groupVec[ iG ];
1937               if ( (int)getDim( aG ) != dim )
1938                 continue;
1939               for ( size_t iC = 0; iC < aG->_cells.size(); ++iC )
1940                 cell2order.insert( cell2order.end(), make_pair( aG->_cells[iC], orderInGroup++ ));
1941             }
1942           if ( cell2order.empty() )
1943             continue;
1944           bool isSelfIntersect = ( orderInGroup != cell2order.size() );
1945           if ( isSelfIntersect ) // self intersecting group
1946             {
1947               ostringstream msg;
1948               msg << "Self intersecting sub-mesh: id = " << i+1
1949                   << ", name = |" << grp._name << "|" << endl
1950                   << " nb unique elements = " << cell2order.size() << endl
1951                   << " total nb elements  = " << orderInGroup;
1952               if ( grp._isProfile )
1953                 {
1954                   THROW_IK_EXCEPTION( msg.str() );
1955                 }
1956               else
1957                 {
1958                   cout << msg.str() << endl;
1959                 }
1960             }
1961           // create a med group
1962           grp._medGroup = DataArrayInt::New();
1963           grp._medGroup->setName( grp._name.c_str() );
1964           grp._medGroup->alloc( cell2order.size(), /*nbOfCompo=*/1 );
1965           int * idsPrt = grp._medGroup->getPointer();
1966           TCellToOrderMap::iterator cell2orderIt, cell2orderEnd = cell2order.end();
1967           for ( cell2orderIt = cell2order.begin(); cell2orderIt != cell2orderEnd; ++cell2orderIt )
1968             *idsPrt++ = (*cell2orderIt).first->_number - 1;
1969
1970           // try to set the mesh name
1971           if ( !isMeshNameSet &&
1972                dim == meshDim &&
1973                !grp._name.empty() &&
1974                grp.size() == mesh->getSizeAtLevel( meshDimRelToMaxExt ))
1975             {
1976               mesh->setName( grp._name.c_str() );
1977               isMeshNameSet = true;
1978             }
1979           if ( !grp._name.empty() )
1980             {
1981               medGroups.push_back( grp._medGroup );
1982             }
1983           // set relocation table
1984           setRelocationTable( &grp, cell2order );
1985
1986           // Issue 0021311. Use case: a gibi group has references (recorded in pile 1)
1987           // and several names (pile 27) refer (pile 10) to this group.
1988           // We create a copy of this group per each named reference
1989           for ( unsigned iRef = 0 ; iRef < grp._refNames.size(); ++iRef )
1990             if ( !grp._refNames[ iRef ].empty() )
1991               {
1992                 refGroups.push_back( grp._medGroup->deepCpy() );
1993                 refGroups.back()->setName( grp._refNames[ iRef ].c_str() );
1994                 medGroups.push_back( refGroups.back() );
1995               }
1996         }
1997       mesh->setGroupsAtLevel( meshDimRelToMaxExt, medGroups );
1998     }
1999 }
2000
2001 //================================================================================
2002 /*!
2003  * \brief Return true if the group is on all elements and return its relative dimension
2004  */
2005 //================================================================================
2006
2007 bool IntermediateMED::isOnAll( const Group* grp, int & dimRel ) const
2008 {
2009   int dim = getDim( grp );
2010
2011   int nbElems = 0;
2012   CellsByDimIterator dimCells( *this, dim );
2013   while ( const set<Cell > * cells = dimCells.nextType() )
2014     nbElems += cells->size();
2015
2016   const bool onAll = ( nbElems == grp->size() );
2017
2018   if ( dim == 0 )
2019     dimRel = 0;
2020   else
2021     {
2022       int meshDim = 3;
2023       for ( ; meshDim > 0; --meshDim )
2024         {
2025           dimCells.init( meshDim );
2026           if ( dimCells.nextType() )
2027             break;
2028         }
2029       dimRel = dim - meshDim;
2030     }
2031   return onAll;
2032 }
2033
2034 //================================================================================
2035 /*!
2036  * \brief Makes fields from own data
2037  */
2038 //================================================================================
2039
2040 ParaMEDMEM::MEDFileFields * IntermediateMED::makeMEDFileFields(ParaMEDMEM::MEDFileUMesh* mesh)
2041 {
2042   if ( _nodeFields.empty() && _cellFields.empty() ) return 0;
2043
2044   // set long names
2045   set< string > usedFieldNames;
2046   setFieldLongNames(usedFieldNames);
2047
2048   MEDFileFields* fields = MEDFileFields::New();
2049
2050   for ( size_t i = 0; i < _nodeFields.size(); ++i )
2051     setFields( _nodeFields[i], fields, mesh, i+1, usedFieldNames );
2052
2053   for ( size_t i = 0; i < _cellFields.size(); ++i )
2054     setFields( _cellFields[i], fields, mesh, i+1, usedFieldNames );
2055
2056   return fields;
2057 }
2058
2059 //================================================================================
2060 /*!
2061  * \brief Make med fields from a SauvUtilities::DoubleField
2062  */
2063 //================================================================================
2064
2065 void IntermediateMED::setFields( SauvUtilities::DoubleField* fld,
2066                                  ParaMEDMEM::MEDFileFields*  medFields,
2067                                  ParaMEDMEM::MEDFileUMesh*   mesh,
2068                                  const TID                   castemID,
2069                                  set< string >&              usedFieldNames)
2070 {
2071   if ( !fld || !fld->isMedCompatible() ) return;
2072
2073   // if ( !fld->hasCommonSupport() ):
2074   //     each sub makes MEDFileFieldMultiTS
2075   // else:
2076   //     unite several subs into a MEDCouplingFieldDouble
2077
2078   const bool uniteSubs = fld->hasCommonSupport();
2079   if ( !uniteSubs )
2080     cout << "Castem field #" << castemID << " " << fld->_name
2081          << " is incompatible with MED format, so we split it into several fields" << endl;
2082
2083   for ( size_t iSub = 0; iSub < fld->_sub.size(); )
2084     {
2085       // set field name
2086       if ( !uniteSubs || fld->_name.empty() )
2087         makeFieldNewName( usedFieldNames, fld );
2088
2089       // allocate values
2090       DataArrayDouble * values = DataArrayDouble::New();
2091       values->alloc( fld->getNbTuples(iSub), fld->_sub[iSub].nbComponents() );
2092
2093       // set values
2094       double * valPtr = values->getPointer();
2095       if ( uniteSubs )
2096         {
2097           int nbElems = fld->_group->size();
2098           for ( int elemShift = 0; elemShift < nbElems; )
2099             elemShift += fld->setValues( valPtr, iSub++, elemShift );
2100           setTS( fld, values, medFields, mesh );
2101         }
2102       else
2103         {
2104           fld->setValues( valPtr, iSub++ );
2105           setTS( fld, values, medFields, mesh, iSub );
2106         }
2107     }
2108 }
2109
2110 //================================================================================
2111 /*!
2112  * \brief Store value array of a field into med fields
2113  */
2114 //================================================================================
2115
2116 void IntermediateMED::setTS( SauvUtilities::DoubleField*  fld,
2117                              ParaMEDMEM::DataArrayDouble* values,
2118                              ParaMEDMEM::MEDFileFields*   medFields,
2119                              ParaMEDMEM::MEDFileUMesh*    mesh,
2120                              const int                    iSub)
2121 {
2122   // analyze a field support
2123   const Group* support = fld->getSupport();
2124   int dimRel;
2125   const bool onAll = isOnAll( support, dimRel );
2126   if ( !onAll && support->_name.empty() )
2127     {
2128       const_cast<Group*>(support)->_name += "PFL_" + fld->_name;
2129       support->_medGroup->setName( support->_name.c_str() );
2130     }
2131
2132   // make a time-stamp
2133   MEDCouplingFieldDouble * timeStamp = MEDCouplingFieldDouble::New( fld->getMedType(),
2134                                                                     fld->getMedTimeDisc() );
2135   timeStamp->setName( fld->_name.c_str() );
2136   timeStamp->setDescription( fld->_description.c_str() );
2137   MEDCouplingAutoRefCountObjectPtr< MEDCouplingUMesh > dimMesh = mesh->getMeshAtLevel( dimRel );
2138   timeStamp->setMesh( dimMesh );
2139   for ( size_t i = 0; i < (size_t)fld->_sub[iSub].nbComponents(); ++i )
2140     values->setInfoOnComponent( i, fld->_sub[iSub]._comp_names[ i ].c_str() );
2141   timeStamp->setArray( values );
2142   values->decrRef();
2143
2144   // get a field to add the time-stamp
2145   bool isNewMedField = false;
2146   if ( !fld->_curMedField || fld->_name != fld->_curMedField->getName() )
2147     {
2148       fld->_curMedField = MEDFileFieldMultiTS::New();
2149       isNewMedField = true;
2150     }
2151
2152   // set an order
2153   timeStamp->setOrder( fld->_curMedField->getNumberOfTS() );
2154
2155   // add the time-stamp
2156   if ( onAll )
2157     fld->_curMedField->appendFieldNoProfileSBT( timeStamp );
2158   else
2159     fld->_curMedField->appendFieldProfile( timeStamp, mesh, dimRel, support->_medGroup );
2160   timeStamp->decrRef();
2161
2162   if ( isNewMedField ) // timeStamp must be added before this
2163     {
2164       medFields->pushField( fld->_curMedField );
2165     }
2166 }
2167
2168 //================================================================================
2169 /*!
2170  * \brief Make a new unique name for a field
2171  */
2172 //================================================================================
2173
2174 void IntermediateMED::makeFieldNewName(std::set< std::string >&    usedNames,
2175                                        SauvUtilities::DoubleField* fld )
2176 {
2177   string base = fld->_name;
2178   if ( base.empty() )
2179     {
2180       base = "F_";
2181     }
2182   else
2183     {
2184       string::size_type pos = base.rfind('_');
2185       if ( pos != string::npos )
2186         base = base.substr( 0, pos+1 );
2187       else
2188         base += '_';
2189     }
2190
2191   int i = 1;
2192   do
2193     {
2194       fld->_name = base + SauvUtilities::toString( i++ );
2195     }
2196   while( !usedNames.insert( fld->_name ).second );
2197 }
2198
2199 //================================================================================
2200 /*!
2201  * \brief Return a vector ready to fill in
2202  */
2203 //================================================================================
2204
2205 std::vector< double >& DoubleField::addComponent( int nb_values )
2206 {
2207   _comp_values.push_back( std::vector< double >() );
2208   std::vector< double >& res = _comp_values.back();
2209   res.resize( nb_values );
2210   return res;
2211 }
2212
2213 DoubleField::~DoubleField()
2214 {
2215   if(_curMedField)
2216     _curMedField->decrRef();
2217 }
2218
2219 //================================================================================
2220 /*!
2221  * \brief Returns a supporting group
2222  */
2223 //================================================================================
2224
2225 const Group* DoubleField::getSupport( const int iSub ) const
2226 {
2227   return _group ? _group : _sub[iSub]._support;
2228 }
2229
2230 //================================================================================
2231 /*!
2232  * \brief Return true if each sub-component is a time stamp
2233  */
2234 //================================================================================
2235
2236 bool DoubleField::isMultiTimeStamps() const
2237 {
2238   if ( _sub.size() < 2 )
2239     return false;
2240   bool sameSupports = true;
2241   Group* grp1 = _sub[0]._support;
2242   for ( size_t i = 1; i < _sub.size() && sameSupports; ++i )
2243     sameSupports = ( grp1 == _sub[i]._support );
2244
2245   return sameSupports;
2246 }
2247
2248 //================================================================================
2249 /*!
2250  * \brief True if the field can be converted into the med field
2251  */
2252 //================================================================================
2253
2254 bool DoubleField::isMedCompatible() const
2255 {
2256   for ( size_t iSub = 0; iSub < _sub.size(); ++iSub )
2257     {
2258       if ( !getSupport(iSub) || !getSupport(iSub)->_medGroup )
2259         THROW_IK_EXCEPTION("SauvReader INTERNAL ERROR: NULL field support");
2260
2261       if ( !_sub[iSub].isValidNbGauss() )
2262         {
2263           cout << "Skip field <" << _name << "> : different nb of gauss points in components" <<endl;
2264           return false;
2265         }
2266     }
2267   // check if there are no gauss or nbGauss() == nbCellNodes,
2268   // else we lack info on gauss point localization
2269   // TODO?
2270   return true;
2271 }
2272
2273 //================================================================================
2274 /*!
2275  * \brief return true if all sub-components has same components and same nbGauss
2276  */
2277 //================================================================================
2278
2279 bool DoubleField::hasSameComponentsBySupport() const
2280 {
2281   vector< _Sub_data >::const_iterator sub_data = _sub.begin();
2282   const _Sub_data& first_sub_data = *sub_data;
2283   for ( ++sub_data ; sub_data != _sub.end(); ++sub_data )
2284   {
2285     if ( first_sub_data._comp_names != sub_data->_comp_names )
2286       return false; // diff names of components
2287
2288     if ( first_sub_data._nb_gauss != sub_data->_nb_gauss &&
2289          first_sub_data._support->_cellType == sub_data->_support->_cellType)
2290       return false; // diff nb of gauss points on same cell type
2291   }
2292   return true;
2293 }
2294
2295 //================================================================================
2296 /*!
2297  * \brief Return type of MEDCouplingFieldDouble
2298  */
2299 //================================================================================
2300
2301 ParaMEDMEM::TypeOfField DoubleField::getMedType( const int iSub ) const
2302 {
2303   using namespace INTERP_KERNEL;
2304
2305   const Group* grp = hasCommonSupport() ? _group : _sub[iSub]._support;
2306   if ( _sub[iSub].nbGauss() > 1 )
2307     {
2308       const CellModel& cm = CellModel::GetCellModel( _sub[iSub]._support->_cellType );
2309       return (int) cm.getNumberOfNodes() == _sub[iSub].nbGauss() ? ON_GAUSS_NE : ON_GAUSS_PT;
2310     }
2311   else
2312     {
2313       return getDim( grp ) == 0 ? ON_NODES : ON_CELLS;
2314     }
2315 }
2316
2317 //================================================================================
2318 /*!
2319  * \brief Return TypeOfTimeDiscretization
2320  */
2321 //================================================================================
2322
2323 ParaMEDMEM::TypeOfTimeDiscretization DoubleField::getMedTimeDisc() const
2324 {
2325   return ONE_TIME;
2326   // NO_TIME = 4,
2327   // ONE_TIME = 5,
2328   // LINEAR_TIME = 6,
2329   // CONST_ON_TIME_INTERVAL = 7
2330 }
2331
2332 //================================================================================
2333 /*!
2334  * \brief Return nb tuples to be used to allocate DataArrayDouble
2335  */
2336 //================================================================================
2337
2338 int DoubleField::getNbTuples( const int iSub ) const
2339 {
2340   int nb = 0;
2341   if ( hasCommonSupport() && !_group->_groups.empty() )
2342     for ( size_t i = 0; i < _group->_groups.size(); ++i )
2343       nb += _sub[i].nbGauss() * _sub[i]._support->size();
2344   else
2345     nb = _sub[iSub].nbGauss() * getSupport(iSub)->size();
2346   return nb;
2347 }
2348
2349 //================================================================================
2350 /*!
2351  * \brief Store values of a sub-component and return nb of elements in the iSub
2352  */
2353 //================================================================================
2354
2355 int DoubleField::setValues( double * valPtr, const int iSub, const int elemShift ) const
2356 {
2357   // find values for iSub
2358   int iComp = 0;
2359   for ( int iS = 0; iS < iSub; ++iS )
2360     iComp += _sub[iS].nbComponents();
2361   const vector< double > * compValues = &_comp_values[ iComp ];
2362
2363   const vector< unsigned >& relocTable = getSupport( iSub )->_relocTable;
2364
2365   // Set values
2366
2367   const int nbElems      = _sub[iSub]._support->size();
2368   const int nbGauss      = _sub[iSub].nbGauss();
2369   const int nbComponents = _sub[iSub].nbComponents();
2370   const int nbValsByElem = nbComponents * nbGauss;
2371   // check nb values
2372   int nbVals = 0;
2373   for ( iComp = 0; iComp < nbComponents; ++iComp )
2374     nbVals += compValues[iComp].size();
2375   if ( nbVals != nbElems * nbValsByElem )
2376     THROW_IK_EXCEPTION("SauvMedConvertor.cxx: support size mismatches field size");
2377   // compute nb values in previous subs
2378   int valsShift = 0;
2379   for ( int iS = iSub-1, shift = elemShift; shift > 0; )
2380   {
2381     int nbE = _sub[iS]._support->size();
2382     shift -= nbE;
2383     valsShift += nbE * _sub[iS].nbComponents() * _sub[iS].nbGauss();
2384   }
2385   for ( int iE = 0; iE < nbElems; ++iE )
2386     {
2387       int iMed = valsShift + nbValsByElem * ( relocTable.empty() ? iE : relocTable[iE+elemShift]-elemShift );
2388       for ( iComp = 0; iComp < nbComponents; ++iComp )
2389         for ( int iG = 0; iG < nbGauss; ++iG )
2390           valPtr[ iMed + iG * nbComponents + iComp ] = compValues[iComp][ iE * nbGauss + iG ];
2391     }
2392   return nbElems;
2393 }
2394
2395 //================================================================================
2396 /*!
2397  * \brief Destructor of IntermediateMED
2398  */
2399 //================================================================================
2400
2401 IntermediateMED::~IntermediateMED()
2402 {
2403   for ( size_t i = 0; i < _nodeFields.size(); ++i )
2404     if ( _nodeFields[i] )
2405       delete _nodeFields[i];
2406   _nodeFields.clear();
2407
2408   for ( size_t i = 0; i < _cellFields.size(); ++i )
2409     if ( _cellFields[i] )
2410       delete _cellFields[i];
2411   _cellFields.clear();
2412
2413   for ( size_t i = 0; i < _groups.size(); ++i )
2414     if ( _groups[i]._medGroup )
2415       _groups[i]._medGroup->decrRef();
2416 }
2417
2418 //================================================================================
2419 /*!
2420  * \brief CellsByDimIterator constructor
2421  */
2422 CellsByDimIterator::CellsByDimIterator( const IntermediateMED & medi, int dimm)
2423 {
2424   myImed = & medi;
2425   init( dimm );
2426 }
2427 /*!
2428  * \brief Initialize iteration on cells of given dimention
2429  */
2430 void CellsByDimIterator::init(const int  dimm)
2431 {
2432   myCurType = -1;
2433   myTypeEnd = INTERP_KERNEL::NORM_HEXA20 + 1;
2434   myDim = dimm;
2435 }
2436 /*!
2437  * \brief return next set of Cell's of required dimension
2438  */
2439 const std::set< Cell > * CellsByDimIterator::nextType()
2440 {
2441   while ( ++myCurType < myTypeEnd )
2442     if ( !myImed->_cellsByType[myCurType].empty() && ( myDim < 0 || dim(false) == myDim ))
2443       return & myImed->_cellsByType[myCurType];
2444   return 0;
2445 }
2446 /*!
2447  * \brief return dimension of cells returned by the last or further next()
2448  */
2449 int CellsByDimIterator::dim(const bool last) const
2450 {
2451   int typp = myCurType;
2452   if ( !last )
2453     while ( typp < myTypeEnd && myImed->_cellsByType[typp].empty() )
2454       ++typp;
2455   return typp < myTypeEnd ? getDimension( TCellType( typp )) : 4;
2456 }
2457 // END CellsByDimIterator ========================================================
2458