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

openmc-dev / openmc / 19058781736

04 Nov 2025 05:26AM UTC coverage: 82.008% (-3.1%) from 85.155%
19058781736

Pull #3252

github

web-flow
Merge b8a72730f into bd76fc056
Pull Request #3252: Adding vtkhdf option to write vtk data

16714 of 23236 branches covered (71.93%)

Branch coverage included in aggregate %.

61 of 66 new or added lines in 1 file covered. (92.42%)

3175 existing lines in 103 files now uncovered.

54243 of 63288 relevant lines covered (85.71%)

43393337.77 hits per line

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

87.69
/src/geometry_aux.cpp
1
#include "openmc/geometry_aux.h"
2

3
#include <algorithm> // for std::max
4
#include <sstream>
5
#include <unordered_set>
6

7
#include <fmt/core.h>
8
#include <pugixml.hpp>
9

10
#include "openmc/cell.h"
11
#include "openmc/constants.h"
12
#include "openmc/container_util.h"
13
#include "openmc/dagmc.h"
14
#include "openmc/error.h"
15
#include "openmc/file_utils.h"
16
#include "openmc/geometry.h"
17
#include "openmc/lattice.h"
18
#include "openmc/material.h"
19
#include "openmc/settings.h"
20
#include "openmc/surface.h"
21
#include "openmc/tallies/filter.h"
22
#include "openmc/tallies/filter_cell_instance.h"
23
#include "openmc/tallies/filter_distribcell.h"
24

25
namespace openmc {
26

27
namespace model {
28
std::unordered_map<int32_t, int32_t> universe_level_counts;
29
} // namespace model
30

31
void read_geometry_xml()
1,753✔
32
{
33
  // Display output message
34
  write_message("Reading geometry XML file...", 5);
1,753✔
35

36
  // Check if geometry.xml exists
37
  std::string filename = settings::path_input + "geometry.xml";
1,753✔
38
  if (!file_exists(filename)) {
1,753!
39
    fatal_error("Geometry XML file '" + filename + "' does not exist!");
×
40
  }
41

42
  // Parse settings.xml file
43
  pugi::xml_document doc;
1,753✔
44
  auto result = doc.load_file(filename.c_str());
1,753✔
45
  if (!result) {
1,753!
46
    fatal_error("Error processing geometry.xml file.");
×
47
  }
48

49
  // Get root element
50
  pugi::xml_node root = doc.document_element();
1,753✔
51

52
  read_geometry_xml(root);
1,753✔
53
}
1,753✔
54

55
void read_geometry_xml(pugi::xml_node root)
7,882✔
56
{
57
  // Read surfaces, cells, lattice
58
  read_surfaces(root);
7,882✔
59
  read_cells(root);
7,882✔
60
  read_lattices(root);
7,880✔
61

62
  // Check to make sure a boundary condition was applied to at least one
63
  // surface
64
  bool boundary_exists = false;
7,880✔
65
  for (const auto& surf : model::surfaces) {
19,082✔
66
    if (surf->bc_) {
19,049✔
67
      boundary_exists = true;
7,847✔
68
      break;
7,847✔
69
    }
70
  }
71

72
  if (settings::run_mode != RunMode::PLOTTING &&
7,880✔
73
      settings::run_mode != RunMode::VOLUME && !boundary_exists) {
7,604!
74
    fatal_error("No boundary conditions were applied to any surfaces!");
×
75
  }
76

77
  // Allocate universes, universe cell arrays, and assign base universe
78
  model::root_universe = find_root_universe();
7,880✔
79

80
  // if the root universe is DAGMC geometry, make sure the model is well-formed
81
  check_dagmc_root_univ();
7,880✔
82
}
7,880✔
83

84
//==============================================================================
85

86
void adjust_indices()
7,882✔
87
{
88
  // Adjust material/fill idices.
89
  for (auto& c : model::cells) {
42,180✔
90
    if (c->fill_ != C_NONE) {
34,298✔
91
      int32_t id = c->fill_;
7,043✔
92
      auto search_univ = model::universe_map.find(id);
7,043✔
93
      auto search_lat = model::lattice_map.find(id);
7,043✔
94
      if (search_univ != model::universe_map.end()) {
7,043✔
95
        c->type_ = Fill::UNIVERSE;
5,036✔
96
        c->fill_ = search_univ->second;
5,036✔
97
      } else if (search_lat != model::lattice_map.end()) {
2,007!
98
        c->type_ = Fill::LATTICE;
2,007✔
99
        c->fill_ = search_lat->second;
2,007✔
100
      } else {
101
        fatal_error(fmt::format("Specified fill {} on cell {} is neither a "
×
102
                                "universe nor a lattice.",
103
          id, c->id_));
×
104
      }
105
    } else {
106
      c->type_ = Fill::MATERIAL;
27,255✔
107
      for (auto& mat_id : c->material_) {
56,198✔
108
        if (mat_id != MATERIAL_VOID) {
28,943✔
109
          auto search = model::material_map.find(mat_id);
20,230✔
110
          if (search == model::material_map.end()) {
20,230!
111
            fatal_error(
×
112
              fmt::format("Could not find material {} specified on cell {}",
×
113
                mat_id, c->id_));
×
114
          }
115
          // Change from ID to index
116
          mat_id = search->second;
20,230✔
117
        }
118
      }
119
    }
120
  }
121

122
  // Change cell.universe values from IDs to indices.
123
  for (auto& c : model::cells) {
42,180✔
124
    auto search = model::universe_map.find(c->universe_);
34,298✔
125
    if (search != model::universe_map.end()) {
34,298!
126
      c->universe_ = search->second;
34,298✔
127
    } else {
128
      fatal_error(fmt::format("Could not find universe {} specified on cell {}",
×
129
        c->universe_, c->id_));
×
130
    }
131
  }
132

133
  // Change all lattice universe values from IDs to indices.
134
  for (auto& l : model::lattices) {
9,800✔
135
    l->adjust_indices();
1,918✔
136
  }
137
}
7,882✔
138

139
//==============================================================================
140
//! Partition some universes with many z-planes for faster find_cell searches.
141

142
void partition_universes()
7,882✔
143
{
144
  // Iterate over universes with more than 10 cells.  (Fewer than 10 is likely
145
  // not worth partitioning.)
146
  for (const auto& univ : model::universes) {
27,257✔
147
    if (univ->cells_.size() > 10) {
19,375✔
148
      // Collect the set of surfaces in this universe.
149
      std::unordered_set<int32_t> surf_inds;
183✔
150
      for (auto i_cell : univ->cells_) {
3,076✔
151
        for (auto token : model::cells[i_cell]->surfaces()) {
10,964✔
152
          surf_inds.insert(std::abs(token) - 1);
8,071✔
153
        }
2,893✔
154
      }
155

156
      // Partition the universe if there are more than 5 z-planes.  (Fewer than
157
      // 5 is likely not worth it.)
158
      int n_zplanes = 0;
183✔
159
      for (auto i_surf : surf_inds) {
2,351✔
160
        if (dynamic_cast<const SurfaceZPlane*>(model::surfaces[i_surf].get())) {
2,264!
161
          ++n_zplanes;
640✔
162
          if (n_zplanes > 5) {
640✔
163
            univ->partitioner_ = make_unique<UniversePartitioner>(*univ);
96✔
164
            break;
96✔
165
          }
166
        }
167
      }
168
    }
183✔
169
  }
170
}
7,882✔
171

172
//==============================================================================
173

174
void assign_temperatures()
7,882✔
175
{
176
  for (auto& c : model::cells) {
42,180✔
177
    // Ignore non-material cells and cells with defined temperature.
178
    if (c->material_.size() == 0)
34,298✔
179
      continue;
7,043✔
180
    if (c->sqrtkT_.size() > 0)
27,255✔
181
      continue;
557✔
182

183
    c->sqrtkT_.reserve(c->material_.size());
26,698✔
184
    for (auto i_mat : c->material_) {
55,048✔
185
      if (i_mat == MATERIAL_VOID) {
28,350✔
186
        // Set void region to 0K.
187
        c->sqrtkT_.push_back(0);
8,713✔
188
      } else {
189
        const auto& mat {model::materials[i_mat]};
19,637✔
190
        c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * mat->temperature()));
19,637✔
191
      }
192
    }
193
  }
194
}
7,882✔
195

196
//==============================================================================
197

198
void finalize_cell_densities()
7,882✔
199
{
200
  for (auto& c : model::cells) {
42,180✔
201
    // Convert to density multipliers.
202
    if (!c->density_mult_.empty()) {
34,298✔
203
      for (int32_t instance = 0; instance < c->density_mult_.size();
80✔
204
           ++instance) {
205
        c->density_mult_[instance] /=
64✔
206
          model::materials[c->material(instance)]->density_gpcc();
64✔
207
      }
208
    } else {
209
      c->density_mult_ = {1.0};
34,282✔
210
    }
211
  }
212
}
7,882✔
213

214
//==============================================================================
215

216
void get_temperatures(
7,606✔
217
  vector<vector<double>>& nuc_temps, vector<vector<double>>& thermal_temps)
218
{
219
  for (const auto& cell : model::cells) {
41,331✔
220
    // Skip non-material cells.
221
    if (cell->fill_ != C_NONE)
33,725✔
222
      continue;
7,030✔
223

224
    for (int j = 0; j < cell->material_.size(); ++j) {
55,078✔
225
      // Skip void materials
226
      int i_material = cell->material_[j];
28,383✔
227
      if (i_material == MATERIAL_VOID)
28,383✔
228
        continue;
8,597✔
229

230
      // Get temperature(s) of cell (rounding to nearest integer)
231
      vector<double> cell_temps;
19,786✔
232
      if (cell->sqrtkT_.size() == 1) {
19,786✔
233
        double sqrtkT = cell->sqrtkT_[0];
17,890✔
234
        cell_temps.push_back(sqrtkT * sqrtkT / K_BOLTZMANN);
17,890✔
235
      } else if (cell->sqrtkT_.size() == cell->material_.size()) {
1,896✔
236
        double sqrtkT = cell->sqrtkT_[j];
1,880✔
237
        cell_temps.push_back(sqrtkT * sqrtkT / K_BOLTZMANN);
1,880✔
238
      } else {
239
        for (double sqrtkT : cell->sqrtkT_)
80✔
240
          cell_temps.push_back(sqrtkT * sqrtkT / K_BOLTZMANN);
64✔
241
      }
242

243
      const auto& mat {model::materials[i_material]};
19,786✔
244
      for (const auto& i_nuc : mat->nuclide_) {
90,706✔
245
        for (double temperature : cell_temps) {
141,888✔
246
          // Add temperature if it hasn't already been added
247
          if (!contains(nuc_temps[i_nuc], temperature))
70,968✔
248
            nuc_temps[i_nuc].push_back(temperature);
29,798✔
249
        }
250
      }
251

252
      for (const auto& table : mat->thermal_tables_) {
23,079✔
253
        // Get index in data::thermal_scatt array
254
        int i_sab = table.index_table;
3,293✔
255

256
        for (double temperature : cell_temps) {
6,586✔
257
          // Add temperature if it hasn't already been added
258
          if (!contains(thermal_temps[i_sab], temperature))
3,293✔
259
            thermal_temps[i_sab].push_back(temperature);
1,192✔
260
        }
261
      }
262
    }
19,786✔
263
  }
264
}
7,606✔
265

266
//==============================================================================
267

268
void finalize_geometry()
7,882✔
269
{
270
  // Perform some final operations to set up the geometry
271
  adjust_indices();
7,882✔
272
  count_universe_instances();
7,882✔
273
  partition_universes();
7,882✔
274

275
  // Assign temperatures to cells that don't have temperatures already assigned
276
  assign_temperatures();
7,882✔
277

278
  // Determine number of nested coordinate levels in the geometry
279
  model::n_coord_levels = maximum_levels(model::root_universe);
7,882✔
280
}
7,882✔
281

282
//==============================================================================
283

284
int32_t find_root_universe()
7,882✔
285
{
286
  // Find all the universes listed as a cell fill.
287
  std::unordered_set<int32_t> fill_univ_ids;
7,882✔
288
  for (const auto& c : model::cells) {
42,180✔
289
    fill_univ_ids.insert(c->fill_);
34,298✔
290
  }
291

292
  // Find all the universes contained in a lattice.
293
  for (const auto& lat : model::lattices) {
9,800✔
294
    for (auto it = lat->begin(); it != lat->end(); ++it) {
919,550✔
295
      fill_univ_ids.insert(*it);
917,632✔
296
    }
297
    if (lat->outer_ != NO_OUTER_UNIVERSE) {
1,918✔
298
      fill_univ_ids.insert(lat->outer_);
387✔
299
    }
300
  }
301

302
  // Figure out which universe is not in the set.  This is the root universe.
303
  bool root_found {false};
7,882✔
304
  int32_t root_univ;
305
  for (int32_t i = 0; i < model::universes.size(); i++) {
27,257✔
306
    auto search = fill_univ_ids.find(model::universes[i]->id_);
19,375✔
307
    if (search == fill_univ_ids.end()) {
19,375✔
308
      if (root_found) {
7,882!
UNCOV
309
        fatal_error("Two or more universes are not used as fill universes, so "
×
310
                    "it is not possible to distinguish which one is the root "
311
                    "universe.");
312
      } else {
313
        root_found = true;
7,882✔
314
        root_univ = i;
7,882✔
315
      }
316
    }
317
  }
318
  if (!root_found)
7,882!
UNCOV
319
    fatal_error("Could not find a root universe.  Make sure "
×
320
                "there are no circular dependencies in the geometry.");
321

322
  return root_univ;
7,882✔
323
}
7,882✔
324

325
//==============================================================================
326

327
void prepare_distribcell(const std::vector<int32_t>* user_distribcells)
7,878✔
328
{
329
  write_message("Preparing distributed cell instances...", 5);
7,878✔
330

331
  std::unordered_set<int32_t> distribcells;
7,878✔
332

333
  // start with any cells manually specified via the C++ API
334
  if (user_distribcells) {
7,878✔
335
    distribcells.insert(user_distribcells->begin(), user_distribcells->end());
16✔
336
  }
337

338
  // Find all cells listed in a DistribcellFilter or CellInstanceFilter
339
  for (auto& filt : model::tally_filters) {
16,144✔
340
    auto* distrib_filt = dynamic_cast<DistribcellFilter*>(filt.get());
8,266!
341
    auto* cell_inst_filt = dynamic_cast<CellInstanceFilter*>(filt.get());
8,266!
342
    if (distrib_filt) {
8,266✔
343
      distribcells.insert(distrib_filt->cell());
233✔
344
    }
345
    if (cell_inst_filt) {
8,266✔
346
      const auto& filter_cells = cell_inst_filt->cells();
34✔
347
      distribcells.insert(filter_cells.begin(), filter_cells.end());
34✔
348
    }
349
  }
350

351
  // By default, add material cells to the list of distributed cells
352
  if (settings::material_cell_offsets) {
7,878!
353
    for (int64_t i = 0; i < model::cells.size(); ++i) {
42,228✔
354
      if (model::cells[i]->type_ == Fill::MATERIAL)
34,350✔
355
        distribcells.insert(i);
27,275✔
356
    }
357
  }
358

359
  // Make sure that the number of materials/temperatures matches the number of
360
  // cell instances.
361
  for (int i = 0; i < model::cells.size(); i++) {
42,228✔
362
    Cell& c {*model::cells[i]};
34,350✔
363

364
    if (c.material_.size() > 1) {
34,350✔
365
      if (c.material_.size() != c.n_instances()) {
256!
UNCOV
366
        fatal_error(fmt::format(
×
367
          "Cell {} was specified with {} materials but has {} distributed "
368
          "instances. The number of materials must equal one or the number "
369
          "of instances.",
UNCOV
370
          c.id_, c.material_.size(), c.n_instances()));
×
371
      }
372
    }
373

374
    if (c.sqrtkT_.size() > 1) {
34,350✔
375
      if (c.sqrtkT_.size() != c.n_instances()) {
260!
UNCOV
376
        fatal_error(fmt::format(
×
377
          "Cell {} was specified with {} temperatures but has {} distributed "
378
          "instances. The number of temperatures must equal one or the number "
379
          "of instances.",
UNCOV
380
          c.id_, c.sqrtkT_.size(), c.n_instances()));
×
381
      }
382
    }
383

384
    if (c.density_mult_.size() > 1) {
34,350✔
385
      if (c.density_mult_.size() != c.n_instances()) {
16!
UNCOV
386
        fatal_error(fmt::format("Cell {} was specified with {} density "
×
387
                                "multipliers but has {} distributed "
388
                                "instances. The number of density multipliers "
389
                                "must equal one or the number "
390
                                "of instances.",
UNCOV
391
          c.id_, c.density_mult_.size(), c.n_instances()));
×
392
      }
393
    }
394
  }
395

396
  // Search through universes for material cells and assign each one a
397
  // distribcell array index according to the containing universe.
398
  vector<int32_t> target_univ_ids;
7,878✔
399
  for (const auto& u : model::universes) {
27,281✔
400
    for (auto idx : u->cells_) {
53,753✔
401
      if (distribcells.find(idx) != distribcells.end()) {
34,350✔
402
        if (!contains(target_univ_ids, u->id_)) {
27,355✔
403
          target_univ_ids.push_back(u->id_);
16,682✔
404
        }
405
        model::cells[idx]->distribcell_index_ =
27,355✔
406
          std::find(target_univ_ids.begin(), target_univ_ids.end(), u->id_) -
27,355✔
407
          target_univ_ids.begin();
54,710✔
408
      }
409
    }
410
  }
411

412
  // Allocate the cell and lattice offset tables.
413
  int n_maps = target_univ_ids.size();
7,878✔
414
  for (auto& c : model::cells) {
42,228✔
415
    if (c->type_ != Fill::MATERIAL) {
34,350✔
416
      c->offset_.resize(n_maps, C_NONE);
7,075✔
417
    }
418
  }
419
  for (auto& lat : model::lattices) {
9,812✔
420
    lat->allocate_offset_table(n_maps);
1,934✔
421
  }
422

423
// Fill the cell and lattice offset tables.
424
#pragma omp parallel for
4,471✔
425
  for (int map = 0; map < target_univ_ids.size(); map++) {
8,037✔
426
    auto target_univ_id = target_univ_ids[map];
4,630✔
427
    std::unordered_map<int32_t, int32_t> univ_count_memo;
4,630✔
428
    for (const auto& univ : model::universes) {
22,346✔
429
      int32_t offset = 0;
17,716✔
430
      for (int32_t cell_indx : univ->cells_) {
81,461✔
431
        Cell& c = *model::cells[cell_indx];
63,745✔
432

433
        if (c.type_ == Fill::UNIVERSE) {
63,745✔
434
          c.offset_[map] = offset;
35,877✔
435
          int32_t search_univ = c.fill_;
35,877✔
436
          offset += count_universe_instances(
35,877✔
437
            search_univ, target_univ_id, univ_count_memo);
438

439
        } else if (c.type_ == Fill::LATTICE) {
27,868✔
440
          c.offset_[map] = offset;
2,950✔
441
          Lattice& lat = *model::lattices[c.fill_];
2,950✔
442
          offset += lat.fill_offset_table(target_univ_id, map, univ_count_memo);
2,950✔
443
        }
444
      }
445
    }
446
  }
4,630✔
447
}
7,878✔
448

449
//==============================================================================
450

451
void count_universe_instances()
7,882✔
452
{
453
  for (auto& univ : model::universes) {
27,257✔
454
    std::unordered_map<int32_t, int32_t> univ_count_memo;
19,375✔
455
    univ->n_instances_ = count_universe_instances(
19,375✔
456
      model::root_universe, univ->id_, univ_count_memo);
19,375✔
457
  }
19,375✔
458
}
7,882✔
459

460
//==============================================================================
461

462
int count_universe_instances(int32_t search_univ, int32_t target_univ_id,
22,334,694✔
463
  std::unordered_map<int32_t, int32_t>& univ_count_memo)
464
{
465
  // If this is the target, it can't contain itself.
466
  if (model::universes[search_univ]->id_ == target_univ_id) {
22,334,694✔
467
    return 1;
2,594,022✔
468
  }
469

470
  // If we have already counted the number of instances, reuse that value.
471
  auto search = univ_count_memo.find(search_univ);
19,740,672✔
472
  if (search != univ_count_memo.end()) {
19,740,672✔
473
    return search->second;
7,674,660✔
474
  }
475

476
  int count {0};
12,066,012✔
477
  for (int32_t cell_indx : model::universes[search_univ]->cells_) {
24,314,456✔
478
    Cell& c = *model::cells[cell_indx];
12,248,444✔
479

480
    if (c.type_ == Fill::UNIVERSE) {
12,248,444✔
481
      int32_t next_univ = c.fill_;
168,214✔
482
      count +=
168,214✔
483
        count_universe_instances(next_univ, target_univ_id, univ_count_memo);
168,214✔
484

485
    } else if (c.type_ == Fill::LATTICE) {
12,080,230✔
486
      Lattice& lat = *model::lattices[c.fill_];
21,516✔
487
      for (auto it = lat.begin(); it != lat.end(); ++it) {
12,830,404✔
488
        int32_t next_univ = *it;
12,808,888✔
489
        count +=
12,808,888✔
490
          count_universe_instances(next_univ, target_univ_id, univ_count_memo);
12,808,888✔
491
      }
492
    }
493
  }
494

495
  // Remember the number of instances in this universe.
496
  univ_count_memo[search_univ] = count;
12,066,012✔
497

498
  return count;
12,066,012✔
499
}
500

501
//==============================================================================
502

503
std::string distribcell_path_inner(int32_t target_cell, int32_t map,
2,566,718✔
504
  int32_t target_offset, const Universe& search_univ, int32_t offset)
505
{
506
  std::stringstream path;
2,566,718✔
507

508
  path << "u" << search_univ.id_ << "->";
2,566,718✔
509

510
  // Check to see if this universe directly contains the target cell.  If so,
511
  // write to the path and return.
512
  for (int32_t cell_indx : search_univ.cells_) {
11,905,267✔
513
    if ((cell_indx == target_cell) && (offset == target_offset)) {
10,266,168!
514
      Cell& c = *model::cells[cell_indx];
927,619✔
515
      path << "c" << c.id_;
927,619✔
516
      return path.str();
1,855,238✔
517
    }
518
  }
519

520
  // The target must be further down the geometry tree and contained in a fill
521
  // cell or lattice cell in this universe.  Find which cell contains the
522
  // target.
523
  vector<std::int32_t>::const_reverse_iterator cell_it {
524
    search_univ.cells_.crbegin()};
1,639,099✔
525
  for (; cell_it != search_univ.cells_.crend(); ++cell_it) {
9,338,076!
526
    Cell& c = *model::cells[*cell_it];
9,338,076✔
527

528
    // Material cells don't contain other cells so ignore them.
529
    if (c.type_ != Fill::MATERIAL) {
9,338,076✔
530
      int32_t temp_offset = offset + c.offset_[map];
2,339,436✔
531
      if (c.type_ == Fill::LATTICE) {
2,339,436!
532
        Lattice& lat = *model::lattices[c.fill_];
2,339,436✔
533
        int32_t indx = lat.universes_.size() * map + lat.begin().indx_;
2,339,436✔
534
        temp_offset += lat.offsets_[indx];
2,339,436✔
535
      }
536

537
      // The desired cell is the first cell that gives an offset smaller or
538
      // equal to the target offset.
539
      if (temp_offset <= target_offset)
2,339,436✔
540
        break;
1,639,099✔
541
    }
542
  }
543

544
  // if we get through the loop without finding an appropriate entry, throw
545
  // an error
546
  if (cell_it == search_univ.cells_.crend()) {
1,639,099!
UNCOV
547
    fatal_error(
×
UNCOV
548
      fmt::format("Failed to generate a text label for distribcell with ID {}."
×
549
                  "The current label is: '{}'",
UNCOV
550
        model::cells[target_cell]->id_, path.str()));
×
551
  }
552

553
  // Add the cell to the path string.
554
  Cell& c = *model::cells[*cell_it];
1,639,099✔
555
  path << "c" << c.id_ << "->";
1,639,099✔
556

557
  if (c.type_ == Fill::UNIVERSE) {
1,639,099!
558
    // Recurse into the fill cell.
UNCOV
559
    offset += c.offset_[map];
×
UNCOV
560
    path << distribcell_path_inner(
×
UNCOV
561
      target_cell, map, target_offset, *model::universes[c.fill_], offset);
×
UNCOV
562
    return path.str();
×
563
  } else {
564
    // Recurse into the lattice cell.
565
    Lattice& lat = *model::lattices[c.fill_];
1,639,099✔
566
    path << "l" << lat.id_;
1,639,099✔
567
    for (ReverseLatticeIter it = lat.rbegin(); it != lat.rend(); ++it) {
289,050,778!
568
      int32_t indx = lat.universes_.size() * map + it.indx_;
289,050,778✔
569
      int32_t temp_offset = offset + lat.offsets_[indx] + c.offset_[map];
289,050,778✔
570
      if (temp_offset <= target_offset) {
289,050,778✔
571
        offset = temp_offset;
1,639,099✔
572
        path << "(" << lat.index_to_string(it.indx_) << ")->";
1,639,099✔
573
        path << distribcell_path_inner(
3,278,198✔
574
          target_cell, map, target_offset, *model::universes[*it], offset);
3,278,198✔
575
        return path.str();
3,278,198✔
576
      }
577
    }
UNCOV
578
    throw std::runtime_error {"Error determining distribcell path."};
×
579
  }
580
}
2,566,718✔
581

582
std::string distribcell_path(
927,619✔
583
  int32_t target_cell, int32_t map, int32_t target_offset)
584
{
585
  auto& root_univ = *model::universes[model::root_universe];
927,619✔
586
  return distribcell_path_inner(target_cell, map, target_offset, root_univ, 0);
927,619✔
587
}
588

589
//==============================================================================
590

591
int maximum_levels(int32_t univ)
931,023✔
592
{
593

594
  const auto level_count = model::universe_level_counts.find(univ);
931,023✔
595
  if (level_count != model::universe_level_counts.end()) {
931,023✔
596
    return level_count->second;
911,817✔
597
  }
598

599
  int levels_below {0};
19,206✔
600

601
  for (int32_t cell_indx : model::universes[univ]->cells_) {
53,327✔
602
    Cell& c = *model::cells[cell_indx];
34,121✔
603
    if (c.type_ == Fill::UNIVERSE) {
34,121✔
604
      int32_t next_univ = c.fill_;
5,036✔
605
      levels_below = std::max(levels_below, maximum_levels(next_univ));
5,036✔
606
    } else if (c.type_ == Fill::LATTICE) {
29,085✔
607
      Lattice& lat = *model::lattices[c.fill_];
2,007✔
608
      for (auto it = lat.begin(); it != lat.end(); ++it) {
920,112✔
609
        int32_t next_univ = *it;
918,105✔
610
        levels_below = std::max(levels_below, maximum_levels(next_univ));
918,105✔
611
      }
612
    }
613
  }
614

615
  ++levels_below;
19,206✔
616
  model::universe_level_counts[univ] = levels_below;
19,206✔
617
  return levels_below;
19,206✔
618
}
619

620
bool is_root_universe(int32_t univ_id)
16,882✔
621
{
622
  return model::universe_map[univ_id] == model::root_universe;
16,882✔
623
}
624

625
//==============================================================================
626

627
void free_memory_geometry()
8,194✔
628
{
629
  model::cells.clear();
8,194✔
630
  model::cell_map.clear();
8,194✔
631

632
  model::universes.clear();
8,194✔
633
  model::universe_map.clear();
8,194✔
634

635
  model::lattices.clear();
8,194✔
636
  model::lattice_map.clear();
8,194✔
637

638
  model::overlap_check_count.clear();
8,194✔
639
}
8,194✔
640

641
} // namespace openmc
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

© 2025 Coveralls, Inc