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

openmc-dev / openmc / 18656608910

20 Oct 2025 03:16PM UTC coverage: 81.844% (-3.4%) from 85.218%
18656608910

Pull #3454

github

web-flow
Merge 5eee478a5 into 055ea15a2
Pull Request #3454: Adding variance of variance and normality tests for tally statistics

16610 of 23118 branches covered (71.85%)

Branch coverage included in aggregate %.

188 of 312 new or added lines in 7 files covered. (60.26%)

2157 existing lines in 77 files now uncovered.

53896 of 63029 relevant lines covered (85.51%)

42554448.35 hits per line

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

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

3
#include <utility> // for move
4

5
#include <fmt/core.h>
6

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

15
namespace openmc {
16

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

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

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

38
  if (check_for_node(node, "translation")) {
11!
39
    set_translation(get_node_array<double>(node, "translation"));
×
40
  }
41
}
11✔
42

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

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

64
  this->set_bins(std::move(element_mats));
11✔
65
}
11✔
66

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

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

83
  n_bins_ = bins_.size();
11✔
84
}
11✔
85

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

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

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

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

112
  Position last_r = p.r_last();
5,359,662✔
113
  Position r = p.r();
5,359,662✔
114
  Position u = p.u();
5,359,662✔
115

116
  // apply translation if present
117
  if (translated_) {
5,359,662!
118
    last_r -= translation();
×
119
    r -= translation();
×
120
  }
121

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

139
    // Go through bins and weights and check which ones are actually a match
140
    // based on the (element, material) pair. For matches, overwrite the bin.
141
    int i = 0;
5,359,662✔
142
    for (int j = n_start; j < n_end; ++j) {
6,123,832✔
143
      int32_t index_element = match.bins_[j];
764,170✔
144
      double weight = match.weights_[j];
764,170✔
145
      auto search = map_.find({index_element, p.material()});
764,170✔
146
      if (search != map_.end()) {
764,170!
147
        match.bins_[n_start + i] = search->second;
764,170✔
148
        match.weights_[n_start + i] = weight;
764,170✔
149
        ++i;
764,170✔
150
      }
151
    }
152

153
    // Resize the vectors to remove the unmatched bins
154
    match.bins_.resize(n_start + i);
5,359,662✔
155
  }
156
}
157

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

163
  size_t n = bins_.size();
11✔
164
  xt::xtensor<size_t, 2> data({n, 2});
11✔
165
  for (int64_t i = 0; i < n; ++i) {
99✔
166
    const auto& x = bins_[i];
88✔
167
    data(i, 0) = x.index_element;
88✔
168
    data(i, 1) = model::materials[x.index_mat]->id_;
88✔
169
  }
170
  write_dataset(filter_group, "bins", data);
11✔
171

172
  if (translated_) {
11!
173
    write_dataset(filter_group, "translation", translation_);
×
174
  }
175
}
11✔
176

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

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