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

openmc-dev / openmc / 22742746807

06 Mar 2026 12:15AM UTC coverage: 81.559% (+0.05%) from 81.51%
22742746807

Pull #3845

github

web-flow
Merge 803bea659 into 6f7261972
Pull Request #3845: Refactor Ray class into its own file

17542 of 25251 branches covered (69.47%)

Branch coverage included in aggregate %.

50 of 57 new or added lines in 2 files covered. (87.72%)

653 existing lines in 14 files now uncovered.

57938 of 67295 relevant lines covered (86.1%)

44805457.91 hits per line

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

71.93
/src/ray.cpp
1
#include "openmc/ray.h"
2

3
#include "openmc/error.h"
4
#include "openmc/geometry.h"
5
#include "openmc/settings.h"
6

7
namespace openmc {
8

9
void Ray::compute_distance()
3,014,638✔
10
{
11
  boundary() = distance_to_boundary(*this);
3,014,638✔
12
}
3,014,638✔
13

14
void Ray::trace()
3,521,056✔
15
{
16
  // To trace the ray from its origin all the way through the model, we have
17
  // to proceed in two phases. In the first, the ray may or may not be found
18
  // inside the model. If the ray is already in the model, phase one can be
19
  // skipped. Otherwise, the ray has to be advanced to the boundary of the
20
  // model where all the cells are defined. Importantly, this is assuming that
21
  // the model is convex, which is a very reasonable assumption for any
22
  // radiation transport model.
23
  //
24
  // After phase one is done, we can starting tracing from cell to cell within
25
  // the model. This step can use neighbor lists to accelerate the ray tracing.
26

27
  bool inside_cell;
3,521,056✔
28
  // Check for location if the particle is already known
29
  if (lowest_coord().cell() == C_NONE) {
3,521,056!
30
    // The geometry position of the particle is either unknown or outside of the
31
    // edge of the model.
32
    if (lowest_coord().universe() == C_NONE) {
3,521,056!
33
      // Attempt to initialize the particle. We may have to
34
      // enter a loop to move it up to the edge of the model.
35
      inside_cell = exhaustive_find_cell(*this, settings::verbosity >= 10);
3,521,056✔
36
    } else {
37
      // It has been already calculated that the current position is outside of
38
      // the edge of the model.
39
      inside_cell = false;
40
    }
41
  } else {
42
    // Availability of the cell means that the particle is located inside the
43
    // edge.
44
    inside_cell = true;
45
  }
46

47
  // Advance to the boundary of the model
48
  while (!inside_cell) {
15,618,438!
49
    advance_to_boundary_from_void();
15,618,438✔
50
    inside_cell = exhaustive_find_cell(*this, settings::verbosity >= 10);
15,618,438✔
51

52
    // If true this means no surface was intersected. See cell.cpp and search
53
    // for numeric_limits to see where we return it.
54
    if (surface() == std::numeric_limits<int>::max()) {
15,618,438!
NEW
55
      warning(fmt::format("Lost a ray, r = {}, u = {}", r(), u()));
×
NEW
56
      return;
×
57
    }
58

59
    // Exit this loop and enter into cell-to-cell ray tracing (which uses
60
    // neighbor lists)
61
    if (inside_cell)
15,618,438✔
62
      break;
63

64
    // if there is no intersection with the model, we're done
65
    if (boundary().surface() == SURFACE_NONE)
14,068,604✔
66
      return;
67

68
    event_counter_++;
12,097,382✔
69
    if (event_counter_ > MAX_INTERSECTIONS) {
12,097,382!
NEW
70
      warning("Likely infinite loop in ray traced plot");
×
NEW
71
      return;
×
72
    }
73
  }
74

75
  // Call the specialized logic for this type of ray. This is for the
76
  // intersection for the first intersection if we had one.
77
  if (boundary().surface() != SURFACE_NONE) {
1,549,834!
78
    // set the geometry state's surface attribute to be used for
79
    // surface normal computation
80
    surface() = boundary().surface();
1,549,834✔
81
    on_intersection();
1,549,834✔
82
    if (stop_)
1,549,834!
83
      return;
84
  }
85

86
  // reset surface attribute to zero after the first intersection so that it
87
  // doesn't perturb surface crossing logic from here on out
88
  surface() = 0;
1,549,834✔
89

90
  // This is the ray tracing loop within the model. It exits after exiting
91
  // the model, which is equivalent to assuming that the model is convex.
92
  // It would be nice to factor out the on_intersection at the end of this
93
  // loop and then do "while (inside_cell)", but we can't guarantee it's
94
  // on a surface in that case. There might be some other way to set it
95
  // up that is perhaps a little more elegant, but this is what works just
96
  // fine.
97
  while (true) {
2,308,570✔
98

99
    compute_distance();
2,308,570✔
100

101
    // There are no more intersections to process
102
    // if we hit the edge of the model, so stop
103
    // the particle in that case. Also, just exit
104
    // if a negative distance was somehow computed.
105
    if (boundary().distance() == INFTY || boundary().distance() == INFINITY ||
2,308,570!
106
        boundary().distance() < 0) {
2,308,570!
107
      return;
108
    }
109

110
    // See below comment where call_on_intersection is checked in an
111
    // if statement for an explanation of this.
112
    bool call_on_intersection {true};
2,308,570✔
113
    if (boundary().distance() < 10 * TINY_BIT) {
2,308,570✔
114
      call_on_intersection = false;
593,285✔
115
    }
116

117
    // DAGMC surfaces expect us to go a little bit further than the advance
118
    // distance to properly check cell inclusion.
119
    boundary().distance() += TINY_BIT;
2,308,570✔
120

121
    // Advance particle, prepare for next intersection
122
    for (int lev = 0; lev < n_coord(); ++lev) {
4,617,140✔
123
      coord(lev).r() += boundary().distance() * coord(lev).u();
2,308,570✔
124
    }
125
    surface() = boundary().surface();
2,308,570✔
126
    // Initialize last cells from the current cell, because the cell() variable
127
    // does not contain the data for the case of a single-segment ray
128
    for (int j = 0; j < n_coord(); ++j) {
4,617,140✔
129
      cell_last(j) = coord(j).cell();
2,308,570✔
130
    }
131
    n_coord_last() = n_coord();
2,308,570✔
132
    n_coord() = boundary().coord_level();
2,308,570!
133
    if (boundary().lattice_translation()[0] != 0 ||
2,308,570!
134
        boundary().lattice_translation()[1] != 0 ||
2,308,570!
135
        boundary().lattice_translation()[2] != 0) {
2,308,570!
NEW
136
      cross_lattice(*this, boundary(), settings::verbosity >= 10);
×
137
    }
138

139
    // Record how far the ray has traveled
140
    traversal_distance_ += boundary().distance();
2,308,570✔
141
    inside_cell = neighbor_list_find_cell(*this, settings::verbosity >= 10);
2,308,570✔
142

143
    // Call the specialized logic for this type of ray. Note that we do not
144
    // call this if the advance distance is very small. Unfortunately, it seems
145
    // darn near impossible to get the particle advanced to the model boundary
146
    // and through it without sometimes accidentally calling on_intersection
147
    // twice. This incorrectly shades the region as occluded when it might not
148
    // actually be. By screening out intersection distances smaller than a
149
    // threshold 10x larger than the scoot distance used to advance up to the
150
    // model boundary, we can avoid that situation.
151
    if (call_on_intersection) {
2,308,570✔
152
      on_intersection();
1,715,285✔
153
      if (stop_)
1,715,285✔
154
        return;
155
    }
156

157
    if (!inside_cell)
2,273,007✔
158
      return;
159

160
    event_counter_++;
758,736✔
161
    if (event_counter_ > MAX_INTERSECTIONS) {
758,736!
NEW
162
      warning("Likely infinite loop in ray traced plot");
×
NEW
163
      return;
×
164
    }
165
  }
166
}
167

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

© 2026 Coveralls, Inc