14#include <dolfinx/common/log.h>
28namespace dolfinx::io::hdf5
51 : _id(std::exchange(h._id, H5I_INVALID_HID)), _close(h._close)
67 _id = std::exchange(h._id, H5I_INVALID_HID);
74 operator hid_t() const noexcept {
return _id; }
78 hid_t
release() noexcept {
return std::exchange(_id, H5I_INVALID_HID); }
93 throw std::runtime_error(
94 std::format(
"Failed to close HDF5 identifier {}.", _id));
96 _id = H5I_INVALID_HID;
101 void close_or_warn() noexcept
103 if (_id > 0 and _close(_id) < 0)
104 logger().warn(
"Failed to close HDF5 identifier {}.", _id);
108 herr_t (*_close)(hid_t);
115 = std::is_same_v<T, float> or std::is_same_v<T, double>
116 or std::is_same_v<T, std::int32_t> or std::is_same_v<T, std::uint32_t>
117 or std::is_same_v<T, std::int64_t> or std::is_same_v<T, std::uint64_t>
118 or std::is_same_v<T, std::uint8_t>;
121template <native_scalar T>
124 if constexpr (std::is_same_v<T, float>)
125 return H5T_NATIVE_FLOAT;
126 else if constexpr (std::is_same_v<T, double>)
127 return H5T_NATIVE_DOUBLE;
128 else if constexpr (std::is_same_v<T, std::int32_t>)
129 return H5T_NATIVE_INT32;
130 else if constexpr (std::is_same_v<T, std::uint32_t>)
131 return H5T_NATIVE_UINT32;
132 else if constexpr (std::is_same_v<T, std::int64_t>)
133 return H5T_NATIVE_INT64;
134 else if constexpr (std::is_same_v<T, std::uint64_t>)
135 return H5T_NATIVE_UINT64;
137 return H5T_NATIVE_UINT8;
145hid_t open_file(MPI_Comm comm,
const std::filesystem::path& filename,
146 std::string_view mode,
bool use_mpi_io);
150void close_file(hid_t handle);
154void flush_file(hid_t handle);
159std::filesystem::path get_filename(hid_t handle);
167bool has_dataset(hid_t handle, std::string_view dataset_path);
178void set_attribute(hid_t handle, std::string_view attr_name,
179 std::string_view value);
185void set_attribute(hid_t handle, std::string_view attr_name,
186 const std::vector<std::int32_t>& value);
192void set_attribute(hid_t handle, std::string_view attr_name,
200hid_t open_dataset(hid_t handle, std::string_view path);
206std::vector<std::int64_t> get_dataset_shape(hid_t handle,
207 std::string_view dataset_path);
212void add_group(hid_t handle, std::string_view dataset_path);
228template <native_scalar T>
229void write_dataset(hid_t file_handle, std::string_view dataset_path,
230 const T* data, std::array<std::int64_t, 2> range,
231 const std::vector<int64_t>& global_size,
bool use_mpi_io,
236 const int rank = global_size.size();
237 if (rank < 1 or rank > 2)
239 throw std::invalid_argument(
240 "Cannot write dataset to HDF5 file. Only rank 1 and rank 2 datasets "
245 const std::string group_name(dataset_path, 0, dataset_path.rfind(
'/'));
246 add_group(file_handle, group_name);
249 const std::string path(dataset_path);
252 const hid_t h5type = hdf5_type<T>();
255 std::vector<hsize_t> count(global_size.begin(), global_size.end());
256 count[0] = range[1] - range[0];
259 std::vector<hsize_t> offset(rank, 0);
260 offset[0] = range[0];
263 const std::vector<hsize_t> dimsf(global_size.begin(), global_size.end());
265 Handle dset_id(H5I_INVALID_HID, H5Dclose);
266 if (has_dataset(file_handle, dataset_path))
269 dset_id = Handle(open_dataset(file_handle, dataset_path), H5Dclose);
270 if (H5Dset_extent(dset_id, dimsf.data()) < 0)
271 throw std::runtime_error(
"Failed to resize HDF5 dataset.");
275 std::vector<hsize_t> maxdims(dimsf.begin(), dimsf.end());
278 Handle chunking_properties(
279 use_chunking ? H5Pcreate(H5P_DATASET_CREATE) : H5P_DEFAULT, H5Pclose);
280 if (chunking_properties < 0)
281 throw std::runtime_error(
"Failed to create HDF5 dataset property list.");
285 std::ranges::fill(maxdims, H5S_UNLIMITED);
289 std::array<hsize_t, 2> chunk_dims{
290 std::clamp(dimsf[0] / 2, hsize_t(1024), hsize_t(1048576)),
291 rank == 2 ? dimsf[1] : hsize_t(1)};
292 if (H5Pset_chunk(chunking_properties, rank, chunk_dims.data()) < 0)
293 throw std::runtime_error(
"Failed to set HDF5 chunk size.");
298 H5Screate_simple(rank, dimsf.data(), maxdims.data()), H5Sclose);
300 throw std::runtime_error(
"Failed to create HDF5 data space");
303 dset_id =
Handle(H5Dcreate2(file_handle, path.c_str(), h5type, filespace0,
304 H5P_DEFAULT, chunking_properties, H5P_DEFAULT),
307 throw std::runtime_error(
"Failed to create HDF5 global dataset.");
310 const Handle dataspace(H5Dget_space(dset_id), H5Sclose);
312 throw std::runtime_error(
"Failed to open HDF5 data space.");
314 if (H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset.data(),
nullptr,
315 count.data(),
nullptr)
318 throw std::runtime_error(
"Failed to select HDF5 hyperslab.");
322 const Handle plist_id(H5Pcreate(H5P_DATASET_XFER), H5Pclose);
324 throw std::runtime_error(
"Failed to create HDF5 data transfer list.");
327 if (H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE) < 0)
329 throw std::runtime_error(
330 "Failed to set HDF5 data transfer property list.");
335 const Handle memspace(H5Screate_simple(rank, count.data(),
nullptr),
338 throw std::runtime_error(
"Failed to create HDF5 local data space.");
341 if (H5Dwrite(dset_id, h5type, memspace, dataspace, plist_id, data) < 0)
342 throw std::runtime_error(
"Failed to write HDF5 local dataset.");
354template <native_scalar T>
355std::vector<T> read_dataset(hid_t dset_id, std::array<std::int64_t, 2> range,
358 auto timer_start = std::chrono::system_clock::now();
363 const Handle dtype(H5Dget_type(dset_id), H5Tclose);
365 throw std::runtime_error(
"Failed to get HDF5 data type.");
366 if (htri_t eq = H5Tequal(dtype, hdf5_type<T>()); eq < 0)
367 throw std::runtime_error(
"HDF5 datatype equality test failed.");
370 throw std::runtime_error(
"Wrong type for reading from HDF5. Use \"h5ls "
371 "-v\" to inspect the types in the HDF5 file.");
376 const Handle dataspace(H5Dget_space(dset_id), H5Sclose);
378 throw std::runtime_error(
"Failed to open HDF5 data space.");
381 int rank = H5Sget_simple_extent_ndims(dataspace);
383 throw std::runtime_error(
"Failed to get rank of data space.");
385 logger().warn(
"io::hdf5::read_dataset untested for rank > 2.");
389 std::vector<hsize_t> offset(rank, 0);
390 std::vector<hsize_t> count(rank);
391 if (H5Sget_simple_extent_dims(dataspace, count.data(),
nullptr) != rank)
392 throw std::runtime_error(
"Failed to get dimensionality of dataspace.");
393 if (range[0] != -1 and range[1] != -1)
395 offset[0] = range[0];
396 count[0] = range[1] - range[0];
401 if (H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset.data(),
nullptr,
402 count.data(),
nullptr)
405 throw std::runtime_error(
"Failed to select HDF5 hyperslab.");
409 const Handle memspace(H5Screate_simple(rank, count.data(),
nullptr),
412 throw std::runtime_error(
"Failed to create HDF5 dataspace.");
416 std::vector<T> data(std::reduce(count.begin(), count.end(), std::size_t(1),
420 if (H5Dread(dset_id, hdf5_type<T>(), memspace, dataspace, H5P_DEFAULT,
424 throw std::runtime_error(
"Failed to read HDF5 data.");
427 auto timer_end = std::chrono::system_clock::now();
428 std::chrono::duration<double> dt = (timer_end - timer_start);
429 double data_rate = data.size() *
sizeof(T) / (1e6 * dt.count());
430 logger().info(
"HDF5 Read data rate: {} MB/s", data_rate);
448template <native_scalar T>
449std::vector<T> read_dataset(hid_t file_handle, std::string_view dataset_path,
450 std::array<std::int64_t, 2> range,
bool allow_cast)
452 const Handle dset_id(open_dataset(file_handle, dataset_path), H5Dclose);
453 return read_dataset<T>(dset_id, range, allow_cast);
Scope guard for an HDF5 identifier.
Definition HDF5Interface.h:39
Handle(hid_t id, herr_t(*close)(hid_t)) noexcept
Take ownership of an HDF5 identifier.
Definition HDF5Interface.h:44
hid_t release() noexcept
Relinquish ownership of the identifier.
Definition HDF5Interface.h:78
~Handle()
Destructor.
Definition HDF5Interface.h:56
void close()
Close the identifier, reporting a failure.
Definition HDF5Interface.h:87
Handle & operator=(Handle &&h) noexcept
Move assignment.
Definition HDF5Interface.h:62
Handle(Handle &&h) noexcept
Move constructor.
Definition HDF5Interface.h:50
Scalar types that can be read from and written to an HDF5 file.
Definition HDF5Interface.h:115
int rank(MPI_Comm comm)
Return process rank for the communicator.
Definition MPI.cpp:73
auto logger() -> spdlog::logger &
Dolfinx's logger.
Definition log.cpp:24