ColumnDataWriter.cpp

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

Generated on Tue Aug 4 16:10:22 2009 for Chaste by  doxygen 1.5.5