Back to index

salome-med  6.5.0
MEDMEM_EnsightUtils.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // This library is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU Lesser General Public
00005 // License as published by the Free Software Foundation; either
00006 // version 2.1 of the License.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // Lesser General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU Lesser General Public
00014 // License along with this library; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00016 //
00017 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00018 //
00019 
00020 // File      : MEDMEM_EnsightUtils.cxx
00021 // Created   : Fri Jun  6 16:08:32 2008
00022 // Author    : Edward AGAPOV (eap)
00023 //
00024 #include "MEDMEM_Field.hxx" // important to include it before MEDMEM_EnsightUtils.hxx,
00025 // in order not to redefine DBL_MIN
00026 
00027 #include "MEDMEM_EnsightUtils.hxx"
00028 
00029 #include "MEDMEM_EnsightMeshDriver.hxx"
00030 #include "MEDMEM_EnsightFieldDriver.hxx"
00031 #include "MEDMEM_DriverTools.hxx"
00032 
00033 #ifdef WNT
00034 #include <io.h>
00035 #else
00036 #include <unistd.h>
00037 #endif
00038 #include <fcntl.h>
00039 //#include <stdio.h>
00040 
00041 using namespace std;
00042 using namespace MEDMEM;
00043 
00044   // TODO:
00045 // -2) in transient model, get time values for meshes form fields on them
00046 // -1) why after reading /data/eap/ENSIGHT/SAMPLES_SRC/EnSight/crash.case only
00047 //     geo EnSIght files are written
00048 // -0) test selecting imaginary part to read
00049 // 0) appending fields to write with same names in Case file
00050 // 1) write grid
00051 // 2) if mesh description is longer that maxLen, distribute it among two lines
00052 // 3) care of mesh description at reading
00053 // 4) at writing, cut off " t=..." from mesh name and set to meshDriver->_meshName
00054 // 5) MEDMEM_EXPORT
00055 // 4.5) do something with zzzz121b.med pb
00056 // 6) stripe in getLine()
00057 // 7) care of elem numbers that were read
00058 // 8) read real and imaginary of complex field by MED driver
00059 // 9) read "mesured" and care of variable on it
00060 // 10) clear theInterMedMap and delete _InterMed's there
00061 // 11) not to fill MESH made in getMeshData()
00062 // 12) care of changing nb of '*' in names
00063 // 14) analize _TimeSet to write in shortest form
00064 // 15) add LOCALIZED where no method name specified
00065 // 17) add checks of input mesh and field like in gibi
00066 // 18) check writing interlace in all modes
00067 // 19) define creation by MEDMEM by case file and not by geo
00068 // 21) there maybe '\n' in binary file after string end
00069 // 22) optimize _ASCIIFileReader::eof() at file end
00070 // 23) What if to create CELL entity with 1-3 dim and a CELL group?
00071 // 24) not to write CELL connectivity if a group on all cells is present
00072 // 25) compact imed (sortedNodeIDs etc.)
00073 // 26) no need in converting EnSight variables to eventual types in convertReals
00074 //     since a result array is not used directly but occupies more memory
00075 // 27) try to exclude merged nodes in DTree and compare time on ChampsDarcy.med
00076 
00077 
00078 namespace MEDMEM
00079 {
00080   // ==============================================================================
00084   // ==============================================================================
00085 
00086   EnSightFormat theEnSightFormatForWriting = ENSIGHT_6;
00087   bool          theBinaryFormatForWriting  = false;
00088   bool          theIgnoreIncompatibility   = false;
00089 
00090   void          setEnSightFormatForWriting (EnSightFormat format, bool isBinary)
00091   {
00092     theEnSightFormatForWriting = format;
00093     theBinaryFormatForWriting  = isBinary;
00094   }
00095   EnSightFormat getEnSightFormatForWriting()
00096   {
00097     return theEnSightFormatForWriting;
00098   }
00099   bool          isBinaryEnSightFormatForWriting()
00100   {
00101     return theBinaryFormatForWriting;
00102   }
00103   // ==============================================================================
00107   // ==============================================================================
00108 
00109   void          setIgnoreIncompatibility(bool toIgnore)
00110   {
00111     theIgnoreIncompatibility = toIgnore;
00112   }
00113 }
00114 
00115 #ifdef WNT
00116 #define FILE_SEPARATOR '\\'
00117 #else
00118 #define FILE_SEPARATOR '/'
00119 #endif
00120 
00121 #define _ATOI( str ) atoi((str).c_str())
00122 #define _ATOF( str ) atof((str).c_str())
00123 
00124 #define BUFFER_SIZE 16184  // for non-stream input
00125 
00126 namespace MEDMEM_ENSIGHT
00127 {
00128   //--------------------------------------------------------------------------------
00138   set< const _CaseFileDriver_User* > theCaseUsers;
00139 
00140   //--------------------------------------------------------------------------------
00149   map< string, _InterMed* > theInterMedMap;
00150 
00151   //--------------------------------------------------------------------------------
00155   bool isToIgnore(const _CaseFileDriver_User* driver);
00156   bool isToIgnore(const _CaseFileDriver_User* driver)
00157   {
00158     return ! theCaseUsers.insert( driver ).second;
00159   }
00160 
00161   //--------------------------------------------------------------------------------
00165   void unregister(const _CaseFileDriver_User* driver);
00166   void unregister(const _CaseFileDriver_User* driver)
00167   {
00168     theCaseUsers.erase( driver );
00169     if ( theCaseUsers.empty() )
00170     {
00171       for ( map< string, _InterMed* >::iterator str_imed = theInterMedMap.begin();
00172             str_imed != theInterMedMap.end();
00173             str_imed++ )
00174         delete str_imed->second;
00175       theInterMedMap.clear();
00176     }
00177   }
00178 
00179   //--------------------------------------------------------------------------------
00183   _InterMed* getMeshData( const string& key );
00184   _InterMed* getMeshData( const string& key )
00185   {
00186     // find existing data
00187     map< string, _InterMed* >::iterator kimed = theInterMedMap.find( key );
00188     if ( kimed != theInterMedMap.end() )
00189       return kimed->second;
00190 
00191     // create a new data
00192     MESH * mesh = new MESH;
00193     string caseFile, meshIndex;
00194     _ASCIIFileReader::split( key, caseFile, meshIndex, ':' );
00195     ENSIGHT_MESH_RDONLY_DRIVER meshDrv(caseFile, mesh, _ATOI( meshIndex ));
00196     meshDrv.read();
00197     kimed = theInterMedMap.find( key );
00198     if ( kimed == theInterMedMap.end() )
00199       return 0;
00200     _InterMed* imed     = kimed->second;
00201     imed->_medMesh      = mesh;
00202     imed->_isOwnMedMesh = true;
00203     return imed;
00204   }
00205   // ---------------------------------------------------------------
00210   STRING compatibilityPb(const string& exceptionText)
00211   {
00212     return STRING("EnSight-MEDMEM compatibility problem:\n") << exceptionText;
00213   }
00214   // ---------------------------------------------------------------
00218   bool   toIgnoreIncompatibility()
00219   {
00220     return theIgnoreIncompatibility;
00221   }
00222 
00223   //--------------------------------------------------------------------------------
00227   template <class TSet> bool isValidIndex(const string& index, const map<int,TSet>& aMap)
00228   {
00229     if ( index.empty() ) return true;
00230     return ( aMap.find( _ATOI( index ) ) != aMap.end() );
00231   }
00232 
00233   //--------------------------------------------------------------------------------
00237   const TEnSightElemType& getEnSightType(medGeometryElement medType)
00238   {
00239     static TEnSightElemType theEnSightType;
00240 
00241     int nbNodes = medType % 100;
00242     theEnSightType._medType = medType;
00243 
00244     switch ( medType ) {
00245     case MED_NONE    :
00246     case MED_POINT1  : {
00247       theEnSightType._name = "point";
00248       theEnSightType._medIndex.resize(1,0);
00249       break ;
00250     }
00251     case MED_SEG2    : {
00252       theEnSightType._name = "bar2";
00253       int conn [2] = {0,1};
00254       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00255       break ;
00256     }
00257     case MED_SEG3    : {  
00258       theEnSightType._name = "bar3";
00259       int conn [3] = {0,2,1};
00260       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00261       break ;
00262     }
00263     case MED_TRIA3   : {
00264       theEnSightType._name = "tria3";
00265       int conn [3] = {0,2,1};
00266       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00267       break ;
00268     }
00269     case MED_QUAD4   : {
00270       theEnSightType._name = "quad4";
00271       int conn [4] = {0,3,2,1};
00272       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00273       break ;
00274     }
00275     case MED_TRIA6   : {
00276       theEnSightType._name = "tria6";
00277       int conn [6] = {0,2,1,5,4,3};
00278       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00279       break ;
00280     }
00281     case MED_QUAD8   : {
00282       theEnSightType._name = "quad8";
00283       int conn [8] = {0,3,2,1,7,6,5,4};
00284       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00285       break ;
00286     }
00287     case MED_TETRA4  : {
00288       theEnSightType._name = "tetra4";
00289       int conn [4] = {0,1,3,2};
00290       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00291       break ;
00292     }
00293     case MED_PYRA5   : {
00294       theEnSightType._name = "pyramid5";
00295       int conn [5] = {0,3,2,1,4};
00296       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00297       break ;
00298     }
00299     case MED_PENTA6  : {
00300       theEnSightType._name = "penta6";
00301       int conn [6] = {0,2,1,3,5,4};
00302       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00303       break ;
00304     }
00305     case MED_HEXA8   : {
00306       theEnSightType._name = "hexa8";
00307       int conn [8] = {0,3,2,1,4,7,6,5};
00308       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00309       break ;
00310     }
00311     case MED_TETRA10 : {
00312       theEnSightType._name = "tetra10";
00313       int conn [10] = {0,2,1,3,6,5,4,7,9,8};
00314       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00315       break ;
00316     }
00317     case MED_PYRA13  : {
00318       theEnSightType._name = "pyramid13";
00319       int conn [13] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
00320       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00321       break ;
00322     }
00323     case MED_PENTA15 : {
00324       theEnSightType._name = "penta15";
00325       int conn [15] = {0,2,1,3,5,4,8,7,6,11,10,12,14,13};
00326       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00327       break ;
00328     }
00329     case MED_HEXA20  : {
00330       theEnSightType._name = "hexa20";
00331       int conn [20] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
00332       theEnSightType._medIndex.assign( conn, conn+nbNodes );
00333       break ;
00334     }
00335     case MED_POLYGON : {
00336       theEnSightType._name = "nsided";
00337       theEnSightType._medIndex.clear();
00338       break ;
00339     }
00340     case MED_POLYHEDRA : {
00341       theEnSightType._name = "nfaced";
00342       theEnSightType._medIndex.clear();
00343       break ;
00344     }
00345     default: {
00346       theEnSightType._name = "";
00347       theEnSightType._medIndex.clear();
00348     }
00349     }
00350     return theEnSightType;
00351   }
00352 
00353   //--------------------------------------------------------------------------------
00357   const TEnSightElemType& getEnSightType(const string& theTypeName)
00358   {
00359     string typeName = theTypeName;
00360     if ( isGhostType( typeName ))
00361       typeName = string( &typeName[2] ); // ghost type
00362 
00363     static map<string, TEnSightElemType> name2Type;
00364 
00365     map<string, TEnSightElemType>::iterator nameType = name2Type.find( typeName );
00366     if ( nameType != name2Type.end() )
00367       return nameType->second;
00368 
00369     const list<medGeometryElement> & allMedTypes = MED_EN::meshEntities[MED_CELL];
00370     list< medGeometryElement >::const_iterator medType = allMedTypes.begin();
00371     for ( ; medType != allMedTypes.end(); ++medType )
00372     {
00373       const TEnSightElemType& enSightType = getEnSightType( *medType );
00374       if ( enSightType._name == typeName )
00375         return name2Type[ typeName ] = enSightType;
00376     }
00377     return getEnSightType(MED_ALL_ELEMENTS);
00378   }
00379 
00380 // =============================================================== _CaseFileDriver
00384 //================================================================================
00385 
00386 _CaseFileDriver::_CaseFileDriver(const string &              fileName,
00387                                  const _CaseFileDriver_User* creator)
00388   : _fileName( fileName ), _directory("."), _user( creator )
00389 {
00390   // Find out if the driver is blocked
00391   _blocked = isToIgnore( creator );
00392   if ( creator->getAccessMode() == MED_EN::RDONLY )
00393     _blocked = false;
00394   if ( !_blocked ) {
00395     // set directory
00396     string::size_type sepPos = _fileName.rfind( FILE_SEPARATOR );
00397     if ( sepPos != _fileName.npos ) {
00398       _directory = _fileName.substr( 0, sepPos );
00399     }
00400     _format = getEnSightFormatForWriting();
00401   }
00402 }
00403 
00404 // =============================================================== _CaseFileDriver
00408 //================================================================================
00409 
00410 _CaseFileDriver::~_CaseFileDriver()
00411 {
00412   if ( !_blocked )
00413   {
00414     // to write case file again by same DRIVER
00415     unregister( _user );
00416     ((_CaseFileDriver_User*)_user)->_imed = 0;
00417   }
00418 }
00419 
00420 #define READ_NEXT_LINE continue
00421 #define RAISE_EXCEPTION break
00422 
00423 //================================================================================
00427 //================================================================================
00428 
00429 void _CaseFileDriver::read() throw (MEDEXCEPTION)
00430 {
00431   if ( _blocked )
00432     return;
00433 
00434   _ASCIIFileReader reader( _fileName );
00435 
00436   STRING badFile("Invalid Case file ");
00437   badFile << _fileName << "\n";
00438 
00439   list<_FileSet> fileSets;
00440   list<_TimeSet> timeSets;
00441 
00442   set<string> varNames; // to detect equal variable names
00443 
00444   string section = "_";
00445   int lineNb = 0;
00446   while ( !reader.eof() )
00447   {
00448     string line = reader.getLine();
00449     ++lineNb;
00450 
00451     // cut off comments
00452     string comment;
00453     reader.split( line, line, comment, '#');
00454     if ( line.empty() )
00455       READ_NEXT_LINE;
00456 
00457     string key, value; // parts of a line splited by column
00458     reader.split( line, key, value, ':');
00459 
00460     STRING errorMsg;
00461 
00462     // analyse not empty lines
00463     switch ( section[0] ) {
00464     case 'V': {
00465       // --------------------------------------------------------------------------------
00466       // VARIABLE
00467 
00468       string type, s, ts, fs;
00469       reader.split(key,type,s);
00470       int newVarIndex = _variables.empty() ? 1 : _variables.rbegin()->first + 1;
00471 
00472       if ( type == "scalar" || type == "vector" || type == "tensor" )
00473       {
00474         // scalar per node:        [ts] [fs] description filename
00475         // vector per node:        [ts] [fs] description filename
00476         // tensor symm per node:       [ts]  [fs]   description filename
00477         // tensor asym per node:       [ts]  [fs]   description filename
00478         // scalar per element:         [ts]  [fs]   description filename
00479         // vector per element:         [ts]  [fs]   description filename
00480         // tensor symm per element:    [ts]  [fs]   description filename
00481         // tensor asym per element:    [ts]  [fs]   description filename
00482         // scalar per measured node:   [ts]  [fs]   description filename
00483         // vector per measured node:   [ts]  [fs]   description filename
00484         list<string> parts;
00485         int nbParts = reader.split( value, parts );
00486         if ( nbParts < 2 ) {
00487           errorMsg << "invalid variable format:\n" << line;
00488           RAISE_EXCEPTION;
00489         }
00490         if ( contains( "per measured node", s.c_str() )) {
00491           //cout << "Skip not supported data type: " << key << endl;
00492           READ_NEXT_LINE;
00493         }
00494         list<string>::reverse_iterator p = parts.rbegin();
00495         _Variable& var      = _variables[newVarIndex];
00496         var._type           = key;
00497         var._fileNameOrData = *p++;
00498         var._name           = *p++;
00499         if ( nbParts == 3 ) {
00500           var._timeSetNumber = *p;
00501         }
00502         else if ( nbParts == 4 ) {
00503           var._fileSetNumber = *p++;
00504           var._timeSetNumber = *p;
00505         }
00506         varNames.insert( var._name );
00507         READ_NEXT_LINE;
00508       }
00509       else if ( type == "constant" )
00510       {
00511         // constant per case:      [ts]      description const_value(s)
00512         // constant per case file: [ts]      description cvfilename
00513         reader.split(value,s,value);
00514         if ( reader.isDigit( s )) {
00515           ts = s;
00516           reader.split(value,s,value);
00517         }
00518         _Variable& var      = _variables[newVarIndex];
00519         var._type           = key;
00520         var._name           = s;
00521         var._fileNameOrData = value;
00522         var._timeSetNumber  = ts;
00523         if ( var._name.empty() || var._fileNameOrData.empty() ) {
00524           errorMsg << "invalid variable format:\n" << line;
00525           RAISE_EXCEPTION;
00526         }
00527         varNames.insert( var._name );
00528         READ_NEXT_LINE;
00529       }
00530       else if ( type == "complex" )
00531       {
00532         // complex scalar per node:    [ts]  [fs]   description Re_fn   Im_fn freq
00533         // complex vector per node:    [ts]  [fs]   description Re_fn   Im_fn freq
00534         // complex scalar per element:    [ts] [fs] description Re_fn   Im_fn freq
00535         // complex vector per element:    [ts] [fs] description Re_fn   Im_fn freq
00536         reader.split(value,s,value);
00537         if ( reader.isDigit( s )) {
00538           ts = s;
00539           reader.split(value,s,value);
00540           if ( reader.isDigit( s )) {
00541             fs = s;
00542             reader.split(value,s,value);
00543           }
00544         }
00545         list<string> parts;
00546         int nbParts = reader.split( value, parts );
00547         if ( nbParts < 3 ) {
00548           errorMsg << "invalid variable format:\n" << line;
00549           RAISE_EXCEPTION;
00550         }
00551         // a variable contains two fields. We leave one slot in _variables empty
00552         // in order to have last key in _variables equal to number of fields.
00553         // Variable index equal to missing slot key corresponds to real part (Re_fn)
00554         _Variable& var     = _variables[++newVarIndex];
00555         var._type          = key;
00556         var._name          = s;
00557         var._timeSetNumber = ts;
00558         var._fileSetNumber = fs;
00559         var._fileNameOrData = value;
00560         varNames.insert( var._name );
00561         READ_NEXT_LINE;
00562       }
00563       break;
00564     }
00565     case 'T': {
00566       // --------------------------------------------------------------------------------
00567       // TIME
00568       //    time set:              ts [description]
00569       //    number of steps:       ns
00570       //    filename start number: fs
00571       //    filename increment:    fi
00572       //    time values:           time_1 time_2 .... time_ns
00573       // or
00574       //    time set:              ts [description]
00575       //    number of steps:       ns
00576       //    filename numbers:      fn
00577       //    time values:           time_1 time_2 .... time_ns
00578       // or
00579       //    time set:              ts [description]
00580       //    number of steps:       ns
00581       //    filename numbers file: fnfilename
00582       //    time values file:      tvfilename
00583       _TimeSet* timeSet = timeSets.empty() ? 0 : & timeSets.back();
00584       // ---------------------------------------------------------
00585       if ( key == "time set" )
00586       {
00587         int nb = _ATOI( value );
00588         if ( nb < 1 ) {
00589           errorMsg << "Invalid time set number: " << value;
00590           RAISE_EXCEPTION;
00591         }
00592         timeSets.push_back( _TimeSet() );
00593         timeSets.back()._number = nb;
00594         READ_NEXT_LINE;
00595       }
00596       // ---------------------------------------------------------
00597       if ( key == "number of steps" )
00598       {
00599         if ( !timeSet || !timeSet->_times.empty() ) {
00600           errorMsg << "Unexpected command: " << key;
00601           RAISE_EXCEPTION;
00602         }
00603         int nbSteps = _ATOI( value );
00604         if ( nbSteps < 1 ) {
00605           errorMsg << "invalid number of steps: " << value;
00606           RAISE_EXCEPTION;
00607         }
00608         timeSet->_times.resize( nbSteps );
00609         timeSet->_fileIndex.resize( nbSteps );
00610         READ_NEXT_LINE;
00611       }
00612       // ---------------------------------------------------------
00613       if ( key == "filename start number" )
00614       {
00615         if ( !timeSet || timeSet->_fileIndex.empty() ) {
00616           errorMsg << "Unexpected command: " << key;
00617           RAISE_EXCEPTION;
00618         }
00619         if ( !reader.isDigit( value )) {
00620           errorMsg << "invalid " << line;
00621           RAISE_EXCEPTION;
00622         }
00623         timeSet->_fileIndex[0] = value;
00624         READ_NEXT_LINE;
00625       }
00626       // ---------------------------------------------------------
00627       if ( key == "filename increment" ) {
00628         int incr = _ATOI( value );
00629         if ( incr == 0 ) {
00630           errorMsg << "invalid " << line;
00631           RAISE_EXCEPTION;
00632         }
00633         if ( !timeSet ||
00634              timeSet->_fileIndex.empty() ||
00635              timeSet->_fileIndex[0].empty() ) {
00636           errorMsg << "Unexpected command: " << key;
00637           RAISE_EXCEPTION;
00638         }
00639         int index = incr + _ATOI( timeSet->_fileIndex[0] );
00640         int nbSteps = timeSet->_fileIndex.size();
00641         for ( int i = 1; i < nbSteps; ++i, index += incr )
00642           timeSet->_fileIndex[i] = STRING( index );
00643         READ_NEXT_LINE;
00644       }
00645       // ---------------------------------------------------------
00646       if ( key == "time values" )
00647       {
00648         if ( !timeSet || timeSet->_times.empty() ) {
00649           errorMsg << "Unexpected command: " << key;
00650           RAISE_EXCEPTION;
00651         }
00652         list<string> times;
00653         int i, nbTimes = reader.split( value, times );
00654         list<string>::iterator t = times.begin();
00655         for ( i = 0; i < nbTimes; ++i, ++t )
00656           timeSet->_times[i] = *t;
00657         while ( nbTimes != (int)timeSet->_times.size() ) {
00658           value = reader.getLine();
00659           ++lineNb;
00660           nbTimes += reader.split( value, times );
00661           for (t = times.begin(); i < nbTimes; ++i, ++t ) {
00662             if ( ! reader.isDigit( *t, /*real=*/true ))
00663               break;
00664             timeSet->_times[i] = *t;
00665           }
00666         }
00667         if ( nbTimes != (int)timeSet->_times.size() ) {
00668           errorMsg << "incorrect number of times in time set " << timeSet->_number;
00669           RAISE_EXCEPTION;
00670         }
00671         for ( i = 1; i < nbTimes; ++i )
00672           if ( _ATOF( timeSet->_times[ i ]) <= _ATOF(timeSet->_times[ i-1 ] ))
00673             break;
00674         if ( i < nbTimes ) { // break from the previous loop occured
00675           errorMsg << "time values are not in ascending order in time set " << timeSet->_number;
00676           RAISE_EXCEPTION;
00677         }
00678         READ_NEXT_LINE;
00679       }
00680       // ---------------------------------------------------------
00681       if ( key == "filename numbers" )
00682       {
00683         if ( !timeSet || timeSet->_fileIndex.empty()) {
00684           errorMsg << "Unexpected command: " << key;
00685           RAISE_EXCEPTION;
00686         }
00687         list<string> numbers;
00688         int i, nb = reader.split( value, numbers );
00689         int nbFiles = timeSet->_fileIndex.size();
00690         timeSet->_fileIndex.insert(timeSet->_fileIndex.begin(), numbers.begin(), numbers.end() );
00691         while ( nb != nbFiles ) {
00692           value = reader.getLine();
00693           ++lineNb;
00694           i = nb;
00695           nb += reader.split( value, numbers );
00696           list<string>::iterator n = numbers.begin();
00697           for ( ; i < nb; ++i, ++n ) {
00698             if ( ! reader.isDigit( *n ))
00699               break;
00700             timeSet->_fileIndex[i] = *n;
00701           }
00702         }
00703         if ( nb != nbFiles ) {
00704           errorMsg << "incorrect number of " << key << " in time set " << timeSet->_number;
00705           RAISE_EXCEPTION;
00706         }
00707         READ_NEXT_LINE;
00708       }
00709       // ---------------------------------------------------------
00710       if ( key == "filename numbers file" ||
00711            key == "time values file" )
00712       {
00713         if ( !timeSet || timeSet->_fileIndex.empty()) {
00714           errorMsg << "Unexpected command: " << key;
00715           RAISE_EXCEPTION;
00716         }
00717         string fileName = _directory + FILE_SEPARATOR + value;
00718         if ( !_user->canOpenFile( fileName, RDONLY )) {
00719           errorMsg << "Can not open file " << fileName;
00720           RAISE_EXCEPTION;
00721         }
00722         _ASCIIFileReader file( fileName );
00723         list<string> numbers;
00724         while ( !file.eof() )
00725           numbers.push_back( file.getWord() );
00726         int nb = numbers.size();
00727         if ( nb != (int)timeSet->_times.size() ) {
00728           errorMsg << "incorrect number of values in file " << value;
00729           RAISE_EXCEPTION;
00730         }
00731         if ( key[0] == 'f' )
00732           timeSet->_fileIndex.assign( numbers.begin(), numbers.end() );
00733         else
00734           timeSet->_times.assign( numbers.begin(), numbers.end() );
00735         READ_NEXT_LINE;
00736       }
00737       break;
00738     }
00739     case 'F': {
00740       if ( section[1] == 'I' ) {
00741         // --------------------------------------------------------------------------------
00742         // FILE
00743         // file set:               fs
00744         // filename index:         fi # Note: only used when data continues in other files
00745         // number of steps:        ns
00746         if ( key == "file set" ) {
00747           int nb = _ATOI( value );
00748           if ( nb < 1 ) {
00749             errorMsg << "Invalid file set number: " << value;
00750           }
00751           else {
00752             fileSets.push_back( _FileSet() );
00753             fileSets.back()._number = nb;
00754             READ_NEXT_LINE;
00755           }
00756         }
00757         else if ( key == "filename index" ) {
00758           if ( fileSets.empty() ) {
00759             errorMsg << "'filename index' before 'file set'";
00760           }
00761           else if ( !value.empty() ) {
00762             fileSets.back()._fileIndex.push_back( value );
00763             READ_NEXT_LINE;
00764           }
00765         }
00766         else if ( key == "number of steps" ) {
00767           if ( fileSets.empty() ) {
00768             errorMsg << "'number of steps' before 'file set'";
00769           }
00770           else if ( value.empty() ) {
00771             errorMsg << "number of steps omitted: " << line;
00772           }
00773           else if ( !reader.isDigit( value )) {
00774             errorMsg << "invalid number of steps: " << value;
00775           }
00776           else {
00777             int n = _ATOI( value );
00778             if ( n < 1 ) {
00779               errorMsg << "invalid number of steps: " << value;
00780               RAISE_EXCEPTION;
00781             }
00782             fileSets.back()._nbStepsInFile.push_back( n );
00783             READ_NEXT_LINE;
00784           }
00785         }
00786       }
00787       else {
00788         // --------------------------------------------------------------------------------
00789         // FORMAT
00790         // type:  ensight
00791         if ( key != "type" ) {
00792           errorMsg << "unexpected info in section " << section << ":\n" << line;
00793           RAISE_EXCEPTION;
00794         }
00795         else {
00796           if ( value == "ensight gold" ) {
00797             _format = ENSIGHT_GOLD;
00798           }
00799           else if ( value == "ensight" ) {
00800             _format = ENSIGHT_6;
00801           }
00802           else {
00803             errorMsg << "Unsupported EnSight format: " << value;
00804             RAISE_EXCEPTION;
00805           }
00806           section = "_";
00807           READ_NEXT_LINE;
00808         }
00809       }
00810       break;
00811     }
00812     case 'G': {
00813       // --------------------------------------------------------------------------------
00814       // GEOMETRY
00815       // model:    [ts] [fs] filename [change_coords_only]
00816       // measured: [ts] [fs] filename [change_coords_only]
00817       // match:              filename
00818       // boundary:           filename
00819       // rigid_body:         filename
00820       if ( key == "measured" || key == "match" || key == "boundary" || key == "rigid_body") {
00821         //errorMsg << key << " geometry not supported";
00822         cout << "Warning: " << key << " geomerty not supported" << endl;
00823         READ_NEXT_LINE;
00824       }
00825       else if ( key == "model" ) {
00826         list<string> parts;
00827         reader.split( value, parts );
00828         list<string>::reverse_iterator s = parts.rbegin();
00829         for ( ; s != parts.rend(); ++s )
00830         {
00831           if ( *s == "change_coords_only" )
00832             _model._change_coords_only = *s;
00833           else if ( _model._fileName.empty() )
00834             _model._fileName = *s;
00835           else if ( _model._fileSetNumber.empty() )
00836             _model._fileSetNumber = *s;
00837           else
00838             _model._timeSetNumber = *s;
00839         }
00840         if ( _model._timeSetNumber.empty() && !_model._fileSetNumber.empty() )
00841           swap( _model._timeSetNumber, _model._fileSetNumber );
00842         if ( _model._fileName.empty() ) {
00843           errorMsg << "invalid model: " << value;
00844           RAISE_EXCEPTION;
00845         }
00846         READ_NEXT_LINE;
00847       }
00848       break;
00849     }
00850     case 'M': { // MATERIAL
00851       string keyWord1;
00852       reader.split(key,keyWord1,key);
00853       if ( keyWord1 == "material" || keyWord1 == "species" )
00854         READ_NEXT_LINE;
00855       break;
00856     }
00857     } // end switch (section[0])
00858 
00859     if ( !errorMsg.empty() ) {
00860       throw MEDEXCEPTION(STRING("Invalid Case file ") << _fileName
00861                          << ":" << lineNb << "\n" << errorMsg );
00862     }
00863 
00864     // we are here if a line was not recognized to belong to a current section
00865     if ( line == "FORMAT"   ||
00866          line == "GEOMETRY" ||
00867          line == "VARIABLE" ||
00868          line == "TIME"     ||
00869          line == "FILE"     ||
00870          line == "MATERIAL")
00871       section = line;
00872     else
00873       throw MEDEXCEPTION(STRING() << "Invalid format of Case file " << _fileName
00874                          << "\nwrong line: " << line );
00875   }
00876 
00877   if ( _model._fileName.empty() )
00878     throw MEDEXCEPTION(badFile << "no supported geometry information found" );
00879 
00880   // store time sets and file sets
00881   list<_FileSet>::iterator fs = fileSets.begin();
00882   for ( ; fs != fileSets.end(); ++fs ) {
00883     if ( fs->_nbStepsInFile.size() > 1 && fs->_fileIndex.empty() )
00884       throw MEDEXCEPTION(badFile << "missing file indices in a file set " << fs->_number );
00885     _fileSets[ fs->_number ] = *fs;
00886   }
00887   list<_TimeSet>::iterator ts = timeSets.begin();
00888   for ( ; ts != timeSets.end(); ++ts )
00889     _timeSets[ ts->_number ] = *ts;
00890 
00891   // check validity of ts and fs
00892 
00893   if ( !isValidIndex( _model._timeSetNumber, _timeSets ))
00894     throw MEDEXCEPTION(badFile << "bad time set index:" << _model._timeSetNumber );
00895   if ( !isValidIndex( _model._fileSetNumber, _fileSets ))
00896     throw MEDEXCEPTION(badFile << "bad file set index:" << _model._timeSetNumber );
00897 
00898   map< int, _Variable>::iterator ivars = _variables.begin();
00899   for ( ; ivars != _variables.end(); ++ivars ) {
00900     if ( !isValidIndex( ivars->second._timeSetNumber, _timeSets ))
00901       throw MEDEXCEPTION(badFile << "bad time set index:" << ivars->second._timeSetNumber );
00902     if ( !isValidIndex( ivars->second._fileSetNumber, _fileSets ))
00903       throw MEDEXCEPTION(badFile << "bad file set index:" << ivars->second._fileSetNumber );
00904   }
00905 
00906   // check uniqueness of variable names
00907   if ( varNames.size() != _variables.size() )
00908     cout << badFile <<
00909       "Warning: there are different fields with equal names, you may have problems!" << endl;
00910 //     throw MEDEXCEPTION(badFile );
00911 
00912   // As variable does not refer to time set if there is one step (issue 0020113),
00913   // we try to restore the reference
00914 
00915   for ( ivars = _variables.begin(); ivars != _variables.end(); ++ivars ) {
00916     _Variable & var = ivars->second;
00917     if ( var._timeSetNumber.empty() )
00918     {
00919       // try to find time set with id equal to variable order number
00920       map< int, _TimeSet >::iterator iTs = _timeSets.find( ivars->first );
00921       if ( iTs != _timeSets.end() && iTs->second._times.size() == 1 )
00922         var._timeSetNumber = STRING( iTs->second._number );
00923       else {
00924         // find any time set with 1 time value
00925         for ( iTs = _timeSets.begin(); iTs != _timeSets.end(); ++iTs )
00926           if ( iTs->second._times.size() == 1 )
00927             var._timeSetNumber = STRING( iTs->second._number ); 
00928       }
00929     }
00930   }
00931 }
00932 
00933 //================================================================================
00937 //================================================================================
00938 
00939 int _CaseFileDriver::getNbMeshes() const
00940 {
00941   if ( _blocked || checkWasRead())
00942     return 0 ;
00943   if ( _model._timeSetNumber.empty() )
00944     return 1;
00945   int ts = _ATOI( _model._timeSetNumber );
00946   map< int, _TimeSet >::const_iterator its = _timeSets.find( ts );
00947   if ( its == _timeSets.end() )
00948     throw MEDEXCEPTION(STRING() << "Invalid format of Case file " << _fileName
00949                        << "\n Inexistent time set number of a model" );
00950   return its->second._times.size();
00951 }
00952 
00953 //================================================================================
00959 //================================================================================
00960 
00961 void _CaseFileDriver::setDataFileName(const int                   meshIndex,
00962                                       ENSIGHT_MESH_RDONLY_DRIVER* meshDriver)
00963 {
00964   if ( _blocked || checkWasRead())
00965     return;
00966   isToIgnore( meshDriver ); // remeber
00967 
00968   meshDriver->_dataFileName    = _directory + FILE_SEPARATOR + _model._fileName;
00969   meshDriver->_indexInDataFile = fixWildCardName( meshIndex,
00970                                                   _model._timeSetNumber,
00971                                                   _model._fileSetNumber,
00972                                                   meshDriver->_dataFileName,
00973                                                   meshDriver->_time);
00974   meshDriver->_isGoldFormat    = ( _format == ENSIGHT_GOLD );
00975   meshDriver->_transientMode   = ( !_model._timeSetNumber.empty() );
00976   meshDriver->_singleFileMode  = ( !_fileSets.empty() );
00977   meshDriver->_imedMapKey      = STRING(_fileName)<<":"<<meshIndex;
00978 
00979   GMESH* ptrMesh = meshDriver->getMesh();
00980   ptrMesh->setName(STRING("EnSight mesh ") << meshIndex);
00981 }
00982 
00983 //================================================================================
00987 //================================================================================
00988 
00989 int  _CaseFileDriver::getNbVariables() const
00990 {
00991   return _variables.empty() ? 0 : _variables.rbegin()->first;
00992 }
00993 
00994 //================================================================================
00998 //================================================================================
00999 
01000 int _CaseFileDriver::getNbVarSteps(const int variableIndex)
01001 {
01002   if ( _blocked || checkWasRead() )
01003     return 0;
01004 
01005   map< int, _Variable>::const_iterator ivar = _variables.find( variableIndex );
01006   if ( ivar == _variables.end() ) {
01007     // it can be index of real part of complex variable
01008     ivar = _variables.find( variableIndex+1 );
01009     if ( ivar == _variables.end() || !contains( "complex", ivar->second._type.c_str() )) {
01010       throw MEDEXCEPTION(STRING( "_CaseFileDriver::getNbVarSteps(): invalid variable index: ")
01011                          << variableIndex);
01012     }
01013   }
01014   const _Variable & var = ivar->second;
01015   if ( var._timeSetNumber.empty() )
01016     return 1;
01017 
01018   const _TimeSet & ts = _timeSets[ _ATOI( var._timeSetNumber)];
01019   return ts._times.size();
01020 }
01021 
01022 //================================================================================
01026 //================================================================================
01027 
01028 int _CaseFileDriver::getVariableIndex(const string & varName) const
01029 {
01030   if ( _blocked || checkWasRead() )
01031     return 0;
01032 
01033   map< int, _Variable>::const_iterator ivar = _variables.begin();
01034   for ( ; ivar != _variables.end(); ++ivar )
01035   {
01036     if ( ivar->second._name == varName ) {
01037       if ( contains( "complex", ivar->second._type.c_str() ))
01038         return ivar->first - 1; // real part of complex variable
01039       return ivar->first;
01040     }
01041   }
01042   // maybe varName is "<true_varName>_Im"
01043   size_t _ImBeg = varName.size() - 3;
01044   if ( varName[ _ImBeg + 0 ] == '_' &&
01045        varName[ _ImBeg + 1 ] == 'I' &&
01046        varName[ _ImBeg + 2 ] == 'm' )
01047   {
01048     int i = getVariableIndex( varName.substr( 0, _ImBeg ));
01049     return ( i ? i + 1 : i ); // getVariableIndex() returns index for a real part
01050   }
01051   return 0;
01052 }
01053 
01054 //================================================================================
01058 //================================================================================
01059 
01060 int _CaseFileDriver::setDataFileName(const int                    varIndex,
01061                                      const int                    stepIndex,
01062                                      ENSIGHT_FIELD_RDONLY_DRIVER* fieldDriver)
01063 {
01064   const char* LOC = "_CaseFileDriver::setDataFileName(): ";
01065   if ( _blocked || checkWasRead() )
01066     return 0;
01067   isToIgnore( fieldDriver ); // remeber
01068 
01069   map< int, _Variable>::iterator ivar = _variables.find( varIndex );
01070   if ( ivar == _variables.end() ) {
01071     // it can be index of real part of complex variable
01072     ivar = _variables.find( varIndex+1 );
01073     if ( ivar == _variables.end() || !contains( "complex", ivar->second._type.c_str() ))
01074       throw MEDEXCEPTION(LOCALIZED(STRING(LOC) << "invalid variable index: " << varIndex));
01075   }
01076   _Variable & var = ivar->second;
01077 
01078   const bool isComplex = contains( "complex", var._type.c_str() );
01079   const bool isImaginary = ( isComplex && varIndex == ivar->first );
01080 
01081   // complex scalar per element:    [ts] [fs] description Re_fn   Im_fn freq
01082   // complex scalar per node:       [ts] [fs] description Re_fn   Im_fn freq
01083   // complex vector per element:    [ts] [fs] description Re_fn   Im_fn freq
01084   // complex vector per node:       [ts] [fs] description Re_fn   Im_fn freq
01085   // constant per case file:        [ts]      description cvfilename
01086   // constant per case:             [ts]      description const_value(s)
01087   // scalar per element:            [ts] [fs] description filename
01088   // scalar per measured node:      [ts] [fs] description filename
01089   // scalar per node:               [ts] [fs] description filename
01090   // tensor asym per element:       [ts] [fs] description filename
01091   // tensor asym per node:          [ts] [fs] description filename
01092   // tensor symm per element:       [ts] [fs] description filename
01093   // tensor symm per node:          [ts] [fs] description filename
01094   // vector per element:            [ts] [fs] description filename
01095   // vector per measured node:      [ts] [fs] description filename
01096   // vector per node:               [ts] [fs] description filename
01097 
01098   FIELD_* field = fieldDriver->getField();
01099 
01100   // field name
01101   if ( field->getName().empty() ) {
01102     if ( isImaginary )
01103       field->setName( var._name + "_Im" );
01104     else
01105       field->setName( var._name );
01106   }
01107   // nb of components
01108   list<string> type_parts;
01109   _ASCIIFileReader::split( var._type, type_parts );
01110   string type1 = type_parts.front(); type_parts.pop_front();
01111   string type2 = type_parts.front(); type_parts.pop_front();
01112   int nbComponents = 1;
01113   if ( type1 == "vector" || type2 == "vector" )
01114     nbComponents = 3;
01115   else if ( type1 == "tensor" )
01116     nbComponents = ( type2 == "symm" ) ? 6 : 9;
01117   field->setNumberOfComponents( nbComponents );
01118 
01119   // component names
01120   vector<string> compNames( nbComponents );
01121   switch ( nbComponents ) {
01122   case 1:
01123     compNames[0] = type1;
01124     break;
01125   case 3: {
01126     const char* xyz[3] = { "X comp","Y comp","Z comp" };
01127     compNames.assign(xyz, xyz+3);
01128     break;
01129   }
01130   case 6: {
01131     const char* xyz[6] = { "11 comp", "22 comp", "33 comp","12 comp", "13 comp", "23 comp" };
01132     compNames.assign(xyz, xyz+6);
01133     break;
01134   }
01135   case 9: {
01136     const char* xyz[9] = { "11 comp", "12 comp", "13 comp", "21 comp", "22 comp", "23 comp",
01137                            "31 comp", "32 comp", "33 comp" };
01138     compNames.assign(xyz, xyz+9);
01139     break;
01140   }}
01141   field->setComponentsNames( & compNames[0] );
01142 
01143   // componet units
01144   vector<UNIT> units( nbComponents );
01145   vector<string> unitS( nbComponents ), descriptions( nbComponents );
01146   field->setComponentsUnits(&units[0]);
01147   field->setMEDComponentsUnits(&unitS[0]);
01148   field->setComponentsDescriptions(&descriptions[0]);
01149 
01150   // support type
01151   SUPPORT* sup = const_cast<SUPPORT*>( field->getSupport());
01152   if ( !sup ) {
01153     field->setSupport( sup = new SUPPORT );
01154     sup->removeReference(); // sup belongs to field
01155   }
01156   medEntityMesh entity = ( type_parts.back() == "node" ) ? MED_NODE : MED_CELL;
01157   sup->setEntity( entity );
01158 
01159   // data file name etc.
01160   list<string> fileData_parts;
01161   _ASCIIFileReader::split( var._fileNameOrData, fileData_parts );
01162   if ( isImaginary )
01163     fieldDriver->_dataFileName  = _directory + FILE_SEPARATOR + *(++fileData_parts.begin());
01164   else
01165     fieldDriver->_dataFileName  = _directory + FILE_SEPARATOR + fileData_parts.front();
01166   fieldDriver->_indexInDataFile = fixWildCardName( stepIndex,
01167                                                    var._timeSetNumber,
01168                                                    var._fileSetNumber,
01169                                                    fieldDriver->_dataFileName,
01170                                                    fieldDriver->_time);
01171   fieldDriver->_isGoldFormat    = ( _format == ENSIGHT_GOLD );
01172   fieldDriver->_transientMode   = ( !var._timeSetNumber.empty() );
01173   fieldDriver->_singleFileMode  = ( !_fileSets.empty() );
01174 
01175   if ( type1 == "constant" ) {
01176     if ( type_parts.back() == "file" ) {
01177       // append constant values from cvfilename to fileData_parts
01178       string cvfilename = _directory + FILE_SEPARATOR + fileData_parts.back();
01179       _ASCIIFileReader cvfile( cvfilename );
01180       fileData_parts.pop_back();
01181       while ( !cvfile.eof() )
01182         fileData_parts.push_back( cvfile.getWord() );
01183     }
01184     if ( (int)fileData_parts.size() < stepIndex )
01185       throw MEDEXCEPTION(LOCALIZED(STRING(LOC) << "can't find value for step " << stepIndex
01186                                    << " of " << var._type << " " << var._name));
01187     list<string>::iterator value = fileData_parts.begin();
01188     advance( value, stepIndex-1 );
01189     fieldDriver->setConstantValue( *value );
01190   }
01191 
01192   // mesh data
01193   int meshIndex = 1;
01194   if ( _model._fileName.find('*') != _model._fileName.npos ) {
01195     _TimeSet& ts = _timeSets[ _ATOI( _model._timeSetNumber )];
01196     vector<string>::iterator t = find( ts._times.begin(), ts._times.end(), fieldDriver->_time );
01197     if ( t != ts._times.end() )
01198       meshIndex += distance( ts._times.begin(), t );
01199   }
01200   fieldDriver->_imedMapKey = STRING(_fileName) << ":" << meshIndex;
01201 
01202   // time
01203   if ( fieldDriver->_transientMode ) {
01204     field->setTime( _ATOF( fieldDriver->_time ));
01205     //field->setOrderNumber( stepIndex );
01206     field->setIterationNumber( stepIndex );
01207   }
01208   return meshIndex;
01209 }
01210 
01211 //================================================================================
01215 //================================================================================
01216 
01217 bool _CaseFileDriver::checkWasRead() const throw (MEDEXCEPTION)
01218 {
01219   if ( _model._fileName.empty() )
01220     throw MEDEXCEPTION(STRING("Case file ") << _fileName << " has not been successfully read");
01221   return false;
01222 }
01223 
01224 //================================================================================
01228 //================================================================================
01229 
01230 int  _CaseFileDriver::fixWildCardName(const int      timeStep,
01231                                       const string & ts,
01232                                       const string & fs,
01233                                       string &       fileName,
01234                                       string &       time)
01235 {
01236   int indexInFile = 0;
01237   string fileIndex;
01238 
01239   STRING badFile("Invalid Case file ");
01240   badFile << _fileName << "\n";
01241 
01242   if ( !fs.empty() ) { // single file mode
01243     const _FileSet & fileSet = _fileSets[ _ATOI( fs ) ];
01244     if ( fileSet._fileIndex.empty() ) { // no file continuation
01245       indexInFile = timeStep;
01246     }
01247     else {
01248       list<int>::const_iterator   nbStepsIt = fileSet._nbStepsInFile.begin();
01249       list<string>::const_iterator fIndexIt = fileSet._fileIndex.begin();
01250       int nbSteps = 0;
01251       for ( ; nbStepsIt != fileSet._nbStepsInFile.end(); ++nbStepsIt ) {
01252         if ( nbSteps + *nbStepsIt <= timeStep )
01253           break;
01254         nbSteps += *nbStepsIt;
01255       }
01256       if ( nbStepsIt == fileSet._nbStepsInFile.end() )
01257         throw MEDEXCEPTION(LOCALIZED(badFile << "Cant'f find file index for time step " <<
01258                                      timeStep << " in file set " << fs ));
01259       indexInFile = timeStep - nbSteps;
01260       fileIndex   = *fIndexIt;
01261     }
01262   }
01263 
01264   string head, queue;
01265   _ASCIIFileReader::split( fileName, head, queue, '*' );
01266   int indexWidth = fileName.size() - head.size() - queue.size();
01267 
01268   if ( indexWidth > 0 || !ts.empty() || timeStep > 1 ) {
01269     int tsId = ts.empty() ? 1 : _ATOI( ts );
01270     const _TimeSet& timeSet = _timeSets[ tsId ];
01271     if ( timeStep > (int)timeSet._times.size() )
01272       throw MEDEXCEPTION(LOCALIZED(badFile << "Cant'f find time for time step " <<
01273                                    timeStep << " in time set " << ts ));
01274     time = timeSet._times[ timeStep-1 ];
01275     if ( timeStep-1 < (int)timeSet._fileIndex.size()  )
01276       fileIndex = timeSet._fileIndex[ timeStep-1 ];
01277     if ( !indexInFile )
01278       indexInFile = 1;
01279   }
01280       
01281   if ( indexWidth > 0 )
01282   {
01283     if ( fileIndex.empty() ) {
01284       throw MEDEXCEPTION(LOCALIZED(badFile << "Can't find file index for time step " <<
01285                                    timeStep << " in time set <" << ts <<
01286                                    "> and file set <" << fs << ">"));
01287     }
01288     if ( indexWidth ==  (int)fileIndex.size() ) {
01289       fileName = head + fileIndex + queue;
01290     }
01291     else {
01292       fileName = (STRING(head) << setw(indexWidth) << setfill('0') << fileIndex << queue);
01293     }
01294   }
01295   return indexInFile;
01296 }
01297 
01298 //================================================================================
01302 //================================================================================
01303 
01304 void _CaseFileDriver::addMesh(const ENSIGHT_MESH_WRONLY_DRIVER* meshDriver)
01305 {
01306   if ( _blocked )
01307     return;
01308 
01309   _meshDrivers.push_back( const_cast<ENSIGHT_MESH_WRONLY_DRIVER*>( meshDriver ));
01310 
01311   if ( _format == ENSIGHT_6 )
01312   {
01313     const GMESH* mesh = _meshDrivers.back()->getMesh();
01314     if ( mesh->getNumberOfElements(MED_CELL, MED_POLYGON) > 0 ||
01315          mesh->getNumberOfElements(MED_FACE, MED_POLYGON) > 0 ||
01316          mesh->getNumberOfElements(MED_CELL, MED_POLYHEDRA) > 0 )
01317       throw MEDEXCEPTION
01318         ( compatibilityPb(STRING("Can't write mesh <") << mesh->getName() <<
01319                           "> since Ensight6 format does not support poly elements,"
01320                           " use Ensight Gold format instead: call "
01321                           "setEnSightFormatForWriting( ENSIGHT_GOLD )"));
01322   }
01323 
01324   isToIgnore( meshDriver ); // remeber
01325 }
01326 
01327 //================================================================================
01331 //================================================================================
01332 
01333 void _CaseFileDriver::addField(const ENSIGHT_FIELD_WRONLY_DRIVER * theFieldDriver)
01334 {
01335   if ( _blocked )
01336     return;
01337 
01338   ENSIGHT_FIELD_WRONLY_DRIVER * fieldDriver =
01339     const_cast<ENSIGHT_FIELD_WRONLY_DRIVER*>( theFieldDriver );
01340 
01341   FIELD_* field = fieldDriver->getField();
01342 
01343   STRING problem;
01344   if ( field->getNumberOfValues() == 0 )
01345     problem << "getNumberOfValues() == 0";
01346   else if ( field->getGaussPresence() )
01347     problem << compatibilityPb("Gauss points are not supported by EnSight v8");
01348   else if ( !field->getSupport() )
01349     problem << "it has NULL support";
01350 
01351   switch ( field->getNumberOfComponents() ) {
01352   case 1:
01353   case 3:
01354   case 6:
01355   case 9: break; // ok, supported
01356   case 2:
01357     if ( const GMESH* mesh = field->getSupport()->getMesh() )
01358       if ( mesh->getSpaceDimension() == 2 )
01359         break; // we add one component to both mesh and field
01360   default:
01361     problem <<
01362       compatibilityPb(STRING("it has ") << field->getNumberOfComponents()
01363                       << " components but only 1,3,6 and 9 components are supported by EnSight");
01364   }
01365   if ( !problem.empty() )
01366     throw MEDEXCEPTION(STRING("Can't write field <") << field->getName() <<
01367                        "> to EnSight: " << problem);
01368 
01369   string fieldName = fieldDriver->getFieldName();
01370   if ( fieldName.empty() )
01371     fieldName = field->getName();
01372   if ( fieldName.empty() )
01373     fieldName = STRING("med_field_")<<_fieldDrivers.size();
01374   else { // replace illegal characters
01375     string::size_type pos = fieldName.find_first_of( ILLEGAL_FIELD_NAME_CHARACTERS );
01376     while ( pos != fieldName.npos ) {
01377       fieldName[ pos ] = '_';
01378       pos = fieldName.find_first_of( ILLEGAL_FIELD_NAME_CHARACTERS );
01379     }
01380   }
01381     
01382   _fieldDrivers[ fieldName ].push_back( fieldDriver );
01383 
01384   isToIgnore( fieldDriver ); // remeber
01385 }
01386 
01387 //================================================================================
01391 //================================================================================
01392 
01393 void _CaseFileDriver::write() throw (MEDEXCEPTION)
01394 {
01395   if ( _blocked )
01396     return;
01397 
01398   // Make case file data from added drivers
01399 
01400   bool dataIsRead = !_model._fileName.empty();
01401   if ( !dataIsRead && _meshDrivers.empty() )
01402     throw MEDEXCEPTION("no mesh to write into Case file");
01403 
01404   const int defaultNbDigits = 3; // in file index
01405 
01406   string path, name, ext;
01407   _ASCIIFileReader::split( _fileName, path, name, FILE_SEPARATOR, /*fromBack=*/true);
01408   _ASCIIFileReader::split( name, name, ext, '.', /*fromBack=*/true);
01409   if ( name.empty())
01410     name = ext; // _fileName: "path/.name"
01411 
01412   list<ENSIGHT_MESH_WRONLY_DRIVER*>::iterator mDrv = _meshDrivers.begin();
01413   TFieldDriversByName::iterator               fDrv = _fieldDrivers.begin();
01414 
01415   map< string, string > fileToRenameTo;
01416 
01417   int i, nbOldMeshes = 0, nbNewMeshes = _meshDrivers.size();
01418 
01419   if ( nbNewMeshes > 0 )
01420   {
01421     if ( dataIsRead )
01422     {
01423       // A mesh is going to be added into an existing case file.
01424       // Check that number of parts is same in the existing model
01425       // and in the added ones
01426       string geoFileName     = _directory + FILE_SEPARATOR + _model._fileName;
01427       string realGeoFileName = geoFileName, time;
01428       fixWildCardName( 1,
01429                        _model._timeSetNumber,
01430                        _model._fileSetNumber,
01431                        realGeoFileName,
01432                        time);
01433       int nbParts = ENSIGHT_MESH_RDONLY_DRIVER::countParts(realGeoFileName,
01434                                                            !_model._fileSetNumber.empty());
01435       for ( ; mDrv != _meshDrivers.end(); ++mDrv )
01436       {
01437         int nbNewParts = (*mDrv)->nbPartsToWrite();
01438         if ( nbParts != nbNewParts )
01439           throw MEDEXCEPTION(compatibilityPb("Can't add a mesh ") << (*mDrv)->getMesh()->getName()
01440                              << "to " << _fileName << " as number of parts in the file "
01441                              "differs from number of parts going to be written");
01442       }
01443       if ( !_model._timeSetNumber.empty() && !_variables.empty() ) {
01444         // Make time set of the model independent of that of variables as
01445         // the number of time steps is apparently becoming different
01446         map< int, _Variable>::iterator ivar = _variables.begin();
01447         for ( ; ivar != _variables.end(); ++ivar ) {
01448           if ( ivar->second._timeSetNumber == _model._timeSetNumber ) {
01449             int tsNum    = _timeSets.rbegin()->first + 1;
01450             _TimeSet& ts = _timeSets[ tsNum ];
01451             ts._number   = tsNum;
01452             ts           = _timeSets[ _ATOI( _model._timeSetNumber )];
01453             _model._timeSetNumber = STRING(tsNum);
01454             break;
01455           }
01456         }
01457       }
01458       string::size_type digitPos = _model._fileName.find('*');
01459       bool isSeveralFiles = ( digitPos != _model._fileName.npos );
01460       int nbDigits = defaultNbDigits;
01461       if ( isSeveralFiles ) {
01462         nbDigits = 1;
01463         while ( _model._fileName[ ++digitPos ] == '*' )
01464           nbDigits++;
01465       }
01466       // Update time set and file set of the model 
01467       int nbMeshes;
01468       if ( _model._timeSetNumber.empty() ) {
01469         // old model is static, create a time set
01470         nbMeshes = nbNewMeshes + 1;
01471         int tsNum    = _timeSets.empty() ? 1 : _timeSets.rbegin()->first + 1;
01472         _TimeSet& ts = _timeSets[ tsNum ];
01473         ts._number   = tsNum;
01474         _model._timeSetNumber = STRING(tsNum);
01475         // fill the new time set
01476         ts._fileIndex.resize( nbMeshes );
01477         ts._times.resize    ( nbMeshes );
01478         for ( i = 0; i < nbMeshes; ++i ) {
01479           ts._fileIndex[ i ] = (STRING() << setw(nbDigits) << setfill('0') << i);
01480           ts._times    [ i ] = STRING(i);
01481         }
01482         // not to create equal time sets
01483         map< int, _TimeSet >::iterator its, tsEnd = _timeSets.end();
01484         for ( --tsEnd, its = _timeSets.begin(); its != tsEnd; ++its ) {
01485           if ( ts == its->second ) {
01486             _model._timeSetNumber = STRING( its->first );
01487             _timeSets.erase( tsEnd );
01488             break;
01489           }
01490         }
01491       }
01492       else {
01493         // old model is transient, add times and file indices for new meshes
01494         _TimeSet& ts = _timeSets[ _ATOI( _model._timeSetNumber )];
01495         nbOldMeshes = ts._times.size();
01496         nbMeshes = nbNewMeshes + nbOldMeshes;
01497         ts._times.resize( nbMeshes );
01498         double time = 1. + _ATOF( ts._times[ nbOldMeshes-1 ] );
01499         for ( i = nbOldMeshes; i < nbMeshes; ++i, time+=1. )
01500           ts._times[ i ] = STRING( time );
01501         if ( _model._fileSetNumber.empty() ) { // multi-file mode
01502           ts._fileIndex.resize( nbMeshes, string(nbDigits,'0'));
01503           i = nbOldMeshes;
01504           int index = 1 + _ATOI( ts._fileIndex[ i-1 ] );
01505           for ( ; i < nbMeshes; ++i, ++index )
01506             ts._fileIndex[ i ] = (STRING() << setw(nbDigits) << setfill('0') << index);
01507         }
01508         else { // single-file mode
01509           _FileSet & fs = _fileSets[ _ATOI( _model._fileSetNumber )];
01510           for ( i = 0; i < nbNewMeshes; ++i )
01511             fs._nbStepsInFile.push_back( 1 );
01512           int index = 1;
01513           if ( fs._fileIndex.empty() )
01514             fs._fileIndex.push_back(string(nbDigits,'0'));
01515           else
01516             index += _ATOI( fs._fileIndex.back() );
01517           for ( i = fs._fileIndex.size(); i < nbMeshes; ++i, ++index )
01518             ts._fileIndex[ i ] = (STRING() << setw(3) << setfill('0') << index);
01519         }
01520       }
01521       // file of the old model is to be renamed
01522       if ( !isSeveralFiles ) {
01523         _model._fileName += string(nbDigits,'*');
01524         fileToRenameTo[ geoFileName ] = geoFileName + string(nbDigits,'0');
01525       }
01526     }
01527     else if ( nbNewMeshes > 1 )
01528     {
01529       // Store meshes into a new case file: create a time set
01530       int tsNum    = _timeSets.empty() ? 1 : _timeSets.rbegin()->first + 1;
01531       _TimeSet& ts = _timeSets[ tsNum ];
01532       ts._number   = tsNum;
01533       _model._timeSetNumber = STRING(tsNum);
01534       _model._fileName      = name + ".geo" + string(defaultNbDigits, '*');
01535       // fill the new time set
01536       ts._fileIndex.resize( nbNewMeshes );
01537       ts._times.resize    ( nbNewMeshes );
01538       for ( i = 0; i < nbNewMeshes; ++i ) {
01539         ts._fileIndex[ i ] = (STRING() << setw(defaultNbDigits) << setfill('0') << i);
01540         ts._times    [ i ] = STRING(i);
01541       }
01542     }
01543     else {
01544       // One mesh in a new file
01545       _model._fileName = name + ".geo";
01546     }
01547 
01548     // Set data to mesh drivers
01549     i = nbOldMeshes + 1;
01550     for ( mDrv = _meshDrivers.begin(); mDrv != _meshDrivers.end(); ++mDrv, ++i )
01551     {
01552       _CaseFileDriver_User* meshDriver = (*mDrv);
01553       meshDriver->_dataFileName    = _directory + FILE_SEPARATOR + _model._fileName;
01554       meshDriver->_indexInDataFile = fixWildCardName( i,
01555                                                       _model._timeSetNumber,
01556                                                       _model._fileSetNumber,
01557                                                       meshDriver->_dataFileName,
01558                                                       meshDriver->_time);
01559       meshDriver->_isGoldFormat    = ( _format == ENSIGHT_GOLD );
01560       meshDriver->_transientMode   = ( meshDriver->_indexInDataFile > 0 );
01561       meshDriver->_singleFileMode  = ( !_fileSets.empty() );
01562       meshDriver->_imedMapKey      = STRING(_fileName)<<":"<<i;
01563     }
01564   }
01565 
01566   typedef map< double, ENSIGHT_FIELD_WRONLY_DRIVER* > FDriverByDouble;
01567 
01568   //bool isVarsRead = ( !_variables.empty() );
01569   for ( ; fDrv != _fieldDrivers.end(); ++fDrv )
01570   {
01571     const string &                       fieldName = fDrv->first;
01572     list< ENSIGHT_FIELD_WRONLY_DRIVER* > & drivers = fDrv->second;
01573 
01574     int nbNewSteps = drivers.size();
01575 
01576     // find out by which parameter fields differ and sort them by the parameter
01577     FDriverByDouble timeMap, iterMap, orderMap;
01578     list< ENSIGHT_FIELD_WRONLY_DRIVER* >::iterator drv;
01579     for ( drv = drivers.begin(); drv != drivers.end(); ++drv ) {
01580       FIELD_* field = (*drv)->getField();
01581       double time = field->getTime();
01582       int    iter = field->getIterationNumber();
01583       int    ordr = field->getOrderNumber();
01584       timeMap.insert  ( make_pair( time, *drv ));
01585       iterMap.insert  ( make_pair( iter, *drv ));
01586       orderMap.insert ( make_pair( ordr, *drv ));
01587     }
01588     FDriverByDouble * sortedDrivers;
01589     FDriverByDouble::iterator tDrv;
01590     if ( (int)timeMap.size() == nbNewSteps )
01591       sortedDrivers = & timeMap;
01592     else if ( (int)iterMap.size() == nbNewSteps )
01593       sortedDrivers = & iterMap;
01594     else if ( (int)orderMap.size() == nbNewSteps )
01595       sortedDrivers = & orderMap;
01596     else {
01597       timeMap.clear();
01598       sortedDrivers = & timeMap;
01599       for ( drv = drivers.begin(); drv != drivers.end(); ++drv ) {
01600         double time = (*drv)->getField()->getTime();
01601         if ( ! timeMap.insert( make_pair( time, *drv )).second )
01602           timeMap.insert( make_pair( timeMap.rbegin()->first + 1., *drv ));
01603       }
01604     }
01605 
01606 //     if ( isVarsRead ) {
01607 //       int iVar = getVariableIndex( fieldName );
01608 //       if ( iVar > 0 ) {
01609 //         // A variable with fieldName already exists,
01610 //         // add more time steps to it
01611 //         _Variable& var = _variables[ iVar ];
01612 //         _TimeSet& ts = _timeSets[ _ATOI( var._timeSetNumber )];
01613 //         int nbOldSteps = ts._times.size();
01614 //       }
01615 //     }
01616     FIELD_* field = drivers.front()->getField();
01617     int varNum = _variables.size() + 1;
01618     _Variable& var = _variables[ varNum ];
01619     var._name = fieldName;
01620     switch ( field->getNumberOfComponents() ) {
01621     case 1: var._type = "scalar "; break;
01622     case 2: var._type = "vector "; break;// we add one component to a vector in 2d space
01623     case 3: var._type = "vector "; break;
01624     case 6: var._type = "tensor symm "; break;
01625     case 9: var._type = "tensor asym "; break;
01626     }
01627     if ( field->getSupport()->getEntity() == MED_NODE )
01628       var._type += "per node";
01629     else
01630       var._type += "per element";
01631     var._fileNameOrData = name + "." + fieldName;
01632 
01633     // always create Time set to store time
01634     int nbDigits = defaultNbDigits;
01635     int tsNum = _timeSets.empty() ? 1 : _timeSets.rbegin()->first + 1;
01636     var._timeSetNumber = STRING( tsNum );
01637     _TimeSet & ts = _timeSets[ tsNum ];
01638     ts._number    = tsNum;
01639     ts._fileIndex.resize( nbNewSteps );
01640     ts._times.resize    ( nbNewSteps );
01641     tDrv = sortedDrivers->begin();
01642     for ( i = 0; tDrv != sortedDrivers->end(); ++tDrv, ++i ) {
01643       ts._times    [ i ] = (STRING( tDrv->first ));
01644       ts._fileIndex[ i ] = (STRING() << setw(nbDigits) << setfill('0') << i);
01645     }
01646     if ( nbNewSteps > 1 )
01647       var._fileNameOrData += string( nbDigits, '*' );
01648     else
01649       ts._fileIndex.clear();
01650     // not to create equal time sets
01651     map< int, _TimeSet >::iterator its, tsEnd = _timeSets.end();
01652     for ( --tsEnd, its = _timeSets.begin(); its != tsEnd; ++its ) {
01653       if ( ts == its->second ) {
01654         tsNum = its->first;
01655         var._timeSetNumber = STRING( tsNum );
01656         _timeSets.erase( tsEnd );
01657         break;
01658       }
01659     }
01660     tDrv = sortedDrivers->begin();
01661     for ( i = 1; tDrv != sortedDrivers->end(); ++tDrv, ++i ) {
01662       _CaseFileDriver_User* fieldDriver = tDrv->second;
01663       fieldDriver->_dataFileName    = _directory + FILE_SEPARATOR + var._fileNameOrData;
01664       fieldDriver->_indexInDataFile = fixWildCardName( i,
01665                                                        var._timeSetNumber,
01666                                                        var._fileSetNumber,
01667                                                        fieldDriver->_dataFileName,
01668                                                        fieldDriver->_time);
01669       fieldDriver->_isGoldFormat    = ( _format == ENSIGHT_GOLD );
01670       fieldDriver->_transientMode   = ( fieldDriver->_indexInDataFile > 0 );
01671       fieldDriver->_singleFileMode  = ( !_fileSets.empty() );
01672     }
01673 
01674     // do not refer to time set if there is one step (issue 0020113)
01675     if ( nbNewSteps == 1 )
01676       var._timeSetNumber = "";
01677 
01678   } // loop on _fieldDrivers
01679 
01680   if ( nbOldMeshes + nbNewMeshes > 1 && !_variables.empty() )
01681   {
01682     // if there are variables on a transient model, model should not change much,
01683     // nb of entities in all parts with values must be same
01684     if ( nbOldMeshes == 0 ) {
01685       // TODO: check consistency
01686     }
01687     if ( toIgnoreIncompatibility() )
01688       cout << "Warning: EnSight file will be probably invalid " << _fileName << endl;
01689     else
01690       throw MEDEXCEPTION
01691         (compatibilityPb(STRING("EnSight file will be invalid if fields refer to "
01692                                 "the second mesh, which differ from the first one too much.\n"
01693                                 "If you are sure in data correctness, you can suppress "
01694                                 "this exception by calling setIgnoreIncompatibility(1)\n")
01695                          << _fileName));
01696   }
01697 
01698   // Write a file
01699 
01700   ofstream caseFile( _fileName.c_str(), ios::out );
01701   if ( !caseFile )
01702     throw MEDEXCEPTION(STRING("Can't open file for writing ") << _fileName);
01703 
01704   caseFile << "# generated by MEDMEM-to-EnSight driver" << endl << endl
01705            << "FORMAT" << endl
01706            << "type: " << (_format==ENSIGHT_GOLD ? "ensight gold" : "ensight") << endl
01707            << endl
01708            << "GEOMETRY"
01709            << endl
01710            << "model:\t"
01711            << _model._timeSetNumber << " "
01712            << _model._fileSetNumber << " "
01713            << _model._fileName << " \t"
01714            << _model._change_coords_only
01715            << endl << endl;
01716 
01717   // write VARIABLE section
01718   if ( !_variables.empty() )
01719   {
01720     caseFile << "VARIABLE" << endl;
01721 
01722     map< int, _Variable>::iterator ivar = _variables.begin();
01723     for ( ; ivar != _variables.end(); ++ivar )
01724     {
01725       _Variable& var = ivar->second;
01726       caseFile << var._type << ": \t"
01727                << var._timeSetNumber << " "
01728                << var._fileSetNumber << " \t"
01729                << var._name << " \t"
01730                << var._fileNameOrData << endl;
01731     }
01732     caseFile << endl;
01733   }
01734   // write TIME section
01735   if ( !_timeSets.empty() )
01736   {
01737     caseFile << "TIME" << endl;
01738 
01739     map< int, _TimeSet>::iterator its = _timeSets.begin();
01740     for ( ; its != _timeSets.end(); ++its )
01741     {
01742       _TimeSet & ts = its->second;
01743       caseFile << "time set:\t"        << ts._number << endl
01744                << "number of steps:\t" << ts._times.size() << endl;
01745       if ( !ts._fileIndex.empty() ) {
01746         STRING numbers( "filename numbers:" );
01747         for ( unsigned i = 0; i < ts._fileIndex.size(); ++i ) {
01748           if (int( numbers.size() + ts._fileIndex[i].size() + 2) > MAX_LINE_LENGTH ) {
01749             caseFile << numbers << endl;
01750             numbers = STRING();
01751           }
01752           numbers << " " << ts._fileIndex[i];
01753         }
01754         caseFile << numbers << endl;
01755       }
01756       STRING times( "time values:" );
01757       for ( unsigned i = 0; i < ts._times.size(); ++i ) {
01758         if (int( times.size() + ts._times[i].size() + 2 ) > MAX_LINE_LENGTH ) {
01759           caseFile << times << endl;
01760           times = STRING();
01761         }
01762         times << " " << ts._times[i];
01763       }
01764       caseFile << times << endl;
01765     }
01766   }
01767   // write FILE section
01768   if ( !_fileSets.empty() )
01769   {
01770     caseFile << "FILE" << endl;
01771 
01772     map< int, _FileSet >::iterator ifs = _fileSets.begin();
01773     for ( ; ifs != _fileSets.end(); ++ifs )
01774     {
01775       _FileSet & fs = ifs->second;
01776       caseFile << "file set: " << fs._number << endl;
01777 
01778       list<int>::iterator nbSteps = fs._nbStepsInFile.begin();
01779       list<string>::iterator fileIndex = fs._fileIndex.begin();
01780       for ( ; nbSteps != fs._nbStepsInFile.end(); ++nbSteps )
01781       {
01782         if ( fileIndex != fs._fileIndex.end() )
01783           caseFile << "filename index: " << *fileIndex++;
01784         caseFile << "number of steps: " << *nbSteps << endl;
01785       }
01786     }
01787   }
01788 
01789   caseFile.close();
01790 
01791 } // _CaseFileDriver::write()
01792 
01793 
01794 //================================================================================
01798 //================================================================================
01799 
01800 _CaseFileDriver_User::_CaseFileDriver_User(const string & caseFileName,
01801                                            med_mode_acces mode)
01802   : GENDRIVER( caseFileName, mode, ENSIGHT_DRIVER ), _imed(0)
01803 {
01804 }
01805 
01806 //================================================================================
01810 //================================================================================
01811 
01812 void _CaseFileDriver_User::merge( const GENDRIVER& driver)
01813 {
01814   const _CaseFileDriver_User* other = dynamic_cast< const _CaseFileDriver_User* >( &driver );
01815   if ( other ) {
01816     _dataFileName    = other->_dataFileName   ;
01817     _isGoldFormat    = other->_isGoldFormat   ;
01818     _transientMode   = other->_transientMode  ;  
01819     _singleFileMode  = other->_singleFileMode ; 
01820     _indexInDataFile = other->_indexInDataFile;
01821     _time            = other->_time           ;           
01822     _imed            = other->_imed           ;            
01823     _imedMapKey      = other->_imedMapKey     ;      
01824   }
01825 }
01826 
01827 //================================================================================
01831 //================================================================================
01832 
01833 bool _CaseFileDriver_User::isBinaryDataFile(const string& dataFileName)
01834 {
01835 #ifdef WNT
01836   int _file = ::_open (dataFileName.c_str(), _O_RDONLY|_O_BINARY);
01837 #else
01838   int _file = ::open (dataFileName.c_str(), O_RDONLY);
01839 #endif
01840   char buf[81];
01841   int nBytesRead = ::read (_file, buf, 80);
01842 
01843   bool isBinary = true;
01844 
01845   const char cBin[] = "C Binary";
01846   const char fBin[] = "Fortran Binary";
01847   if ( strncmp( buf, cBin, sizeof(cBin)-1) != 0 &&
01848        strncmp( buf, fBin, sizeof(fBin)-1) != 0 )
01849   {
01850     for ( int i = nBytesRead-1; i >= 0 && isBinary; --i )
01851       isBinary = ( buf[ i ] != '\n' );
01852   }
01853 
01854   ::close (_file);
01855 
01856   return isBinary;
01857 }
01858 
01859 //================================================================================
01863 //================================================================================
01864 
01865 int _CaseFileDriver_User::getPartNumber(const SUPPORT* support) const
01866 {
01867   bool isGroup = ( dynamic_cast<const GROUP*>( support ));
01868   bool isForField = ( dynamic_cast<const ENSIGHT_FIELD_DRIVER*>( this ));
01869   medEntityMesh entity = support->getEntity();
01870   const GMESH* mesh = support->getMesh();
01871 
01872   // for supports on all entities, reserve numbers corresponding to entity
01873   bool isOnAll = support->isOnAllElements();
01874   if (!isOnAll && mesh ) {
01875     int nbMeshElem = mesh->getNumberOfElements(entity, MED_ALL_ELEMENTS);
01876     int nbSuppElem = support->getNumberOfElements(MED_ALL_ELEMENTS);
01877     isOnAll = (  nbSuppElem == nbMeshElem );
01878   }
01879   if ( !isGroup ) {
01880     if ( !isOnAll )
01881       return 0;
01882     else if ( entity == MED_NODE )
01883       return 1 + MED_CELL; // all nodes are described with all CELLs
01884     else
01885       return 1 + entity;
01886   }
01887   if ( isForField && isOnAll ) {
01888     if ( entity == MED_NODE )
01889       return 1 + MED_CELL; // all nodes are described with all CELLs
01890     else
01891       return 1 + entity;
01892   }
01893   if ( !mesh )
01894     return 0;
01895 
01896   int partNum = MED_ALL_ENTITIES + 1;
01897   for ( int ent = MED_CELL; ent < MED_ALL_ENTITIES; ++ent ) {
01898     entity = (medEntityMesh) ent;
01899     int nbGroups = mesh->getNumberOfGroups(entity);
01900     if ( entity != support->getEntity() ) {
01901       partNum += nbGroups;
01902     }
01903     else {
01904       for ( int i=1; i<=nbGroups; ++i, ++partNum)
01905         if ( support == mesh->getGroup( entity, i ))
01906           return partNum;
01907     }
01908   }
01909   throw MED_EXCEPTION
01910     ( LOCALIZED( STRING("Can't find GROUP ") << support->getName() << " in its MESH"));
01911 
01912   return 0;
01913 }
01914 
01915 //================================================================================
01919 //================================================================================
01920 
01921 bool _CaseFileDriver_User::isToWriteEntity(const medEntityMesh entity,
01922                                            const GMESH*        mesh)
01923 {
01924   if ( entity == MED_NODE )
01925     return mesh->getNumberOfNodes() > 0;
01926 
01927   if ( mesh->getNumberOfElements( entity, MED_ALL_ELEMENTS ) < 1 )
01928     return false;
01929   if ( entity == MED_CELL )
01930     return true;
01931   int meshDim = mesh->getTypes(MED_CELL)[0] / 100;
01932   if ( entity == MED_FACE )
01933     return ( meshDim == 3 || meshDim == 5 );
01934   if ( entity == MED_EDGE )
01935     return ( meshDim == 2 || meshDim == 4 );
01936 
01937   return false;
01938 }
01939 
01940 //================================================================================
01944 //================================================================================
01945 
01946 void _CaseFileDriver_User::getSupportNodes(const SUPPORT* support, map<int, int> & nodeIds)
01947 {
01948   medEntityMesh entity = support->getEntity();
01949 
01950   const medConnectivity conType     = MED_NODAL;
01951   const medGeometryElement allGeoms = MED_ALL_ELEMENTS;
01952   const int * connectivity          = 0;
01953   const int * elemConnectivity      = 0;
01954   const int * index                 = 0;
01955   const int * number                = 0;
01956   int j;
01957 
01958   if ( support->isOnAllElements() )
01959   {
01960     if ( entity == MED_NODE ) { // all NODES
01961       int numberOfCell = support->getNumberOfElements(allGeoms);
01962       while ( numberOfCell ) {
01963         nodeIds.insert( nodeIds.begin(), make_pair( numberOfCell, numberOfCell ));
01964         --numberOfCell;
01965       }
01966     }
01967     else {
01968       const MESH* mesh = support->getMesh()->convertInMESH();
01969       int conLength = 0;
01970       connectivity = mesh->getConnectivity      (conType, entity, allGeoms);
01971       conLength    = mesh->getConnectivityLength(conType, entity, allGeoms);
01972       while ( conLength-- ) nodeIds[ *connectivity++ ];
01973       mesh->removeReference();
01974     }
01975     return;
01976   }
01977 
01978   if ( entity == MED_NODE )
01979   {
01980     number           = support->getNumber(MED_ALL_ELEMENTS);
01981     int numberOfCell = support->getNumberOfElements(MED_ALL_ELEMENTS);
01982     for (j=0; j < numberOfCell; j++)
01983       nodeIds.insert(nodeIds.end(), make_pair( number[j], j ));
01984     return;
01985   }
01986 
01987   number           = support->getNumber(MED_ALL_ELEMENTS);
01988   int numberOfCell = support->getNumberOfElements(MED_ALL_ELEMENTS);
01989   const MESH* mesh = support->getMesh()->convertInMESH();
01990   index        = mesh->getConnectivityIndex( MED_NODAL, entity);
01991   connectivity = mesh->getConnectivity( MED_NODAL, entity, MED_ALL_ELEMENTS);
01992   for ( j = 0; j < numberOfCell; ++j )
01993   {
01994     int elem = number[j];
01995     elemConnectivity   = connectivity + index[elem-1]-1;
01996     const int* connEnd = connectivity + index[elem]-1;
01997     while ( elemConnectivity < connEnd )
01998       nodeIds[ *elemConnectivity++ ];
01999   }
02000   mesh->removeReference();
02001 }
02002 
02003 //================================================================================
02008 //================================================================================
02009 
02010 void _CaseFileDriver_User::setInterData(_InterMed* imed )
02011 {
02012   theInterMedMap[ _imedMapKey ] = imed;
02013   if ( ENSIGHT_MESH_DRIVER* mDrv = dynamic_cast<ENSIGHT_MESH_DRIVER*>( this )) {
02014     imed->_medMesh = dynamic_cast<MESH*>( mDrv->getMesh() );
02015     imed->_isOwnMedMesh = false;
02016   }
02017   else
02018     imed->_medMesh = 0;
02019 }
02020 
02021 //================================================================================
02025 //================================================================================
02026 
02027 _InterMed* _CaseFileDriver_User::getInterData()
02028 {
02029   return _imed = getMeshData( _imedMapKey );
02030 }
02031 
02032 //================================================================================
02036 //================================================================================
02037 
02038 _SubPart* _CaseFileDriver_User::getSubPart(const _SubPartDesc & descriptor)
02039   throw (MEDEXCEPTION)
02040 {
02041   if ( !_imed )
02042     _imed = getMeshData( _imedMapKey );
02043 
02044   map< _SubPartDesc, _SubPart >::iterator descPart = 
02045     _imed->_subPartDescribed.find( descriptor );
02046 
02047   if ( descPart != _imed->_subPartDescribed.end() )
02048     return & descPart->second;
02049 
02050   if ( descriptor == _SubPartDesc::globalCoordDesc() )
02051     return 0; // if the mesh is structured, there are no global coordinates (EnSight 6)
02052 
02053   throw MEDEXCEPTION(LOCALIZED(STRING("No mesh info for part ") << descriptor.partNumber()
02054                                << " " << descriptor.typeName()));
02055 }
02056 
02057 //================================================================================
02061 //================================================================================
02062 
02063 _Support* _CaseFileDriver_User::getSupport(const _SupportDesc & descriptor,
02064                                            const medEntityMesh  entity)
02065   throw (MEDEXCEPTION)
02066 {
02067   const char* LOC = "_CaseFileDriver_User::getSupport(): ";
02068   if ( !_imed )
02069     _imed = getMeshData( _imedMapKey );
02070 
02071   _imed->treatGroupes();
02072 
02073   if ( _imed->_supportDescribed.empty() && !_imed->_subPartDescribed.empty() )
02074   {
02075     // fill _supportDescribed with _Support's corresponding to EnSight parts
02076     for (unsigned int i=0; i < _imed->groupes.size(); ++i)
02077     {
02078       _groupe& grp = _imed->groupes[i];
02079       if ( !grp.medGroup ) continue;
02080       
02081       vector<int> grpIndices(1,i);
02082       if ( !grp.groupes.empty() )
02083         grpIndices.assign( grp.groupes.begin(), grp.groupes.end());
02084 
02085       _SupportDesc supDescriptor;
02086       // look for a subpart for each _groupe
02087       vector<int>::iterator grIndex = grpIndices.begin(), grIndexEnd = grpIndices.end();
02088       for ( ; grIndex != grIndexEnd; ++grIndex )
02089       {
02090         map< _SubPartDesc, _SubPart >::iterator descSub;
02091         for ( descSub  = _imed->_subPartDescribed.begin();
02092               descSub != _imed->_subPartDescribed.end();
02093               ++descSub)
02094         {
02095           if ( descSub->second.myCellGroupIndex == *grIndex ) {
02096             supDescriptor.insert( descSub->first );
02097             break;
02098           }
02099         }
02100       }
02101       if ( supDescriptor.size() == grpIndices.size() ) {
02102         _Support & sup = _imed->_supportDescribed[ supDescriptor ];
02103         sup.setGroup( & grp );
02104       }
02105     }
02106   }
02107 
02108   // find the support by its description
02109   map< _SupportDesc, _Support >::iterator descSup =
02110     _imed->_supportDescribed.find( descriptor );
02111 
02112   // Create a new support
02113   if ( descSup == _imed->_supportDescribed.end() || !descSup->second.medSupport( entity ))
02114   {
02115     // create a _groupe composed of groups corresponding to subparts
02116     _imed->groupes.push_back(_groupe());
02117     _groupe& grp = _imed->groupes.back();
02118     grp.groupes.reserve( descriptor.size() );
02119 
02120     // to detect dimension change within a support group
02121     set<int> dimensions;
02122 
02123     // fill grp with sub-group indices
02124     _SupportDesc::const_iterator subPartDesc = descriptor.begin();
02125     for ( ; subPartDesc != descriptor.end(); ++subPartDesc )
02126     {
02127       const _SubPart* subPart = getSubPart(*subPartDesc);
02128       if ( !subPart )
02129         throw MEDEXCEPTION(LOCALIZED(STRING("No mesh info for ") << *subPartDesc));
02130 
02131       int groupIndex =
02132         (entity == MED_NODE) ? subPart->myNodeGroupIndex : subPart->myCellGroupIndex;
02133       if ( groupIndex < 1 ) {
02134         if ( entity == MED_NODE )
02135         {
02136           // make a _groupe of nodes
02137           _imed->groupes.push_back(_groupe());
02138           groupIndex = subPart->myNodeGroupIndex = _imed->groupes.size();
02139           _groupe & groupe = _imed->groupes.back();
02140           groupe.mailles.resize( subPart->myNbNodes );
02141 
02142           _maille ma( MED_POINT1, 1 );
02143           ma.sommets.resize( 1 );
02144           map< int, _noeud >::iterator n = subPart->myFirstNode;
02145           for (int i = 0; i < subPart->myNbNodes; ++i, ++n ) {
02146             ma.sommets[0] = n;
02147             ma.setOrdre( n->second.number );
02148             groupe.mailles[i] = _imed->insert(ma);
02149           }
02150         }
02151         else
02152         {
02153           throw MEDEXCEPTION(LOCALIZED(STRING("No cell info for ") << *subPartDesc));
02154         }
02155       }
02156       grp.groupes.push_back( groupIndex );
02157 
02158       // find out subpart dimension
02159       if ( entity != MED_NODE )
02160         dimensions.insert( _imed->groupes[ groupIndex-1 ].maille(0).dimensionWithPoly() );
02161     }
02162     // check if MEDMEM allows creating such a support
02163     if ( dimensions.size() > 1 )
02164       throw MEDEXCEPTION
02165         (compatibilityPb(LOC) << "can't create a SUPPORT for the field from "
02166          << _dataFileName << ", since it includes different mesh entities");
02167 
02168     ENSIGHT_MESH_RDONLY_DRIVER::makeGroup( grp, *_imed );
02169 
02170     // add _Support
02171     descSup = _imed->_supportDescribed.insert( make_pair( descriptor, _Support() )).first;
02172     _Support & sup = descSup->second;
02173     sup.setGroup( & grp );
02174       
02175   } // new SUPPORT creation
02176 
02177   _Support* sup = & descSup->second;
02178 
02179   // remove temporary mesh from med SUPPORT
02180   if ( _imed->_isOwnMedMesh )
02181   {
02182     if ( sup->medSupport( entity )->getMesh() == _imed->_medMesh )
02183       _imed->_medMesh->addReference(); // don't want _medMesh to die.
02184     sup->medSupport( entity )->setMesh( 0 );
02185     sup->medSupport( entity )->setMeshName( _imed->_medMesh->getName() );
02186   }
02187 
02188   return sup;
02189 }
02190 
02191 //================================================================================
02195 //================================================================================
02196 
02197 bool _CaseFileDriver_User::canOpenFile(const string&  fileName,
02198                                        med_mode_acces mode)
02199 {
02200   bool ok = false;
02201   if ( mode == WRONLY ) {
02202     fstream file( fileName.c_str(),
02203                   ios::app | ios_base::out ); // not to overwrite it, just to check
02204     ok = bool(file);
02205   }
02206   else {
02207     fstream file( fileName.c_str(), ios::in );
02208     ok = bool(file);
02209   }
02210   return ok;
02211 }
02212 
02213 //================================================================================
02217 //================================================================================
02218 
02219 _CaseFileDriver_User::~_CaseFileDriver_User()
02220 {
02221   if ( _imed )
02222     _imed->_nbUsers--;
02223   unregister( this );
02224 }
02225 
02226 //================================================================================
02230 //================================================================================
02231 
02232 bool contains( const char* what, const char* inString )
02233 {
02234   size_t whatLen = strlen( what );
02235   size_t inLen   = strlen( inString );
02236   return 
02237     ( search( inString, inString+inLen, what, what + whatLen) != inString+inLen );
02238 }
02239 
02240 //================================================================================
02244 //================================================================================
02245 
02246 void _InterMed::addSubPart(const _SubPart& theSubPart)
02247 {
02248   if ( _needSubParts ) {
02249     _SubPart & subPart = _subPartDescribed[ theSubPart.getDescriptor() ];
02250     subPart = theSubPart;
02251     if ( subPart.myCellGroupIndex > 0 ) {
02252       _groupe & groupe = this->groupes[ subPart.myCellGroupIndex-1 ];
02253       subPart.myFirstCell = groupe.mailles.begin();
02254     }
02255   }
02256 }
02257 //================================================================================
02261 //================================================================================
02262 
02263 _InterMed::~_InterMed()
02264 {
02265   if ( _isOwnMedMesh )
02266   {
02267     // remove MEDMEM groups not belonging to _medMesh
02268     for (unsigned int i=0; i < _intermediateMED::groupes.size(); ++i)
02269     {
02270       _groupe& grp = _intermediateMED::groupes[i];
02271       if ( !grp.medGroup ) continue;
02272       vector<GROUP*> groups = _medMesh->getGroups( grp.medGroup->getEntity() );
02273       if ( find( groups.begin(), groups.end(), grp.medGroup ) == groups.end() )
02274         grp.medGroup->removeReference();
02275     }
02276     if(_medMesh) _medMesh->removeReference();
02277     _medMesh=0;
02278   }
02279 }
02280 //================================================================================
02284 //================================================================================
02285 
02286 int _Support::getIndex( const pair<const int,_noeud>& inode)
02287 {
02288   if ( myNodeGroup->relocMap.empty() ) // on all and not self intersecting support
02289     return abs( inode.second.number );
02290 
02291   map<unsigned,int>::iterator ordreIndex = myNodeGroup->relocMap.find( abs( inode.second.number ));
02292   if ( ordreIndex == myNodeGroup->relocMap.end() )
02293     throw MEDEXCEPTION(LOCALIZED(STRING("No index found for ") << inode.second));
02294 //   map < int, int >::iterator numIndex = myNodeRelocMap.find( node->number );
02295 //   if ( numIndex == myNodeRelocMap.end() )
02296 //     throw MEDEXCEPTION(STRING("No index found for node ") << node->number);
02297 
02298   return ordreIndex->second;
02299 }
02300 
02301 //================================================================================
02305 //================================================================================
02306 
02307 int _Support::getIndex( const _groupe::TMaille& cell)
02308 {
02309   if ( myCellGroup->relocMap.empty() ) // on all and not self intersecting support
02310     return cell->ordre();
02311 
02312   map<unsigned,int>::iterator ordreIndex = myCellGroup->relocMap.find( cell->ordre() );
02313   if ( ordreIndex == myCellGroup->relocMap.end() )
02314     throw MEDEXCEPTION(LOCALIZED(STRING("No index found for ") << *cell));
02315 
02316   return ordreIndex->second;
02317 }
02318 
02319 //================================================================================
02323 //================================================================================
02324 
02325 // medGeometryElement _Support::getType( const pair<const int,_noeud>& node)
02326 // {
02327 //   return myNodeGroup->medGroup.getTypes[0];
02328 // }
02329 
02330 // //================================================================================
02331 // /*!
02332 //  * \brief Return med geom type for a subPart element
02333 //  */
02334 // //================================================================================
02335 
02336 // medGeometryElement _Support::getType( const _groupe::TMaille& cell)
02337 // {
02338 //   return cell->geometricType;
02339 // }
02340 
02341 //================================================================================
02345 //================================================================================
02346 
02347 void _Support::setGroup( _groupe* group )
02348 {
02349   if ( group->medGroup ) {
02350     if ( group->medGroup->getEntity() == MED_NODE )
02351       myNodeGroup = group;
02352     else
02353       myCellGroup = group;
02354   }
02355   else {
02356     throw MEDEXCEPTION(LOCALIZED("_Support::setGroup(): med GROUP is NULL"));
02357   }
02358 }
02359 
02360 //================================================================================
02364 //================================================================================
02365 
02366 SUPPORT* _Support::medSupport( medEntityMesh entity )
02367 {
02368   if ( entity == MED_NODE )
02369     return myNodeGroup ? myNodeGroup->medGroup : 0;
02370   else
02371     return myCellGroup ? myCellGroup->medGroup : 0;
02372 }
02373 
02374 //================================================================================
02378 //================================================================================
02379 
02380 std::ostream& operator << (std::ostream& os, const _SubPartDesc& desc)
02381 {
02382   if ( desc == _SubPartDesc::globalCoordDesc() )
02383     os << "'global coordinates'";
02384   else
02385     os << "<'part " << desc.partNumber() << "', '" << desc.typeName() << "'>";
02386   return os;
02387 }
02388 
02389 //================================================================================
02393 //================================================================================
02394 
02395 _ASCIIFileReader::_ASCIIFileReader(const string& fileName) throw (MEDEXCEPTION)
02396 {
02397 #ifdef WNT
02398   _file = ::_open (fileName.c_str(), _O_RDONLY|_O_BINARY);
02399 #else
02400   _file = ::open (fileName.c_str(), O_RDONLY);
02401 #endif
02402   if (_file >= 0)
02403   {
02404     _start = new char [BUFFER_SIZE];
02405     _ptr   = _start;
02406     _eptr  = _start;
02407   }
02408   else
02409   {
02410     throw MEDEXCEPTION(STRING("Can't read from ")<<fileName);
02411   }
02412   if ( eof() )
02413     throw MEDEXCEPTION(STRING("Empty file ")<<fileName);
02414 
02415   // there must be end-of-line in ASCII file
02416   char* ptr = _start + MAX_LINE_LENGTH;
02417   bool isASCII = false;
02418   while ( !isASCII && ptr >= _start )
02419     isASCII = (*ptr-- == '\n');
02420   _isWin = ( *ptr == '\r');
02421   if ( !isASCII )
02422     throw MEDEXCEPTION(STRING("Not ASCII file ")<<fileName);
02423 }
02424 
02425 //================================================================================
02429 //================================================================================
02430 
02431 bool _ASCIIFileReader::eof()
02432 {
02433   // Check the state of the buffer;
02434   // if there is too little left, read the next portion of data
02435   int nBytesRest = _eptr - _ptr;
02436   if (nBytesRest < 2 * MAX_LINE_LENGTH)
02437   {
02438     if (nBytesRest > 0) {
02439       char* tmpBuf = new char [nBytesRest];
02440       memcpy (tmpBuf, _ptr, nBytesRest);
02441       memcpy (_start, tmpBuf, nBytesRest);
02442       delete [] tmpBuf;
02443     } else {
02444       nBytesRest = 0;
02445     }
02446     _ptr = _start;
02447     const int nBytesRead = ::read (_file,
02448                                    &_start [nBytesRest],
02449                                    BUFFER_SIZE - nBytesRest);
02450     nBytesRest += nBytesRead;
02451     _eptr = &_start [nBytesRest];
02452 
02453     // skip spaces at file end
02454     if ( nBytesRest < MAX_LINE_LENGTH ) {
02455       while ( isspace( *_ptr )) _ptr++;
02456       nBytesRest = _eptr - _ptr;
02457     }
02458   }
02459   return nBytesRest < 1;
02460 }
02461 
02462 //================================================================================
02466 //================================================================================
02467 
02468 void _ASCIIFileReader::skip(int nbVals, int nbPerLine, int valWidth)
02469 {
02470   int nbLines = (nbVals + nbPerLine - 1) / nbPerLine;
02471   int width = nbVals * valWidth;
02472   skip( width, nbLines );
02473 }
02474 
02475 //================================================================================
02479 //================================================================================
02480 
02481 void _ASCIIFileReader::skip(int width, int nbLines)
02482 {
02483   width += nbLines; // to skip '\n'
02484   if ( _isWin )
02485     width += nbLines; // to skip '\r'
02486 
02487   _ptr += width;
02488   int nBytesRest = _eptr - _ptr;
02489   while ( nBytesRest < 0 ) {
02490     width = -nBytesRest;
02491     if ( eof() ) return;
02492     _ptr += width;
02493     nBytesRest = _eptr - _ptr;
02494   }
02495 }
02496 
02497 //================================================================================
02501 //================================================================================
02502 
02503 char* _ASCIIFileReader::getLine() throw (MEDEXCEPTION)
02504 {
02505   if ( eof() )
02506     throw MEDEXCEPTION("Unexpected EOF");
02507 
02508   // Check the buffer for the end-of-line
02509   char * ptr = _ptr;
02510   while (true)
02511   {
02512     // Check for end-of-the-buffer, the ultimate criterion for termination
02513     if (ptr >= _eptr)
02514     {
02515       //_eptr[-1] = '\0';
02516       _eptr[0] = '\0';
02517       break;
02518     }
02519     // seek the line-feed character
02520     if (ptr[0] == '\n')
02521     {
02522       if ( ptr > _start && // avoid "Invalid read" error by valgrind
02523            ptr[-1] == '\r')
02524         ptr[-1] = '\0';
02525       ptr[0] = '\0';
02526       ++ptr;
02527       break;
02528     }
02529     ++ptr;
02530   }
02531   // Output the result
02532   char * line = _ptr;
02533   _ptr = ptr;
02534 
02535   return line;
02536 }
02537 
02538 //================================================================================
02542 //================================================================================
02543 
02544 bool _ASCIIFileReader::lookAt( const char* text )
02545 {
02546   while ( isspace(*_ptr)) ++_ptr;
02547   return ( strncmp( _ptr, text, strlen( text )) == 0 );
02548 }
02549 
02550 //================================================================================
02554 //================================================================================
02555 
02556 string _ASCIIFileReader::getWord()
02557 {
02558   if ( eof() )
02559     return "";
02560 
02561   // skip spaces
02562   while ( isspace(*_ptr)) ++_ptr;
02563   if ( _ptr >= _eptr )
02564     return "";
02565 
02566   // skip not spaces
02567   char* word = _ptr++;
02568   while ( !isspace(*_ptr)) ++_ptr;
02569 
02570   return string( word, _ptr - word );
02571 }
02572 
02573 //================================================================================
02577 //================================================================================
02578 
02579 bool _ASCIIFileReader::isTimeStepBeginning()
02580 {
02581   if ( eof() ) throw MEDEXCEPTION(LOCALIZED("Unexpected EOF"));
02582 
02583   while ( isspace(*_ptr)) ++_ptr;
02584 
02585   if ( strncmp( _ptr, TIME_STEP_BEG, TIME_STEP_BEG_LEN ) != 0 )
02586     return false;
02587 
02588   _ptr += TIME_STEP_BEG_LEN;
02589   while ( isspace(*_ptr)) ++_ptr;
02590   return true;
02591 }
02592 
02593 //================================================================================
02597 //================================================================================
02598 
02599 bool _ASCIIFileReader::isTimeStepEnd()
02600 {
02601   if ( eof() ) return true;
02602 
02603   while ( isspace(*_ptr)) ++_ptr;
02604 
02605   if ( strncmp( _ptr, TIME_STEP_END, TIME_STEP_END_LEN ) != 0 )
02606     return false;
02607 
02608   _ptr += TIME_STEP_END_LEN;
02609   while ( isspace(*_ptr)) ++_ptr;
02610   return true;
02611 }
02612 
02613 
02614 //================================================================================
02618 //================================================================================
02619 
02620 int _ASCIIFileReader::split(const string& str,
02621                             string &      part1,
02622                             string &      part2,
02623                             const char    separator,
02624                             const bool    fromBack)
02625 {
02626   int nbParts = 0;
02627   string parts[2];
02628   const char* ptr1 = str.c_str();
02629   const char* back = ptr1 + str.size();
02630   for (nbParts = 0; nbParts < 2; ++nbParts ) {
02631     // skip spaces before the current part
02632     while ( isspace(*ptr1)) ++ptr1;
02633     if ( !*ptr1) break;
02634     // find end of the part and beginning of the next part
02635     const char* ptr2 = ptr1;
02636     const char* nextBeg = back;
02637     if ( nbParts > 0 ) {
02638       ptr2 = back;
02639     }
02640     else if ( fromBack ) {
02641       ptr2 = back;
02642       string::size_type pos = str.rfind( separator );
02643       if ( pos != str.npos ) {
02644         ptr2 = & str[ pos ];
02645         nextBeg = ptr2 + 1;
02646         if ( separator != ' ')
02647           while ( *nextBeg && *nextBeg == separator ) ++nextBeg;
02648       }
02649     }
02650     else if ( separator == ' ' ) {
02651       while ( *ptr2 && !isspace(*ptr2)) ++ptr2;
02652       if ( *ptr2 ) nextBeg = ptr2 + 1;
02653     }
02654     else {
02655       while ( *ptr2 && *ptr2 != separator ) ++ptr2;
02656       if ( *ptr2 ) {
02657         nextBeg = ptr2 + 1;
02658         while ( *nextBeg && *nextBeg == separator ) ++nextBeg;
02659       }
02660     }
02661     //if ( !*ptr2) --ptr2;
02662     // skip spaces after the current part
02663     while ( ptr2 > ptr1 && isspace(ptr2[-1])) --ptr2;
02664     parts[ nbParts ] = string( ptr1, ptr2-ptr1 );
02665     ptr1 = nextBeg;
02666   }
02667   part1 = parts[0];
02668   part2 = parts[1];
02669   return nbParts;
02670 }
02671 
02672 //================================================================================
02676 //================================================================================
02677 
02678 int _ASCIIFileReader::split(const string&       str,
02679                             list<string> &      parts,
02680                             const char          separator,
02681                             const bool          fromBack)
02682 {
02683   parts.clear();
02684   if ( str.empty() )
02685     return 0;
02686   int nbParts = 0;
02687   const char* ptr1 = str.c_str();
02688   const char* back = ptr1 + str.size();
02689   if ( fromBack ) {
02690     swap( ptr1, back );
02691     while (1) {
02692       // skip spaces after the current part
02693       while ( isspace(ptr1[-1])) --ptr1;
02694       if ( ptr1 <= back ) break;
02695       // find beginning of the part
02696       const char* ptr2 = ptr1 - 1;
02697       if ( separator == ' ' )
02698         while ( ptr2 > back && !isspace(ptr2[-1])) --ptr2;
02699       else
02700         while ( ptr2 > back && ptr2[-1] != separator ) --ptr2;
02701       //if ( !*ptr2) --ptr2;
02702       const char* sepPtr = ptr2;
02703       // skip spaces before the current part
02704       while ( isspace(*ptr2)) ++ptr2;
02705       parts.push_back( string( ptr2, ptr1-ptr2 ));
02706       ++nbParts;
02707       ptr1 = sepPtr - 1;
02708     }
02709   }
02710   else {
02711     while (1) {
02712       // skip spaces before the current part
02713       while ( isspace(*ptr1)) ++ptr1;
02714       if ( ptr1 >= back) break;
02715       // find end of the part
02716       const char* ptr2 = ptr1 + 1;
02717       if ( separator == ' ' )
02718         while ( *ptr2 && !isspace(*ptr2)) ++ptr2;
02719       else
02720         while ( *ptr2 && *ptr2 != separator ) ++ptr2;
02721       //if ( !*ptr2) --ptr2;
02722       const char* sepPtr = ptr2;
02723       // skip spaces after the current part
02724       while ( ptr2 > ptr1 && isspace(ptr2[-1])) --ptr2;
02725       parts.push_back( string( ptr1, ptr2-ptr1 ));
02726       ++nbParts;
02727       ptr1 = sepPtr + int( sepPtr < back );
02728     }
02729   }
02730   return nbParts;
02731 }
02732 
02733 //================================================================================
02737 //================================================================================
02738 
02739 bool _ASCIIFileReader::isDigit(const string& str, const bool real)
02740 {
02741   const char* s = str.c_str();
02742   if ( real ) {
02743     while ( *s ) {
02744       char c = *s++;
02745       if ( !isdigit(c) && c!='-' && c!='+' && c!='.' && c!=',' && c!='E' && c!='e')
02746         return false;
02747     }
02748   }
02749   else {
02750     while ( *s ) {
02751       if ( !isdigit( *s++ ))
02752         return false;
02753     }
02754   }
02755   return true;
02756 }
02757 
02758 //================================================================================
02762 //================================================================================
02763 
02764 _ASCIIFileReader::~_ASCIIFileReader()
02765 {
02766   if (_file >= 0)
02767   {
02768     ::close (_file);
02769     delete [] _start;
02770   }
02771 }
02772 
02773 //================================================================================
02777 //================================================================================
02778 
02779 _BinaryFileReader::_BinaryFileReader(const string& fileName) throw (MEDEXCEPTION)
02780   : _exception(STRING("Unexpected EOF ") << fileName), _mySwapBytes(false)
02781 {
02782 #ifdef WNT
02783   _file = ::_open (fileName.c_str(), _O_RDONLY|_O_BINARY);
02784 #else
02785   _file = ::open (fileName.c_str(), O_RDONLY);
02786 #endif
02787 
02788   if (_file < 0)
02789     throw MEDEXCEPTION(STRING("Can't read from ") << fileName);
02790 
02791   _maxPos = ::lseek( _file, 0, SEEK_END);
02792   _pos    = ::lseek( _file, 0, SEEK_SET);
02793 }
02794 
02795 //================================================================================
02799 //================================================================================
02800 
02801 _BinaryFileReader::~_BinaryFileReader()
02802 {
02803   if (_file >= 0)
02804     ::close (_file);
02805 }
02806 
02807 //================================================================================
02811 //================================================================================
02812 
02813 void _BinaryFileReader::rewind()
02814 {
02815   _pos = ::lseek( _file, 0, SEEK_SET);
02816 }
02817 
02818 //================================================================================
02822 //================================================================================
02823 
02824 int _BinaryFileReader::moreValuesAvailable() const
02825 {
02826   return (_maxPos - _pos) / sizeof(int); // believe that sizeof(int) == sizeof(float)
02827 }
02828 
02829 //================================================================================
02833 //================================================================================
02834 
02835 bool _BinaryFileReader::eof()
02836 {
02837   return _pos >= _maxPos;
02838 }
02839 
02840 //================================================================================
02844 //================================================================================
02845 
02846 void _BinaryFileReader::skip(int size) throw (MEDEXCEPTION)
02847 {
02848   if ( _pos + size > _maxPos )
02849     throw _exception;
02850   off_t newPos = ::lseek( _file, size, SEEK_CUR);
02851   if ( newPos < _pos + size )
02852     throw _exception;
02853   _pos = newPos;
02854 }
02855 
02856 //================================================================================
02860 //================================================================================
02861 
02862 void _BinaryFileReader::skipTimeStepBeginning() throw (MEDEXCEPTION)
02863 {
02864   bool tsbReached = false;
02865   while ( !tsbReached ) {
02866     TStrOwner line( getLine() );
02867     tsbReached = ( strncmp( line, TIME_STEP_BEG, TIME_STEP_BEG_LEN ) == 0 );
02868   }
02869 }
02870 
02871 //================================================================================
02875 //================================================================================
02876 
02877 _BinaryFileWriter::_BinaryFileWriter(const string& fileName)  throw (MEDEXCEPTION)
02878   : _exception(STRING("Can't write into ") << fileName)
02879 {
02880 #ifdef WNT
02881   _file = ::_open (fileName.c_str(), _O_WRONLY|_O_BINARY|_O_TRUNC);
02882 #else
02883   _file = ::open (fileName.c_str(), O_WRONLY|O_TRUNC); //length shall be truncated to 0
02884 #endif
02885 
02886   if (_file < 0)
02887     throw _exception;
02888 }
02889 
02890 //================================================================================
02894 //================================================================================
02895 
02896 _BinaryFileWriter::~_BinaryFileWriter()
02897 {
02898   if (_file >= 0)
02899     ::close (_file);
02900 }
02901 
02902 //================================================================================
02906 //================================================================================
02907 
02908 void _BinaryFileWriter::addString(const char* str) throw (MEDEXCEPTION)
02909 {
02910   size_t len = strlen( str );
02911   if ((int) len > MAX_LINE_LENGTH )
02912     throw MEDEXCEPTION
02913       (LOCALIZED(STRING("_BinaryFileWriter::addString(), too long string (>80):\n") << str));
02914 
02915   string buffer( str, len );
02916   // avoid "Syscall param write(buf) points to uninitialised byte(s)" error by valgrind
02917   buffer += string(MAX_LINE_LENGTH, ' ');
02918   buffer[ len ] = '\0';
02919   buffer[ MAX_LINE_LENGTH-1 ] = '\0'; // to have line-end within
02920 
02921   add( buffer.c_str(), MAX_LINE_LENGTH );
02922 }
02923 
02924 
02925 
02926 } // end namespace MEDMEM_ENSIGHT