Hdf5DataWriter.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 /*
00029 * Implementation file for Hdf5DataWriter class.
00030 *
00031 */
00032 
00033 #include "Hdf5DataWriter.hpp"
00034 
00035 #include "Exception.hpp"
00036 #include "OutputFileHandler.hpp"
00037 #include "PetscTools.hpp"
00038 #include "Version.hpp"
00039 
00040 Hdf5DataWriter::Hdf5DataWriter(DistributedVectorFactory& rVectorFactory,
00041                                const std::string& rDirectory,
00042                                const std::string& rBaseName,
00043                                bool cleanDirectory,
00044                                bool extendData)
00045     : mrVectorFactory(rVectorFactory),
00046       mDirectory(rDirectory),
00047       mBaseName(rBaseName),
00048       mCleanDirectory(cleanDirectory),
00049       mIsInDefineMode(true),
00050       mIsFixedDimensionSet(false),
00051       mIsUnlimitedDimensionSet(false),
00052       mFileFixedDimensionSize(0u),
00053       mDataFixedDimensionSize(0u),
00054       mLo(mrVectorFactory.GetLow()),
00055       mHi(mrVectorFactory.GetHigh()),
00056       mNumberOwned(0u),
00057       mOffset(0u),
00058       mIsDataComplete(true),
00059       mNeedExtend(false),
00060       mCurrentTimeStep(0)
00061 {
00062     if (extendData && cleanDirectory)
00063     {
00064         EXCEPTION("You are asking to delete a file and then extend it, change arguments to constructor.");
00065     }
00066 
00067     if (extendData)
00068     {
00069         // Where to find the file
00070         OutputFileHandler output_file_handler(mDirectory, false);
00071         std::string results_dir = output_file_handler.GetOutputDirectoryFullPath();
00072         std::string file_name = results_dir + mBaseName + ".h5";
00073 
00074         // Set up a property list saying how we'll open the file
00075         hid_t property_list_id = H5Pcreate(H5P_FILE_ACCESS);
00076         H5Pset_fapl_mpio(property_list_id, PETSC_COMM_WORLD, MPI_INFO_NULL);
00077 
00078         // Open the file and free the property list
00079         mFileId = H5Fopen(file_name.c_str(), H5F_ACC_RDWR, property_list_id);
00080         H5Pclose(property_list_id);
00081 
00082         if (mFileId < 0)
00083         {
00084             mDatasetId = 0;
00085             EXCEPTION("Hdf5DataWriter could not open " + file_name);
00086         }
00087 
00088         // Open the main dataset, and figure out its size/shape
00089         mDatasetId = H5Dopen(mFileId, "Data");
00090         hid_t variables_dataspace = H5Dget_space(mDatasetId);
00091         //unsigned variables_dataset_rank = H5Sget_simple_extent_ndims(variables_dataspace);
00092         hsize_t dataset_max_sizes[DATASET_DIMS];
00093         H5Sget_simple_extent_dims(variables_dataspace, mDatasetDims, dataset_max_sizes);
00094         H5Sclose(variables_dataspace);
00095         // Check that an unlimited dimension is defined
00096         if (dataset_max_sizes[0] != H5S_UNLIMITED)
00097         {
00098             H5Dclose(mDatasetId);
00099             H5Fclose(mFileId);
00100             EXCEPTION("Tried to open a datafile for extending which doesn't have an unlimited dimension.");
00101         }
00102         mIsUnlimitedDimensionSet = true;
00103         // Sanity check other dimension sizes
00104         for (unsigned i=1; i<DATASET_DIMS; i++)  // Zero is excluded since it is unlimited
00105         {
00106             assert(mDatasetDims[i] == dataset_max_sizes[i]);
00107         }
00108         mFileFixedDimensionSize = mDatasetDims[1];
00109         mIsFixedDimensionSet = true;
00110         mVariables.reserve(mDatasetDims[2]);
00111 
00112         // Figure out what the variables are
00113         hid_t attribute_id = H5Aopen_name(mDatasetId, "Variable Details");
00114         hid_t attribute_type  = H5Aget_type(attribute_id);
00115         hid_t attribute_space = H5Aget_space(attribute_id);
00116         hsize_t attr_dataspace_dim;
00117         H5Sget_simple_extent_dims(attribute_space, &attr_dataspace_dim, NULL);
00118         unsigned num_columns = H5Sget_simple_extent_npoints(attribute_space);
00119         assert(num_columns == mDatasetDims[2]); // I think...
00120 
00121         char* string_array = (char *)malloc(sizeof(char)*MAX_STRING_SIZE*(int)num_columns);
00122         H5Aread(attribute_id, attribute_type, string_array);
00123         // Loop over columns/variables
00124         for (unsigned index=0; index<num_columns; index++)
00125         {
00126             // Read the string from the raw vector
00127             std::string column_name_unit(&string_array[MAX_STRING_SIZE*index]);
00128             // Find location of unit name
00129             size_t name_length = column_name_unit.find('(');
00130             size_t unit_length = column_name_unit.find(')') - name_length - 1;
00131             // Create the variable
00132             DataWriterVariable var;
00133             var.mVariableName = column_name_unit.substr(0, name_length);
00134             var.mVariableUnits = column_name_unit.substr(name_length+1, unit_length);
00135             mVariables.push_back(var);
00136         }
00137         // Free memory, release ids
00138         free(string_array);
00139         H5Tclose(attribute_type);
00140         H5Sclose(attribute_space);
00141         H5Aclose(attribute_id);
00142 
00143         // Now deal with time
00144         mUnlimitedDimensionName = "Time"; // Assumed by the reader...
00145         mTimeDatasetId = H5Dopen(mFileId, mUnlimitedDimensionName.c_str());
00146         mUnlimitedDimensionUnit = "ms"; // Assumed by Chaste...
00147         // How many time steps have been written so far?
00148         hid_t timestep_dataspace = H5Dget_space(mTimeDatasetId);
00149         hsize_t num_timesteps;
00150         H5Sget_simple_extent_dims(timestep_dataspace, &num_timesteps, NULL);
00151         H5Sclose(timestep_dataspace);
00152         mCurrentTimeStep = (long)num_timesteps - 1;
00153 
00154         // Incomplete data?
00155         attribute_id = H5Aopen_name(mDatasetId, "IsDataComplete");
00156         if (attribute_id < 0)
00157         {
00158 #define COVERAGE_IGNORE
00159             // Old format, before we added the attribute.
00160             EXCEPTION("Extending old-format files isn't supported.");
00161 #undef COVERAGE_IGNORE
00162         }
00163         else
00164         {
00165             attribute_type = H5Aget_type(attribute_id);
00166             attribute_space = H5Aget_space(attribute_id);
00167             unsigned is_data_complete;
00168             H5Aread(attribute_id, H5T_NATIVE_UINT, &is_data_complete);
00169             mIsDataComplete = (is_data_complete == 1) ? true : false;
00170             H5Tclose(attribute_type);
00171             H5Sclose(attribute_space);
00172             H5Aclose(attribute_id);
00173         }
00174         if (mIsDataComplete)
00175         {
00176             mNumberOwned = mrVectorFactory.GetLocalOwnership();
00177             mOffset = mLo;
00178             mDataFixedDimensionSize = mFileFixedDimensionSize;
00179         }
00180         else
00181         {
00182             // Read which nodes appear in the file (mIncompleteNodeIndices)
00183             attribute_id = H5Aopen_name(mDatasetId, "NodeMap");
00184             attribute_type  = H5Aget_type(attribute_id);
00185             attribute_space = H5Aget_space(attribute_id);
00186             // Get the dataset/dataspace dimensions
00187             unsigned num_node_indices = H5Sget_simple_extent_npoints(attribute_space);
00188             // Read data from hyperslab in the file into the hyperslab in memory
00189             mIncompleteNodeIndices.clear();
00190             mIncompleteNodeIndices.resize(num_node_indices);
00191             H5Aread(attribute_id, H5T_NATIVE_UINT, &mIncompleteNodeIndices[0]);
00192             // Release ids
00193             H5Tclose(attribute_type);
00194             H5Sclose(attribute_space);
00195             H5Aclose(attribute_id);
00196             // Set up what data we can
00197             mNumberOwned = mrVectorFactory.GetLocalOwnership();
00198             ComputeIncompleteOffset();
00202             mDataFixedDimensionSize = UINT_MAX;
00203             H5Dclose(mDatasetId);
00204             H5Dclose(mTimeDatasetId);
00205             H5Fclose(mFileId);
00206             EXCEPTION("Unable to extend an incomplete data file at present.");
00207         }
00208 
00209         // Done!
00210         mIsInDefineMode = false;
00211         AdvanceAlongUnlimitedDimension();
00212     }
00213 }
00214 
00215 Hdf5DataWriter::~Hdf5DataWriter()
00216 {
00217     Close();
00218 }
00219 
00220 void Hdf5DataWriter::DefineFixedDimension(long dimensionSize)
00221 {
00222     if (!mIsInDefineMode)
00223     {
00224         EXCEPTION("Cannot define variables when not in Define mode");
00225     }
00226     if (dimensionSize < 1)
00227     {
00228         EXCEPTION("Fixed dimension must be at least 1 long");
00229     }
00230     if (mIsFixedDimensionSet)
00231     {
00232         EXCEPTION("Fixed dimension already set");
00233     }
00234 
00235     // Work out the ownership details
00236     mLo = mrVectorFactory.GetLow();
00237     mHi = mrVectorFactory.GetHigh();
00238     mNumberOwned = mrVectorFactory.GetLocalOwnership();
00239     mOffset = mLo;
00240     mFileFixedDimensionSize = dimensionSize;
00241     mDataFixedDimensionSize = dimensionSize;
00242     mIsFixedDimensionSet = true;
00243 }
00244 
00245 void Hdf5DataWriter::DefineFixedDimension(const std::vector<unsigned>& rNodesToOuput, long vecSize)
00246 {
00247     unsigned vector_size = rNodesToOuput.size();
00248 
00249     for (unsigned index=0; index < vector_size-1; index++)
00250     {
00251         if (rNodesToOuput[index] >= rNodesToOuput[index+1])
00252         {
00253             EXCEPTION("Input should be monotonic increasing");
00254         }
00255     }
00256 
00257     if ((int) rNodesToOuput.back() >= vecSize)
00258     {
00259         EXCEPTION("Vector size doesn't match nodes to output");
00260     }
00261 
00262     DefineFixedDimension(vecSize);
00263 
00264     mFileFixedDimensionSize = vector_size;
00265     mIsDataComplete = false;
00266     mIncompleteNodeIndices = rNodesToOuput;
00267     ComputeIncompleteOffset();
00268 }
00269 
00270 void Hdf5DataWriter::ComputeIncompleteOffset()
00271 {
00272     mOffset = 0;
00273     mNumberOwned = 0;
00274     for (unsigned i=0; i<mIncompleteNodeIndices.size(); i++)
00275     {
00276         if (mIncompleteNodeIndices[i] < mLo)
00277         {
00278             mOffset++;
00279         }
00280         else if (mIncompleteNodeIndices[i] < mHi)
00281         {
00282             mNumberOwned++;
00283         }
00284      }
00285 }
00286 
00287 int Hdf5DataWriter::DefineVariable(const std::string& rVariableName,
00288                                    const std::string& rVariableUnits)
00289 {
00290     if (!mIsInDefineMode)
00291     {
00292         EXCEPTION("Cannot define variables when not in Define mode");
00293     }
00294 
00295     CheckVariableName(rVariableName);
00296     CheckUnitsName(rVariableUnits);
00297 
00298     // Check for the variable being already defined
00299     for (unsigned index=0; index<mVariables.size(); index++)
00300     {
00301         if (mVariables[index].mVariableName == rVariableName)
00302         {
00303             EXCEPTION("Variable name already exists");
00304         }
00305     }
00306 
00307     DataWriterVariable new_variable;
00308     new_variable.mVariableName = rVariableName;
00309     new_variable.mVariableUnits = rVariableUnits;
00310     int variable_id;
00311 
00312     // Add the variable to the variable vector
00313     mVariables.push_back(new_variable);
00314 
00315     // Use the index of the variable vector as the variable ID.
00316     // This is ok since there is no way to remove variables.
00317     variable_id = mVariables.size() - 1;
00318 
00319     return variable_id;
00320 }
00321 
00322 void Hdf5DataWriter::CheckVariableName(const std::string& rName)
00323 {
00324     if (rName.length() == 0)
00325     {
00326         EXCEPTION("Variable name not allowed: may not be blank.");
00327     }
00328     CheckUnitsName(rName);
00329 }
00330 
00331 void Hdf5DataWriter::CheckUnitsName(const std::string& rName)
00332 {
00333     for (unsigned i=0; i<rName.length(); i++)
00334     {
00335         if (!isalnum(rName[i]) && !(rName[i]=='_'))
00336         {
00337             std::string error = "Variable name/units '" + rName + "' not allowed: may only contain alphanumeric characters or '_'.";
00338             EXCEPTION(error);
00339         }
00340     }
00341 }
00342 
00343 void Hdf5DataWriter::EndDefineMode()
00344 {
00345     //Check that at least one variable has been defined
00346     if (mVariables.size() < 1)
00347     {
00348         EXCEPTION("Cannot end define mode. No variables have been defined.");
00349     }
00350 
00351     //Check that a fixed dimension has been defined
00352     if (mIsFixedDimensionSet == false)
00353     {
00354         EXCEPTION("Cannot end define mode. One fixed dimension should be defined.");
00355     }
00356 
00357     OutputFileHandler output_file_handler(mDirectory, mCleanDirectory);
00358     std::string results_dir = output_file_handler.GetOutputDirectoryFullPath();
00359     std::string file_name = results_dir + mBaseName + ".h5";
00360 
00361     // Set up a property list saying how we'll open the file
00362     hid_t property_list_id = H5Pcreate(H5P_FILE_ACCESS);
00363     H5Pset_fapl_mpio(property_list_id, PETSC_COMM_WORLD, MPI_INFO_NULL);
00364 
00365     // Create a file (collectively) and free the property list
00366     mFileId = H5Fcreate(file_name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, property_list_id);
00367     H5Pclose(property_list_id);
00368     if (mFileId < 0)
00369     {
00370         EXCEPTION("Hdf5DataWriter could not create " + file_name);
00371     }
00372     mIsInDefineMode = false;
00373 
00374     /*
00375      *  Create "Data" dataset
00376      */
00377     // Create the dataspace for the dataset.
00378     mDatasetDims[0] = 1; // While developing we got a non-documented "only the first dimension can be extendible" error.
00379     mDatasetDims[1] = mFileFixedDimensionSize;
00380     mDatasetDims[2] = mVariables.size();
00381 
00382     hsize_t* max_dims = NULL;
00383     hsize_t dataset_max_dims[DATASET_DIMS]; // dataset max dimensions
00384 
00385     hid_t cparms = H5P_DEFAULT;
00386 
00387     if (mIsUnlimitedDimensionSet)
00388     {
00389         dataset_max_dims[0] = H5S_UNLIMITED;
00390         dataset_max_dims[1] = mDatasetDims[1];
00391         dataset_max_dims[2] = mDatasetDims[2];
00392         max_dims = dataset_max_dims;
00393 
00394         // Modify dataset creation properties to enable chunking.
00395         hsize_t chunk_dims[DATASET_DIMS] ={1, mDatasetDims[1], mDatasetDims[2]};
00396         cparms = H5Pcreate (H5P_DATASET_CREATE);
00397         H5Pset_chunk( cparms, DATASET_DIMS, chunk_dims);
00398     }
00399 
00400     hid_t filespace = H5Screate_simple(DATASET_DIMS, mDatasetDims, max_dims);
00401 
00402     // Create the dataset and close filespace
00403     mDatasetId = H5Dcreate(mFileId, "Data", H5T_NATIVE_DOUBLE, filespace, cparms);
00404     H5Sclose(filespace);
00405 
00406     // Create dataspace for the name, unit attribute
00407     const unsigned MAX_STRING_SIZE = 100;
00408     hsize_t columns[1] = {mVariables.size()};
00409     hid_t colspace = H5Screate_simple(1, columns, NULL);
00410 
00411     // Create attribute for variable names
00412     char* col_data = (char*) malloc(mVariables.size() * sizeof(char) * MAX_STRING_SIZE);
00413 
00414     char* col_data_offset = col_data;
00415     for (unsigned var=0; var<mVariables.size(); var++)
00416     {
00417         std::string full_name = mVariables[var].mVariableName + "(" + mVariables[var].mVariableUnits + ")";
00418         strcpy (col_data_offset, full_name.c_str());
00419         col_data_offset += sizeof(char) * MAX_STRING_SIZE;
00420     }
00421 
00422     // Create the type 'string'
00423     hid_t string_type = H5Tcopy(H5T_C_S1);
00424     H5Tset_size(string_type, MAX_STRING_SIZE );
00425     hid_t attr = H5Acreate(mDatasetId, "Variable Details", string_type, colspace, H5P_DEFAULT);
00426 
00427     // Write to the attribute
00428     H5Awrite(attr, string_type, col_data);
00429 
00430     // Close dataspace & attribute
00431     free(col_data);
00432     H5Sclose(colspace);
00433     H5Aclose(attr);
00434 
00435     // Create "boolean" attribute telling the data to be incomplete or not
00436     columns[0] = 1;
00437     colspace = H5Screate_simple(1, columns, NULL);
00438     attr = H5Acreate(mDatasetId, "IsDataComplete", H5T_NATIVE_UINT, colspace, H5P_DEFAULT);
00439 
00440     // Write to the attribute - note that the native boolean is not predictable
00441     unsigned is_data_complete = mIsDataComplete ? 1 : 0;
00442     H5Awrite(attr, H5T_NATIVE_UINT, &is_data_complete);
00443 
00444     H5Sclose(colspace);
00445     H5Aclose(attr);
00446 
00447     if (!mIsDataComplete)
00448     {
00449         // We need to write a map
00450         // Create "unsigned" attribute with the map
00451         columns[0] = mFileFixedDimensionSize;
00452         colspace = H5Screate_simple(1, columns, NULL);
00453         attr = H5Acreate(mDatasetId, "NodeMap", H5T_NATIVE_UINT, colspace, H5P_DEFAULT);
00454 
00455         // Write to the attribute
00456         H5Awrite(attr, H5T_NATIVE_UINT, &mIncompleteNodeIndices[0]);
00457 
00458         H5Sclose(colspace);
00459         H5Aclose(attr);
00460     }
00461 
00462     /*
00463      *  Create "Time" dataset
00464      */
00465     if (mIsUnlimitedDimensionSet)
00466     {
00467         hsize_t time_dataset_dims[1] = {1};
00468         hsize_t time_dataset_max_dims[1] = {H5S_UNLIMITED};
00469 
00470         // Modify dataset creation properties to enable chunking.
00471         hsize_t time_chunk_dims[1] ={1};
00472         hid_t time_cparms = H5Pcreate (H5P_DATASET_CREATE);
00473         H5Pset_chunk( time_cparms, 1, time_chunk_dims);
00474 
00475         hid_t time_filespace = H5Screate_simple(1, time_dataset_dims, time_dataset_max_dims);
00476 
00477         // Create the dataset
00478         mTimeDatasetId = H5Dcreate(mFileId, mUnlimitedDimensionName.c_str(), H5T_NATIVE_DOUBLE, time_filespace, time_cparms);
00479 
00480         // Create the dataspace for the attribute
00481         hsize_t one = 1;
00482         hid_t one_column_space = H5Screate_simple(1, &one, NULL);
00483 
00484         // Create an attribute for the time unit
00485         hid_t unit_attr = H5Acreate(mTimeDatasetId, "Unit", string_type, one_column_space, H5P_DEFAULT);
00486 
00487         // Copy the unit to a string MAX_STRING_SIZE long and write it
00488         char unit_string[MAX_STRING_SIZE];
00489         strcpy(unit_string, mUnlimitedDimensionUnit.c_str());
00490         H5Awrite(unit_attr, string_type, unit_string);
00491 
00492         // Close the filespace
00493         H5Sclose(one_column_space);
00494         H5Aclose(unit_attr);
00495         H5Sclose(time_filespace);
00496     }
00497 
00498     /*
00499      * Create the provenance attribute
00500      */
00501     // Create a longer type for 'string'
00502     const unsigned MAX_PROVENANCE_STRING_SIZE = 365;
00503     hid_t long_string_type = H5Tcopy(H5T_C_S1);
00504     H5Tset_size(long_string_type, MAX_PROVENANCE_STRING_SIZE );
00505     hsize_t prov_columns[1] = {1};
00506     hid_t provenance_space = H5Screate_simple(1, prov_columns, NULL);
00507     char* provenance_data = (char*) malloc(sizeof(char) * MAX_PROVENANCE_STRING_SIZE);
00508     assert( ChasteBuildInfo::GetProvenanceString().length() < MAX_PROVENANCE_STRING_SIZE);
00509     
00510     strcpy(provenance_data,  ChasteBuildInfo::GetProvenanceString().c_str());
00511     hid_t prov_attr = H5Acreate(mDatasetId, "Chaste Provenance", long_string_type, provenance_space, H5P_DEFAULT);
00512 
00513     // Write to the attribute
00514     H5Awrite(prov_attr, long_string_type, provenance_data);
00515 
00516     // Close dataspace & attribute
00517     free(provenance_data);
00518     H5Sclose(provenance_space);
00519     H5Aclose(prov_attr);
00520 
00521 }
00522 
00523 void Hdf5DataWriter::PutVector(int variableID, Vec petscVector)
00524 {
00525     if (mIsInDefineMode)
00526     {
00527         EXCEPTION("Cannot write data while in define mode.");
00528     }
00529 
00530     int vector_size;
00531     VecGetSize(petscVector, &vector_size);
00532 
00533     if ((unsigned) vector_size != mDataFixedDimensionSize)
00534     {
00535         EXCEPTION("Vector size doesn't match fixed dimension");
00536     }
00537 
00538     // Make sure that everything is actually extended to the correct dimension.
00539     PossiblyExtend();
00540 
00541     // Define a dataset in memory for this process
00542     hid_t memspace=0;
00543     if (mNumberOwned !=0)
00544     {
00545         hsize_t v_size[1] = {mNumberOwned};
00546         memspace = H5Screate_simple(1, v_size, NULL);
00547     }
00548     // Select hyperslab in the file
00549     hsize_t count[DATASET_DIMS] = {1, mNumberOwned, 1};
00550     hsize_t offset_dims[DATASET_DIMS] = {mCurrentTimeStep, mOffset, variableID};
00551     hid_t file_dataspace = H5Dget_space(mDatasetId);
00552 
00553     // Create property list for collective dataset
00554     hid_t property_list_id = H5Pcreate(H5P_DATASET_XFER);
00555     H5Pset_dxpl_mpio(property_list_id, H5FD_MPIO_COLLECTIVE);
00556 
00557     H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, offset_dims, NULL, count, NULL);
00558 
00559     double* p_petsc_vector;
00560     VecGetArray(petscVector, &p_petsc_vector);
00561 
00562     if (mIsDataComplete)
00563     {
00564         H5Dwrite(mDatasetId, H5T_NATIVE_DOUBLE, memspace, file_dataspace, property_list_id, p_petsc_vector);
00565     }
00566     else
00567     {
00568         // Make a local copy of the data you own
00569         double local_data[mNumberOwned];
00570         for (unsigned i=0; i<mNumberOwned; i++)
00571         {
00572             local_data[i] = p_petsc_vector[ mIncompleteNodeIndices[mOffset+i]-mLo ];
00573 
00574         }
00575         H5Dwrite(mDatasetId, H5T_NATIVE_DOUBLE, memspace, file_dataspace, property_list_id, local_data);
00576     }
00577 
00578     VecRestoreArray(petscVector, &p_petsc_vector);
00579 
00580     H5Pclose(property_list_id);
00581     H5Sclose(file_dataspace);
00582     if (mNumberOwned !=0)
00583     {
00584         H5Sclose(memspace);
00585     }
00586 }
00587 
00588 void Hdf5DataWriter::PutStripedVector(int firstVariableID, int secondVariableID, Vec petscVector)
00589 {
00590     if (mIsInDefineMode)
00591     {
00592         EXCEPTION("Cannot write data while in define mode.");
00593     }
00594 
00595     int NUM_STRIPES=2;
00596 
00597     // Currently the method only works with consecutive columns, can be extended if needed
00598     if (secondVariableID-firstVariableID != 1)
00599     {
00600         EXCEPTION("Columns should be consecutive. Try reordering them.");
00601     }
00602 
00603     int vector_size;
00604     VecGetSize(petscVector, &vector_size);
00605 
00606     if ((unsigned) vector_size != NUM_STRIPES*mDataFixedDimensionSize)
00607     {
00608         EXCEPTION("Vector size doesn't match fixed dimension");
00609     }
00610 
00611     // Make sure that everything is actually extended to the correct dimension
00612     PossiblyExtend();
00613 
00614     // Define a dataset in memory for this process
00615     hid_t memspace=0;
00616     if (mNumberOwned !=0)
00617     {
00618         hsize_t v_size[1] = {mNumberOwned*NUM_STRIPES};
00619         memspace = H5Screate_simple(1, v_size, NULL);
00620     }
00621 
00622     // Select hyperslab in the file
00623     hsize_t start[DATASET_DIMS] = {mCurrentTimeStep, mOffset, firstVariableID};
00624     hsize_t stride[DATASET_DIMS] = {1, 1, secondVariableID-firstVariableID};
00625     hsize_t block_size[DATASET_DIMS] = {1, mNumberOwned, 1};
00626     hsize_t number_blocks[DATASET_DIMS] = {1, 1, NUM_STRIPES};
00627 
00628     hid_t hyperslab_space = H5Dget_space(mDatasetId);
00629     H5Sselect_hyperslab(hyperslab_space, H5S_SELECT_SET, start, stride, number_blocks, block_size);
00630 
00631     // Create property list for collective dataset write, and write! Finally.
00632     hid_t property_list_id = H5Pcreate(H5P_DATASET_XFER);
00633     H5Pset_dxpl_mpio(property_list_id, H5FD_MPIO_COLLECTIVE);
00634 
00635     double* p_petsc_vector;
00636     VecGetArray(petscVector, &p_petsc_vector);
00637 
00638     if (mIsDataComplete)
00639     {
00640         H5Dwrite(mDatasetId, H5T_NATIVE_DOUBLE, memspace, hyperslab_space, property_list_id, p_petsc_vector);
00641     }
00642     else
00643     {
00644         // Make a local copy of the data you own
00645         double local_data[mNumberOwned*NUM_STRIPES];
00646         for (unsigned i=0; i<mNumberOwned; i++)
00647         {
00649             unsigned local_node_number=mIncompleteNodeIndices[mOffset+i] - mLo;
00650             local_data[NUM_STRIPES*i]   = p_petsc_vector[ local_node_number*NUM_STRIPES ];
00651             local_data[NUM_STRIPES*i+1] = p_petsc_vector[ local_node_number*NUM_STRIPES + 1];
00652         }
00653         H5Dwrite(mDatasetId, H5T_NATIVE_DOUBLE, memspace, hyperslab_space, property_list_id, local_data);
00654     }
00655 
00656     VecRestoreArray(petscVector, &p_petsc_vector);
00657 
00658     H5Sclose(hyperslab_space);
00659     if (mNumberOwned != 0)
00660     {
00661         H5Sclose(memspace);
00662     }
00663     H5Pclose(property_list_id);
00664 }
00665 
00666 void Hdf5DataWriter::PutUnlimitedVariable(double value)
00667 {
00668     if (mIsInDefineMode)
00669     {
00670         EXCEPTION("Cannot write data while in define mode.");
00671     }
00672 
00673     if (!mIsUnlimitedDimensionSet)
00674     {
00675         EXCEPTION("PutUnlimitedVariable() called but no unlimited dimension has been set");
00676     }
00677 
00678     // This data is only written by the master
00679     if (!PetscTools::AmMaster())
00680     {
00681         return;
00682     }
00683 
00684     // Make sure that everything is actually extended to the correct dimension.
00685     PossiblyExtend();
00686 
00687     hsize_t size[1] = {1};
00688     hid_t memspace = H5Screate_simple(1, size, NULL);
00689 
00690     // Select hyperslab in the file.
00691     hsize_t count[1] = {1};
00692     hsize_t offset[1] = {mCurrentTimeStep};
00693     hid_t hyperslab_space = H5Dget_space(mTimeDatasetId);
00694     H5Sselect_hyperslab(hyperslab_space, H5S_SELECT_SET, offset, NULL, count, NULL);
00695 
00696     H5Dwrite(mTimeDatasetId, H5T_NATIVE_DOUBLE, memspace, hyperslab_space, H5P_DEFAULT, &value);
00697 
00698     H5Sclose(hyperslab_space);
00699     H5Sclose(memspace);
00700 }
00701 
00702 void Hdf5DataWriter::Close()
00703 {
00704     if (mIsInDefineMode)
00705     {
00706         return; // Nothing to do...
00707     }
00708     
00709     H5Dclose(mDatasetId);
00710     if (mIsUnlimitedDimensionSet)
00711     {
00712         H5Dclose(mTimeDatasetId);
00713     }
00714     H5Fclose(mFileId);
00715     
00716     // Cope with being called twice (e.g. if a user calls Close then the destructor)
00717     mIsInDefineMode = true;
00718 }
00719 
00720 void Hdf5DataWriter::DefineUnlimitedDimension(const std::string& rVariableName,
00721                                               const std::string& rVariableUnits)
00722 {
00723     if (mIsUnlimitedDimensionSet)
00724     {
00725         EXCEPTION("Unlimited dimension already set. Cannot be defined twice");
00726     }
00727 
00728     if (!mIsInDefineMode)
00729     {
00730         EXCEPTION("Cannot define variables when not in Define mode");
00731     }
00732 
00733     mIsUnlimitedDimensionSet = true;
00734     mUnlimitedDimensionName = rVariableName;
00735     mUnlimitedDimensionUnit = rVariableUnits;
00736 }
00737 
00738 void Hdf5DataWriter::AdvanceAlongUnlimitedDimension()
00739 {
00740     if (!mIsUnlimitedDimensionSet)
00741     {
00742         EXCEPTION("Trying to advance along an unlimited dimension without having defined any");
00743     }
00744 
00745     // Extend the dataset
00746     mDatasetDims[0]++;
00747     mNeedExtend = true;
00748 
00749     mCurrentTimeStep++;
00750 }
00751 
00752 void Hdf5DataWriter::PossiblyExtend()
00753 {
00754     if (mNeedExtend)
00755     {
00756         H5Dextend (mDatasetId, mDatasetDims);
00757         H5Dextend (mTimeDatasetId, mDatasetDims);
00758     }
00759     mNeedExtend = false;
00760 }
00761 
00762 int Hdf5DataWriter::GetVariableByName(const std::string& rVariableName)
00763 {
00764     int id = -1;
00765     // Check for the variable name in the existing variables
00766     for (unsigned index=0; index<mVariables.size(); index++)
00767     {
00768         if (mVariables[index].mVariableName == rVariableName)
00769         {
00770             id = index;
00771             break;
00772         }
00773     }
00774     if (id == -1)
00775     {
00776         EXCEPTION("Variable does not exist in hdf5 definitions.");
00777     }
00778     return id;
00779 }

Generated by  doxygen 1.6.2