ColumnDataWriter.cpp

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

Generated on Mon Apr 18 11:35:28 2011 for Chaste by  doxygen 1.5.5