00001 /* 00002 * The information in this file is 00003 * Copyright(c) 2007 Ball Aerospace & Technologies Corporation 00004 * and is subject to the terms and conditions of the 00005 * GNU Lesser General Public License Version 2.1 00006 * The license text is available from 00007 * http://www.gnu.org/licenses/lgpl.html 00008 */ 00009 00010 #ifndef HDF5_INCREMENTAL_WRITER_H 00011 #define HDF5_INCREMENTAL_WRITER_H 00012 00013 #include "Hdf5CustomWriter.h" 00014 00015 #include <string> 00016 #include <vector> 00017 00018 #include <hdf5.h> 00019 00020 /** 00021 * This class provides the ability to incrementally 00022 * write values to a HDF5 dataset without having 00023 * to write values to the entire dataset as 00024 * HdfUtilities::writeDataset() requires. 00025 */ 00026 template<typename T> 00027 class Hdf5IncrementalWriter 00028 { 00029 public: 00030 /** 00031 * Create the HDF5 dataset that will be written 00032 * to by this writer. The dataset will be 00033 * created in the file with the given name 00034 * and dimensions. The HDF5 type of the dataset 00035 * is determined by the T that this class 00036 * is templated on. The HDF5 type of the dataset 00037 * will be queried from the 00038 * Hdf5CustomWriter::getWriteFileType() instance 00039 * that is constructed by calling 00040 * createCustomHdf5Writer() with the given T. 00041 * To determine if the HDF5 dataset was created 00042 * successfully in the file, call isValid() 00043 * after this object has been constructed. 00044 * 00045 * @param fileId 00046 * A handle to an open HDF5 file that 00047 * the dataset should be written to. 00048 * @param datasetName 00049 * The full path to a location in the file 00050 * where the HDF5 datatset should be created. 00051 * This writer assumes that any required 00052 * groups in the path have already been created 00053 * in the file. 00054 * @param datasetDimensions 00055 * A vector specifying the number of dimensions 00056 * and the size of the dimensions that should 00057 * be used when creating the HDF5 dataset. 00058 */ 00059 Hdf5IncrementalWriter(hid_t fileId, 00060 const std::string& datasetName, 00061 const std::vector<hsize_t>& datasetDimensions) 00062 { 00063 mpWriter = createHdf5CustomWriter<T>(); 00064 mDataset = -1; 00065 mDataspace = -1; 00066 if (mpWriter == NULL) 00067 { 00068 return; 00069 } 00070 if (datasetDimensions.empty()) 00071 { 00072 mDataspace = H5Screate(H5S_SCALAR); 00073 } 00074 else 00075 { 00076 mDataspace = H5Screate_simple(datasetDimensions.size(), &(datasetDimensions.front()), NULL); 00077 } 00078 if (mDataspace != -1) 00079 { 00080 mDataset = H5Dcreate1(fileId, datasetName.c_str(), 00081 *(mpWriter->getWriteFileType()), mDataspace, H5P_DEFAULT); 00082 } 00083 } 00084 00085 /** 00086 * Destroys the writer instance. This will also 00087 * close the HDF5 dataset that was being written 00088 * to by this writer. 00089 */ 00090 virtual ~Hdf5IncrementalWriter() 00091 { 00092 delete mpWriter; 00093 if (mDataspace != -1) 00094 { 00095 H5Sclose(mDataspace); 00096 } 00097 00098 if (mDataset != -1) 00099 { 00100 H5Dclose(mDataset); 00101 } 00102 } 00103 00104 /** 00105 * Returns whether this writer 00106 * is valid to use. If this 00107 * method returns false, you 00108 * should not attempt to call 00109 * any other functions on this writer. 00110 * This method should be called 00111 * immediately after the constructor. 00112 * 00113 * @return Returns true is this writer 00114 * is valid, false otherwise. 00115 */ 00116 bool isValid() const 00117 { 00118 return mpWriter != NULL && mDataspace != -1 && mDataset != -1; 00119 } 00120 00121 /** 00122 * Returns a HDF5 handle to the dataset 00123 * that is being written to by this writer. 00124 * 00125 * @return Returns a HDF5 handle to the dataset 00126 * that is being written to. 00127 */ 00128 hid_t getDataSet() const 00129 { 00130 return mDataset; 00131 } 00132 00133 /** 00134 * Returns the dataspace that represents 00135 * the selection within the dataset 00136 * that is being written to. 00137 * 00138 * @return Returns a HDF5 dataspace handle 00139 * to the selection within the 00140 * dataset that is being written to. 00141 */ 00142 hid_t getDataSpace() const 00143 { 00144 return mDataspace; 00145 } 00146 00147 /** 00148 * Provides a convenient way to write data 00149 * to a single dimensional HDF5 dataset. 00150 * (ie. a one-dimensional array). This method 00151 * will write data to a single dimensional HDF5 00152 * dataset starting at the row provided. 00153 * 00154 * @param startRowNumber 00155 * The starting row number in the single 00156 * dimensional HDF5 dataset where data 00157 * should be written. This number is zero-based. 00158 * @param object 00159 * The data that should be written to the 00160 * HDF5 dataset starting at the given row 00161 * number. This data can be scalar or it 00162 * can be single dimensional as well. 00163 * 00164 * Returns true if the write was successful, false otherwise. 00165 */ 00166 bool writeBlock(hsize_t startRowNumber, const T& object) 00167 { 00168 DO_IF(!isValid(), return false); 00169 DO_IF(H5Sget_simple_extent_ndims(mDataspace) != 1, return false); 00170 DO_IF(!mpWriter->setDataToWrite(const_cast<T*>(&object)), return false); 00171 Hdf5DataSpaceResource memSpaceId(mpWriter->createDataSpace()); 00172 DO_IF(*memSpaceId < 0, return false); 00173 00174 hsize_t sizeArray[H5S_MAX_RANK]; 00175 int numdims = H5Sget_simple_extent_dims(*memSpaceId, sizeArray, NULL); 00176 if (numdims == 0) 00177 { 00178 sizeArray[0] = 1; 00179 } 00180 00181 hsize_t oneValue = 1; 00182 DO_IF(H5Sselect_hyperslab(mDataspace, H5S_SELECT_SET, &startRowNumber, &oneValue, sizeArray, NULL) < 0, 00183 return false); 00184 00185 Hdf5TypeResource memTypeId(mpWriter->getWriteMemoryType()); 00186 DO_IF(*memTypeId < 0, return false) 00187 const void* pData = mpWriter->getWriteBuffer(); 00188 if (pData != NULL) 00189 { 00190 herr_t writeStatus = H5Dwrite(mDataset, *memTypeId, *memSpaceId, 00191 mDataspace, H5P_DEFAULT, pData); 00192 return writeStatus == 0; 00193 } 00194 return false; 00195 } 00196 00197 /** 00198 * Writes the specified data to a selection 00199 * in the dataset defined by a hyperslab. 00200 * The hyperslab selection is done by using 00201 * H5Sselect_hyperslab() provided by the 00202 * HDF5 library. Please note that this 00203 * method erases any previous selection in 00204 * the dataset before performing the hyperslab 00205 * selection. The provided data will be 00206 * written to the selected hyperslab in 00207 * the HDF5 dataset. 00208 * 00209 * @param pStart 00210 * Please see H5Sselect_hyperslab() documentation. 00211 * @param pStride 00212 * Please see H5Sselect_hyperslab() documentation. 00213 * @param pCount 00214 * Please see H5Sselect_hyperslab() documentation. 00215 * @param pBlock 00216 * Please see H5Sselect_hyperslab() documentation. 00217 * @param object 00218 * The data that should be written to the selected 00219 * hyperslab in the file. The provided data 00220 * must contain the same number of points as the 00221 * selected hyperslab contains. 00222 * 00223 * @return Returns true if the hyperslab selection and 00224 * write were successful, false otherwise. 00225 */ 00226 bool writeHyperslab(const hsize_t* pStart, 00227 const hsize_t* pStride, 00228 const hsize_t* pCount, 00229 const hsize_t* pBlock, 00230 const T& object) 00231 { 00232 DO_IF(!isValid(), return false); 00233 DO_IF(H5Sselect_hyperslab(mDataspace, H5S_SELECT_SET, pStart, pStride, pCount, pBlock) < 0, return false); 00234 return writeToSelectedData(object); 00235 } 00236 00237 /** 00238 * Writes the specified data to a selection 00239 * in the dataset defined by a element selection. 00240 * The element selection is done by using 00241 * H5Sselect_elements() provided by the 00242 * HDF5 library. Please note that this 00243 * method erases any previous selection in 00244 * the dataset before performing the element 00245 * selection. The provided data will be 00246 * written to the selected elements in 00247 * the HDF5 dataset. 00248 * 00249 * @param num_elements 00250 * Please see H5Sselect_elements() documentation. 00251 * @param pCoordinates 00252 * Please see H5Sselect_elements() documentation. 00253 * @param object 00254 * The data that should be written to the selected 00255 * elements in the file. The provided data 00256 * must contain the same number of points as the 00257 * element selection contains. 00258 * 00259 * @return Returns true if the element selection and 00260 * write were successful, false otherwise. 00261 */ 00262 bool writeElements(const size_t num_elements, 00263 const hsize_t * pCoordinates, 00264 const T& object) 00265 { 00266 DO_IF(!isValid(), return false); 00267 DO_IF(H5Sselect_elements(mDataspace, H5S_SELECT_SET, num_elements, pCoordinates) < 0, return false); 00268 return writeToSelectedData(object); 00269 } 00270 00271 /** 00272 * Writes the provided data to the current selection 00273 * as returned by getDataSpace(). This method should 00274 * be used if the options provided by writeBlock(), 00275 * writeHyperslab() and writeElements() is insufficent. 00276 * In this case, you can get the dataspace by calling 00277 * getDataSpace() and the perform the selection manually 00278 * using HDF5 library calls. 00279 * 00280 * @param object 00281 * The data that should be written to the current 00282 * selection in the file. The provided data 00283 * must contain the same number of points as the 00284 * current selection contains. 00285 * 00286 * @return Returns true if the write was successful, 00287 * false otherwise. 00288 */ 00289 bool writeToSelectedData(const T& object) 00290 { 00291 DO_IF(!isValid(), return false); 00292 DO_IF(!mpWriter->setDataToWrite(const_cast<T*>(&object)), return false); 00293 Hdf5DataSpaceResource memSpaceId(mpWriter->createDataSpace()); 00294 DO_IF(*memSpaceId < 0, return false); 00295 00296 DO_IF(H5Sget_select_npoints(mDataspace) != H5Sget_select_npoints(*memSpaceId), return false); 00297 00298 Hdf5TypeResource memTypeId(mpWriter->getWriteMemoryType()); 00299 DO_IF(*memTypeId < 0, return false) 00300 const void* pData = mpWriter->getWriteBuffer(); 00301 if (pData != NULL) 00302 { 00303 herr_t writeStatus = H5Dwrite(mDataset, *memTypeId, *memSpaceId, 00304 mDataspace, H5P_DEFAULT, pData); 00305 return writeStatus == 0; 00306 } 00307 return false; 00308 } 00309 00310 protected: 00311 hid_t mDataset; 00312 hid_t mDataspace; 00313 Hdf5CustomWriter* mpWriter; 00314 }; 00315 00316 #endif