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

openmc-dev / openmc / 13860705201

14 Mar 2025 04:10PM UTC coverage: 84.925% (-0.1%) from 85.042%
13860705201

Pull #3305

github

web-flow
Merge f02782e46 into 906548db2
Pull Request #3305: New Feature Development: The Implementation of chord length sampling (CLS) method for stochastic media( #3286 )

20 of 161 new or added lines in 8 files covered. (12.42%)

1010 existing lines in 44 files now uncovered.

51574 of 60729 relevant lines covered (84.92%)

36935786.37 hits per line

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

89.15
/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/stochastic_media.h"
21
#include "openmc/surface.h"
22
#include "openmc/tallies/filter.h"
23
#include "openmc/tallies/filter_cell_instance.h"
24
#include "openmc/tallies/filter_distribcell.h"
25

26
namespace openmc {
27

28
namespace model {
29
std::unordered_map<int32_t, std::unordered_map<int32_t, int32_t>>
30
  universe_cell_counts;
31
std::unordered_map<int32_t, int32_t> universe_level_counts;
32
} // namespace model
33

34
// adds the cell counts of universe b to universe a
35
void update_universe_cell_count(int32_t a, int32_t b)
856,450✔
36
{
37
  auto& universe_a_counts = model::universe_cell_counts[a];
856,450✔
38
  const auto& universe_b_counts = model::universe_cell_counts[b];
856,450✔
39
  for (const auto& it : universe_b_counts) {
2,432,677✔
40
    universe_a_counts[it.first] += it.second;
1,576,227✔
41
  }
42
}
856,450✔
43

44
void read_geometry_xml()
1,320✔
45
{
46
  // Display output message
47
  write_message("Reading geometry XML file...", 5);
1,320✔
48

49
  // Check if geometry.xml exists
50
  std::string filename = settings::path_input + "geometry.xml";
1,320✔
51
  if (!file_exists(filename)) {
1,320✔
52
    fatal_error("Geometry XML file '" + filename + "' does not exist!");
×
53
  }
54

55
  // Parse settings.xml file
56
  pugi::xml_document doc;
1,320✔
57
  auto result = doc.load_file(filename.c_str());
1,320✔
58
  if (!result) {
1,320✔
59
    fatal_error("Error processing geometry.xml file.");
×
60
  }
61

62
  // Get root element
63
  pugi::xml_node root = doc.document_element();
1,320✔
64

65
  read_geometry_xml(root);
1,320✔
66
}
1,320✔
67

68
void read_geometry_xml(pugi::xml_node root)
6,370✔
69
{
70
  // Read surfaces, cells, lattice, and stochastic media
71
  read_surfaces(root);
6,370✔
72
  read_cells(root);
6,370✔
73
  read_lattices(root);
6,368✔
74
  read_stochastic_media(root);
6,368✔
75

76
  // Check to make sure a boundary condition was applied to at least one
77
  // surface
78
  bool boundary_exists = false;
6,368✔
79
  for (const auto& surf : model::surfaces) {
16,171✔
80
    if (surf->bc_) {
16,138✔
81
      boundary_exists = true;
6,335✔
82
      break;
6,335✔
83
    }
84
  }
85

86
  if (settings::run_mode != RunMode::PLOTTING &&
6,368✔
87
      settings::run_mode != RunMode::VOLUME && !boundary_exists) {
6,095✔
88
    fatal_error("No boundary conditions were applied to any surfaces!");
×
89
  }
90

91
  // Allocate universes, universe cell arrays, and assign base universe
92
  model::root_universe = find_root_universe();
6,368✔
93

94
  // if the root universe is DAGMC geometry, make sure the model is well-formed
95
  check_dagmc_root_univ();
6,368✔
96
}
6,368✔
97

98
//==============================================================================
99

100
void adjust_indices()
6,370✔
101
{
102
  // Adjust material/fill idices.
103
  for (auto& c : model::cells) {
36,895✔
104
    if (c->fill_ != C_NONE) {
30,525✔
105
      int32_t id = c->fill_;
6,596✔
106
      auto search_univ = model::universe_map.find(id);
6,596✔
107
      auto search_lat = model::lattice_map.find(id);
6,596✔
108
      auto search_media = model::stochastic_media_map.find(id);
6,596✔
109
      if (search_univ != model::universe_map.end()) {
6,596✔
110
        c->type_ = Fill::UNIVERSE;
4,954✔
111
        c->fill_ = search_univ->second;
4,954✔
112
      } else if (search_lat != model::lattice_map.end()) {
1,642✔
113
        c->type_ = Fill::LATTICE;
1,642✔
114
        c->fill_ = search_lat->second;
1,642✔
NEW
115
      } else if (search_media != model::stochastic_media_map.end()) {
×
NEW
116
        c->type_ = Fill::STOCHASTIC_MEDIA;
×
NEW
117
        c->fill_ = search_media->second;
×
118
      } else {
NEW
119
        fatal_error(fmt::format("Specified fill {} on cell {} must be one of  "
×
120
                                "universe  lattice and stochastic media.",
UNCOV
121
          id, c->id_));
×
122
      }
123
    } else {
124
      c->type_ = Fill::MATERIAL;
23,929✔
125
      for (auto& mat_id : c->material_) {
49,323✔
126
        if (mat_id != MATERIAL_VOID) {
25,394✔
127
          auto search = model::material_map.find(mat_id);
17,206✔
128
          if (search == model::material_map.end()) {
17,206✔
129
            fatal_error(
×
130
              fmt::format("Could not find material {} specified on cell {}",
×
131
                mat_id, c->id_));
×
132
          }
133
          // Change from ID to index
134
          mat_id = search->second;
17,206✔
135
        }
136
      }
137
    }
138
  }
139

140
  // Change cell.universe values from IDs to indices.
141
  for (auto& c : model::cells) {
36,895✔
142
    auto search = model::universe_map.find(c->universe_);
30,525✔
143
    if (search != model::universe_map.end()) {
30,525✔
144
      c->universe_ = search->second;
30,525✔
145
    } else {
146
      fatal_error(fmt::format("Could not find universe {} specified on cell {}",
×
147
        c->universe_, c->id_));
×
148
    }
149
  }
150

151
  // Change all lattice universe values from IDs to indices.
152
  for (auto& l : model::lattices) {
7,979✔
153
    l->adjust_indices();
1,609✔
154
  }
155

156
  for (auto& media : model::stochastic_media)
6,370✔
157
  {
NEW
158
    media->adjust_indices();
×
159
  }
160
}
6,370✔
161

162
//==============================================================================
163
//! Partition some universes with many z-planes for faster find_cell searches.
164

165
void partition_universes()
6,370✔
166
{
167
  // Iterate over universes with more than 10 cells.  (Fewer than 10 is likely
168
  // not worth partitioning.)
169
  for (const auto& univ : model::universes) {
23,827✔
170
    if (univ->cells_.size() > 10) {
17,457✔
171
      // Collect the set of surfaces in this universe.
172
      std::unordered_set<int32_t> surf_inds;
182✔
173
      for (auto i_cell : univ->cells_) {
3,064✔
174
        for (auto token : model::cells[i_cell]->surfaces()) {
10,920✔
175
          surf_inds.insert(std::abs(token) - 1);
8,038✔
176
        }
2,882✔
177
      }
178

179
      // Partition the universe if there are more than 5 z-planes.  (Fewer than
180
      // 5 is likely not worth it.)
181
      int n_zplanes = 0;
182✔
182
      for (auto i_surf : surf_inds) {
2,342✔
183
        if (dynamic_cast<const SurfaceZPlane*>(model::surfaces[i_surf].get())) {
2,256✔
184
          ++n_zplanes;
640✔
185
          if (n_zplanes > 5) {
640✔
186
            univ->partitioner_ = make_unique<UniversePartitioner>(*univ);
96✔
187
            break;
96✔
188
          }
189
        }
190
      }
191
    }
182✔
192
  }
193
}
6,370✔
194

195
//==============================================================================
196

197
void assign_temperatures()
6,370✔
198
{
199
  for (auto& c : model::cells) {
36,895✔
200
    // Ignore non-material cells and cells with defined temperature.
201
    if (c->material_.size() == 0) {
30,525✔
202
      if (c->type_ != Fill::STOCHASTIC_MEDIA)
6,596✔
203
        continue;
6,596✔
NEW
204
      c->sqrtkT_.reserve(1);
×
205

NEW
206
      auto fill_idx = model::stochastic_media_map[c->fill_];
×
NEW
207
      auto mat_id {model::stochastic_media[fill_idx]->particle_mat()[0]};
×
NEW
208
      const auto& mat {model::materials[mat_id]};
×
NEW
209
      c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * mat->temperature()));
×
210
    }
211
    if (c->sqrtkT_.size() > 0)
23,929✔
212
      continue;
428✔
213

214
    c->sqrtkT_.reserve(c->material_.size());
23,501✔
215
    for (auto i_mat : c->material_) {
48,458✔
216
      if (i_mat == MATERIAL_VOID) {
24,957✔
217
        // Set void region to 0K.
218
        c->sqrtkT_.push_back(0);
8,188✔
219
      } else {
220
        const auto& mat {model::materials[i_mat]};
16,769✔
221
        c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * mat->temperature()));
16,769✔
222
      }
223
    }
224
  }
225
}
6,370✔
226

227
//==============================================================================
228

229
void get_temperatures(
6,097✔
230
  vector<vector<double>>& nuc_temps, vector<vector<double>>& thermal_temps)
231
{
232
  for (const auto& cell : model::cells) {
36,067✔
233
    // Skip non-material cells.
234
    if (cell->fill_ != C_NONE)
29,970✔
235
      continue;
6,585✔
236

237
    for (int j = 0; j < cell->material_.size(); ++j) {
48,235✔
238
      // Skip void materials
239
      int i_material = cell->material_[j];
24,850✔
240
      if (i_material == MATERIAL_VOID)
24,850✔
241
        continue;
8,078✔
242

243
      // Get temperature(s) of cell (rounding to nearest integer)
244
      vector<double> cell_temps;
16,772✔
245
      if (cell->sqrtkT_.size() == 1) {
16,772✔
246
        double sqrtkT = cell->sqrtkT_[0];
15,124✔
247
        cell_temps.push_back(sqrtkT * sqrtkT / K_BOLTZMANN);
15,124✔
248
      } else if (cell->sqrtkT_.size() == cell->material_.size()) {
1,648✔
249
        double sqrtkT = cell->sqrtkT_[j];
1,632✔
250
        cell_temps.push_back(sqrtkT * sqrtkT / K_BOLTZMANN);
1,632✔
251
      } else {
252
        for (double sqrtkT : cell->sqrtkT_)
80✔
253
          cell_temps.push_back(sqrtkT * sqrtkT / K_BOLTZMANN);
64✔
254
      }
255

256
      const auto& mat {model::materials[i_material]};
16,772✔
257
      for (const auto& i_nuc : mat->nuclide_) {
81,616✔
258
        for (double temperature : cell_temps) {
129,736✔
259
          // Add temperature if it hasn't already been added
260
          if (!contains(nuc_temps[i_nuc], temperature))
64,892✔
261
            nuc_temps[i_nuc].push_back(temperature);
25,680✔
262
        }
263
      }
264

265
      for (const auto& table : mat->thermal_tables_) {
19,775✔
266
        // Get index in data::thermal_scatt array
267
        int i_sab = table.index_table;
3,003✔
268

269
        for (double temperature : cell_temps) {
6,006✔
270
          // Add temperature if it hasn't already been added
271
          if (!contains(thermal_temps[i_sab], temperature))
3,003✔
272
            thermal_temps[i_sab].push_back(temperature);
1,008✔
273
        }
274
      }
275
    }
16,772✔
276
  }
277
}
6,097✔
278

279
//==============================================================================
280

281
void finalize_geometry()
6,370✔
282
{
283
  // Perform some final operations to set up the geometry
284
  adjust_indices();
6,370✔
285
  count_cell_instances(model::root_universe);
6,370✔
286
  partition_universes();
6,370✔
287

288
  // Assign temperatures to cells that don't have temperatures already assigned
289
  assign_temperatures();
6,370✔
290

291
  // Determine number of nested coordinate levels in the geometry
292
  model::n_coord_levels = maximum_levels(model::root_universe);
6,370✔
293
}
6,370✔
294

295
//==============================================================================
296

297
int32_t find_root_universe()
6,370✔
298
{
299
  // Find all the universes listed as a cell fill.
300
  std::unordered_set<int32_t> fill_univ_ids;
6,370✔
301
  for (const auto& c : model::cells) {
36,895✔
302
    fill_univ_ids.insert(c->fill_);
30,525✔
303
  }
304

305
  // Find all the universes contained in a lattice.
306
  for (const auto& lat : model::lattices) {
7,979✔
307
    for (auto it = lat->begin(); it != lat->end(); ++it) {
852,940✔
308
      fill_univ_ids.insert(*it);
851,331✔
309
    }
310
    if (lat->outer_ != NO_OUTER_UNIVERSE) {
1,609✔
311
      fill_univ_ids.insert(lat->outer_);
246✔
312
    }
313
  }
314

315
  // Figure out which universe is not in the set.  This is the root universe.
316
  bool root_found {false};
6,370✔
317
  int32_t root_univ;
318
  for (int32_t i = 0; i < model::universes.size(); i++) {
23,827✔
319
    auto search = fill_univ_ids.find(model::universes[i]->id_);
17,457✔
320
    if (search == fill_univ_ids.end()) {
17,457✔
321
      if (root_found) {
6,370✔
322
        fatal_error("Two or more universes are not used as fill universes, so "
×
323
                    "it is not possible to distinguish which one is the root "
324
                    "universe.");
325
      } else {
326
        root_found = true;
6,370✔
327
        root_univ = i;
6,370✔
328
      }
329
    }
330
  }
331
  if (!root_found)
6,370✔
332
    fatal_error("Could not find a root universe.  Make sure "
×
333
                "there are no circular dependencies in the geometry.");
334

335
  return root_univ;
6,370✔
336
}
6,370✔
337

338
//==============================================================================
339

340
void prepare_distribcell(const std::vector<int32_t>* user_distribcells)
6,384✔
341
{
342
  write_message("Preparing distributed cell instances...", 5);
6,384✔
343

344
  std::unordered_set<int32_t> distribcells;
6,384✔
345

346
  // start with any cells manually specified via the C++ API
347
  if (user_distribcells) {
6,384✔
348
    distribcells.insert(user_distribcells->begin(), user_distribcells->end());
16✔
349
  }
350

351
  // Find all cells listed in a DistribcellFilter or CellInstanceFilter
352
  for (auto& filt : model::tally_filters) {
13,675✔
353
    auto* distrib_filt = dynamic_cast<DistribcellFilter*>(filt.get());
7,291✔
354
    auto* cell_inst_filt = dynamic_cast<CellInstanceFilter*>(filt.get());
7,291✔
355
    if (distrib_filt) {
7,291✔
356
      distribcells.insert(distrib_filt->cell());
177✔
357
    }
358
    if (cell_inst_filt) {
7,291✔
359
      const auto& filter_cells = cell_inst_filt->cells();
34✔
360
      distribcells.insert(filter_cells.begin(), filter_cells.end());
34✔
361
    }
362
  }
363

364
  // By default, add material cells to the list of distributed cells
365
  if (settings::material_cell_offsets) {
6,384✔
366
    for (int64_t i = 0; i < model::cells.size(); ++i) {
36,979✔
367
      if (model::cells[i]->type_ == Fill::MATERIAL)
30,595✔
368
        distribcells.insert(i);
23,967✔
369
    }
370
  }
371

372
  // Make sure that the number of materials/temperatures matches the number of
373
  // cell instances.
374
  for (int i = 0; i < model::cells.size(); i++) {
36,979✔
375
    Cell& c {*model::cells[i]};
30,595✔
376

377
    if (c.material_.size() > 1) {
30,595✔
378
      if (c.material_.size() != c.n_instances_) {
195✔
379
        fatal_error(fmt::format(
×
380
          "Cell {} was specified with {} materials but has {} distributed "
381
          "instances. The number of materials must equal one or the number "
382
          "of instances.",
383
          c.id_, c.material_.size(), c.n_instances_));
×
384
      }
385
    }
386

387
    if (c.sqrtkT_.size() > 1) {
30,595✔
388
      if (c.sqrtkT_.size() != c.n_instances_) {
208✔
389
        fatal_error(fmt::format(
×
390
          "Cell {} was specified with {} temperatures but has {} distributed "
391
          "instances. The number of temperatures must equal one or the number "
392
          "of instances.",
393
          c.id_, c.sqrtkT_.size(), c.n_instances_));
×
394
      }
395
    }
396
  }
397

398
  // Search through universes for material cells and assign each one a
399
  // unique distribcell array index.
400
  int distribcell_index = 0;
6,384✔
401
  vector<int32_t> target_univ_ids;
6,384✔
402
  for (const auto& u : model::universes) {
23,887✔
403
    for (auto idx : u->cells_) {
48,098✔
404
      if (distribcells.find(idx) != distribcells.end()) {
30,595✔
405
        model::cells[idx]->distribcell_index_ = distribcell_index++;
24,047✔
406
        target_univ_ids.push_back(u->id_);
24,047✔
407
      }
408
    }
409
  }
410

411
  // Allocate the cell and lattice offset tables.
412
  int n_maps = target_univ_ids.size();
6,384✔
413
  for (auto& c : model::cells) {
36,979✔
414
    if (c->type_ != Fill::MATERIAL) {
30,595✔
415
      c->offset_.resize(n_maps, C_NONE);
6,628✔
416
    }
417
  }
418
  for (auto& lat : model::lattices) {
8,009✔
419
    lat->allocate_offset_table(n_maps);
1,625✔
420
  }
421

422
// Fill the cell and lattice offset tables.
423
#pragma omp parallel for
3,553✔
424
  for (int map = 0; map < target_univ_ids.size(); map++) {
10,755✔
425
    auto target_univ_id = target_univ_ids[map];
7,924✔
426
    std::unordered_map<int32_t, int32_t> univ_count_memo;
7,924✔
427
    for (const auto& univ : model::universes) {
38,574✔
428
      int32_t offset = 0;
30,650✔
429
      for (int32_t cell_indx : univ->cells_) {
159,043✔
430
        Cell& c = *model::cells[cell_indx];
128,393✔
431

432
        if (c.type_ == Fill::UNIVERSE) {
128,393✔
433
          c.offset_[map] = offset;
43,608✔
434
          int32_t search_univ = c.fill_;
43,608✔
435
          offset += count_universe_instances(
43,608✔
436
            search_univ, target_univ_id, univ_count_memo);
437

438
        } else if (c.type_ == Fill::LATTICE) {
84,785✔
439
          c.offset_[map] = offset;
6,888✔
440
          Lattice& lat = *model::lattices[c.fill_];
6,888✔
441
          offset +=
6,888✔
442
            lat.fill_offset_table(offset, target_univ_id, map, univ_count_memo);
6,888✔
443
        }
444
      }
445
    }
446
  }
7,924✔
447
}
6,384✔
448

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

451
void count_cell_instances(int32_t univ_indx)
862,820✔
452
{
453
  const auto univ_counts = model::universe_cell_counts.find(univ_indx);
862,820✔
454
  if (univ_counts != model::universe_cell_counts.end()) {
862,820✔
455
    for (const auto& it : univ_counts->second) {
2,395,445✔
456
      model::cells[it.first]->n_instances_ += it.second;
1,549,914✔
457
    }
458
  } else {
459
    for (int32_t cell_indx : model::universes[univ_indx]->cells_) {
47,638✔
460
      Cell& c = *model::cells[cell_indx];
30,349✔
461
      ++c.n_instances_;
30,349✔
462
      model::universe_cell_counts[univ_indx][cell_indx] += 1;
30,349✔
463

464
      if (c.type_ == Fill::UNIVERSE) {
30,349✔
465
        // This cell contains another universe.  Recurse into that universe.
466
        count_cell_instances(c.fill_);
4,954✔
467
        update_universe_cell_count(univ_indx, c.fill_);
4,954✔
468
      } else if (c.type_ == Fill::LATTICE) {
25,395✔
469
        // This cell contains a lattice.  Recurse into the lattice universes.
470
        Lattice& lat = *model::lattices[c.fill_];
1,642✔
471
        for (auto it = lat.begin(); it != lat.end(); ++it) {
853,138✔
472
          count_cell_instances(*it);
851,496✔
473
          update_universe_cell_count(univ_indx, *it);
851,496✔
474
        }
475
      }
476
    }
477
  }
478
}
862,820✔
479

480
//==============================================================================
481

482
int count_universe_instances(int32_t search_univ, int32_t target_univ_id,
15,593,425✔
483
  std::unordered_map<int32_t, int32_t>& univ_count_memo)
484
{
485
  // If this is the target, it can't contain itself.
486
  if (model::universes[search_univ]->id_ == target_univ_id) {
15,593,425✔
487
    return 1;
2,183,683✔
488
  }
489

490
  // If we have already counted the number of instances, reuse that value.
491
  auto search = univ_count_memo.find(search_univ);
13,409,742✔
492
  if (search != univ_count_memo.end()) {
13,409,742✔
493
    return search->second;
7,372,486✔
494
  }
495

496
  int count {0};
6,037,256✔
497
  for (int32_t cell_indx : model::universes[search_univ]->cells_) {
12,194,896✔
498
    Cell& c = *model::cells[cell_indx];
6,157,640✔
499

500
    if (c.type_ == Fill::UNIVERSE) {
6,157,640✔
501
      int32_t next_univ = c.fill_;
94,446✔
502
      count +=
94,446✔
503
        count_universe_instances(next_univ, target_univ_id, univ_count_memo);
94,446✔
504

505
    } else if (c.type_ == Fill::LATTICE) {
6,063,194✔
506
      Lattice& lat = *model::lattices[c.fill_];
7,538✔
507
      for (auto it = lat.begin(); it != lat.end(); ++it) {
3,397,522✔
508
        int32_t next_univ = *it;
3,389,984✔
509
        count +=
3,389,984✔
510
          count_universe_instances(next_univ, target_univ_id, univ_count_memo);
3,389,984✔
511
      }
512
    }
513
  }
514

515
  // Remember the number of instances in this universe.
516
  univ_count_memo[search_univ] = count;
6,037,256✔
517

518
  return count;
6,037,256✔
519
}
520

521
//==============================================================================
522

523
std::string distribcell_path_inner(int32_t target_cell, int32_t map,
2,565,486✔
524
  int32_t target_offset, const Universe& search_univ, int32_t offset)
525
{
526
  std::stringstream path;
2,565,486✔
527

528
  path << "u" << search_univ.id_ << "->";
2,565,486✔
529

530
  // Check to see if this universe directly contains the target cell.  If so,
531
  // write to the path and return.
532
  for (int32_t cell_indx : search_univ.cells_) {
11,902,803✔
533
    if ((cell_indx == target_cell) && (offset == target_offset)) {
10,264,320✔
534
      Cell& c = *model::cells[cell_indx];
927,003✔
535
      path << "c" << c.id_;
927,003✔
536
      return path.str();
1,854,006✔
537
    }
538
  }
539

540
  // The target must be further down the geometry tree and contained in a fill
541
  // cell or lattice cell in this universe.  Find which cell contains the
542
  // target.
543
  vector<std::int32_t>::const_reverse_iterator cell_it {
544
    search_univ.cells_.crbegin()};
1,638,483✔
545
  for (; cell_it != search_univ.cells_.crend(); ++cell_it) {
9,337,152✔
546
    Cell& c = *model::cells[*cell_it];
9,337,152✔
547

548
    // Material cells don't contain other cells so ignore them.
549
    if (c.type_ != Fill::MATERIAL) {
9,337,152✔
550
      int32_t temp_offset;
551
      if (c.type_ == Fill::UNIVERSE) {
2,338,512✔
552
        temp_offset =
×
553
          offset + c.offset_[map]; // TODO: should also apply to lattice fills?
×
554
      } else {
555
        Lattice& lat = *model::lattices[c.fill_];
2,338,512✔
556
        int32_t indx = lat.universes_.size() * map + lat.begin().indx_;
2,338,512✔
557
        temp_offset = offset + lat.offsets_[indx];
2,338,512✔
558
      }
559

560
      // The desired cell is the first cell that gives an offset smaller or
561
      // equal to the target offset.
562
      if (temp_offset <= target_offset - c.offset_[map])
2,338,512✔
563
        break;
1,638,483✔
564
    }
565
  }
566

567
  // if we get through the loop without finding an appropriate entry, throw
568
  // an error
569
  if (cell_it == search_univ.cells_.crend()) {
1,638,483✔
570
    fatal_error(
×
571
      fmt::format("Failed to generate a text label for distribcell with ID {}."
×
572
                  "The current label is: '{}'",
573
        model::cells[target_cell]->id_, path.str()));
×
574
  }
575

576
  // Add the cell to the path string.
577
  Cell& c = *model::cells[*cell_it];
1,638,483✔
578
  path << "c" << c.id_ << "->";
1,638,483✔
579

580
  if (c.type_ == Fill::UNIVERSE) {
1,638,483✔
581
    // Recurse into the fill cell.
582
    offset += c.offset_[map];
×
583
    path << distribcell_path_inner(
×
584
      target_cell, map, target_offset, *model::universes[c.fill_], offset);
×
585
    return path.str();
×
586
  } else {
587
    // Recurse into the lattice cell.
588
    Lattice& lat = *model::lattices[c.fill_];
1,638,483✔
589
    path << "l" << lat.id_;
1,638,483✔
590
    for (ReverseLatticeIter it = lat.rbegin(); it != lat.rend(); ++it) {
289,048,650✔
591
      int32_t indx = lat.universes_.size() * map + it.indx_;
289,048,650✔
592
      int32_t temp_offset = offset + lat.offsets_[indx];
289,048,650✔
593
      if (temp_offset <= target_offset - c.offset_[map]) {
289,048,650✔
594
        offset = temp_offset;
1,638,483✔
595
        path << "(" << lat.index_to_string(it.indx_) << ")->";
1,638,483✔
596
        path << distribcell_path_inner(target_cell, map, target_offset,
3,276,966✔
597
          *model::universes[*it], offset + c.offset_[map]);
3,276,966✔
598
        return path.str();
3,276,966✔
599
      }
600
    }
601
    throw std::runtime_error {"Error determining distribcell path."};
×
602
  }
603
}
2,565,486✔
604

605
std::string distribcell_path(
927,003✔
606
  int32_t target_cell, int32_t map, int32_t target_offset)
607
{
608
  auto& root_univ = *model::universes[model::root_universe];
927,003✔
609
  return distribcell_path_inner(target_cell, map, target_offset, root_univ, 0);
927,003✔
610
}
611

612
//==============================================================================
613

614
int maximum_levels(int32_t univ)
862,820✔
615
{
616

617
  const auto level_count = model::universe_level_counts.find(univ);
862,820✔
618
  if (level_count != model::universe_level_counts.end()) {
862,820✔
619
    return level_count->second;
845,531✔
620
  }
621

622
  int levels_below {0};
17,289✔
623

624
  for (int32_t cell_indx : model::universes[univ]->cells_) {
47,638✔
625
    Cell& c = *model::cells[cell_indx];
30,349✔
626
    if (c.type_ == Fill::UNIVERSE) {
30,349✔
627
      int32_t next_univ = c.fill_;
4,954✔
628
      levels_below = std::max(levels_below, maximum_levels(next_univ));
4,954✔
629
    } else if (c.type_ == Fill::LATTICE) {
25,395✔
630
      Lattice& lat = *model::lattices[c.fill_];
1,642✔
631
      for (auto it = lat.begin(); it != lat.end(); ++it) {
853,138✔
632
        int32_t next_univ = *it;
851,496✔
633
        levels_below = std::max(levels_below, maximum_levels(next_univ));
851,496✔
634
      }
635
    }
636
  }
637

638
  ++levels_below;
17,289✔
639
  model::universe_level_counts[univ] = levels_below;
17,289✔
640
  return levels_below;
17,289✔
641
}
642

643
bool is_root_universe(int32_t univ_id)
×
644
{
645
  return model::universe_map[univ_id] == model::root_universe;
×
646
}
647

648
//==============================================================================
649

650
void free_memory_geometry()
6,494✔
651
{
652
  model::cells.clear();
6,494✔
653
  model::cell_map.clear();
6,494✔
654

655
  model::universes.clear();
6,494✔
656
  model::universe_map.clear();
6,494✔
657

658
  model::lattices.clear();
6,494✔
659
  model::lattice_map.clear();
6,494✔
660

661
  model::stochastic_media.clear();
6,494✔
662
  model::stochastic_media_map.clear();
6,494✔
663

664
  model::overlap_check_count.clear();
6,494✔
665
}
6,494✔
666

667
} // 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