ColumnDataWriter.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00041 #include <ctype.h>
00042 #include <sstream>
00043 #include <iomanip>
00044 #include <fstream>
00045
00046 #include "ColumnDataWriter.hpp"
00047 #include "ColumnDataConstants.hpp"
00048 #include "Exception.hpp"
00049 #include "Version.hpp"
00050
00051
00052 ColumnDataWriter::ColumnDataWriter(const std::string& rDirectory,
00053 const std::string& rBaseName,
00054 bool cleanDirectory,
00055 unsigned precision)
00056 : mOutputFileHandler(rDirectory, cleanDirectory),
00057 mDirectory(rDirectory),
00058 mBaseName(rBaseName),
00059 mIsInDefineMode(true),
00060 mIsFixedDimensionSet(false),
00061 mIsUnlimitedDimensionSet(false),
00062 mUnlimitedDimensionPosition(0),
00063 mFixedDimensionSize(-1),
00064 mpCurrentOutputFile(NULL),
00065 mpCurrentAncillaryFile(NULL),
00066 mpUnlimitedDimensionVariable(NULL),
00067 mpFixedDimensionVariable(NULL),
00068 mFieldWidth(precision+8),
00069 mPrecision(precision),
00070 mHasPutVariable(false),
00071 mNeedAdvanceAlongUnlimitedDimension(false),
00072 mCommentForInfoFile("")
00073 {
00074 if (mPrecision<2 || mPrecision>20)
00075 {
00076 EXCEPTION("Precision must be between 2 and 20 (inclusive)");
00077 }
00078 }
00079
00080 ColumnDataWriter::~ColumnDataWriter()
00081 {
00082
00083 Close();
00084
00085
00086 if (mpUnlimitedDimensionVariable != NULL)
00087 {
00088 delete mpUnlimitedDimensionVariable;
00089 }
00090 if (mpFixedDimensionVariable != NULL)
00091 {
00092 delete mpFixedDimensionVariable;
00093 }
00094 }
00095
00096 std::string ColumnDataWriter::GetOutputDirectory()
00097 {
00098 return mOutputFileHandler.GetOutputDirectoryFullPath();
00099 }
00100
00101 void ColumnDataWriter::Close()
00102 {
00103 if (mpCurrentOutputFile.get() != NULL)
00104 {
00105 mpCurrentOutputFile->close();
00106 mpCurrentOutputFile = out_stream(NULL);
00107 }
00108
00109 if (mpCurrentAncillaryFile.get() != NULL)
00110 {
00111 mpCurrentAncillaryFile->close();
00112 mpCurrentAncillaryFile = out_stream(NULL);
00113 }
00114 }
00115
00116 void ColumnDataWriter::CheckVariableName(const std::string& rName)
00117 {
00118 if (rName.length() == 0)
00119 {
00120 EXCEPTION("Variable name not allowed: may not be blank.");
00121 }
00122 CheckUnitsName(rName);
00123 }
00124
00125 void ColumnDataWriter::CheckUnitsName(const std::string& rName)
00126 {
00127 for (unsigned i=0; i<rName.length(); i++)
00128 {
00129 if (!isalnum(rName[i]) && !(rName[i]=='_'))
00130 {
00131 std::string error = "Variable name/units '" + rName + "' not allowed: may only contain alphanumeric characters or '_'.";
00132 EXCEPTION(error);
00133 }
00134 }
00135 }
00136
00137 int ColumnDataWriter::DefineUnlimitedDimension(const std::string& rDimensionName,
00138 const std::string& rDimensionUnits)
00139 {
00140 if (mIsUnlimitedDimensionSet)
00141 {
00142 EXCEPTION("Unlimited dimension already set. Cannot be defined twice");
00143 }
00144
00145 if (!mIsInDefineMode)
00146 {
00147 EXCEPTION("Cannot define variables when not in Define mode");
00148 }
00149
00150 CheckVariableName(rDimensionName);
00151 CheckUnitsName(rDimensionUnits);
00152
00153 mUnlimitedDimensionName = rDimensionName;
00154 mUnlimitedDimensionUnits = rDimensionUnits;
00155
00156 mpUnlimitedDimensionVariable = new DataWriterVariable;
00157 mpUnlimitedDimensionVariable->mVariableName = rDimensionName;
00158 mpUnlimitedDimensionVariable->mVariableUnits = rDimensionUnits;
00159
00160 mIsUnlimitedDimensionSet = true;
00161
00162 return UNLIMITED_DIMENSION_VAR_ID;
00163 }
00164
00165 int ColumnDataWriter::DefineFixedDimension(const std::string& rDimensionName,
00166 const std::string& rDimensionUnits,
00167 long dimensionSize)
00168 {
00169 if (!mIsInDefineMode)
00170 {
00171 EXCEPTION("Cannot define variables when not in Define mode");
00172 }
00173 if (dimensionSize < 1)
00174 {
00175 EXCEPTION("Fixed dimension must be at least 1 long");
00176 }
00177
00178 CheckVariableName(rDimensionName);
00179 CheckUnitsName(rDimensionUnits);
00180
00181 mFixedDimensionName = rDimensionName;
00182 mFixedDimensionUnits = rDimensionUnits;
00183 mFixedDimensionSize = dimensionSize;
00184
00185 mIsFixedDimensionSet = true;
00186
00187 mpFixedDimensionVariable = new DataWriterVariable;
00188 mpFixedDimensionVariable->mVariableName = rDimensionName;
00189 mpFixedDimensionVariable->mVariableUnits = rDimensionUnits;
00190 return FIXED_DIMENSION_VAR_ID;
00191 }
00192
00193 int ColumnDataWriter::DefineVariable(const std::string& rVariableName,
00194 const std::string& rVariableUnits)
00195 {
00196 if (!mIsInDefineMode)
00197 {
00198 EXCEPTION("Cannot define variables when not in Define mode");
00199 }
00200
00201 CheckVariableName(rVariableName);
00202 CheckUnitsName(rVariableUnits);
00203
00204 int variable_id;
00205
00206 if (rVariableName == mUnlimitedDimensionName)
00207 {
00208 EXCEPTION("Variable name: " + rVariableName + " already in use as unlimited dimension");
00209 }
00210 else if (rVariableName == mFixedDimensionName)
00211 {
00212 EXCEPTION("Variable name: " + rVariableName + " already in use as fixed dimension");
00213 }
00214 else
00215 {
00216
00217 DataWriterVariable new_variable;
00218 new_variable.mVariableName = rVariableName;
00219 new_variable.mVariableUnits = rVariableUnits;
00220 mVariables.push_back(new_variable);
00221
00222
00223
00224 variable_id = mVariables.size()-1;
00225 }
00226
00227 return variable_id;
00228 }
00229
00230 void ColumnDataWriter::EndDefineMode()
00231 {
00232
00233 if (mIsFixedDimensionSet == false && mIsUnlimitedDimensionSet == false)
00234 {
00235 EXCEPTION("Cannot end define mode. No dimensions have been defined.");
00236 }
00237
00238 if (mVariables.size() < 1)
00239 {
00240 EXCEPTION("Cannot end define mode. No variables have been defined.");
00241 }
00242
00243 int unlimited_dimension_variable = (mpUnlimitedDimensionVariable != NULL);
00244 int fixed_dimension_variable = (mpFixedDimensionVariable != NULL);
00245 if (mIsUnlimitedDimensionSet)
00246 {
00247 if (mIsFixedDimensionSet)
00248 {
00249 mRowWidth = (mVariables.size() + fixed_dimension_variable) * (mFieldWidth + SPACING);
00250 mAncillaryRowWidth = mFieldWidth + SPACING;
00251
00252
00253 std::stringstream suffix;
00254 suffix << std::setfill('0') << std::setw(FILE_SUFFIX_WIDTH) << mUnlimitedDimensionPosition;
00255
00256 if (mpUnlimitedDimensionVariable != NULL)
00257 {
00258 std::string ancillary_filename = mBaseName + "_unlimited.dat";
00259 mpCurrentAncillaryFile = mOutputFileHandler.OpenOutputFile(ancillary_filename, std::ios::out | std::ios::binary);
00260 (*mpCurrentAncillaryFile) << std::setiosflags(std::ios::scientific);
00261 (*mpCurrentAncillaryFile) << std::setprecision(mPrecision);
00262 if (mpUnlimitedDimensionVariable != NULL)
00263 {
00264 (*mpCurrentAncillaryFile) << mpUnlimitedDimensionVariable->mVariableName
00265 << "(" << mpUnlimitedDimensionVariable->mVariableUnits << ") ";
00266 }
00267 }
00268 mAncillaryRowStartPosition = mpCurrentAncillaryFile->tellp();
00269 std::string filename = mBaseName + "_" + suffix.str() + ".dat";
00270 this->CreateFixedDimensionFile(filename);
00271 }
00272 else
00273 {
00274 mRowWidth = (mVariables.size() + unlimited_dimension_variable) * (mFieldWidth + SPACING);
00275
00276
00277 std::string filename = mBaseName + ".dat";
00278 mpCurrentOutputFile = mOutputFileHandler.OpenOutputFile(filename, std::ios::out);
00279 (*mpCurrentOutputFile) << std::setiosflags(std::ios::scientific);
00280 (*mpCurrentOutputFile) << std::setprecision(mPrecision);
00281 if (mpUnlimitedDimensionVariable != NULL)
00282 {
00283 (*mpCurrentOutputFile) << mpUnlimitedDimensionVariable->mVariableName
00284 << "(" << mpUnlimitedDimensionVariable->mVariableUnits << ") ";
00285 }
00286
00287
00288
00289
00290
00291 for (unsigned i=0; i<mVariables.size(); i++)
00292 {
00293 (*mpCurrentOutputFile) << mVariables[i].mVariableName << "(" << mVariables[i].mVariableUnits << ")";
00294 if (i < mVariables.size()-1)
00295 {
00296 (*mpCurrentOutputFile) << " ";
00297 }
00298 }
00299 (*mpCurrentOutputFile) << std::endl;
00300 mRowStartPosition = mpCurrentOutputFile->tellp();
00301
00302
00303 std::string blank_line(mRowWidth, ' ');
00304 (*mpCurrentOutputFile) << blank_line;
00305 }
00306 }
00307 else
00308 {
00309
00310 mRowWidth = (mVariables.size() + fixed_dimension_variable) * (mFieldWidth + SPACING);
00311 std::string filename = mBaseName + ".dat";
00312 this->CreateFixedDimensionFile(filename);
00313 }
00314
00315
00316 std::string infoname = mBaseName + ".info";
00317 this->CreateInfoFile(infoname);
00318
00319 mIsInDefineMode = false;
00320 }
00321
00322 void ColumnDataWriter::CreateFixedDimensionFile(const std::string& rFileName)
00323 {
00324
00325 mpCurrentOutputFile = mOutputFileHandler.OpenOutputFile(rFileName, std::ios::out | std::ios::binary);
00326 (*mpCurrentOutputFile) << std::setiosflags(std::ios::scientific);
00327 (*mpCurrentOutputFile) << std::setprecision(mPrecision);
00328 if (mpFixedDimensionVariable != NULL)
00329 {
00330 (*mpCurrentOutputFile) << mpFixedDimensionVariable->mVariableName
00331 << "(" << mpFixedDimensionVariable->mVariableUnits << ") ";
00332 }
00333
00334 for (unsigned i = 0; i < mVariables.size(); i++)
00335 {
00336 (*mpCurrentOutputFile) << mVariables[i].mVariableName << "(" << mVariables[i].mVariableUnits << ")";
00337 if (i < mVariables.size()-1)
00338 {
00339 (*mpCurrentOutputFile) << " ";
00340 }
00341 }
00342 (*mpCurrentOutputFile) << std::endl;
00343 mRowStartPosition = mpCurrentOutputFile->tellp();
00344 std::string blank_line(mRowWidth, ' ');
00345 for (int i = 0; i < mFixedDimensionSize; i++)
00346 {
00347 (*mpCurrentOutputFile) << blank_line << std::endl;
00348 }
00349 }
00350
00351 void ColumnDataWriter::CreateInfoFile(const std::string& rFileName)
00352 {
00353
00354 out_stream p_info_file = mOutputFileHandler.OpenOutputFile(rFileName, std::ios::out | std::ios::binary);
00355 (*p_info_file) << "FIXED " << mFixedDimensionSize << std::endl;
00356 (*p_info_file) << "UNLIMITED " << mIsUnlimitedDimensionSet << std::endl;
00357 (*p_info_file) << "VARIABLES " << mVariables.size() << std::endl;
00358 if (mCommentForInfoFile != "")
00359 {
00360 *p_info_file << mCommentForInfoFile << std::endl;
00361 }
00362 *p_info_file << ChasteBuildInfo::GetProvenanceString();
00363 p_info_file->close();
00364 }
00365
00366 void ColumnDataWriter::DoAdvanceAlongUnlimitedDimension()
00367 {
00368 mHasPutVariable = false;
00369 mNeedAdvanceAlongUnlimitedDimension = false;
00370
00371 if (mIsUnlimitedDimensionSet)
00372 {
00373 if (mIsFixedDimensionSet)
00374 {
00375
00376 mpCurrentOutputFile->close();
00377 std::stringstream suffix;
00378 suffix << std::setfill('0') << std::setw(FILE_SUFFIX_WIDTH) << mUnlimitedDimensionPosition + 1;
00379
00380 std::string filename = mBaseName + "_" + suffix.str() + ".dat";
00381 this->CreateFixedDimensionFile(filename);
00382 }
00383 else
00384 {
00385
00386 mpCurrentOutputFile->seekp(mRowStartPosition+mRowWidth);
00387 (*mpCurrentOutputFile) << std::endl;
00388 mRowStartPosition = mpCurrentOutputFile->tellp();
00389 std::string blank_line(mRowWidth,' ');
00390 (*mpCurrentOutputFile) << blank_line;
00391 }
00392 }
00393 else
00394 {
00395 EXCEPTION("Cannot advance along unlimited dimension if it is not defined");
00396 }
00397 mUnlimitedDimensionPosition++;
00398 }
00399
00400 void ColumnDataWriter::AdvanceAlongUnlimitedDimension()
00401 {
00402 if (mHasPutVariable)
00403 {
00404 mNeedAdvanceAlongUnlimitedDimension = true;
00405 }
00406 }
00407
00408 void ColumnDataWriter::PutVariable(int variableID, double variableValue, long dimensionPosition)
00409 {
00410
00411 if (mNeedAdvanceAlongUnlimitedDimension)
00412 {
00413 DoAdvanceAlongUnlimitedDimension();
00414 }
00415
00416
00417 if (mIsInDefineMode)
00418 {
00419 EXCEPTION("Cannot put variables when in Define mode");
00420 }
00421
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
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+SPACING) * dimensionPosition;
00463 }
00464 else
00465 {
00466
00467 position = mRowStartPosition + (mRowWidth+SPACING) * dimensionPosition +
00468 ((variableID + (mpFixedDimensionVariable != NULL)) * (mFieldWidth + SPACING));
00469 }
00470
00471 mpCurrentOutputFile->seekp(position);
00472 mpCurrentOutputFile->width(mFieldWidth);
00473 (*mpCurrentOutputFile) << variableValue;
00474 }
00475 }
00476 else
00477 {
00478
00479 int position;
00480 if (variableID == UNLIMITED_DIMENSION_VAR_ID)
00481 {
00482 position = mRowStartPosition;
00483 }
00484 else
00485 {
00486 position = (variableID + (mpUnlimitedDimensionVariable != NULL)) * (mFieldWidth + SPACING) +
00487 mRowStartPosition;
00488 }
00489
00490 mpCurrentOutputFile->seekp(position);
00491 mpCurrentOutputFile->width(mFieldWidth);
00492 (*mpCurrentOutputFile) << variableValue;
00493
00494 }
00495 }
00496 else
00497 {
00498
00499 int position;
00500 if (variableID == FIXED_DIMENSION_VAR_ID)
00501 {
00502 position = mRowStartPosition + (mRowWidth+SPACING) * dimensionPosition;
00503 }
00504 else
00505 {
00506 position = mRowStartPosition + (mRowWidth+SPACING) * dimensionPosition +
00507 ((variableID + (mpFixedDimensionVariable != NULL)) * (mFieldWidth + SPACING));
00508 }
00509 mpCurrentOutputFile->seekp(position);
00510 mpCurrentOutputFile->width(mFieldWidth);
00511 (*mpCurrentOutputFile) << variableValue;
00512 }
00513
00514 mHasPutVariable = true;
00515 }