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

openmc-dev / openmc / 33875847135

04 Sep 2026 01:02PM UTC coverage: 81.319% (-0.07%) from 81.388%
33875847135

Pull #3881

github

web-flow
Merge 33358e4a2 into 4cf988693
Pull Request #3881: Implement ParticleRay class

18688 of 27195 branches covered (68.72%)

Branch coverage included in aggregate %.

11 of 32 new or added lines in 2 files covered. (34.38%)

3109 existing lines in 96 files now uncovered.

60518 of 70207 relevant lines covered (86.2%)

49996815.21 hits per line

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

74.42
/src/event.cpp
1
#include "openmc/event.h"
2

3
#include "openmc/bank.h"
4
#include "openmc/error.h"
5
#include "openmc/material.h"
6
#include "openmc/settings.h"
7
#include "openmc/simulation.h"
8
#include "openmc/timer.h"
9

10
namespace openmc {
11

12
//==============================================================================
13
// Global variables
14
//==============================================================================
15

16
namespace simulation {
17

18
SharedArray<EventQueueItem> calculate_fuel_xs_queue;
19
SharedArray<EventQueueItem> calculate_nonfuel_xs_queue;
20
SharedArray<EventQueueItem> advance_particle_queue;
21
SharedArray<EventQueueItem> surface_crossing_queue;
22
SharedArray<EventQueueItem> collision_queue;
23

24
vector<Particle> particles;
25

26
} // namespace simulation
27

28
//==============================================================================
29
// Non-member functions
30
//==============================================================================
31

32
void init_event_queues(int64_t n_particles)
278 ✔
33
{
34
  simulation::calculate_fuel_xs_queue.reserve(n_particles);
278 ✔
35
  simulation::calculate_nonfuel_xs_queue.reserve(n_particles);
278 ✔
36
  simulation::advance_particle_queue.reserve(n_particles);
278 ✔
37
  simulation::surface_crossing_queue.reserve(n_particles);
278 ✔
38
  simulation::collision_queue.reserve(n_particles);
278 ✔
39

40
  simulation::particles.resize(n_particles);
278 ✔
41
}
278 ✔
42

43
void free_event_queues(void)
×
44
{
45
  simulation::calculate_fuel_xs_queue.clear();
×
46
  simulation::calculate_nonfuel_xs_queue.clear();
×
UNCOV
47
  simulation::advance_particle_queue.clear();
×
48
  simulation::surface_crossing_queue.clear();
×
49
  simulation::collision_queue.clear();
×
50

UNCOV
51
  simulation::particles.clear();
×
UNCOV
52
}
×
53

54
void dispatch_xs_event(int64_t buffer_idx)
232,894,070 ✔
55
{
56
  Particle& p = simulation::particles[buffer_idx];
232,894,070 ✔
57
  if (p.material() == MATERIAL_VOID ||
232,894,070 ✔
58
      !model::materials[p.material()]->fissionable()) {
218,608,182 ✔
59
    simulation::calculate_nonfuel_xs_queue.thread_safe_append({p, buffer_idx});
53,890,395 ✔
60
  } else {
61
    simulation::calculate_fuel_xs_queue.thread_safe_append({p, buffer_idx});
179,003,675 ✔
62
  }
63
}
232,894,070 ✔
64

65
void process_init_events(int64_t n_particles, int64_t source_offset)
3,262 ✔
66
{
67
  simulation::time_event_init.start();
3,262 ✔
68
#pragma omp parallel for schedule(runtime)
3,262 ✔
69
  for (int64_t i = 0; i < n_particles; i++) {
×
70
    initialize_particle_track(
71
      simulation::particles[i], source_offset + i + 1, false);
72
    dispatch_xs_event(i);
73
  }
74
  simulation::time_event_init.stop();
3,262 ✔
75
}
3,262 ✔
76

77
void process_calculate_xs_events(SharedArray<EventQueueItem>& queue)
1,399,658 ✔
78
{
79
  simulation::time_event_calculate_xs.start();
1,399,658 ✔
80

81
  // TODO: If using C++17, we could perform a parallel sort of the queue by
82
  // particle type, material type, and then energy, in order to improve cache
83
  // locality and reduce thread divergence on GPU. However, the parallel
84
  // algorithms typically require linking against an additional library (Intel
85
  // TBB). Prior to C++17, std::sort is a serial only operation, which in this
86
  // case makes it too slow to be practical for most test problems.
87
  //
88
  // std::sort(std::execution::par_unseq, queue.data(), queue.data() +
89
  // queue.size());
90

91
  int64_t offset = simulation::advance_particle_queue.size();
1,399,658 ✔
92

93
#pragma omp parallel for schedule(runtime)
1,399,658 ✔
94
  for (int64_t i = 0; i < queue.size(); i++) {
×
95
    Particle* p = &simulation::particles[queue[i].idx];
96
    p->event_calculate_xs();
97

98
    // After executing a calculate_xs event, particles will
99
    // always require an advance event. Therefore, we don't need to use
100
    // the protected enqueuing function.
101
    simulation::advance_particle_queue[offset + i] = queue[i];
102
  }
103

104
  simulation::advance_particle_queue.resize(offset + queue.size());
1,399,658 ✔
105

106
  queue.resize(0);
1,399,658 ✔
107

108
  simulation::time_event_calculate_xs.stop();
1,399,658 ✔
109
}
1,399,658 ✔
110

111
void process_advance_particle_events()
1,394,677 ✔
112
{
113
  simulation::time_event_advance_particle.start();
1,394,677 ✔
114

115
#pragma omp parallel for schedule(runtime)
1,394,677 ✔
116
  for (int64_t i = 0; i < simulation::advance_particle_queue.size(); i++) {
×
117
    int64_t buffer_idx = simulation::advance_particle_queue[i].idx;
118
    Particle& p = simulation::particles[buffer_idx];
119
    p.event_advance();
120
    if (!p.alive())
×
121
      continue;
122
    if (p.collision_distance() > p.boundary().distance()) {
×
123
      simulation::surface_crossing_queue.thread_safe_append({p, buffer_idx});
124
    } else {
125
      simulation::collision_queue.thread_safe_append({p, buffer_idx});
126
    }
127
  }
128

129
  simulation::advance_particle_queue.resize(0);
1,394,677 ✔
130

131
  simulation::time_event_advance_particle.stop();
1,394,677 ✔
132
}
1,394,677 ✔
133

134
void process_surface_crossing_events()
267,710 ✔
135
{
136
  simulation::time_event_surface_crossing.start();
267,710 ✔
137

138
#pragma omp parallel for schedule(runtime)
267,710 ✔
139
  for (int64_t i = 0; i < simulation::surface_crossing_queue.size(); i++) {
×
140
    int64_t buffer_idx = simulation::surface_crossing_queue[i].idx;
141
    Particle& p = simulation::particles[buffer_idx];
142
    p.event_cross_surface();
143
    p.event_check_limit_and_revive();
144
    if (p.alive())
×
145
      dispatch_xs_event(buffer_idx);
146
  }
147

148
  simulation::surface_crossing_queue.resize(0);
267,710 ✔
149

150
  simulation::time_event_surface_crossing.stop();
267,710 ✔
151
}
267,710 ✔
152

153
void process_collision_events()
1,147,400 ✔
154
{
155
  simulation::time_event_collision.start();
1,147,400 ✔
156

157
#pragma omp parallel for schedule(runtime)
1,147,400 ✔
158
  for (int64_t i = 0; i < simulation::collision_queue.size(); i++) {
×
159
    int64_t buffer_idx = simulation::collision_queue[i].idx;
160
    Particle& p = simulation::particles[buffer_idx];
161
    p.event_collide();
162
    p.event_check_limit_and_revive();
163
    if (p.alive())
×
164
      dispatch_xs_event(buffer_idx);
165
  }
166

167
  simulation::collision_queue.resize(0);
1,147,400 ✔
168

169
  simulation::time_event_collision.stop();
1,147,400 ✔
170
}
1,147,400 ✔
171

172
void process_death_events(int64_t n_particles)
3,946 ✔
173
{
174
  simulation::time_event_death.start();
3,946 ✔
175
#pragma omp parallel for schedule(runtime)
3,946 ✔
176
  for (int64_t i = 0; i < n_particles; i++) {
×
177
    Particle& p = simulation::particles[i];
178
    p.event_death();
179
  }
180
  simulation::time_event_death.stop();
3,946 ✔
181
}
3,946 ✔
182

183
void process_transport_events()
3,946 ✔
184
{
185
  while (true) {
4,213,391 ✔
186
    int64_t max = std::max({simulation::calculate_fuel_xs_queue.size(),
4,213,391 ✔
187
      simulation::calculate_nonfuel_xs_queue.size(),
4,213,391 ✔
188
      simulation::advance_particle_queue.size(),
4,213,391 ✔
189
      simulation::surface_crossing_queue.size(),
4,213,391 ✔
190
      simulation::collision_queue.size()});
4,213,391 ✔
191

192
    if (max == 0) {
4,213,391 ✔
193
      break;
194
    } else if (max == simulation::calculate_fuel_xs_queue.size()) {
4,209,445 ✔
195
      process_calculate_xs_events(simulation::calculate_fuel_xs_queue);
466,311 ✔
196
    } else if (max == simulation::calculate_nonfuel_xs_queue.size()) {
3,743,134 ✔
197
      process_calculate_xs_events(simulation::calculate_nonfuel_xs_queue);
933,347 ✔
198
    } else if (max == simulation::advance_particle_queue.size()) {
2,809,787 ✔
199
      process_advance_particle_events();
1,394,677 ✔
200
    } else if (max == simulation::surface_crossing_queue.size()) {
1,415,110 ✔
201
      process_surface_crossing_events();
267,710 ✔
202
    } else if (max == simulation::collision_queue.size()) {
1,147,400 !
203
      process_collision_events();
1,147,400 ✔
204
    }
205
  }
206
}
3,946 ✔
207

208
void process_init_secondary_events(int64_t n_particles, int64_t offset,
684 ✔
209
  const SharedArray<SourceSite>& shared_secondary_bank)
210
{
211
  simulation::time_event_init.start();
684 ✔
212
#pragma omp parallel for schedule(runtime)
684 ✔
213
  for (int64_t i = 0; i < n_particles; i++) {
×
214
    initialize_particle_track(simulation::particles[i], offset + i + 1, true);
215
    const SourceSite& site = shared_secondary_bank[offset + i];
216
    simulation::particles[i].event_revive_from_secondary(site);
217
    if (simulation::particles[i].alive()) {
×
218
      dispatch_xs_event(i);
219
    }
220
  }
221
  simulation::time_event_init.stop();
684 ✔
222
}
684 ✔
223

224
} // namespace openmc
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc