Chaste Release::3.1
|
00001 /* 00002 00003 Copyright (c) 2005-2012, University of Oxford. 00004 All rights reserved. 00005 00006 University of Oxford means the Chancellor, Masters and Scholars of the 00007 University of Oxford, having an administrative office at Wellington 00008 Square, Oxford OX1 2JD, UK. 00009 00010 This file is part of Chaste. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 * Redistributions of source code must retain the above copyright notice, 00015 this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright notice, 00017 this list of conditions and the following disclaimer in the documentation 00018 and/or other materials provided with the distribution. 00019 * Neither the name of the University of Oxford nor the names of its 00020 contributors may be used to endorse or promote products derived from this 00021 software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 */ 00035 00042 #include "ColumnDataReader.hpp" 00043 #include "ColumnDataConstants.hpp" 00044 00045 #include <fstream> 00046 #include <sstream> 00047 #include <iomanip> 00048 #include <cassert> 00049 #include <climits> 00050 #include "OutputFileHandler.hpp" 00051 #include "Exception.hpp" 00052 00057 const int NOT_READ = -999; 00058 00059 ColumnDataReader::ColumnDataReader(const std::string& rDirectory, 00060 const std::string& rBaseName, 00061 bool makeAbsolute) 00062 { 00063 // Find out where files are really stored 00064 std::string directory; 00065 if (makeAbsolute) 00066 { 00067 OutputFileHandler output_file_handler(rDirectory, false); 00068 directory = output_file_handler.GetOutputDirectoryFullPath(); 00069 } 00070 else 00071 { 00072 // Add a trailing slash if needed 00073 if ( !(*(rDirectory.end()-1) == '/')) 00074 { 00075 directory = rDirectory + "/"; 00076 } 00077 } 00078 CheckFiles(directory, rBaseName); 00079 } 00080 00081 ColumnDataReader::ColumnDataReader(const FileFinder& rDirectory, 00082 const std::string& rBaseName) 00083 { 00084 if (!rDirectory.IsDir() || !rDirectory.Exists()) 00085 { 00086 EXCEPTION("Directory does not exist: " + rDirectory.GetAbsolutePath()); 00087 } 00088 CheckFiles(rDirectory.GetAbsolutePath(), rBaseName); 00089 } 00090 00091 void ColumnDataReader::CheckFiles(const std::string& rDirectory, const std::string& rBaseName) 00092 { 00093 // Read in info file 00094 mInfoFilename = rDirectory + rBaseName + ".info"; 00095 std::ifstream infofile(mInfoFilename.c_str(), std::ios::in); 00096 00097 // If it doesn't exist - throw exception 00098 if (!infofile.is_open()) 00099 { 00100 EXCEPTION("Couldn't open info file: " + mInfoFilename); 00101 } 00102 std::string junk; 00103 mNumFixedDimensions = NOT_READ; 00104 mHasUnlimitedDimension = false; 00105 mNumVariables = NOT_READ; 00106 00107 infofile >> junk; 00108 infofile >> mNumFixedDimensions >> junk; 00109 infofile >> mHasUnlimitedDimension >> junk; 00110 infofile >> mNumVariables; 00111 00112 if (mNumFixedDimensions == NOT_READ || mNumVariables == NOT_READ) 00113 { 00114 infofile.close(); 00115 EXCEPTION("Couldn't read info file correctly"); 00116 } 00117 00118 // Read in variables and associated them with a column number 00119 if (mHasUnlimitedDimension) 00120 { 00121 if (mNumFixedDimensions < 1) 00122 { 00123 mDataFilename = rDirectory + rBaseName + ".dat"; 00124 } 00125 else 00126 { 00127 std::stringstream suffix; 00128 suffix << std::setfill('0') << std::setw(FILE_SUFFIX_WIDTH) << 0; 00129 00130 mDataFilename = rDirectory + rBaseName + "_" + suffix.str() + ".dat"; 00131 00132 /* 00133 * The ancillary path needs to come from a single place that is 00134 * used by both the reader & writer, otherwise all will be bad. 00135 */ 00136 mAncillaryFilename = rDirectory + rBaseName + "_unlimited.dat"; 00137 00138 // Extract the units and place into map 00139 std::ifstream ancillaryfile(mAncillaryFilename.c_str(), std::ios::in); 00140 00141 // If it doesn't exist - throw exception 00142 if (!ancillaryfile.is_open()) 00143 { 00144 EXCEPTION("Couldn't open ancillary data file"); 00145 } 00146 std::string dimension; 00147 std::getline(ancillaryfile, dimension); 00148 std::stringstream dimension_stream(dimension); 00149 std::string dimension_unit, dimension_name, header; 00150 dimension_stream >> header; 00151 00152 // Separate into variable name and units 00153 int unitpos = header.find("(") + 1; 00154 00155 dimension_name = header.substr(0, unitpos - 1); 00156 dimension_unit = header.substr(unitpos, header.length() - unitpos - 1); 00157 00158 mVariablesToUnits[dimension_name] = dimension_unit; 00159 ancillaryfile.close(); 00160 } 00161 } 00162 else 00163 { 00164 mDataFilename = rDirectory + rBaseName + ".dat"; 00165 } 00166 00167 std::ifstream datafile(mDataFilename.c_str(), std::ios::in); 00168 // If it doesn't exist - throw exception 00169 if (!datafile.is_open()) 00170 { 00171 EXCEPTION("Couldn't open data file"); 00172 } 00173 00174 std::string variables; 00175 std::getline(datafile, variables); 00176 std::stringstream variable_stream(variables); 00177 std::string header, variable, unit; 00178 int column = 0; 00179 00180 // Insert variables into map 00181 while (variable_stream >> header) 00182 { 00183 // Separate into variable name and units 00184 int unitpos = header.find("(") + 1; 00185 00186 variable = header.substr(0, unitpos - 1); 00187 unit = header.substr(unitpos, header.length() - unitpos - 1); 00188 00189 mVariablesToColumns[variable] = column; 00190 mVariablesToUnits[variable] = unit; 00191 00192 column++; 00193 } 00194 00195 /* 00196 * Now read the first line of proper data to determine the field width used when this 00197 * file was created. Do this by reading the first entry and measuring the distance from 00198 * the decimal point to the 'e'. This gives the precision; the field width is then 00199 * precision + 7. 00200 * e.g. if the first entry is 00201 * 6.3124e+01 => field width = 11 // chaste release 1 and 1.1 00202 * -3.5124e+01 => field width = 11 // chaste release 1 and 1.1 00203 * +1.00000000e+00 => field width = 15 00204 * -1.20000000e+01 => field width = 15 00205 * -1.12345678e-321 => field width = 15 00206 */ 00207 std::string first_line; 00208 std::string first_entry; 00209 00210 // Read the first entry of the line. If there is no first entry, move to the next line.. 00211 while (first_entry.length()==0 && !datafile.eof()) 00212 { 00213 std::getline(datafile, first_line); 00214 std::stringstream stream(first_line); 00215 stream >> first_entry; 00216 } 00217 00218 if (datafile.eof() && first_entry.length()==0) 00219 { 00220 EXCEPTION("Unable to determine field width from file as cannot find any data entries"); 00221 } 00222 00223 size_t dot_pos = first_entry.find("."); 00224 size_t e_pos = first_entry.find("e"); 00225 if (dot_pos == std::string::npos || e_pos == std::string::npos) 00226 { 00227 EXCEPTION("Badly formatted scientific data field"); 00228 } 00229 mFieldWidth = e_pos - dot_pos - 1 + 7; 00230 00231 // Attempt to account for old format files (which only allowed 2 characters for the exponent) 00232 dot_pos = first_line.find("."); 00233 size_t second_dot_pos = first_line.find(".", dot_pos+1); 00234 if ((second_dot_pos != std::string::npos) && 00235 (second_dot_pos - dot_pos == mFieldWidth + SPACING - 1)) 00236 { 00237 mFieldWidth--; 00238 } 00239 00240 infofile.close(); 00241 datafile.close(); 00242 } 00243 00244 std::vector<double> ColumnDataReader::GetValues(const std::string& rVariableName) 00245 { 00246 if (mNumFixedDimensions > 0) 00247 { 00248 EXCEPTION("Data file has fixed dimension which must be specified"); 00249 } 00250 00251 std::map<std::string, int>::iterator col = mVariablesToColumns.find(rVariableName); 00252 if (col == mVariablesToColumns.end()) 00253 { 00254 std::stringstream variable_name; 00255 variable_name << rVariableName; 00256 EXCEPTION("'" + variable_name.str() + "' is an unknown variable."); 00257 } 00258 00259 int column = (*col).second; 00260 ReadColumnFromFile(mDataFilename, column); 00261 00262 return mValues; 00263 } 00264 00265 std::vector<double> ColumnDataReader::GetValues(const std::string& rVariableName, 00266 int fixedDimension) 00267 { 00268 if (mNumFixedDimensions < 1) 00269 { 00270 EXCEPTION("Data file has no fixed dimension"); 00271 } 00272 00273 mValues.clear(); 00274 if (mHasUnlimitedDimension) 00275 { 00276 std::string datafile = mDataFilename; 00277 std::map<std::string, int>::iterator col = mVariablesToColumns.find(rVariableName); 00278 if (col == mVariablesToColumns.end()) 00279 { 00280 EXCEPTION("Unknown variable"); 00281 } 00282 int column = (*col).second; 00283 00284 int counter = 1; 00285 while (true) 00286 { 00287 try 00288 { 00289 ReadValueFromFile(datafile, column, fixedDimension); 00290 } 00291 catch (Exception) 00292 { 00293 break; 00294 } 00295 00296 // Advance counter 00297 std::string::size_type underscore_pos = datafile.rfind("_", datafile.length()); 00298 std::stringstream suffix; 00299 00300 suffix << std::setfill('0') << std::setw(FILE_SUFFIX_WIDTH) << counter; 00301 00302 if (underscore_pos != std::string::npos) 00303 { 00304 datafile = datafile.substr(0, underscore_pos+1) + suffix.str() + ".dat"; 00305 } 00306 counter++; 00307 } 00308 } 00309 else 00310 { 00311 int column = mVariablesToColumns[rVariableName]; 00312 if (0 == column) 00313 { 00314 EXCEPTION("Unknown variable"); 00315 } 00316 ReadValueFromFile(mDataFilename, column, fixedDimension); 00317 } 00318 00319 return mValues; 00320 } 00321 00322 std::vector<double> ColumnDataReader::GetUnlimitedDimensionValues() 00323 { 00324 mValues.clear(); 00325 if (!mHasUnlimitedDimension) 00326 { 00327 EXCEPTION("Data file has no unlimited dimension"); 00328 } 00329 if (mNumFixedDimensions > 0) 00330 { 00331 // Read in from the ancillary file 00332 ReadColumnFromFile(mAncillaryFilename, 0); 00333 } 00334 else 00335 { 00336 // Read the first column 00337 ReadColumnFromFile(mDataFilename, 0); 00338 } 00339 return mValues; 00340 } 00341 00342 void ColumnDataReader::ReadValueFromFile(const std::string& rFilename, int col, int row) 00343 { 00344 std::ifstream datafile(rFilename.c_str(), std::ios::in); 00345 // If it doesn't exist - throw exception 00346 if (!datafile.is_open()) 00347 { 00348 EXCEPTION("Couldn't open data file"); 00349 } 00350 std::string variable_values; 00351 for (int i=0; i<row+1; i++) 00352 { 00353 std::getline(datafile, variable_values); 00354 } 00355 00356 std::getline(datafile, variable_values); 00357 this->PushColumnEntryFromLine(variable_values, col); 00358 00359 datafile.close(); 00360 } 00361 00362 void ColumnDataReader::ReadColumnFromFile(const std::string& rFilename, int col) 00363 { 00364 // Empty the values vector 00365 mValues.clear(); 00366 00367 // Read in from the ancillary file 00368 std::ifstream datafile(rFilename.c_str(), std::ios::in); 00369 std::string value; 00370 00371 // We should have already checked that this file can be opened. 00372 assert(datafile.is_open()); 00373 00374 // The current variable becomes true just after reading the last line 00375 bool end_of_file_reached = false; 00376 00377 // Skip header line 00378 end_of_file_reached = std::getline(datafile, value).eof(); 00379 00380 while (!end_of_file_reached) 00381 { 00382 end_of_file_reached = std::getline(datafile, value).eof(); 00383 this->PushColumnEntryFromLine(value, col); 00384 } 00385 datafile.close(); 00386 } 00387 00388 void ColumnDataReader::PushColumnEntryFromLine(const std::string& rLine, int col) 00389 { 00390 int startpos = col * (mFieldWidth + SPACING) + SPACING - 1; 00391 std::string value = rLine.substr(startpos, mFieldWidth + 1); 00392 std::stringstream variable_stream(value); 00393 double d_value; 00394 variable_stream >> d_value; 00395 if (variable_stream.fail()) 00396 { 00397 d_value = DBL_MAX; 00398 } 00399 00400 mValues.push_back(d_value); 00401 } 00402 00403 bool ColumnDataReader::HasValues(const std::string& rVariableName) 00404 { 00405 std::map<std::string, int>::iterator col = mVariablesToColumns.find(rVariableName); 00406 return !(col == mVariablesToColumns.end()); 00407 } 00408 00409 unsigned ColumnDataReader::GetFieldWidth() 00410 { 00411 return mFieldWidth; 00412 }