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