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

openmc-dev / openmc / 30834488152

03 Aug 2026 04:56PM UTC coverage: 81.269% (-0.2%) from 81.425%
30834488152

Pull #4042

github

web-flow
Merge a5707c2ce into 8202ef6fb
Pull Request #4042: Set all tally estimators to collision in RR simulations

18530 of 26845 branches covered (69.03%)

Branch coverage included in aggregate %.

2 of 2 new or added lines in 1 file covered. (100.0%)

196 existing lines in 2 files now uncovered.

60319 of 70177 relevant lines covered (85.95%)

49926763.46 hits per line

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

53.42
/src/dagmc.cpp
1
#include "openmc/dagmc.h"
2

3
#include <array>
4
#include <cassert>
5

6
#include "openmc/constants.h"
7
#include "openmc/container_util.h"
8
#include "openmc/error.h"
9
#include "openmc/file_utils.h"
10
#include "openmc/geometry.h"
11
#include "openmc/geometry_aux.h"
12
#include "openmc/hdf5_interface.h"
13
#include "openmc/material.h"
14
#include "openmc/settings.h"
15
#include "openmc/string_utils.h"
16

17
#ifdef OPENMC_UWUW_ENABLED
18
#include "uwuw.hpp"
19
#endif
20
#include <fmt/core.h>
21

22
#include <algorithm>
23
#include <filesystem>
24
#include <fstream>
25
#include <sstream>
26
#include <string>
27

28
namespace openmc {
29

30
#ifdef OPENMC_DAGMC_ENABLED
31
const bool DAGMC_ENABLED = true;
32
#else
33
const bool DAGMC_ENABLED = false;
34
#endif
35

36
#ifdef OPENMC_UWUW_ENABLED
37
const bool UWUW_ENABLED = true;
38
#else
39
const bool UWUW_ENABLED = false;
40
#endif
41

42
} // namespace openmc
43

44
#ifdef OPENMC_DAGMC_ENABLED
45

46
namespace openmc {
47

48
//==============================================================================
49
// DAGMC Universe implementation
50
//==============================================================================
51

52
DAGUniverse::DAGUniverse(pugi::xml_node node)
46✔
53
{
54
  MaterialOverrides material_overrides;
46✔
55
  TemperatureOverrides temperature_overrides;
46✔
56
  DensityOverrides density_overrides;
46✔
57

58
  if (check_for_node(node, "id")) {
46!
59
    id_ = std::stoi(get_node_value(node, "id"));
92✔
60
  } else {
UNCOV
61
    fatal_error("Must specify the id of the DAGMC universe");
×
62
  }
63

64
  if (check_for_node(node, "filename")) {
46!
65
    filename_ = get_node_value(node, "filename");
46✔
66
    if (!starts_with(filename_, "/")) {
46✔
67
      std::filesystem::path d(dir_name(settings::path_input));
23✔
68
      filename_ = (d / filename_).string();
69✔
69
    }
23✔
70
  } else {
UNCOV
71
    fatal_error("Must specify a file for the DAGMC universe");
×
72
  }
73

74
  adjust_geometry_ids_ = false;
46✔
75
  if (check_for_node(node, "auto_geom_ids")) {
46✔
76
    adjust_geometry_ids_ = get_node_value_bool(node, "auto_geom_ids");
17✔
77
  }
78

79
  adjust_material_ids_ = false;
46✔
80
  if (check_for_node(node, "auto_mat_ids")) {
46!
UNCOV
81
    adjust_material_ids_ = get_node_value_bool(node, "auto_mat_ids");
×
82
  }
83

84
  if (check_for_node(node, "length_multiplier")) {
46✔
85
    length_multiplier_ = std::stod(get_node_value(node, "length_multiplier"));
4✔
86
  }
87

88
  // Get material assignment overrides from nested DAGMC cell elements.
89
  if (node.child("cell")) {
46✔
90
    for (pugi::xml_node cell_node : node.children("cell")) {
12✔
91
      if (!check_for_node(cell_node, "id")) {
9!
UNCOV
92
        fatal_error(
×
93
          "Must specify id for each DAGMC cell override in <dagmc_universe>.");
94
      }
95

96
      int32_t cell_id = std::stoi(get_node_value(cell_node, "id"));
18✔
97

98
      if (check_for_node(cell_node, "region")) {
9!
UNCOV
99
        fatal_error(fmt::format(
×
100
          "DAGMC cell {} override cannot specify a region.", cell_id));
101
      }
102
      if (check_for_node(cell_node, "fill")) {
9!
UNCOV
103
        fatal_error(fmt::format(
×
104
          "DAGMC cell {} override currently only supports material fills.",
105
          cell_id));
106
      }
107
      if (check_for_node(cell_node, "universe")) {
9!
UNCOV
108
        fatal_error(fmt::format(
×
109
          "DAGMC cell {} override cannot specify a universe.", cell_id));
110
      }
111
      if (check_for_node(cell_node, "translation") ||
18!
112
          check_for_node(cell_node, "rotation")) {
9✔
UNCOV
113
        fatal_error(fmt::format(
×
114
          "DAGMC cell {} override does not support translation or rotation.",
115
          cell_id));
116
      }
117
      if (!check_for_node(cell_node, "material")) {
9!
UNCOV
118
        fatal_error(fmt::format(
×
119
          "DAGMC cell {} override must specify material.", cell_id));
120
      }
121

122
      auto inserted = material_overrides.emplace(
9✔
123
        cell_id, parse_cell_material_xml(cell_node, cell_id));
9✔
124
      if (!inserted.second) {
9!
UNCOV
125
        fatal_error(fmt::format(
×
126
          "Duplicate DAGMC cell override specified for cell {}", cell_id));
127
      }
128

129
      if (check_for_node(cell_node, "temperature")) {
9!
UNCOV
130
        temperature_overrides.emplace(
×
UNCOV
131
          cell_id, parse_cell_temperature_xml(cell_node, cell_id));
×
132
      }
133

134
      if (check_for_node(cell_node, "density")) {
9!
UNCOV
135
        density_overrides.emplace(
×
UNCOV
136
          cell_id, parse_cell_density_xml(cell_node, cell_id));
×
137
      }
138
    }
139
  } else if (check_for_node(node, "material_overrides")) {
43!
UNCOV
140
    if (node.child("cell")) {
×
UNCOV
141
      fatal_error("DAGMCUniverse cannot specify both <material_overrides> and "
×
142
                  "<cell> sub-elements. Use <cell> elements only.");
143
    }
UNCOV
144
    warning("DAGMCUniverse <material_overrides> is deprecated. Use nested "
×
145
            "<cell> elements under <dagmc_universe> instead.");
UNCOV
146
    for (pugi::xml_node co :
×
UNCOV
147
      node.child("material_overrides").children("cell_override")) {
×
UNCOV
148
      int32_t cell_id = std::stoi(get_node_value(co, "id"));
×
UNCOV
149
      std::istringstream iss(co.child("material_ids").text().get());
×
UNCOV
150
      vector<int32_t> mats;
×
UNCOV
151
      for (std::string s; iss >> s;) {
×
UNCOV
152
        mats.push_back(s == "void" ? MATERIAL_VOID : std::stoi(s));
×
UNCOV
153
      }
×
UNCOV
154
      material_overrides.emplace(cell_id, mats);
×
UNCOV
155
    }
×
156
  }
157

158
  initialize(material_overrides, temperature_overrides, density_overrides);
46✔
159
}
132!
160

UNCOV
161
DAGUniverse::DAGUniverse(const std::string& filename, bool auto_geom_ids,
×
UNCOV
162
  bool auto_mat_ids, double length_multiplier)
×
UNCOV
163
  : filename_(filename), adjust_geometry_ids_(auto_geom_ids),
×
UNCOV
164
    adjust_material_ids_(auto_mat_ids), length_multiplier_(length_multiplier)
×
165
{
UNCOV
166
  set_id();
×
UNCOV
167
  initialize();
×
UNCOV
168
}
×
169

170
DAGUniverse::DAGUniverse(std::shared_ptr<moab::DagMC> dagmc_ptr,
2✔
171
  const std::string& filename, bool auto_geom_ids, bool auto_mat_ids,
172
  double length_multiplier)
2✔
173
  : dagmc_instance_(dagmc_ptr), filename_(filename),
4!
174
    adjust_geometry_ids_(auto_geom_ids), adjust_material_ids_(auto_mat_ids),
2✔
175
    length_multiplier_(length_multiplier)
4!
176
{
177
  MaterialOverrides material_overrides;
2✔
178
  TemperatureOverrides temperature_overrides;
2✔
179
  DensityOverrides density_overrides;
2✔
180
  set_id();
2✔
181
  init_metadata();
2✔
182
  init_geometry(material_overrides, temperature_overrides, density_overrides);
2✔
183
}
6!
184

185
void DAGUniverse::set_id()
2✔
186
{
187
  // determine the next universe id
188
  int32_t next_univ_id = 0;
2✔
189
  for (const auto& u : model::universes) {
2!
UNCOV
190
    if (u->id_ > next_univ_id)
×
191
      next_univ_id = u->id_;
192
  }
193
  next_univ_id++;
2✔
194

195
  // set the universe id
196
  id_ = next_univ_id;
2✔
197
}
2✔
198

UNCOV
199
void DAGUniverse::initialize()
×
200
{
UNCOV
201
  MaterialOverrides material_overrides;
×
UNCOV
202
  TemperatureOverrides temperature_overrides;
×
UNCOV
203
  initialize(material_overrides, temperature_overrides);
×
UNCOV
204
}
×
205

206
void DAGUniverse::initialize(const MaterialOverrides& material_overrides,
46✔
207
  const TemperatureOverrides& temperature_overrides,
208
  const DensityOverrides& density_overrides)
209
{
210
#ifdef OPENMC_UWUW_ENABLED
211
  // read uwuw materials from the .h5m file if present
212
  read_uwuw_materials();
46✔
213
#endif
214

215
  init_dagmc();
46✔
216

217
  init_metadata();
46✔
218

219
  init_geometry(material_overrides, temperature_overrides, density_overrides);
46✔
220
}
44✔
221

222
void DAGUniverse::init_dagmc()
46✔
223
{
224

225
  // create a new DAGMC instance
226
  dagmc_instance_ = std::make_shared<moab::DagMC>();
46!
227

228
  // load the DAGMC geometry
229
  if (!file_exists(filename_)) {
46!
UNCOV
230
    fatal_error("Geometry DAGMC file '" + filename_ + "' does not exist!");
×
231
  }
232
  moab::ErrorCode rval = dagmc_instance_->load_file(filename_.c_str());
46✔
233
  MB_CHK_ERR_CONT(rval);
46!
234

235
  if (length_multiplier_ != 1.0) {
46✔
236
    moab::Range verts;
2✔
237
    rval =
2✔
238
      dagmc_instance_->moab_instance()->get_entities_by_dimension(0, 0, verts);
2✔
239
    MB_CHK_ERR_CONT(rval);
2!
240

241
    for (auto vert : verts) {
1,284✔
242
      std::array<double, 3> coord;
1,280✔
243
      rval =
1,280✔
244
        dagmc_instance_->moab_instance()->get_coords(&vert, 1, coord.data());
1,280✔
245
      MB_CHK_ERR_CONT(rval);
1,280!
246

247
      for (auto& c : coord) {
5,120✔
248
        c *= length_multiplier_;
3,840✔
249
      }
250

251
      rval =
1,280✔
252
        dagmc_instance_->moab_instance()->set_coords(&vert, 1, coord.data());
1,280✔
253
      MB_CHK_ERR_CONT(rval);
1,280!
254
    }
255
  }
2✔
256

257
  // initialize acceleration data structures
258
  rval = dagmc_instance_->init_OBBTree();
46✔
259
  MB_CHK_ERR_CONT(rval);
46!
260
}
46✔
261

262
void DAGUniverse::init_metadata()
48✔
263
{
264
  // parse model metadata
265
  dmd_ptr =
48✔
266
    std::make_unique<dagmcMetaData>(dagmc_instance_.get(), false, false);
48✔
267
  dmd_ptr->load_property_data();
48✔
268

269
  std::vector<std::string> keywords {"temp"};
96!
270
  std::map<std::string, std::string> dum;
48✔
271
  std::string delimiters = ":/";
48✔
272
  moab::ErrorCode rval;
48✔
273
  rval = dagmc_instance_->parse_properties(keywords, dum, delimiters.c_str());
48✔
274
  MB_CHK_ERR_CONT(rval);
48!
275
}
48✔
276

277
void DAGUniverse::init_geometry(const MaterialOverrides& material_overrides,
48✔
278
  const TemperatureOverrides& temperature_overrides,
279
  const DensityOverrides& density_overrides)
280
{
281
  moab::ErrorCode rval;
48✔
282

283
  // determine the next cell id
284
  int32_t next_cell_id = 0;
48✔
285
  for (const auto& c : model::cells) {
74✔
286
    if (c->id_ > next_cell_id)
26✔
287
      next_cell_id = c->id_;
288
  }
289
  cell_idx_offset_ = model::cells.size();
48✔
290
  next_cell_id++;
48✔
291

292
  // initialize cell objects
293
  int n_cells = dagmc_instance_->num_entities(3);
48✔
294
  moab::EntityHandle graveyard = 0;
48✔
295
  for (int i = 0; i < n_cells; i++) {
257✔
296
    moab::EntityHandle vol_handle = dagmc_instance_->entity_by_index(3, i + 1);
211✔
297

298
    // set cell ids using global IDs
299
    auto c = std::make_unique<DAGCell>(dagmc_instance_, i + 1);
211✔
300
    c->id_ = adjust_geometry_ids_
211✔
301
               ? next_cell_id++
211✔
302
               : dagmc_instance_->id_by_index(3, c->dag_index());
139✔
303
    c->universe_ = this->id_;
211✔
304
    c->fill_ = C_NONE; // no fill, single universe
211✔
305
    if (dagmc_instance_->is_implicit_complement(vol_handle)) {
211✔
306
      c->name_ = "implicit complement";
46✔
307
    }
308

309
    auto in_map = model::cell_map.find(c->id_);
211!
310
    if (in_map == model::cell_map.end()) {
211!
311
      model::cell_map[c->id_] = model::cells.size();
211✔
312
    } else {
UNCOV
313
      warning(fmt::format("DAGMC Cell IDs: {}", dagmc_ids_for_dim(3)));
×
UNCOV
314
      fatal_error(fmt::format(
×
315
        "DAGMC Universe {} contains a cell with ID {}, which "
316
        "already exists elsewhere in the geometry. Setting auto_geom_ids "
317
        "to True when initiating the DAGMC Universe may "
318
        "resolve this issue",
UNCOV
319
        this->id_, c->id_));
×
320
    }
321

322
    // --- Materials ---
323

324
    // determine volume material assignment
325
    std::string mat_str = dmd_ptr->get_volume_property("material", vol_handle);
211✔
326

327
    if (mat_str.empty()) {
211!
UNCOV
328
      fatal_error(fmt::format("Volume {} has no material assignment.", c->id_));
×
329
    }
330

331
    to_lower(mat_str);
211✔
332

333
    if (mat_str == "graveyard") {
211✔
334
      graveyard = vol_handle;
37✔
335
    }
336
    if (material_overrides.count(c->id_)) {
211✔
337
      override_assign_material(c, material_overrides);
9✔
338
    } else if (mat_str == "void" || mat_str == "vacuum" ||
403✔
339
               mat_str == "graveyard") {
158✔
340
      c->material_.push_back(MATERIAL_VOID);
80✔
341
    } else if (uses_uwuw()) {
122✔
342
      uwuw_assign_material(vol_handle, c);
12✔
343
    } else {
344
      legacy_assign_material(mat_str, c);
218✔
345
    }
346

347
    if (temperature_overrides.count(c->id_)) {
209!
UNCOV
348
      if (c->material_.empty() || c->material_[0] == MATERIAL_VOID) {
×
UNCOV
349
        fatal_error(fmt::format("DAGMC cell {} was specified with a "
×
350
                                "temperature but no non-void material.",
UNCOV
351
          c->id_));
×
352
      }
353

UNCOV
354
      c->sqrtkT_.clear();
×
UNCOV
355
      const auto& temp_overrides = temperature_overrides.at(c->id_);
×
UNCOV
356
      c->sqrtkT_.reserve(temp_overrides.size());
×
UNCOV
357
      for (auto T : temp_overrides) {
×
UNCOV
358
        c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * T));
×
359
      }
360

UNCOV
361
      if (settings::verbosity >= 10) {
×
UNCOV
362
        std::stringstream override_values;
×
UNCOV
363
        for (size_t i = 0; i < temp_overrides.size(); ++i) {
×
UNCOV
364
          if (i > 0) {
×
UNCOV
365
            override_values << " ";
×
366
          }
UNCOV
367
          override_values << temp_overrides[i];
×
368
        }
UNCOV
369
        auto msg = fmt::format("Overriding DAGMC cell {} property "
×
370
                               "'temperature [K]' with value(s): {}",
UNCOV
371
          c->id_, override_values.str());
×
UNCOV
372
        write_message(msg, 10);
×
UNCOV
373
      }
×
374
    }
375

376
    if (density_overrides.count(c->id_)) {
209!
UNCOV
377
      if (c->material_.empty() || c->material_[0] == MATERIAL_VOID) {
×
UNCOV
378
        fatal_error(fmt::format("DAGMC cell {} was specified with a density "
×
379
                                "but no non-void material.",
UNCOV
380
          c->id_));
×
381
      }
382
      // density_mult_ holds the true density until materials are finalized,
383
      // at which point it is converted to a proper multiplier (same as CSG).
UNCOV
384
      c->density_mult_ = density_overrides.at(c->id_);
×
385

UNCOV
386
      if (settings::verbosity >= 10) {
×
UNCOV
387
        const auto& dens = density_overrides.at(c->id_);
×
UNCOV
388
        std::stringstream override_values;
×
UNCOV
389
        for (size_t i = 0; i < dens.size(); ++i) {
×
UNCOV
390
          if (i > 0)
×
UNCOV
391
            override_values << " ";
×
UNCOV
392
          override_values << dens[i];
×
393
        }
UNCOV
394
        write_message(fmt::format("Overriding DAGMC cell {} property "
×
395
                                  "'density [g/cm³]' with value(s): {}",
UNCOV
396
                        c->id_, override_values.str()),
×
397
          10);
UNCOV
398
      }
×
399
    }
400

401
    // check for temperature assignment
402
    std::string temp_value;
209✔
403

404
    // no temperature if void
405
    if (c->material_[0] == MATERIAL_VOID) {
209✔
406
      model::cells.emplace_back(std::move(c));
84✔
407
      continue;
84✔
408
    }
409

410
    // assign cell temperature if not explicitly overridden
411
    if (c->sqrtkT_.empty()) {
125!
412
      const auto& mat =
125✔
413
        model::materials[model::material_map.at(c->material_[0])];
125✔
414
      if (dagmc_instance_->has_prop(vol_handle, "temp")) {
125✔
415
        rval = dagmc_instance_->prop_value(vol_handle, "temp", temp_value);
46✔
416
        MB_CHK_ERR_CONT(rval);
46!
417
        double temp = std::stod(temp_value);
46✔
418
        c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * temp));
46✔
419
      } else if (mat->temperature() > 0.0) {
79!
420
        c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * mat->temperature()));
79✔
421
      } else {
UNCOV
422
        c->sqrtkT_.push_back(
×
UNCOV
423
          std::sqrt(K_BOLTZMANN * settings::temperature_default));
×
424
      }
425
    }
426

427
    model::cells.emplace_back(std::move(c));
125✔
428
  }
209✔
429

430
  // allocate the cell overlap count if necessary
431
  if (settings::check_overlaps) {
46!
UNCOV
432
    model::overlap_check_count.resize(model::cells.size(), 0);
×
433
  }
434

435
  has_graveyard_ = graveyard;
46✔
436

437
  // determine the next surface id
438
  int32_t next_surf_id = 0;
46✔
439
  for (const auto& s : model::surfaces) {
192✔
440
    if (s->id_ > next_surf_id)
146✔
441
      next_surf_id = s->id_;
442
  }
443
  surf_idx_offset_ = model::surfaces.size();
46✔
444
  next_surf_id++;
46✔
445

446
  // initialize surface objects
447
  int n_surfaces = dagmc_instance_->num_entities(2);
46✔
448
  for (int i = 0; i < n_surfaces; i++) {
876✔
449
    moab::EntityHandle surf_handle = dagmc_instance_->entity_by_index(2, i + 1);
830✔
450

451
    // set cell ids using global IDs
452
    auto s = std::make_unique<DAGSurface>(dagmc_instance_, i + 1);
830✔
453
    s->id_ = adjust_geometry_ids_ ? next_surf_id++
1,385✔
454
                                  : dagmc_instance_->id_by_index(2, i + 1);
555✔
455

456
    // set surface source attribute if needed
457
    if (contains(settings::source_write_surf_id, s->id_) ||
1,660✔
458
        settings::source_write_surf_id.empty()) {
826✔
459
      s->surf_source_ = true;
708✔
460
    }
461

462
    // set BCs
463
    std::string bc_value =
830✔
464
      dmd_ptr->get_surface_property("boundary", surf_handle);
830✔
465
    to_lower(bc_value);
830✔
466
    if (bc_value.empty() || bc_value == "transmit" ||
848!
467
        bc_value == "transmission") {
18!
468
      // set to transmission by default (nullptr)
469
    } else if (bc_value == "vacuum") {
18✔
470
      s->bc_ = make_unique<VacuumBC>();
6✔
471
    } else if (bc_value == "reflective" || bc_value == "reflect" ||
24!
472
               bc_value == "reflecting") {
12!
473
      s->bc_ = make_unique<ReflectiveBC>();
12✔
UNCOV
474
    } else if (bc_value == "periodic") {
×
UNCOV
475
      fatal_error("Periodic boundary condition not supported in DAGMC.");
×
476
    } else {
UNCOV
477
      fatal_error(fmt::format("Unknown boundary condition \"{}\" specified "
×
478
                              "on surface {}",
UNCOV
479
        bc_value, s->id_));
×
480
    }
481

482
    // graveyard check
483
    moab::Range parent_vols;
830✔
484
    rval = dagmc_instance_->moab_instance()->get_parent_meshsets(
830✔
485
      surf_handle, parent_vols);
486
    MB_CHK_ERR_CONT(rval);
830!
487

488
    // if this surface belongs to the graveyard
489
    if (graveyard && parent_vols.find(graveyard) != parent_vols.end()) {
1,175✔
490
      // set graveyard surface BC's to vacuum
491
      s->bc_ = make_unique<VacuumBC>();
444✔
492
    }
493

494
    // add to global array and map
495

496
    auto in_map = model::surface_map.find(s->id_);
830!
497
    if (in_map == model::surface_map.end()) {
830!
498
      model::surface_map[s->id_] = model::surfaces.size();
830✔
499
    } else {
UNCOV
500
      warning(fmt::format("DAGMC Surface IDs: {}", dagmc_ids_for_dim(2)));
×
UNCOV
501
      fatal_error(fmt::format("Surface ID {} exists in both Universe {} "
×
502
                              "and the CSG geometry.",
UNCOV
503
        s->id_, this->id_));
×
504
    }
505

506
    model::surfaces.emplace_back(std::move(s));
830✔
507
  } // end surface loop
830✔
508
}
46✔
509

510
int32_t DAGUniverse::cell_index(moab::EntityHandle vol) const
46,716✔
511
{
512
  // return the index of the volume in the DAGMC instance and then
513
  // adjust by the offset into the model cells for this DAGMC universe
514
  return dagmc_ptr()->index_by_handle(vol) + cell_idx_offset_;
46,716✔
515
}
516

UNCOV
517
int32_t DAGUniverse::surface_index(moab::EntityHandle surf) const
×
518
{
519
  // return the index of the surface in the DAGMC instance and then
520
  // adjust by the offset into the model cells for this DAGMC universe
UNCOV
521
  return dagmc_ptr()->index_by_handle(surf) + surf_idx_offset_;
×
522
}
523

UNCOV
524
std::string DAGUniverse::dagmc_ids_for_dim(int dim) const
×
525
{
526
  // generate a vector of ids
UNCOV
527
  std::vector<int> id_vec;
×
UNCOV
528
  int n_ents = dagmc_instance_->num_entities(dim);
×
UNCOV
529
  for (int i = 1; i <= n_ents; i++) {
×
UNCOV
530
    id_vec.push_back(dagmc_instance_->id_by_index(dim, i));
×
531
  }
532

533
  // sort the vector of ids
UNCOV
534
  std::sort(id_vec.begin(), id_vec.end());
×
535

536
  // generate a string representation of the ID range(s)
UNCOV
537
  std::stringstream out;
×
538

UNCOV
539
  int i = 0;
×
UNCOV
540
  int start_id = id_vec[0]; // initialize with first ID
×
UNCOV
541
  int stop_id;
×
542
  // loop over all cells in the universe
UNCOV
543
  while (i < n_ents) {
×
544

UNCOV
545
    stop_id = id_vec[i];
×
546

547
    // if the next ID is not in this contiguous set of IDS,
548
    // figure out how to write the string representing this set
UNCOV
549
    if (id_vec[i + 1] > stop_id + 1) {
×
550

UNCOV
551
      if (start_id != stop_id) {
×
552
        // there are several IDs in a row, print condensed version (i.e. 1-10,
553
        // 12-20)
UNCOV
554
        out << start_id << "-" << stop_id;
×
555
      } else {
556
        // only one ID in this contiguous block (i.e. 3, 5, 7, 9)
UNCOV
557
        out << start_id;
×
558
      }
559
      // insert a comma as long as we aren't in the last ID set
UNCOV
560
      if (i < n_ents - 1) {
×
UNCOV
561
        out << ", ";
×
562
      }
563

564
      // if we are at the end of a set, set the start ID to the first value
565
      // in the next set.
UNCOV
566
      start_id = id_vec[++i];
×
567
    }
568

UNCOV
569
    i++;
×
570
  }
571

UNCOV
572
  return out.str();
×
UNCOV
573
}
×
574

575
int32_t DAGUniverse::implicit_complement_idx() const
757,702✔
576
{
577
  moab::EntityHandle ic;
757,702✔
578
  moab::ErrorCode rval =
757,702✔
579
    dagmc_instance_->geom_tool()->get_implicit_complement(ic);
1,515,404!
580
  MB_CHK_SET_ERR_CONT(rval, "Failed to get implicit complement");
757,702!
581
  // off-by-one: DAGMC indices start at one
582
  return cell_idx_offset_ + dagmc_instance_->index_by_handle(ic) - 1;
757,702✔
583
}
584

585
bool DAGUniverse::find_cell(GeometryState& p) const
7,143,655✔
586
{
587
  // if the particle isn't in any of the other DagMC
588
  // cells, place it in the implicit complement
589
  bool found = Universe::find_cell(p);
7,143,655✔
590
  if (!found && model::universe_map[this->id_] != model::root_universe) {
7,143,655!
591
    p.lowest_coord().cell() = implicit_complement_idx();
757,485✔
592
    found = true;
757,485✔
593
  }
594
  return found;
7,143,655✔
595
}
596

597
void DAGUniverse::to_hdf5(hid_t universes_group) const
35✔
598
{
599
  // Create a group for this universe.
600
  auto group = create_group(universes_group, fmt::format("universe {}", id_));
35✔
601

602
  // Write the geometry representation type.
603
  write_string(group, "geom_type", "dagmc", false);
35✔
604

605
  // Write other properties of the DAGMC Universe
606
  write_string(group, "filename", filename_, false);
35✔
607
  write_attribute(
35✔
608
    group, "auto_geom_ids", static_cast<int>(adjust_geometry_ids_));
35✔
609
  write_attribute(
35✔
610
    group, "auto_mat_ids", static_cast<int>(adjust_material_ids_));
35✔
611
  write_attribute(group, "length_multiplier", length_multiplier_);
35✔
612

613
  close_group(group);
35✔
614
}
35✔
615

616
bool DAGUniverse::uses_uwuw() const
172✔
617
{
618
#ifdef OPENMC_UWUW_ENABLED
619
  return uwuw_ && !uwuw_->material_library.empty();
172✔
620
#else
621
  return false;
622
#endif // OPENMC_UWUW_ENABLED
623
}
624

625
std::string DAGUniverse::get_uwuw_materials_xml() const
4✔
626
{
627
#ifdef OPENMC_UWUW_ENABLED
628
  if (!uses_uwuw()) {
4!
UNCOV
629
    throw std::runtime_error("This DAGMC Universe does not use UWUW materials");
×
630
  }
631

632
  std::stringstream ss;
4✔
633
  // write header
634
  ss << "<?xml version=\"1.0\"?>\n";
4✔
635
  ss << "<materials>\n";
4✔
636
  const auto& mat_lib = uwuw_->material_library;
4✔
637
  // write materials
638
  for (auto mat : mat_lib) {
12✔
639
    ss << mat.second->openmc("atom");
16✔
640
  }
8✔
641
  // write footer
642
  ss << "</materials>";
4✔
643

644
  return ss.str();
8✔
645
#else
646
  fatal_error("DAGMC was not configured with UWUW.");
647
#endif // OPENMC_UWUW_ENABLED
648
}
4✔
649

UNCOV
650
void DAGUniverse::write_uwuw_materials_xml(const std::string& outfile) const
×
651
{
652
#ifdef OPENMC_UWUW_ENABLED
UNCOV
653
  if (!uses_uwuw()) {
×
UNCOV
654
    throw std::runtime_error(
×
UNCOV
655
      "This DAGMC universe does not use UWUW materials.");
×
656
  }
657

UNCOV
658
  std::string xml_str = get_uwuw_materials_xml();
×
659
  // if there is a material library in the file
UNCOV
660
  std::ofstream mats_xml(outfile);
×
UNCOV
661
  mats_xml << xml_str;
×
UNCOV
662
  mats_xml.close();
×
663
#else
664
  fatal_error("DAGMC was not configured with UWUW.");
665
#endif // OPENMC_UWUW_ENABLED
UNCOV
666
}
×
667

668
void DAGUniverse::legacy_assign_material(
110✔
669
  std::string mat_string, std::unique_ptr<DAGCell>& c) const
670
{
671
  bool mat_found_by_name = false;
110✔
672
  // attempt to find a material with a matching name
673
  to_lower(mat_string);
110✔
674
  for (const auto& m : model::materials) {
335✔
675
    std::string m_name = m->name();
225✔
676
    to_lower(m_name);
225✔
677
    if (mat_string == m_name) {
225✔
678
      // assign the material with that name
679
      if (!mat_found_by_name) {
88!
680
        mat_found_by_name = true;
88✔
681
        c->material_.push_back(m->id_);
88✔
682
        // report error if more than one material is found
683
      } else {
UNCOV
684
        fatal_error(fmt::format(
×
685
          "More than one material found with name '{}'. Please ensure "
686
          "materials "
687
          "have unique names if using this property to assign materials.",
688
          mat_string));
689
      }
690
    }
691
  }
225✔
692

693
  // if no material was set using a name, assign by id
694
  if (!mat_found_by_name) {
110✔
695
    bool found_by_id = true;
22✔
696
    try {
22✔
697
      auto id = std::stoi(mat_string);
22✔
698
      if (model::material_map.find(id) == model::material_map.end())
21✔
699
        found_by_id = false;
1✔
700
      c->material_.emplace_back(id);
21✔
701
    } catch (const std::invalid_argument&) {
1!
702
      found_by_id = false;
1✔
703
    }
1✔
704

705
    // report failure for failed int conversion or missing material
706
    if (!found_by_id)
22✔
707
      fatal_error(
2✔
708
        fmt::format("Material with name/ID '{}' not found for volume (cell) {}",
2✔
709
          mat_string, c->id_));
2✔
710
  }
711

712
  if (settings::verbosity >= 10) {
108!
UNCOV
713
    const auto& m = model::materials[model::material_map.at(c->material_[0])];
×
UNCOV
714
    std::stringstream msg;
×
UNCOV
715
    msg << "DAGMC material " << mat_string << " was assigned";
×
UNCOV
716
    if (mat_found_by_name) {
×
UNCOV
717
      msg << " using material name: " << m->name_;
×
718
    } else {
UNCOV
719
      msg << " using material id: " << m->id_;
×
720
    }
UNCOV
721
    write_message(msg.str(), 10);
×
UNCOV
722
  }
×
723
}
108✔
724

725
void DAGUniverse::read_uwuw_materials()
46✔
726
{
727
#ifdef OPENMC_UWUW_ENABLED
728
  // If no filename was provided, don't read UWUW materials
729
  if (filename_ == "")
46!
730
    return;
42✔
731

732
  uwuw_ = std::make_shared<UWUW>(filename_.c_str());
46!
733

734
  if (!uses_uwuw())
46✔
735
    return;
736

737
  // Notify user if UWUW materials are going to be used
738
  write_message("Found UWUW Materials in the DAGMC geometry file.", 6);
4✔
739

740
  // if we're using automatic IDs, update the UWUW material metadata
741
  if (adjust_material_ids_) {
4!
UNCOV
742
    int32_t next_material_id = 0;
×
UNCOV
743
    for (const auto& m : model::materials) {
×
UNCOV
744
      next_material_id = std::max(m->id_, next_material_id);
×
745
    }
UNCOV
746
    next_material_id++;
×
747

UNCOV
748
    for (auto& mat : uwuw_->material_library) {
×
UNCOV
749
      mat.second->metadata["mat_number"] = next_material_id++;
×
750
    }
751
  }
752

753
  std::string mat_xml_string = get_uwuw_materials_xml();
4✔
754

755
  // create a pugi XML document from this string
756
  pugi::xml_document doc;
4✔
757
  auto result = doc.load_string(mat_xml_string.c_str());
4✔
758
  if (!result) {
4!
UNCOV
759
    fatal_error("Error processing XML created using DAGMC UWUW materials.");
×
760
  }
761
  pugi::xml_node root = doc.document_element();
4✔
762
  for (pugi::xml_node material_node : root.children("material")) {
12✔
763
    model::materials.push_back(std::make_unique<Material>(material_node));
16✔
764
  }
765
#else
766
  fatal_error("DAGMC was not configured with UWUW.");
767
#endif // OPENMC_UWUW_ENABLED
768
}
4✔
769

770
void DAGUniverse::uwuw_assign_material(
12✔
771
  moab::EntityHandle vol_handle, std::unique_ptr<DAGCell>& c) const
772
{
773
#ifdef OPENMC_UWUW_ENABLED
774
  // lookup material in uwuw if present
775
  std::string uwuw_mat = dmd_ptr->volume_material_property_data_eh[vol_handle];
12✔
776
  if (uwuw_->material_library.count(uwuw_mat) != 0) {
24!
777
    // Note: material numbers are set by UWUW
778
    int mat_number = uwuw_->material_library.get_material(uwuw_mat)
12✔
779
                       .metadata["mat_number"]
12✔
780
                       .asInt();
12✔
781
    c->material_.push_back(mat_number);
12✔
782
  } else {
UNCOV
783
    fatal_error(fmt::format("Material with value '{}' not found in the "
×
784
                            "UWUW material library",
785
      uwuw_mat));
786
  }
787
#else
788
  fatal_error("DAGMC was not configured with UWUW.");
789
#endif // OPENMC_UWUW_ENABLED
790
}
12✔
791

792
void DAGUniverse::override_assign_material(std::unique_ptr<DAGCell>& c,
9✔
793
  const MaterialOverrides& material_overrides) const
794
{
795
  // if Cell ID matches an override key, use it to override the material
796
  // assignment else if UWUW is used, get the material assignment from the DAGMC
797
  // metadata
798
  // Notify User that an override is being applied on a DAGMCCell
799
  write_message(fmt::format("Applying override for DAGMCCell {}", c->id_), 8);
9✔
800

801
  const auto& mat_overrides = material_overrides.at(c->id_);
9✔
802
  if (settings::verbosity >= 10) {
9!
UNCOV
803
    std::stringstream override_values;
×
UNCOV
804
    for (size_t i = 0; i < mat_overrides.size(); ++i) {
×
UNCOV
805
      if (i > 0) {
×
UNCOV
806
        override_values << " ";
×
807
      }
UNCOV
808
      if (mat_overrides[i] == MATERIAL_VOID) {
×
UNCOV
809
        override_values << "void";
×
810
      } else {
UNCOV
811
        override_values << mat_overrides[i];
×
812
      }
813
    }
UNCOV
814
    auto msg = fmt::format("Overriding DAGMC cell {} property 'material' "
×
815
                           "with value(s): {}",
UNCOV
816
      c->id_, override_values.str());
×
UNCOV
817
    write_message(msg, 10);
×
UNCOV
818
  }
×
819

820
  // Override the material assignment for each cell instance using the legacy
821
  // assignement
822
  for (auto mat_id : mat_overrides) {
27✔
823
    if (mat_id != MATERIAL_VOID &&
18!
824
        model::material_map.find(mat_id) == model::material_map.end()) {
14!
UNCOV
825
      fatal_error(fmt::format(
×
UNCOV
826
        "Material with ID '{}' not found for DAGMC cell {}", mat_id, c->id_));
×
827
    }
828
    c->material_.push_back(mat_id);
18✔
829
  }
830
}
9✔
831

832
//==============================================================================
833
// DAGMC Cell implementation
834
//==============================================================================
835

836
DAGCell::DAGCell(std::shared_ptr<moab::DagMC> dag_ptr, int32_t dag_idx)
211✔
837
  : Cell {}, dagmc_ptr_(dag_ptr), dag_index_(dag_idx) {};
211!
838

839
std::pair<double, int32_t> DAGCell::distance(
349,842✔
840
  Position r, Direction u, int32_t on_surface, GeometryState* p) const
841
{
842
  // if we've changed direction or we're not on a surface,
843
  // reset the history and update last direction
844
  if (u != p->last_dir()) {
349,842✔
845
    p->last_dir() = u;
301,582✔
846
    p->history().reset();
301,582✔
847
  }
848
  if (on_surface == SURFACE_NONE) {
349,842✔
849
    p->history().reset();
281,212✔
850
  }
851

852
  const auto& univ = model::universes[p->lowest_coord().universe()];
349,842!
853

854
  DAGUniverse* dag_univ = static_cast<DAGUniverse*>(univ.get());
349,842!
855
  if (!dag_univ)
349,842!
UNCOV
856
    fatal_error("DAGMC call made for particle in a non-DAGMC universe");
×
857

858
  // initialize to lost particle conditions
859
  int surf_idx = -1;
349,842✔
860
  double dist = INFINITY;
349,842✔
861

862
  moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_);
349,842✔
863
  moab::EntityHandle hit_surf;
349,842✔
864

865
  // create the ray
866
  double pnt[3] = {r.x, r.y, r.z};
349,842✔
867
  double dir[3] = {u.x, u.y, u.z};
349,842✔
868
  MB_CHK_ERR_CONT(
349,842!
869
    dagmc_ptr_->ray_fire(vol, pnt, dir, hit_surf, dist, &p->history()));
870
  if (hit_surf != 0) {
349,842✔
871
    surf_idx =
661,838✔
872
      dag_univ->surf_idx_offset_ + dagmc_ptr_->index_by_handle(hit_surf);
330,919✔
873
  } else if (!dagmc_ptr_->is_implicit_complement(vol) ||
37,846!
874
             is_root_universe(dag_univ->id_)) {
18,923✔
875
    // surface boundary conditions are ignored for projection plotting, meaning
876
    // that the particle may move through the graveyard (bounding) volume and
877
    // into the implicit complement on the other side where no intersection will
878
    // be found. Treating this as a lost particle is problematic when plotting.
879
    // Instead, the infinite distance and invalid surface index are returned.
UNCOV
880
    if (settings::run_mode == RunMode::PLOTTING)
×
UNCOV
881
      return {INFTY, -1};
×
882

883
    // the particle should be marked as lost immediately if an intersection
884
    // isn't found in a volume that is not the implicit complement. In the case
885
    // that the DAGMC model is the root universe of the geometry, even a missing
886
    // intersection in the implicit complement should trigger this condition.
UNCOV
887
    std::string material_id =
×
UNCOV
888
      p->material() == MATERIAL_VOID
×
889
        ? "-1 (VOID)"
UNCOV
890
        : std::to_string(model::materials[p->material()]->id());
×
UNCOV
891
    p->mark_as_lost(fmt::format(
×
UNCOV
892
      "No intersection found with DAGMC cell {}, filled with material {}", id_,
×
893
      material_id));
UNCOV
894
  }
×
895

896
  return {dist, surf_idx};
349,842✔
897
}
898

899
bool DAGCell::contains(Position r, Direction u, int32_t on_surface) const
8,492,336✔
900
{
901
  moab::ErrorCode rval;
8,492,336✔
902
  moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_);
8,492,336✔
903

904
  int result = 0;
8,492,336✔
905
  double pnt[3] = {r.x, r.y, r.z};
8,492,336✔
906
  double dir[3] = {u.x, u.y, u.z};
8,492,336✔
907
  rval = dagmc_ptr_->point_in_volume(vol, pnt, result, dir);
8,492,336✔
908
  MB_CHK_ERR_CONT(rval);
8,492,336!
909
  return result;
8,492,336✔
910
}
911

912
moab::EntityHandle DAGCell::mesh_handle() const
46,716✔
913
{
914
  return dagmc_ptr()->entity_by_index(3, dag_index());
46,716✔
915
}
916

917
void DAGCell::to_hdf5_inner(hid_t group_id) const
155✔
918
{
919
  write_string(group_id, "geom_type", "dagmc", false);
155✔
920
}
155✔
921

UNCOV
922
BoundingBox DAGCell::bounding_box() const
×
923
{
UNCOV
924
  moab::ErrorCode rval;
×
UNCOV
925
  moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_);
×
UNCOV
926
  double min[3], max[3];
×
UNCOV
927
  rval = dagmc_ptr_->getobb(vol, min, max);
×
UNCOV
928
  MB_CHK_ERR_CONT(rval);
×
UNCOV
929
  return {{min[0], min[1], min[2]}, {max[0], max[1], max[2]}};
×
930
}
931

932
//==============================================================================
933
// DAGSurface implementation
934
//==============================================================================
935

936
DAGSurface::DAGSurface(std::shared_ptr<moab::DagMC> dag_ptr, int32_t dag_idx)
830✔
937
  : Surface {}, dagmc_ptr_(dag_ptr), dag_index_(dag_idx)
830!
938
{} // empty constructor
830✔
939

940
moab::EntityHandle DAGSurface::mesh_handle() const
49,474✔
941
{
942
  return dagmc_ptr()->entity_by_index(2, dag_index());
49,474✔
943
}
944

UNCOV
945
double DAGSurface::evaluate(Position r) const
×
946
{
UNCOV
947
  return 0.0;
×
948
}
949

UNCOV
950
double DAGSurface::distance(Position r, Direction u, bool coincident) const
×
951
{
UNCOV
952
  moab::ErrorCode rval;
×
UNCOV
953
  moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_);
×
UNCOV
954
  moab::EntityHandle hit_surf;
×
UNCOV
955
  double dist;
×
UNCOV
956
  double pnt[3] = {r.x, r.y, r.z};
×
UNCOV
957
  double dir[3] = {u.x, u.y, u.z};
×
UNCOV
958
  rval = dagmc_ptr_->ray_fire(surf, pnt, dir, hit_surf, dist, NULL, 0, 0);
×
UNCOV
959
  MB_CHK_ERR_CONT(rval);
×
UNCOV
960
  if (dist < 0.0)
×
UNCOV
961
    dist = INFTY;
×
UNCOV
962
  return dist;
×
963
}
964

UNCOV
965
Direction DAGSurface::normal(Position r) const
×
966
{
UNCOV
967
  moab::ErrorCode rval;
×
UNCOV
968
  moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_);
×
UNCOV
969
  double pnt[3] = {r.x, r.y, r.z};
×
UNCOV
970
  double dir[3];
×
UNCOV
971
  rval = dagmc_ptr_->get_angle(surf, pnt, dir);
×
UNCOV
972
  MB_CHK_ERR_CONT(rval);
×
UNCOV
973
  return dir;
×
974
}
975

976
Direction DAGSurface::reflect(Position r, Direction u, GeometryState* p) const
2,758✔
977
{
978
  assert(p);
2,758!
979
  double pnt[3] = {r.x, r.y, r.z};
2,758✔
980
  double dir[3];
2,758✔
981
  moab::ErrorCode rval =
2,758✔
982
    dagmc_ptr_->get_angle(mesh_handle(), pnt, dir, &p->history());
2,758✔
983
  MB_CHK_ERR_CONT(rval);
2,758!
984
  return u.reflect(dir);
2,758✔
985
}
986

987
//==============================================================================
988
// Non-member functions
989
//==============================================================================
990

991
void read_dagmc_universes(pugi::xml_node node)
1,050✔
992
{
993
  for (pugi::xml_node dag_node : node.children("dagmc_universe")) {
1,094✔
994
    model::universes.push_back(std::make_unique<DAGUniverse>(dag_node));
46✔
995
    model::universe_map[model::universes.back()->id_] =
44✔
996
      model::universes.size() - 1;
44✔
997
  }
998
}
1,048✔
999

1000
void check_dagmc_root_univ()
1,050✔
1001
{
1002
  const auto& ru = model::universes[model::root_universe];
1,050✔
1003
  if (ru->geom_type() == GeometryType::DAG) {
1,050✔
1004
    // if the root universe contains DAGMC geometry, warn the user
1005
    // if it does not contain a graveyard volume
1006
    auto dag_univ = dynamic_cast<DAGUniverse*>(ru.get());
23!
1007
    if (dag_univ && !dag_univ->has_graveyard()) {
23!
1008
      warning(
2✔
1009
        "No graveyard volume found in the DagMC model. "
1010
        "This may result in lost particles and rapid simulation failure.");
1011
    }
1012
  }
1013
}
1,050✔
1014

1015
int32_t next_cell(int32_t surf, int32_t curr_cell, int32_t univ)
46,716✔
1016
{
1017
  auto surfp = dynamic_cast<DAGSurface*>(model::surfaces[surf].get());
46,716!
1018
  auto cellp = dynamic_cast<DAGCell*>(model::cells[curr_cell].get());
46,716!
1019
  auto univp = static_cast<DAGUniverse*>(model::universes[univ].get());
46,716✔
1020

1021
  moab::EntityHandle surf_handle = surfp->mesh_handle();
46,716✔
1022
  moab::EntityHandle curr_vol = cellp->mesh_handle();
46,716✔
1023

1024
  moab::EntityHandle new_vol;
46,716✔
1025
  moab::ErrorCode rval =
46,716✔
1026
    cellp->dagmc_ptr()->next_vol(surf_handle, curr_vol, new_vol);
46,716✔
1027
  if (rval != moab::MB_SUCCESS)
46,716!
1028
    return -1;
1029

1030
  return univp->cell_index(new_vol);
46,716✔
1031
}
1032

1033
extern "C" int openmc_dagmc_universe_get_cell_ids(
11✔
1034
  int32_t univ_id, int32_t* ids, size_t* n)
1035
{
1036
  // make sure the universe id is a DAGMC Universe
1037
  const auto& univ = model::universes[model::universe_map[univ_id]];
11✔
1038
  if (univ->geom_type() != GeometryType::DAG) {
11!
UNCOV
1039
    set_errmsg(fmt::format("Universe {} is not a DAGMC Universe", univ_id));
×
UNCOV
1040
    return OPENMC_E_INVALID_TYPE;
×
1041
  }
1042

1043
  std::vector<int32_t> dag_cell_ids;
11✔
1044
  for (const auto& cell_index : univ->cells_) {
51✔
1045
    const auto& cell = model::cells[cell_index];
40✔
1046
    if (cell->geom_type() == GeometryType::CSG) {
40!
UNCOV
1047
      set_errmsg(fmt::format("Cell {} is not a DAGMC Cell", cell->id_));
×
UNCOV
1048
      return OPENMC_E_INVALID_TYPE;
×
1049
    }
1050
    dag_cell_ids.push_back(cell->id_);
40✔
1051
  }
1052
  std::copy(dag_cell_ids.begin(), dag_cell_ids.end(), ids);
11✔
1053
  *n = dag_cell_ids.size();
11✔
1054
  return 0;
11✔
1055
}
11✔
1056

1057
extern "C" int openmc_dagmc_universe_get_num_cells(int32_t univ_id, size_t* n)
11✔
1058
{
1059
  // make sure the universe id is a DAGMC Universe
1060
  const auto& univ = model::universes[model::universe_map[univ_id]];
11✔
1061
  if (univ->geom_type() != GeometryType::DAG) {
11!
UNCOV
1062
    set_errmsg(fmt::format("Universe {} is not a DAGMC universe", univ_id));
×
UNCOV
1063
    return OPENMC_E_INVALID_TYPE;
×
1064
  }
1065
  *n = univ->cells_.size();
11✔
1066
  return 0;
11✔
1067
}
1068

1069
} // namespace openmc
1070

1071
#else
1072

1073
namespace openmc {
1074

1075
extern "C" int openmc_dagmc_universe_get_cell_ids(
1076
  int32_t univ_id, int32_t* ids, size_t* n)
1077
{
1078
  set_errmsg("OpenMC was not configured with DAGMC");
1079
  return OPENMC_E_UNASSIGNED;
1080
};
1081

1082
extern "C" int openmc_dagmc_universe_get_num_cells(int32_t univ_id, size_t* n)
1083
{
1084
  set_errmsg("OpenMC was not configured with DAGMC");
1085
  return OPENMC_E_UNASSIGNED;
1086
};
1087

1088
void read_dagmc_universes(pugi::xml_node node)
1089
{
1090
  if (check_for_node(node, "dagmc_universe")) {
8,067!
1091
    fatal_error("DAGMC Universes are present but OpenMC was not configured "
1092
                "with DAGMC");
1093
  }
1094
};
1095

1096
void check_dagmc_root_univ() {};
1097

1098
int32_t next_cell(int32_t surf, int32_t curr_cell, int32_t univ);
1099

1100
} // namespace openmc
1101

1102
#endif // OPENMC_DAGMC_ENABLED
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc