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