ColumnDataWriter.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 <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     // Close any open output files
00083     Close();
00084 
00085     // Delete memory allocated for variables
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 // ordinary variable
00215     {
00216         // Add the variable to the variable vector
00217         DataWriterVariable new_variable;
00218         new_variable.mVariableName = rVariableName;
00219         new_variable.mVariableUnits = rVariableUnits;
00220         mVariables.push_back(new_variable);
00221 
00222         // Use the index of the variable vector as the variable ID.
00223         // This is ok since there is no way to remove variables.
00224         variable_id = mVariables.size()-1;
00225     }
00226 
00227     return variable_id;
00228 }
00229 
00230 void ColumnDataWriter::EndDefineMode()
00231 {
00232     // Check that a dimension has been defined
00233     if (mIsFixedDimensionSet == false && mIsUnlimitedDimensionSet == false)
00234     {
00235         EXCEPTION("Cannot end define mode. No dimensions have been defined.");
00236     }
00237     // Check that at least one variable has been defined
00238     if (mVariables.size() < 1)
00239     {
00240         EXCEPTION("Cannot end define mode. No variables have been defined.");
00241     }
00242     // Calculate the width of each row
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             // Write out the headers for the first position along the unlimited dimension
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             // Write out the column headers
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              * Write out header(which may contain several variables) for output file.
00288              * In this scope the method "CreateFixedDimensionFile" has not been invoked,
00289              * because there is no mFixedDimensionSize available.
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             // Write out a line of blank space which is #variables * (mFieldWidth + 1) -1
00303             std::string blank_line(mRowWidth, ' ');
00304             (*mpCurrentOutputFile) << blank_line;
00305         }
00306     }
00307     else
00308     {
00309         // The fixed dimension must be set at this point or we wouldn't be here
00310         mRowWidth = (mVariables.size() + fixed_dimension_variable) * (mFieldWidth + SPACING);
00311         std::string filename = mBaseName + ".dat";
00312         this->CreateFixedDimensionFile(filename);
00313     }
00314 
00315     // Write info file
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     // Create new data file
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     // Write out the column headers and spaces for the rest of the file
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     // Create new info file
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             //first close the current file before creating another one
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             //go to the end of the current line
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     // 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+SPACING) * dimensionPosition;
00463                 }
00464                 else
00465                 {
00466                     // ordinary variables
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             // Go to the correct position in the file
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         // Go to the correct position in the file
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 }

Generated by  doxygen 1.6.2