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

openmc-dev / openmc / 18299973882

07 Oct 2025 02:14AM UTC coverage: 81.92% (-3.3%) from 85.194%
18299973882

push

github

web-flow
Switch to using coveralls github action for reporting (#3594)

16586 of 23090 branches covered (71.83%)

Branch coverage included in aggregate %.

53703 of 62712 relevant lines covered (85.63%)

43428488.21 hits per line

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

84.42
/src/universe.cpp
1
#include "openmc/universe.h"
2

3
#include <set>
4

5
#include "openmc/hdf5_interface.h"
6
#include "openmc/particle.h"
7

8
namespace openmc {
9

10
namespace model {
11

12
std::unordered_map<int32_t, int32_t> universe_map;
13
vector<unique_ptr<Universe>> universes;
14

15
} // namespace model
16

17
//==============================================================================
18
// Universe implementation
19
//==============================================================================
20

21
void Universe::to_hdf5(hid_t universes_group) const
16,008✔
22
{
23
  // Create a group for this universe.
24
  auto group = create_group(universes_group, fmt::format("universe {}", id_));
32,016✔
25

26
  // Write the geometry representation type.
27
  write_string(group, "geom_type", "csg", false);
16,008✔
28

29
  // Write the contained cells.
30
  if (cells_.size() > 0) {
16,008!
31
    vector<int32_t> cell_ids;
16,008✔
32
    for (auto i_cell : cells_)
43,116✔
33
      cell_ids.push_back(model::cells[i_cell]->id_);
27,108✔
34
    write_dataset(group, "cells", cell_ids);
16,008✔
35
  }
16,008✔
36

37
  close_group(group);
16,008✔
38
}
16,008✔
39

40
bool Universe::find_cell(GeometryState& p) const
1,577,876,960✔
41
{
42
  const auto& cells {
43
    !partitioner_ ? cells_ : partitioner_->get_cells(p.r_local(), p.u_local())};
1,577,876,960✔
44

45
  Position r {p.r_local()};
1,577,876,960✔
46
  Position u {p.u_local()};
1,577,876,960✔
47
  auto surf = p.surface();
1,577,876,960✔
48
  int32_t i_univ = p.lowest_coord().universe();
1,577,876,960✔
49

50
  for (auto i_cell : cells) {
2,147,483,647✔
51
    if (model::cells[i_cell]->universe_ != i_univ)
2,044,760,207!
52
      continue;
×
53
    // Check if this cell contains the particle
54
    if (model::cells[i_cell]->contains(r, u, surf)) {
2,044,760,207✔
55
      p.lowest_coord().cell() = i_cell;
1,404,728,600✔
56
      return true;
1,404,728,600✔
57
    }
58
  }
59
  return false;
173,148,360✔
60
}
61

62
BoundingBox Universe::bounding_box() const
15✔
63
{
64
  BoundingBox bbox = {INFTY, -INFTY, INFTY, -INFTY, INFTY, -INFTY};
15✔
65
  if (cells_.size() == 0) {
15!
66
    return {};
×
67
  } else {
68
    for (const auto& cell : cells_) {
60✔
69
      auto& c = model::cells[cell];
45✔
70
      bbox |= c->bounding_box();
45✔
71
    }
72
  }
73
  return bbox;
15✔
74
}
75

76
//==============================================================================
77
// UniversePartitioner implementation
78
//==============================================================================
79

80
UniversePartitioner::UniversePartitioner(const Universe& univ)
96✔
81
{
82
  // Define an ordered set of surface indices that point to z-planes.  Use a
83
  // functor to to order the set by the z0_ values of the corresponding planes.
84
  struct compare_surfs {
85
    bool operator()(const int32_t& i_surf, const int32_t& j_surf) const
9,872✔
86
    {
87
      const auto* surf = model::surfaces[i_surf].get();
9,872✔
88
      const auto* zplane = dynamic_cast<const SurfaceZPlane*>(surf);
9,872!
89
      double zi = zplane->z0_;
9,872✔
90
      surf = model::surfaces[j_surf].get();
9,872✔
91
      zplane = dynamic_cast<const SurfaceZPlane*>(surf);
9,872!
92
      double zj = zplane->z0_;
9,872✔
93
      return zi < zj;
9,872✔
94
    }
95
  };
96
  std::set<int32_t, compare_surfs> surf_set;
96✔
97

98
  // Find all of the z-planes in this universe.  A set is used here for the
99
  // O(log(n)) insertions that will ensure entries are not repeated.
100
  for (auto i_cell : univ.cells_) {
1,344✔
101
    for (auto token : model::cells[i_cell]->surfaces()) {
5,520✔
102
      auto i_surf = std::abs(token) - 1;
4,272✔
103
      const auto* surf = model::surfaces[i_surf].get();
4,272✔
104
      if (const auto* zplane = dynamic_cast<const SurfaceZPlane*>(surf))
4,272!
105
        surf_set.insert(i_surf);
2,432✔
106
    }
1,248✔
107
  }
108

109
  // Populate the surfs_ vector from the ordered set.
110
  surfs_.insert(surfs_.begin(), surf_set.begin(), surf_set.end());
96✔
111

112
  // Populate the partition lists.
113
  partitions_.resize(surfs_.size() + 1);
96✔
114
  for (auto i_cell : univ.cells_) {
1,344✔
115
    // It is difficult to determine the bounds of a complex cell, so add complex
116
    // cells to all partitions.
117
    if (!model::cells[i_cell]->is_simple()) {
1,248!
118
      for (auto& p : partitions_)
×
119
        p.push_back(i_cell);
×
120
      continue;
×
121
    }
×
122

123
    // Find the tokens for bounding z-planes.
124
    int32_t lower_token = 0, upper_token = 0;
1,248✔
125
    double min_z, max_z;
126
    for (auto token : model::cells[i_cell]->surfaces()) {
5,520✔
127
      const auto* surf = model::surfaces[std::abs(token) - 1].get();
4,272✔
128
      if (const auto* zplane = dynamic_cast<const SurfaceZPlane*>(surf)) {
4,272!
129
        if (lower_token == 0 || zplane->z0_ < min_z) {
2,432!
130
          lower_token = token;
1,248✔
131
          min_z = zplane->z0_;
1,248✔
132
        }
133
        if (upper_token == 0 || zplane->z0_ > max_z) {
2,432!
134
          upper_token = token;
2,432✔
135
          max_z = zplane->z0_;
2,432✔
136
        }
137
      }
138
    }
1,248✔
139

140
    // If there are no bounding z-planes, add this cell to all partitions.
141
    if (lower_token == 0) {
1,248!
142
      for (auto& p : partitions_)
×
143
        p.push_back(i_cell);
×
144
      continue;
×
145
    }
×
146

147
    // Find the first partition this cell lies in.  If the lower_token indicates
148
    // a negative halfspace, then the cell is unbounded in the lower direction
149
    // and it lies in the first partition onward.  Otherwise, it is bounded by
150
    // the positive halfspace given by the lower_token.
151
    int first_partition = 0;
1,248✔
152
    if (lower_token > 0) {
1,248✔
153
      for (int i = 0; i < surfs_.size(); ++i) {
4,624!
154
        if (lower_token == surfs_[i] + 1) {
4,624✔
155
          first_partition = i + 1;
1,216✔
156
          break;
1,216✔
157
        }
158
      }
159
    }
160

161
    // Find the last partition this cell lies in.  The logic is analogous to the
162
    // logic for first_partition.
163
    int last_partition = surfs_.size();
1,248✔
164
    if (upper_token < 0) {
1,248✔
165
      for (int i = first_partition; i < surfs_.size(); ++i) {
2,624!
166
        if (upper_token == -(surfs_[i] + 1)) {
2,624✔
167
          last_partition = i;
1,216✔
168
          break;
1,216✔
169
        }
170
      }
171
    }
172

173
    // Add the cell to all relevant partitions.
174
    for (int i = first_partition; i <= last_partition; ++i) {
3,920✔
175
      partitions_[i].push_back(i_cell);
2,672✔
176
    }
177
  }
178
}
96✔
179

180
const vector<int32_t>& UniversePartitioner::get_cells(
247,445✔
181
  Position r, Direction u) const
182
{
183
  // Perform a binary search for the partition containing the given coordinates.
184
  int left = 0;
247,445✔
185
  int middle = (surfs_.size() - 1) / 2;
247,445✔
186
  int right = surfs_.size() - 1;
247,445✔
187
  while (true) {
188
    // Check the sense of the coordinates for the current surface.
189
    const auto& surf = *model::surfaces[surfs_[middle]];
742,362✔
190
    if (surf.sense(r, u)) {
742,362✔
191
      // The coordinates lie in the positive halfspace.  Recurse if there are
192
      // more surfaces to check.  Otherwise, return the cells on the positive
193
      // side of this surface.
194
      int right_leaf = right - (right - middle) / 2;
286,217✔
195
      if (right_leaf != middle) {
286,217✔
196
        left = middle + 1;
248,264✔
197
        middle = right_leaf;
248,264✔
198
      } else {
199
        return partitions_[middle + 1];
37,953✔
200
      }
201

202
    } else {
203
      // The coordinates lie in the negative halfspace.  Recurse if there are
204
      // more surfaces to check.  Otherwise, return the cells on the negative
205
      // side of this surface.
206
      int left_leaf = left + (middle - left) / 2;
456,145✔
207
      if (left_leaf != middle) {
456,145✔
208
        right = middle - 1;
246,653✔
209
        middle = left_leaf;
246,653✔
210
      } else {
211
        return partitions_[middle];
209,492✔
212
      }
213
    }
214
  }
494,917✔
215
}
216

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