Coverage Report

Created: 2025-08-26 07:05

/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
31
{
119
31
    ::H5::CompType h5type{getRecordSize(definition)};
120
31
    size_t fieldOffset = 0;
121
122
31
    for (const auto& field : definition)
123
465
    {
124
465
        h5type.insertMember(field.name, fieldOffset,
125
465
            getH5memoryType(static_cast<DataType>(field.type)));
126
127
465
        fieldOffset += Layer::getElementSize(static_cast<DataType>(field.type));
128
465
    }
129
130
31
    return h5type;
131
31
}
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
218
{
148
    //Get the elevation HD5 dataset.
149
218
    const auto h5dataset = h5file.openDataSet(path);
150
218
    const auto h5pList = h5dataset.getCreatePlist();
151
152
218
    if (h5pList.getLayout() == H5D_CHUNKED)
153
191
    {
154
191
        std::array<hsize_t, kRank> maxDims{};
155
156
191
        const int rankChunk = h5pList.getChunk(kRank, maxDims.data());
157
191
        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
187
            return (uint64_t) maxDims[0];
161
191
    }
162
163
31
    return 0;
164
218
}
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
218
{
181
    //Get the elevation HD5 dataset.
182
218
    const auto h5dataset = h5file.openDataSet(path);
183
218
    const auto h5pList = h5dataset.getCreatePlist();
184
185
240
    for (int i=0; i<h5pList.getNfilters(); ++i)
186
185
    {
187
185
        unsigned int flags = 0;
188
185
        size_t cdNelmts = 10;
189
185
        constexpr size_t nameLen = 64;
190
185
        std::array<unsigned int, 10> cdValues{};
191
185
        std::array<char, 64> name{};
192
185
        unsigned int filterConfig = 0;
193
194
185
        const auto filter = h5pList.getFilter(i, flags, cdNelmts,
195
185
            cdValues.data(), nameLen, name.data(), filterConfig);
196
185
        if (filter == H5Z_FILTER_DEFLATE && cdNelmts >= 1)
197
163
            return static_cast<int>(cdValues.front());
198
185
    }
199
200
55
    return 0;
201
218
}
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
66
{
214
66
    return std::accumulate(cbegin(definition), cend(definition), 0ULL,
215
969
        [](size_t sum, const auto& field) {
216
969
            return sum + Layer::getElementSize(static_cast<DataType>(field.type));
217
969
        });
218
66
}
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
465
{
267
465
    static ::H5::StrType strType{::H5::PredType::C_S1, H5T_VARIABLE};
268
269
465
    switch(type)
270
465
    {
271
33
    case DT_UINT32:
272
33
        return H5::PredType::NATIVE_UINT32;
273
162
    case DT_FLOAT32:
274
162
        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
101
    case DT_BOOLEAN:
282
101
        return ::H5::PredType::NATIVE_HBOOL;
283
169
    case DT_STRING:
284
169
        return strType;
285
0
    case DT_COMPOUND:  //[fallthrough]
286
0
    case DT_UNKNOWN_DATA_TYPE:  //[fallthrough]
287
0
    default:
288
0
        throw UnsupportedDataType{};
289
465
    }
290
465
}
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