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

openmc-dev / openmc / 20368472998

19 Dec 2025 11:20AM UTC coverage: 82.143% (+0.004%) from 82.139%
20368472998

Pull #3566

github

web-flow
Merge a657bcb6c into a230b8612
Pull Request #3566: Resolve merge conflicts for PR #3516 - Implement Virtual Lattice Method for Efficient Simulation of Dispersed Fuels

17200 of 23810 branches covered (72.24%)

Branch coverage included in aggregate %.

266 of 322 new or added lines in 9 files covered. (82.61%)

2 existing lines in 1 file now uncovered.

55371 of 64537 relevant lines covered (85.8%)

43403485.97 hits per line

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

81.04
/src/geometry.cpp
1
#include "openmc/geometry.h"
2

3
#include <fmt/core.h>
4
#include <fmt/ostream.h>
5

6
#include "openmc/array.h"
7
#include "openmc/cell.h"
8
#include "openmc/constants.h"
9
#include "openmc/error.h"
10
#include "openmc/lattice.h"
11
#include "openmc/settings.h"
12
#include "openmc/simulation.h"
13
#include "openmc/string_utils.h"
14
#include "openmc/surface.h"
15

16
namespace openmc {
17

18
//==============================================================================
19
// Global variables
20
//==============================================================================
21

22
namespace model {
23

24
int root_universe {-1};
25
int n_coord_levels;
26

27
vector<int64_t> overlap_check_count;
28

29
} // namespace model
30

31
//==============================================================================
32
// Non-member functions
33
//==============================================================================
34

35
bool check_cell_overlap(GeometryState& p, bool error)
1,321,100✔
36
{
37
  int n_coord = p.n_coord();
1,321,100✔
38

39
  // Loop through each coordinate level
40
  for (int j = 0; j < n_coord; j++) {
2,267,892✔
41
    Universe& univ = *model::universes[p.coord(j).universe()];
1,321,100✔
42

43
    // Loop through each cell on this level
44
    for (auto index_cell : univ.cells_) {
4,468,992✔
45
      Cell& c = *model::cells[index_cell];
3,522,200✔
46
      if (c.contains(p.coord(j).r(), p.coord(j).u(), p.surface())) {
3,522,200✔
47
        if (index_cell != p.coord(j).cell()) {
1,250,854✔
48
          if (error) {
374,308!
49
            fatal_error(
×
50
              fmt::format("Overlapping cells detected: {}, {} on universe {}",
×
51
                c.id_, model::cells[p.coord(j).cell()]->id_, univ.id_));
×
52
          }
53
          return true;
374,308✔
54
        }
55
#pragma omp atomic
478,116✔
56
        ++model::overlap_check_count[index_cell];
876,546✔
57
      }
58
    }
59
  }
60

61
  return false;
946,792✔
62
}
63

64
//==============================================================================
65

66
int cell_instance_at_level(const GeometryState& p, int level)
2,147,483,647✔
67
{
68
  // throw error if the requested level is too deep for the geometry
69
  if (level > model::n_coord_levels) {
2,147,483,647!
70
    fatal_error(fmt::format("Cell instance at level {} requested, but only {} "
×
71
                            "levels exist in the geometry.",
72
      level, p.n_coord()));
73
  }
74

75
  // determine the cell instance
76
  Cell& c {*model::cells[p.coord(level).cell()]};
2,147,483,647✔
77

78
  // quick exit if this cell doesn't have distribcell instances
79
  if (c.distribcell_index_ == C_NONE)
2,147,483,647!
80
    return C_NONE;
×
81

82
  // compute the cell's instance
83
  int instance = 0;
2,147,483,647✔
84
  for (int i = 0; i < level; i++) {
2,147,483,647✔
85
    const auto& c_i {*model::cells[p.coord(i).cell()]};
2,061,993,813✔
86
    if (c_i.type_ == Fill::UNIVERSE) {
2,061,993,813✔
87
      instance += c_i.offset_[c.distribcell_index_];
860,749,337✔
88
    } else if (c_i.type_ == Fill::LATTICE) {
1,201,244,476!
89
      instance += c_i.offset_[c.distribcell_index_];
1,201,244,476✔
90
      auto& lat {*model::lattices[p.coord(i + 1).lattice()]};
1,201,244,476✔
91
      const auto& i_xyz {p.coord(i + 1).lattice_index()};
1,201,244,476✔
92
      if (lat.are_valid_indices(i_xyz)) {
1,201,244,476✔
93
        instance += lat.offset(c.distribcell_index_, i_xyz);
1,196,360,509✔
94
      }
95
    }
96
  }
97
  return instance;
2,147,483,647✔
98
}
99

100
//==============================================================================
101

102
bool find_cell_inner(
2,147,483,647✔
103
  GeometryState& p, const NeighborList* neighbor_list, bool verbose)
104
{
105
  // Find which cell of this universe the particle is in.  Use the neighbor list
106
  // to shorten the search if one was provided.
107
  bool found = false;
2,147,483,647✔
108
  int32_t i_cell = C_NONE;
2,147,483,647✔
109
  if (neighbor_list) {
2,147,483,647✔
110
    for (auto it = neighbor_list->cbegin(); it != neighbor_list->cend(); ++it) {
1,765,241,788✔
111
      i_cell = *it;
1,763,642,008✔
112

113
      // Make sure the search cell is in the same universe.
114
      int i_universe = p.lowest_coord().universe();
1,763,642,008✔
115
      if (model::cells[i_cell]->universe_ != i_universe)
1,763,642,008!
116
        continue;
×
117

118
      // Check if this cell contains the particle.
119
      Position r {p.r_local()};
1,763,642,008✔
120
      Direction u {p.u_local()};
1,763,642,008✔
121
      auto surf = p.surface();
1,763,642,008✔
122
      if (model::cells[i_cell]->contains(r, u, surf)) {
1,763,642,008✔
123
        p.lowest_coord().cell() = i_cell;
1,434,854,759✔
124
        found = true;
1,434,854,759✔
125
        break;
1,434,854,759✔
126
      }
127
    }
128

129
    // If we're attempting a neighbor list search and fail, we
130
    // now know we should return false. This will trigger an
131
    // exhaustive search from neighbor_list_find_cell and make
132
    // the result from that be appended to the neighbor list.
133
    if (!found) {
1,436,454,539✔
134
      return found;
1,599,780✔
135
    }
136
  }
137

138
  // Check successively lower coordinate levels until finding material fill
139
  for (;; ++p.n_coord()) {
688,148,904✔
140
    // If we did not attempt to use neighbor lists, i_cell is still C_NONE.  In
141
    // that case, we should now do an exhaustive search to find the right value
142
    // of i_cell.
143
    //
144
    // Alternatively, neighbor list searches could have succeeded, but we found
145
    // that the fill of the neighbor cell was another universe. As such, in the
146
    // code below this conditional, we set i_cell back to C_NONE to indicate
147
    // that.
148
    if (i_cell == C_NONE) {
2,147,483,647✔
149
      int i_universe = p.lowest_coord().universe();
1,559,548,840✔
150
      const auto& univ {model::universes[i_universe]};
1,559,548,840✔
151
      found = univ->find_cell(p);
1,559,548,840✔
152
    }
153

154
    if (!found) {
2,147,483,647✔
155
      return found;
173,105,957✔
156
    }
157
    i_cell = p.lowest_coord().cell();
2,147,483,647✔
158

159
    // Announce the cell that the particle is entering.
160
    if (found && verbose) {
2,147,483,647!
161
      auto msg = fmt::format("    Entering cell {}", model::cells[i_cell]->id_);
×
162
      write_message(msg, 1);
×
163
    }
×
164

165
    Cell& c {*model::cells[i_cell]};
2,147,483,647✔
166
    if (c.type_ == Fill::MATERIAL) {
2,147,483,647✔
167
      // Found a material cell which means this is the lowest coord level.
168

169
      p.cell_instance() = 0;
2,147,483,647✔
170
      // Find the distribcell instance number.
171
      if (c.distribcell_index_ >= 0) {
2,147,483,647✔
172
        p.cell_instance() = cell_instance_at_level(p, p.n_coord() - 1);
2,147,483,647✔
173
      }
174

175
      // Set the material, temperature and density multiplier.
176
      p.material_last() = p.material();
2,147,483,647✔
177
      p.material() = c.material(p.cell_instance());
2,147,483,647✔
178
      p.sqrtkT_last() = p.sqrtkT();
2,147,483,647✔
179
      p.sqrtkT() = c.sqrtkT(p.cell_instance());
2,147,483,647✔
180
      p.density_mult_last() = p.density_mult();
2,147,483,647✔
181
      p.density_mult() = c.density_mult(p.cell_instance());
2,147,483,647✔
182

183
      return true;
2,147,483,647✔
184

185
    } else if (c.type_ == Fill::UNIVERSE) {
344,074,452✔
186
      //========================================================================
187
      //! Found a lower universe, update this coord level then search the next.
188

189
      // Set the lower coordinate level universe.
190
      auto& coord {p.coord(p.n_coord())};
197,475,578✔
191
      coord.universe() = c.fill_;
197,475,578✔
192

193
      // Set the position and direction.
194
      coord.r() = p.r_local();
197,475,578✔
195
      coord.u() = p.u_local();
197,475,578✔
196

197
      // Apply translation.
198
      coord.r() -= c.translation_;
197,475,578✔
199

200
      // Apply rotation.
201
      if (!c.rotation_.empty()) {
197,475,578✔
202
        coord.rotate(c.rotation_);
2,211,858✔
203
      }
204

205
    } else if (c.type_ == Fill::LATTICE) {
146,598,874!
206
      //========================================================================
207
      //! Found a lower lattice, update this coord level then search the next.
208

209
      Lattice& lat {*model::lattices[c.fill_]};
146,598,874✔
210

211
      // Set the position and direction.
212
      auto& coord {p.coord(p.n_coord())};
146,598,874✔
213
      coord.r() = p.r_local();
146,598,874✔
214
      coord.u() = p.u_local();
146,598,874✔
215

216
      // Apply translation.
217
      coord.r() -= c.translation_;
146,598,874✔
218

219
      // Apply rotation.
220
      if (!c.rotation_.empty()) {
146,598,874✔
221
        coord.rotate(c.rotation_);
358,336✔
222
      }
223

224
      // Determine lattice indices.
225
      auto& i_xyz {coord.lattice_index()};
146,598,874✔
226
      lat.get_indices(coord.r(), coord.u(), i_xyz);
146,598,874✔
227

228
      // Get local position in appropriate lattice cell
229
      coord.r() = lat.get_local_position(coord.r(), i_xyz);
146,598,874✔
230

231
      // Set lattice indices.
232
      coord.lattice() = c.fill_;
146,598,874✔
233

234
      // Set the lower coordinate level universe.
235
      if (lat.are_valid_indices(i_xyz)) {
146,598,874✔
236
        coord.universe() = lat[i_xyz];
141,714,907✔
237
      } else {
238
        if (lat.outer_ != NO_OUTER_UNIVERSE) {
4,883,967!
239
          coord.universe() = lat.outer_;
4,883,967✔
240
        } else {
241
          p.mark_as_lost(fmt::format(
×
242
            "Particle {} left lattice {}, but it has no outer definition.",
243
            p.id(), lat.id_));
×
244
        }
245
      }
246
    }
247
    i_cell = C_NONE; // trip non-neighbor cell search at next iteration
344,074,452✔
248
    found = false;
344,074,452✔
249
  }
344,074,452✔
250

251
  return found;
252
}
253

254
//==============================================================================
255

256
bool neighbor_list_find_cell(GeometryState& p, bool verbose)
1,436,454,539✔
257
{
258

259
  // Reset all the deeper coordinate levels.
260
  for (int i = p.n_coord(); i < model::n_coord_levels; i++) {
2,142,445,095✔
261
    p.coord(i).reset();
705,990,556✔
262
  }
263

264
  // Get the cell this particle was in previously.
265
  auto coord_lvl = p.n_coord() - 1;
1,436,454,539✔
266
  auto i_cell = p.coord(coord_lvl).cell();
1,436,454,539✔
267
  Cell& c {*model::cells[i_cell]};
1,436,454,539✔
268

269
  // Search for the particle in that cell's neighbor list.  Return if we
270
  // found the particle.
271
  bool found = find_cell_inner(p, &c.neighbors_, verbose);
1,436,454,539✔
272
  if (found)
1,436,454,539✔
273
    return found;
1,434,854,759✔
274

275
  // The particle could not be found in the neighbor list.  Try searching all
276
  // cells in this universe, and update the neighbor list if we find a new
277
  // neighboring cell.
278
  found = find_cell_inner(p, nullptr, verbose);
1,599,780✔
279
  if (found)
1,599,780✔
280
    c.neighbors_.push_back(p.coord(coord_lvl).cell());
28,857✔
281
  return found;
1,599,780✔
282
}
283

284
bool exhaustive_find_cell(GeometryState& p, bool verbose)
1,213,874,608✔
285
{
286
  int i_universe = p.lowest_coord().universe();
1,213,874,608✔
287
  if (i_universe == C_NONE) {
1,213,874,608✔
288
    p.coord(0).universe() = model::root_universe;
276,327,545✔
289
    p.n_coord() = 1;
276,327,545✔
290
    i_universe = model::root_universe;
276,327,545✔
291
  }
292
  // Reset all the deeper coordinate levels.
293
  for (int i = p.n_coord(); i < model::n_coord_levels; i++) {
1,289,087,488✔
294
    p.coord(i).reset();
75,212,880✔
295
  }
296
  return find_cell_inner(p, nullptr, verbose);
1,213,874,608✔
297
}
298

299
bool find_cell_in_virtual_lattice(GeometryState& p, bool verbose)
2,357,630✔
300
{
301
  int i_surface = std::abs(p.surface());
2,357,630✔
302
  if (p.surface() > 0) {
2,357,630✔
303
    for (int i = p.n_coord(); i < model::n_coord_levels; i++) {
2,356,596✔
304
      p.coord(i).reset();
1,178,298✔
305
    }
306
    p.coord(p.n_coord() - 1).cell() =
1,178,298✔
307
      model::cell_map[model::surfaces[i_surface - 1]->triso_base_index_];
1,178,298✔
308
  } else if (p.surface() < 0) {
1,179,332!
309
    for (int i = p.n_coord(); i < model::n_coord_levels; i++) {
2,358,664✔
310
      p.coord(i).reset();
1,179,332✔
311
    }
312
    if (model::surfaces[i_surface - 1]->triso_particle_index_ == -1) {
1,179,332!
NEW
313
      fatal_error(fmt::format("Particle cell of surface {} is not defined",
×
NEW
314
        model::surfaces[i_surface - 1]->id_));
×
315
    }
316
    p.lowest_coord().cell() =
1,179,332✔
317
      model::cell_map[model::surfaces[i_surface - 1]->triso_particle_index_];
1,179,332✔
318
  }
319

320
  // find material
321
  bool found = true;
2,357,630✔
322
  int i_cell = p.lowest_coord().cell();
2,357,630✔
323
  for (;; ++p.n_coord()) {
1,179,332✔
324
    if (i_cell == C_NONE) {
3,536,962✔
325
      int i_universe = p.lowest_coord().universe();
1,179,332✔
326
      const auto& univ {model::universes[i_universe]};
1,179,332✔
327

328
      if (univ->filled_with_triso_base_ != -1) {
1,179,332!
NEW
329
        p.lowest_coord().cell() =
×
NEW
330
          model::cell_map[univ->filled_with_triso_base_];
×
NEW
331
        found = true;
×
332
      } else {
333
        found = univ->find_cell(p);
1,179,332✔
334
      }
335
      if (!found) {
1,179,332!
NEW
336
        return found;
×
337
      }
338
    }
339

340
    i_cell = p.lowest_coord().cell();
3,536,962✔
341

342
    Cell& c {*model::cells[i_cell]};
3,536,962✔
343
    if (c.type_ == Fill::MATERIAL) {
3,536,962✔
344
      // Found a material cell which means this is the lowest coord level.
345

346
      p.cell_instance() = 0;
2,357,630✔
347
      // Find the distribcell instance number.
348
      if (c.distribcell_index_ >= 0) {
2,357,630!
349
        p.cell_instance() = cell_instance_at_level(p, p.n_coord() - 1);
2,357,630✔
350
      }
351

352
      // Set the material and temperature.
353
      p.material_last() = p.material();
2,357,630✔
354
      if (c.material_.size() > 1) {
2,357,630!
NEW
355
        p.material() = c.material_[p.cell_instance()];
×
356
      } else {
357
        p.material() = c.material_[0];
2,357,630✔
358
      }
359
      p.sqrtkT_last() = p.sqrtkT();
2,357,630✔
360
      if (c.sqrtkT_.size() > 1) {
2,357,630!
NEW
361
        p.sqrtkT() = c.sqrtkT_[p.cell_instance()];
×
362
      } else {
363
        p.sqrtkT() = c.sqrtkT_[0];
2,357,630✔
364
      }
365
      return found;
2,357,630✔
366

367
    } else if (c.type_ == Fill::UNIVERSE) {
1,179,332!
368
      //========================================================================
369
      //! Found a lower universe, update this coord level then search the
370
      //! next.
371

372
      // Set the lower coordinate level universe.
373
      auto& coor {p.coord(p.n_coord())};
1,179,332✔
374
      coor.universe() = c.fill_;
1,179,332✔
375

376
      // Set the position and direction.
377
      coor.r() = p.r_local();
1,179,332✔
378
      coor.u() = p.u_local();
1,179,332✔
379

380
      // Apply translation.
381
      coor.r() -= c.translation_;
1,179,332✔
382

383
      // Apply rotation.
384
      if (!c.rotation_.empty()) {
1,179,332!
NEW
385
        coor.rotate(c.rotation_);
×
386
      }
387
      i_cell = C_NONE;
1,179,332✔
388
    }
389
  }
1,179,332✔
390
}
391
//==============================================================================
392

393
void cross_lattice(GeometryState& p, const BoundaryInfo& boundary, bool verbose)
718,776,219✔
394
{
395
  auto& coord {p.lowest_coord()};
718,776,219✔
396
  auto& lat {*model::lattices[coord.lattice()]};
718,776,219✔
397

398
  if (verbose) {
718,776,219!
399
    write_message(
×
400
      fmt::format("    Crossing lattice {}. Current position ({},{},{}). r={}",
×
401
        lat.id_, coord.lattice_index()[0], coord.lattice_index()[1],
×
402
        coord.lattice_index()[2], p.r()),
×
403
      1);
404
  }
405

406
  // Set the lattice indices.
407
  coord.lattice_index()[0] += boundary.lattice_translation()[0];
718,776,219✔
408
  coord.lattice_index()[1] += boundary.lattice_translation()[1];
718,776,219✔
409
  coord.lattice_index()[2] += boundary.lattice_translation()[2];
718,776,219✔
410

411
  // Set the new coordinate position.
412
  const auto& upper_coord {p.coord(p.n_coord() - 2)};
718,776,219✔
413
  const auto& cell {model::cells[upper_coord.cell()]};
718,776,219✔
414
  Position r = upper_coord.r();
718,776,219✔
415
  r -= cell->translation_;
718,776,219✔
416
  if (!cell->rotation_.empty()) {
718,776,219✔
417
    r = r.rotate(cell->rotation_);
471,647✔
418
  }
419
  p.r_local() = lat.get_local_position(r, coord.lattice_index());
718,776,219✔
420

421
  if (!lat.are_valid_indices(coord.lattice_index())) {
718,776,219✔
422
    // The particle is outside the lattice.  Search for it from the base coords.
423
    p.n_coord() = 1;
3,714,425✔
424
    bool found = exhaustive_find_cell(p);
3,714,425✔
425

426
    if (!found) {
3,714,425!
427
      p.mark_as_lost(fmt::format("Particle {} could not be located after "
×
428
                                 "crossing a boundary of lattice {}",
429
        p.id(), lat.id_));
×
430
    }
431

432
  } else {
433
    // Find cell in next lattice element.
434
    p.lowest_coord().universe() = lat[coord.lattice_index()];
715,061,794✔
435
    bool found = exhaustive_find_cell(p);
715,061,794✔
436

437
    if (!found) {
715,061,794!
438
      // A particle crossing the corner of a lattice tile may not be found.  In
439
      // this case, search for it from the base coords.
440
      p.n_coord() = 1;
×
441
      bool found = exhaustive_find_cell(p);
×
442
      if (!found) {
×
443
        p.mark_as_lost(fmt::format("Particle {} could not be located after "
×
444
                                   "crossing a boundary of lattice {}",
445
          p.id(), lat.id_));
×
446
      }
447
    }
448
  }
449
}
718,776,219✔
450

451
//==============================================================================
452

453
BoundaryInfo distance_to_boundary(GeometryState& p)
2,147,483,647✔
454
{
455
  BoundaryInfo info;
2,147,483,647✔
456
  double d_lat = INFINITY;
2,147,483,647✔
457
  double d_surf = INFINITY;
2,147,483,647✔
458
  int32_t level_surf_cross;
459
  array<int, 3> level_lat_trans {};
2,147,483,647✔
460

461
  // Loop over each coordinate level.
462
  for (int i = 0; i < p.n_coord(); i++) {
2,147,483,647✔
463
    const auto& coord {p.coord(i)};
2,147,483,647✔
464
    const Position& r {coord.r()};
2,147,483,647✔
465
    const Direction& u {coord.u()};
2,147,483,647✔
466
    Cell& c {*model::cells[coord.cell()]};
2,147,483,647✔
467

468
    // Find the oncoming surface in this cell and the distance to it.
469
    auto surface_distance = c.distance(r, u, p.surface(), &p);
2,147,483,647✔
470
    d_surf = surface_distance.first;
2,147,483,647✔
471
    level_surf_cross = surface_distance.second;
2,147,483,647✔
472

473
    // Find the distance to the next lattice tile crossing.
474
    if (coord.lattice() != C_NONE) {
2,147,483,647✔
475
      auto& lat {*model::lattices[coord.lattice()]};
1,258,539,338✔
476
      // TODO: refactor so both lattice use the same position argument (which
477
      // also means the lat.type attribute can be removed)
478
      std::pair<double, array<int, 3>> lattice_distance;
1,258,539,338✔
479
      switch (lat.type_) {
1,258,539,338!
480
      case LatticeType::rect:
1,173,036,041✔
481
        lattice_distance = lat.distance(r, u, coord.lattice_index());
1,173,036,041✔
482
        break;
1,173,036,041✔
483
      case LatticeType::hex:
85,503,297✔
484
        auto& cell_above {model::cells[p.coord(i - 1).cell()]};
85,503,297✔
485
        Position r_hex {p.coord(i - 1).r()};
85,503,297✔
486
        r_hex -= cell_above->translation_;
85,503,297✔
487
        if (coord.rotated()) {
85,503,297✔
488
          r_hex = r_hex.rotate(cell_above->rotation_);
701,954✔
489
        }
490
        r_hex.z = coord.r().z;
85,503,297✔
491
        lattice_distance = lat.distance(r_hex, u, coord.lattice_index());
85,503,297✔
492
        break;
85,503,297✔
493
      }
494
      d_lat = lattice_distance.first;
1,258,539,338✔
495
      level_lat_trans = lattice_distance.second;
1,258,539,338✔
496

497
      if (d_lat < 0) {
1,258,539,338!
498
        p.mark_as_lost(fmt::format("Particle {} had a negative distance "
×
499
                                   "to a lattice boundary.",
500
          p.id()));
×
501
      }
502
    }
503

504
    // If the boundary on this coordinate level is coincident with a boundary on
505
    // a higher level then we need to make sure that the higher level boundary
506
    // is selected.  This logic must consider floating point precision.
507
    double& d = info.distance();
2,147,483,647✔
508
    if (d_surf < d_lat - FP_COINCIDENT) {
2,147,483,647✔
509
      if (d == INFINITY || (d - d_surf) / d >= FP_REL_PRECISION) {
2,147,483,647✔
510
        // Update closest distance
511
        d = d_surf;
2,147,483,647✔
512

513
        // If the cell is not simple, it is possible that both the negative and
514
        // positive half-space were given in the region specification. Thus, we
515
        // have to explicitly check which half-space the particle would be
516
        // traveling into if the surface is crossed
517
        if (c.is_simple() || d == INFTY) {
2,147,483,647✔
518
          info.surface() = level_surf_cross;
2,147,483,647✔
519
        } else {
520
          Position r_hit = r + d_surf * u;
12,866,965✔
521
          Surface& surf {*model::surfaces[std::abs(level_surf_cross) - 1]};
12,866,965✔
522
          Direction norm = surf.normal(r_hit);
12,866,965✔
523
          if (u.dot(norm) > 0) {
12,866,965✔
524
            info.surface() = std::abs(level_surf_cross);
6,365,733✔
525
          } else {
526
            info.surface() = -std::abs(level_surf_cross);
6,501,232✔
527
          }
528
        }
529

530
        info.lattice_translation()[0] = 0;
2,147,483,647✔
531
        info.lattice_translation()[1] = 0;
2,147,483,647✔
532
        info.lattice_translation()[2] = 0;
2,147,483,647✔
533
        info.coord_level() = i + 1;
2,147,483,647✔
534
      }
535
    } else {
536
      if (d == INFINITY || (d - d_lat) / d >= FP_REL_PRECISION) {
1,025,314,935!
537
        d = d_lat;
825,450,171✔
538
        info.surface() = SURFACE_NONE;
825,450,171✔
539
        info.lattice_translation() = level_lat_trans;
825,450,171✔
540
        info.coord_level() = i + 1;
825,450,171✔
541
      }
542
    }
543
  }
544
  return info;
2,147,483,647✔
545
}
546

547
//==============================================================================
548
// C API
549
//==============================================================================
550

551
extern "C" int openmc_find_cell(
600,308✔
552
  const double* xyz, int32_t* index, int32_t* instance)
553
{
554
  GeometryState geom_state;
600,308✔
555

556
  geom_state.r() = Position {xyz};
600,308✔
557
  geom_state.u() = {0.0, 0.0, 1.0};
600,308✔
558

559
  if (!exhaustive_find_cell(geom_state)) {
600,308✔
560
    set_errmsg(
11✔
561
      fmt::format("Could not find cell at position {}.", geom_state.r()));
31✔
562
    return OPENMC_E_GEOMETRY;
11✔
563
  }
564

565
  *index = geom_state.lowest_coord().cell();
600,297✔
566
  *instance = geom_state.cell_instance();
600,297✔
567
  return 0;
600,297✔
568
}
600,308✔
569

570
extern "C" int openmc_global_bounding_box(double* llc, double* urc)
11✔
571
{
572
  auto bbox = model::universes.at(model::root_universe)->bounding_box();
11✔
573

574
  // set lower left corner values
575
  llc[0] = bbox.xmin;
11✔
576
  llc[1] = bbox.ymin;
11✔
577
  llc[2] = bbox.zmin;
11✔
578

579
  // set upper right corner values
580
  urc[0] = bbox.xmax;
11✔
581
  urc[1] = bbox.ymax;
11✔
582
  urc[2] = bbox.zmax;
11✔
583

584
  return 0;
11✔
585
}
586

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