/src/bag/api/bag_hdfhelper.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | #include "bag_exceptions.h" |
3 | | #include "bag_hdfhelper.h" |
4 | | |
5 | | #include <array> |
6 | | #include <H5Cpp.h> |
7 | | #include <numeric> |
8 | | |
9 | | |
10 | | namespace BAG { |
11 | | |
12 | | //! Create an HDF5 CompType based on the layer and group types. |
13 | | /*! |
14 | | \param layerType |
15 | | The type of layer. |
16 | | The supported types are NODE and ELEVATION. |
17 | | \param groupType |
18 | | The group type of the layer. |
19 | | For NODE, the supported types are: Hypothesis_Strength, Num_Hypotheses. |
20 | | For ELEVATION, the supported types are: Shoal_Elevation, Std_Dev, Num_Soundings. |
21 | | |
22 | | \return |
23 | | The compound type of the specified layer and group type. |
24 | | */ |
25 | | ::H5::CompType createH5compType( |
26 | | LayerType layerType, |
27 | | GroupType groupType) |
28 | 0 | { |
29 | 0 | ::H5::CompType h5type; |
30 | |
|
31 | 0 | if (groupType == NODE) |
32 | 0 | { |
33 | 0 | switch (layerType) |
34 | 0 | { |
35 | 0 | case Hypothesis_Strength: |
36 | 0 | h5type = ::H5::CompType{sizeof(float)}; |
37 | 0 | h5type.insertMember("hyp_strength", |
38 | 0 | 0, |
39 | 0 | ::H5::PredType::NATIVE_FLOAT); |
40 | 0 | break; |
41 | 0 | case Num_Hypotheses: |
42 | 0 | h5type = ::H5::CompType{sizeof(unsigned int)}; |
43 | 0 | h5type.insertMember("num_hypotheses", |
44 | 0 | 0, |
45 | 0 | ::H5::PredType::NATIVE_UINT32); |
46 | 0 | break; |
47 | 0 | default: |
48 | 0 | throw UnsupportedLayerType{}; |
49 | 0 | } |
50 | 0 | } |
51 | 0 | else if (groupType == ELEVATION) |
52 | 0 | { |
53 | 0 | switch(layerType) |
54 | 0 | { |
55 | 0 | case Shoal_Elevation: |
56 | 0 | h5type = ::H5::CompType{sizeof(float)}; |
57 | 0 | h5type.insertMember("shoal_elevation", |
58 | 0 | 0, |
59 | 0 | ::H5::PredType::NATIVE_FLOAT); |
60 | 0 | break; |
61 | 0 | case Std_Dev: |
62 | 0 | h5type = ::H5::CompType{sizeof(float)}; |
63 | 0 | h5type.insertMember("stddev", |
64 | 0 | 0, |
65 | 0 | ::H5::PredType::NATIVE_FLOAT); |
66 | 0 | break; |
67 | 0 | case Num_Soundings: |
68 | 0 | h5type = ::H5::CompType{sizeof(int)}; |
69 | 0 | h5type.insertMember("num_soundings", |
70 | 0 | 0, |
71 | 0 | ::H5::PredType::NATIVE_INT32); |
72 | 0 | break; |
73 | 0 | default: |
74 | 0 | throw UnsupportedLayerType{}; |
75 | 0 | } |
76 | 0 | } |
77 | 0 | else |
78 | 0 | throw UnsupportedGroupType{}; |
79 | | |
80 | 0 | return h5type; |
81 | 0 | } |
82 | | |
83 | | //! Create an HDF5 CompType used for file I/O based upon the Record Definition. |
84 | | /*! |
85 | | \param definition |
86 | | The list of fields making up the record. |
87 | | |
88 | | \return |
89 | | The HDF5 CompType to be used when reading and writing to an HDF file. |
90 | | */ |
91 | | ::H5::CompType createH5fileCompType( |
92 | | const RecordDefinition& definition) |
93 | 0 | { |
94 | 0 | ::H5::CompType h5type{getRecordSize(definition)}; |
95 | 0 | size_t fieldOffset = 0; |
96 | |
|
97 | 0 | for (const auto& field : definition) |
98 | 0 | { |
99 | 0 | h5type.insertMember(field.name, fieldOffset, |
100 | 0 | getH5fileType(static_cast<DataType>(field.type))); |
101 | |
|
102 | 0 | fieldOffset += Layer::getElementSize(static_cast<DataType>(field.type)); |
103 | 0 | } |
104 | |
|
105 | 0 | return h5type; |
106 | 0 | } |
107 | | |
108 | | //! Create an HDF5 CompType to be used in memory based upon the Record Definition. |
109 | | /*! |
110 | | \param definition |
111 | | The list of fields making up the record. |
112 | | |
113 | | \return |
114 | | The HDF5 CompType to be used when reading and writing from memory. |
115 | | */ |
116 | | ::H5::CompType createH5memoryCompType( |
117 | | const RecordDefinition& definition) |
118 | 49 | { |
119 | 49 | ::H5::CompType h5type{getRecordSize(definition)}; |
120 | 49 | size_t fieldOffset = 0; |
121 | | |
122 | 49 | for (const auto& field : definition) |
123 | 719 | { |
124 | 719 | h5type.insertMember(field.name, fieldOffset, |
125 | 719 | getH5memoryType(static_cast<DataType>(field.type))); |
126 | | |
127 | 719 | fieldOffset += Layer::getElementSize(static_cast<DataType>(field.type)); |
128 | 719 | } |
129 | | |
130 | 49 | return h5type; |
131 | 49 | } |
132 | | |
133 | | //! Get the chunk size from an HDF5 file. |
134 | | /*! |
135 | | \param h5file |
136 | | The HDF5 file. |
137 | | \param path |
138 | | The path to the HDF5 DataSet. |
139 | | |
140 | | \return |
141 | | The chunk size of the specified HDF5 DataSet in the HDF5 file. |
142 | | 0 if the HDF5 DataSet does not use chunking. |
143 | | */ |
144 | | uint64_t getChunkSize( |
145 | | const ::H5::H5File& h5file, |
146 | | const std::string& path) |
147 | 271 | { |
148 | | //Get the elevation HD5 dataset. |
149 | 271 | const auto h5dataset = h5file.openDataSet(path); |
150 | 271 | const auto h5pList = h5dataset.getCreatePlist(); |
151 | | |
152 | 271 | if (h5pList.getLayout() == H5D_CHUNKED) |
153 | 244 | { |
154 | 244 | std::array<hsize_t, kRank> maxDims{}; |
155 | | |
156 | 244 | const int rankChunk = h5pList.getChunk(kRank, maxDims.data()); |
157 | 244 | if (rankChunk == kRank) |
158 | | // This cast probably only matters on 32-bit systems, but gets rid of a compiler warning from the |
159 | | // previous code, which was `return {maxDims[0]}; |
160 | 241 | return (uint64_t) maxDims[0]; |
161 | 244 | } |
162 | | |
163 | 30 | return 0; |
164 | 271 | } |
165 | | |
166 | | //! Get the compression level from an HDF5 file. |
167 | | /*! |
168 | | \param h5file |
169 | | The HDF5 file. |
170 | | \param path |
171 | | The path to the HDF5 DataSet. |
172 | | |
173 | | \return |
174 | | The compression level of the specified HDF5 DataSet in the HDF5 file. |
175 | | 0 if the HDF5 DataSet is not compressed. |
176 | | */ |
177 | | int getCompressionLevel( |
178 | | const ::H5::H5File& h5file, |
179 | | const std::string& path) |
180 | 271 | { |
181 | | //Get the elevation HD5 dataset. |
182 | 271 | const auto h5dataset = h5file.openDataSet(path); |
183 | 271 | const auto h5pList = h5dataset.getCreatePlist(); |
184 | | |
185 | 291 | for (int i=0; i<h5pList.getNfilters(); ++i) |
186 | 238 | { |
187 | 238 | unsigned int flags = 0; |
188 | 238 | size_t cdNelmts = 10; |
189 | 238 | constexpr size_t nameLen = 64; |
190 | 238 | std::array<unsigned int, 10> cdValues{}; |
191 | 238 | std::array<char, 64> name{}; |
192 | 238 | unsigned int filterConfig = 0; |
193 | | |
194 | 238 | const auto filter = h5pList.getFilter(i, flags, cdNelmts, |
195 | 238 | cdValues.data(), nameLen, name.data(), filterConfig); |
196 | 238 | if (filter == H5Z_FILTER_DEFLATE && cdNelmts >= 1) |
197 | 218 | return static_cast<int>(cdValues.front()); |
198 | 238 | } |
199 | | |
200 | 53 | return 0; |
201 | 271 | } |
202 | | |
203 | | //! Get the size of a record in memory. |
204 | | /*! |
205 | | \param definition |
206 | | The list of fields in the record. |
207 | | |
208 | | \return |
209 | | The record size in memory, ignoring alignment. |
210 | | */ |
211 | | size_t getRecordSize( |
212 | | const RecordDefinition& definition) |
213 | 102 | { |
214 | 102 | return std::accumulate(cbegin(definition), cend(definition), 0ULL, |
215 | 1.47k | [](size_t sum, const auto& field) { |
216 | 1.47k | return sum + Layer::getElementSize(static_cast<DataType>(field.type)); |
217 | 1.47k | }); |
218 | 102 | } |
219 | | |
220 | | //! Determine the HDF5 file DataType from the specified data type. |
221 | | /*! |
222 | | \param type |
223 | | The data type to be matched. |
224 | | |
225 | | \return |
226 | | The matching HDF5 type used in file reading and writing. |
227 | | */ |
228 | | const ::H5::AtomType& getH5fileType( |
229 | | DataType type) |
230 | 0 | { |
231 | 0 | static ::H5::StrType strType{::H5::PredType::C_S1, H5T_VARIABLE}; |
232 | |
|
233 | 0 | switch(type) |
234 | 0 | { |
235 | 0 | case DT_UINT32: |
236 | 0 | return ::H5::PredType::NATIVE_UINT32; |
237 | 0 | case DT_FLOAT32: |
238 | 0 | return ::H5::PredType::NATIVE_FLOAT; |
239 | 0 | case DT_UINT8: |
240 | 0 | return ::H5::PredType::NATIVE_UINT8; |
241 | 0 | case DT_UINT16: |
242 | 0 | return ::H5::PredType::NATIVE_UINT16; |
243 | 0 | case DT_UINT64: |
244 | 0 | return ::H5::PredType::NATIVE_UINT64; |
245 | 0 | case DT_BOOLEAN: |
246 | 0 | return ::H5::PredType::NATIVE_HBOOL; |
247 | 0 | case DT_STRING: |
248 | 0 | return strType; |
249 | 0 | case DT_COMPOUND: //[fallthrough] |
250 | 0 | case DT_UNKNOWN_DATA_TYPE: //[fallthrough] |
251 | 0 | default: |
252 | 0 | throw UnsupportedDataType{}; |
253 | 0 | } |
254 | 0 | } |
255 | | |
256 | | //! Determine the HDF5 memory DataType from the specified DataType. |
257 | | /*! |
258 | | \param type |
259 | | The data type to be matched. |
260 | | |
261 | | \return |
262 | | The matching HDF5 type used in memory. |
263 | | */ |
264 | | const ::H5::AtomType& getH5memoryType( |
265 | | DataType type) |
266 | 719 | { |
267 | 719 | static ::H5::StrType strType{::H5::PredType::C_S1, H5T_VARIABLE}; |
268 | | |
269 | 719 | switch(type) |
270 | 719 | { |
271 | 50 | case DT_UINT32: |
272 | 50 | return H5::PredType::NATIVE_UINT32; |
273 | 231 | case DT_FLOAT32: |
274 | 231 | return ::H5::PredType::NATIVE_FLOAT; |
275 | 0 | case DT_UINT8: |
276 | 0 | return ::H5::PredType::NATIVE_UINT8; |
277 | 0 | case DT_UINT16: |
278 | 0 | return ::H5::PredType::NATIVE_UINT16; |
279 | 0 | case DT_UINT64: |
280 | 0 | return ::H5::PredType::NATIVE_UINT64; |
281 | 169 | case DT_BOOLEAN: |
282 | 169 | return ::H5::PredType::NATIVE_HBOOL; |
283 | 269 | case DT_STRING: |
284 | 269 | return strType; |
285 | 0 | case DT_COMPOUND: //[fallthrough] |
286 | 0 | case DT_UNKNOWN_DATA_TYPE: //[fallthrough] |
287 | 0 | default: |
288 | 0 | throw UnsupportedDataType{}; |
289 | 719 | } |
290 | 719 | } |
291 | | |
292 | | //! Create an attribute on an HDF5 DataSet. |
293 | | /*! |
294 | | \param h5dataSet |
295 | | The HDF5 DataSet to create the attribute on. |
296 | | \param attributeType |
297 | | The HDF5 type of the attribute. |
298 | | \param path |
299 | | The HDF5 path of the attribute. |
300 | | The path cannot be nullptr. |
301 | | |
302 | | \return |
303 | | The new HDF5 attribute. |
304 | | */ |
305 | | ::H5::Attribute createAttribute( |
306 | | const ::H5::DataSet& h5dataSet, |
307 | | const ::H5::PredType& attributeType, |
308 | | const char* path) |
309 | 0 | { |
310 | 0 | return h5dataSet.createAttribute(path, attributeType, {}); |
311 | 0 | } |
312 | | |
313 | | //! Create attributes on an HDF5 DataSet. |
314 | | /*! |
315 | | \param h5dataSet |
316 | | The HDF5 DataSet to create the attributes on. |
317 | | \param attributeType |
318 | | The HDF5 type of the attributes. |
319 | | \param paths |
320 | | The HDF5 paths of the attributes. |
321 | | If no paths are provided, no attributes are written. |
322 | | If a path is nullptr, that attribute is not written. |
323 | | */ |
324 | | void createAttributes( |
325 | | const ::H5::DataSet& h5dataSet, |
326 | | const ::H5::PredType& attributeType, |
327 | | const std::vector<const char*>& paths) |
328 | 0 | { |
329 | 0 | if (paths.empty()) |
330 | 0 | return; |
331 | | |
332 | 0 | for (const auto& path : paths) |
333 | 0 | if (path) |
334 | 0 | createAttribute(h5dataSet, attributeType, path); |
335 | 0 | } |
336 | | |
337 | | //! Write an attribute to the specified HDF5 DataSet. |
338 | | /*! |
339 | | \param h5dataSet |
340 | | The HDF5 DataSet to create the attribute on. |
341 | | \param attributeType |
342 | | The HDF5 type of the attribute. |
343 | | \param valiue |
344 | | The value of the attribute. |
345 | | \param path |
346 | | The HDF5 path of the attribute. |
347 | | The path cannot be nullptr. |
348 | | */ |
349 | | template <typename T> |
350 | | void writeAttribute( |
351 | | const ::H5::DataSet& h5dataSet, |
352 | | const ::H5::PredType& attributeType, |
353 | | T value, |
354 | | const char* path) |
355 | 0 | { |
356 | 0 | const auto att = h5dataSet.openAttribute(path); |
357 | 0 | att.write(attributeType, &value); |
358 | 0 | } Unexecuted instantiation: void BAG::writeAttribute<float>(H5::DataSet const&, H5::PredType const&, float, char const*) Unexecuted instantiation: void BAG::writeAttribute<unsigned int>(H5::DataSet const&, H5::PredType const&, unsigned int, char const*) |
359 | | |
360 | | //! Write attributes to an HDF5 DataSet. |
361 | | /*! |
362 | | \param h5dataSet |
363 | | The HDF5 DataSet to create the attributes on. |
364 | | \param attributeType |
365 | | The HDF5 type of the attributes. |
366 | | \param paths |
367 | | The HDF5 paths of the attributes. |
368 | | If no paths are provided, no attributes are written. |
369 | | If a path is nullptr, that attribute is not written. |
370 | | */ |
371 | | template <typename T> |
372 | | void writeAttributes( |
373 | | const ::H5::DataSet& h5dataSet, |
374 | | const ::H5::PredType& attributeType, |
375 | | T value, |
376 | | const std::vector<const char*>& paths) |
377 | 0 | { |
378 | 0 | if (paths.empty()) |
379 | 0 | return; |
380 | | |
381 | 0 | for (const auto& path : paths) |
382 | 0 | if (path) |
383 | 0 | writeAttribute(h5dataSet, attributeType, value, path); |
384 | 0 | } Unexecuted instantiation: void BAG::writeAttributes<float>(H5::DataSet const&, H5::PredType const&, float, std::__1::vector<char const*, std::__1::allocator<char const*> > const&) Unexecuted instantiation: void BAG::writeAttributes<unsigned int>(H5::DataSet const&, H5::PredType const&, unsigned int, std::__1::vector<char const*, std::__1::allocator<char const*> > const&) |
385 | | |
386 | | |
387 | | // Explicit template instantiations. |
388 | | |
389 | | //! Write a float point value to an attribute. |
390 | | /* |
391 | | \param h5dataSet |
392 | | The HDF5 DataSet to create the attributes on. |
393 | | \param attributeType |
394 | | The HDF5 type of the attribute. |
395 | | \param value |
396 | | The value to write to the attribute. |
397 | | \param path |
398 | | The HDF5 path to the attribute in the HDF5 DataSet. |
399 | | Cannot be nullptr. |
400 | | */ |
401 | | template void writeAttribute<float>(const ::H5::DataSet& h5dataSet, |
402 | | const ::H5::PredType& attributeType, float value, const char* path); |
403 | | |
404 | | //! Write an unsigned 32 bit integer value to an attribute. |
405 | | /* |
406 | | \param h5dataSet |
407 | | The HDF5 DataSet to create the attributes on. |
408 | | \param attributeType |
409 | | The HDF5 type of the attribute. |
410 | | \param value |
411 | | The value to write to the attribute. |
412 | | \param path |
413 | | The HDF5 path to the attribute in the HDF5 DataSet. |
414 | | Cannot be nullptr. |
415 | | */ |
416 | | template void writeAttribute<uint32_t>(const ::H5::DataSet& h5dataSet, |
417 | | const ::H5::PredType& attributeType, uint32_t value, const char* path); |
418 | | |
419 | | //! Write a floating point value to multiple attributes. |
420 | | /* |
421 | | \param h5dataSet |
422 | | The HDF5 DataSet to create the attributes on. |
423 | | \param attributeType |
424 | | The HDF5 type of the attribute. |
425 | | \param value |
426 | | The value to write to the attribute. |
427 | | \param paths |
428 | | The HDF5 path to the attributes in the HDF5 DataSet. |
429 | | If no paths provided, no attributes are written. |
430 | | If any path is nullptr, that attribute is not written. |
431 | | */ |
432 | | template void writeAttributes<float>(const ::H5::DataSet& h5dataSet, |
433 | | const ::H5::PredType& attributeType, float value, |
434 | | const std::vector<const char*>& paths); |
435 | | |
436 | | //! Write an unsigned 32 bit integer value to multiple attributes. |
437 | | /* |
438 | | \param h5dataSet |
439 | | The HDF5 DataSet to create the attributes on. |
440 | | \param attributeType |
441 | | The HDF5 type of the attribute. |
442 | | \param value |
443 | | The value to write to the attribute. |
444 | | \param paths |
445 | | The HDF5 path to the attributes in the HDF5 DataSet. |
446 | | If no paths provided, no attributes are written. |
447 | | If any path is nullptr, that attribute is not written. |
448 | | */ |
449 | | template void writeAttributes<uint32_t>(const ::H5::DataSet& h5dataSet, |
450 | | const ::H5::PredType& attributeType, uint32_t value, |
451 | | const std::vector<const char*>& paths); |
452 | | |
453 | | } // namespace BAG |
454 | | |