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