• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmc-dev / openmc / 22231282333

20 Feb 2026 04:04PM UTC coverage: 81.861% (-0.2%) from 82.058%
22231282333

Pull #2693

github

web-flow
Merge e5188d202 into 53ce1910f
Pull Request #2693: Add reactivity control to coupled transport-depletion analyses

17278 of 24307 branches covered (71.08%)

Branch coverage included in aggregate %.

75 of 80 new or added lines in 4 files covered. (93.75%)

3462 existing lines in 80 files now uncovered.

57630 of 67199 relevant lines covered (85.76%)

49119197.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.24
/include/openmc/hdf5_interface.h
1
#ifndef OPENMC_HDF5_INTERFACE_H
2
#define OPENMC_HDF5_INTERFACE_H
3

4
#include <algorithm> // for min
5
#include <complex>
6
#include <cstddef>
7
#include <cstring> // for strlen
8
#include <sstream>
9
#include <string>
10
#include <type_traits>
11

12
#include "hdf5.h"
13
#include "hdf5_hl.h"
14
#include "openmc/tensor.h"
15

16
#include "openmc/array.h"
17
#include "openmc/error.h"
18
#include "openmc/position.h"
19
#include "openmc/vector.h"
20

21
namespace openmc {
22

23
//==============================================================================
24
// Low-level internal functions
25
//==============================================================================
26

27
void read_attr(hid_t obj_id, const char* name, hid_t mem_type_id, void* buffer);
28

29
void write_attr(hid_t obj_id, int ndim, const hsize_t* dims, const char* name,
30
  hid_t mem_type_id, const void* buffer);
31

32
void read_dataset_lowlevel(hid_t obj_id, const char* name, hid_t mem_type_id,
33
  hid_t mem_space_id, bool indep, void* buffer);
34

35
void write_dataset_lowlevel(hid_t group_id, int ndim, const hsize_t* dims,
36
  const char* name, hid_t mem_type_id, hid_t mem_space_id, bool indep,
37
  const void* buffer);
38

39
bool using_mpio_device(hid_t obj_id);
40

41
//==============================================================================
42
// Normal functions that are used to read/write files
43
//==============================================================================
44

45
hid_t create_group(hid_t parent_id, const std::string& name);
46

47
inline hid_t create_group(hid_t parent_id, const std::stringstream& name)
48
{
49
  return create_group(parent_id, name.str());
50
}
51

52
hid_t file_open(const std::string& filename, char mode, bool parallel = false);
53
hid_t open_group(hid_t group_id, const std::string& name);
54
void write_string(
55
  hid_t group_id, const char* name, const std::string& buffer, bool indep);
56

57
vector<hsize_t> attribute_shape(hid_t obj_id, const char* name);
58
vector<std::string> dataset_names(hid_t group_id);
59
void ensure_exists(hid_t obj_id, const char* name, bool attribute = false);
60
vector<std::string> group_names(hid_t group_id);
61
vector<hsize_t> object_shape(hid_t obj_id);
62
std::string object_name(hid_t obj_id);
63
hid_t open_object(hid_t group_id, const std::string& name);
64
void close_object(hid_t obj_id);
65

66
//==============================================================================
67
// Fortran compatibility functions
68
//==============================================================================
69

70
extern "C" {
71
bool attribute_exists(hid_t obj_id, const char* name);
72
size_t attribute_typesize(hid_t obj_id, const char* name);
73
hid_t create_group(hid_t parent_id, const char* name);
74
void close_dataset(hid_t dataset_id);
75
void close_group(hid_t group_id);
76
int dataset_ndims(hid_t dset);
77
size_t dataset_typesize(hid_t obj_id, const char* name);
78
hid_t file_open(const char* filename, char mode, bool parallel);
79
void file_close(hid_t file_id);
80
void get_name(hid_t obj_id, std::string& name);
81
int get_num_datasets(hid_t group_id);
82
int get_num_groups(hid_t group_id);
83
void get_datasets(hid_t group_id, char* name[]);
84
void get_groups(hid_t group_id, char* name[]);
85
void get_shape(hid_t obj_id, hsize_t* dims);
86
void get_shape_attr(hid_t obj_id, const char* name, hsize_t* dims);
87
bool object_exists(hid_t object_id, const char* name);
88
hid_t open_dataset(hid_t group_id, const char* name);
89
hid_t open_group(hid_t group_id, const char* name);
90
void read_attr_double(hid_t obj_id, const char* name, double* buffer);
91
void read_attr_int(hid_t obj_id, const char* name, int* buffer);
92
void read_attr_string(
93
  hid_t obj_id, const char* name, size_t slen, char* buffer);
94
void read_complex(
95
  hid_t obj_id, const char* name, std::complex<double>* buffer, bool indep);
96
void read_double(hid_t obj_id, const char* name, double* buffer, bool indep);
97
void read_int(hid_t obj_id, const char* name, int* buffer, bool indep);
98
void read_llong(hid_t obj_id, const char* name, long long* buffer, bool indep);
99
void read_string(
100
  hid_t obj_id, const char* name, size_t slen, char* buffer, bool indep);
101

102
void read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score,
103
  hsize_t n_results, double* results);
104
void write_attr_double(hid_t obj_id, int ndim, const hsize_t* dims,
105
  const char* name, const double* buffer);
106
void write_attr_int(hid_t obj_id, int ndim, const hsize_t* dims,
107
  const char* name, const int* buffer);
108
void write_attr_string(hid_t obj_id, const char* name, const char* buffer);
109
void write_double(hid_t group_id, int ndim, const hsize_t* dims,
110
  const char* name, const double* buffer, bool indep);
111
void write_int(hid_t group_id, int ndim, const hsize_t* dims, const char* name,
112
  const int* buffer, bool indep);
113
void write_llong(hid_t group_id, int ndim, const hsize_t* dims,
114
  const char* name, const long long* buffer, bool indep);
115
void write_string(hid_t group_id, int ndim, const hsize_t* dims, size_t slen,
116
  const char* name, const char* buffer, bool indep);
117
void write_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score,
118
  hsize_t n_results, const double* results);
119
} // extern "C"
120

121
//==============================================================================
122
// Template struct used to map types to HDF5 datatype IDs, which are stored
123
// using the type hid_t. By having a single static data member, the template can
124
// be specialized for each type we know of. The specializations appear in the
125
// .cpp file since they are definitions.
126
//==============================================================================
127

128
template<typename T>
129
struct H5TypeMap {
130
  static const hid_t type_id;
131
};
132

133
//==============================================================================
134
// Templates/overloads for read_attribute
135
//==============================================================================
136

137
// Scalar version
138
template<typename T>
139
void read_attribute(hid_t obj_id, const char* name, T& buffer)
17,183,498✔
140
{
141
  read_attr(obj_id, name, H5TypeMap<T>::type_id, &buffer);
17,183,498✔
142
}
17,183,498✔
143

144
// array version
145
template<typename T, std::size_t N>
146
inline void read_attribute(hid_t obj_id, const char* name, array<T, N>& buffer)
2,507✔
147
{
148
  read_attr(obj_id, name, H5TypeMap<T>::type_id, buffer.data());
2,507✔
149
}
2,507✔
150

151
// vector version
152
template<typename T>
153
void read_attribute(hid_t obj_id, const char* name, vector<T>& vec)
12,022,535✔
154
{
155
  // Get shape of attribute array
156
  auto shape = attribute_shape(obj_id, name);
12,022,535✔
157

158
  // Allocate new array to read data into
159
  std::size_t size = 1;
12,022,535✔
160
  for (const auto x : shape)
24,045,070✔
161
    size *= x;
12,022,535✔
162
  vec.resize(size);
12,022,535✔
163

164
  // Read data from attribute
165
  read_attr(obj_id, name, H5TypeMap<T>::type_id, vec.data());
12,022,535✔
166
}
12,022,535✔
167

168
// Tensor version
169
template<typename T>
170
void read_attribute(hid_t obj_id, const char* name, tensor::Tensor<T>& tensor)
396,487✔
171
{
172
  // Get shape of attribute
173
  auto shape = attribute_shape(obj_id, name);
396,487✔
174

175
  // Resize tensor and read data directly
176
  vector<size_t> tshape(shape.begin(), shape.end());
396,487✔
177
  tensor.resize(tshape);
396,487✔
178

179
  // Read data from attribute
180
  read_attr(obj_id, name, H5TypeMap<T>::type_id, tensor.data());
396,487✔
181
}
396,487✔
182

183
// overload for std::string
184
inline void read_attribute(hid_t obj_id, const char* name, std::string& str)
15,622,453✔
185
{
186
  // Create buffer to read data into
187
  auto n = attribute_typesize(obj_id, name);
15,622,453✔
188
  char* buffer = new char[n];
15,622,453✔
189

190
  // Read attribute and set string
191
  read_attr_string(obj_id, name, n, buffer);
15,622,453✔
192
  str = std::string {buffer, n};
15,622,453✔
193
  delete[] buffer;
15,622,453!
194
}
15,622,453✔
195

196
// overload for vector<std::string>
197
inline void read_attribute(
1,809✔
198
  hid_t obj_id, const char* name, vector<std::string>& vec)
199
{
200
  auto dims = attribute_shape(obj_id, name);
1,809✔
201
  auto m = dims[0];
1,809✔
202

203
  // Allocate a C char array to get strings
204
  auto n = attribute_typesize(obj_id, name);
1,809✔
205
  char* buffer = new char[m * n];
1,809✔
206

207
  // Read char data in attribute
208
  read_attr_string(obj_id, name, n, buffer);
1,809✔
209

210
  for (decltype(m) i = 0; i < m; ++i) {
7,982✔
211
    // Determine proper length of string -- strlen doesn't work because
212
    // buffer[i] might not have any null characters
213
    std::size_t k = 0;
6,173✔
214
    for (; k < n; ++k)
18,263✔
215
      if (buffer[i * n + k] == '\0')
12,678✔
216
        break;
588✔
217

218
    // Create string based on (char*, size_t) constructor
219
    vec.emplace_back(&buffer[i * n], k);
6,173✔
220
  }
221
  delete[] buffer;
1,809!
222
}
1,809✔
223

224
//==============================================================================
225
// Templates/overloads for read_dataset and related methods
226
//==============================================================================
227

228
// Template for scalars. We need to be careful that the compiler does not use
229
// this version of read_dataset for vectors, arrays, or other non-scalar types.
230
// enable_if_t allows us to conditionally remove the function from overload
231
// resolution when the type T doesn't meet a certain criterion.
232
template<typename T>
233
inline std::enable_if_t<std::is_scalar<std::decay_t<T>>::value> read_dataset(
62,251✔
234
  hid_t obj_id, const char* name, T& buffer, bool indep = false)
235
{
236
  read_dataset_lowlevel(
62,251✔
237
    obj_id, name, H5TypeMap<T>::type_id, H5S_ALL, indep, &buffer);
238
}
62,251✔
239

240
// overload for std::string
241
inline void read_dataset(
156✔
242
  hid_t obj_id, const char* name, std::string& str, bool indep = false)
243
{
244
  // Create buffer to read data into
245
  auto n = dataset_typesize(obj_id, name);
156✔
246
  std::vector<std::string::value_type> buffer(n, '\0');
156✔
247

248
  // Read attribute and set string
249
  read_string(obj_id, name, n, buffer.data(), indep);
156✔
250
  str = std::string {buffer.begin(), buffer.end()};
156✔
251
}
156✔
252

253
// array version
254
template<typename T, std::size_t N>
255
inline void read_dataset(
80✔
256
  hid_t dset, const char* name, array<T, N>& buffer, bool indep = false)
257
{
258
  read_dataset_lowlevel(
80✔
259
    dset, name, H5TypeMap<T>::type_id, H5S_ALL, indep, buffer.data());
80✔
260
}
80✔
261

262
// vector version
263
template<typename T>
264
void read_dataset(hid_t dset, vector<T>& vec, bool indep = false)
5,213,377✔
265
{
266
  // Get shape of dataset
267
  vector<hsize_t> shape = object_shape(dset);
5,213,377✔
268

269
  // Resize vector to appropriate size
270
  vec.resize(shape[0]);
5,213,377✔
271

272
  // Read data into vector
273
  read_dataset_lowlevel(
5,213,377✔
274
    dset, nullptr, H5TypeMap<T>::type_id, H5S_ALL, indep, vec.data());
5,213,377✔
275
}
5,213,377✔
276

277
template<typename T>
278
void read_dataset(
2,922,818✔
279
  hid_t obj_id, const char* name, vector<T>& vec, bool indep = false)
280
{
281
  hid_t dset = open_dataset(obj_id, name);
2,922,818✔
282
  read_dataset(dset, vec, indep);
2,922,818✔
283
  close_dataset(dset);
2,922,818✔
284
}
2,922,818✔
285

286
template<typename T>
287
void read_dataset(hid_t dset, tensor::Tensor<T>& tensor, bool indep = false)
5,878,185✔
288
{
289
  // Get shape of dataset
290
  vector<hsize_t> shape = object_shape(dset);
5,878,185✔
291

292
  // Resize tensor and read data directly
293
  vector<size_t> tshape(shape.begin(), shape.end());
5,878,185✔
294
  tensor.resize(tshape);
5,878,185✔
295

296
  // Read data from dataset
297
  read_dataset_lowlevel(
5,878,185✔
298
    dset, nullptr, H5TypeMap<T>::type_id, H5S_ALL, indep, tensor.data());
5,878,185✔
299
}
5,878,185✔
300

301
template<>
302
void read_dataset(
303
  hid_t dset, tensor::Tensor<std::complex<double>>& tensor, bool indep);
304

305
template<typename T>
306
void read_dataset(
81,467✔
307
  hid_t obj_id, const char* name, tensor::Tensor<T>& tensor, bool indep = false)
308
{
309
  // Open dataset and read tensor
310
  hid_t dset = open_dataset(obj_id, name);
81,467✔
311
  read_dataset(dset, tensor, indep);
81,467✔
312
  close_dataset(dset);
81,467✔
313
}
81,467✔
314

315
// overload for Position
316
inline void read_dataset(
80✔
317
  hid_t obj_id, const char* name, Position& r, bool indep = false)
318
{
319
  array<double, 3> x;
320
  read_dataset(obj_id, name, x, indep);
80✔
321
  r.x = x[0];
80✔
322
  r.y = x[1];
80✔
323
  r.z = x[2];
80✔
324
}
80✔
325

326
template<typename T>
327
inline void read_dataset_as_shape(
19,492✔
328
  hid_t obj_id, const char* name, tensor::Tensor<T>& tensor, bool indep = false)
329
{
330
  hid_t dset = open_dataset(obj_id, name);
19,492✔
331

332
  // Read data directly into pre-shaped tensor
333
  read_dataset_lowlevel(
19,492✔
334
    dset, nullptr, H5TypeMap<T>::type_id, H5S_ALL, indep, tensor.data());
19,492✔
335

336
  close_dataset(dset);
19,492✔
337
}
19,492✔
338

339
template<typename T>
340
inline void read_nd_tensor(hid_t obj_id, const char* name,
27,236✔
341
  tensor::Tensor<T>& result, bool must_have = false)
342
{
343
  if (object_exists(obj_id, name)) {
27,236✔
344
    read_dataset_as_shape(obj_id, name, result, true);
19,492✔
345
  } else if (must_have) {
7,744!
UNCOV
346
    fatal_error(std::string("Must provide " + std::string(name) + "!"));
×
347
  }
348
}
27,236✔
349

350
//==============================================================================
351
// Templates/overloads for write_attribute
352
//==============================================================================
353

354
template<typename T>
355
inline void write_attribute(hid_t obj_id, const char* name, T buffer)
156,107✔
356
{
357
  write_attr(obj_id, 0, nullptr, name, H5TypeMap<T>::type_id, &buffer);
156,107✔
358
}
156,107✔
359

360
inline void write_attribute(hid_t obj_id, const char* name, const char* buffer)
15,413✔
361
{
362
  write_attr_string(obj_id, name, buffer);
15,413✔
363
}
15,413✔
364

365
inline void write_attribute(
19,940✔
366
  hid_t obj_id, const char* name, const std::string& buffer)
367
{
368
  write_attr_string(obj_id, name, buffer.c_str());
19,940✔
369
}
19,940✔
370

371
template<typename T, std::size_t N>
372
inline void write_attribute(
29,200✔
373
  hid_t obj_id, const char* name, const array<T, N>& buffer)
374
{
375
  hsize_t dims[] {N};
29,200✔
376
  write_attr(obj_id, 1, dims, name, H5TypeMap<T>::type_id, buffer.data());
29,200✔
377
}
29,200✔
378

379
template<typename T>
380
inline void write_attribute(
13,282✔
381
  hid_t obj_id, const char* name, const vector<T>& buffer)
382
{
383
  hsize_t dims[] {buffer.size()};
13,282✔
384
  write_attr(obj_id, 1, dims, name, H5TypeMap<T>::type_id, buffer.data());
13,282✔
385
}
13,282✔
386

387
inline void write_attribute(hid_t obj_id, const char* name, Position r)
460✔
388
{
389
  array<double, 3> buffer {r.x, r.y, r.z};
460✔
390
  write_attribute(obj_id, name, buffer);
460✔
391
}
460✔
392

393
//==============================================================================
394
// Templates/overloads for write_dataset
395
//==============================================================================
396

397
// Template for scalars (ensured by SFINAE)
398
template<typename T>
399
inline std::enable_if_t<std::is_scalar<std::decay_t<T>>::value> write_dataset(
281,359✔
400
  hid_t obj_id, const char* name, T buffer)
401
{
402
  write_dataset_lowlevel(
281,359✔
403
    obj_id, 0, nullptr, name, H5TypeMap<T>::type_id, H5S_ALL, false, &buffer);
404
}
281,359✔
405

406
inline void write_dataset(hid_t obj_id, const char* name, const char* buffer)
59,723✔
407
{
408
  write_string(obj_id, name, buffer, false);
59,723✔
409
}
59,723✔
410

411
template<typename T, std::size_t N>
412
inline void write_dataset(
44,022✔
413
  hid_t obj_id, const char* name, const array<T, N>& buffer)
414
{
415
  hsize_t dims[] {N};
44,022✔
416
  write_dataset_lowlevel(obj_id, 1, dims, name, H5TypeMap<T>::type_id, H5S_ALL,
44,022✔
417
    false, buffer.data());
44,022✔
418
}
44,022✔
419

420
inline void write_dataset(
56,963✔
421
  hid_t obj_id, const char* name, const vector<std::string>& buffer)
422
{
423
  auto n {buffer.size()};
56,963✔
424
  hsize_t dims[] {n};
56,963✔
425

426
  // Determine length of longest string, including \0
427
  size_t m = 1;
56,963✔
428
  for (const auto& s : buffer) {
178,738✔
429
    m = std::max(m, s.size() + 1);
121,775✔
430
  }
431

432
  // Copy data into contiguous buffer
433
  char* temp = new char[n * m];
56,963✔
434
  std::fill(temp, temp + n * m, '\0');
56,963✔
435
  for (decltype(n) i = 0; i < n; ++i) {
178,738✔
436
    std::copy(buffer[i].begin(), buffer[i].end(), temp + i * m);
121,775✔
437
  }
438

439
  // Write 2D data
440
  write_string(obj_id, 1, dims, m, name, temp, false);
56,963✔
441

442
  // Free temp array
443
  delete[] temp;
56,963!
444
}
56,963✔
445

446
template<typename T>
447
inline void write_dataset(
107,321✔
448
  hid_t obj_id, const char* name, const vector<T>& buffer)
449
{
450
  hsize_t dims[] {buffer.size()};
107,321✔
451
  write_dataset_lowlevel(obj_id, 1, dims, name, H5TypeMap<T>::type_id, H5S_ALL,
107,321✔
452
    false, buffer.data());
107,321✔
453
}
107,321✔
454

455
// Template for Tensor and StaticTensor2D. A SFINAE guard is used here to
456
// prevent this template from matching vector/string types that have their own
457
// overloads above. A generic Container parameter avoids duplicating the body
458
// for both Tensor<T> and StaticTensor2D<T,R,C>.
459
template<typename Container,
460
  typename =
461
    std::enable_if_t<tensor::is_tensor<std::decay_t<Container>>::value>>
462
inline void write_dataset(hid_t obj_id, const char* name, const Container& arr)
15,084✔
463
{
464
  using T = typename std::decay_t<Container>::value_type;
465
  auto s = arr.shape();
15,084✔
466
  vector<hsize_t> dims {s.cbegin(), s.cend()};
15,084✔
467
  write_dataset_lowlevel(obj_id, dims.size(), dims.data(), name,
15,084✔
468
    H5TypeMap<T>::type_id, H5S_ALL, false, arr.data());
15,084✔
469
}
15,084✔
470

471
inline void write_dataset(hid_t obj_id, const char* name, Position r)
3,716✔
472
{
473
  array<double, 3> buffer {r.x, r.y, r.z};
3,716✔
474
  write_dataset(obj_id, name, buffer);
3,716✔
475
}
3,716✔
476

477
inline void write_dataset(hid_t obj_id, const char* name, std::string buffer)
48,417✔
478
{
479
  write_string(obj_id, name, buffer.c_str(), false);
48,417✔
480
}
48,417✔
481

482
} // namespace openmc
483
#endif // OPENMC_HDF5_INTERFACE_H
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc