1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // File : SauvWriter.cxx
20 // Created : Wed Aug 24 12:55:55 2011
21 // Author : Edward AGAPOV (eap)
23 #include "SauvWriter.hxx"
25 #include "InterpKernelException.hxx"
26 #include "MEDFileMesh.hxx"
27 #include "MEDFileField.hxx"
28 #include "MEDFileData.hxx"
29 #include "CellModel.hxx"
37 using namespace ParaMEDMEM;
38 using namespace SauvUtilities;
41 #define INFOS_MED(txt) cout << txt << endl;
45 const char* zeroI8 = " 0"; // FORMAT(I8)
47 // ============================================================
48 // the class writes endl to the file as soon as <limit> fields
49 // have been written after the last endl
50 // ============================================================
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(); }
67 //================================================================================
69 * \brief Return a name of a field support on all elements
71 //================================================================================
73 string noProfileName( INTERP_KERNEL::NormalizedCellType type )
75 return "INTERP_KERNEL::NormalizedCellType_" + SauvUtilities::toString( type );
78 //================================================================================
80 * \brief Remove white spaces from the head and tail
82 //================================================================================
84 string cleanName( const string& theName )
86 string name = theName;
89 // cut off leading white spaces
90 string::size_type firstChar = name.find_first_not_of(" \t");
91 if (firstChar < name.length())
93 name = name.substr(firstChar);
97 name = ""; // only whitespaces there - remove them
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);
107 //================================================================================
109 * \brief Converts MED long names into SAUVE short ones, returnes a healed long name
111 //================================================================================
113 string addName (map<string,int>& nameMap,
114 map<string,int>& namePrefixesMap,
115 const string& theName,
118 // Converts names like:
120 // TEMPERATURE_FLUIDE -> TEMPE001
121 // TEMPERATURE_SOLIDE -> TEMPE002
122 // PRESSION -> PRESSION
124 // VOLUM001 -> VOLUM001
125 // VOLUMOFOBJECT -> VOLUM003
126 // VOLUM002 -> VOLUM002
127 string healedName = cleanName(theName);
130 if (!healedName.empty())
132 string name = healedName;
133 int len = name.length();
134 for (int i = 0; i < len; ++i)
135 name[i] = toupper(name[i]);
137 bool doResave = false; // only for tracing
139 // I. Save a short name as it is
142 INFOS_MED("Save <" << theName << "> as <" << name << ">");
144 map<string,int>::iterator it = nameMap.find(name);
145 if (it != nameMap.end())
147 // There is already such name in the map.
149 // a. Replace in the map the old pair by the current one
150 int old_ind = nameMap[name];
152 // b. Rebuild the old pair (which was in the map,
153 // it seems to be built automatically by step II)
155 // continue with step II
156 doResave = true; // only for tracing
161 nameMap.insert(make_pair(name, ind));
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
167 int new_loc_index = atoi(name.c_str() + 5);
168 if (new_loc_index > 0)
171 string str = name.substr(0,5);
172 if (namePrefixesMap.find(str) != namePrefixesMap.end())
174 int old_loc_index = namePrefixesMap[str];
175 if (new_loc_index < old_loc_index) new_loc_index = old_loc_index;
177 namePrefixesMap[str] = new_loc_index;
184 // II. Cut long name and add a numeric suffix
186 // first 5 or less characters of the name
187 if (len > 5) name = name.substr(0,5);
190 map<string,int>::iterator name2ind = namePrefixesMap.insert( make_pair( name, 0 )).first;
191 string numSuffix = SauvUtilities::toString( ++(name2ind->second) );
193 if ( numSuffix.size() + name.size() > 8 )
194 THROW_IK_EXCEPTION("Can't write not unique name: " << healedName);
196 if ( numSuffix.size() < 3 )
197 numSuffix.insert( 0, 3 - numSuffix.size(), '0' );
200 nameMap.insert(make_pair(name, ind));
204 INFOS_MED("Resave previous <" << healedName << "> as <" << name << ">");
208 INFOS_MED("Save <" << theName << "> as <" << name << ">");
215 SauvWriter::SauvWriter():_cpy_grp_if_on_single_family(false)
219 SauvWriter* SauvWriter::New()
221 return new SauvWriter;
224 std::size_t SauvWriter::getHeapMemorySizeWithoutChildren() const
229 std::vector<const BigMemoryObject *> SauvWriter::getDirectChildren() const
231 return std::vector<const BigMemoryObject *>();
234 void SauvWriter::setCpyGrpIfOnASingleFamilyStatus(bool status)
236 _cpy_grp_if_on_single_family=status;
239 bool SauvWriter::getCpyGrpIfOnASingleFamilyStatus() const
241 return _cpy_grp_if_on_single_family;
244 //================================================================================
246 * \brief Fills own DS by MEDFileData
248 //================================================================================
250 void SauvWriter::setMEDFileDS(const MEDFileData* medData,
253 if ( !medData) THROW_IK_EXCEPTION("NULL MEDFileData");
255 MEDFileMeshes * meshes = medData->getMeshes();
256 MEDFileFields * fields = medData->getFields();
257 if ( !meshes) THROW_IK_EXCEPTION("No meshes in MEDFileData");
259 _fileMesh = meshes->getMeshAtPos( meshIndex );
260 _fileMesh->incrRef();
263 for ( int i = 0; i < fields->getNumberOfFields(); ++i )
265 MEDFileAnyTypeFieldMultiTS * fB = fields->getFieldAtPos(i);
266 MEDFileFieldMultiTS * f = dynamic_cast<MEDFileFieldMultiTS *>(fB);
268 continue;// fields on int32 not managed
269 if ( f->getMeshName() == _fileMesh->getName() )
271 vector< vector<TypeOfField> > fTypes = f->getTypesOfFieldAvailable();
272 if ( fTypes[0].size() == 1 && fTypes[0][0] == ON_NODES )
273 _nodeFields.push_back( f );
275 _cellFields.push_back( f );
280 //================================================================================
282 * \brief Adds a submesh
284 //================================================================================
286 SauvWriter::SubMesh* SauvWriter::addSubMesh(const std::string& name, int dimRelExt)
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();
293 sm._dimRelExt = dimRelExt;
296 //================================================================================
298 * \brief Returns nb of cell types
300 //================================================================================
302 int SauvWriter::SubMesh::nbTypes() const
305 for (int i = 0; i < cellIDsByTypeSize(); ++i )
306 nb += int( !_cellIDsByType[i].empty() );
310 //================================================================================
314 //================================================================================
316 void SauvWriter::fillSubMeshes( int& nbSauvObjects, map<string,int>& nameNbMap )
318 // evaluate nb of _subs in order to avoid re-allocation of _subs
319 int 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();
324 _subs.reserve( nbSubs );
326 fillFamilySubMeshes();
327 fillGroupSubMeshes();
328 fillProfileSubMeshes();
330 // fill names of SubMesh'es and count nb of sauv sub-meshes they will be stored into
332 map<string,int> namePrefixMap;
333 for ( size_t i = 0; i < _subs.size(); ++i )
335 SubMesh& sm = _subs[i];
337 sm._nbSauvObjects = 0;
338 if ( sm._subs.empty() )
340 sm._nbSauvObjects = sm.nbTypes();
344 sm._nbSauvObjects = 1;
347 sm._id = nbSauvObjects+1;
348 nbSauvObjects += sm._nbSauvObjects;
350 if ( sm._nbSauvObjects )
351 sm._name = addName( nameNbMap, namePrefixMap, sm._name, sm._id );
353 if ( sm._nbSauvObjects && !sm._name.empty() )
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);
364 //================================================================================
366 * \brief fill sub-meshes of families
368 //================================================================================
370 void SauvWriter::fillFamilySubMeshes()
372 SubMesh* nilSm = (SubMesh*) 0;
373 std::vector<int> dims = _fileMesh->getNonEmptyLevelsExt();
374 for ( size_t iDim = 0; iDim < dims.size(); ++iDim )
376 int dimRelExt = dims[ iDim ];
377 MEDCouplingAutoRefCountObjectPtr< MEDCouplingMesh > mesh = _fileMesh->getGenMeshAtLevel(dimRelExt);
378 const DataArrayInt * famIds = _fileMesh->getFamilyFieldAtLevel(dimRelExt);
379 if ( !famIds ) continue;
382 SubMesh* curSubMesh = addSubMesh( "", dimRelExt ); // submesh of zero family
383 _famIDs2Sub[0] = curSubMesh;
384 int sub0Index = _subs.size()-1;
386 const int * famID = famIds->begin(), * famIDEnd = famIds->end();
387 for ( int cellID = 0; famID < famIDEnd; ++famID, cellID++ )
389 if ( *famID != curFamID )
392 map< int, SubMesh* >::iterator f2s = _famIDs2Sub.insert( make_pair( curFamID, nilSm )).first;
394 f2s->second = addSubMesh( "", dimRelExt ); // no names for families
395 curSubMesh = f2s->second;
397 INTERP_KERNEL::NormalizedCellType cellType =
398 dimRelExt == 1 ? INTERP_KERNEL::NORM_POINT1 : mesh->getTypeOfCell( cellID );
399 curSubMesh->_cellIDsByType[ cellType ].push_back( cellID );
402 if ( dimRelExt == 1 )
404 // clear submesh of nodal zero family
405 _famIDs2Sub[0]->_cellIDsByType[ INTERP_KERNEL::NORM_POINT1 ].clear();
407 else if ( dimRelExt == 0 )
409 // make a submesh including all cells
410 if ( sub0Index == (int)(_subs.size()-1) )
412 _famIDs2Sub[0]->_name = _fileMesh->getName(); // there is the zero family only
416 curSubMesh = addSubMesh( _fileMesh->getName(), dimRelExt );
417 if ( _famIDs2Sub[0]->nbTypes() == 0 )
418 sub0Index++; // skip an empty zero family
419 for ( size_t i = sub0Index; i < _subs.size()-1; ++i )
420 curSubMesh->_subs.push_back( & _subs[i] );
426 //================================================================================
428 * \brief fill sub-meshes of groups
430 //================================================================================
432 void SauvWriter::fillGroupSubMeshes()
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 )
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() );
443 for ( size_t i = 0; i < famNames.size(); ++i )
445 int famID = _fileMesh->getFamilyId( famNames[i].c_str() );
446 map< int, SubMesh* >::iterator i2f = _famIDs2Sub.find( famID );
447 if ( i2f != _famIDs2Sub.end() )
449 famSubMeshes[ k ] = i2f->second;
453 // if a family exists but has no element, no submesh has been found for this family
454 // => we have to resize famSubMeshes with the number of submeshes stored
455 if (k != famNames.size())
456 famSubMeshes.resize(k);
457 SubMesh* grpSubMesh = addSubMesh( groupName, famSubMeshes[0]->_dimRelExt );
458 if(!_cpy_grp_if_on_single_family)
459 grpSubMesh->_subs.swap( famSubMeshes );
462 /* If a group sub mesh consists of only one family, the group is written as
463 * a copy of this family.
464 * A mesh composed of only one submesh may cause an issue with some Gibi operators.*/
465 if (famSubMeshes.size() == 1)
467 for(int i = 0; i < famSubMeshes[0]->cellIDsByTypeSize() ; i++)
469 grpSubMesh->_cellIDsByType[i] = famSubMeshes[0]->_cellIDsByType[i];
473 grpSubMesh->_subs.swap( famSubMeshes );
479 //================================================================================
481 * \brief fill sub-meshes of profiles
483 //================================================================================
485 void SauvWriter::fillProfileSubMeshes()
487 _profile2Sub.clear();
488 SubMesh* nilSm = (SubMesh*) 0;
489 for ( int isOnNodes = 0; isOnNodes < 2; ++isOnNodes )
491 vector< MEDCouplingAutoRefCountObjectPtr< MEDFileFieldMultiTS > >
492 fields = isOnNodes ? _nodeFields : _cellFields;
493 for ( size_t i = 0; i < fields.size(); ++i )
495 vector< pair<int,int> > iters = fields[i]->getIterations();
497 vector<INTERP_KERNEL::NormalizedCellType> types;
498 vector< vector<TypeOfField> > typesF;
499 vector< vector<string> > pfls, locs;
500 fields[i]->getFieldSplitedByType( iters[0].first, iters[0].second,
501 _fileMesh->getName().c_str(), types, typesF, pfls, locs);
503 for ( size_t iType = 0; iType < types.size(); ++iType )
505 if ( types[iType] == INTERP_KERNEL::NORM_ERROR )
506 dimRelExt = 1; // on nodes
508 dimRelExt = getDimension( types[iType] ) - _fileMesh->getMeshDimension();
509 for ( size_t iPfl = 0; iPfl < pfls[iType].size(); ++iPfl )
511 bool isOnAll = pfls[iType][iPfl].empty();
512 if ( isOnAll ) pfls[iType][iPfl] = noProfileName( types[iType] );
513 map< string, SubMesh* >::iterator pfl2sm =
514 _profile2Sub.insert( make_pair( pfls[iType][iPfl], nilSm )).first;
515 if ( !pfl2sm->second )
517 SubMesh* sm = pfl2sm->second = addSubMesh( "", dimRelExt ); // no names for profiles
518 const DataArrayInt * pfl = isOnAll ? 0 : fields[i]->getProfile( pfls[iType][iPfl].c_str() );
519 makeProfileIDs( sm, types[iType], pfl );
527 //================================================================================
529 * \brief Return max possible nb of sub-meshes to decsribe field supports
531 //================================================================================
533 int SauvWriter::evaluateNbProfileSubMeshes() const
536 for ( size_t i = 0; i < _nodeFields.size(); ++i )
537 nb += 1 + _nodeFields[i]->getPflsReallyUsed().size();
539 for ( size_t i = 0; i < _cellFields.size(); ++i )
541 nb += _cellFields[i]->getPflsReallyUsed().size();
543 vector< pair<int,int> > iters = _cellFields[i]->getIterations();
545 vector<INTERP_KERNEL::NormalizedCellType> types;
546 vector< vector<TypeOfField> > typesF;
547 vector< vector<string> > pfls, locs;
548 _cellFields[i]->getFieldSplitedByType( iters[0].first, iters[0].second,
549 _fileMesh->getName().c_str(), types, typesF, pfls, locs);
550 nb += 2 * types.size(); // x 2 - a type can be on nodes and on cells at the same time
556 //================================================================================
558 * \brief Transorm a profile into ids of mesh elements
560 //================================================================================
562 void SauvWriter::makeProfileIDs( SubMesh* sm,
563 INTERP_KERNEL::NormalizedCellType type,
564 const DataArrayInt* profile )
566 MEDCouplingAutoRefCountObjectPtr< MEDCouplingMesh >
567 mesh = _fileMesh->getGenMeshAtLevel(sm->_dimRelExt);
568 const MEDCouplingUMesh* uMesh = dynamic_cast< const MEDCouplingUMesh* > ((const MEDCouplingMesh*) mesh );
570 if ( sm->_dimRelExt == 1 ) type = INTERP_KERNEL::NORM_POINT1;
571 vector< int >& ids = sm->_cellIDsByType[ type ];
573 if ( sm->_dimRelExt == 1 || !uMesh )
575 // profile on nodes or mesh is CARTESIAN
578 ids.assign( profile->begin(), profile->end() );
582 ids.resize( sm->_dimRelExt == 1 ? mesh->getNumberOfNodes() : mesh->getNumberOfCells() );
583 for ( size_t i = 0; i < ids.size(); ++i )
592 if ( profile ) // on profile
594 code[1] = profile->getNumberOfTuples();
599 code[1] = mesh->getNumberOfCellsWithType( type );
602 vector<const DataArrayInt *> idsPerType( 1, profile );
603 MEDCouplingAutoRefCountObjectPtr<DataArrayInt>
604 resIDs = uMesh->checkTypeConsistencyAndContig( code, idsPerType );
605 if (( const DataArrayInt *) resIDs )
607 ids.assign( resIDs->begin(), resIDs->end() );
609 else // mesh includes only one type
612 for ( ids.resize( nbE ); nbE; --nbE )
613 ids[ nbE-1 ] = nbE-1;
618 //================================================================================
620 * \brief Write its data into the SAUVE file
622 //================================================================================
624 void SauvWriter::write(const std::string& fileName)
626 std::fstream fileStream;
627 fileStream.open( fileName.c_str(), ios::out);
630 ( !fileStream || !fileStream.is_open() )
632 ( !fileStream || !fileStream.rdbuf()->is_open() )
634 THROW_IK_EXCEPTION("Can't open the file |"<<fileName<<"|");
635 _sauvFile = &fileStream;
639 _profile2Sub.clear();
640 _longNames[ LN_MAIL ].clear();
641 _longNames[ LN_CHAM ].clear();
642 _longNames[ LN_COMP ].clear();
644 map<string,int> fldNamePrefixMap;
649 writeNodalFields(fldNamePrefixMap);
650 writeElemFields(fldNamePrefixMap);
656 //================================================================================
658 * \brief Writes "ENREGISTREMENT DE TYPE" 4 and 7
660 //================================================================================
662 void SauvWriter::writeFileHead()
664 MEDCouplingAutoRefCountObjectPtr< MEDCouplingMesh > mesh = _fileMesh->getGenMeshAtLevel(0);
667 << " ENREGISTREMENT DE TYPE 4" << endl
668 << " NIVEAU 16 NIVEAU ERREUR 0 DIMENSION " << mesh->getSpaceDimension() <<endl
669 << " DENSITE 0.00000E+00" << endl
670 << " ENREGISTREMENT DE TYPE 7" << endl
671 << " NOMBRE INFO CASTEM2000 8" <<endl
672 << " IFOUR -1 NIFOUR 0 IFOMOD -1 IECHO 1 IIMPI 0 IOSPI 0 ISOTYP 1" << endl
673 << " NSDPGE 0" << endl;
676 //================================================================================
678 * \brief Writes names of objects
680 //================================================================================
682 void SauvWriter::writeNames( const map<string,int>& nameNbMap )
684 if ( !nameNbMap.empty() )
686 // write names of objects
687 // * 8001 FORMAT(8(1X,A8))
688 TFieldCounter fcount( *_sauvFile, 8 );
690 map<string,int>::const_iterator nameNbIt = nameNbMap.begin();
691 for ( ; nameNbIt != nameNbMap.end(); nameNbIt++, fcount++ )
692 *_sauvFile << " " << setw(8) << nameNbIt->first;
696 // write IDs of named objects in the pile
697 // * 8000 FORMAT(10I8)
698 nameNbIt = nameNbMap.begin();
699 for ( fcount.init(10); nameNbIt != nameNbMap.end(); nameNbIt++, fcount++ )
700 *_sauvFile << setw(8) << nameNbIt->second;
704 //================================================================================
706 * \brief Writes "PILE NUMERO 1"
708 //================================================================================
710 void SauvWriter::writeSubMeshes()
713 map<string,int> nameNbMap;
714 fillSubMeshes( nbSauvObjects, nameNbMap );
716 // * 800 FORMAT (' ENREGISTREMENT DE TYPE', I4)
717 *_sauvFile << " ENREGISTREMENT DE TYPE 2" << endl;
718 // * 801 FORMAT(' PILE NUMERO',I4,'NBRE OBJETS NOMMES',I8,'NBRE OBJETS',I8)
719 *_sauvFile << " PILE NUMERO 1NBRE OBJETS NOMMES" << setw(8) << nameNbMap.size() <<
720 "NBRE OBJETS" << setw(8) << nbSauvObjects <<endl;
722 writeNames( nameNbMap );
724 TFieldCounter fcount( *_sauvFile, 10 ); // 10 intergers per line
726 for ( size_t iSub = 0; iSub < _subs.size(); ++iSub )
728 SubMesh& sm = _subs[iSub];
729 if ( sm._nbSauvObjects < 1 ) continue;
731 // The first record of each sub-mesh writes
732 // - type of cells; zero means a compound object whose the 2nd record enumerates its components
733 // - number of components of a compound object
734 // - number of references; each reference means a "pointer" to this sub-mesh
735 // - number of nodes per cell
738 if ( !sm._subs.empty() )
740 writeCompoundSubMesh(iSub);
744 // write each sub-type as a SAUV sub-mesh
745 MEDCouplingAutoRefCountObjectPtr< MEDCouplingMesh >
746 mesh = _fileMesh->getGenMeshAtLevel( sm._dimRelExt );
747 MEDCouplingAutoRefCountObjectPtr< MEDCouplingUMesh>
748 umesh = mesh->buildUnstructured();
750 for ( int iType=0; iType < sm.cellIDsByTypeSize(); ++iType )
752 const vector<int>& cellIDs = sm._cellIDsByType[iType];
753 if ( cellIDs.empty() ) continue;
755 INTERP_KERNEL::NormalizedCellType
756 cellType = INTERP_KERNEL::NormalizedCellType( iType );
757 const INTERP_KERNEL::CellModel &
758 cell = INTERP_KERNEL::CellModel::GetCellModel( cellType );
759 int castemType = SauvUtilities::med2gibiGeom( cellType );
760 unsigned nbElemNodes = cell.getNumberOfNodes();
761 unsigned nbElems = cellIDs.size();
763 *_sauvFile << setw(8) << castemType
766 << setw(8) << nbElemNodes
767 << setw(8) << nbElems << endl;
769 // write color of each element
770 // * 8000 FORMAT(10I8)
771 for ( size_t i = 0; i < nbElems; ++i, fcount++ ) *_sauvFile << zeroI8;
774 // write connectivity
775 // gibi IDs are in FORTRAN mode while MEDCoupling IDs are in C mode
776 if ( sm._dimRelExt == 1 ) // nodes
778 for ( size_t i = 0; i < nbElems; ++i, fcount++ )
779 *_sauvFile << setw(8) << ( cellIDs[i] + 1 );
783 // indices to transform MED connectivity to GIBI one
784 const int * toMedConn = getGibi2MedQuadraticInterlace( cellType );
786 vector< int > cellConn( nbElemNodes ), transformedConn( nbElemNodes );
787 for ( size_t i = 0; i < nbElems; ++i )
790 umesh->getNodeIdsOfCell( cellIDs[i], cellConn );
793 for ( unsigned j = 0; j < nbElemNodes; ++j )
794 transformedConn[ toMedConn[ j ]] = cellConn[ j ];
795 cellConn.swap( transformedConn );
797 for ( unsigned j = 0; j < nbElemNodes; ++j, fcount++ )
798 *_sauvFile << setw(8) << ( cellConn[j] + 1 );
803 } // loop on cell types
804 } // not a compound object
805 } // loop on sub-meshes
808 //================================================================================
810 * \brief Writes a sum-mesh composed of other sum-meshes
811 * This submesh corresponds to a med mesh or group composed of families
813 //================================================================================
815 void SauvWriter::writeCompoundSubMesh(int iSub)
817 SubMesh& sm = _subs[iSub];
818 if ( sm._nbSauvObjects < 1 || sm._subs.empty()) return;
820 vector< int > subIDs;
821 for ( size_t i = 0; i < sm._subs.size(); ++i ) // loop on sub-meshes of families
822 for ( int j = 0; j < sm._subs[i]->_nbSauvObjects; ++j )
823 subIDs.push_back( sm._subs[i]->_id + j );
826 << setw(8) << subIDs.size()
831 TFieldCounter fcount( *_sauvFile, 10 ); // 10 intergers per line
832 for ( size_t i = 0; i < subIDs.size(); ++i, fcount++ )
833 *_sauvFile << setw(8) << subIDs[i];
836 //================================================================================
838 * \brief Write piles relating to nodes
840 //================================================================================
842 void SauvWriter::writeNodes()
844 MEDCouplingAutoRefCountObjectPtr< MEDCouplingMesh > mesh = _fileMesh->getGenMeshAtLevel( 1 );
845 MEDCouplingAutoRefCountObjectPtr< MEDCouplingUMesh > umesh = mesh->buildUnstructured();
847 // write the index connecting nodes with their coodrinates
849 const int nbNodes = umesh->getNumberOfNodes();
850 *_sauvFile << " ENREGISTREMENT DE TYPE 2" << endl
851 << " PILE NUMERO 32NBRE OBJETS NOMMES 0NBRE OBJETS" << setw(8) << nbNodes << endl;
852 *_sauvFile << setw(8) << nbNodes << endl;
854 TFieldCounter fcount( *_sauvFile, 10 );// * 8000 FORMAT(10I8)
855 for ( int i = 0; i < nbNodes; ++i, fcount++ )
856 *_sauvFile << setw(8) << i + 1;
859 // write coordinates and density of nodes
861 *_sauvFile << " ENREGISTREMENT DE TYPE 2" << endl;
862 *_sauvFile << " PILE NUMERO 33NBRE OBJETS NOMMES 0NBRE OBJETS 1" << endl;
864 const int dim = umesh->getSpaceDimension();
865 const int nbValues = nbNodes * ( dim + 1 );
866 *_sauvFile << setw(8) << nbValues << endl;
868 // * 8003 FORMAT(1P,3E22.14)
869 const char* density = " 0.00000000000000E+00";
871 _sauvFile->precision(14);
872 _sauvFile->setf( ios_base::scientific, ios_base::floatfield );
873 _sauvFile->setf( ios_base::uppercase );
874 MEDCouplingAutoRefCountObjectPtr< DataArrayDouble> coordArray = umesh->getCoordinatesAndOwner();
875 const double precision = 1.e-99; // PAL12077
876 for ( int i = 0; i < nbNodes; ++i)
878 for ( int j = 0; j < dim; ++j, fcount++ )
880 double coo = coordArray->getIJ( i, j );
881 bool zero = ( -precision < coo && coo < precision );
882 *_sauvFile << setw(22) << ( zero ? 0.0 : coo );
884 *_sauvFile << density;
889 //================================================================================
891 * \brief Store correspondence between GIBI (short) and MED (long) names
893 * IMP 0020434: mapping GIBI names to MED names
894 * Store correspondence between GIBI and MED names as one PILE_STRINGS and one
895 * PILE_TABLES (in three tables: MED_MAIL, MED_CHAM and MED_COMP)
897 //================================================================================
899 void SauvWriter::writeLongNames()
902 3 - _longNames[ LN_MAIL ].empty() - _longNames[ LN_CHAM ].empty() - _longNames[ LN_COMP ].empty();
903 if (nbTables == 0) return;
905 // ---------------------
906 // Write the TABLE pile
907 // ---------------------
909 *_sauvFile << " ENREGISTREMENT DE TYPE 2" << endl
910 << " PILE NUMERO 10NBRE OBJETS NOMMES" << setw(8) << nbTables
911 << "NBRE OBJETS" << setw(8) << nbTables << endl;
913 if (!_longNames[ LN_MAIL ].empty()) *_sauvFile << " MED_MAIL";
914 if (!_longNames[ LN_CHAM ].empty()) *_sauvFile << " MED_CHAM";
915 if (!_longNames[ LN_COMP ].empty()) *_sauvFile << " MED_COMP";
918 for ( int i = 0; i < nbTables; ++i ) *_sauvFile << setw(8) << i+1;
921 string theWholeString; // concatenated long names
922 vector<int> theOffsets;
924 TFieldCounter fcount (*_sauvFile, 10);
926 for ( int iTbl = 0; iTbl < LN_NB; ++iTbl )
928 vector<nameGIBItoMED>& longNames = _longNames[ iTbl ];
929 if ( longNames.empty() ) continue;
930 const bool isComp = ( iTbl == LN_COMP);
932 // to assure unique MED names
933 set<string> medUniqueNames;
935 *_sauvFile << setw(8) << longNames.size()*4 << endl; // Nb of table values
937 vector<nameGIBItoMED>::iterator itGIBItoMED = longNames.begin();
938 for (; itGIBItoMED != longNames.end(); itGIBItoMED++, iStr++)
940 // PILE of i-th key (med name)
941 *_sauvFile << setw(8) << PILE_STRINGS;
943 // ID of i-th key (med name)
944 *_sauvFile << setw(8) << iStr;
946 // PILE of i-th value (gibi name)
947 *_sauvFile << setw(8) << itGIBItoMED->gibi_pile;
949 // ID of i-th value (gibi name)
950 *_sauvFile << setw(8) << ( isComp ? ++iStr : itGIBItoMED->gibi_id );
953 // add a MED name to the string (while making it be unique for sub-meshes and fields)
954 string aMedName = itGIBItoMED->med_name;
956 for (int ind = 1; !medUniqueNames.insert(aMedName).second; ++ind )
957 aMedName = itGIBItoMED->med_name + "_" + SauvUtilities::toString( ind );
958 theWholeString += aMedName;
961 theOffsets.push_back( theWholeString.size() );
964 theWholeString += itGIBItoMED->gibi_name;
965 theOffsets.push_back( theWholeString.size() );
971 // ----------------------
972 // Write the STRING pile
973 // ----------------------
975 const int nbNames = theOffsets.size();
976 *_sauvFile << " ENREGISTREMENT DE TYPE 2" << endl
977 << " PILE NUMERO 27NBRE OBJETS NOMMES" << zeroI8 << "NBRE OBJETS" << setw(8) << nbNames << endl
978 << setw(8) << theWholeString.length() << setw(8) << nbNames << endl;
980 // write the whole string
981 const int fixedLength = 71;
982 for ( string::size_type aPos = 0; aPos < theWholeString.length(); aPos += fixedLength)
983 *_sauvFile << setw(72) << theWholeString.substr(aPos, fixedLength) << endl;
986 for ( size_t i = 0; i < theOffsets.size(); ++i, fcount++ )
987 *_sauvFile << setw(8) << theOffsets[i];
990 //================================================================================
992 * \brief Write beginning of field record
994 //================================================================================
996 void SauvWriter::writeFieldNames( const bool isNodal,
997 std::map<std::string,int>& fldNamePrefixMap)
999 vector< MEDCouplingAutoRefCountObjectPtr< MEDFileFieldMultiTS > >&
1000 flds = isNodal ? _nodeFields : _cellFields;
1001 map<string,int> nameNbMap;
1003 for ( size_t iF = 0; iF < flds.size(); ++iF )
1005 string name = addName( nameNbMap, fldNamePrefixMap, flds[iF]->getName(), iF+1 );
1006 nameGIBItoMED aMEDName;
1007 aMEDName.gibi_pile = isNodal ? PILE_NODES_FIELD : PILE_FIELD;
1008 aMEDName.gibi_id = iF+1;
1009 aMEDName.med_name = name;
1010 _longNames[ LN_CHAM ].push_back(aMEDName);
1013 *_sauvFile << " ENREGISTREMENT DE TYPE 2" << endl
1014 << ( isNodal ? " PILE NUMERO 2" : " PILE NUMERO 39")
1015 << "NBRE OBJETS NOMMES" << setw(8) << nameNbMap.size()
1016 << "NBRE OBJETS" << setw(8) << flds.size() << endl;
1017 writeNames( nameNbMap );
1020 //================================================================================
1022 * \brief Make short names of field components
1024 * IMP 0020434: mapping GIBI names to MED names
1026 //================================================================================
1028 void SauvWriter::makeCompNames(const string& fieldName,
1029 const vector<string>& compInfo,
1030 map<string, string>& mapMedToGibi)
1032 for ( size_t i = 0; i < compInfo.size(); ++i )
1033 mapMedToGibi[compInfo[i]] = cleanName( compInfo[i] );
1036 map<string, string>::iterator namesIt = mapMedToGibi.begin();
1037 for (; namesIt != mapMedToGibi.end(); namesIt++)
1039 string & compGibiName = (*namesIt).second;
1040 if (compGibiName.size() > 4) {
1041 // use new name in form "CXXX", where "XXX" is a number
1044 compGibiName = SauvUtilities::toString( compIndex++ );
1045 if ( compGibiName.size() < 3 )
1046 compGibiName.insert( 0, 3 - compGibiName.size(), '0' );
1047 compGibiName = "C" + compGibiName;
1049 while (mapMedToGibi.count(compGibiName) > 0); // real component name could be CXXX
1052 string compMedName = fieldName + "." + namesIt->first;
1053 nameGIBItoMED aMEDName;
1054 aMEDName.med_name = compMedName;
1055 aMEDName.gibi_pile = PILE_STRINGS;
1056 aMEDName.gibi_name = compGibiName;
1057 _longNames[ LN_COMP ].push_back(aMEDName);
1061 //================================================================================
1063 * \brief Writes "PILE NUMERO 2": fields on nodes
1065 //================================================================================
1067 void SauvWriter::writeNodalFields(map<string,int>& fldNamePrefixMap)
1069 writeFieldNames( /*isNodal=*/true, fldNamePrefixMap );
1071 TFieldCounter fcount (*_sauvFile, 10);
1073 // EXAMPLE ( with no values )
1076 // (2) -88 0 3 -89 0 1 -90 0 2 -91
1078 // (3) FX FY FZ FZ FX FY FLX
1079 // (4) 0 0 0 0 0 0 0
1080 // (5) cree par muc pri
1083 for ( size_t iF = 0; iF < _nodeFields.size(); ++iF )
1085 // (1) write nb subcomponents, nb components(total)
1086 vector< pair<int,int> > iters = _nodeFields[iF]->getIterations();
1087 const vector<string>& compInfo = _nodeFields[iF]->getInfo();
1088 const int nbSub = iters.size();
1089 const int nbComp = compInfo.size();
1090 const int totalNbComp = nbSub * nbComp;
1091 *_sauvFile << setw(8) << nbSub
1092 << setw(8) << totalNbComp
1093 << setw(8) << -1 // IFOUR
1094 << setw(8) << 0 << endl; // nb attributes
1096 // (2) for each sub-component (iteration)
1097 // write support, number of values and number of components
1099 vector< int > vals(3);
1100 for ( std::size_t iIt = 0; iIt < iters.size(); ++iIt )
1102 pair<int,int> it = iters[iIt];
1104 vector<INTERP_KERNEL::NormalizedCellType> types;
1105 vector< vector<TypeOfField> > typesF;
1106 vector< vector<string> > pfls, locs;
1107 vector< vector< std::pair<int,int> > > valsVec;
1108 valsVec=_nodeFields[iF]->getFieldSplitedByType( it.first, it.second, _fileMesh->getName().c_str(),
1109 types, typesF, pfls, locs);
1110 // believe that there can be only one type in a nodal field,
1111 // so do not use a loop on types
1112 if ( pfls[0][0].empty() ) pfls[0][0] = noProfileName( types[0] );
1113 map< string, SubMesh* >::iterator pfl2Sub = _profile2Sub.find( pfls[0][0] );
1114 if ( pfl2Sub == _profile2Sub.end() )
1115 THROW_IK_EXCEPTION( "SauvWriter::writeNodalFields(): no sub-mesh for profile |"
1116 << pfls[0][0] << "|");
1117 vals[0] = -pfl2Sub->second->_id;
1118 vals[1] = (valsVec[0][0].second-valsVec[0][0].first);
1119 vals[2] = compInfo.size();
1120 for ( size_t i = 0; i < vals.size(); ++i, fcount++ )
1121 *_sauvFile << setw(8) << vals[i];
1125 // (3) Write names of components
1126 map<string, string> mapMedToGibi;
1127 makeCompNames( _nodeFields[iF]->getName(), compInfo, mapMedToGibi );
1130 for ( std::size_t iIt = 0; iIt < iters.size(); ++iIt )
1131 for ( size_t i = 0; i < compInfo.size(); ++i, fcount++ )
1132 *_sauvFile << " " << setw(4) << mapMedToGibi[compInfo[i]];
1133 *_sauvFile << right;
1138 for ( size_t i = 0; i < (std::size_t)totalNbComp; ++i, fcount++ )
1139 *_sauvFile << " " << setw(8) << 0;
1142 string description = _nodeFields[iF]->getName();
1143 *_sauvFile << endl; // (5) TYPE
1144 *_sauvFile << setw(72) << description.substr(0,71) << endl; // (6) TITRE
1145 //*_sauvFile << endl; // (7) 0 attributes
1147 // write values of each component
1148 fcount.init( 3 ); // 3 values per a line
1149 for ( std::size_t iIt = 0; iIt < iters.size(); ++iIt )
1151 pair<int,int> it = iters[iIt];
1153 vector<INTERP_KERNEL::NormalizedCellType> types;
1154 vector< vector<TypeOfField> > typesF;
1155 vector< vector<string> > pfls, locs;
1156 vector< vector< std::pair<int,int> > > valsVec;
1157 valsVec = _nodeFields[iF]->getFieldSplitedByType( it.first, it.second, _fileMesh->getName().c_str(),
1158 types, typesF, pfls, locs);
1159 // believe that there can be only one type in a nodal field,
1160 // so do not perform a loop on types
1161 const DataArrayDouble* valsArray = _nodeFields[iF]->getUndergroundDataArray(it.first, it.second);
1162 for ( size_t j = 0; j < compInfo.size(); ++j )
1164 for ( size_t i = valsVec[0][0].first; i < (std::size_t)valsVec[0][0].second; ++i, fcount++ )
1165 *_sauvFile << setw(22) << valsArray->getIJ( i, j );
1172 //================================================================================
1174 * \brief Writes "PILE NUMERO 39": fields on cells
1176 //================================================================================
1178 void SauvWriter::writeElemFields(map<string,int>& fldNamePrefixMap)
1180 writeFieldNames( /*isNodal=*/false, fldNamePrefixMap );
1182 TFieldCounter fcount (*_sauvFile, 10);
1187 // (2) CARACTERISTIQUES
1188 // (3) -15 317773 4 0 0 0 -2 0 3
1191 // (6) 317767 317761 317755 317815
1192 // (7) YOUN NU H SIGY
1193 // (8) REAL*8 REAL*8 REAL*8 REAL*8
1195 // (10) 2.00000000000000E+05
1197 // (10) 3.30000000000000E-01
1199 // (10) 1.00000000000000E+04
1201 // (10) 1.00000000000000E+02 1.00000000000000E+02 1.00000000000000E+02
1202 // (10) 1.00000000000000E+02 1.00000000000000E+02 1.00000000000000E+02
1205 for ( size_t iF = 0; iF < _cellFields.size(); ++iF )
1207 // count nb of sub-components
1208 int iSub, nbSub = 0;
1209 vector< pair<int,int> > iters = _cellFields[iF]->getIterations();
1210 for ( std::size_t iIt = 0; iIt < iters.size(); ++iIt )
1212 pair<int,int> it = iters[iIt];
1214 vector<INTERP_KERNEL::NormalizedCellType> types;
1215 vector< vector<TypeOfField> > typesF;
1216 vector< vector<string> > pfls, locs;
1217 vector< vector< std::pair<int,int> > > valsVec;
1218 valsVec = _cellFields[iF]->getFieldSplitedByType( it.first, it.second, _fileMesh->getName().c_str(),
1219 types, typesF, pfls, locs);
1220 for ( size_t i = 0; i < valsVec.size(); ++i )
1221 nbSub += valsVec[i].size();
1223 // (1) write nb sub-components, title length
1224 *_sauvFile << setw(8) << nbSub
1225 << setw(8) << -1 // whatever
1226 << setw(8) << 6 // whatever
1227 << setw(8) << 72 << endl; // title length
1229 string title = _cellFields[iF]->getName();
1230 *_sauvFile << setw(72) << title.substr(0,71) << endl;
1231 *_sauvFile << setw(72) << " " << endl;
1233 // (3) support, nb components
1234 vector<int> vals(9, 0);
1235 const vector<string>& compInfo = _cellFields[iF]->getInfo();
1236 vals[2] = compInfo.size();
1238 for ( std::size_t iIt = 0; iIt < iters.size(); ++iIt )
1240 pair<int,int> it = iters[iIt];
1242 vector<INTERP_KERNEL::NormalizedCellType> types;
1243 vector< vector<TypeOfField> > typesF;
1244 vector< vector<string> > pfls, locs;
1245 _cellFields[iF]->getFieldSplitedByType( it.first, it.second, _fileMesh->getName().c_str(),
1246 types, typesF, pfls, locs);
1247 for ( size_t iType = 0; iType < pfls.size(); ++iType )
1248 for ( size_t iP = 0; iP < pfls[iType].size(); ++iP )
1250 if ( pfls[iType][iP].empty() ) pfls[iType][iP] = noProfileName( types[iType] );
1251 map< string, SubMesh* >::iterator pfl2Sub = _profile2Sub.find( pfls[iType][iP] );
1252 if ( pfl2Sub == _profile2Sub.end() )
1253 THROW_IK_EXCEPTION( "SauvWriter::writeElemFields(): no sub-mesh for profile |"
1254 << pfls[iType][iP] << "|");
1255 const int supportID = pfl2Sub->second->_id;
1256 vals[0] = -supportID;
1258 for ( size_t i = 0; i < vals.size(); ++i, fcount++ )
1259 *_sauvFile << setw(8) << vals[ i ];
1264 // (4) dummy strings
1265 for ( fcount.init(4), iSub = 0; iSub < nbSub; ++iSub, fcount++ )
1269 // (5) dummy strings
1270 for ( fcount.init(8), iSub = 0; iSub < nbSub; ++iSub, fcount++ )
1274 // loop on sub-components of a field, each of which refers to
1275 // a certain support and has its own number of components
1276 for ( std::size_t iIt = 0; iIt < iters.size(); ++iIt )
1278 pair<int,int> it = iters[iIt];
1279 writeElemTimeStamp( iF, it.first, it.second );
1281 } // loop on cell fields
1284 //================================================================================
1286 * \brief Write one elemental time stamp
1288 //================================================================================
1290 void SauvWriter::writeElemTimeStamp(int iF, int iter, int order)
1292 // (6) 317767 317761 317755 317815
1293 // (7) YOUN NU H SIGY
1294 // (8) REAL*8 REAL*8 REAL*8 REAL*8
1296 // (10) 2.00000000000000E+05
1298 // (10) 3.30000000000000E-01
1300 // (10) 1.00000000000000E+04
1302 // (10) 1.00000000000000E+02 1.00000000000000E+02 1.00000000000000E+02
1303 // (10) 1.00000000000000E+02 1.00000000000000E+02 1.00000000000000E+02
1305 TFieldCounter fcount (*_sauvFile, 10);
1307 vector<INTERP_KERNEL::NormalizedCellType> types;
1308 vector< vector<TypeOfField> > typesF;
1309 vector< vector<string> > pfls, locs;
1310 vector< vector< std::pair<int,int> > > valsVec;
1311 valsVec = _cellFields[iF]->getFieldSplitedByType( iter, order, _fileMesh->getName().c_str(),
1312 types, typesF, pfls, locs);
1313 for ( size_t iType = 0; iType < pfls.size(); ++iType )
1314 for ( size_t iP = 0; iP < pfls[iType].size(); ++iP )
1316 const vector<string>& compInfo = _cellFields[iF]->getInfo();
1318 // (6) component addresses
1319 int iComp = 0, nbComp = compInfo.size();
1320 for ( fcount.init(10); iComp < nbComp; ++iComp, fcount++ )
1321 *_sauvFile << setw(8) << 777; // a good number
1324 // (7) component names
1325 map<string, string> mapMedToGibi;
1326 makeCompNames( _cellFields[iF]->getName(), compInfo, mapMedToGibi );
1328 for ( fcount.init(8), iComp = 0; iComp < nbComp; ++iComp, fcount++ )
1329 *_sauvFile << " " << setw(8) << mapMedToGibi[compInfo[iComp]];
1332 // (8) component types
1333 for ( fcount.init(4), iComp = 0; iComp < nbComp; ++iComp, fcount++ )
1334 *_sauvFile << " " << setw(17) << "REAL*8";
1336 *_sauvFile << right;
1338 // (9) nb values per element, nb of elements
1339 int nbPntPerCell = 1;
1340 if ( !locs[iType][iP].empty() )
1342 int locID = _cellFields[iF]->getLocalizationId( locs[iType][iP].c_str() );
1343 nbPntPerCell = _cellFields[iF]->getNbOfGaussPtPerCell( locID );
1345 else if ( typesF[iType][iP] == ON_GAUSS_NE )
1347 nbPntPerCell = INTERP_KERNEL::CellModel::GetCellModel(types[iType]).getNumberOfNodes();
1351 const std::pair<int,int>& bgEnd = valsVec[iType][iP];
1352 const DataArrayDouble* valArray = _cellFields[iF]->getUndergroundDataArray(iter, order);
1353 for ( iComp = 0; iComp < nbComp; ++iComp )
1355 *_sauvFile << setw(8) << nbPntPerCell
1356 << setw(8) << (bgEnd.second-bgEnd.first) / nbPntPerCell
1361 for ( size_t i = bgEnd.first; i < (size_t) bgEnd.second; ++i, fcount++ )
1362 *_sauvFile << setw(22) << valArray->getIJ( i, iComp );
1368 //================================================================================
1370 * \brief Write the last record of the SAUV file
1372 //================================================================================
1374 void SauvWriter::writeLastRecord()
1376 *_sauvFile << " ENREGISTREMENT DE TYPE 5" << endl;
1377 *_sauvFile << "LABEL AUTOMATIQUE : 1" << endl;