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

openmc-dev / openmc / 22110756672

17 Feb 2026 06:31PM UTC coverage: 81.831% (+0.1%) from 81.721%
22110756672

Pull #3813

github

web-flow
Merge 47dc7194f into 977ade79a
Pull Request #3813: Check for positive radii

17268 of 24298 branches covered (71.07%)

Branch coverage included in aggregate %.

16 of 16 new or added lines in 1 file covered. (100.0%)

1065 existing lines in 28 files now uncovered.

57520 of 67095 relevant lines covered (85.73%)

45595325.95 hits per line

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

59.9
/src/tallies/filter_meshmaterial.cpp
1
#include "openmc/tallies/filter_meshmaterial.h"
2

3
#include <cassert>
4
#include <utility> // for move
5

6
#include <fmt/core.h>
7

8
#include "openmc/capi.h"
9
#include "openmc/constants.h"
10
#include "openmc/container_util.h"
11
#include "openmc/error.h"
12
#include "openmc/material.h"
13
#include "openmc/mesh.h"
14
#include "openmc/tensor.h"
15
#include "openmc/xml_interface.h"
16

17
namespace openmc {
18

19
void MeshMaterialFilter::from_xml(pugi::xml_node node)
20✔
20
{
21
  // Get mesh ID
22
  auto mesh = get_node_array<int32_t>(node, "mesh");
20✔
23
  if (mesh.size() != 1) {
20!
UNCOV
24
    fatal_error(
×
UNCOV
25
      "Only one mesh can be specified per " + type_str() + " mesh filter.");
×
26
  }
27

28
  auto id = mesh[0];
20✔
29
  auto search = model::mesh_map.find(id);
20✔
30
  if (search == model::mesh_map.end()) {
20!
UNCOV
31
    fatal_error(
×
UNCOV
32
      fmt::format("Could not find mesh {} specified on tally filter.", id));
×
33
  }
34
  set_mesh(search->second);
20✔
35

36
  // Get pairs of (element index, material) and set the bins
37
  auto bins = get_node_array<int32_t>(node, "bins");
20✔
38
  this->set_bins(bins);
20✔
39

40
  if (check_for_node(node, "translation")) {
20!
UNCOV
41
    set_translation(get_node_array<double>(node, "translation"));
×
42
  }
43
}
20✔
44

45
void MeshMaterialFilter::set_bins(span<int32_t> bins)
20✔
46
{
47
  if (bins.size() % 2 != 0) {
20!
UNCOV
48
    fatal_error(
×
UNCOV
49
      fmt::format("Size of mesh material bins is not even: {}", bins.size()));
×
50
  }
51

52
  // Create a vector of ElementMat pairs from the flat vector of bins
53
  vector<ElementMat> element_mats;
20✔
54
  for (int64_t i = 0; i < bins.size() / 2; ++i) {
120✔
55
    int32_t element = bins[2 * i];
100✔
56
    int32_t mat_id = bins[2 * i + 1];
100✔
57
    auto search = model::material_map.find(mat_id);
100✔
58
    if (search == model::material_map.end()) {
100!
UNCOV
59
      fatal_error(fmt::format(
×
60
        "Could not find material {} specified on tally filter.", mat_id));
61
    }
62
    int32_t mat_index = search->second;
100✔
63
    element_mats.push_back({element, mat_index});
100✔
64
  }
65

66
  this->set_bins(std::move(element_mats));
20✔
67
}
20✔
68

69
void MeshMaterialFilter::set_bins(vector<ElementMat>&& bins)
20✔
70
{
71
  // Swap internal bins_ with the provided vector to avoid copying
72
  bins_.swap(bins);
20✔
73

74
  // Clear and update the mapping and vector of materials
75
  materials_.clear();
20✔
76
  map_.clear();
20✔
77
  for (std::size_t i = 0; i < bins_.size(); ++i) {
120✔
78
    const auto& x = bins_[i];
100✔
79
    assert(x.index_mat >= 0);
80!
80
    assert(x.index_mat < model::materials.size());
80!
81
    materials_.insert(x.index_mat);
100✔
82
    map_[x] = i;
100✔
83
  }
84

85
  n_bins_ = bins_.size();
20✔
86
}
20✔
87

88
void MeshMaterialFilter::set_mesh(int32_t mesh)
20✔
89
{
90
  // perform any additional perparation for mesh tallies here
91
  mesh_ = mesh;
20✔
92
  model::meshes[mesh_]->prepare_for_point_location();
20✔
93
}
20✔
94

95
void MeshMaterialFilter::set_translation(const Position& translation)
×
96
{
97
  translated_ = true;
×
UNCOV
98
  translation_ = translation;
×
99
}
×
100

101
void MeshMaterialFilter::set_translation(const double translation[3])
×
102
{
UNCOV
103
  this->set_translation({translation[0], translation[1], translation[2]});
×
UNCOV
104
}
×
105

106
void MeshMaterialFilter::get_all_bins(
7,121,830✔
107
  const Particle& p, TallyEstimator estimator, FilterMatch& match) const
108
{
109
  // If current material is not in any bins, don't bother checking
110
  if (!contains(materials_, p.material())) {
7,121,830!
UNCOV
111
    return;
×
112
  }
113

114
  Position last_r = p.r_last();
7,121,830✔
115
  Position r = p.r();
7,121,830✔
116
  Position u = p.u();
7,121,830✔
117

118
  // apply translation if present
119
  if (translated_) {
7,121,830!
UNCOV
120
    last_r -= translation();
×
UNCOV
121
    r -= translation();
×
122
  }
123

124
  if (estimator != TallyEstimator::TRACKLENGTH) {
7,121,830!
125
    int32_t index_element = model::meshes[mesh_]->get_bin(r);
×
126
    if (index_element >= 0) {
×
127
      auto search = map_.find({index_element, p.material()});
×
128
      if (search != map_.end()) {
×
UNCOV
129
        match.bins_.push_back(search->second);
×
UNCOV
130
        match.weights_.push_back(1.0);
×
131
      }
132
    }
133
  } else {
134
    // First determine which elements the particle crosses (may or may not
135
    // actually match bins so we have to adjust bins_/weight_ after)
136
    int32_t n_start = match.bins_.size();
7,121,830✔
137
    model::meshes[mesh_]->bins_crossed(
7,121,830✔
138
      last_r, r, u, match.bins_, match.weights_);
7,121,830✔
139
    int32_t n_end = match.bins_.size();
7,121,830✔
140

141
    // Go through bins and weights and check which ones are actually a match
142
    // based on the (element, material) pair. For matches, overwrite the bin.
143
    int i = 0;
7,121,830✔
144
    for (int j = n_start; j < n_end; ++j) {
10,065,940✔
145
      int32_t index_element = match.bins_[j];
2,944,110✔
146
      double weight = match.weights_[j];
2,944,110✔
147
      auto search = map_.find({index_element, p.material()});
2,944,110✔
148
      if (search != map_.end()) {
2,944,110!
149
        match.bins_[n_start + i] = search->second;
2,944,110✔
150
        match.weights_[n_start + i] = weight;
2,944,110✔
151
        ++i;
2,944,110✔
152
      }
153
    }
154

155
    // Resize the vectors to remove the unmatched bins
156
    match.bins_.resize(n_start + i);
7,121,830✔
157
  }
158
}
159

160
void MeshMaterialFilter::to_statepoint(hid_t filter_group) const
20✔
161
{
162
  Filter::to_statepoint(filter_group);
20✔
163
  write_dataset(filter_group, "mesh", model::meshes[mesh_]->id_);
20✔
164

165
  size_t n = bins_.size();
20✔
166
  tensor::Tensor<size_t> data({n, 2});
20✔
167
  for (int64_t i = 0; i < n; ++i) {
120✔
168
    const auto& x = bins_[i];
100✔
169
    data(i, 0) = x.index_element;
100✔
170
    data(i, 1) = model::materials[x.index_mat]->id_;
100✔
171
  }
172
  write_dataset(filter_group, "bins", data);
20✔
173

174
  if (translated_) {
20!
UNCOV
175
    write_dataset(filter_group, "translation", translation_);
×
176
  }
177
}
20✔
178

179
std::string MeshMaterialFilter::text_label(int bin) const
120✔
180
{
181
  auto& x = bins_[bin];
120✔
182
  auto& mesh = *model::meshes.at(mesh_);
120✔
183
  return fmt::format("Mesh {}, {}, Material {}", mesh.id(),
120✔
184
    mesh.bin_label(x.index_element), model::materials[x.index_mat]->id_);
240✔
185
}
186

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