ColumnDataReader.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00035 #include "ColumnDataReader.hpp"
00036 #include "ColumnDataConstants.hpp"
00037 
00038 #include <fstream>
00039 #include <sstream>
00040 #include <iomanip>
00041 #include <cassert>
00042 #include <climits>
00043 #include "OutputFileHandler.hpp"
00044 #include "Exception.hpp"
00045 
00050 const int NOT_READ = -999;
00051 
00052 ColumnDataReader::ColumnDataReader(const std::string& rDirectory,
00053                                    const std::string& rBaseName,
00054                                    bool makeAbsolute)
00055 {
00056     // Find out where files are really stored
00057     std::string directory;
00058     if (makeAbsolute)
00059     {
00060         OutputFileHandler output_file_handler(rDirectory, false);
00061         directory = output_file_handler.GetOutputDirectoryFullPath();
00062     }
00063     else
00064     {
00065         // Add a trailing slash if needed
00066         if ( !(*(rDirectory.end()-1) == '/'))
00067         {
00068             directory = rDirectory + "/";
00069         }
00070     }
00071 
00072     // Read in info file
00073     mInfoFilename = directory + rBaseName + ".info";
00074     std::ifstream infofile(mInfoFilename.c_str(), std::ios::in);
00075 
00076     // If it doesn't exist - throw exception
00077     if (!infofile.is_open())
00078     {
00079         EXCEPTION("Couldn't open info file: " + mInfoFilename);
00080     }
00081     std::string junk;
00082     mNumFixedDimensions = NOT_READ;
00083     mHasUnlimitedDimension = false;
00084     mNumVariables = NOT_READ;
00085 
00086     infofile >> junk;
00087     infofile >> mNumFixedDimensions >> junk;
00088     infofile >> mHasUnlimitedDimension >> junk;
00089     infofile >> mNumVariables;
00090 
00091     if (mNumFixedDimensions == NOT_READ || mNumVariables == NOT_READ)
00092     {
00093         infofile.close();
00094         EXCEPTION("Couldn't read info file correctly");
00095     }
00096 
00097     // Read in variables and associated them with a column number
00098     if (mHasUnlimitedDimension)
00099     {
00100         if (mNumFixedDimensions < 1)
00101         {
00102             mDataFilename = directory + rBaseName + ".dat";
00103         }
00104         else
00105         {
00106             std::stringstream suffix;
00107             suffix << std::setfill('0') << std::setw(FILE_SUFFIX_WIDTH) << 0;
00108 
00109             mDataFilename = directory + rBaseName + "_" + suffix.str() + ".dat";
00110 
00111             // The ancillary path needs to come from a single place that is
00112             // used by both the reader & writer, otherwise all will be bad.
00113             mAncillaryFilename = directory + rBaseName + "_unlimited.dat";
00114 
00115             // Extract the units and place into map
00116             std::ifstream ancillaryfile(mAncillaryFilename.c_str(), std::ios::in);
00117 
00118             // If it doesn't exist - throw exception
00119             if (!ancillaryfile.is_open())
00120             {
00121                 EXCEPTION("Couldn't open ancillary data file");
00122             }
00123             std::string dimension;
00124             std::getline(ancillaryfile, dimension);
00125             std::stringstream dimension_stream(dimension);
00126             std::string dimension_unit, dimension_name, header;
00127             dimension_stream >> header;
00128 
00129             // Separate into variable name and units
00130             int unitpos = header.find("(") + 1;
00131 
00132             dimension_name = header.substr(0, unitpos - 1);
00133             dimension_unit = header.substr(unitpos, header.length() - unitpos - 1);
00134 
00135             mVariablesToUnits[dimension_name] = dimension_unit;
00136             ancillaryfile.close();
00137         }
00138     }
00139     else
00140     {
00141         mDataFilename = directory + rBaseName + ".dat";
00142     }
00143 
00144     std::ifstream datafile(mDataFilename.c_str(), std::ios::in);
00145     // If it doesn't exist - throw exception
00146     if (!datafile.is_open())
00147     {
00148         EXCEPTION("Couldn't open data file");
00149     }
00150 
00151     std::string variables;
00152     std::getline(datafile, variables);
00153     std::stringstream variable_stream(variables);
00154     std::string header, variable, unit;
00155     int column = 0;
00156 
00157     // Insert variables into map
00158     while (variable_stream >> header)
00159     {
00160         // Separate into variable name and units
00161         int unitpos = header.find("(") + 1;
00162 
00163         variable = header.substr(0, unitpos - 1);
00164         unit = header.substr(unitpos, header.length() - unitpos - 1);
00165 
00166         mVariablesToColumns[variable] = column;
00167         mVariablesToUnits[variable] = unit;
00168 
00169         column++;
00170     }
00171 
00172     // Now read the first line of proper data to determine the field width used when this
00173     // file was created. Do this by reading the first entry and measuring the distance from
00174     // the decimal point to the 'e'.  This gives the precision; the field width is then
00175     // precision + 7.
00176     // eg, if the first entry is
00177     //   6.3124e+01         => field width = 11 // chaste release 1 and 1.1
00178     //  -3.5124e+01         => field width = 11 // chaste release 1 and 1.1
00179     //  +1.00000000e+00     => field width = 15
00180     //  -1.20000000e+01     => field width = 15
00181     //  -1.12345678e-321    => field width = 15
00182     //
00183     std::string first_line;
00184     std::string first_entry;
00185 
00186     // read the first entry of the line. If there is no first entry, move to the next line..
00187     while (first_entry.length()==0 && !datafile.eof())
00188     {
00189         std::getline(datafile, first_line);
00190         std::stringstream stream(first_line);
00191         stream >> first_entry;
00192     }
00193 
00194     if (datafile.eof() && first_entry.length()==0)
00195     {
00196         EXCEPTION("Unable to determine field width from file as cannot find any data entries");
00197     }
00198 
00199     size_t dot_pos = first_entry.find(".");
00200     size_t e_pos = first_entry.find("e");
00201     if (dot_pos == std::string::npos || e_pos == std::string::npos)
00202     {
00203         EXCEPTION("Badly formatted scientific data field");
00204     }
00205     mFieldWidth = e_pos - dot_pos - 1 + 7;
00206     // Attempt to account for old format files (which only allowed 2 characters for the exponent)
00207     dot_pos = first_line.find(".");
00208     size_t second_dot_pos = first_line.find(".", dot_pos+1);
00209     if ((second_dot_pos != std::string::npos) &&
00210         (second_dot_pos - dot_pos == mFieldWidth + SPACING - 1))
00211     {
00212         mFieldWidth--;
00213     }
00214 
00215     infofile.close();
00216     datafile.close();
00217 }
00218 
00219 std::vector<double> ColumnDataReader::GetValues(const std::string& rVariableName)
00220 {
00221     if (mNumFixedDimensions > 0)
00222     {
00223         EXCEPTION("Data file has fixed dimension which must be specified");
00224     }
00225 
00226     std::map<std::string, int>::iterator col = mVariablesToColumns.find(rVariableName);
00227     if (col == mVariablesToColumns.end())
00228     {
00229         std::stringstream variable_name;
00230         variable_name << rVariableName;
00231         EXCEPTION("'" + variable_name.str() + "' is an unknown variable.");
00232     }
00233 
00234     int column = (*col).second;
00235     ReadColumnFromFile(mDataFilename, column);
00236 
00237     return mValues;
00238 }
00239 
00240 std::vector<double> ColumnDataReader::GetValues(const std::string& rVariableName,
00241                                                 int fixedDimension)
00242 {
00243     if (mNumFixedDimensions < 1)
00244     {
00245         EXCEPTION("Data file has no fixed dimension");
00246     }
00247 
00248     mValues.clear();
00249     if (mHasUnlimitedDimension)
00250     {
00251         std::string datafile = mDataFilename;
00252         std::map<std::string, int>::iterator col = mVariablesToColumns.find(rVariableName);
00253         if (col == mVariablesToColumns.end())
00254         {
00255             EXCEPTION("Unknown variable");
00256         }
00257         int column = (*col).second;
00258 
00259         int counter = 1;
00260         while (true)
00261         {
00262             try
00263             {
00264                 ReadValueFromFile(datafile, column, fixedDimension);
00265             }
00266             catch (Exception)
00267             {
00268                 break;
00269             }
00270 
00271             // Advance counter
00272             std::string::size_type underscore_pos = datafile.rfind("_", datafile.length());
00273             std::stringstream suffix;
00274 
00275             suffix << std::setfill('0') << std::setw(FILE_SUFFIX_WIDTH) << counter;
00276 
00277             if (underscore_pos != std::string::npos)
00278             {
00279                 datafile = datafile.substr(0, underscore_pos+1) + suffix.str() + ".dat";
00280             }
00281             counter++;
00282         }
00283     }
00284     else
00285     {
00286         int column = mVariablesToColumns[rVariableName];
00287         if (0 == column)
00288         {
00289             EXCEPTION("Unknown variable");
00290         }
00291         ReadValueFromFile(mDataFilename, column, fixedDimension);
00292     }
00293 
00294     return mValues;
00295 }
00296 
00297 std::vector<double> ColumnDataReader::GetUnlimitedDimensionValues()
00298 {
00299     mValues.clear();
00300     if (!mHasUnlimitedDimension)
00301     {
00302         EXCEPTION("Data file has no unlimited dimension");
00303     }
00304     if (mNumFixedDimensions > 0)
00305     {
00306         // Read in from the ancillary file
00307         ReadColumnFromFile(mAncillaryFilename, 0);
00308     }
00309     else
00310     {
00311         // Read the first column
00312         ReadColumnFromFile(mDataFilename, 0);
00313     }
00314     return mValues;
00315 }
00316 
00317 void ColumnDataReader::ReadValueFromFile(const std::string& rFilename, int col, int row)
00318 {
00319     std::ifstream datafile(rFilename.c_str(), std::ios::in);
00320     // If it doesn't exist - throw exception
00321     if (!datafile.is_open())
00322     {
00323         EXCEPTION("Couldn't open data file");
00324     }
00325     std::string variable_values;
00326     for (int i=0; i<row+1; i++)
00327     {
00328         std::getline(datafile, variable_values);
00329     }
00330 
00331     std::getline(datafile, variable_values);
00332     this->PushColumnEntryFromLine(variable_values, col);
00333 
00334     datafile.close();
00335 }
00336 
00337 void ColumnDataReader::ReadColumnFromFile(const std::string& rFilename, int col)
00338 {
00339     // Empty the values vector
00340     mValues.clear();
00341 
00342     // Read in from the ancillary file
00343     std::ifstream datafile(rFilename.c_str(), std::ios::in);
00344     std::string value;
00345 
00346     // We should have already checked that this file can be opened.
00347     assert(datafile.is_open());
00348 
00349     // The current variable becomes true just after reading the last line
00350     bool end_of_file_reached = false;
00351 
00352     // Skip header line
00353     end_of_file_reached = std::getline(datafile, value).eof();
00354 
00355     while (!end_of_file_reached)
00356     {
00357         end_of_file_reached = std::getline(datafile, value).eof();
00358         this->PushColumnEntryFromLine(value, col);
00359     }
00360     datafile.close();
00361 }
00362 
00363 void ColumnDataReader::PushColumnEntryFromLine(const std::string& rLine, int col)
00364 {
00365     int startpos = col * (mFieldWidth + SPACING) + SPACING - 1;
00366     std::string value = rLine.substr(startpos, mFieldWidth + 1);
00367     std::stringstream variable_stream(value);
00368     double d_value;
00369     variable_stream >> d_value;
00370     if (variable_stream.fail())
00371     {
00372         d_value = DBL_MAX;
00373     }
00374 
00375     mValues.push_back(d_value);
00376 }
00377 
00378 bool ColumnDataReader::HasValues(const std::string& rVariableName)
00379 {
00380     std::map<std::string, int>::iterator col = mVariablesToColumns.find(rVariableName);
00381     return !(col == mVariablesToColumns.end());
00382 }
00383 
00384 unsigned ColumnDataReader::GetFieldWidth()
00385 {
00386     return mFieldWidth;
00387 }
00388 

Generated by  doxygen 1.6.2