Coverage Report

Created: 2025-07-11 06:33

/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
34
{
119
34
    ::H5::CompType h5type{getRecordSize(definition)};
120
34
    size_t fieldOffset = 0;
121
122
34
    for (const auto& field : definition)
123
510
    {
124
510
        h5type.insertMember(field.name, fieldOffset,
125
510
            getH5memoryType(static_cast<DataType>(field.type)));
126
127
510
        fieldOffset += Layer::getElementSize(static_cast<DataType>(field.type));
128
510
    }
129
130
34
    return h5type;
131
34
}
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
188
            return (uint64_t) maxDims[0];
161
191
    }
162
163
30
    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
238
    for (int i=0; i<h5pList.getNfilters(); ++i)
186
186
    {
187
186
        unsigned int flags = 0;
188
186
        size_t cdNelmts = 10;
189
186
        constexpr size_t nameLen = 64;
190
186
        std::array<unsigned int, 10> cdValues{};
191
186
        std::array<char, 64> name{};
192
186
        unsigned int filterConfig = 0;
193
194
186
        const auto filter = h5pList.getFilter(i, flags, cdNelmts,
195
186
            cdValues.data(), nameLen, name.data(), filterConfig);
196
186
        if (filter == H5Z_FILTER_DEFLATE && cdNelmts >= 1)
197
166
            return static_cast<int>(cdValues.front());
198
186
    }
199
200
52
    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
71
{
214
71
    return std::accumulate(cbegin(definition), cend(definition), 0ULL,
215
1.04k
        [](size_t sum, const auto& field) {
216
1.04k
            return sum + Layer::getElementSize(static_cast<DataType>(field.type));
217
1.04k
        });
218
71
}
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
510
{
267
510
    static ::H5::StrType strType{::H5::PredType::C_S1, H5T_VARIABLE};
268
269
510
    switch(type)
270
510
    {
271
35
    case DT_UINT32:
272
35
        return H5::PredType::NATIVE_UINT32;
273
173
    case DT_FLOAT32:
274
173
        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
115
    case DT_BOOLEAN:
282
115
        return ::H5::PredType::NATIVE_HBOOL;
283
187
    case DT_STRING:
284
187
        return strType;
285
0
    case DT_COMPOUND:  //[fallthrough]
286
0
    case DT_UNKNOWN_DATA_TYPE:  //[fallthrough]
287
0
    default:
288
0
        throw UnsupportedDataType{};
289
510
    }
290
510
}
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