High Performance Plasticity  0.5.0
hdfUtils.h
Go to the documentation of this file.
1 
8 #ifndef HPP_HDFUTILS_H
9 #define HPP_HDFUTILS_H
10 
11 #include <stdexcept>
12 #include <cstddef>
13 #include <string>
14 #include <stdio.h>
15 #include <map>
16 #include <vector>
17 #include <iostream>
18 #include <sstream>
19 #include "mpi.h"
20 #include <hpp/config.h>
21 #include <hdf5/openmpi/hdf5.h>
22 
23 namespace hpp
24 {
25 
26 class HDFUtilsError: public std::runtime_error
27 {
28  public:
29  explicit HDFUtilsError (const std::string &val) : std::runtime_error::runtime_error(val) {}
30 };
31 
32 // Check an HDF C API call
33 #define HDFCHECK(ans) hdfAssert((ans), __FILE__, __LINE__)
34 inline void hdfAssert(herr_t code, const char *file, int line){
35  if (code < 0){
36  // Throw
37  std::ostringstream errorStringStream;
38  errorStringStream << "HDF error above occured at ";
39  errorStringStream << file << ":" << line;
40  throw HDFUtilsError(errorStringStream.str());
41  }
42 }
43 
44 // Suppressing errors
45 extern H5E_auto2_t dummyHDFErrorHandler;
46 extern void *dummyHDFClientData;
47 void hdfSuppressErrors();
48 void hdfRestoreErrors();
49 #define HDF_IGNORE_ERRORS(expr) hdfSuppressErrors();expr;hdfRestoreErrors()
50 
51 enum class HDFReadWrite: char
52 {
53  Write='w',
54  Read='r'
55 };
56 
63  double r;
64  double i;
65 };
66 extern hid_t hdf_complex_id;
67 
73 template <typename T>
74 hid_t getHDF5TypeC() {
75  hid_t dataType;
76  if (std::is_same<T, float>::value) {
77  dataType = H5T_NATIVE_FLOAT;
78  }
79  else if (std::is_same<T, double>::value) {
80  dataType = H5T_NATIVE_DOUBLE;
81  }
82  else if (std::is_same<T, unsigned short>::value) {
83  dataType = H5T_NATIVE_USHORT;
84  }
85  else if (std::is_same<T, unsigned int>::value) {
86  dataType = H5T_NATIVE_UINT;
87  }
88  else if (std::is_same<T, hdf_complex_t>::value) {
89  dataType = hdf_complex_id;
90  }
91  else {
92  throw HDFUtilsError("Datatype lookup not implemented for this type.");
93  }
94  return dataType;
95 };
96 
98  std::vector<hsize_t> dataOffset;
99  std::vector<hsize_t> dataCount;
100  hid_t datatype;
101 };
102 
103 template <typename T>
104 hid_t createHDF5Dataset(hid_t file_id, std::string datasetName, std::vector<hsize_t> dataDims) {
105  // Create the dataset
106  hsize_t dataRank = dataDims.size();
107 
108  // Dataspace
109  hid_t dataspace = H5Screate_simple(dataRank, dataDims.data(), NULL);
110  HDFCHECK(dataspace);
111 
112  // Datatype
113  hid_t dataType = getHDF5TypeC<T>();
114 
115  // Actual dataset
116  hid_t dataset = H5Dcreate(file_id, datasetName.c_str(), dataType, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
117  HDFCHECK(dataset);
118 
119  // Close
120  //HDFCHECK(H5Sclose(dataspace)); // this needs to be closed after the dataset is
121 
122  // Return
123  return dataset;
124 }
125 
126 template <typename T>
127 hid_t createHDF5GridOfArrays(hid_t file_id, std::string datasetName, std::vector<hsize_t> gridDims, std::vector<hsize_t> arrayDims) {
128  // Get full data dims
129  std::vector<hsize_t> dataDims = gridDims;
130  dataDims.insert(dataDims.end(), arrayDims.begin(), arrayDims.end());
131 
132  // Create
133  return createHDF5Dataset<T>(file_id, datasetName, dataDims);
134 }
135 
144 template <typename T>
145 HDFReadWriteParamsC getReadWriteParametersForMultipleHDF5Arrays(hid_t dset_id, std::vector<hsize_t> gridOffset,
146  std::vector<hsize_t> arrayDims, std::vector<hsize_t> arrayCount)
147 {
148  // Grid: the grid of arrays, dimensions (m_1, m_2, ... )
149  // Array: the array, dimensions (n_1, n_2, ... )
150  // Data: The combination, dimensions (m1, m2, ..., n1, n_2, ...)
151  // Offset: The offset of the array within the grid
152 
153  // Check that datatypes match
154  hid_t datatype = H5Dget_type(dset_id);
155  HDFCHECK(datatype);
156  hid_t datatypeExpected = getHDF5TypeC<T>();
157  if (!H5Tequal(datatype,datatypeExpected)) {
158  throw HDFUtilsError("Datatype mismatch.");
159  }
160  HDFCHECK(H5Tclose(datatype));
161  datatype = datatypeExpected;
162 
163  // Get data dimensions
164  hid_t dataspace = H5Dget_space(dset_id);
165  HDFCHECK(dataspace);
166  hsize_t dataRank = H5Sget_simple_extent_ndims(dataspace);
167  HDFCHECK(dataRank);
168  std::vector<hsize_t> dataDims(dataRank);
169  H5Sget_simple_extent_dims(dataspace, dataDims.data(), NULL);
170 
171  // Check rank matches
172  hsize_t gridRank = gridOffset.size();
173  hsize_t arrayRank = arrayDims.size();
174  hsize_t dataRankExpected = gridRank + arrayRank;
175  if (dataRank != dataRankExpected) {
176  throw HDFUtilsError("Data rank mismatch.");
177  }
178 
179  // Check array dimensions match
180  std::vector<hsize_t> arrayDimsRead(dataDims.end()-arrayDims.size(), dataDims.end());
181  if (arrayDims != arrayDimsRead) {
182  throw HDFUtilsError("Array dimension mismatch.");
183  }
184 
185  // Get the grid dimensions
186  std::vector<hsize_t> gridDims(dataDims.begin(), dataDims.begin()+gridRank);
187 
188  // Check that offset is within the grid bounds
189  for (unsigned int i=0; i<gridRank; i++) {
190  if (gridOffset[i] > gridDims[i]-1) {
191  throw HDFUtilsError("Offset out of grid bounds.");
192  }
193  }
194 
195  // The offset and count in the overall data
196  std::vector<hsize_t> dataOffset(dataRank);
197  std::vector<hsize_t> dataCount(dataRank);
198  for (unsigned int i=0; i<gridRank; i++) {
199  dataOffset[i] = gridOffset[i];
200  dataCount[i] = arrayCount[i];
201  }
202  for (unsigned int i=0; i<arrayRank; i++) {
203  dataOffset[gridRank + i] = 0;
204  dataCount[gridRank + i] = arrayDims[i];
205  }
206 
207  // Close any spaces created inside this function
208  HDFCHECK(H5Sclose(dataspace));
209 
210  // Prepare parameters
211  HDFReadWriteParamsC parms;
212  parms.dataOffset = dataOffset;
213  parms.dataCount = dataCount;
214  parms.datatype = datatype;
215 
216  // Return
217  return parms;
218 }
219 
227 template <typename T>
228 HDFReadWriteParamsC getReadWriteParametersForSingleHDF5Array(hid_t dset_id, std::vector<hsize_t> gridOffset,
229  std::vector<hsize_t> arrayDims)
230 {
231  unsigned int gridRank = gridOffset.size();
232  std::vector<hsize_t> arrayCount(gridRank, 1);
233  return getReadWriteParametersForMultipleHDF5Arrays<T>(dset_id, gridOffset, arrayDims, arrayCount);
234 }
235 
236 template <typename T>
237 void readWriteHDF5SimpleArray(hid_t dset_id, hid_t plist_id, HDFReadWriteParamsC parms, T* output, HDFReadWrite mode) {
238  // Create the spaces
239  hid_t dataspace = H5Dget_space(dset_id);
240  HDFCHECK(dataspace);
241  hid_t memspace = H5Screate_simple(parms.dataCount.size(), parms.dataCount.data(), NULL);
242  HDFCHECK(memspace);
243 
244  // Select the hyperslab
245  HDFCHECK(H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, parms.dataOffset.data(), NULL, parms.dataCount.data(), NULL));
246 
247  // Read/write
248  if (mode == HDFReadWrite::Read) {
249  HDFCHECK(H5Dread(dset_id, parms.datatype, memspace, dataspace, plist_id, output));
250  }
251  else if (mode == HDFReadWrite::Write) {
252  HDFCHECK(H5Dwrite(dset_id, parms.datatype, memspace, dataspace, plist_id, output));
253  }
254  else {
255  throw HDFUtilsError("Unrecognized mode.");
256  }
257 
258  // Close any spaces created inside this function
259  HDFCHECK(H5Sclose(memspace));
260  HDFCHECK(H5Sclose(dataspace));
261 }
262 
263 template <typename T>
264 void readHDF5SimpleArray(hid_t dset_id, hid_t plist_id, HDFReadWriteParamsC parms, T* output) {
265  readWriteHDF5SimpleArray<T>(dset_id, plist_id, parms, output, HDFReadWrite::Read);
266 }
267 
268 template <typename T>
269 void writeHDF5SimpleArray(hid_t dset_id, hid_t plist_id, HDFReadWriteParamsC parms, T* output) {
270  readWriteHDF5SimpleArray<T>(dset_id, plist_id, parms, output, HDFReadWrite::Write);
271 }
272 
273 template <typename T>
274 void readSingleHDF5Array(hid_t dset_id, hid_t plist_id, std::vector<hsize_t> gridOffset, std::vector<hsize_t> arrayDims, T* output) {
275  HDFReadWriteParamsC parms = getReadWriteParametersForSingleHDF5Array<T>(dset_id, gridOffset, arrayDims);
276  readHDF5SimpleArray<T>(dset_id, plist_id, parms, output);
277 }
278 
279 template <typename T>
280 void readSingleHDF5Array(hid_t dset_id, hid_t plist_id, std::vector<hsize_t> arrayDims, T* output) {
281  std::vector<hsize_t> gridOffset;//no offset
282  HDFReadWriteParamsC parms = getReadWriteParametersForSingleHDF5Array<T>(dset_id, gridOffset, arrayDims);
283  readHDF5SimpleArray<T>(dset_id, plist_id, parms, output);
284 }
285 
286 template <typename T>
287 void writeSingleHDF5Array(hid_t dset_id, hid_t plist_id, std::vector<hsize_t> gridOffset, std::vector<hsize_t> arrayDims, T* output) {
288  HDFReadWriteParamsC parms = getReadWriteParametersForSingleHDF5Array<T>(dset_id, gridOffset, arrayDims);
289  writeHDF5SimpleArray<T>(dset_id, plist_id, parms, output);
290 }
291 
292 template <typename T>
293 void writeSingleHDF5Array(hid_t dset_id, hid_t plist_id, std::vector<hsize_t> arrayDims, T* output) {
294  std::vector<hsize_t> gridOffset;//no offset
295  HDFReadWriteParamsC parms = getReadWriteParametersForSingleHDF5Array<T>(dset_id, gridOffset, arrayDims);
296  writeHDF5SimpleArray<T>(dset_id, plist_id, parms, output);
297 }
298 
299 template <typename T>
300 void writeMultipleHDF5Arrays(hid_t dset_id, hid_t plist_id, std::vector<hsize_t> gridOffset, std::vector<hsize_t> arrayDims, std::vector<hsize_t> arrayCount, T* output) {
301  HDFReadWriteParamsC parms = getReadWriteParametersForMultipleHDF5Arrays<T>(dset_id, gridOffset, arrayDims, arrayCount);
302  writeHDF5SimpleArray<T>(dset_id, plist_id, parms, output);
303 }
304 
305 template <typename T>
306 void readMultipleHDF5Arrays(hid_t dset_id, hid_t plist_id, std::vector<hsize_t> gridOffset, std::vector<hsize_t> arrayDims, std::vector<hsize_t> arrayCount, T* output) {
307  HDFReadWriteParamsC parms = getReadWriteParametersForMultipleHDF5Arrays<T>(dset_id, gridOffset, arrayDims, arrayCount);
308  readHDF5SimpleArray<T>(dset_id, plist_id, parms, output);
309 }
310 
311 template <typename T>
312 void readSingleHDF5Value(hid_t dset_id, hid_t plist_id, std::vector<hsize_t> gridOffset, T* output) {
313  // Empty array dims is equivalent to a single value
314  std::vector<hsize_t> arrayDims;
315  HDFReadWriteParamsC parms = getReadWriteParametersForSingleHDF5Array<T>(dset_id, gridOffset, arrayDims);
316  readHDF5SimpleArray<T>(dset_id, plist_id, parms, output);
317 }
318 
319 template <typename T>
320 void writeSingleHDF5Value(hid_t dset_id, hid_t plist_id, std::vector<hsize_t> gridOffset, T* output) {
321  // Empty array dims is equivalent to a single value
322  std::vector<hsize_t> arrayDims;
323  HDFReadWriteParamsC parms = getReadWriteParametersForSingleHDF5Array<T>(dset_id, gridOffset, arrayDims);
324  writeHDF5SimpleArray<T>(dset_id, plist_id, parms, output);
325 }
326 
327 std::vector<hsize_t> getDatasetDims(hid_t dset_id);
328 
339 {
340  public:
341  // MPI constructor
342  HDF5Handler(std::string filename, MPI_Comm comm, bool doCreate);
343 
344  // Serial constructor
345  HDF5Handler(std::string filename, bool doCreate);
346 
347  // Create datasets
348  template <typename T>
349  hid_t createDataset(std::string datasetName, std::vector<hsize_t> dataDims);
350  template <typename T>
351  hid_t createDataset(std::string datasetName, std::vector<hsize_t> gridDims, std::vector<hsize_t> arrayDims);
352 
353  // Get dataset
354  hid_t getDataset(std::string datasetName);
355 
356  // Property list for transfer
357  hid_t getPropertyListTransferIndependent() {return plist_id_xfer_independent;};
358 
359  // Get names of datasets
360  std::vector<std::string> getDatasetNames();
361 
362  // Default destructor
363  ~HDF5Handler();
364  private:
365  // File
366  std::string filename;
367  hid_t file_id;
368 
369  // MPI Configuration
370  bool usingMPI = false;
371  MPI_Comm comm;
374 
375  // Dictionary of datasets
376  // Open datasets get added to or removed from this dictionary
377  // All the ones left open at the time of destruction are closed
378  std::map<std::string, hid_t> currentlyOpenDatasets;
379 
380  // Datasets
381  void openDataset(std::string datasetName);
382 
383  // Property list for file access
385 
386  // Property list for independent transfers
387  // In MPI context, this is each process making transfers asynchronously
388  // In serial context, this is just a usual transfer. It's technically
389  // "independent" since there is only one process.
391 };
392 
393 } //END NAMESPACE HPP
394 
395 #endif /* HPP_HDFUTILS_H */
void hdfAssert(herr_t code, const char *file, int line)
Definition: hdfUtils.h:34
std::vector< hsize_t > dataOffset
Definition: hdfUtils.h:98
#define HDFCHECK(ans)
Definition: hdfUtils.h:33
std::vector< hsize_t > dataCount
Definition: hdfUtils.h:99
HDFReadWriteParamsC getReadWriteParametersForMultipleHDF5Arrays(hid_t dset_id, std::vector< hsize_t > gridOffset, std::vector< hsize_t > arrayDims, std::vector< hsize_t > arrayCount)
Gets the parameters and ensures that they&#39;re compatible with the actual dataset.
Definition: hdfUtils.h:145
H5E_auto2_t dummyHDFErrorHandler
Definition: hdfUtils.cpp:14
HDFReadWriteParamsC getReadWriteParametersForSingleHDF5Array(hid_t dset_id, std::vector< hsize_t > gridOffset, std::vector< hsize_t > arrayDims)
Gets the parameters and ensures that they&#39;re compatible with the actual dataset.
Definition: hdfUtils.h:228
hid_t createHDF5Dataset(hid_t file_id, std::string datasetName, std::vector< hsize_t > dataDims)
Definition: hdfUtils.h:104
hid_t file_id
Definition: hdfUtils.h:367
Definition: casesUtils.cpp:4
void writeSingleHDF5Array(hid_t dset_id, hid_t plist_id, std::vector< hsize_t > gridOffset, std::vector< hsize_t > arrayDims, T *output)
Definition: hdfUtils.h:287
int comm_size
Definition: hdfUtils.h:372
void readWriteHDF5SimpleArray(hid_t dset_id, hid_t plist_id, HDFReadWriteParamsC parms, T *output, HDFReadWrite mode)
Definition: hdfUtils.h:237
hid_t createHDF5GridOfArrays(hid_t file_id, std::string datasetName, std::vector< hsize_t > gridDims, std::vector< hsize_t > arrayDims)
Definition: hdfUtils.h:127
hid_t datatype
Definition: hdfUtils.h:100
Definition: hdfUtils.h:338
void writeHDF5SimpleArray(hid_t dset_id, hid_t plist_id, HDFReadWriteParamsC parms, T *output)
Definition: hdfUtils.h:269
void writeMultipleHDF5Arrays(hid_t dset_id, hid_t plist_id, std::vector< hsize_t > gridOffset, std::vector< hsize_t > arrayDims, std::vector< hsize_t > arrayCount, T *output)
Definition: hdfUtils.h:300
std::vector< hsize_t > getDatasetDims(hid_t dset_id)
Definition: hdfUtils.cpp:35
Definition: hdfUtils.h:97
void readMultipleHDF5Arrays(hid_t dset_id, hid_t plist_id, std::vector< hsize_t > gridOffset, std::vector< hsize_t > arrayDims, std::vector< hsize_t > arrayCount, T *output)
Definition: hdfUtils.h:306
A complex number type.
Definition: hdfUtils.h:62
double r
Definition: hdfUtils.h:63
HDFReadWrite
Definition: hdfUtils.h:51
std::string filename
Definition: hdfUtils.h:366
void hdfSuppressErrors()
Definition: hdfUtils.cpp:16
Definition: hdfUtils.h:26
std::map< std::string, hid_t > currentlyOpenDatasets
Definition: hdfUtils.h:378
hid_t getPropertyListTransferIndependent()
Definition: hdfUtils.h:357
hid_t getHDF5TypeC()
Get HDF5 equivalent type.
Definition: hdfUtils.h:74
hid_t plist_id_file_access
Definition: hdfUtils.h:384
void * dummyHDFClientData
Definition: hdfUtils.cpp:15
void readSingleHDF5Value(hid_t dset_id, hid_t plist_id, std::vector< hsize_t > gridOffset, T *output)
Definition: hdfUtils.h:312
hid_t hdf_complex_id
Definition: hdfUtils.cpp:32
void readHDF5SimpleArray(hid_t dset_id, hid_t plist_id, HDFReadWriteParamsC parms, T *output)
Definition: hdfUtils.h:264
void writeSingleHDF5Value(hid_t dset_id, hid_t plist_id, std::vector< hsize_t > gridOffset, T *output)
Definition: hdfUtils.h:320
int comm_rank
Definition: hdfUtils.h:373
void hdfRestoreErrors()
Definition: hdfUtils.cpp:20
HDFUtilsError(const std::string &val)
Definition: hdfUtils.h:29
hid_t plist_id_xfer_independent
Definition: hdfUtils.h:390
double i
Definition: hdfUtils.h:64
MPI_Comm comm
Definition: hdfUtils.h:371
void readSingleHDF5Array(hid_t dset_id, hid_t plist_id, std::vector< hsize_t > gridOffset, std::vector< hsize_t > arrayDims, T *output)
Definition: hdfUtils.h:274