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

openmc-dev / openmc / 18538152141

15 Oct 2025 06:02PM UTC coverage: 81.97% (-3.2%) from 85.194%
18538152141

Pull #3417

github

web-flow
Merge 4604e1321 into e9077b137
Pull Request #3417: Addition of a collision tracking feature

16794 of 23357 branches covered (71.9%)

Branch coverage included in aggregate %.

480 of 522 new or added lines in 13 files covered. (91.95%)

457 existing lines in 53 files now uncovered.

54128 of 63165 relevant lines covered (85.69%)

42776927.64 hits per line

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

86.67
/src/collision_track.cpp
1
#include "openmc/collision_track.h"
2

3
#include <algorithm>
4
#include <string>
5

6
#include <fmt/format.h>
7

8
#include "openmc/bank.h"
9
#include "openmc/bank_io.h"
10
#include "openmc/cell.h"
11
#include "openmc/constants.h"
12
#include "openmc/error.h"
13
#include "openmc/file_utils.h"
14
#include "openmc/hdf5_interface.h"
15
#include "openmc/material.h"
16
#include "openmc/mcpl_interface.h"
17
#include "openmc/message_passing.h"
18
#include "openmc/nuclide.h"
19
#include "openmc/output.h"
20
#include "openmc/particle.h"
21
#include "openmc/settings.h"
22
#include "openmc/simulation.h"
23
#include "openmc/universe.h"
24

25
#ifdef OPENMC_MPI
26
#include <mpi.h>
27
#endif
28

29
namespace openmc {
30

31
namespace {
32

33
hid_t h5_collision_track_banktype()
144✔
34
{
35
  hid_t postype = H5Tcreate(H5T_COMPOUND, sizeof(Position));
144✔
36
  H5Tinsert(postype, "x", HOFFSET(Position, x), H5T_NATIVE_DOUBLE);
144✔
37
  H5Tinsert(postype, "y", HOFFSET(Position, y), H5T_NATIVE_DOUBLE);
144✔
38
  H5Tinsert(postype, "z", HOFFSET(Position, z), H5T_NATIVE_DOUBLE);
144✔
39

40
  hid_t banktype = H5Tcreate(H5T_COMPOUND, sizeof(CollisionTrackSite));
144✔
41

42
  H5Tinsert(banktype, "r", HOFFSET(CollisionTrackSite, r), postype);
144✔
43
  H5Tinsert(banktype, "u", HOFFSET(CollisionTrackSite, u), postype);
144✔
44
  H5Tinsert(banktype, "E", HOFFSET(CollisionTrackSite, E), H5T_NATIVE_DOUBLE);
144✔
45
  H5Tinsert(banktype, "dE", HOFFSET(CollisionTrackSite, dE), H5T_NATIVE_DOUBLE);
144✔
46
  H5Tinsert(
144✔
47
    banktype, "time", HOFFSET(CollisionTrackSite, time), H5T_NATIVE_DOUBLE);
144✔
48
  H5Tinsert(
144✔
49
    banktype, "wgt", HOFFSET(CollisionTrackSite, wgt), H5T_NATIVE_DOUBLE);
144✔
50
  H5Tinsert(banktype, "event_mt", HOFFSET(CollisionTrackSite, event_mt),
144✔
51
    H5T_NATIVE_INT);
144✔
52
  H5Tinsert(banktype, "delayed_group",
144✔
53
    HOFFSET(CollisionTrackSite, delayed_group), H5T_NATIVE_INT);
144✔
54
  H5Tinsert(
144✔
55
    banktype, "cell_id", HOFFSET(CollisionTrackSite, cell_id), H5T_NATIVE_INT);
144✔
56
  H5Tinsert(banktype, "nuclide_id", HOFFSET(CollisionTrackSite, nuclide_id),
144✔
57
    H5T_NATIVE_INT);
144✔
58
  H5Tinsert(banktype, "material_id", HOFFSET(CollisionTrackSite, material_id),
144✔
59
    H5T_NATIVE_INT);
144✔
60
  H5Tinsert(banktype, "universe_id", HOFFSET(CollisionTrackSite, universe_id),
144✔
61
    H5T_NATIVE_INT);
144✔
62
  H5Tinsert(banktype, "n_collision", HOFFSET(CollisionTrackSite, n_collision),
144✔
63
    H5T_NATIVE_INT);
144✔
64
  H5Tinsert(banktype, "particle", HOFFSET(CollisionTrackSite, particle),
144✔
65
    H5T_NATIVE_INT);
144✔
66
  H5Tinsert(banktype, "parent_id", HOFFSET(CollisionTrackSite, parent_id),
144✔
67
    H5T_NATIVE_INT64);
144✔
68
  H5Tinsert(banktype, "progeny_id", HOFFSET(CollisionTrackSite, progeny_id),
144✔
69
    H5T_NATIVE_INT64);
144✔
70
  H5Tclose(postype);
144✔
71
  return banktype;
144✔
72
}
73

74
void write_collision_track_bank(hid_t group_id,
144✔
75
  openmc::span<CollisionTrackSite> collision_track_bank,
76
  const openmc::vector<int64_t>& bank_index)
77
{
78
  hid_t banktype = h5_collision_track_banktype();
144✔
79
#ifdef OPENMC_MPI
80
  write_bank_dataset("collision_track_bank", group_id, collision_track_bank,
85✔
81
    bank_index, banktype, mpi::collision_track_site);
82
#else
83
  write_bank_dataset("collision_track_bank", group_id, collision_track_bank,
59✔
84
    bank_index, banktype);
85
#endif
86

87
  H5Tclose(banktype);
144✔
88
}
144✔
89

90
void write_h5_collision_track(const char* filename,
144✔
91
  openmc::span<CollisionTrackSite> collision_track_bank,
92
  const openmc::vector<int64_t>& bank_index)
93
{
94
#ifdef PHDF5
95
  bool parallel = true;
85✔
96
#else
97
  bool parallel = false;
59✔
98
#endif
99

100
  if (!filename)
144!
NEW
101
    fatal_error("write_h5_collision_track filename needs a nonempty name.");
×
102

103
  std::string filename_(filename);
144✔
104
  const auto extension = get_file_extension(filename_);
144✔
105
  if (extension.empty()) {
144!
NEW
106
    filename_.append(".h5");
×
107
  } else if (extension != "h5") {
144!
NEW
108
    warning("write_h5_collision_track was passed a file extension differing "
×
109
            "from .h5, but an hdf5 file will be written.");
110
  }
111

112
  hid_t file_id;
113
  if (mpi::master || parallel) {
144!
114
    file_id = file_open(filename_.c_str(), 'w', true);
144✔
115

116
    // Write filetype and version info
117
    write_attribute(file_id, "filetype", "collision_track");
144✔
118
    write_attribute(file_id, "version", VERSION_COLLISION_TRACK);
144✔
119
  }
120

121
  write_collision_track_bank(file_id, collision_track_bank, bank_index);
144✔
122

123
  if (mpi::master || parallel)
144!
124
    file_close(file_id);
144✔
125
}
144✔
126

127
} // namespace
128

129
bool should_record_event(int id_cell, int mt_event, const std::string& nuclide,
150,087✔
130
  int id_universe, int id_material, double energy_loss)
131
{
132
  auto matches_filter = [](const auto& filter_set, const auto& value) {
363,904✔
133
    return filter_set.empty() || filter_set.count(value) > 0;
363,904✔
134
  };
135

136
  const auto& cfg = settings::collision_track_config;
137
  return simulation::current_batch > settings::n_inactive &&
138
         !simulation::collision_track_bank.full() &&
139
         matches_filter(cfg.cell_ids, id_cell) &&
140
         matches_filter(cfg.mt_numbers, mt_event) &&
141
         matches_filter(cfg.universe_ids, id_universe) &&
142
         matches_filter(cfg.material_ids, id_material) &&
143
         matches_filter(cfg.nuclides, nuclide) &&
144
         (cfg.deposited_energy_threshold == 0 ||
145
           cfg.deposited_energy_threshold < energy_loss);
146
}
147

148
void collision_track_reserve_bank()
165✔
149
{
150
  simulation::collision_track_bank.reserve(
165✔
151
    settings::collision_track_config.max_collisions);
152
}
165✔
153

154
void collision_track_flush_bank()
643✔
155
{
156
  const auto& cfg = settings::collision_track_config;
643✔
157
  if (simulation::ct_current_file > cfg.max_files)
643✔
158
    return;
488✔
159

160
  bool last_batch = (simulation::current_batch == settings::n_batches);
613✔
161
  if (!simulation::collision_track_bank.full() && !last_batch)
613✔
162
    return;
458✔
163

164
  auto size = simulation::collision_track_bank.size();
155✔
165
  if (size == 0 && !last_batch)
155!
NEW
166
    return;
×
167

168
  auto collision_track_work_index = mpi::calculate_parallel_index_vector(size);
155✔
169
  openmc::span<CollisionTrackSite> collisiontrackbankspan(
170
    simulation::collision_track_bank.begin(), size);
155✔
171

172
  std::string ext = cfg.mcpl_write ? "mcpl" : "h5";
310✔
173
  auto filename = fmt::format("{}collision_track.{}.{}", settings::path_output,
174
    simulation::ct_current_file, ext);
126✔
175

176
  if (cfg.max_files == 1 || (simulation::ct_current_file == 1 && last_batch)) {
155!
177
    filename = settings::path_output + "collision_track." + ext;
155✔
178
  }
179
  write_message("Creating {}...", filename, 4);
155✔
180

181
  if (cfg.mcpl_write) {
155✔
182
    write_mcpl_collision_track(
11✔
183
      filename.c_str(), collisiontrackbankspan, collision_track_work_index);
184
  } else {
185
    write_h5_collision_track(
144✔
186
      filename.c_str(), collisiontrackbankspan, collision_track_work_index);
187
  }
188

189
  simulation::collision_track_bank.clear();
155✔
190
  if (!last_batch && cfg.max_files >= 1) {
155!
191
    collision_track_reserve_bank();
10!
192
  }
193
  ++simulation::ct_current_file;
155✔
194
}
155✔
195

196
void collision_track_record(Particle& particle)
150,087✔
197
{
198
  int cell_index = particle.lowest_coord().cell();
150,087✔
199
  if (cell_index == C_NONE)
150,087!
200
    return;
128,674✔
201

202
  int cell_id = model::cells[cell_index]->id_;
150,087✔
203
  const auto* nuclide_ptr = data::nuclides[particle.event_nuclide()].get();
150,087✔
204
  std::string nuclide = nuclide_ptr->name_;
150,087✔
205
  int universe_id = model::universes[particle.lowest_coord().universe()]->id_;
150,087✔
206
  double delta_E = particle.E_last() - particle.E();
150,087✔
207
  int material_index = particle.material();
150,087✔
208
  if (material_index == C_NONE)
150,087!
NEW
209
    return;
×
210

211
  int material_id = model::materials[material_index]->id_;
150,087✔
212

213
  if (!should_record_event(cell_id, particle.event_mt(), nuclide, universe_id,
150,087✔
214
        material_id, delta_E))
215
    return;
128,674✔
216

217
  CollisionTrackSite site;
21,413✔
218
  site.r = particle.r();
21,413✔
219
  site.u = particle.u();
21,413✔
220
  site.E = particle.E_last();
21,413✔
221
  site.dE = delta_E;
21,413✔
222
  site.time = particle.time();
21,413✔
223
  site.wgt = particle.wgt();
21,413✔
224
  site.event_mt = particle.event_mt();
21,413✔
225
  site.delayed_group = particle.delayed_group();
21,413✔
226
  site.cell_id = cell_id;
21,413✔
227
  site.nuclide_id =
21,413✔
228
    10000 * nuclide_ptr->Z_ + 10 * nuclide_ptr->A_ + nuclide_ptr->metastable_;
21,413✔
229
  site.material_id = material_id;
21,413✔
230
  site.universe_id = universe_id;
21,413✔
231
  site.n_collision = particle.n_collision();
21,413✔
232
  site.particle = particle.type();
21,413✔
233
  site.parent_id = particle.id();
21,413✔
234
  site.progeny_id = particle.n_progeny();
21,413✔
235
  simulation::collision_track_bank.thread_safe_append(site);
21,413✔
236
}
150,087✔
237

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