Robowflex  v0.1
Making MoveIt Easy
hdf5.cpp
Go to the documentation of this file.
1 /* Author: Zachary Kingston */
2 
3 #include <iostream>
4 #include <numeric>
5 
6 #include <robowflex_library/io.h>
10 
11 using namespace robowflex;
12 
13 ///
14 /// IO::HDF5Data
15 ///
16 
17 template <typename T>
18 IO::HDF5Data::HDF5Data(const T &location, const std::string &name)
19  : dataset_(location.openDataSet(name))
20  , space_(dataset_.getSpace())
21  , type_(dataset_.getTypeClass())
22  , rank_(space_.getSimpleExtentNdims())
23  , dims_([&] {
24  auto *dims = new hsize_t[rank_];
25  space_.getSimpleExtentDims(dims);
26  return dims;
27  }())
28  , data_([&] {
29  const auto &properties = getDataProperties();
30  void *data = std::malloc(std::get<1>(properties) * //
31  std::accumulate(dims_, dims_ + rank_, 1, std::multiplies<hsize_t>()));
32 
33  dataset_.read(data, std::get<0>(properties), space_, space_);
34  return data;
35  }())
36 {
37 }
38 
39 template IO::HDF5Data::HDF5Data(const H5::H5File &, const std::string &);
40 template IO::HDF5Data::HDF5Data(const H5::Group &, const std::string &);
41 
43 {
44  delete dims_;
45 
46  // clang-format off
48  // clang-format on
49 
50  std::free((void *)data_);
52 }
53 
55 {
56  return std::vector<hsize_t>(dims_, dims_ + rank_);
57 }
58 
59 const void *IO::HDF5Data::getData() const
60 {
61  return data_;
62 }
63 
65 {
67  ss << "HDF5DataSet ";
68  ss << "Rank: " << rank_ << ", ";
69  ss << "Type: " << std::get<2>(getDataProperties()) << ", ";
70  ss << "Dimensions: ";
71  for (int i = 0; i < rank_; ++i)
72  {
73  if (i > 0)
74  ss << " x ";
75  ss << dims_[i];
76  }
77 
78  return ss.str();
79 }
80 
81 namespace
82 {
83  hsize_t hpow(hsize_t base, hsize_t exp)
84  {
85  hsize_t result = 1;
86  while (exp)
87  {
88  if (exp & 1)
89  result *= base;
90  exp /= 2;
91  base *= base;
92  }
93 
94  return result;
95  }
96 }; // namespace
97 
98 template <typename T>
99 const T &IO::HDF5Data::get(const std::vector<hsize_t> &index) const
100 {
101  if (index.size() != (unsigned int)rank_)
102  throw Exception(1, "Index size must be the same as data rank!");
103 
104  const T *data = reinterpret_cast<const T *>(data_);
105  unsigned int offset = 0;
106 
107  for (int i = 0; i < rank_; ++i)
108  offset += hpow(dims_[i], i) * index[rank_ - (i + 1)];
109 
110  return data[offset];
111 }
112 
113 template const int &IO::HDF5Data::get(const std::vector<hsize_t> &index) const;
114 template const double &IO::HDF5Data::get(const std::vector<hsize_t> &index) const;
115 
117 {
118  switch (type_)
119  {
120  case H5T_INTEGER:
121  return std::make_tuple(H5::PredType::NATIVE_INT, sizeof(int), "integer");
122  case H5T_FLOAT:
123  return std::make_tuple(H5::PredType::NATIVE_DOUBLE, sizeof(double), "double");
124  // case H5T_TIME:
125  // case H5T_STRING:
126  // case H5T_BITFIELD:
127  // case H5T_OPAQUE:
128  // case H5T_COMPOUND:
129  // case H5T_REFERENCE:
130  // case H5T_ENUM:
131  // case H5T_VLEN:
132  // case H5T_ARRAY:
133  default:
134  return std::make_tuple(H5::PredType::NATIVE_OPAQUE, 0, "unknown");
135  break;
136  }
137 }
138 
139 ///
140 /// IO::HDF5File
141 ///
142 
144  : file_(IO::resolvePath(filename), H5F_ACC_RDONLY), data_(NodeMap())
145 {
146  for (const auto &obj : listObjects(file_))
147  loadData(data_, file_, obj);
148 }
149 
150 namespace
151 {
152  void getKeysHelper(std::vector<std::vector<std::string>> &keys, const std::vector<std::string> &key,
153  const IO::HDF5File::NodeMap &node)
154  {
155  for (const auto &element : node)
156  {
157  auto next_key = key;
158  next_key.push_back(element.first);
159 
160  try
161  {
162  const auto &next = boost::get<IO::HDF5File::NodeMap>(element.second);
163  getKeysHelper(keys, next_key, next);
164  }
165  catch (std::exception &e)
166  {
167  keys.push_back(next_key);
168  }
169  }
170  }
171 
172  IO::HDF5DataPtr getDataHelper(const std::vector<std::string> &keys, const IO::HDF5File::NodeMap &node)
173  {
174  if (keys.empty())
175  return nullptr;
176 
177  const auto &element = node.find(keys.front());
178  if (element == node.end())
179  return nullptr;
180 
181  try
182  {
183  const auto &next = boost::get<IO::HDF5File::NodeMap>(element->second);
184  std::vector<std::string> copy(keys.begin() + 1, keys.end());
185  return getDataHelper(copy, next);
186  }
187  catch (std::exception &e)
188  {
189  return boost::get<IO::HDF5DataPtr>(element->second);
190  }
191 
192  return nullptr;
193  }
194 
195  template <typename T>
196  H5O_type_t childObjType(const T &location, const std::string &name)
197  {
198  H5O_info_t info;
199  H5O_type_t type = H5O_TYPE_UNKNOWN;
200 
201  herr_t r = H5Oget_info_by_name(location.getId(), name.c_str(), &info, H5P_DEFAULT);
202 
203  if (r < 0)
204  return type;
205 
206  switch (info.type)
207  {
208  case H5O_TYPE_GROUP:
209  case H5O_TYPE_DATASET:
210  case H5O_TYPE_NAMED_DATATYPE:
211  type = info.type;
212  default:
213  break;
214  }
215 
216  return (type);
217  }
218 }; // namespace
219 
220 const IO::HDF5DataPtr IO::HDF5File::getData(const std::vector<std::string> &keys) const
221 {
222  const NodeMap &node = boost::get<NodeMap>(data_);
223  return getDataHelper(keys, node);
224 }
225 
227 {
228  const NodeMap &node = boost::get<NodeMap>(data_);
231 
232  getKeysHelper(keys, key, node);
233 
234  return keys;
235 }
236 
237 template <typename T>
239 {
241  for (hsize_t i = 0; i < location.getNumObjs(); ++i)
242  names.emplace_back(location.getObjnameByIdx(i));
243 
244  return names;
245 }
246 
247 template std::vector<std::string> IO::HDF5File::listObjects(const H5::H5File &) const;
248 template std::vector<std::string> IO::HDF5File::listObjects(const H5::Group &) const;
249 
250 template <typename T>
251 void IO::HDF5File::loadData(Node &node, const T &location, const std::string &name)
252 {
253  auto &map = boost::get<NodeMap>(node);
254 
255 #if ROBOWFLEX_AT_LEAST_KINETIC
256  H5O_type_t type = location.childObjType(name);
257 #else
258  H5O_type_t type = childObjType(location, name);
259 #endif
260 
261  switch (type)
262  {
263  case H5O_TYPE_GROUP:
264  {
265  map[name] = NodeMap();
266 
267  H5::Group group = location.openGroup(name);
268  for (const auto &obj : listObjects(group))
269  loadData(map[name], group, obj);
270 
271  break;
272  }
273  case H5O_TYPE_DATASET:
274  {
275  map[name] = std::make_shared<HDF5Data>(location, name);
276  break;
277  }
278 
279  // case H5O_TYPE_NAMED_DATATYPE:
280  // case H5O_TYPE_NTYPES:
281  default:
282  break;
283  };
284 }
285 
286 template void IO::HDF5File::loadData(Node &, const H5::H5File &, const std::string &);
287 template void IO::HDF5File::loadData(Node &, const H5::Group &, const std::string &);
T accumulate(T... args)
T begin(T... args)
T c_str(T... args)
Exception that contains a message and an error code.
Definition: util.h:15
const void * getData() const
Get a pointer to the underlying data array. It is of size type[dim0][dim1]...
Definition: hdf5.cpp:59
const std::string getStatus() const
Get a string describing the data.
Definition: hdf5.cpp:64
~HDF5Data()
Destructor. Cleans up all read data.
Definition: hdf5.cpp:42
const int rank_
Rank of the dataset.
Definition: hdf5.h:81
HDF5Data(const T &location, const std::string &name)
Constructor. Loads reads DataSet from file.
Definition: hdf5.cpp:18
const T & get(const std::vector< hsize_t > &index) const
Get the value at an index.
Definition: hdf5.cpp:99
const std::vector< hsize_t > getDims() const
Gets the dimensions of the data. Can be used to create the array necessary to store results.
Definition: hdf5.cpp:54
const H5::DataSpace space_
Size of the dataset.
Definition: hdf5.h:78
std::tuple< H5::PredType, unsigned int, std::string > getDataProperties() const
Return information about the data type of the data.
Definition: hdf5.cpp:116
boost::make_recursive_variant< HDF5DataPtr, std::map< std::string, boost::recursive_variant_ > >::type Node
A recursive map that has a dictionary-like structure to store HDF5 datasets.
Definition: hdf5.h:95
Node data_
A recursive map of loaded data.
Definition: hdf5.h:134
std::vector< std::string > listObjects(const T &location) const
List the objects at the HDF5 location.
Definition: hdf5.cpp:238
void loadData(Node &node, const T &location, const std::string &name)
Loads the data in the object name at the HDF5 location. Recursive.
Definition: hdf5.cpp:251
const std::vector< std::vector< std::string > > getKeys() const
Gets all valid keys in the file.
Definition: hdf5.cpp:226
const H5::H5File file_
The loaded HDF5 file.
Definition: hdf5.h:133
HDF5File(const std::string &filename)
Constructor. Opens filename.
Definition: hdf5.cpp:143
const HDF5DataPtr getData(const std::vector< std::string > &keys) const
Get the dataset under the set of keys. Each key is applied successively.
Definition: hdf5.cpp:220
T copy(T... args)
T emplace_back(T... args)
T empty(T... args)
T end(T... args)
T find(T... args)
T free(T... args)
T front(T... args)
#define ROBOWFLEX_PUSH_DISABLE_GCC_WARNING(warning)
Definition: macros.h:77
#define ROBOWFLEX_POP_GCC
Definition: macros.h:80
T make_tuple(T... args)
T malloc(T... args)
std::string resolvePath(const std::string &path)
Resolves package:// URLs and relative file paths to their canonical form.
Main namespace. Contains all library classes and functions.
Definition: scene.cpp:25
T next(T... args)
T push_back(T... args)
T size(T... args)
T str(T... args)