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 00041 #include "ColumnDataWriter.hpp" 00042 #include "ColumnDataConstants.hpp" 00043 #include "Exception.hpp" 00044 #include "Version.hpp" 00045 00046 #include <ctype.h> 00047 #include <sstream> 00048 #include <iomanip> 00049 #include <fstream> 00050 00051 //#include <sys/stat.h> // For chmod() 00052 00053 ColumnDataWriter::ColumnDataWriter(const std::string& rDirectory, 00054 const std::string& rBaseName, 00055 bool cleanDirectory, 00056 unsigned precision) 00057 : mOutputFileHandler(rDirectory, cleanDirectory), 00058 mDirectory(rDirectory), 00059 mBaseName(rBaseName), 00060 mIsInDefineMode(true), 00061 mIsFixedDimensionSet(false), 00062 mIsUnlimitedDimensionSet(false), 00063 mUnlimitedDimensionPosition(0), 00064 mFixedDimensionSize(-1), 00065 mpCurrentOutputFile(NULL), 00066 mpCurrentAncillaryFile(NULL), 00067 mpUnlimitedDimensionVariable(NULL), 00068 mpFixedDimensionVariable(NULL), 00069 mFieldWidth(precision+7), // Allow for numbers like -1.111e-321 (where precision=3) 00070 mPrecision(precision), 00071 mHasPutVariable(false), 00072 mNeedAdvanceAlongUnlimitedDimension(false), 00073 mCommentForInfoFile("") 00074 { 00075 if (mPrecision<2 || mPrecision>20) 00076 { 00077 EXCEPTION("Precision must be between 2 and 20 (inclusive)"); 00078 } 00079 } 00080 00081 ColumnDataWriter::~ColumnDataWriter() 00082 { 00083 // Close any open output files 00084 Close(); 00085 00086 // Delete memory allocated for variables 00087 if (mpUnlimitedDimensionVariable != NULL) 00088 { 00089 delete mpUnlimitedDimensionVariable; 00090 } 00091 if (mpFixedDimensionVariable != NULL) 00092 { 00093 delete mpFixedDimensionVariable; 00094 } 00095 } 00096 00097 std::string ColumnDataWriter::GetOutputDirectory() 00098 { 00099 return mOutputFileHandler.GetOutputDirectoryFullPath(); 00100 } 00101 00102 void ColumnDataWriter::Close() 00103 { 00104 if (mpCurrentOutputFile.get() != NULL) 00105 { 00106 mpCurrentOutputFile->close(); 00107 mpCurrentOutputFile = out_stream(NULL); 00108 } 00109 00110 if (mpCurrentAncillaryFile.get() != NULL) 00111 { 00112 mpCurrentAncillaryFile->close(); 00113 mpCurrentAncillaryFile = out_stream(NULL); 00114 } 00115 } 00116 00117 void ColumnDataWriter::CheckVariableName(const std::string& rName) 00118 { 00119 if (rName.length() == 0) 00120 { 00121 EXCEPTION("Variable name not allowed: may not be blank."); 00122 } 00123 CheckUnitsName(rName); 00124 } 00125 00126 void ColumnDataWriter::CheckUnitsName(const std::string& rName) 00127 { 00128 for (unsigned i=0; i<rName.length(); i++) 00129 { 00130 if (!isalnum(rName[i]) && !(rName[i]=='_')) 00131 { 00132 std::string error = "Variable name/units '" + rName + "' not allowed: may only contain alphanumeric characters or '_'."; 00133 EXCEPTION(error); 00134 } 00135 } 00136 } 00137 00138 int ColumnDataWriter::DefineUnlimitedDimension(const std::string& rDimensionName, 00139 const std::string& rDimensionUnits) 00140 { 00141 if (mIsUnlimitedDimensionSet) 00142 { 00143 EXCEPTION("Unlimited dimension already set. Cannot be defined twice"); 00144 } 00145 00146 if (!mIsInDefineMode) 00147 { 00148 EXCEPTION("Cannot define variables when not in Define mode"); 00149 } 00150 00151 CheckVariableName(rDimensionName); 00152 CheckUnitsName(rDimensionUnits); 00153 00154 mUnlimitedDimensionName = rDimensionName; 00155 mUnlimitedDimensionUnits = rDimensionUnits; 00156 00157 mpUnlimitedDimensionVariable = new DataWriterVariable; 00158 mpUnlimitedDimensionVariable->mVariableName = rDimensionName; 00159 mpUnlimitedDimensionVariable->mVariableUnits = rDimensionUnits; 00160 00161 mIsUnlimitedDimensionSet = true; 00162 00163 return UNLIMITED_DIMENSION_VAR_ID; 00164 } 00165 00166 int ColumnDataWriter::DefineFixedDimension(const std::string& rDimensionName, 00167 const std::string& rDimensionUnits, 00168 long dimensionSize) 00169 { 00170 if (!mIsInDefineMode) 00171 { 00172 EXCEPTION("Cannot define variables when not in Define mode"); 00173 } 00174 if (dimensionSize < 1) 00175 { 00176 EXCEPTION("Fixed dimension must be at least 1 long"); 00177 } 00178 00179 CheckVariableName(rDimensionName); 00180 CheckUnitsName(rDimensionUnits); 00181 00182 mFixedDimensionName = rDimensionName; 00183 mFixedDimensionUnits = rDimensionUnits; 00184 mFixedDimensionSize = dimensionSize; 00185 00186 mIsFixedDimensionSet = true; 00187 00188 mpFixedDimensionVariable = new DataWriterVariable; 00189 mpFixedDimensionVariable->mVariableName = rDimensionName; 00190 mpFixedDimensionVariable->mVariableUnits = rDimensionUnits; 00191 return FIXED_DIMENSION_VAR_ID; 00192 } 00193 00194 int ColumnDataWriter::DefineVariable(const std::string& rVariableName, 00195 const std::string& rVariableUnits) 00196 { 00197 if (!mIsInDefineMode) 00198 { 00199 EXCEPTION("Cannot define variables when not in Define mode"); 00200 } 00201 00202 CheckVariableName(rVariableName); 00203 CheckUnitsName(rVariableUnits); 00204 00205 int variable_id; 00206 00207 if (rVariableName == mUnlimitedDimensionName) 00208 { 00209 EXCEPTION("Variable name: " + rVariableName + " already in use as unlimited dimension"); 00210 } 00211 else if (rVariableName == mFixedDimensionName) 00212 { 00213 EXCEPTION("Variable name: " + rVariableName + " already in use as fixed dimension"); 00214 } 00215 else // ordinary variable 00216 { 00217 // Add the variable to the variable vector 00218 DataWriterVariable new_variable; 00219 new_variable.mVariableName = rVariableName; 00220 new_variable.mVariableUnits = rVariableUnits; 00221 mVariables.push_back(new_variable); 00222 00223 // Use the index of the variable vector as the variable ID. 00224 // This is ok since there is no way to remove variables. 00225 variable_id = mVariables.size()-1; 00226 } 00227 00228 return variable_id; 00229 } 00230 00231 void ColumnDataWriter::EndDefineMode() 00232 { 00233 // Check that a dimension has been defined 00234 if (mIsFixedDimensionSet == false && mIsUnlimitedDimensionSet == false) 00235 { 00236 EXCEPTION("Cannot end define mode. No dimensions have been defined."); 00237 } 00238 // Check that at least one variable has been defined 00239 if (mVariables.size() < 1) 00240 { 00241 EXCEPTION("Cannot end define mode. No variables have been defined."); 00242 } 00243 // Calculate the width of each row 00244 int unlimited_dimension_variable = (mpUnlimitedDimensionVariable != NULL); 00245 int fixed_dimension_variable = (mpFixedDimensionVariable != NULL); 00246 if (mIsUnlimitedDimensionSet) 00247 { 00248 if (mIsFixedDimensionSet) 00249 { 00250 mRowWidth = (mVariables.size() + fixed_dimension_variable) * (mFieldWidth + SPACING); 00251 mAncillaryRowWidth = mFieldWidth + SPACING; 00252 00253 // Write out the headers for the first position along the unlimited dimension 00254 std::stringstream suffix; 00255 suffix << std::setfill('0') << std::setw(FILE_SUFFIX_WIDTH) << mUnlimitedDimensionPosition; 00256 00257 if (mpUnlimitedDimensionVariable != NULL) 00258 { 00259 std::string ancillary_filename = mBaseName + "_unlimited.dat"; 00260 mpCurrentAncillaryFile = mOutputFileHandler.OpenOutputFile(ancillary_filename, std::ios::out); 00261 (*mpCurrentAncillaryFile) << std::setiosflags(std::ios::scientific); 00262 (*mpCurrentAncillaryFile) << std::setprecision(mPrecision); 00263 if (mpUnlimitedDimensionVariable != NULL) 00264 { 00265 (*mpCurrentAncillaryFile) << mpUnlimitedDimensionVariable->mVariableName 00266 << "(" << mpUnlimitedDimensionVariable->mVariableUnits << ") "; 00267 } 00268 } 00269 mAncillaryRowStartPosition = mpCurrentAncillaryFile->tellp(); 00270 std::string filename = mBaseName + "_" + suffix.str() + ".dat"; 00271 this->CreateFixedDimensionFile(filename); 00272 } 00273 else 00274 { 00275 mRowWidth = (mVariables.size() + unlimited_dimension_variable) * (mFieldWidth + SPACING); 00276 00277 // Write out the column headers 00278 std::string filename = mBaseName + ".dat"; 00279 mpCurrentOutputFile = mOutputFileHandler.OpenOutputFile(filename, std::ios::out); 00280 (*mpCurrentOutputFile) << std::setiosflags(std::ios::scientific); 00281 (*mpCurrentOutputFile) << std::setprecision(mPrecision); 00282 if (mpUnlimitedDimensionVariable != NULL) 00283 { 00284 (*mpCurrentOutputFile) << mpUnlimitedDimensionVariable->mVariableName 00285 << "(" << mpUnlimitedDimensionVariable->mVariableUnits << ") "; 00286 } 00287 /* 00288 * Write out header(which may contain several variables) for output file. 00289 * In this scope the method "CreateFixedDimensionFile" has not been invoked, 00290 * because there is no mFixedDimensionSize available. 00291 */ 00292 for (unsigned i=0; i<mVariables.size(); i++) 00293 { 00294 (*mpCurrentOutputFile) << mVariables[i].mVariableName << "(" << mVariables[i].mVariableUnits << ")"; 00295 if (i < mVariables.size()-1) 00296 { 00297 (*mpCurrentOutputFile) << " "; 00298 } 00299 } 00300 (*mpCurrentOutputFile) << std::endl; 00301 mRowStartPosition = mpCurrentOutputFile->tellp(); 00302 00303 // Write out a line of blank space which is #variables * (mFieldWidth + 1) -1 00304 std::string blank_line(mRowWidth, ' '); 00305 (*mpCurrentOutputFile) << blank_line; 00306 } 00307 } 00308 else 00309 { 00310 // The fixed dimension must be set at this point or we wouldn't be here 00311 mRowWidth = (mVariables.size() + fixed_dimension_variable) * (mFieldWidth + SPACING); 00312 std::string filename = mBaseName + ".dat"; 00313 this->CreateFixedDimensionFile(filename); 00314 } 00315 00316 // Write info file 00317 std::string infoname = mBaseName + ".info"; 00318 this->CreateInfoFile(infoname); 00319 00320 mIsInDefineMode = false; 00321 } 00322 00323 void ColumnDataWriter::CreateFixedDimensionFile(const std::string& rFileName) 00324 { 00325 // Create new data file 00326 mpCurrentOutputFile = mOutputFileHandler.OpenOutputFile(rFileName, std::ios::out); 00327 (*mpCurrentOutputFile) << std::setiosflags(std::ios::scientific); 00328 (*mpCurrentOutputFile) << std::setprecision(mPrecision); 00329 if (mpFixedDimensionVariable != NULL) 00330 { 00331 (*mpCurrentOutputFile) << mpFixedDimensionVariable->mVariableName 00332 << "(" << mpFixedDimensionVariable->mVariableUnits << ") "; 00333 } 00334 // Write out the column headers and spaces for the rest of the file 00335 for (unsigned i = 0; i < mVariables.size(); i++) 00336 { 00337 (*mpCurrentOutputFile) << mVariables[i].mVariableName << "(" << mVariables[i].mVariableUnits << ")"; 00338 if (i < mVariables.size()-1) 00339 { 00340 (*mpCurrentOutputFile) << " "; 00341 } 00342 } 00343 (*mpCurrentOutputFile) << std::endl; 00344 mRowStartPosition = mpCurrentOutputFile->tellp(); 00345 std::string blank_line(mRowWidth, ' '); 00346 for (int i = 0; i < mFixedDimensionSize; i++) 00347 { 00348 (*mpCurrentOutputFile) << blank_line << std::endl; 00349 } 00350 } 00351 00352 void ColumnDataWriter::CreateInfoFile(const std::string& rFileName) 00353 { 00354 // Create new info file 00355 out_stream p_info_file = mOutputFileHandler.OpenOutputFile(rFileName, std::ios::out); 00356 (*p_info_file) << "FIXED " << mFixedDimensionSize << std::endl; 00357 (*p_info_file) << "UNLIMITED " << mIsUnlimitedDimensionSet << std::endl; 00358 (*p_info_file) << "VARIABLES " << mVariables.size() << std::endl; 00359 if (mCommentForInfoFile != "") 00360 { 00361 *p_info_file << mCommentForInfoFile << std::endl; 00362 } 00363 *p_info_file << ChasteBuildInfo::GetProvenanceString(); 00364 p_info_file->close(); 00365 } 00366 00367 void ColumnDataWriter::DoAdvanceAlongUnlimitedDimension() 00368 { 00369 mHasPutVariable = false; 00370 mNeedAdvanceAlongUnlimitedDimension = false; 00371 00372 if (mIsUnlimitedDimensionSet) 00373 { 00374 if (mIsFixedDimensionSet) 00375 { 00376 //first close the current file before creating another one 00377 mpCurrentOutputFile->close(); 00378 std::stringstream suffix; 00379 suffix << std::setfill('0') << std::setw(FILE_SUFFIX_WIDTH) << mUnlimitedDimensionPosition + 1; 00380 00381 std::string filename = mBaseName + "_" + suffix.str() + ".dat"; 00382 this->CreateFixedDimensionFile(filename); 00383 } 00384 else 00385 { 00386 //go to the end of the current line 00387 mpCurrentOutputFile->seekp(mRowStartPosition+mRowWidth); 00388 (*mpCurrentOutputFile) << std::endl; 00389 mRowStartPosition = mpCurrentOutputFile->tellp(); 00390 std::string blank_line(mRowWidth,' '); 00391 (*mpCurrentOutputFile) << blank_line; 00392 } 00393 } 00394 else 00395 { 00396 EXCEPTION("Cannot advance along unlimited dimension if it is not defined"); 00397 } 00398 mUnlimitedDimensionPosition++; 00399 } 00400 00401 void ColumnDataWriter::AdvanceAlongUnlimitedDimension() 00402 { 00403 if (mHasPutVariable) 00404 { 00405 mNeedAdvanceAlongUnlimitedDimension = true; 00406 } 00407 } 00408 00409 void ColumnDataWriter::PutVariable(int variableID, double variableValue, long dimensionPosition) 00410 { 00411 if (mNeedAdvanceAlongUnlimitedDimension) 00412 { 00413 DoAdvanceAlongUnlimitedDimension(); 00414 } 00415 00416 // Check that we are not in define mode 00417 if (mIsInDefineMode) 00418 { 00419 EXCEPTION("Cannot put variables when in Define mode"); 00420 } 00421 // Check that variableID is in range (exception) 00422 if (variableID > (int)mVariables.size() || 00423 (variableID != UNLIMITED_DIMENSION_VAR_ID && 00424 variableID != FIXED_DIMENSION_VAR_ID && 00425 variableID < 0)) 00426 { 00427 EXCEPTION("variableID unknown"); 00428 } 00429 00430 if (mIsFixedDimensionSet) 00431 { 00432 if (dimensionPosition == -1 && variableID != UNLIMITED_DIMENSION_VAR_ID) 00433 { 00434 EXCEPTION("Dimension position not supplied"); 00435 } 00436 if (dimensionPosition < -1 || dimensionPosition >= mFixedDimensionSize) 00437 { 00438 EXCEPTION("Dimension position out of range"); 00439 } 00440 if (dimensionPosition != -1 && variableID == UNLIMITED_DIMENSION_VAR_ID) 00441 { 00442 EXCEPTION("Dimension position supplied, but not required"); 00443 } 00444 } 00445 00446 if (mIsUnlimitedDimensionSet) 00447 { 00448 if (mIsFixedDimensionSet) 00449 { 00450 // Go to the correct position in the file 00451 if (variableID == UNLIMITED_DIMENSION_VAR_ID) 00452 { 00453 (*mpCurrentAncillaryFile) << std::endl << " "; 00454 mpCurrentAncillaryFile->width(mFieldWidth); 00455 (*mpCurrentAncillaryFile) << variableValue; 00456 } 00457 else 00458 { 00459 int position; 00460 if (variableID == FIXED_DIMENSION_VAR_ID) 00461 { 00462 position = mRowStartPosition + (mRowWidth+1) * dimensionPosition + SPACING - 1; 00463 } 00464 else 00465 { 00466 // ordinary variables 00467 position = mRowStartPosition + (mRowWidth+1) * dimensionPosition + 00468 ((variableID + (mpFixedDimensionVariable != NULL)) * (mFieldWidth + SPACING)) + SPACING - 1; 00469 } 00470 00471 mpCurrentOutputFile->seekp(position); 00472 mpCurrentOutputFile->width(mFieldWidth); 00473 (*mpCurrentOutputFile) << variableValue; 00474 } 00475 } 00476 else 00477 { 00478 // Go to the correct position in the file 00479 int position; 00480 if (variableID == UNLIMITED_DIMENSION_VAR_ID) 00481 { 00482 position = mRowStartPosition + SPACING - 1; 00483 } 00484 else 00485 { 00486 position = (variableID + (mpUnlimitedDimensionVariable != NULL)) * (mFieldWidth + SPACING) + 00487 mRowStartPosition + SPACING - 1; 00488 } 00489 00490 mpCurrentOutputFile->seekp(position); 00491 mpCurrentOutputFile->width(mFieldWidth); 00492 (*mpCurrentOutputFile) << variableValue; 00493 } 00494 } 00495 else 00496 { 00497 // Go to the correct position in the file 00498 int position; 00499 if (variableID == FIXED_DIMENSION_VAR_ID) 00500 { 00501 position = mRowStartPosition + (mRowWidth+1) * dimensionPosition + SPACING - 1; 00502 } 00503 else 00504 { 00505 position = mRowStartPosition + (mRowWidth+1) * dimensionPosition + 00506 ((variableID + (mpFixedDimensionVariable != NULL)) * (mFieldWidth + SPACING)) + SPACING - 1; 00507 } 00508 mpCurrentOutputFile->seekp(position); 00509 mpCurrentOutputFile->width(mFieldWidth); 00510 (*mpCurrentOutputFile) << variableValue; 00511 } 00512 00513 mHasPutVariable = true; 00514 }