Utopia  2
Framework for studying models of complex & adaptive systems.
hdfdataspace.hh
Go to the documentation of this file.
1 #ifndef UTOPIA_DATAIO_HDFDATASPACE_HH
2 #define UTOPIA_DATAIO_HDFDATASPACE_HH
3 
4 #include <armadillo>
5 #include <stdexcept>
6 
7 #include <hdf5.h>
8 
9 #include "../core/logging.hh"
10 #include "../core/type_traits.hh"
11 #include "../core/ostream.hh"
12 
13 #include "hdfobject.hh"
14 #include "hdfutilities.hh"
15 
16 
17 namespace Utopia
18 {
19 namespace DataIO
20 {
36 class HDFDataspace final : public HDFObject< HDFCategory::dataspace >
37 {
38  public:
45  hsize_t
46  rank()
47  {
48  if (is_valid())
49  {
50  return H5Sget_simple_extent_ndims(get_C_id());
51  }
52  else
53  {
54  throw std::runtime_error(
55  "Error, trying to get rank of invalid dataspace");
56  return 0;
57  }
58  }
59 
66  std::pair< arma::Row< hsize_t >, arma::Row< hsize_t > >
68  {
69  if (not is_valid())
70  {
71  throw std::runtime_error(
72  "Error, trying to get properties of invalid dataspace," +
74  }
75 
76  arma::Row< hsize_t > size;
77  size.resize(H5Sget_simple_extent_ndims(get_C_id()));
78 
79  arma::Row< hsize_t > capacity;
80  capacity.resize(size.size());
81 
82  H5Sget_simple_extent_dims(get_C_id(), size.memptr(), capacity.memptr());
83 
84  return std::make_pair(size, capacity);
85  }
86 
93  arma::Row< hsize_t >
94  size()
95  {
96  return get_properties().first;
97  }
98 
105  arma::Row< hsize_t >
107  {
108  return get_properties().second;
109  }
110 
116  void
118  {
119 
120  this->_log->debug("Opening dataspace, setting it to H5S_ALL");
121  // no explicit close function needed for H5S_ALL
122  _id.open(H5S_ALL, [](hid_t) -> herr_t { return 1; });
123  _path = "Dataspace_all";
124  }
125 
132  template < typename Object >
133  void
134  open(Object&& object)
135  {
136 
137  this->_log->debug(
138  "Opening dataspace of {}", generate_object_name(object));
139 
140  // open_dataspace is defined for attribute and dataset
141  // in their respective headerfiles to provide uniform
142  // interface for both, such that we do not have to
143  // differentiate between them
144  bind_to(open_dataspace(std::forward< Object >(object)),
145  &H5Sclose,
146  object.get_path() + " dataspace");
147 
148  _log = spdlog::get("data_io");
149  }
150 
161  void
162  open(std::string name,
163  hsize_t rank,
164  arma::Row< hsize_t > extent,
165  arma::Row< hsize_t > capacity)
166  {
167 
168  this->_log->debug("Opening dataspace from scratch with rank {}, extent "
169  "{} and capacity {}",
170  rank,
171  Utils::str(extent),
173  if (capacity.size() == 0)
174  {
175  bind_to(
176  H5Screate_simple(rank, extent.memptr(), NULL), &H5Sclose, name);
177  }
178  else
179  {
180  bind_to(H5Screate_simple(rank, extent.memptr(), capacity.memptr()),
181  &H5Sclose,
182  name);
183  }
184 
185  _log = spdlog::get("data_io");
186  }
187 
194  std::pair< arma::Row< hsize_t >, arma::Row< hsize_t > >
196  {
197  arma::Row< hsize_t > start;
198  arma::Row< hsize_t > end;
199 
200  if (is_valid())
201  {
202  hsize_t r = rank();
203  start.resize(r);
204  end.resize(r);
205 
206  if (H5Sget_select_bounds(get_C_id(), start.memptr(), end.memptr()) <
207  0)
208  {
209  throw std::runtime_error(
210  "Error, cannot get selection bounds of invalid dataspace");
211  }
212  }
213  return std::make_pair(start, end);
214  }
215 
224  void
225  select_slice(arma::Row< hsize_t > start,
226  arma::Row< hsize_t > end,
227  arma::Row< hsize_t > stride)
228  {
229 
230  this->_log->debug(
231  "Selecting slice in dataspace with start={}, end={}, stride={}",
232  Utils::str(start),
233  Utils::str(end),
234  Utils::str(stride));
235 
236  if (not is_valid())
237  {
238  throw std::runtime_error(
239  "Error, trying to select a slice in an invalid dataspace");
240  }
241 
242  hsize_t r = rank();
243 
244  if ((start.n_elem != r) or (end.n_elem != r))
245  {
246  throw std::runtime_error(
247  "Error, dimensionality of start and end has to be the same as "
248  "the dataspace's rank");
249  }
250  // stride may not be given, and hence we have to check for
251  // it in order to correctly compute the counts vector: divison
252  // can be skipped when stride.size() == 0
253 
254  arma::Row< hsize_t > count;
255  hsize_t* strideptr = nullptr;
256  if (stride.size() == 0)
257  {
258  count = ((end - start)).as_row();
259  }
260  else
261  {
262  count = ((end - start) / stride).as_row();
263  strideptr = stride.memptr();
264  }
265 
266  auto err = H5Sselect_hyperslab(get_C_id(),
267  H5S_SELECT_SET,
268  start.memptr(),
269  strideptr,
270  count.memptr(),
271  nullptr);
272  if (err < 0)
273  {
274  throw std::runtime_error(
275  "Error when trying to select slice in dataspace");
276  }
277  }
278 
283  void
285  {
286  this->_log->debug("Selecting everything in dataspace");
287 
288  if (not is_valid())
289  {
290  throw std::runtime_error(
291  "Error, trying to select everything of an invalid dataspace");
292  }
293 
294  herr_t err = H5Sselect_all(get_C_id());
295  if (err < 0)
296  {
297  throw std::runtime_error(
298  "Error when trying to select entire dataspace");
299  }
300  }
301 
310  void
311  resize(arma::Row< hsize_t > new_size)
312  {
313  this->_log->debug("Resizing dataset from {} to {}",
314  Utils::str(size()),
315  Utils::str(new_size));
316 
317  if (not is_valid())
318  {
319  throw std::runtime_error(
320  "Error, trying to resize an invalid dataspace");
321  }
322 
323  auto [current_extent, current_capacity] = get_properties();
324 
325  // make capacity bigger if needed
326  auto new_capacity = arma::max(current_capacity, new_size);
327 
328  // resize the dataspace
329  herr_t err = H5Sset_extent_simple(get_C_id(),
330  new_size.size(),
331  new_size.memptr(),
332  current_capacity.memptr());
333 
334  if (err < 0)
335  {
336  throw std::runtime_error("Error in resizing dataspace");
337  }
338  }
339 
344  void
346  {
347  this->_log->debug("Releasing selection");
348 
349  if (not is_valid())
350  {
351  throw std::runtime_error(
352  "Cannot reset selection, dataspace is invalid");
353  }
354 
355  H5Sselect_none(get_C_id());
356  }
357 
364  {
365  open();
366  }
367 
372  HDFDataspace(const HDFDataspace&) = default;
373 
379 
385  HDFDataspace&
386  operator=(const HDFDataspace&) = default;
387 
393  HDFDataspace&
394  operator=(HDFDataspace&&) = default;
395 
403  HDFDataspace(std::string name,
404  hsize_t rank,
405  std::vector< hsize_t > extent,
406  std::vector< hsize_t > capacity)
407  {
408  open(name, rank, extent, capacity);
409  }
410 
418  template < typename Object >
419  HDFDataspace(Object&& object,
420  std::enable_if_t<
421  not std::is_same_v< std::decay_t< Object >, HDFDataspace >,
422  int > = 0)
423  {
424  open(std::forward< Object >(object));
425  }
426 
431  virtual ~HDFDataspace() = default;
432 
438  void
440  {
441  using std::swap;
442  using Utopia::DataIO::swap;
443  swap(static_cast< Base& >(*this), static_cast< Base& >(other));
444  }
445 };
446 
453 void
455 {
456  lhs.swap(rhs);
457 }
458 
459 }
460 
461 }
462 #endif
Class that wraps an HDF5 dataspace and takes care of managing its resources.
Definition: hdfdataspace.hh:37
void open(hid_t id, std::function< herr_t(hid_t) > closing_func)
Open the object and bind it to another C-Level id.
Definition: hdfidentifier.hh:156
Common base class for all HDF5 classes in the DATAIO Module i.e., for all classes that wrap HDF5-C-Li...
Definition: hdfobject.hh:37
std::string _path
Name of the object.
Definition: hdfobject.hh:50
std::string get_path() const
Get the name or path object.
Definition: hdfobject.hh:88
virtual bool is_valid() const
Check if the object is still valid.
Definition: hdfobject.hh:143
std::shared_ptr< spdlog::logger > _log
pointer to the logger for dataio
Definition: hdfobject.hh:56
HDFIdentifier _id
Identifier object that binds an instance of this class to an HDF5 object.
Definition: hdfobject.hh:44
hid_t get_C_id() const
Get the C id object.
Definition: hdfobject.hh:120
void bind_to(hid_t id, std::function< herr_t(hid_t) > closing_func, std::string path={})
Open the object and bind it to a HDF5 object identified by 'id' with name 'path'. Object should be cr...
Definition: hdfobject.hh:186
std::string to_string(const Config &node)
Given a config node, returns a string representation of it.
Definition: cfg_utils.hh:110
void swap(WriteTask< BGB, DW, DB, AWG, AWD > &lhs, WriteTask< BGB, DW, DB, AWG, AWD > &rhs)
Swaps the state of lhs and rhs.
Definition: write_task.hh:240
hid_t open_dataspace(Object &&object)
Depending on object category, opens a dataset or attribute dataspace.
Definition: hdfutilities.hh:235
arma::Row< hsize_t > size()
Get the current size of the dataspace in each dimension.
Definition: hdfdataspace.hh:94
void open(std::string name, hsize_t rank, arma::Row< hsize_t > extent, arma::Row< hsize_t > capacity)
Open a new dataset of type 'simple', which is equivalent to a N-dimensional array of dimension N = 'r...
Definition: hdfdataspace.hh:162
void swap(HDFDataspace &other)
Swap state with argument.
Definition: hdfdataspace.hh:439
HDFDataspace(HDFDataspace &&)=default
Move constructor.
void release_selection()
Release a previously defined selection.
Definition: hdfdataspace.hh:345
std::string generate_object_name(const Object &object)
Use category and path variable of object to make a string that identifies the object it is applied to...
Definition: hdfutilities.hh:220
virtual ~HDFDataspace()=default
Destroy the HDFDataspace object.
void select_slice(arma::Row< hsize_t > start, arma::Row< hsize_t > end, arma::Row< hsize_t > stride)
Select a slice in the dataspace defined by [start, end, stride] in the manner of numpy....
Definition: hdfdataspace.hh:225
arma::Row< hsize_t > capacity()
Get the capacity of the dataspace in each dimension.
Definition: hdfdataspace.hh:106
HDFDataspace(const HDFDataspace &)=default
Copy constructor.
HDFDataspace(Object &&object, std::enable_if_t< not std::is_same_v< std::decay_t< Object >, HDFDataspace >, int >=0)
Construct a new HDFDataspace object from an HDFDataset or HDFAttribute. This loads the file-dataspace...
Definition: hdfdataspace.hh:419
void open(Object &&object)
Open the dataspace with an HDF5 object, i.e., dataset or attribute.
Definition: hdfdataspace.hh:134
HDFDataspace(std::string name, hsize_t rank, std::vector< hsize_t > extent, std::vector< hsize_t > capacity)
Construct HDFDataspace from the given arguments.
Definition: hdfdataspace.hh:403
void select_all()
Select the entire dataspace as hyperslap to be read/written to.
Definition: hdfdataspace.hh:284
std::pair< arma::Row< hsize_t >, arma::Row< hsize_t > > get_selection_bounds()
Get the selection bounding box, i.e., the start and end vector of the currently selected subset of th...
Definition: hdfdataspace.hh:195
HDFDataspace & operator=(HDFDataspace &&)=default
Move assign dataspace.
HDFDataspace & operator=(const HDFDataspace &)=default
Copy assign dataspace.
HDFDataspace()
Construct HDFDataspace per default. Equivalent to using H5S_ALL when employing the pure C interface.
Definition: hdfdataspace.hh:363
hsize_t rank()
Get thet dataspace's rank, i.e., number of dimensions.
Definition: hdfdataspace.hh:46
void open()
Open the dataspace - set it to be equivalent to any data that later will be used to write or read.
Definition: hdfdataspace.hh:117
std::pair< arma::Row< hsize_t >, arma::Row< hsize_t > > get_properties()
Get the properties object: size and capacity. @notice The dimensions can be infered from the size of ...
Definition: hdfdataspace.hh:67
void swap(HDFDataspace &lhs, HDFDataspace &rhs)
Swap states of lhs and rhs.
Definition: hdfdataspace.hh:454
void resize(arma::Row< hsize_t > new_size)
Resize the dataspace. The new size needs to fit into the dataspaces capacity.
Definition: hdfdataspace.hh:311
This file provides metafunctions for automatically determining the nature of a C/C++ types at compile...
auto end(zip< Containers... > &zipper)
end function like std::end
Definition: zip.hh:550
std::string str(T &&t)
Turn any object for which operator<< exists into a string. Mostly useful for logging data via spdlog ...
Definition: ostream.hh:164
Definition: agent.hh:11