ColumnDataWriter.cpp

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

Generated on Mon Nov 1 12:35:17 2010 for Chaste by  doxygen 1.5.5