Salome HOME
fcbbd5ef26038c499f95ae81120254c02ae876be
[modules/med.git] / src / MEDLoader / SauvReader.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      : SauvReader.cxx
20 // Created   : Tue Aug 16 13:57:42 2011
21 // Author    : Edward AGAPOV (eap)
22 //
23
24 #include "SauvReader.hxx"
25
26 #include "SauvMedConvertor.hxx"
27 #include "MEDCouplingAutoRefCountObjectPtr.hxx"
28 #include "NormalizedUnstructuredMesh.hxx"
29 #include "MEDCouplingRefCountObject.hxx"
30
31 #include <cstring>
32 #include <sstream>
33 #include <iostream>
34
35 using namespace ParaMEDMEM;
36 using namespace SauvUtilities;
37 using namespace std;
38
39 #define GIBI_EQUAL(var_str, stat_str) (strncmp (var_str, stat_str, strlen(stat_str)) == 0)
40
41 //================================================================================
42 /*!
43  * \brief Creates a reader of a given sauve file
44  */
45 //================================================================================
46
47 SauvReader* SauvReader::New(const char *fileName) throw(INTERP_KERNEL::Exception)
48 {
49   if ( !fileName || strlen(fileName) < 1 ) THROW_IK_EXCEPTION("Invalid file name");
50
51   ParaMEDMEM::MEDCouplingAutoRefCountObjectPtr< SauvUtilities::FileReader> parser;
52
53   // try to open as XRD
54   parser = new XDRReader( fileName );
55   if ( parser->open() )
56     {
57       SauvReader* reader = new SauvReader;
58       reader->_fileReader = parser.retn();
59       return reader;
60     }
61
62   // try to open as ASCII
63   parser = new ASCIIReader( fileName );
64   if ( parser->open() )
65     {
66       SauvReader* reader = new SauvReader;
67       reader->_fileReader = parser.retn();
68       return reader;
69     }
70
71   THROW_IK_EXCEPTION("Unable to open file |"<< fileName << "|");
72 }
73 //================================================================================
74 /*!
75  * \brief Destructor
76  */
77 //================================================================================
78
79 SauvReader::~SauvReader()
80 {
81   _fileReader->decrRef();
82 }
83
84 //================================================================================
85 /*!
86  * \brief Return current line of ASCII file to report an error
87  */
88 //================================================================================
89
90 std::string SauvReader::lineNb() const
91 {
92   if ( isASCII() )
93     return string(" (line #") + SauvUtilities::toString
94       ( static_cast<SauvUtilities::ASCIIReader*>( _fileReader )->lineNb() ) + ")";
95
96   return "";
97 }
98
99 //================================================================================
100 /*!
101  * \brief Reads contents of the sauve file and convert it to MEDFileData
102  */
103 //================================================================================
104
105 ParaMEDMEM::MEDFileData * SauvReader::loadInMEDFileDS() throw(INTERP_KERNEL::Exception)
106 {
107   SauvUtilities::IntermediateMED iMed; // intermadiate DS
108   _iMed = &iMed;
109
110   char* line; // a current line
111   const char* enregistrement_type=" ENREGISTREMENT DE TYPE";
112
113   while ( getNextLine(line, /*raiseOEF=*/false)) // external loop looking for "ENREGISTREMENT DE TYPE"
114     {
115       if ( isASCII() && !GIBI_EQUAL( line, enregistrement_type ))
116         continue; // "ENREGISTREMENT DE TYPE" not found -> read the next line
117
118       // read the number of a record
119       int recordNumber;
120       if ( isASCII() )
121         recordNumber = atoi( line + strlen(enregistrement_type) + 1 );
122       else
123         recordNumber = getInt();
124
125       // read the record
126       if ( recordNumber == 2 )
127         readRecord2();
128       else if (recordNumber == 4 )
129         readRecord4();
130       else if (recordNumber == 7 )
131         readRecord7();
132       else if (recordNumber == 5 )
133         break; // stop reading
134       else
135         if ( !isASCII() )
136           THROW_IK_EXCEPTION("XDR : ENREGISTREMENT DE TYPE " << recordNumber << " not implemented!!!");
137     }
138
139   ParaMEDMEM::MEDFileData* medFileData = iMed.convertInMEDFileDS();
140
141   return medFileData;
142 }
143
144 //================================================================================
145 /*!
146  * \brief Reads "ENREGISTREMENT DE TYPE 4"
147  */
148 //================================================================================
149
150 void SauvReader::readRecord4()
151 {
152   if ( !isASCII() )
153     {
154       getInt(); // skip NIVEAU
155       getInt(); // skip ERREUR
156       _iMed->_spaceDim = getInt();
157       getFloat(); // skip DENSITE
158     }
159   else
160     {
161       char* line;
162       getNextLine(line);
163       const char* s = " NIVEAU  15 NIVEAU ERREUR   0 DIMENSION";
164       _iMed->_spaceDim = atoi( line + strlen( s ) + 1 );
165       if ( !GIBI_EQUAL( line, " NIVEAU" ))
166         THROW_IK_EXCEPTION( "Could not read space dimension" << lineNb() );
167       }
168   if ( _iMed->_spaceDim < 1 )
169     THROW_IK_EXCEPTION( "Invalid space dimension:" << _iMed->_spaceDim );
170 }
171
172 //================================================================================
173 /*!
174  * \brief Reads "ENREGISTREMENT DE TYPE 7"
175  */
176 //================================================================================
177
178 void SauvReader::readRecord7()
179 {
180   if ( !isASCII() )
181     {
182       getInt(); // skip NOMBRE INFO CASTEM2000
183       getInt(); // skip IFOUR
184       getInt(); // skip NIFOUR
185       getInt(); // skip IFOMOD
186       getInt(); // skip IECHO
187       getInt(); // skip IIMPI
188       getInt(); // skip IOSPI
189       getInt(); // skip ISOTYP
190       getInt(); // skip NSDPGE
191     }
192   else
193     {
194       // skip 3 lines:
195       // NOMBRE INFO CASTEM2000   8
196       // IFOUR   2 NIFOUR   0 IFOMOD   2 IECHO   1 IIMPI   0 IOSPI   0 ISOTYP   1
197       // NSDPGE     0
198       char* line;
199       getNextLine(line);
200       getNextLine(line);
201       getNextLine(line);
202     }
203 }
204
205 //================================================================================
206 /*!
207  * \brief Reads the pile number, nb of objects and nb named of objects
208  */
209 //================================================================================
210
211 int SauvReader::readPileNumber(int& nbNamedObjects, int& nbObjects)
212 {
213   // FORMAT(' PILE NUMERO',I4,'NBRE ObjectS NOMMES',I8,'NBRE ObjectS',I8)
214   int pileNumber;
215   if ( !isASCII() )
216     {
217       initIntReading(3);
218       pileNumber     = getInt(); next();
219       nbNamedObjects = getInt(); next();
220       nbObjects      = getInt(); next();
221     }
222   else
223     {
224       char* line;
225       getNextLine(line);
226       const char *s1 = " PILE NUMERO", *s2 = "NBRE ObjectS NOMMES", *s3 = "NBRE ObjectS";
227       if ( ! GIBI_EQUAL( line, s1 ) )
228         THROW_IK_EXCEPTION("Could not read the pile number " << lineNb() );
229       line           = line + strlen(s1);
230       pileNumber     = atoi( line );
231       line           = line + 4 + strlen(s2);
232       nbNamedObjects = atoi( line );
233       line           = line + 8 + strlen(s3);
234       nbObjects      = atoi( line );
235     }
236   if ( nbNamedObjects<0 )
237     THROW_IK_EXCEPTION("Invalid nb of named objects: " << nbNamedObjects  << lineNb() );
238   if ( nbObjects<0)
239     THROW_IK_EXCEPTION("Invalid nb of objects: " << nbObjects  << lineNb() );
240   // It appears to be a valid case
241   // if ( nbObjects<nbNamedObjects)
242   //   THROW_IK_EXCEPTION("In PILE " << pileNumber <<
243   //                      " nb of objects is less than nb of named objects"  << lineNb() );
244   return pileNumber;
245 }
246
247 //================================================================================
248 /*!
249  * \brief Reads "ENREGISTREMENT DE TYPE 2"
250  */
251 //================================================================================
252
253 void SauvReader::readRecord2()
254 {
255   if ( _iMed->_spaceDim == 0 )
256     THROW_IK_EXCEPTION("Missing ENREGISTREMENT DE TYPE   4");
257
258   // read a pile number
259   int pileNumber, nbNamedObjects, nbObjects;
260   pileNumber = readPileNumber(nbNamedObjects, nbObjects);
261
262   if ( !_encounteredPiles.insert( pileNumber ).second && // piles may repeat
263        isASCII())
264     return;
265
266   // read object names and their indices
267   vector<string> objectNames(nbNamedObjects);
268   for ( initNameReading( nbNamedObjects ); more(); next() )
269     objectNames[ index() ] = getName();
270
271   vector<int> nameIndices(nbNamedObjects);
272   for ( initIntReading( nbNamedObjects ); more(); next() )
273     nameIndices[ index() ] = getInt();
274
275   switch ( pileNumber )
276     {
277     case PILE_SOUS_MAILLAGE:
278       read_PILE_SOUS_MAILLAGE(nbObjects, objectNames, nameIndices);
279       break;
280     case PILE_NODES_FIELD:
281       read_PILE_NODES_FIELD(nbObjects, objectNames, nameIndices);
282       break;
283     case PILE_TABLES:
284       read_PILE_TABLES(nbObjects, objectNames, nameIndices);
285       break;
286     case PILE_LREEL:
287       read_PILE_LREEL(nbObjects, objectNames, nameIndices);
288       break;
289     case PILE_LOGIQUES:
290       read_PILE_LOGIQUES(nbObjects, objectNames, nameIndices);
291       break;
292     case PILE_FLOATS:
293       read_PILE_FLOATS(nbObjects, objectNames, nameIndices);
294       break;
295     case PILE_INTEGERS:
296       read_PILE_INTEGERS(nbObjects, objectNames, nameIndices);
297       break;
298     case PILE_STRINGS:
299       read_PILE_STRINGS(nbObjects, objectNames, nameIndices);
300       break;
301     case PILE_LMOTS:
302       read_PILE_LMOTS(nbObjects, objectNames, nameIndices);
303       break;
304     case PILE_NOEUDS:
305       read_PILE_NOEUDS(nbObjects, objectNames, nameIndices);
306       break;
307     case PILE_COORDONNEES:
308       read_PILE_COORDONNEES(nbObjects, objectNames, nameIndices);
309       break;
310     case PILE_MODL:
311       read_PILE_MODL(nbObjects, objectNames, nameIndices);
312       break;
313     case PILE_FIELD:
314       read_PILE_FIELD(nbObjects, objectNames, nameIndices);
315       break;
316     default:
317       if ( !isASCII() )
318         THROW_IK_EXCEPTION("XDR : reading PILE " << pileNumber << " not implemented !!!");
319     }
320 }
321
322 //================================================================================
323 /*!
324  * \brief Reads "PILE NUMERO   1": gibi sub-meshes that are converted into med groups
325  */
326 //================================================================================
327
328 void SauvReader::read_PILE_SOUS_MAILLAGE(const int                 nbObjects,
329                                          std::vector<std::string>& objectNames,
330                                          std::vector<int>&         nameIndices)
331 {
332   _iMed->_groups.reserve(nbObjects*2); // fields may add some groups
333
334   char* line;
335   map<int,int> strangeGroupType;
336   int i;
337
338   for (int object=0; object!=nbObjects; ++object) // loop on sub-groups
339     {
340       initIntReading( 5 );
341       int castemCellType = getIntNext();
342       int nbSubGroups    = getIntNext();
343       int nbReferences   = getIntNext();
344       int nbNodesPerElem = getIntNext();
345       int nbElements     = getIntNext();
346
347       _iMed->_groups.push_back(Group());
348       SauvUtilities::Group & group = _iMed->_groups.back();
349
350       // Issue 0021311. Allocate places for names of referring groups
351       // that will be possibly filled after reading long names from
352       // PILE_TABLES and PILE_STRINGS
353       group._refNames.resize( nbReferences );
354
355       // castemCellType=0 corresponds to a sub-mesh composed of other sub-meshes
356       if (castemCellType==0 && nbSubGroups>0)
357         {
358           group._groups.resize( nbSubGroups );
359           for ( initIntReading( nbSubGroups ); more(); next() )
360             group._groups[ index() ] = & _iMed->_groups[ getInt() - 1 ];
361           //std::sort( group._groups.begin(), group._groups.end() ); // for _groups comparison in getFieldSupport()
362         }
363       // skip references
364       if ( isASCII() )
365         for ( i = 0; i < nbReferences; i += 10 ) // FORMAT(10I8)
366           getNextLine(line);
367       else
368         for (initIntReading(nbReferences); more(); next());
369
370       // skip colors
371       if ( isASCII() )
372         for ( i = 0; i < nbElements; i += 10 )
373           getNextLine(line);
374       else
375         for (initIntReading(nbElements); more(); next());
376
377       // not a composit group
378       if (castemCellType>0 && nbSubGroups==0)
379         {
380           group._cellType = SauvUtilities::gibi2medGeom(castemCellType);
381
382           initIntReading( nbElements * nbNodesPerElem );
383           if ( group._cellType == INTERP_KERNEL::NORM_ERROR ) // look for group end
384             {
385               for ( ; more();  next());
386               strangeGroupType.insert( make_pair( object, castemCellType ));
387             }
388           else
389             {
390               // if ( group._cellType == MED_POINT1 ) group._cellType = NORM_ERROR; // issue 21199
391
392               // read connectivity of elements of a group
393               SauvUtilities::Cell ma( nbNodesPerElem );
394               SauvUtilities::Node* pNode;
395               group._cells.resize( nbElements );
396               for ( i = 0; i < nbElements; ++i )
397                 {
398                   ma.init();
399                   for ( int n = 0; n < nbNodesPerElem; ++n )
400                     {
401                       int nodeID = getIntNext();
402                       pNode = _iMed->getNode( nodeID );
403                       ma._nodes[n] = pNode;
404                       _iMed->_nbNodes += ( !pNode->isUsed() );
405                       pNode->_number = nodeID;
406                     }
407                   ma._number = _iMed->getNbCellsOfType( group._cellType ) + 1;
408                   group._cells[i] = _iMed->insert( group._cellType, ma );
409                 }
410             }
411         }
412     } // loop on groups
413
414   // set group names
415   for (i=0; i!=(int)objectNames.size(); ++i)
416     {
417       int grpID = nameIndices[i];
418       SauvUtilities::Group & grp = _iMed->_groups[ grpID-1 ];
419       if ( !grp._name.empty() ) // a group has several names
420         { // create a group with subgroup grp and named grp.name
421           _iMed->_groups.push_back(Group());
422           _iMed->_groups.back()._groups.push_back( &_iMed->_groups[ grpID-1 ]);
423           _iMed->_groups.back()._name = grp._name;
424         }
425       grp._name=objectNames[i];
426 #ifdef _DEBUG
427       map<int,int>::iterator it = strangeGroupType.find( grpID - 1 );
428       if ( it != strangeGroupType.end() )
429         cout << "Skip " << grp._name << " of not supported CASTEM type: " << it->second << endl;
430 #endif
431     }
432 } // read_PILE_SOUS_MAILLAGE()
433
434 //================================================================================
435 /*!
436  * \brief Skip "PILE NUMERO  18" of XDR file
437  */
438 //================================================================================
439
440 void SauvReader::read_PILE_LREEL (const int nbObjects, std::vector<std::string>&, std::vector<int>&)
441 {
442   if ( isXRD() )
443     {
444       for (int object=0; object!=nbObjects; ++object) // pour chaque Group
445         {
446           initIntReading(1);
447           int nb_vals = getIntNext();
448           initDoubleReading(nb_vals);
449           for(int i=0; i<nb_vals; i++) next();
450         }
451     }
452 }
453
454 //================================================================================
455 /*!
456  * \brief Skip "PILE NUMERO  24" of XDR file
457  */
458 //================================================================================
459
460 void SauvReader::read_PILE_LOGIQUES (const int, std::vector<std::string>&, std::vector<int>&)
461 {
462   if ( isXRD() )
463     {
464       initIntReading(1);
465       int nb_vals = getIntNext();
466       initIntReading(nb_vals);
467       for(int i=0; i<nb_vals; i++) next();
468     }
469 }
470
471 //================================================================================
472 /*!
473  * \brief Skip "PILE NUMERO  25" of XDR file
474  */
475 //================================================================================
476
477 void SauvReader::read_PILE_FLOATS (const int, std::vector<std::string>&, std::vector<int>&)
478 {
479   if ( isXRD() )
480     {
481       initIntReading(1);
482       int nb_vals = getIntNext();
483       initDoubleReading(nb_vals);
484       for(int i=0; i<nb_vals; i++) next();
485     }
486 }
487
488 //================================================================================
489 /*!
490  * \brief Skip "PILE NUMERO  26" of XDR file
491  */
492 //================================================================================
493
494 void SauvReader::read_PILE_INTEGERS (const int, std::vector<std::string>&, std::vector<int>&)
495 {
496   if ( isXRD() )
497     {
498       initIntReading(1);
499       int nb_vals = getIntNext();
500       initIntReading(nb_vals);
501       for(int i=0; i<nb_vals; i++) next();
502     }
503 }
504
505 //================================================================================
506 /*!
507  * \brief Skip "PILE NUMERO  29" of XDR file
508  */
509 //================================================================================
510
511 void SauvReader::read_PILE_LMOTS (const int nbObjects, std::vector<std::string>&, std::vector<int>&)
512 {
513   if ( isXRD() )
514     {
515       for (int object=0; object!=nbObjects; ++object) // pour chaque Group
516         {
517           initIntReading(2);
518           int len = getIntNext();
519           int nb_vals = getIntNext();
520           int nb_char = len*nb_vals;
521           int nb_char_tmp = 0;
522           int fixed_length = 71;
523           while (nb_char_tmp < nb_char)
524             {
525               int remain_len = nb_char - nb_char_tmp;
526               int width;
527               if ( remain_len > fixed_length )
528                 {
529                   width = fixed_length;
530                 }
531               else
532                 {
533                   width = remain_len;
534                 }
535               initNameReading(1, width);
536               next();
537               nb_char_tmp += width;
538             }
539         }
540     }
541 }
542
543 //================================================================================
544 /*!
545  * \brief Skip "PILE NUMERO  38" of XDR file
546  */
547 //================================================================================
548
549 void SauvReader::read_PILE_MODL (const int nbObjects, std::vector<std::string>&, std::vector<int>&)
550 {
551   if ( isXRD() )
552     {
553       for (int object=0; object!=nbObjects; ++object) // pour chaque Group
554         {
555           // see wrmodl.eso
556           initIntReading(10);
557           int n1  = getIntNext();
558           int nm2 = getIntNext();
559           int nm3 = getIntNext();
560           int nm4 = getIntNext();
561           int nm5 = getIntNext();
562           int n45 = getIntNext();
563           /*int nm6 =*/ getIntNext();
564           /*int nm7 =*/ getIntNext();
565           next();
566           next();
567           int nm1 = n1 * n45;
568           int nm9 = n1 * 16;
569           for (initIntReading(nm1); more(); next());
570           for (initIntReading(nm9); more(); next());
571           for (initNameReading(nm5, 8); more(); next());
572           for (initNameReading(nm2, 8); more(); next());
573           for (initNameReading(nm3, 8); more(); next());
574           for (initIntReading(nm4); more(); next());
575         }
576     }
577 } // Fin case pile 38
578
579 //================================================================================
580 /*!
581  * \brief Read "PILE NUMERO  32": links to node coordinates
582  */
583 //================================================================================
584
585 void SauvReader::read_PILE_NOEUDS (const int nbObjects, std::vector<std::string>&, std::vector<int>&)
586 {
587   initIntReading(1);
588   int nb_indices = getIntNext();
589
590   if (nb_indices != nbObjects)
591     THROW_IK_EXCEPTION("Error of reading PILE NUMERO  " << PILE_NOEUDS << lineNb() );
592
593   for ( initIntReading( nbObjects ); more(); next() )
594     {
595       int coordID = getInt();
596       _iMed->getNode( index()+1 )->_coordID = coordID;
597     }
598 }
599
600 //================================================================================
601 /*!
602  * \brief Read "PILE NUMERO  33": node coordinates
603  */
604 //================================================================================
605
606 void SauvReader::read_PILE_COORDONNEES (const int nbObjects, std::vector<std::string>&, std::vector<int>&)
607 {
608   initIntReading(1);
609   int nbReals = getIntNext();
610
611   if ( nbReals < (int)(_iMed->_nbNodes*(_iMed->_spaceDim+1)) )
612     THROW_IK_EXCEPTION("Error of reading PILE NUMERO  " << PILE_COORDONNEES << lineNb() );
613
614   // there are coordinates + density for each node
615   _iMed->_coords.resize( nbReals - nbReals/(_iMed->_spaceDim+1));
616   double* coordPtr = &_iMed->_coords[0];
617
618   initDoubleReading( nbReals );
619   while ( more() )
620     {
621       for (unsigned j = 0; j < _iMed->_spaceDim; ++j, next())
622         *coordPtr++ = getDouble();
623       // skip density
624       getDouble();
625       next();
626     }
627 }
628
629 //================================================================================
630 /*!
631  * \brief Finds or create a Group equal to a given field support 
632  */
633 //================================================================================
634
635 SauvUtilities::Group* SauvReader::getFieldSupport(const vector<SauvUtilities::Group*>& supports)
636 {
637   SauvUtilities::Group* group = NULL;
638   set<SauvUtilities::Group*> sup_set( supports.begin(), supports.end() );
639   if (sup_set.size() == 1 ) // one or equal supports
640     {
641       group = supports[0];
642     }
643   else
644     {
645       // try to find an existing composite group with the same sub-groups
646       for ( size_t i = 0; i < _iMed->_groups.size() && !group; ++i )
647         {
648           Group & grp = _iMed->_groups[i];
649           if (sup_set.size() == grp._groups.size())
650             {
651               bool sameOrder = true;
652               for ( size_t j = 0; j < supports.size() && sameOrder; ++j )
653                 sameOrder = ( supports[j] == grp._groups[ j % grp._groups.size() ]);
654               if ( sameOrder )
655                 group = & _iMed->_groups[i];
656             }
657         }
658       if ( !group ) // no such a group, add a new one
659         {
660           vector<SauvUtilities::Group*> newGroups( supports.begin(),
661                                                    supports.begin() + sup_set.size() );
662           // check if supports includes newGroups in the same order
663           bool sameOrder = true;
664           for ( size_t j = newGroups.size(); j < supports.size() && sameOrder; ++j )
665             sameOrder = ( supports[j] == newGroups[ j % newGroups.size() ]);
666           if ( sameOrder )
667             {
668               _iMed->_groups.push_back( SauvUtilities::Group() );
669               group = & _iMed->_groups.back();
670               group->_groups.swap( newGroups );
671             }
672         }
673     }
674   if ( group )
675     group->_isProfile = true;
676   return group;
677 }
678
679 //================================================================================
680 /*!
681  * \brief set field names
682  */
683 //================================================================================
684
685 void SauvReader::setFieldNames(const vector<SauvUtilities::DoubleField* >& fields,
686                                const vector<string>&                       objets_nommes,
687                                const vector<int>&                          indices_objets_nommes)
688 {
689   unsigned i;
690   for ( i = 0; i < indices_objets_nommes.size(); ++i )
691     {
692       int fieldIndex = indices_objets_nommes[ i ];
693       if ( fields[ fieldIndex - 1 ] )
694         fields[ fieldIndex - 1 ]->_name = objets_nommes[ i ];
695     }
696 }
697
698 //================================================================================
699 /*!
700  * \brief Read "PILE NUMERO   2": NODE FIELDS
701  */
702 //================================================================================
703
704 void SauvReader::read_PILE_NODES_FIELD (const int                 nbObjects,
705                                         std::vector<std::string>& objectNames,
706                                         std::vector<int>&         nameIndices)
707 {
708   _iMed->_nodeFields.resize( nbObjects, (SauvUtilities::DoubleField*) 0 );
709   for (int object=0; object!=nbObjects; ++object) // loop on fields
710     {
711       // EXAMPLE ( with no values )
712
713       // (1)       4       7       2       1
714       // (2)     -88       0       3     -89       0       1     -90       0       2     -91
715       // (2)       0       1
716       // (3) FX   FY   FZ   FZ   FX   FY   FLX
717       // (4)       0       0       0       0       0       0       0
718       // (5)           cree  par  muc pri
719       // (6)
720       // (7)       2
721
722       // (1): nb subcomponents, nb components(total), IFOUR, nb attributes
723       int nb_sub, total_nb_comp, nb_attr;
724       int i_sub, i_comp;
725       initIntReading( 4 );
726       nb_sub        = getIntNext();
727       total_nb_comp = getIntNext();
728       next(); // ignore IFOUR
729       nb_attr       = getIntNext();
730       if ( nb_sub < 0 || total_nb_comp < 0 || nb_attr < 0 )
731         THROW_IK_EXCEPTION("Error of field reading " << lineNb());
732
733       // (2) loop on subcomponents of a field, for each read
734       // (a) support, (b) number of values and (c) number of components
735       vector<Group*> supports( nb_sub );
736       vector<int> nb_values  ( nb_sub );
737       vector<int> nb_comps   ( nb_sub );
738       int total_nb_values = 0;
739       initIntReading( nb_sub * 3 );
740       for ( i_sub = 0; i_sub < nb_sub; ++i_sub )
741         {
742           int supId = -getIntNext(); // (a) reference to support
743           if ( supId < 1 || supId > (int)_iMed->_groups.size() )
744             THROW_IK_EXCEPTION("Wrong mesh reference: "<< supId << lineNb() );
745           supports[ i_sub ] = &_iMed->_groups[ supId-1 ]; // (a) reference to support
746
747           nb_values[ i_sub ] = getIntNext();    // (b) nb points
748           total_nb_values += nb_values[ i_sub ];
749           if ( nb_values[ i_sub ] < 0 )
750             THROW_IK_EXCEPTION(" Wrong nb of points: " << nb_values[ i_sub ]  << lineNb() );
751           nb_comps[ i_sub ] = getInt(); next();     // (c) nb of components in i_sub
752         }
753
754       // create a field if there are values
755       SauvUtilities::DoubleField* fdouble = 0;
756       if ( total_nb_values > 0 )
757         fdouble = new DoubleField( nb_sub, total_nb_comp );
758       _iMed->_nodeFields[ object ] = fdouble;
759
760       // (3) component names
761       initNameReading( total_nb_comp, 4 );
762       for ( i_sub = 0; i_sub < nb_sub; ++i_sub )
763         {
764           // store support id and nb components of a sub
765           if ( fdouble )
766             fdouble->_sub[ i_sub ].setData( nb_comps[ i_sub ], supports[ i_sub ] );
767           for ( i_comp = 0; i_comp < nb_comps[ i_sub ]; ++i_comp, next() )
768             {
769               // store component name
770               string compName = getName();
771               if ( fdouble )
772                 fdouble->_sub[ i_sub ].compName( i_comp ) = compName;
773             }
774         }
775       // (4) nb harmonics ( ignored )
776       for ( initIntReading( total_nb_comp ); more(); next() );
777       // (5) TYPE ( ignored )
778       for (initNameReading(1, /*length=*/71); more(); next());
779       // (6) TITRE ( ignored )
780       for (initNameReading(1, /*length=*/71); more(); next());
781       // (7) attributes ( ignored )
782       for ( initIntReading( nb_attr ); more(); next() );
783
784       for ( i_sub = 0; i_sub < nb_sub; ++i_sub )
785         {
786           // loop on components: read values
787           initDoubleReading( nb_values[ i_sub ] * nb_comps[ i_sub ] );
788           for ( i_comp = 0; i_comp < nb_comps[ i_sub ]; ++i_comp )
789             {
790               if ( fdouble )
791                 {
792                   vector<double>& vals = fdouble->addComponent( nb_values[ i_sub ] );
793                   for ( int i = 0; more() && i < nb_values[ i_sub ]; next(), ++i )
794                     vals[ i ] = getDouble();
795                 }
796               else
797                 {
798                   for ( int i = 0; i < nb_values[ i_sub ]; next(), ++i );
799                 }
800             }
801         } // loop on subcomponents of a field
802
803       // set a supporting group including all subs supports but only
804       // if all subs have the same components
805       if ( fdouble && fdouble->hasSameComponentsBySupport() )
806         fdouble->_group = getFieldSupport( supports );
807       else
808         for ( i_sub = 0; i_sub < nb_sub; ++i_sub )
809           fdouble->_sub[ i_sub ]._support->_isProfile = true;
810
811     } // end loop on field objects
812
813   // set field names
814   setFieldNames( _iMed->_nodeFields, objectNames, nameIndices );
815
816 }  // read_PILE_NODES_FIELD()
817
818 //================================================================================
819 /*!
820  * \brief Read "PILE NUMERO  39": FIELDS
821  */
822 //================================================================================
823
824 void SauvReader::read_PILE_FIELD (const int                 nbObjects,
825                                   std::vector<std::string>& objectNames,
826                                   std::vector<int>&         nameIndices)
827 {
828   // REAL EXAMPLE
829
830   // (1)        1       2       6      16
831   // (2)                                                         CARACTERISTIQUES
832   // (3)      -15  317773       4       0       0       0      -2       0       3
833   // (4)             317581
834   // (5)  0
835   // (6)   317767  317761  317755  317815
836   // (7)  YOUN     NU       H        SIGY
837   // (8)  REAL*8            REAL*8            REAL*8            REAL*8
838   // (9)        1       1       0       0
839   // (10)  2.00000000000000E+05
840   // (11)       1       1       0       0
841   // (12)  3.30000000000000E-01
842   // (13)       1       1       0       0
843   // (14)  1.00000000000000E+04
844   // (15)       6     706       0       0
845   // (16)  1.00000000000000E+02  1.00000000000000E+02  1.00000000000000E+02
846   // (17)  1.00000000000000E+02  1.00000000000000E+02  1.00000000000000E+02
847   // (18)  ...
848
849   _iMed->_cellFields.resize( nbObjects, (SauvUtilities::DoubleField*) 0 );
850   for (int object=0; object!=nbObjects; ++object) // pour chaque field
851     {
852       initIntReading( 4 );
853       int i_sub, nb_sub = getIntNext(); // (1) <nb_sub> 2 6 <title length>
854       next(); // skip "2"
855       next(); // skip "6"
856       int title_length = getIntNext(); // <title length>
857       if ( nb_sub < 1 )
858         THROW_IK_EXCEPTION("Error of field reading: wrong nb of subcomponents " << nb_sub << lineNb() );
859
860       string description;
861       if ( title_length )
862         {
863           if ( isXRD() )
864             {
865               initNameReading(1, title_length);
866               description = getName();
867               next();
868             }
869           else
870             {
871               char* line;
872               getNextLine( line ); // (2) title
873               const int len = 72; // line length
874               description = string(line + len - title_length, title_length); // title is right justified
875             }
876         }
877       // look for a line starting with '-' : <reference to support>
878       if ( isXRD() )
879         {
880           initIntReading( nb_sub * 9 );
881         }
882       else
883         {
884           do {
885             initIntReading( nb_sub * 9 );
886           } while ( getInt() >= 0 );
887         }
888       int total_nb_comp = 0;
889       vector<Group*> supports( nb_sub );
890       vector<int>     nb_comp( nb_sub );
891       for ( i_sub = 0; i_sub < nb_sub; ++i_sub )
892         {                                    // (3)
893           int supportId     = -getIntNext(); // <reference to support>
894           next();                            // ignore <address>
895           nb_comp [ i_sub ] =  getIntNext(); // <nb of components in the sub>
896           for ( int i = 0; i < 6; ++i ) next();  // ignore 6 ints, in example "0 0 0 -2 0 3"
897
898           if ( supportId < 1 || supportId > (int)_iMed->_groups.size() )
899             THROW_IK_EXCEPTION("Error of field reading: wrong mesh reference "<< supportId << lineNb() );
900           if ( nb_comp[ i_sub ] < 0 )
901             THROW_IK_EXCEPTION("Error of field reading: wrong nb of components " <<nb_comp[ i_sub ] << lineNb() );
902
903           supports[ i_sub ] = &_iMed->_groups[ supportId-1 ];
904           total_nb_comp += nb_comp[ i_sub ];
905         }
906       // (4) dummy strings
907       for ( initNameReading( nb_sub, 17 ); more(); next() );
908       // (5) dummy strings
909       for ( initNameReading( nb_sub ); more(); next() );
910
911       // loop on subcomponents of a field, each of which refers to
912       // a certain support and has its own number of components;
913       // read component values
914       SauvUtilities::DoubleField* fdouble = 0;
915       for ( i_sub = 0; i_sub < nb_sub; ++ i_sub )
916         {
917           vector<string> comp_names( nb_comp[ i_sub ]), comp_type( nb_comp[ i_sub ]);
918           // (6) nb_comp addresses of MELVAL structure
919           for ( initIntReading( nb_comp[ i_sub ] ); more(); next() );
920           // (7) component names
921           for ( initNameReading( nb_comp[ i_sub ] ); more(); next() )
922             comp_names[ index() ] = getName();
923           // (8) component type
924           for ( initNameReading( nb_comp[ i_sub ], 17 ); more(); next() ) // 17 is name width
925             {
926               comp_type[ index() ] = getName();
927               // component types must be the same
928               if ( index() > 0 && comp_type[ index() ] != comp_type[ index() - 1] )
929                 THROW_IK_EXCEPTION( "Error of field reading: diff component types <"
930                                     << comp_type[ index() ] << "> != <" << comp_type[ index() - 1 ]
931                                     << ">" << lineNb() );
932             }
933           // now type is known, create a field, one for all subs
934           bool isReal = (nb_comp[i_sub] > 0) ? (comp_type[0] == "REAL*8") : true;
935           if ( !fdouble && total_nb_comp )
936             {
937               if ( !isReal )
938                 cout << "Warning: read NOT REAL field, type <" << comp_type[0] << ">" << lineNb() << endl;
939               _iMed->_cellFields[ object ] = fdouble = new SauvUtilities::DoubleField( nb_sub, total_nb_comp );
940               fdouble->_description = description;
941             }
942           // store support id and nb components of a sub
943           if ( fdouble )
944             fdouble->_sub[ i_sub ].setData( nb_comp[ i_sub ], supports[ i_sub ]);
945           // loop on components: read values
946           for ( int i_comp = 0; i_comp < nb_comp[ i_sub ]; ++i_comp )
947             {
948               // (9) nb of values
949               initIntReading( 4 );
950               int nb_val_by_elem = getIntNext();
951               int nb_values      = getIntNext();
952               next();
953               next();
954               fdouble->_sub[ i_sub ]._nb_gauss[ i_comp ] = nb_val_by_elem;
955
956               // (10) values
957               nb_values *= nb_val_by_elem;
958               if ( fdouble )
959                 {
960                   vector<double> & vals = fdouble->addComponent( nb_values );
961                   for ( isReal ? initDoubleReading( nb_values ) : initIntReading( nb_values ); more(); next())
962                     vals[ index() ] = getDouble();
963                   // store component name
964                   fdouble->_sub[ i_sub ].compName( i_comp ) = comp_names[ i_comp ];
965                 }
966               else
967                 {
968                   for ( isReal ? initDoubleReading( nb_values ) : initIntReading( nb_values ); more(); next() ) ;
969                 }
970             }
971         } // loop on subcomponents of a field
972
973       // set id of a group including all sub supports but only
974       // if all subs have the same nb of components
975       if ( fdouble && fdouble->hasSameComponentsBySupport() )
976         fdouble->_group = getFieldSupport( supports );
977       else
978         for ( i_sub = 0; i_sub < nb_sub; ++i_sub )
979           fdouble->_sub[ i_sub ]._support->_isProfile = true;
980
981     } // end loop on field objects
982
983   // set field names
984   setFieldNames( _iMed->_cellFields, objectNames, nameIndices );
985
986 } // read_PILE_FIELD()
987
988 //================================================================================
989 /*!
990  * \brief Read "PILE NUMERO  10": TABLES
991  */
992 //================================================================================
993
994 void SauvReader::read_PILE_TABLES (const int                 nbObjects,
995                                    std::vector<std::string>& objectNames,
996                                    std::vector<int>&         nameIndices)
997 {
998   // IMP 0020434: mapping GIBI names to MED names
999
1000   string table_med_mail = "MED_MAIL";
1001   string table_med_cham = "MED_CHAM";
1002   string table_med_comp = "MED_COMP";
1003   int table_med_mail_id = -1;
1004   int table_med_cham_id = -1;
1005   int table_med_comp_id = -1;
1006   for (size_t iname = 0; iname < objectNames.size(); iname++)
1007     if      (objectNames[iname] == table_med_mail) table_med_mail_id = nameIndices[iname];
1008     else if (objectNames[iname] == table_med_cham) table_med_cham_id = nameIndices[iname];
1009     else if (objectNames[iname] == table_med_comp) table_med_comp_id = nameIndices[iname];
1010
1011   if ( isASCII() )
1012     if (table_med_mail_id < 0 && table_med_cham_id < 0 && table_med_comp_id < 0)
1013       return;
1014
1015   for (int itable = 1; itable <= nbObjects; itable++)
1016     {
1017       // read tables "MED_MAIL", "MED_CHAM" and "MED_COMP", that keeps correspondence
1018       // between GIBI names (8 symbols if any) and MED names (possibly longer)
1019       initIntReading(1);
1020       int nb_table_vals = getIntNext();
1021       if (nb_table_vals < 0)
1022         THROW_IK_EXCEPTION("Error of reading PILE NUMERO  10" << lineNb() );
1023
1024       int name_i_med_pile;
1025       initIntReading(nb_table_vals);
1026       for (int i = 0; i < nb_table_vals/4; i++)
1027         {
1028           if (itable == table_med_mail_id ||
1029               itable == table_med_cham_id ||
1030               itable == table_med_comp_id)
1031             {
1032               nameGIBItoMED name_i;
1033               name_i_med_pile  = getIntNext();
1034               name_i.med_id    = getIntNext();
1035               name_i.gibi_pile = getIntNext();
1036               name_i.gibi_id   = getIntNext();
1037
1038               if (name_i_med_pile != PILE_STRINGS)
1039                 {
1040                   // error: med(long) names are always kept in PILE_STRINGS
1041                 }
1042               if (itable == table_med_mail_id)
1043                 {
1044                   if (name_i.gibi_pile != PILE_SOUS_MAILLAGE) {
1045                     // error: must be PILE_SOUS_MAILLAGE
1046                   }
1047                   _iMed->_listGIBItoMED_mail.push_back(name_i);
1048                 }
1049               else if (itable == table_med_cham_id)
1050                 {
1051                   if (name_i.gibi_pile != PILE_FIELD &&
1052                       name_i.gibi_pile != PILE_NODES_FIELD)
1053                     {
1054                       // error: must be PILE_FIELD or PILE_NODES_FIELD
1055                     }
1056                   _iMed->_listGIBItoMED_cham.push_back(name_i);
1057                 }
1058               else if (itable == table_med_comp_id)
1059                 {
1060                   if (name_i.gibi_pile != PILE_STRINGS)
1061                     {
1062                       // error: gibi(short) names of components are kept in PILE_STRINGS
1063                     }
1064                   _iMed->_listGIBItoMED_comp.push_back(name_i);
1065                 }
1066             }
1067           else
1068             {
1069               // pass table
1070               for ( int ii = 0; ii < 4; ++ii ) next();
1071             }
1072         }
1073     } // for (int itable = 0; itable < nbObjects; itable++)
1074 }
1075
1076 //================================================================================
1077 /*!
1078  * \brief Read "PILE NUMERO  27"
1079  */
1080 //================================================================================
1081
1082 void SauvReader::read_PILE_STRINGS (const int                 nbObjects,
1083                                     std::vector<std::string>& objectNames,
1084                                     std::vector<int>&         nameIndices)
1085 {
1086   // IMP 0020434: mapping GIBI names to MED names
1087   initIntReading(2);
1088   int stringLen    = getIntNext();
1089   int nbSubStrings = getIntNext();
1090   if (nbSubStrings != nbObjects)
1091     THROW_IK_EXCEPTION("Error of reading PILE NUMERO  27" << lineNb() );
1092
1093   string aWholeString;
1094   if ( isXRD() )
1095     {
1096       const int fixedLength = 71;
1097       while ((int)aWholeString.length() < stringLen)
1098         {
1099           int remainLen = stringLen - aWholeString.length();
1100           int len;
1101           if ( remainLen > fixedLength )
1102             {
1103               len = fixedLength;
1104             }
1105           else
1106             {
1107               len = remainLen;
1108             }
1109           initNameReading(1, len);
1110           aWholeString += getName();
1111           next();
1112         }
1113     }
1114   else
1115     {
1116       char* line;
1117       const int fixedLength = 71;
1118       while ((int)aWholeString.length() < stringLen)
1119         {
1120           getNextLine( line );
1121           int remainLen = stringLen - aWholeString.length();
1122           if ( remainLen > fixedLength )
1123             {
1124               aWholeString += line + 1;
1125             }
1126           else
1127             {
1128               aWholeString += line + ( 72 - remainLen );
1129             }
1130         }
1131     }
1132   int prevOffset = 0;
1133   int currOffset = 0;
1134   initIntReading(nbSubStrings);
1135   for (int istr = 1; istr <= nbSubStrings; istr++, next())
1136     {
1137       currOffset = getInt();
1138       // fill mapStrings
1139       _iMed->_mapStrings[istr] = aWholeString.substr(prevOffset, currOffset - prevOffset);
1140       prevOffset = currOffset;
1141     }
1142 }