src/csv_table_reader.cpp
//------------------------------------------------------------------------------
/*! \brief Process the CSV file looking for the given varName and route the data
 *         into the core.
 *
 *  The input stream will be reset to allow to processing multiple times from
 *  this reader.  Next the header row is read and searched to find the column
 *  which varName is contained in.  Then each row of the table is read.  Should the
 *  the first column be UNITS it will use the row to set the units string to pass
 *  along with read data to provide units checking.  Otherwise it will assume
 *  the first column is the time series index and consistent columns for each
 *  row. Each value will be routed through the core as rows are read.  Extra
 *  white space will be removed before sending the value into the core.
 *
 *  \param core A pointer to the model core to route data through.
 *  \param componentName The model component to set varName in.
 *  \param varName The variable name to look for in the CSV file and set.
 *  \exception h_exception For any I/O errors, improper formatting, and inability
 *                         to find varName.  Also any errors while trying to
 *                         setData will also be propagated.
 */
\brief Process the CSV file looking for the given varName and route the data
into the core.

The input stream will be reset to allow to processing multiple times from
this reader.  Next the header row is read and searched to find the column
which varName is contained in.  Then each row of the table is read.  Should the
the first column be UNITS it will use the row to set the units string to pass
along with read data to provide units checking.  Otherwise it will assume
the first column is the time series index and consistent columns for each
row. Each value will be routed through the core as rows are read.  Extra
white space will be removed before sending the value into the core.

\param core A pointer to the model core to route data through.
\param componentName The model component to set varName in.
\param varName The variable name to look for in the CSV file and set.
\exception h_exception For any I/O errors, improper formatting, and inability
to find varName.  Also any errors while trying to
setData will also be propagated.
\ brief Process the CSV file looking for the given varName and route the data into the core . The input stream will be reset to allow to processing multiple times from this reader . Next the header row is read and searched to find the column which varName is contained in . Then each row of the table is read . Should the the first column be UNITS it will use the row to set the units string to pass along with read data to provide units checking . Otherwise it will assume the first column is the time series index and consistent columns for each row . Each value will be routed through the core as rows are read . Extra white space will be removed before sending the value into the core . \ param core A pointer to the model core to route data through . \ param componentName The model component to set varName in . \ param varName The variable name to look for in the CSV file and set . \ exception h_exception For any I / O errors improper formatting and inability to find varName . Also any errors while trying to setData will also be propagated .
void CSVTableReader::process( Core* core, const string& componentName,
                             const string& varName ) throw ( h_exception )
{
    using namespace boost;
    try {
        tableInputStream.clear();
        tableInputStream.seekg( 0, ifstream::beg );
        lineNum = 0;
        string line;
        vector<string> row;
        string unitsLabel;
        size_t columnIndex = 0; 
        line = csv_getline();
        H_ASSERT( !line.empty(), "line empty" );
        split( row, line, is_any_of( "," ) );
        for( size_t col = 1; col < row.size() && columnIndex == 0; ++col ) {
            trim( row[ col ] );
            if( row[ col ] == varName ) {
                columnIndex = col;
            }
        }
        if( columnIndex == 0 ) {
            H_THROW( "Could not find a column for "+varName+" in "+fileName+" header="+line );
        }
        int lines_read = 0;
        while( !tableInputStream.eof() && tableInputStream.peek() != -1 ) {
            line = csv_getline();
            lines_read++;
            if( line.empty() || line[ 0 ] == '\r' ) {
                continue;
            }
            split( row, line, is_any_of( "," ) );
            trim( row[ 0 ] );
            trim( row[ columnIndex ] );
            if( row[ 0 ] == "UNITS" ) {
                unitsLabel = row[ columnIndex ];
            } else {
                double tseriesIndex = lexical_cast<double>( row[ 0 ] );
                if( !row[ columnIndex ].empty() ) {      
                    message_data data( row[ columnIndex ] );
                    data.date = tseriesIndex;
                    data.units_str = unitsLabel;
                    core->setData( componentName, varName, data );
                }
            }
        }
    } catch( ifstream::failure e ) {
        string errorStr = "I/O exception while processing "+fileName+" error: "+strerror(errno);
        H_THROW( errorStr );
    } catch( bad_lexical_cast& castException ) {
        H_THROW( "Could not convert index to double on line: "+lexical_cast<string>( lineNum )+", exception: "
                +castException.what() );
    }
}
void CSVTableReader :: process ( Core * core , const string & componentName , const string & varName ) throw ( h_exception ) { using namespace boost ; try { tableInputStream . clear ( ) ; tableInputStream . seekg ( 0 , ifstream :: beg ) ; lineNum = 0 ; string line ; vector < string > row ; string unitsLabel ; size_t columnIndex = 0 ; line = csv_getline ( ) ; H_ASSERT ( ! line . empty ( ) , " " ) ; split ( row , line , is_any_of ( " " ) ) ; for ( size_t col = 1 ; col < row . size ( ) && columnIndex == 0 ; ++ col ) { trim ( row [ col ] ) ; if ( row [ col ] == varName ) { columnIndex = col ; } } if ( columnIndex == 0 ) { H_THROW ( " " + varName + " " + fileName + " " + line ) ; } int lines_read = 0 ; while ( ! tableInputStream . eof ( ) && tableInputStream . peek ( ) != -1 ) { line = csv_getline ( ) ; lines_read ++ ; if ( line . empty ( ) || line [ 0 ] == ' \r ' ) { continue ; } split ( row , line , is_any_of ( " " ) ) ; trim ( row [ 0 ] ) ; trim ( row [ columnIndex ] ) ; if ( row [ 0 ] == " " ) { unitsLabel = row [ columnIndex ] ; } else { double tseriesIndex = lexical_cast < double > ( row [ 0 ] ) ; if ( ! row [ columnIndex ] . empty ( ) ) { message_data data ( row [ columnIndex ] ) ; data . date = tseriesIndex ; data . units_str = unitsLabel ; core -> setData ( componentName , varName , data ) ; } } } } catch ( ifstream :: failure e ) { string errorStr = " " + fileName + " " + strerror ( errno ) ; H_THROW ( errorStr ) ; } catch ( bad_lexical_cast & castException ) { H_THROW ( " " + lexical_cast < string > ( lineNum ) + " " + castException . what ( ) ) ; } }
\brief Process the CSV file looking for the given varName and route the data
         into the core.
\ brief Process the CSV file looking for the given varName and route the data into the core .
// reset the stream in case we are re-reading from this stream // code for "not found", takes advantage of skipping col==0 in the loop below. // read the header line and attempt to find varName. The first column is // not considered because that should be the index column. //        const int headerRowSize = row.size(); // ignore white space before comparing variable names // we are all set to process the table // note that getline sets the fail bit when it hits eof which is not what // want, a work around is to check peek // read the next row to process // Ignore blank lines. A stray windows line ending which may have made // its way in from a mixed line ending file can be skipped as well. // we should have a constant number of columns //TODO: figure this out for VS!  H_ASSERT( columnIndex < row.size() && headerRowSize == row.size(), "varying columns in data line "+ boost::lexical_cast<std::string>( lines_read ) ); // remove extra white space from the table value // this row of the table is specifying units for all columns // we only need to keep track of the value for the column of interest // this row is a regular row of data // the first column is assumed to be the index // route the data to the appropriate model component // ignore blanks // h_exceptions from setData should just be passed along