Salome HOME
Merge from V6_main (04/10/2012)
[modules/med.git] / src / MEDLoader / SauvWriter.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      : SauvWriter.cxx
20 // Created   : Wed Aug 24 12:55:55 2011
21 // Author    : Edward AGAPOV (eap)
22
23 #include "SauvWriter.hxx"
24
25 #include "InterpKernelException.hxx"
26 #include "MEDFileMesh.hxx"
27 #include "MEDFileField.hxx"
28 #include "MEDFileData.hxx"
29 #include "CellModel.hxx"
30
31 #include <fstream>
32 #include <sstream>
33 #include <iostream>
34 #include <cstdlib>
35 #include <iomanip>
36
37 using namespace ParaMEDMEM;
38 using namespace SauvUtilities;
39 using namespace std;
40
41 #define INFOS_MED(txt) cout << txt << endl;
42
43 namespace
44 {
45   const char* zeroI8 = "       0"; // FORMAT(I8)
46
47   // ============================================================
48   // the class writes endl to the file as soon as <limit> fields
49   // have been written after the last endl
50   // ============================================================
51
52   class TFieldCounter
53   {
54     fstream& _file;
55     int _count, _limit;
56   public:
57     TFieldCounter(fstream& f, int limit=0): _file(f), _limit(limit) { init(); }
58     void init(int limit=0) // init, is done by stop() as well
59     { if (limit) _limit = limit; _count = 0; }
60     void operator++(int) // next
61     { if ( ++_count == _limit ) { _file << endl; init(); }}
62     void stop() // init() and write endl if there was no endl after the last written field
63     { if ( _count ) _file << endl; init(); }
64     ~TFieldCounter() { stop(); }
65   };
66
67   //================================================================================
68   /*!
69    * \brief Return a name of a field support on all elements
70    */
71   //================================================================================
72
73   string noProfileName( INTERP_KERNEL::NormalizedCellType type )
74   {
75     return "INTERP_KERNEL::NormalizedCellType_" + SauvUtilities::toString( type );
76   }
77
78   //================================================================================
79   /*!
80    * \brief Remove white spaces from the head and tail
81    */
82   //================================================================================
83
84   string cleanName( const string& theName )
85   {
86     string name = theName;
87     if ( !name.empty() )
88       {
89         // cut off leading white spaces
90         string::size_type firstChar = name.find_first_not_of(" \t");
91         if (firstChar < name.length())
92           {
93             name = name.substr(firstChar);
94           }
95         else
96           {
97             name = ""; // only whitespaces there - remove them
98           }
99         // cut off trailing white spaces
100         string::size_type lastChar = name.find_last_not_of(" \t");
101         if (lastChar < name.length())
102           name = name.substr(0, lastChar + 1);
103       }
104     return name;
105   }
106
107   //================================================================================
108   /*!
109    * \brief Converts MED long names into SAUVE short ones, returnes a healed long name
110    */
111   //================================================================================
112
113   string addName (map<string,int>& nameMap,
114                   map<string,int>& namePrefixesMap,
115                   const string&    theName,
116                   const int        index)
117   {
118     // Converts names like:
119     // MED:                       GIBI:     
120     //   TEMPERATURE_FLUIDE   ->    TEMPE001
121     //   TEMPERATURE_SOLIDE   ->    TEMPE002
122     //   PRESSION             ->    PRESSION
123     //   NU                   ->    NU      
124     //   VOLUM001             ->    VOLUM001
125     //   VOLUMOFOBJECT        ->    VOLUM003
126     //   VOLUM002             ->    VOLUM002
127     string healedName = cleanName(theName);
128     int ind = index;
129
130     if (!healedName.empty())
131       {
132         string name = healedName;
133         int len = name.length();
134         for (int i = 0; i < len; ++i)
135           name[i] = toupper(name[i]);
136
137         bool doResave = false; // only for tracing
138
139         // I. Save a short name as it is
140         if (len <= 8)
141           {
142             INFOS_MED("Save <" << theName << "> as <" << name << ">");
143
144             map<string,int>::iterator it = nameMap.find(name);
145             if (it != nameMap.end())
146               {
147                 // There is already such name in the map.
148
149                 // a. Replace in the map the old pair by the current one
150                 int old_ind = nameMap[name];
151                 nameMap[name] = ind;
152                 // b. Rebuild the old pair (which was in the map,
153                 //    it seems to be built automatically by step II)
154                 ind = old_ind;
155                 // continue with step II
156                 doResave = true; // only for tracing
157               }
158             else
159               {
160                 // Save in the map
161                 nameMap.insert(make_pair(name, ind));
162
163                 // Update loc_index for this name (if last free characters represents a number)
164                 // to avoid conflicts with long names, same in first 5 characters
165                 if (len == 8)
166                   {
167                     int new_loc_index = atoi(name.c_str() + 5);
168                     if (new_loc_index > 0)
169                       {
170                         // prefix
171                         string str = name.substr(0,5);
172                         if (namePrefixesMap.find(str) != namePrefixesMap.end())
173                           {
174                             int old_loc_index = namePrefixesMap[str];
175                             if (new_loc_index < old_loc_index) new_loc_index = old_loc_index;
176                           }
177                         namePrefixesMap[str] = new_loc_index;
178                       }
179                   }
180                 return healedName;
181               }
182           } // if (len <= 8)
183
184         // II. Cut long name and add a numeric suffix
185
186         // first 5 or less characters of the name
187         if (len > 5) name = name.substr(0,5);
188
189         // numeric suffix
190         map<string,int>::iterator name2ind = namePrefixesMap.insert( make_pair( name, 0 )).first;
191         string numSuffix = SauvUtilities::toString( ++(name2ind->second) );
192
193         if ( numSuffix.size() + name.size() > 8 )
194           THROW_IK_EXCEPTION("Can't write not unique name: " << healedName);
195
196         if ( numSuffix.size() < 3 )
197           numSuffix.insert( 0, 3 - numSuffix.size(), '0' );
198
199         name += numSuffix;
200         nameMap.insert(make_pair(name, ind));
201
202         if (doResave)
203           {
204             INFOS_MED("Resave previous <" << healedName << "> as <" << name << ">");
205           }
206         else
207           {
208             INFOS_MED("Save <" << theName << "> as <" << name << ">");
209           }
210       }
211     return healedName;
212   }
213 }
214
215 //================================================================================
216 /*!
217  * \brief Creates SauvWriter
218  */
219 //================================================================================
220
221 SauvWriter* SauvWriter::New()
222 {
223   return new SauvWriter;
224 }
225
226 //================================================================================
227 /*!
228  * \brief Fills own DS by MEDFileData
229  */
230 //================================================================================
231
232 void SauvWriter::setMEDFileDS(const MEDFileData* medData,
233                               unsigned           meshIndex)
234 {
235   if ( !medData) THROW_IK_EXCEPTION("NULL MEDFileData");
236
237   MEDFileMeshes * meshes = medData->getMeshes();
238   MEDFileFields * fields = medData->getFields();
239   if ( !meshes) THROW_IK_EXCEPTION("No meshes in MEDFileData");
240
241   _fileMesh = meshes->getMeshAtPos( meshIndex );
242   _fileMesh->incrRef();
243
244   if ( fields )
245     for ( int i = 0; i < fields->getNumberOfFields(); ++i )
246       {
247         MEDFileFieldMultiTS * f = fields->getFieldAtPos(i);
248         if ( f->getMeshName() == _fileMesh->getName() )
249           {
250             vector< vector<TypeOfField> > fTypes = f->getTypesOfFieldAvailable();
251             if ( fTypes[0].size() == 1 && fTypes[0][0] == ON_NODES )
252               _nodeFields.push_back( f );
253             else
254               _cellFields.push_back( f );
255           }
256       }
257 }
258
259 //================================================================================
260 /*!
261  * \brief Adds a submesh
262  */
263 //================================================================================
264
265 SauvWriter::SubMesh* SauvWriter::addSubMesh(const std::string& name, int dimRelExt)
266 {
267   if ( _subs.capacity() < _subs.size() + 1 )
268     THROW_IK_EXCEPTION("SauvWriter: INTERNAL error, wrong evaluation of nb of sub-meshes");
269   _subs.resize( _subs.size() + 1 );
270   SubMesh& sm = _subs.back();
271   sm._name = name;
272   sm._dimRelExt = dimRelExt;
273   return &sm;
274 }
275 //================================================================================
276 /*!
277  * \brief Returns nb of cell types
278  */
279 //================================================================================
280
281 int SauvWriter::SubMesh::nbTypes() const
282 {
283   int nb = 0;
284   for (int i = 0; i < cellIDsByTypeSize(); ++i )
285     nb += int( !_cellIDsByType[i].empty() );
286   return nb;
287 }
288
289 //================================================================================
290 /*!
291  * \brief Fill _subs
292  */
293 //================================================================================
294
295 void SauvWriter::fillSubMeshes( int& nbSauvObjects, map<string,int>& nameNbMap )
296 {
297   // evaluate nb of _subs in order to avoid re-allocation of _subs
298   int nbSubs = 1; // for the very mesh
299   nbSubs += _fileMesh->getFamilyInfo().size() + 4;  // + 4 zero families (for each dimRelExt)
300   nbSubs += _fileMesh->getGroupInfo().size();
301   nbSubs += evaluateNbProfileSubMeshes();
302   _subs.clear();
303   _subs.reserve( nbSubs );
304
305   fillFamilySubMeshes();
306   fillGroupSubMeshes();
307   fillProfileSubMeshes();
308
309   // fill names of SubMesh'es and count nb of sauv sub-meshes they will be stored into
310   nbSauvObjects = 0;
311   map<string,int> namePrefixMap;
312   for ( size_t i = 0; i < _subs.size(); ++i )
313     {
314       SubMesh& sm = _subs[i];
315
316       sm._nbSauvObjects = 0;
317       if ( sm._subs.empty() )
318         {
319           sm._nbSauvObjects = sm.nbTypes();
320         }
321       else
322         {
323           sm._nbSauvObjects = 1;
324         }
325
326       sm._id = nbSauvObjects+1;
327       nbSauvObjects += sm._nbSauvObjects;
328
329       if ( sm._nbSauvObjects )
330         sm._name = addName( nameNbMap, namePrefixMap, sm._name, sm._id );
331
332       if ( sm._nbSauvObjects && !sm._name.empty() )
333         {
334           nameGIBItoMED aMEDName;
335           aMEDName.gibi_pile = PILE_SOUS_MAILLAGE;
336           aMEDName.gibi_id   = sm._id;
337           aMEDName.med_name  = sm._name;
338           _longNames[ LN_MAIL ].push_back(aMEDName);
339         }
340     }
341 }
342
343 //================================================================================
344 /*!
345  * \brief fill sub-meshes of families
346  */
347 //================================================================================
348
349 void SauvWriter::fillFamilySubMeshes()
350 {
351   SubMesh* nilSm = (SubMesh*) 0;
352   std::vector<int> dims = _fileMesh->getNonEmptyLevelsExt();
353   for ( size_t iDim = 0; iDim < dims.size(); ++iDim )
354     {
355       int dimRelExt = dims[ iDim ];
356       MEDCouplingAutoRefCountObjectPtr< MEDCouplingMesh > mesh = _fileMesh->getGenMeshAtLevel(dimRelExt);
357       const DataArrayInt * famIds = _fileMesh->getFamilyFieldAtLevel(dimRelExt);
358       if ( !famIds ) continue;
359
360       int curFamID = 0;
361       SubMesh* curSubMesh = addSubMesh( "", dimRelExt ); // submesh of zero family
362       _famIDs2Sub[0] = curSubMesh;
363       int sub0Index = _subs.size()-1;
364
365       const int * famID = famIds->begin(), * famIDEnd = famIds->end();
366       for ( int cellID = 0; famID < famIDEnd; ++famID, cellID++ )
367         {
368           if ( *famID != curFamID )
369             {
370               curFamID = *famID;
371               map< int, SubMesh* >::iterator f2s = _famIDs2Sub.insert( make_pair( curFamID, nilSm )).first;
372               if ( !f2s->second )
373                 f2s->second = addSubMesh( "", dimRelExt ); // no names for families
374               curSubMesh = f2s->second;
375             }
376           INTERP_KERNEL::NormalizedCellType cellType =
377             dimRelExt == 1 ? INTERP_KERNEL::NORM_POINT1 : mesh->getTypeOfCell( cellID );
378           curSubMesh->_cellIDsByType[ cellType ].push_back( cellID );
379         }
380
381       if ( dimRelExt == 1 )
382         {
383           // clear submesh of nodal zero family
384           _famIDs2Sub[0]->_cellIDsByType[ INTERP_KERNEL::NORM_POINT1 ].clear();
385         }
386       else if ( dimRelExt == 0 )
387         {
388           // make a submesh including all cells
389           if ( sub0Index == (int)(_subs.size()-1) )
390             {
391               _famIDs2Sub[0]->_name = _fileMesh->getName(); // there is the zero family only
392             }
393           else
394             {
395               curSubMesh = addSubMesh( _fileMesh->getName(), dimRelExt );
396               if ( _famIDs2Sub[0]->nbTypes() == 0 )
397                 sub0Index++; // skip an empty zero family
398               for ( size_t i = sub0Index; i < _subs.size()-1; ++i )
399                 curSubMesh->_subs.push_back( & _subs[i] );
400             }
401         }
402     }
403 }
404
405 //================================================================================
406 /*!
407  * \brief fill sub-mehses of groups
408  */
409 //================================================================================
410
411 void SauvWriter::fillGroupSubMeshes()
412 {
413   const map<string, vector<string> >& grpFams = _fileMesh->getGroupInfo();
414   map<string, vector<string> >::const_iterator g2ff = grpFams.begin();
415   for ( ; g2ff != grpFams.end(); ++g2ff )
416     {
417       const string&        groupName = g2ff->first;
418       const vector<string>& famNames = g2ff->second;
419       if ( famNames.empty() ) continue;
420       std::vector<SubMesh*> famSubMeshes( famNames.size() );
421       for ( size_t i = 0; i < famNames.size(); ++i )
422         {
423           int famID = _fileMesh->getFamilyId( famNames[i].c_str() );
424           map< int, SubMesh* >::iterator i2f = _famIDs2Sub.find( famID );
425           if ( i2f == _famIDs2Sub.end() )
426             THROW_IK_EXCEPTION("SauvWriter::fillGroupSubMeshes(): unknown family ID: " << famID);
427           famSubMeshes[ i ] = i2f->second;
428         }
429       SubMesh* grpSubMesh = addSubMesh( groupName, famSubMeshes[0]->_dimRelExt );
430       grpSubMesh->_subs.swap( famSubMeshes );
431     }
432 }
433
434 //================================================================================
435 /*!
436  * \brief fill sub-mehses of profiles
437  */
438 //================================================================================
439
440 void SauvWriter::fillProfileSubMeshes()
441 {
442   _profile2Sub.clear();
443   SubMesh* nilSm = (SubMesh*) 0;
444   for ( int isOnNodes = 0; isOnNodes < 2; ++isOnNodes )
445     {
446       vector< MEDCouplingAutoRefCountObjectPtr< MEDFileFieldMultiTS > >
447         fields = isOnNodes ? _nodeFields : _cellFields;
448       for ( size_t i = 0; i < fields.size(); ++i )
449         {
450           vector< pair<int,int> > iters = fields[i]->getIterations();
451
452           vector<INTERP_KERNEL::NormalizedCellType> types;
453           vector< vector<TypeOfField> > typesF;
454           vector< vector<string> > pfls, locs;
455           fields[i]->getFieldSplitedByType( iters[0].first, iters[0].second,
456                                             _fileMesh->getName(), types, typesF, pfls, locs);
457           int dimRelExt;
458           for ( size_t iType = 0; iType < types.size(); ++iType )
459             {
460               if ( types[iType] == INTERP_KERNEL::NORM_ERROR )
461                 dimRelExt = 1; // on nodes
462               else
463                 dimRelExt = getDimension( types[iType] ) - _fileMesh->getMeshDimension();
464               for ( size_t iPfl = 0; iPfl < pfls[iType].size(); ++iPfl )
465                 {
466                   bool isOnAll = pfls[iType][iPfl].empty();
467                   if ( isOnAll ) pfls[iType][iPfl] = noProfileName( types[iType] );
468                   map< string, SubMesh* >::iterator pfl2sm =
469                     _profile2Sub.insert( make_pair( pfls[iType][iPfl], nilSm )).first;
470                   if ( !pfl2sm->second )
471                     {
472                       SubMesh* sm = pfl2sm->second = addSubMesh( "", dimRelExt ); // no names for profiles
473                       const DataArrayInt * pfl = isOnAll ? 0 : fields[i]->getProfile( pfls[iType][iPfl].c_str() );
474                       makeProfileIDs( sm, types[iType], pfl );
475                     }
476                 }
477             }
478         }
479     }
480 }
481
482 //================================================================================
483 /*!
484  * \brief Return max possible nb of sub-meshes to decsribe field supports
485  */
486 //================================================================================
487
488 int SauvWriter::evaluateNbProfileSubMeshes() const
489 {
490   int nb = 0;
491   for ( size_t i = 0; i < _nodeFields.size(); ++i )
492     nb += 1 + _nodeFields[i]->getPflsReallyUsed().size();
493
494   for ( size_t i = 0; i < _cellFields.size(); ++i )
495     {
496       nb += _cellFields[i]->getPflsReallyUsed().size();
497
498       vector< pair<int,int> > iters = _cellFields[i]->getIterations();
499
500       vector<INTERP_KERNEL::NormalizedCellType> types;
501       vector< vector<TypeOfField> > typesF;
502       vector< vector<string> > pfls, locs;
503       _cellFields[i]->getFieldSplitedByType( iters[0].first, iters[0].second,
504                                              _fileMesh->getName(), types, typesF, pfls, locs);
505       nb += 2 * types.size(); // x 2 - a type can be on nodes and on cells at the same time
506     }
507
508   return nb;
509 }
510
511 //================================================================================
512 /*!
513  * \brief Transorm a profile into ids of mesh elements
514  */
515 //================================================================================
516
517 void SauvWriter::makeProfileIDs( SubMesh*                          sm,
518                                  INTERP_KERNEL::NormalizedCellType type,
519                                  const DataArrayInt*               profile )
520 {
521   MEDCouplingAutoRefCountObjectPtr< MEDCouplingMesh >
522     mesh = _fileMesh->getGenMeshAtLevel(sm->_dimRelExt);
523   const MEDCouplingUMesh* uMesh = dynamic_cast< const MEDCouplingUMesh* > ((const MEDCouplingMesh*) mesh );
524
525   if ( sm->_dimRelExt == 1 ) type = INTERP_KERNEL::NORM_POINT1;
526   vector< int >& ids = sm->_cellIDsByType[ type ];
527
528   if ( sm->_dimRelExt == 1 || !uMesh )
529     {
530       // profile on nodes or mesh is CARTESIAN
531       if ( profile )
532         {
533           ids.assign( profile->begin(), profile->end() );
534         }
535       else // on all
536         {
537           ids.resize( sm->_dimRelExt == 1 ? mesh->getNumberOfNodes() : mesh->getNumberOfCells() );
538           for ( size_t i = 0; i < ids.size(); ++i )
539             ids[i]=i;
540         }
541     }
542   else
543     {
544       // profile on cells
545       vector<int> code(3);
546       code[0] = type;
547       if ( profile ) // on profile
548         {
549           code[1] = profile->getNumberOfTuples();
550           code[2] = 0;
551         }
552       else // on all cells
553         {
554           code[1] = mesh->getNumberOfCellsWithType( type );
555           code[2] = -1;
556         }
557       vector<const DataArrayInt *> idsPerType( 1, profile );
558       MEDCouplingAutoRefCountObjectPtr<DataArrayInt>
559         resIDs = uMesh->checkTypeConsistencyAndContig( code, idsPerType );
560       ids.assign( resIDs->begin(), resIDs->end() );
561     }
562 }
563
564 //================================================================================
565 /*!
566  * \brief Write its data into the SAUVE file
567  */
568 //================================================================================
569
570 void SauvWriter::write(const char* fileName)
571 {
572   std::fstream fileStream;
573   fileStream.open( fileName, ios::out);
574   if
575 #ifdef WIN32
576     ( !fileStream || !fileStream.is_open() )
577 #else
578     ( !fileStream || !fileStream.rdbuf()->is_open() )
579 #endif
580       THROW_IK_EXCEPTION("Can't open the file |"<<fileName<<"|");
581   _sauvFile = &fileStream;
582
583   _subs.clear();
584   _famIDs2Sub.clear();
585   _profile2Sub.clear();
586   _longNames[ LN_MAIL ].clear();
587   _longNames[ LN_CHAM ].clear();
588   _longNames[ LN_COMP ].clear();
589
590   map<string,int> fldNamePrefixMap;
591
592   writeFileHead();
593   writeSubMeshes();
594   writeNodes();
595   writeNodalFields(fldNamePrefixMap);
596   writeElemFields(fldNamePrefixMap);
597   writeLongNames();
598   writeLastRecord();
599
600   _sauvFile->close();
601 }
602 //================================================================================
603 /*!
604  * \brief Writes "ENREGISTREMENT DE TYPE" 4 and 7
605  */
606 //================================================================================
607
608 void SauvWriter::writeFileHead()
609 {
610   MEDCouplingAutoRefCountObjectPtr< MEDCouplingMesh > mesh = _fileMesh->getGenMeshAtLevel(0);
611
612   *_sauvFile
613     << " ENREGISTREMENT DE TYPE   4" << endl
614     << " NIVEAU  16 NIVEAU ERREUR   0 DIMENSION   " << mesh->getSpaceDimension() <<endl
615     << " DENSITE 0.00000E+00" << endl
616     << " ENREGISTREMENT DE TYPE   7" << endl
617     << " NOMBRE INFO CASTEM2000   8" <<endl
618     << " IFOUR  -1 NIFOUR   0 IFOMOD  -1 IECHO   1 IIMPI   0 IOSPI   0 ISOTYP   1" << endl
619     << " NSDPGE     0" << endl;
620 }
621
622 //================================================================================
623 /*!
624  * \brief Writes names of objects
625  */
626 //================================================================================
627
628 void SauvWriter::writeNames( const map<string,int>& nameNbMap )
629 {
630   if ( !nameNbMap.empty() )
631   {
632     // write names of objects
633     // * 8001       FORMAT(8(1X,A8))
634     TFieldCounter fcount( *_sauvFile, 8 );
635     *_sauvFile << left;
636     map<string,int>::const_iterator nameNbIt = nameNbMap.begin();
637     for ( ; nameNbIt != nameNbMap.end(); nameNbIt++, fcount++ )
638       *_sauvFile << " " << setw(8) << nameNbIt->first;
639     fcount.stop();
640     *_sauvFile << right;
641
642     // write IDs of named objects in the pile
643     // *  8000 FORMAT(10I8)
644     nameNbIt = nameNbMap.begin();
645     for ( fcount.init(10); nameNbIt != nameNbMap.end(); nameNbIt++, fcount++ )
646       *_sauvFile << setw(8) << nameNbIt->second;
647   }
648 }
649
650 //================================================================================
651 /*!
652  * \brief Writes "PILE NUMERO   1"
653  */
654 //================================================================================
655
656 void SauvWriter::writeSubMeshes()
657 {
658   int nbSauvObjects;
659   map<string,int> nameNbMap;
660   fillSubMeshes( nbSauvObjects, nameNbMap );
661
662   // * 800   FORMAT (' ENREGISTREMENT DE TYPE', I4)
663   *_sauvFile << " ENREGISTREMENT DE TYPE   2" << endl;
664   // * 801     FORMAT(' PILE NUMERO',I4,'NBRE OBJETS NOMMES',I8,'NBRE OBJETS',I8)
665   *_sauvFile << " PILE NUMERO   1NBRE OBJETS NOMMES" << setw(8) << nameNbMap.size() <<
666     "NBRE OBJETS" << setw(8) << nbSauvObjects <<endl;
667
668   writeNames( nameNbMap );
669
670   TFieldCounter fcount( *_sauvFile, 10 ); // 10 intergers per line
671
672   for ( size_t iSub = 0; iSub < _subs.size(); ++iSub )
673     {
674       SubMesh& sm = _subs[iSub];
675       if ( sm._nbSauvObjects < 1 ) continue;
676
677       // The first record of each sub-mesh writes
678       // - type of cells; zero means a compound object whose the 2nd record enumerates its components
679       // - number of components of a compound object
680       // - number of references; each reference means a "pointer" to this sub-mesh
681       // - number of nodes per cell
682       // - number of cells
683
684       if ( !sm._subs.empty() )
685         {
686           writeCompoundSubMesh(iSub);
687         }
688       else
689         {
690           // write each sub-type as a SAUV sub-mesh
691           MEDCouplingAutoRefCountObjectPtr< MEDCouplingMesh >
692             mesh = _fileMesh->getGenMeshAtLevel( sm._dimRelExt );
693           MEDCouplingAutoRefCountObjectPtr< MEDCouplingUMesh>
694             umesh = mesh->buildUnstructured();
695
696           for ( int iType=0; iType < sm.cellIDsByTypeSize(); ++iType )
697             {
698               const vector<int>& cellIDs = sm._cellIDsByType[iType];
699               if ( cellIDs.empty() ) continue;
700
701               INTERP_KERNEL::NormalizedCellType
702                 cellType = INTERP_KERNEL::NormalizedCellType( iType );
703               const INTERP_KERNEL::CellModel &
704                 cell = INTERP_KERNEL::CellModel::GetCellModel( cellType );
705               int castemType       = SauvUtilities::med2gibiGeom( cellType );
706               unsigned nbElemNodes = cell.getNumberOfNodes();
707               unsigned nbElems     = cellIDs.size();
708
709               *_sauvFile << setw(8) << castemType
710                         << zeroI8
711                         << zeroI8
712                         << setw(8) << nbElemNodes
713                         << setw(8) << nbElems << endl;
714
715               // write color of each element
716               // * 8000 FORMAT(10I8)
717               for ( size_t i = 0; i < nbElems; ++i, fcount++ ) *_sauvFile << zeroI8;
718               fcount.stop();
719
720               // write connectivity
721               // gibi IDs are in FORTRAN mode while MEDCoupling IDs are in C mode
722               if ( sm._dimRelExt == 1 ) // nodes
723                 {
724                   for ( size_t i = 0; i < nbElems; ++i, fcount++ )
725                     *_sauvFile << setw(8) << ( cellIDs[i] + 1 );
726                 }
727               else
728                 {
729                   // indices to transform MED connectivity to GIBI one
730                   const int * toMedConn = getGibi2MedQuadraticInterlace( cellType );
731
732                   vector< int > cellConn( nbElemNodes ), transformedConn( nbElemNodes );
733                   for ( size_t i = 0; i < nbElems; ++i )
734                     {
735                       cellConn.clear();
736                       umesh->getNodeIdsOfCell( cellIDs[i], cellConn );
737                       if ( toMedConn )
738                         {
739                           for ( unsigned j = 0; j < nbElemNodes; ++j )
740                             transformedConn[ toMedConn[ j ]] = cellConn[ j ];
741                           cellConn.swap( transformedConn );
742                         }
743                       for ( unsigned j = 0; j < nbElemNodes; ++j, fcount++ )
744                         *_sauvFile << setw(8) << ( cellConn[j] + 1 );
745                     }
746                 }
747               fcount.stop();
748
749             } // loop on cell types
750         } // not a compound object
751     } // loop on sub-meshes
752 }
753
754 //================================================================================
755 /*!
756  * \brief Writes a sum-mesh composed of other sum-meshes
757  * This submesh corresponds to a med mesh or group composed of families
758  */
759 //================================================================================
760
761 void SauvWriter::writeCompoundSubMesh(int iSub)
762 {
763   SubMesh& sm = _subs[iSub];
764   if ( sm._nbSauvObjects < 1 || sm._subs.empty()) return;
765
766   vector< int > subIDs;
767   for ( size_t i = 0; i < sm._subs.size(); ++i ) // loop on sub-meshes of families
768     for ( int j = 0; j < sm._subs[i]->_nbSauvObjects; ++j )
769       subIDs.push_back( sm._subs[i]->_id + j );
770       
771   *_sauvFile << zeroI8
772              << setw(8) << subIDs.size()
773              << zeroI8
774              << zeroI8
775              << zeroI8 << endl;
776
777   TFieldCounter fcount( *_sauvFile, 10 ); // 10 intergers per line
778   for ( size_t i = 0; i < subIDs.size(); ++i, fcount++ )
779     *_sauvFile << setw(8) << subIDs[i];
780 }
781
782 //================================================================================
783 /*!
784  * \brief Write piles relating to nodes
785  */
786 //================================================================================
787
788 void SauvWriter::writeNodes()
789 {
790   MEDCouplingAutoRefCountObjectPtr< MEDCouplingMesh > mesh = _fileMesh->getGenMeshAtLevel( 1 );
791   MEDCouplingAutoRefCountObjectPtr< MEDCouplingUMesh > umesh = mesh->buildUnstructured();
792
793   // write the index connecting nodes with their coodrinates
794
795   const int nbNodes = umesh->getNumberOfNodes();
796   *_sauvFile << " ENREGISTREMENT DE TYPE   2" << endl
797              << " PILE NUMERO  32NBRE OBJETS NOMMES       0NBRE OBJETS" << setw(8) << nbNodes << endl;
798   *_sauvFile << setw(8) << nbNodes << endl;
799   //
800   TFieldCounter fcount( *_sauvFile, 10 );// * 8000 FORMAT(10I8)
801   for ( int i = 0; i < nbNodes; ++i, fcount++ )
802     *_sauvFile << setw(8) << i + 1; 
803   fcount.stop();
804
805   // write coordinates and density of nodes
806
807   *_sauvFile << " ENREGISTREMENT DE TYPE   2" << endl;
808   *_sauvFile << " PILE NUMERO  33NBRE OBJETS NOMMES       0NBRE OBJETS       1" << endl;
809   // 
810   const int dim = umesh->getSpaceDimension();
811   const int nbValues = nbNodes * ( dim + 1 );
812   *_sauvFile << setw(8) << nbValues << endl;
813
814   // * 8003   FORMAT(1P,3E22.14)
815   const char* density = "  0.00000000000000E+00";
816   fcount.init(3);
817   _sauvFile->precision(14);
818   _sauvFile->setf( ios_base::scientific, ios_base::floatfield );
819   _sauvFile->setf( ios_base::uppercase );
820   MEDCouplingAutoRefCountObjectPtr< DataArrayDouble> coordArray = umesh->getCoordinatesAndOwner();
821   const double precision = 1.e-99; // PAL12077
822   for ( int i = 0; i < nbNodes; ++i)
823   {
824     for ( int j = 0; j < dim; ++j, fcount++ )
825       {
826         double coo = coordArray->getIJ( i, j );
827         bool  zero = ( -precision < coo && coo < precision );
828         *_sauvFile << setw(22) << ( zero ? 0.0 : coo );
829       }
830     *_sauvFile << density;
831     fcount++;
832   }
833 }
834
835 //================================================================================
836 /*!
837  * \brief Store correspondence between GIBI (short) and MED (long) names
838  *
839  * IMP 0020434: mapping GIBI names to MED names
840  * Store correspondence between GIBI and MED names as one PILE_STRINGS and one
841  * PILE_TABLES (in three tables: MED_MAIL, MED_CHAM and MED_COMP)
842  */
843 //================================================================================
844
845 void SauvWriter::writeLongNames()
846 {
847   int nbTables =
848     3 - _longNames[ LN_MAIL ].empty() - _longNames[ LN_CHAM ].empty() - _longNames[ LN_COMP ].empty();
849   if (nbTables == 0) return;
850
851   // ---------------------
852   // Write the TABLE pile
853   // ---------------------
854
855   *_sauvFile << " ENREGISTREMENT DE TYPE   2" << endl
856         << " PILE NUMERO  10NBRE OBJETS NOMMES" << setw(8) << nbTables
857         << "NBRE OBJETS" << setw(8) << nbTables << endl;
858   // table names
859   if (!_longNames[ LN_MAIL ].empty()) *_sauvFile << " MED_MAIL";
860   if (!_longNames[ LN_CHAM ].empty()) *_sauvFile << " MED_CHAM";
861   if (!_longNames[ LN_COMP ].empty()) *_sauvFile << " MED_COMP";
862   *_sauvFile << endl;
863   // table indices
864   for ( int i = 0; i < nbTables; ++i ) *_sauvFile << setw(8) << i+1;
865   *_sauvFile << endl;
866
867   string theWholeString; // concatenated long names
868   vector<int> theOffsets;
869   int iStr = 1;
870   TFieldCounter fcount (*_sauvFile, 10);
871
872   for ( int iTbl = 0; iTbl < LN_NB; ++iTbl )
873     {
874       vector<nameGIBItoMED>& longNames = _longNames[ iTbl ];
875       if ( longNames.empty() ) continue;
876       const bool isComp = ( iTbl == LN_COMP);
877
878       // to assure unique MED names
879       set<string> medUniqueNames;
880
881       *_sauvFile << setw(8) << longNames.size()*4 << endl; // Nb of table values
882
883       vector<nameGIBItoMED>::iterator itGIBItoMED = longNames.begin();
884       for (; itGIBItoMED != longNames.end(); itGIBItoMED++, iStr++)
885         {
886           // PILE of i-th key (med name)
887           *_sauvFile << setw(8) << PILE_STRINGS;
888           fcount++;
889           // ID of i-th key (med name)
890           *_sauvFile << setw(8) << iStr;
891           fcount++;
892           // PILE of i-th value (gibi name)
893           *_sauvFile << setw(8) << itGIBItoMED->gibi_pile;
894           fcount++;
895           // ID of i-th value (gibi name)
896           *_sauvFile << setw(8) << ( isComp ? ++iStr : itGIBItoMED->gibi_id );
897           fcount++;
898
899           // add a MED name to the string (while making it be unique for sub-meshes and fields)
900           string aMedName = itGIBItoMED->med_name;
901           if ( !isComp )
902             for (int ind = 1; !medUniqueNames.insert(aMedName).second; ++ind )
903               aMedName = itGIBItoMED->med_name + "_" + SauvUtilities::toString( ind );
904           theWholeString += aMedName;
905
906           // add an offset
907           theOffsets.push_back( theWholeString.size() );
908           if ( isComp )
909             {
910               theWholeString += itGIBItoMED->gibi_name;
911               theOffsets.push_back( theWholeString.size() );
912             }
913         }
914       fcount.stop();
915     }
916
917   // ----------------------
918   // Write the STRING pile
919   // ----------------------
920
921   const int nbNames = theOffsets.size();
922   *_sauvFile << " ENREGISTREMENT DE TYPE   2" << endl
923         << " PILE NUMERO  27NBRE OBJETS NOMMES" << zeroI8 << "NBRE OBJETS" << setw(8) << nbNames << endl
924         << setw(8) << theWholeString.length() << setw(8) << nbNames << endl;
925
926   // write the whole string
927   const int fixedLength = 71;
928   for ( string::size_type aPos = 0; aPos < theWholeString.length(); aPos += fixedLength)
929     *_sauvFile << setw(72) << theWholeString.substr(aPos, fixedLength) << endl;
930
931   // write the offsets
932   for ( size_t i = 0; i < theOffsets.size(); ++i, fcount++ )
933     *_sauvFile << setw(8) << theOffsets[i];
934 }
935
936 //================================================================================
937 /*!
938  * \brief Write beginning of field record
939  */
940 //================================================================================
941
942 void SauvWriter::writeFieldNames( const bool                 isNodal,
943                                   std::map<std::string,int>& fldNamePrefixMap)
944 {
945   vector< MEDCouplingAutoRefCountObjectPtr< MEDFileFieldMultiTS > >&
946     flds = isNodal ? _nodeFields : _cellFields;
947   map<string,int> nameNbMap;
948
949   for ( size_t iF = 0; iF < flds.size(); ++iF )
950     {
951       string name = addName( nameNbMap, fldNamePrefixMap, flds[iF]->getName(), iF+1 );
952       nameGIBItoMED aMEDName;
953       aMEDName.gibi_pile = isNodal ? PILE_NODES_FIELD : PILE_FIELD;
954       aMEDName.gibi_id   = iF+1;
955       aMEDName.med_name  = name;
956       _longNames[ LN_CHAM ].push_back(aMEDName);
957     }
958
959   *_sauvFile << " ENREGISTREMENT DE TYPE   2" << endl
960              << ( isNodal ? " PILE NUMERO   2" : " PILE NUMERO  39")
961              << "NBRE OBJETS NOMMES" << setw(8) << nameNbMap.size()
962              << "NBRE OBJETS"        << setw(8) << flds.size() << endl;
963   writeNames( nameNbMap );
964 }
965
966 //================================================================================
967 /*!
968  * \brief Make short names of field components
969  *
970  * IMP 0020434: mapping GIBI names to MED names
971  */
972 //================================================================================
973
974 void SauvWriter::makeCompNames(const string&         fieldName,
975                                const vector<string>& compInfo,
976                                map<string, string>&  mapMedToGibi)
977 {
978   for ( size_t i = 0; i < compInfo.size(); ++i )
979     mapMedToGibi[compInfo[i]] = cleanName( compInfo[i] );
980
981   int compIndex = 1;
982   map<string, string>::iterator namesIt = mapMedToGibi.begin();
983   for (; namesIt != mapMedToGibi.end(); namesIt++)
984     {
985       string & compGibiName = (*namesIt).second;
986       if (compGibiName.size() > 4) {
987         // use new name in form "CXXX", where "XXX" is a number
988         do
989           {
990             compGibiName = SauvUtilities::toString( compIndex++ );
991             if ( compGibiName.size() < 3 )
992               compGibiName.insert( 0, 3 - compGibiName.size(), '0' );
993             compGibiName = "C" + compGibiName;
994           }
995         while (mapMedToGibi.count(compGibiName) > 0); // real component name could be CXXX
996       }
997
998       string compMedName = fieldName + "." + namesIt->first;
999       nameGIBItoMED aMEDName;
1000       aMEDName.med_name  = compMedName;
1001       aMEDName.gibi_pile = PILE_STRINGS;
1002       aMEDName.gibi_name = compGibiName;
1003       _longNames[ LN_COMP ].push_back(aMEDName);
1004     }
1005 }
1006
1007 //================================================================================
1008 /*!
1009  * \brief Writes "PILE NUMERO   2": fields on nodes
1010  */
1011 //================================================================================
1012
1013 void SauvWriter::writeNodalFields(map<string,int>& fldNamePrefixMap)
1014 {
1015   writeFieldNames( /*isNodal=*/true, fldNamePrefixMap );
1016
1017   TFieldCounter fcount (*_sauvFile, 10);
1018
1019   // EXAMPLE ( with no values )
1020
1021   // (1)       4       7       2       1
1022   // (2)     -88       0       3     -89       0       1     -90       0       2     -91
1023   // (2)       0       1
1024   // (3) FX   FY   FZ   FZ   FX   FY   FLX
1025   // (4)       0       0       0       0       0       0       0
1026   // (5)           cree  par  muc pri
1027   // (6)
1028   // (7)       2
1029   for ( size_t iF = 0; iF < _nodeFields.size(); ++iF )
1030     {
1031       // (1) write nb subcomponents, nb components(total)
1032       vector< pair<int,int> >  iters = _nodeFields[iF]->getIterations();
1033       const vector<string>& compInfo = _nodeFields[iF]->getInfo();
1034       const int nbSub = iters.size();
1035       const int nbComp = compInfo.size();
1036       const int totalNbComp = nbSub * nbComp;
1037       *_sauvFile << setw(8) << nbSub
1038                  << setw(8) << totalNbComp
1039                  << setw(8) << -1         // IFOUR
1040                  << setw(8) << 0 << endl; // nb attributes
1041
1042       // (2) for each sub-component (iteration)
1043       // write support, number of values and number of components
1044       fcount.init(10);
1045       vector< int > vals(3);
1046       for ( std::size_t iIt = 0; iIt < iters.size(); ++iIt )
1047         {
1048           pair<int,int> it = iters[iIt];
1049
1050           vector<INTERP_KERNEL::NormalizedCellType> types;
1051           vector< vector<TypeOfField> > typesF;
1052           vector< vector<string> > pfls, locs;
1053           vector< vector< std::pair<int,int> > > valsVec;
1054           valsVec=_nodeFields[iF]->getFieldSplitedByType( it.first, it.second, _fileMesh->getName(),
1055                                                           types, typesF, pfls, locs);
1056           // believe that there can be only one type in a nodal field,
1057           // so do not use a loop on types
1058           if ( pfls[0][0].empty() ) pfls[0][0] = noProfileName( types[0] );
1059           map< string, SubMesh* >::iterator pfl2Sub = _profile2Sub.find( pfls[0][0] );
1060           if ( pfl2Sub == _profile2Sub.end() )
1061             THROW_IK_EXCEPTION( "SauvWriter::writeNodalFields(): no sub-mesh for profile |"
1062                                 << pfls[0][0] << "|");
1063           vals[0] = -pfl2Sub->second->_id;
1064           vals[1] = (valsVec[0][0].second-valsVec[0][0].first);
1065           vals[2] = compInfo.size();
1066           for ( size_t i = 0; i < vals.size(); ++i, fcount++ )
1067             *_sauvFile << setw(8) << vals[i];
1068         }
1069       fcount.stop();
1070
1071       // (3) Write names of components
1072       map<string, string> mapMedToGibi;
1073       makeCompNames( _nodeFields[iF]->getName(), compInfo, mapMedToGibi );
1074       fcount.init(8);
1075       *_sauvFile << left;
1076       for ( std::size_t iIt = 0; iIt < iters.size(); ++iIt )
1077         for ( size_t i = 0; i < compInfo.size(); ++i, fcount++ )
1078           *_sauvFile << " "  << setw(4) << mapMedToGibi[compInfo[i]];
1079       *_sauvFile << right;
1080       fcount.stop();
1081
1082       // (4) nb harmonics
1083       fcount.init(10);
1084       for ( size_t i = 0; i < (std::size_t)totalNbComp; ++i, fcount++ )
1085         *_sauvFile << " "  << setw(8) << 0;
1086       fcount.stop();
1087
1088       string description = _nodeFields[iF]->getName();
1089       *_sauvFile << endl;                                         // (5) TYPE
1090       *_sauvFile << setw(72) << description.substr(0,71) << endl; // (6) TITRE
1091       //*_sauvFile << endl;                                         // (7) 0 attributes
1092
1093       // write values of each component
1094       fcount.init( 3 ); // 3 values per a line
1095       for ( std::size_t iIt = 0; iIt < iters.size(); ++iIt )
1096         {
1097           pair<int,int> it = iters[iIt];
1098
1099           vector<INTERP_KERNEL::NormalizedCellType> types;
1100           vector< vector<TypeOfField> > typesF;
1101           vector< vector<string> > pfls, locs;
1102           vector< vector< std::pair<int,int> > > valsVec;
1103           valsVec = _nodeFields[iF]->getFieldSplitedByType( it.first, it.second, _fileMesh->getName(),
1104                                                             types, typesF, pfls, locs);
1105           // believe that there can be only one type in a nodal field,
1106           // so do not perform a loop on types
1107           const DataArrayDouble* valsArray = _nodeFields[iF]->getUndergroundDataArray(it.first, it.second);
1108           for ( size_t j = 0; j < compInfo.size(); ++j )
1109             {
1110               for ( size_t i = valsVec[0][0].first; i < (std::size_t)valsVec[0][0].second; ++i, fcount++ )
1111                 *_sauvFile << setw(22) << valsArray->getIJ( i, j );
1112               fcount.stop();
1113             }
1114         }
1115     } // loop on fiels
1116 }
1117
1118 //================================================================================
1119 /*!
1120  * \brief Writes "PILE NUMERO  39": fields on cells
1121  */
1122 //================================================================================
1123
1124 void SauvWriter::writeElemFields(map<string,int>& fldNamePrefixMap)
1125 {
1126   writeFieldNames( /*isNodal=*/false, fldNamePrefixMap );
1127
1128   TFieldCounter fcount (*_sauvFile, 10);
1129
1130   // REAL EXAMPLE
1131
1132   // (1)        1       2       6      16
1133   // (2)                                                         CARACTERISTIQUES
1134   // (3)      -15  317773       4       0       0       0      -2       0       3
1135   // (4)             317581
1136   // (5)  0
1137   // (6)   317767  317761  317755  317815
1138   // (7)  YOUN     NU       H        SIGY
1139   // (8)  REAL*8            REAL*8            REAL*8            REAL*8
1140   // (9)        1       1       0       0
1141   // (10)  2.00000000000000E+05
1142   // (9)       1       1       0       0
1143   // (10)  3.30000000000000E-01
1144   // (9)       1       1       0       0
1145   // (10)  1.00000000000000E+04
1146   // (9)       6     706       0       0
1147   // (10)  1.00000000000000E+02  1.00000000000000E+02  1.00000000000000E+02
1148   // (10)  1.00000000000000E+02  1.00000000000000E+02  1.00000000000000E+02
1149   // (10)  ...
1150
1151   for ( size_t iF = 0; iF < _cellFields.size(); ++iF )
1152     {
1153       // count nb of sub-components
1154       int iSub, nbSub = 0;
1155       vector< pair<int,int> >  iters = _cellFields[iF]->getIterations();
1156       for ( std::size_t iIt = 0; iIt < iters.size(); ++iIt )
1157         {
1158           pair<int,int> it = iters[iIt];
1159
1160           vector<INTERP_KERNEL::NormalizedCellType> types;
1161           vector< vector<TypeOfField> > typesF;
1162           vector< vector<string> > pfls, locs;
1163           vector< vector< std::pair<int,int> > > valsVec;
1164           valsVec = _cellFields[iF]->getFieldSplitedByType( it.first, it.second, _fileMesh->getName(),
1165                                                             types, typesF, pfls, locs);
1166           for ( size_t i = 0; i < valsVec.size(); ++i )
1167             nbSub += valsVec[i].size();
1168         }
1169       // (1) write nb sub-components, title length
1170       *_sauvFile << setw(8) << nbSub
1171                  << setw(8) << -1 // whatever
1172                  << setw(8) << 6  // whatever
1173                  << setw(8) << 72 << endl; // title length
1174       // (2) title
1175       string title = _cellFields[iF]->getName();
1176       *_sauvFile << setw(72) << title.substr(0,71) << endl;
1177       *_sauvFile << setw(72) << " " << endl;
1178
1179       // (3) support, nb components
1180       vector<int> vals(9, 0);
1181       const vector<string>& compInfo = _cellFields[iF]->getInfo();
1182       vals[2] = compInfo.size();
1183       fcount.init(10);
1184       for ( std::size_t iIt = 0; iIt < iters.size(); ++iIt )
1185         {
1186           pair<int,int> it = iters[iIt];
1187
1188           vector<INTERP_KERNEL::NormalizedCellType> types;
1189           vector< vector<TypeOfField> > typesF;
1190           vector< vector<string> > pfls, locs;
1191           _cellFields[iF]->getFieldSplitedByType( it.first, it.second, _fileMesh->getName(),
1192                                                   types, typesF, pfls, locs);
1193           for ( size_t iType = 0; iType < pfls.size(); ++iType )
1194             for ( size_t iP = 0; iP < pfls[iType].size(); ++iP )
1195               {
1196                 if ( pfls[iType][iP].empty() ) pfls[iType][iP] = noProfileName( types[iType] );
1197                 map< string, SubMesh* >::iterator pfl2Sub = _profile2Sub.find( pfls[iType][iP] );
1198                 if ( pfl2Sub == _profile2Sub.end() )
1199                   THROW_IK_EXCEPTION( "SauvWriter::writeElemFields(): no sub-mesh for profile |"
1200                                       << pfls[iType][iP] << "|");
1201                 const int supportID = pfl2Sub->second->_id;
1202                 vals[0] = -supportID;
1203
1204                 for ( size_t i = 0; i < vals.size(); ++i, fcount++ )
1205                   *_sauvFile << setw(8) << vals[ i ];
1206               }
1207         }
1208       fcount.stop();
1209
1210       // (4) dummy strings
1211       for ( fcount.init(4), iSub = 0; iSub < nbSub; ++iSub, fcount++ )
1212         *_sauvFile << "                  ";
1213       fcount.stop();
1214
1215       // (5) dummy strings
1216       for ( fcount.init(8), iSub = 0; iSub < nbSub; ++iSub, fcount++ )
1217         *_sauvFile << "         ";
1218       fcount.stop();
1219
1220       // loop on sub-components of a field, each of which refers to
1221       // a certain support and has its own number of components
1222       for ( std::size_t iIt = 0; iIt < iters.size(); ++iIt )
1223         {
1224           pair<int,int> it = iters[iIt];
1225           writeElemTimeStamp( iF, it.first, it.second );
1226         }
1227     } // loop on cell fields
1228 }
1229
1230 //================================================================================
1231 /*!
1232  * \brief Write one elemental time stamp
1233  */
1234 //================================================================================
1235
1236 void SauvWriter::writeElemTimeStamp(int iF, int iter, int order)
1237 {
1238   // (6)   317767  317761  317755  317815
1239   // (7)  YOUN     NU       H        SIGY
1240   // (8)  REAL*8            REAL*8            REAL*8            REAL*8
1241   // (9)        1       1       0       0
1242   // (10)  2.00000000000000E+05
1243   // (9)       1       1       0       0
1244   // (10)  3.30000000000000E-01
1245   // (9)       1       1       0       0
1246   // (10)  1.00000000000000E+04
1247   // (9)       6     706       0       0
1248   // (10)  1.00000000000000E+02  1.00000000000000E+02  1.00000000000000E+02
1249   // (10)  1.00000000000000E+02  1.00000000000000E+02  1.00000000000000E+02
1250
1251   TFieldCounter fcount (*_sauvFile, 10);
1252
1253   vector<INTERP_KERNEL::NormalizedCellType> types;
1254   vector< vector<TypeOfField> > typesF;
1255   vector< vector<string> > pfls, locs;
1256   vector< vector< std::pair<int,int> > > valsVec;
1257   valsVec = _cellFields[iF]->getFieldSplitedByType( iter, order, _fileMesh->getName(),
1258                                                     types, typesF, pfls, locs);
1259   for ( size_t iType = 0; iType < pfls.size(); ++iType )
1260     for ( size_t iP = 0; iP < pfls[iType].size(); ++iP )
1261       {
1262         const vector<string>& compInfo = _cellFields[iF]->getInfo();
1263
1264         // (6) component addresses
1265         int iComp = 0, nbComp = compInfo.size();
1266         for ( fcount.init(10); iComp < nbComp; ++iComp, fcount++ )
1267           *_sauvFile << setw(8) << 777; // a good number
1268         fcount.stop();
1269
1270         // (7) component names
1271         map<string, string> mapMedToGibi;
1272         makeCompNames( _cellFields[iF]->getName(), compInfo, mapMedToGibi );
1273         *_sauvFile << left;
1274         for ( fcount.init(8), iComp = 0; iComp < nbComp; ++iComp, fcount++ )
1275           *_sauvFile << " "  << setw(8) << mapMedToGibi[compInfo[iComp]];
1276         fcount.stop();
1277
1278         // (8) component types
1279         for ( fcount.init(4), iComp = 0; iComp < nbComp; ++iComp, fcount++ )
1280           *_sauvFile << " "  << setw(17) << "REAL*8";
1281         fcount.stop();
1282         *_sauvFile << right;
1283
1284         // (9) nb values per element, nb of elements
1285         int nbPntPerCell = 1;
1286         if ( !locs[iType][iP].empty() )
1287           {
1288             int locID = _cellFields[iF]->getLocalizationId( locs[iType][iP].c_str() );
1289             nbPntPerCell = _cellFields[iF]->getNbOfGaussPtPerCell( locID );
1290           }
1291         else if ( typesF[iType][iP] == ON_GAUSS_NE )
1292           {
1293             nbPntPerCell = INTERP_KERNEL::CellModel::GetCellModel(types[iType]).getNumberOfNodes();
1294           }
1295
1296         // (10) values
1297         const std::pair<int,int>& bgEnd = valsVec[iType][iP];
1298         const DataArrayDouble* valArray = _cellFields[iF]->getUndergroundDataArray(iter, order);
1299         for ( iComp = 0; iComp < nbComp; ++iComp )
1300           {
1301             *_sauvFile << setw(8) << nbPntPerCell
1302                        << setw(8) << (bgEnd.second-bgEnd.first) / nbPntPerCell
1303                        << setw(8) << 0
1304                        << setw(8) << 0
1305                        << endl;
1306             fcount.init(3);
1307             for ( size_t i = bgEnd.first; i < (size_t) bgEnd.second; ++i, fcount++ )
1308               *_sauvFile << setw(22) << valArray->getIJ( i, iComp );
1309             fcount.stop();
1310           }
1311       }
1312 }
1313
1314 //================================================================================
1315 /*!
1316  * \brief Write the last record of the SAUV file
1317  */
1318 //================================================================================
1319
1320 void SauvWriter::writeLastRecord()
1321 {
1322   *_sauvFile << " ENREGISTREMENT DE TYPE   5" << endl;
1323   *_sauvFile << "LABEL AUTOMATIQUE :   1" << endl;
1324 }