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 */
00033 #include "ColumnDataWriter.hpp"
00034 
00035 
00036 using std::string;
00042 ColumnDataWriter::ColumnDataWriter(string directory, string baseName, bool cleanDirectory) :
00043         mOutputFileHandler(directory, cleanDirectory),
00044         mDirectory(directory),
00045         mBaseName(baseName),
00046         mIsInDefineMode(true),
00047         mIsFixedDimensionSet(false),
00048         mIsUnlimitedDimensionSet(false),
00049         mUnlimitedDimensionPosition(0),
00050         mFixedDimensionSize(-1),
00051         mpCurrentOutputFile(NULL),
00052         mpCurrentAncillaryFile(NULL),
00053         mpUnlimitedDimensionVariable(NULL),
00054         mpFixedDimensionVariable(NULL),
00055         mHasPutVariable(false),
00056         mNeedAdvanceAlongUnlimitedDimension(false)
00057 {}
00062 ColumnDataWriter::~ColumnDataWriter()
00063 {
00064     // Close any open output files.
00065     Close();
00066 
00067     // Delete memory allocated for variables.
00068     if (mpUnlimitedDimensionVariable != NULL)
00069     {
00070         delete mpUnlimitedDimensionVariable;
00071     }
00072     if (mpFixedDimensionVariable != NULL)
00073     {
00074         delete mpFixedDimensionVariable;
00075     }
00076 }
00077 
00081 std::string ColumnDataWriter::GetOutputDirectory(void)
00082 {
00083     return mOutputFileHandler.GetOutputDirectoryFullPath();
00084 }
00085 
00089 void ColumnDataWriter::Close()
00090 {
00091     if (mpCurrentOutputFile.get() != NULL)
00092     {
00093         mpCurrentOutputFile->close();
00094         mpCurrentOutputFile = out_stream(NULL);
00095     }
00096 
00097     if (mpCurrentAncillaryFile.get() != NULL)
00098     {
00099         mpCurrentAncillaryFile->close();
00100         mpCurrentAncillaryFile = out_stream(NULL);
00101     }
00102 }
00103 
00104 
00105 void ColumnDataWriter::CheckVariableName(std::string name)
00106 {
00107     if (name.length() == 0)
00108     {
00109         EXCEPTION("Variable name not allowed: may not be blank.");
00110     }
00111     CheckUnitsName(name);
00112 }
00113 
00114 void ColumnDataWriter::CheckUnitsName(std::string name)
00115 {
00116     for (unsigned i=0; i<name.length(); i++)
00117     {
00118         if (!isalnum(name[i]) && !(name[i]=='_'))
00119         {
00120             std::string error = "Variable name/units '" + name + "' not allowed: may only contain alphanumeric characters or '_'.";
00121             EXCEPTION(error);
00122         }
00123     }
00124 }
00125 
00134 int ColumnDataWriter::DefineUnlimitedDimension(string dimensionName, string dimensionUnits)
00135 {
00136     if (mIsUnlimitedDimensionSet)
00137     {
00138         EXCEPTION("Unlimited dimension already set. Cannot be defined twice");
00139     }
00140 
00141     if (!mIsInDefineMode)
00142     {
00143         EXCEPTION("Cannot define variables when not in Define mode");
00144     }
00145 
00146     CheckVariableName(dimensionName);
00147     CheckUnitsName(dimensionUnits);
00148 
00149     mUnlimitedDimensionName = dimensionName;
00150     mUnlimitedDimensionUnits = dimensionUnits;
00151 
00152     mpUnlimitedDimensionVariable = new DataWriterVariable;
00153     mpUnlimitedDimensionVariable->mVariableName = dimensionName;
00154     mpUnlimitedDimensionVariable->mVariableUnits = dimensionUnits;
00155 
00156     mIsUnlimitedDimensionSet = true;
00157 
00158     return UNLIMITED_DIMENSION_VAR_ID;
00159 }
00160 
00170 int ColumnDataWriter::DefineFixedDimension(string dimensionName, string dimensionUnits, long dimensionSize)
00171 {
00172     if (!mIsInDefineMode)
00173     {
00174         EXCEPTION("Cannot define variables when not in Define mode");
00175     }
00176     if (dimensionSize < 1)
00177     {
00178         EXCEPTION("Fixed dimension must be at least 1 long");
00179     }
00180 
00181     CheckVariableName(dimensionName);
00182     CheckUnitsName(dimensionUnits);
00183 
00184     mFixedDimensionName = dimensionName;
00185     mFixedDimensionUnits = dimensionUnits;
00186     mFixedDimensionSize = dimensionSize;
00187 
00188     mIsFixedDimensionSet = true;
00189 
00190     mpFixedDimensionVariable = new DataWriterVariable;
00191     mpFixedDimensionVariable->mVariableName = dimensionName;
00192     mpFixedDimensionVariable->mVariableUnits = dimensionUnits;
00193     return FIXED_DIMENSION_VAR_ID;
00194 }
00195 
00206 int ColumnDataWriter::DefineVariable(string variableName, string variableUnits)
00207 {
00208     if (!mIsInDefineMode)
00209     {
00210         EXCEPTION("Cannot define variables when not in Define mode");
00211     }
00212 
00213     CheckVariableName(variableName);
00214     CheckUnitsName(variableUnits);
00215 
00216     DataWriterVariable new_variable;
00217     new_variable.mVariableName = variableName;
00218     new_variable.mVariableUnits = variableUnits;
00219     int variable_id;
00220 
00221     if (variableName == mUnlimitedDimensionName)
00222     {
00223         EXCEPTION("Variable name: " + variableName + " already in use as unlimited dimension");
00224     }
00225     else if (variableName == mFixedDimensionName)
00226     {
00227         EXCEPTION("Variable name: " + variableName + " already in use as fixed dimension");
00228     }
00229     else //ordinary variable
00230     {
00231         //add the variable to the variable vector
00232         mVariables.push_back(new_variable);
00233         //use the index of the variable vector as the variable ID.
00234         //this is ok since there is no way to remove variables.
00235         variable_id = mVariables.size()-1;
00236     }
00237 
00238     return variable_id;
00239 }
00240 
00241 
00246 void ColumnDataWriter::EndDefineMode()
00247 {
00248     //Check that a dimension has been defined
00249     if (mIsFixedDimensionSet == false && mIsUnlimitedDimensionSet == false)
00250     {
00251         EXCEPTION("Cannot end define mode. No dimensions have been defined.");
00252     }
00253     //Check that at least one variable has been defined
00254     if (mVariables.size() < 1)
00255     {
00256         EXCEPTION("Cannot end define mode. No variables have been defined.");
00257     }
00258     //Calculate the width of each row
00259     int unlimited_dimension_variable = (mpUnlimitedDimensionVariable != NULL);
00260     int fixed_dimension_variable = (mpFixedDimensionVariable != NULL);
00261     if (mIsUnlimitedDimensionSet)
00262     {
00263         if (mIsFixedDimensionSet)
00264         {
00265             mRowWidth = (mVariables.size() + fixed_dimension_variable)  * (FIELD_WIDTH + SPACING);
00266             mAncillaryRowWidth = FIELD_WIDTH + SPACING;
00267             //write out the headers for the first position along the unlimited dimension
00268             std::stringstream suffix;
00269             suffix << std::setfill('0') << std::setw(FILE_SUFFIX_WIDTH) << mUnlimitedDimensionPosition;
00270 
00271             if (mpUnlimitedDimensionVariable != NULL)
00272             {
00273                 std::string ancillary_filename = mBaseName + "_unlimited.dat";
00274                 mpCurrentAncillaryFile = mOutputFileHandler.OpenOutputFile(
00275                                              ancillary_filename, std::ios::out);
00276                 (*mpCurrentAncillaryFile) << std::setiosflags(std::ios::scientific);
00277                 (*mpCurrentAncillaryFile) << std::setprecision(FIELD_WIDTH-6);
00278                 if (mpUnlimitedDimensionVariable != NULL)
00279                 {
00280                     (*mpCurrentAncillaryFile) << mpUnlimitedDimensionVariable->mVariableName
00281                     << "(" << mpUnlimitedDimensionVariable->mVariableUnits << ") ";
00282                 }
00283             }
00284             mAncillaryRowStartPosition = mpCurrentAncillaryFile->tellp();
00285             std::string filename = mBaseName + "_" + suffix.str() + ".dat";
00286             this->CreateFixedDimensionFile(filename);
00287         }
00288         else
00289         {
00290             mRowWidth = (mVariables.size() + unlimited_dimension_variable)  * (FIELD_WIDTH + SPACING);
00291             //write out the column headers
00292             std::string filename = mBaseName + ".dat";
00293             mpCurrentOutputFile = mOutputFileHandler.OpenOutputFile(filename, std::ios::out);
00294             (*mpCurrentOutputFile) << std::setiosflags(std::ios::scientific);
00295             (*mpCurrentOutputFile) << std::setprecision(FIELD_WIDTH-6);
00296             if (mpUnlimitedDimensionVariable != NULL)
00297             {
00298                 (*mpCurrentOutputFile) << mpUnlimitedDimensionVariable->mVariableName
00299                 << "(" << mpUnlimitedDimensionVariable->mVariableUnits << ") ";
00300             }
00301             //Write out header(which may contain several variabls) for output file.
00302             //In this scope the method "CreateFixedDimensionFile" has not been invoked,
00303             //because there is no mFixedDimensionSize available.
00304             for (unsigned i = 0; i < mVariables.size(); i++)
00305             {
00306                 (*mpCurrentOutputFile) << mVariables[i].mVariableName << "(" << mVariables[i].mVariableUnits << ")";
00307                 if (i < mVariables.size()-1)
00308                 {
00309                     (*mpCurrentOutputFile) << " ";
00310                 }
00311             }
00312             (*mpCurrentOutputFile) << std::endl;
00313             mRowStartPosition = mpCurrentOutputFile->tellp();
00314             //write out a line of blank space which is #variables * (FIELD_WIDTH + 1) -1
00315             std::string blank_line(mRowWidth,' ');
00316             (*mpCurrentOutputFile) << blank_line;
00317         }
00318     }
00319     else
00320     {
00321         // The fixed dimension must be set at this point or we wouldn't be here
00322         mRowWidth = (mVariables.size() + fixed_dimension_variable)  * (FIELD_WIDTH + SPACING);
00323         std::string filename = mBaseName + ".dat";
00324         this->CreateFixedDimensionFile(filename);
00325     }
00326 
00327     // Write info file
00328     std::string infoname = mBaseName + ".info";
00329     this->CreateInfoFile(infoname);
00330 
00331     mIsInDefineMode = false;
00332 }
00333 
00338 void ColumnDataWriter::CreateFixedDimensionFile(std::string filename)
00339 {
00340     //create new data file
00341     mpCurrentOutputFile = mOutputFileHandler.OpenOutputFile(filename, std::ios::out);
00342     (*mpCurrentOutputFile) << std::setiosflags(std::ios::scientific);
00343     (*mpCurrentOutputFile) << std::setprecision(FIELD_WIDTH-6);
00344     if (mpFixedDimensionVariable != NULL)
00345     {
00346         (*mpCurrentOutputFile) << mpFixedDimensionVariable->mVariableName
00347         << "(" << mpFixedDimensionVariable->mVariableUnits << ") ";
00348     }
00349     //write out the column headers and spaces for the rest of the file
00350     for (unsigned i = 0; i < mVariables.size(); i++)
00351     {
00352         (*mpCurrentOutputFile) << mVariables[i].mVariableName << "(" << mVariables[i].mVariableUnits << ")";
00353         if (i < mVariables.size()-1)
00354         {
00355             (*mpCurrentOutputFile) << " ";
00356         }
00357     }
00358     (*mpCurrentOutputFile) << std::endl;
00359     mRowStartPosition = mpCurrentOutputFile->tellp();
00360     std::string blank_line(mRowWidth,' ');
00361     for (int i = 0; i < mFixedDimensionSize; i++)
00362     {
00363         (*mpCurrentOutputFile) << blank_line << std::endl;
00364     }
00365 
00366 }
00367 
00368 
00369 
00373 void ColumnDataWriter::CreateInfoFile(std::string filename)
00374 {
00375     //create new info file
00376     out_stream p_info_file = mOutputFileHandler.OpenOutputFile(filename, std::ios::out);
00377     (*p_info_file) << "FIXED " << mFixedDimensionSize << std::endl;
00378     (*p_info_file) << "UNLIMITED " << mIsUnlimitedDimensionSet << std::endl;
00379     (*p_info_file) << "VARIABLES " << mVariables.size() << std::endl;
00380     p_info_file->close();
00381 }
00382 
00383 
00389 void ColumnDataWriter::DoAdvanceAlongUnlimitedDimension()
00390 {
00391     mHasPutVariable = false;
00392     mNeedAdvanceAlongUnlimitedDimension = false;
00393 
00394     if (mIsUnlimitedDimensionSet)
00395     {
00396         if (mIsFixedDimensionSet)
00397         {
00398             //first close the current file before creating another one
00399             mpCurrentOutputFile->close();
00400             std::stringstream suffix;
00401             suffix << std::setfill('0') << std::setw(FILE_SUFFIX_WIDTH) << mUnlimitedDimensionPosition + 1;
00402 
00403 
00404 //            // pad out the suffix, so that its always 6 digits
00405 //            while (suffix.size() < 6)
00406 //            {
00407 //                suffix = "0" + suffix;
00408 //            }
00409 
00410             std::string filename = mBaseName + "_" + suffix.str() + ".dat";
00411             this->CreateFixedDimensionFile(filename);
00412         }
00413         else
00414         {
00415             //go to the end of the current line
00416             mpCurrentOutputFile->seekp(mRowStartPosition+mRowWidth);
00417             (*mpCurrentOutputFile) << std::endl;
00418             mRowStartPosition = mpCurrentOutputFile->tellp();
00419             std::string blank_line(mRowWidth,' ');
00420             (*mpCurrentOutputFile) << blank_line;
00421         }
00422     }
00423     else
00424     {
00425         EXCEPTION("Cannot advance along unlimited dimension if it is not defined");
00426     }
00427     mUnlimitedDimensionPosition++;
00428 }
00429 
00430 
00435 void ColumnDataWriter::AdvanceAlongUnlimitedDimension()
00436 {
00437     if (mHasPutVariable)
00438         mNeedAdvanceAlongUnlimitedDimension = true;
00439 }
00440 
00441 
00442 //dimensionPosition is required if there is a fixed dimension, and will be the position along that dimension
00447 void ColumnDataWriter::PutVariable(int variableID, double variableValue, long dimensionPosition)
00448 {
00449     if (mNeedAdvanceAlongUnlimitedDimension)
00450         DoAdvanceAlongUnlimitedDimension();
00451 
00452     //check that we are not in define mode
00453     if (mIsInDefineMode)
00454     {
00455         EXCEPTION("Cannot put variables when in Define mode");
00456     }
00457     //Check that variableID is in range (exception)
00458     if (variableID > (int)mVariables.size() ||
00459         (variableID != UNLIMITED_DIMENSION_VAR_ID &&
00460          variableID != FIXED_DIMENSION_VAR_ID &&
00461          variableID < 0))
00462     {
00463         EXCEPTION("variableID unknown");
00464     }
00465 
00466     if (mIsFixedDimensionSet)
00467     {
00468         if (dimensionPosition == -1 && variableID != UNLIMITED_DIMENSION_VAR_ID)
00469         {
00470             EXCEPTION("Dimension position not supplied");
00471         }
00472         if (dimensionPosition < -1 || dimensionPosition >= mFixedDimensionSize)
00473         {
00474             EXCEPTION("Dimension position out of range");
00475         }
00476         if (dimensionPosition != -1 && variableID == UNLIMITED_DIMENSION_VAR_ID)
00477         {
00478             EXCEPTION("Dimension position supplied, but not required");
00479         }
00480     }
00481 
00482     if (mIsUnlimitedDimensionSet)
00483     {
00484         if (mIsFixedDimensionSet)
00485         {
00486             //go to the correct position in the file
00487             if (variableID == UNLIMITED_DIMENSION_VAR_ID)
00488             {
00489 
00490                 if (variableValue >= 0)
00491                 {
00492                     (*mpCurrentAncillaryFile) << std::endl << "  ";
00493                 }
00494                 else //negative variable value has extra minus sign
00495                 {
00496                     (*mpCurrentAncillaryFile) << std::endl << " ";
00497                 }
00498                 mpCurrentAncillaryFile->width(FIELD_WIDTH);
00499                 (*mpCurrentAncillaryFile) << variableValue;
00500             }
00501             else
00502             {
00503                 int position;
00504                 if (variableID == FIXED_DIMENSION_VAR_ID)
00505                 {
00506                     position = mRowStartPosition + (mRowWidth+1) * dimensionPosition + SPACING;
00507                 }
00508                 else
00509                 {
00510                     //ordinary variables
00511                     position = mRowStartPosition + (mRowWidth+1) * dimensionPosition +
00512                                ((variableID + (mpFixedDimensionVariable != NULL))* (FIELD_WIDTH + SPACING)) + SPACING;
00513                 }
00514 
00515                 if (variableValue >= 0)
00516                 {
00517                     mpCurrentOutputFile->seekp(position);
00518                     mpCurrentOutputFile->width(FIELD_WIDTH);
00519                 }
00520                 else //negative variable value has extra minus sign
00521                 {
00522                     mpCurrentOutputFile->seekp(position-1);
00523                     mpCurrentOutputFile->width(FIELD_WIDTH);
00524                 }
00525                 (*mpCurrentOutputFile) << variableValue;
00526             }
00527         }
00528         else
00529         {
00530             //go to the correct position in the file
00531             int position;
00532             if (variableID == UNLIMITED_DIMENSION_VAR_ID)
00533             {
00534                 position = mRowStartPosition + SPACING;
00535             }
00536             else
00537             {
00538                 position = (variableID + (mpUnlimitedDimensionVariable != NULL)) * (FIELD_WIDTH + SPACING) + mRowStartPosition + SPACING;
00539             }
00540 
00541             if (variableValue >= 0)
00542             {
00543                 mpCurrentOutputFile->seekp(position);
00544                 mpCurrentOutputFile->width(FIELD_WIDTH);
00545             }
00546             else //negative variable value has extra minus sign
00547             {
00548                 mpCurrentOutputFile->seekp(position-1);
00549                 mpCurrentOutputFile->width(FIELD_WIDTH);
00550             }
00551             (*mpCurrentOutputFile) << variableValue;
00552         }
00553     }
00554     else
00555     {
00556         //go to the correct position in the file
00557         int position;
00558         if (variableID == FIXED_DIMENSION_VAR_ID)
00559         {
00560             position = mRowStartPosition + (mRowWidth+1) * dimensionPosition + SPACING;
00561         }
00562         else
00563         {
00564             position = mRowStartPosition + (mRowWidth+1) * dimensionPosition +
00565                        ((variableID + (mpFixedDimensionVariable != NULL))* (FIELD_WIDTH + SPACING)) + SPACING;
00566         }
00567         if (variableValue >= 0)
00568         {
00569             mpCurrentOutputFile->seekp(position);
00570             mpCurrentOutputFile->width(FIELD_WIDTH);
00571         }
00572         else //negative variable value has extra minus sign
00573         {
00574             mpCurrentOutputFile->seekp(position-1);
00575             mpCurrentOutputFile->width(FIELD_WIDTH);
00576         }
00577 
00578         (*mpCurrentOutputFile) << variableValue;
00579 
00580     }
00581 
00582     mHasPutVariable = true;
00583 }

Generated on Wed Mar 18 12:51:52 2009 for Chaste by  doxygen 1.5.5