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

openmc-dev / openmc / 21489819490

29 Jan 2026 06:21PM UTC coverage: 80.077% (-1.9%) from 81.953%
21489819490

Pull #3757

github

web-flow
Merge d08626053 into f7a734189
Pull Request #3757: Testing point detectors

16004 of 22621 branches covered (70.75%)

Branch coverage included in aggregate %.

94 of 518 new or added lines in 26 files covered. (18.15%)

1021 existing lines in 52 files now uncovered.

53779 of 64524 relevant lines covered (83.35%)

8016833.26 hits per line

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

79.48
/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_point.h"
35
#include "openmc/tallies/filter_polar.h"
36
#include "openmc/tallies/filter_sph_harm.h"
37
#include "openmc/tallies/filter_sptl_legendre.h"
38
#include "openmc/tallies/filter_surface.h"
39
#include "openmc/tallies/filter_time.h"
40
#include "openmc/tallies/filter_universe.h"
41
#include "openmc/tallies/filter_weight.h"
42
#include "openmc/tallies/filter_zernike.h"
43
#include "openmc/xml_interface.h"
44

45
// explicit template instantiation definition
46
template class openmc::vector<openmc::FilterMatch>;
47

48
namespace openmc {
49

50
//==============================================================================
51
// Global variables
52
//==============================================================================
53

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

59
//==============================================================================
60
// Non-member functions
61
//==============================================================================
62

63
extern "C" size_t tally_filters_size()
105✔
64
{
65
  return model::tally_filters.size();
105✔
66
}
67

68
//==============================================================================
69
// Filter implementation
70
//==============================================================================
71

72
Filter::Filter()
788✔
73
{
74
  index_ = model::tally_filters.size(); // Avoids warning about narrowing
788✔
75
}
788✔
76

77
Filter::~Filter()
788✔
78
{
79
  model::filter_map.erase(id_);
788✔
80
}
788✔
81

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

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

96
  // Allocate according to the filter type
97
  auto f = Filter::create(s, filter_id);
663✔
98

99
  // Read filter data from XML
100
  f->from_xml(node);
663✔
101
  return f;
663✔
102
}
663✔
103

104
Filter* Filter::create(const std::string& type, int32_t id)
787✔
105
{
106
  if (type == "azimuthal") {
787✔
107
    return Filter::create<AzimuthalFilter>(id);
2✔
108
  } else if (type == "cell") {
785✔
109
    return Filter::create<CellFilter>(id);
55✔
110
  } else if (type == "cellborn") {
730✔
111
    return Filter::create<CellBornFilter>(id);
1✔
112
  } else if (type == "cellfrom") {
729✔
113
    return Filter::create<CellFromFilter>(id);
6✔
114
  } else if (type == "cellinstance") {
723✔
115
    return Filter::create<CellInstanceFilter>(id);
2✔
116
  } else if (type == "distribcell") {
721✔
117
    return Filter::create<DistribcellFilter>(id);
13✔
118
  } else if (type == "delayedgroup") {
708✔
119
    return Filter::create<DelayedGroupFilter>(id);
9✔
120
  } else if (type == "energyfunction") {
699✔
121
    return Filter::create<EnergyFunctionFilter>(id);
15✔
122
  } else if (type == "energy") {
684✔
123
    return Filter::create<EnergyFilter>(id);
131✔
124
  } else if (type == "collision") {
553✔
125
    return Filter::create<CollisionFilter>(id);
1✔
126
  } else if (type == "energyout") {
552✔
127
    return Filter::create<EnergyoutFilter>(id);
42✔
128
  } else if (type == "legendre") {
510✔
129
    return Filter::create<LegendreFilter>(id);
55✔
130
  } else if (type == "material") {
455✔
131
    return Filter::create<MaterialFilter>(id);
166✔
132
  } else if (type == "materialfrom") {
289✔
133
    return Filter::create<MaterialFromFilter>(id);
1✔
134
  } else if (type == "mesh") {
288✔
135
    return Filter::create<MeshFilter>(id);
187✔
136
  } else if (type == "meshborn") {
101✔
137
    return Filter::create<MeshBornFilter>(id);
2✔
138
  } else if (type == "meshmaterial") {
99✔
139
    return Filter::create<MeshMaterialFilter>(id);
2✔
140
  } else if (type == "meshsurface") {
97✔
141
    return Filter::create<MeshSurfaceFilter>(id);
30✔
142
  } else if (type == "mu") {
67✔
143
    return Filter::create<MuFilter>(id);
2✔
144
  } else if (type == "musurface") {
65✔
145
    return Filter::create<MuSurfaceFilter>(id);
2✔
146
  } else if (type == "parentnuclide") {
63✔
147
    return Filter::create<ParentNuclideFilter>(id);
1✔
148
  } else if (type == "particle") {
62✔
149
    return Filter::create<ParticleFilter>(id);
30✔
150
  } else if (type == "point") {
32!
NEW
151
    return Filter::create<PointFilter>(id);
×
152
  } else if (type == "polar") {
32✔
153
    return Filter::create<PolarFilter>(id);
3✔
154
  } else if (type == "surface") {
29✔
155
    return Filter::create<SurfaceFilter>(id);
12✔
156
  } else if (type == "spatiallegendre") {
17✔
157
    return Filter::create<SpatialLegendreFilter>(id);
1✔
158
  } else if (type == "sphericalharmonics") {
16✔
159
    return Filter::create<SphericalHarmonicsFilter>(id);
3✔
160
  } else if (type == "time") {
13✔
161
    return Filter::create<TimeFilter>(id);
7✔
162
  } else if (type == "universe") {
6✔
163
    return Filter::create<UniverseFilter>(id);
1✔
164
  } else if (type == "weight") {
5✔
165
    return Filter::create<WeightFilter>(id);
1✔
166
  } else if (type == "zernike") {
4!
167
    return Filter::create<ZernikeFilter>(id);
4✔
168
  } else if (type == "zernikeradial") {
×
169
    return Filter::create<ZernikeRadialFilter>(id);
×
170
  } else {
171
    throw std::runtime_error {fmt::format("Unknown filter type: {}", type)};
×
172
  }
173
  return nullptr;
174
}
175

176
void Filter::set_id(int32_t id)
893✔
177
{
178
  assert(id >= 0 || id == C_NONE);
893!
179

180
  // Clear entry in filter map if an ID was already assigned before
181
  if (id_ != C_NONE) {
893✔
182
    model::filter_map.erase(id_);
105✔
183
    id_ = C_NONE;
105✔
184
  }
185

186
  // Make sure no other filter has same ID
187
  if (model::filter_map.find(id) != model::filter_map.end()) {
893!
188
    throw std::runtime_error {
×
189
      "Two filters have the same ID: " + std::to_string(id)};
×
190
  }
191

192
  // If no ID specified, auto-assign next ID in sequence
193
  if (id == C_NONE) {
893✔
194
    id = 0;
125✔
195
    for (const auto& f : model::tally_filters) {
637✔
196
      id = std::max(id, f->id_);
512✔
197
    }
198
    ++id;
125✔
199
  }
200

201
  // Update ID and entry in filter map
202
  id_ = id;
893✔
203
  model::filter_map[id] = index_;
893✔
204
}
893✔
205

206
//==============================================================================
207
// C API functions
208
//==============================================================================
209

210
int verify_filter(int32_t index)
1,880✔
211
{
212
  if (index < 0 || index >= model::tally_filters.size()) {
1,880!
213
    set_errmsg("Filter index is out of bounds.");
×
214
    return OPENMC_E_OUT_OF_BOUNDS;
×
215
  }
216
  return 0;
1,880✔
217
}
218

219
extern "C" int openmc_filter_get_id(int32_t index, int32_t* id)
968✔
220
{
221
  if (int err = verify_filter(index))
968!
222
    return err;
×
223

224
  *id = model::tally_filters[index]->id();
968✔
225
  return 0;
968✔
226
}
227

228
extern "C" int openmc_filter_set_id(int32_t index, int32_t id)
105✔
229
{
230
  if (int err = verify_filter(index))
105!
231
    return err;
×
232

233
  model::tally_filters[index]->set_id(id);
105✔
234
  return 0;
105✔
235
}
236

237
extern "C" int openmc_filter_get_type(int32_t index, char* type)
530✔
238
{
239
  if (int err = verify_filter(index))
530!
240
    return err;
×
241

242
  std::strcpy(type, model::tally_filters[index]->type_str().c_str());
530✔
243
  return 0;
530✔
244
}
245

246
extern "C" int openmc_filter_get_num_bins(int32_t index, int* n_bins)
12✔
247
{
248
  if (int err = verify_filter(index))
12!
249
    return err;
×
250

251
  *n_bins = model::tally_filters[index]->n_bins();
12✔
252
  return 0;
12✔
253
}
254

255
extern "C" int openmc_get_filter_index(int32_t id, int32_t* index)
1✔
256
{
257
  auto it = model::filter_map.find(id);
1✔
258
  if (it == model::filter_map.end()) {
1!
259
    set_errmsg("No filter exists with ID=" + std::to_string(id) + ".");
×
260
    return OPENMC_E_INVALID_ID;
×
261
  }
262

263
  *index = it->second;
1✔
264
  return 0;
1✔
265
}
266

267
extern "C" void openmc_get_filter_next_id(int32_t* id)
×
268
{
269
  int32_t largest_filter_id = 0;
×
270
  for (const auto& t : model::tally_filters) {
×
271
    largest_filter_id = std::max(largest_filter_id, t->id());
×
272
  }
273
  *id = largest_filter_id + 1;
×
274
}
×
275

276
extern "C" int openmc_new_filter(const char* type, int32_t* index)
105✔
277
{
278
  *index = model::tally_filters.size();
105✔
279
  Filter::create(type);
105✔
280
  return 0;
105✔
281
}
282

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