ColumnDataReader.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
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     CheckFiles(directory, rBaseName);
00072 }
00073 
00074 ColumnDataReader::ColumnDataReader(const FileFinder& rDirectory,
00075                                    const std::string& rBaseName)
00076 {
00077     if (!rDirectory.IsDir() || !rDirectory.Exists())
00078     {
00079         EXCEPTION("Directory does not exist: " + rDirectory.GetAbsolutePath());
00080     }
00081     CheckFiles(rDirectory.GetAbsolutePath(), rBaseName);
00082 }
00083 
00084 void ColumnDataReader::CheckFiles(const std::string& rDirectory, const std::string& rBaseName)
00085 {
00086     // Read in info file
00087     mInfoFilename = rDirectory + rBaseName + ".info";
00088     std::ifstream infofile(mInfoFilename.c_str(), std::ios::in);
00089 
00090     // If it doesn't exist - throw exception
00091     if (!infofile.is_open())
00092     {
00093         EXCEPTION("Couldn't open info file: " + mInfoFilename);
00094     }
00095     std::string junk;
00096     mNumFixedDimensions = NOT_READ;
00097     mHasUnlimitedDimension = false;
00098     mNumVariables = NOT_READ;
00099 
00100     infofile >> junk;
00101     infofile >> mNumFixedDimensions >> junk;
00102     infofile >> mHasUnlimitedDimension >> junk;
00103     infofile >> mNumVariables;
00104 
00105     if (mNumFixedDimensions == NOT_READ || mNumVariables == NOT_READ)
00106     {
00107         infofile.close();
00108         EXCEPTION("Couldn't read info file correctly");
00109     }
00110 
00111     // Read in variables and associated them with a column number
00112     if (mHasUnlimitedDimension)
00113     {
00114         if (mNumFixedDimensions < 1)
00115         {
00116             mDataFilename = rDirectory + rBaseName + ".dat";
00117         }
00118         else
00119         {
00120             std::stringstream suffix;
00121             suffix << std::setfill('0') << std::setw(FILE_SUFFIX_WIDTH) << 0;
00122 
00123             mDataFilename = rDirectory + rBaseName + "_" + suffix.str() + ".dat";
00124 
00125             // The ancillary path needs to come from a single place that is
00126             // used by both the reader & writer, otherwise all will be bad.
00127             mAncillaryFilename = rDirectory + rBaseName + "_unlimited.dat";
00128 
00129             // Extract the units and place into map
00130             std::ifstream ancillaryfile(mAncillaryFilename.c_str(), std::ios::in);
00131 
00132             // If it doesn't exist - throw exception
00133             if (!ancillaryfile.is_open())
00134             {
00135                 EXCEPTION("Couldn't open ancillary data file");
00136             }
00137             std::string dimension;
00138             std::getline(ancillaryfile, dimension);
00139             std::stringstream dimension_stream(dimension);
00140             std::string dimension_unit, dimension_name, header;
00141             dimension_stream >> header;
00142 
00143             // Separate into variable name and units
00144             int unitpos = header.find("(") + 1;
00145 
00146             dimension_name = header.substr(0, unitpos - 1);
00147             dimension_unit = header.substr(unitpos, header.length() - unitpos - 1);
00148 
00149             mVariablesToUnits[dimension_name] = dimension_unit;
00150             ancillaryfile.close();
00151         }
00152     }
00153     else
00154     {
00155         mDataFilename = rDirectory + rBaseName + ".dat";
00156     }
00157 
00158     std::ifstream datafile(mDataFilename.c_str(), std::ios::in);
00159     // If it doesn't exist - throw exception
00160     if (!datafile.is_open())
00161     {
00162         EXCEPTION("Couldn't open data file");
00163     }
00164 
00165     std::string variables;
00166     std::getline(datafile, variables);
00167     std::stringstream variable_stream(variables);
00168     std::string header, variable, unit;
00169     int column = 0;
00170 
00171     // Insert variables into map
00172     while (variable_stream >> header)
00173     {
00174         // Separate into variable name and units
00175         int unitpos = header.find("(") + 1;
00176 
00177         variable = header.substr(0, unitpos - 1);
00178         unit = header.substr(unitpos, header.length() - unitpos - 1);
00179 
00180         mVariablesToColumns[variable] = column;
00181         mVariablesToUnits[variable] = unit;
00182 
00183         column++;
00184     }
00185 
00186     // Now read the first line of proper data to determine the field width used when this
00187     // file was created. Do this by reading the first entry and measuring the distance from
00188     // the decimal point to the 'e'.  This gives the precision; the field width is then
00189     // precision + 7.
00190     // eg, if the first entry is
00191     //   6.3124e+01         => field width = 11 // chaste release 1 and 1.1
00192     //  -3.5124e+01         => field width = 11 // chaste release 1 and 1.1
00193     //  +1.00000000e+00     => field width = 15
00194     //  -1.20000000e+01     => field width = 15
00195     //  -1.12345678e-321    => field width = 15
00196     //
00197     std::string first_line;
00198     std::string first_entry;
00199 
00200     // read the first entry of the line. If there is no first entry, move to the next line..
00201     while (first_entry.length()==0 && !datafile.eof())
00202     {
00203         std::getline(datafile, first_line);
00204         std::stringstream stream(first_line);
00205         stream >> first_entry;
00206     }
00207 
00208     if (datafile.eof() && first_entry.length()==0)
00209     {
00210         EXCEPTION("Unable to determine field width from file as cannot find any data entries");
00211     }
00212 
00213     size_t dot_pos = first_entry.find(".");
00214     size_t e_pos = first_entry.find("e");
00215     if (dot_pos == std::string::npos || e_pos == std::string::npos)
00216     {
00217         EXCEPTION("Badly formatted scientific data field");
00218     }
00219     mFieldWidth = e_pos - dot_pos - 1 + 7;
00220     // Attempt to account for old format files (which only allowed 2 characters for the exponent)
00221     dot_pos = first_line.find(".");
00222     size_t second_dot_pos = first_line.find(".", dot_pos+1);
00223     if ((second_dot_pos != std::string::npos) &&
00224         (second_dot_pos - dot_pos == mFieldWidth + SPACING - 1))
00225     {
00226         mFieldWidth--;
00227     }
00228 
00229     infofile.close();
00230     datafile.close();
00231 }
00232 
00233 std::vector<double> ColumnDataReader::GetValues(const std::string& rVariableName)
00234 {
00235     if (mNumFixedDimensions > 0)
00236     {
00237         EXCEPTION("Data file has fixed dimension which must be specified");
00238     }
00239 
00240     std::map<std::string, int>::iterator col = mVariablesToColumns.find(rVariableName);
00241     if (col == mVariablesToColumns.end())
00242     {
00243         std::stringstream variable_name;
00244         variable_name << rVariableName;
00245         EXCEPTION("'" + variable_name.str() + "' is an unknown variable.");
00246     }
00247 
00248     int column = (*col).second;
00249     ReadColumnFromFile(mDataFilename, column);
00250 
00251     return mValues;
00252 }
00253 
00254 std::vector<double> ColumnDataReader::GetValues(const std::string& rVariableName,
00255                                                 int fixedDimension)
00256 {
00257     if (mNumFixedDimensions < 1)
00258     {
00259         EXCEPTION("Data file has no fixed dimension");
00260     }
00261 
00262     mValues.clear();
00263     if (mHasUnlimitedDimension)
00264     {
00265         std::string datafile = mDataFilename;
00266         std::map<std::string, int>::iterator col = mVariablesToColumns.find(rVariableName);
00267         if (col == mVariablesToColumns.end())
00268         {
00269             EXCEPTION("Unknown variable");
00270         }
00271         int column = (*col).second;
00272 
00273         int counter = 1;
00274         while (true)
00275         {
00276             try
00277             {
00278                 ReadValueFromFile(datafile, column, fixedDimension);
00279             }
00280             catch (Exception)
00281             {
00282                 break;
00283             }
00284 
00285             // Advance counter
00286             std::string::size_type underscore_pos = datafile.rfind("_", datafile.length());
00287             std::stringstream suffix;
00288 
00289             suffix << std::setfill('0') << std::setw(FILE_SUFFIX_WIDTH) << counter;
00290 
00291             if (underscore_pos != std::string::npos)
00292             {
00293                 datafile = datafile.substr(0, underscore_pos+1) + suffix.str() + ".dat";
00294             }
00295             counter++;
00296         }
00297     }
00298     else
00299     {
00300         int column = mVariablesToColumns[rVariableName];
00301         if (0 == column)
00302         {
00303             EXCEPTION("Unknown variable");
00304         }
00305         ReadValueFromFile(mDataFilename, column, fixedDimension);
00306     }
00307 
00308     return mValues;
00309 }
00310 
00311 std::vector<double> ColumnDataReader::GetUnlimitedDimensionValues()
00312 {
00313     mValues.clear();
00314     if (!mHasUnlimitedDimension)
00315     {
00316         EXCEPTION("Data file has no unlimited dimension");
00317     }
00318     if (mNumFixedDimensions > 0)
00319     {
00320         // Read in from the ancillary file
00321         ReadColumnFromFile(mAncillaryFilename, 0);
00322     }
00323     else
00324     {
00325         // Read the first column
00326         ReadColumnFromFile(mDataFilename, 0);
00327     }
00328     return mValues;
00329 }
00330 
00331 void ColumnDataReader::ReadValueFromFile(const std::string& rFilename, int col, int row)
00332 {
00333     std::ifstream datafile(rFilename.c_str(), std::ios::in);
00334     // If it doesn't exist - throw exception
00335     if (!datafile.is_open())
00336     {
00337         EXCEPTION("Couldn't open data file");
00338     }
00339     std::string variable_values;
00340     for (int i=0; i<row+1; i++)
00341     {
00342         std::getline(datafile, variable_values);
00343     }
00344 
00345     std::getline(datafile, variable_values);
00346     this->PushColumnEntryFromLine(variable_values, col);
00347 
00348     datafile.close();
00349 }
00350 
00351 void ColumnDataReader::ReadColumnFromFile(const std::string& rFilename, int col)
00352 {
00353     // Empty the values vector
00354     mValues.clear();
00355 
00356     // Read in from the ancillary file
00357     std::ifstream datafile(rFilename.c_str(), std::ios::in);
00358     std::string value;
00359 
00360     // We should have already checked that this file can be opened.
00361     assert(datafile.is_open());
00362 
00363     // The current variable becomes true just after reading the last line
00364     bool end_of_file_reached = false;
00365 
00366     // Skip header line
00367     end_of_file_reached = std::getline(datafile, value).eof();
00368 
00369     while (!end_of_file_reached)
00370     {
00371         end_of_file_reached = std::getline(datafile, value).eof();
00372         this->PushColumnEntryFromLine(value, col);
00373     }
00374     datafile.close();
00375 }
00376 
00377 void ColumnDataReader::PushColumnEntryFromLine(const std::string& rLine, int col)
00378 {
00379     int startpos = col * (mFieldWidth + SPACING) + SPACING - 1;
00380     std::string value = rLine.substr(startpos, mFieldWidth + 1);
00381     std::stringstream variable_stream(value);
00382     double d_value;
00383     variable_stream >> d_value;
00384     if (variable_stream.fail())
00385     {
00386         d_value = DBL_MAX;
00387     }
00388 
00389     mValues.push_back(d_value);
00390 }
00391 
00392 bool ColumnDataReader::HasValues(const std::string& rVariableName)
00393 {
00394     std::map<std::string, int>::iterator col = mVariablesToColumns.find(rVariableName);
00395     return !(col == mVariablesToColumns.end());
00396 }
00397 
00398 unsigned ColumnDataReader::GetFieldWidth()
00399 {
00400     return mFieldWidth;
00401 }
00402 

Generated on Mon Apr 18 11:35:28 2011 for Chaste by  doxygen 1.5.5