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

openmc-dev / openmc / 25631610076

10 May 2026 02:44PM UTC coverage: 81.026% (-0.4%) from 81.388%
25631610076

Pull #3757

github

web-flow
Merge debc5a921 into d56cda254
Pull Request #3757: Testing point detectors

17769 of 25812 branches covered (68.84%)

Branch coverage included in aggregate %.

51 of 373 new or added lines in 25 files covered. (13.67%)

3 existing lines in 2 files now uncovered.

58805 of 68694 relevant lines covered (85.6%)

40257430.53 hits per line

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

80.22
/src/tallies/filter.cpp
1
#include "openmc/tallies/filter.h"
2

3
#include <algorithm> // for max
4
#include <cassert>
5
#include <cstring> // for strcpy
6
#include <string>
7

8
#include <fmt/core.h>
9

10
#include "openmc/capi.h"
11
#include "openmc/constants.h" // for MAX_LINE_LEN;
12
#include "openmc/error.h"
13
#include "openmc/tallies/filter_azimuthal.h"
14
#include "openmc/tallies/filter_cell.h"
15
#include "openmc/tallies/filter_cell_instance.h"
16
#include "openmc/tallies/filter_cellborn.h"
17
#include "openmc/tallies/filter_cellfrom.h"
18
#include "openmc/tallies/filter_collision.h"
19
#include "openmc/tallies/filter_delayedgroup.h"
20
#include "openmc/tallies/filter_distribcell.h"
21
#include "openmc/tallies/filter_energy.h"
22
#include "openmc/tallies/filter_energyfunc.h"
23
#include "openmc/tallies/filter_legendre.h"
24
#include "openmc/tallies/filter_material.h"
25
#include "openmc/tallies/filter_materialfrom.h"
26
#include "openmc/tallies/filter_mesh.h"
27
#include "openmc/tallies/filter_meshborn.h"
28
#include "openmc/tallies/filter_meshmaterial.h"
29
#include "openmc/tallies/filter_meshsurface.h"
30
#include "openmc/tallies/filter_mu.h"
31
#include "openmc/tallies/filter_musurface.h"
32
#include "openmc/tallies/filter_parent_nuclide.h"
33
#include "openmc/tallies/filter_particle.h"
34
#include "openmc/tallies/filter_particle_production.h"
35
#include "openmc/tallies/filter_point.h"
36
#include "openmc/tallies/filter_polar.h"
37
#include "openmc/tallies/filter_reaction.h"
38
#include "openmc/tallies/filter_sph_harm.h"
39
#include "openmc/tallies/filter_sptl_legendre.h"
40
#include "openmc/tallies/filter_surface.h"
41
#include "openmc/tallies/filter_time.h"
42
#include "openmc/tallies/filter_universe.h"
43
#include "openmc/tallies/filter_weight.h"
44
#include "openmc/tallies/filter_zernike.h"
45
#include "openmc/xml_interface.h"
46

47
// explicit template instantiation definition
48
template class openmc::vector<openmc::FilterMatch>;
49

50
namespace openmc {
51

52
//==============================================================================
53
// Global variables
54
//==============================================================================
55

56
namespace model {
57
std::unordered_map<int, int> filter_map;
58
vector<unique_ptr<Filter>> tally_filters;
59
} // namespace model
60

61
//==============================================================================
62
// Non-member functions
63
//==============================================================================
64

65
extern "C" size_t tally_filters_size()
861✔
66
{
67
  return model::tally_filters.size();
861✔
68
}
69

70
//==============================================================================
71
// Filter implementation
72
//==============================================================================
73

74
Filter::Filter()
8,170✔
75
{
76
  index_ = model::tally_filters.size(); // Avoids warning about narrowing
8,170✔
77
}
8,170✔
78

79
Filter::~Filter()
8,170✔
80
{
81
  model::filter_map.erase(id_);
8,170✔
82
}
8,170✔
83

84
Filter* Filter::create(pugi::xml_node node)
7,082✔
85
{
86
  // Copy filter id
87
  if (!check_for_node(node, "id")) {
7,082!
88
    fatal_error("Must specify id for filter in tally XML file.");
×
89
  }
90
  int filter_id = std::stoi(get_node_value(node, "id"));
14,164✔
91

92
  // Convert filter type to lower case
93
  std::string s;
7,082✔
94
  if (check_for_node(node, "type")) {
7,082!
95
    s = get_node_value(node, "type", true);
7,082✔
96
  }
97

98
  // Allocate according to the filter type
99
  auto f = Filter::create(s, filter_id);
7,082✔
100

101
  // Read filter data from XML
102
  f->from_xml(node);
7,082✔
103
  return f;
7,082✔
104
}
7,082✔
105

106
Filter* Filter::create(const std::string& type, int32_t id)
8,159✔
107
{
108
  if (type == "azimuthal") {
8,159✔
109
    return Filter::create<AzimuthalFilter>(id);
22✔
110
  } else if (type == "cell") {
8,137✔
111
    return Filter::create<CellFilter>(id);
605✔
112
  } else if (type == "cellborn") {
7,532✔
113
    return Filter::create<CellBornFilter>(id);
11✔
114
  } else if (type == "cellfrom") {
7,521✔
115
    return Filter::create<CellFromFilter>(id);
74✔
116
  } else if (type == "cellinstance") {
7,447✔
117
    return Filter::create<CellInstanceFilter>(id);
24✔
118
  } else if (type == "distribcell") {
7,423✔
119
    return Filter::create<DistribcellFilter>(id);
131✔
120
  } else if (type == "delayedgroup") {
7,292✔
121
    return Filter::create<DelayedGroupFilter>(id);
93✔
122
  } else if (type == "energyfunction") {
7,199✔
123
    return Filter::create<EnergyFunctionFilter>(id);
144✔
124
  } else if (type == "energy") {
7,055✔
125
    return Filter::create<EnergyFilter>(id);
1,421✔
126
  } else if (type == "collision") {
5,634✔
127
    return Filter::create<CollisionFilter>(id);
11✔
128
  } else if (type == "energyout") {
5,623✔
129
    return Filter::create<EnergyoutFilter>(id);
472✔
130
  } else if (type == "legendre") {
5,151✔
131
    return Filter::create<LegendreFilter>(id);
579✔
132
  } else if (type == "material") {
4,572✔
133
    return Filter::create<MaterialFilter>(id);
1,763✔
134
  } else if (type == "materialfrom") {
2,809✔
135
    return Filter::create<MaterialFromFilter>(id);
11✔
136
  } else if (type == "mesh") {
2,798✔
137
    return Filter::create<MeshFilter>(id);
1,734✔
138
  } else if (type == "meshborn") {
1,064✔
139
    return Filter::create<MeshBornFilter>(id);
19✔
140
  } else if (type == "meshmaterial") {
1,045✔
141
    return Filter::create<MeshMaterialFilter>(id);
32✔
142
  } else if (type == "meshsurface") {
1,013✔
143
    return Filter::create<MeshSurfaceFilter>(id);
270✔
144
  } else if (type == "mu") {
743✔
145
    return Filter::create<MuFilter>(id);
22✔
146
  } else if (type == "musurface") {
721✔
147
    return Filter::create<MuSurfaceFilter>(id);
19✔
148
  } else if (type == "parentnuclide") {
702✔
149
    return Filter::create<ParentNuclideFilter>(id);
16✔
150
  } else if (type == "particle") {
686✔
151
    return Filter::create<ParticleFilter>(id);
320✔
152
  } else if (type == "particleproduction") {
366✔
153
    return Filter::create<ParticleProductionFilter>(id);
22✔
154
  } else if (type == "point") {
344!
NEW
155
    return Filter::create<PointFilter>(id);
×
156
  } else if (type == "polar") {
344✔
157
    return Filter::create<PolarFilter>(id);
33✔
158
  } else if (type == "reaction") {
311✔
159
    return Filter::create<ReactionFilter>(id);
11✔
160
  } else if (type == "surface") {
300✔
161
    return Filter::create<SurfaceFilter>(id);
155✔
162
  } else if (type == "spatiallegendre") {
145✔
163
    return Filter::create<SpatialLegendreFilter>(id);
8✔
164
  } else if (type == "sphericalharmonics") {
137✔
165
    return Filter::create<SphericalHarmonicsFilter>(id);
27✔
166
  } else if (type == "time") {
110✔
167
    return Filter::create<TimeFilter>(id);
59✔
168
  } else if (type == "universe") {
51✔
169
    return Filter::create<UniverseFilter>(id);
11✔
170
  } else if (type == "weight") {
40✔
171
    return Filter::create<WeightFilter>(id);
8✔
172
  } else if (type == "zernike") {
32!
173
    return Filter::create<ZernikeFilter>(id);
32✔
174
  } else if (type == "zernikeradial") {
×
175
    return Filter::create<ZernikeRadialFilter>(id);
×
176
  } else {
177
    throw std::runtime_error {fmt::format("Unknown filter type: {}", type)};
×
178
  }
179
  return nullptr;
180
}
181

182
void Filter::set_id(int32_t id)
9,031✔
183
{
184
  assert(id >= 0 || id == C_NONE);
9,031!
185

186
  // Clear entry in filter map if an ID was already assigned before
187
  if (id_ != C_NONE) {
9,031✔
188
    model::filter_map.erase(id_);
861✔
189
    id_ = C_NONE;
861✔
190
  }
191

192
  // Make sure no other filter has same ID
193
  if (model::filter_map.find(id) != model::filter_map.end()) {
9,031!
194
    throw std::runtime_error {
×
195
      "Two filters have the same ID: " + std::to_string(id)};
×
196
  }
197

198
  // If no ID specified, auto-assign next ID in sequence
199
  if (id == C_NONE) {
9,031✔
200
    id = 0;
1,088✔
201
    for (const auto& f : model::tally_filters) {
5,483✔
202
      id = std::max(id, f->id_);
7,504✔
203
    }
204
    ++id;
1,088✔
205
  }
206

207
  // Update ID and entry in filter map
208
  id_ = id;
9,031✔
209
  model::filter_map[id] = index_;
9,031✔
210
}
9,031✔
211

212
//==============================================================================
213
// C API functions
214
//==============================================================================
215

216
int verify_filter(int32_t index)
15,193✔
217
{
218
  if (index < 0 || index >= model::tally_filters.size()) {
15,193!
219
    set_errmsg("Filter index is out of bounds.");
×
220
    return OPENMC_E_OUT_OF_BOUNDS;
×
221
  }
222
  return 0;
223
}
224

225
extern "C" int openmc_filter_get_id(int32_t index, int32_t* id)
7,781✔
226
{
227
  if (int err = verify_filter(index))
7,781!
228
    return err;
229

230
  *id = model::tally_filters[index]->id();
7,781✔
231
  return 0;
7,781✔
232
}
233

234
extern "C" int openmc_filter_set_id(int32_t index, int32_t id)
861✔
235
{
236
  if (int err = verify_filter(index))
861!
237
    return err;
238

239
  model::tally_filters[index]->set_id(id);
861✔
240
  return 0;
861✔
241
}
242

243
extern "C" int openmc_filter_get_type(int32_t index, char* type)
4,256✔
244
{
245
  if (int err = verify_filter(index))
4,256!
246
    return err;
247

248
  std::strcpy(type, model::tally_filters[index]->type_str().c_str());
4,256✔
249
  return 0;
4,256✔
250
}
251

252
extern "C" int openmc_filter_get_num_bins(int32_t index, int* n_bins)
96✔
253
{
254
  if (int err = verify_filter(index))
96!
255
    return err;
256

257
  *n_bins = model::tally_filters[index]->n_bins();
96✔
258
  return 0;
96✔
259
}
260

261
extern "C" int openmc_get_filter_index(int32_t id, int32_t* index)
8✔
262
{
263
  auto it = model::filter_map.find(id);
8!
264
  if (it == model::filter_map.end()) {
8!
265
    set_errmsg("No filter exists with ID=" + std::to_string(id) + ".");
×
266
    return OPENMC_E_INVALID_ID;
×
267
  }
268

269
  *index = it->second;
8✔
270
  return 0;
8✔
271
}
272

273
extern "C" void openmc_get_filter_next_id(int32_t* id)
×
274
{
275
  int32_t largest_filter_id = 0;
×
276
  for (const auto& t : model::tally_filters) {
×
277
    largest_filter_id = std::max(largest_filter_id, t->id());
×
278
  }
279
  *id = largest_filter_id + 1;
×
280
}
×
281

282
extern "C" int openmc_new_filter(const char* type, int32_t* index)
861✔
283
{
284
  *index = model::tally_filters.size();
861✔
285
  Filter::create(type);
861✔
286
  return 0;
861✔
287
}
288

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