13 #include <dolfinx/common/log.h>
36 static hid_t
open_file(MPI_Comm mpi_comm,
const std::string& filename,
37 const std::string& mode,
const bool use_mpi_io);
63 static void write_dataset(
const hid_t handle,
const std::string& dataset_path,
65 const std::array<std::int64_t, 2>& range,
66 const std::vector<std::int64_t>& global_size,
67 bool use_mpi_io,
bool use_chunking);
79 const std::string& dataset_path,
80 const std::array<std::int64_t, 2>& range);
86 static bool has_dataset(
const hid_t handle,
const std::string& dataset_path);
92 static std::vector<std::int64_t>
113 static void add_group(
const hid_t handle,
const std::string& dataset_path);
116 template <
typename T>
117 static hid_t hdf5_type()
119 throw std::runtime_error(
"Cannot get HDF5 primitive data type. "
120 "No specialised function for this data type");
126 inline hid_t HDF5Interface::hdf5_type<float>()
128 return H5T_NATIVE_FLOAT;
132 inline hid_t HDF5Interface::hdf5_type<double>()
134 return H5T_NATIVE_DOUBLE;
138 inline hid_t HDF5Interface::hdf5_type<int>()
140 return H5T_NATIVE_INT;
144 inline hid_t HDF5Interface::hdf5_type<std::int64_t>()
146 return H5T_NATIVE_INT64;
150 inline hid_t HDF5Interface::hdf5_type<std::size_t>()
152 if (
sizeof(std::size_t) ==
sizeof(
unsigned long))
153 return H5T_NATIVE_ULONG;
154 else if (
sizeof(std::size_t) ==
sizeof(
unsigned int))
155 return H5T_NATIVE_UINT;
157 throw std::runtime_error(
"Cannot determine size of std::size_t. "
158 "std::size_t is not the same size as long or int");
161 template <
typename T>
163 const hid_t file_handle,
const std::string& dataset_path,
const T* data,
164 const std::array<std::int64_t, 2>& range,
165 const std::vector<int64_t>& global_size,
bool use_mpi_io,
bool use_chunking)
168 const std::size_t rank = global_size.size();
173 throw std::runtime_error(
"Cannot write dataset to HDF5 file"
174 "Only rank 1 and rank 2 dataset are supported");
178 const hid_t h5type = hdf5_type<T>();
181 std::vector<hsize_t> count(global_size.begin(), global_size.end());
182 count[0] = range[1] - range[0];
185 std::vector<hsize_t> offset(rank, 0);
186 offset[0] = range[0];
189 const std::vector<hsize_t> dimsf(global_size.begin(), global_size.end());
195 const hid_t filespace0 = H5Screate_simple(rank, dimsf.data(),
nullptr);
196 assert(filespace0 != HDF5_FAIL);
199 hid_t chunking_properties;
203 hsize_t chunk_size = dimsf[0] / 2;
204 if (chunk_size > 1048576)
205 chunk_size = 1048576;
206 if (chunk_size < 1024)
209 hsize_t chunk_dims[2] = {chunk_size, dimsf[1]};
210 chunking_properties = H5Pcreate(H5P_DATASET_CREATE);
211 H5Pset_chunk(chunking_properties, rank, chunk_dims);
214 chunking_properties = H5P_DEFAULT;
217 const std::string group_name(dataset_path, 0, dataset_path.rfind(
'/'));
218 add_group(file_handle, group_name);
222 = H5Dcreate2(file_handle, dataset_path.c_str(), h5type, filespace0,
223 H5P_DEFAULT, chunking_properties, H5P_DEFAULT);
224 assert(dset_id != HDF5_FAIL);
227 status = H5Sclose(filespace0);
228 assert(status != HDF5_FAIL);
231 const hid_t memspace = H5Screate_simple(rank, count.data(),
nullptr);
232 assert(memspace != HDF5_FAIL);
235 const hid_t filespace1 = H5Dget_space(dset_id);
236 status = H5Sselect_hyperslab(filespace1, H5S_SELECT_SET, offset.data(),
237 nullptr, count.data(),
nullptr);
238 assert(status != HDF5_FAIL);
241 const hid_t plist_id = H5Pcreate(H5P_DATASET_XFER);
244 #ifdef H5_HAVE_PARALLEL
245 status = H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE);
246 assert(status != HDF5_FAIL);
248 throw std::runtime_error(
"HDF5 library has not been configured with MPI");
253 status = H5Dwrite(dset_id, h5type, memspace, filespace1, plist_id, data);
254 assert(status != HDF5_FAIL);
259 status = H5Pclose(chunking_properties);
260 assert(status != HDF5_FAIL);
264 status = H5Dclose(dset_id);
265 assert(status != HDF5_FAIL);
268 status = H5Sclose(filespace1);
269 assert(status != HDF5_FAIL);
272 status = H5Sclose(memspace);
273 assert(status != HDF5_FAIL);
276 status = H5Pclose(plist_id);
277 assert(status != HDF5_FAIL);
280 template <
typename T>
281 inline std::vector<T>
283 const std::string& dataset_path,
284 const std::array<std::int64_t, 2>& range)
286 auto timer_start = std::chrono::system_clock::now();
290 = H5Dopen2(file_handle, dataset_path.c_str(), H5P_DEFAULT);
291 assert(dset_id != HDF5_FAIL);
294 const hid_t dataspace = H5Dget_space(dset_id);
295 assert(dataspace != HDF5_FAIL);
298 const int rank = H5Sget_simple_extent_ndims(dataspace);
302 LOG(WARNING) <<
"HDF5Interface::read_dataset untested for rank > 2.";
305 std::vector<hsize_t> shape(rank);
308 const int ndims = H5Sget_simple_extent_dims(dataspace, shape.data(),
nullptr);
309 assert(ndims == rank);
312 std::vector<hsize_t> offset(rank, 0);
313 std::vector<hsize_t> count = shape;
314 if (range[0] != -1 and range[1] != -1)
316 offset[0] = range[0];
317 count[0] = range[1] - range[0];
324 herr_t status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset.data(),
325 nullptr, count.data(),
nullptr);
326 assert(status != HDF5_FAIL);
329 const hid_t memspace = H5Screate_simple(rank, count.data(),
nullptr);
330 assert(memspace != HDF5_FAIL);
333 std::size_t data_size = 1;
334 for (std::size_t i = 0; i < count.size(); ++i)
335 data_size *= count[i];
336 std::vector<T> data(data_size);
339 const hid_t h5type = hdf5_type<T>();
341 = H5Dread(dset_id, h5type, memspace, dataspace, H5P_DEFAULT, data.data());
342 assert(status != HDF5_FAIL);
345 status = H5Sclose(dataspace);
346 assert(status != HDF5_FAIL);
349 status = H5Sclose(memspace);
350 assert(status != HDF5_FAIL);
353 status = H5Dclose(dset_id);
354 assert(status != HDF5_FAIL);
356 auto timer_end = std::chrono::system_clock::now();
357 std::chrono::duration<double> dt = (timer_end - timer_start);
358 double data_rate = data.size() *
sizeof(T) / (1e6 * dt.count());
360 LOG(INFO) <<
"HDF5 Read data rate: " << data_rate <<
"MB/s";