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

openmc-dev / openmc / 14959976595

11 May 2025 09:43PM UTC coverage: 85.187% (-0.02%) from 85.204%
14959976595

Pull #3406

github

web-flow
Merge 52719edcd into f615441f0
Pull Request #3406: Implement a new MeshMaterialFilter

159 of 197 new or added lines in 6 files covered. (80.71%)

1 existing line in 1 file now uncovered.

52394 of 61505 relevant lines covered (85.19%)

36957531.14 hits per line

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

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

3
#include <fmt/core.h>
4

5
#include "openmc/capi.h"
6
#include "openmc/constants.h"
7
#include "openmc/error.h"
8
#include "openmc/material.h"
9
#include "openmc/mesh.h"
10
#include "openmc/xml_interface.h"
11

12
namespace openmc {
13

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

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

31
  // Get pairs of (element index, material)
32
  auto bins = get_node_array<int32_t>(node, "bins");
11✔
33
  assert(bins.size() % 2 == 0);
9✔
34

35
  // Convert into vector of ElementMat
36
  vector<ElementMat> element_mats;
11✔
37
  for (int64_t i = 0; i < bins.size() / 2; ++i) {
99✔
38
    int32_t element = bins[2 * i];
88✔
39
    int32_t mat_id = bins[2 * i + 1];
88✔
40
    auto search = model::material_map.find(mat_id);
88✔
41
    if (search == model::material_map.end()) {
88✔
NEW
42
      throw std::runtime_error {fmt::format(
×
NEW
43
        "Could not find material {} specified on tally filter.", mat_id)};
×
44
    }
45
    int32_t mat_index = search->second;
88✔
46
    element_mats.push_back({element, mat_index});
88✔
47
  }
48

49
  this->set_bins(element_mats);
11✔
50

51
  if (check_for_node(node, "translation")) {
11✔
NEW
52
    set_translation(get_node_array<double>(node, "translation"));
×
53
  }
54
}
11✔
55

56
void MeshMaterialFilter::set_bins(span<ElementMat> bins)
11✔
57
{
58
  // Clear existing cells
59
  bins_.clear();
11✔
60
  bins_.reserve(bins.size());
11✔
61
  materials_.clear();
11✔
62
  map_.clear();
11✔
63

64
  // Update cells and mapping
65
  for (auto& x : bins) {
99✔
66
    assert(x.index_mat >= 0);
72✔
67
    assert(x.index_mat < model::materials.size());
72✔
68
    bins_.push_back(x);
88✔
69
    materials_.insert(x.index_mat);
88✔
70
    map_[x] = bins_.size() - 1;
88✔
71
  }
72

73
  n_bins_ = bins_.size();
11✔
74
}
11✔
75

76
void MeshMaterialFilter::set_mesh(int32_t mesh)
11✔
77
{
78
  // perform any additional perparation for mesh tallies here
79
  mesh_ = mesh;
11✔
80
  model::meshes[mesh_]->prepare_for_point_location();
11✔
81
}
11✔
82

NEW
83
void MeshMaterialFilter::set_translation(const Position& translation)
×
84
{
NEW
85
  translated_ = true;
×
NEW
86
  translation_ = translation;
×
87
}
88

NEW
89
void MeshMaterialFilter::set_translation(const double translation[3])
×
90
{
NEW
91
  this->set_translation({translation[0], translation[1], translation[2]});
×
92
}
93

94
void MeshMaterialFilter::get_all_bins(
5,359,662✔
95
  const Particle& p, TallyEstimator estimator, FilterMatch& match) const
96
{
97

98
  Position last_r = p.r_last();
5,359,662✔
99
  Position r = p.r();
5,359,662✔
100
  Position u = p.u();
5,359,662✔
101

102
  // apply translation if present
103
  if (translated_) {
5,359,662✔
NEW
104
    last_r -= translation();
×
NEW
105
    r -= translation();
×
106
  }
107

108
  if (estimator != TallyEstimator::TRACKLENGTH) {
5,359,662✔
NEW
109
    int32_t index_element = model::meshes[mesh_]->get_bin(r);
×
NEW
110
    if (index_element >= 0) {
×
NEW
111
      auto search = map_.find({index_element, p.material()});
×
NEW
112
      if (search != map_.end()) {
×
NEW
113
        match.bins_.push_back(search->second);
×
NEW
114
        match.weights_.push_back(1.0);
×
115
      }
116
    }
117
  } else {
118
    // If current material is not in any bins, don't bother checking
119
    if (materials_.find(p.material()) == materials_.end()) {
5,359,662✔
NEW
120
      return;
×
121
    }
122

123
    // First determine which elements the particle crosses (may or may not
124
    // actually match bins so we have to adjust bins_/weight_ after)
125
    int32_t n_start = match.bins_.size();
5,359,662✔
126
    model::meshes[mesh_]->bins_crossed(
5,359,662✔
127
      last_r, r, u, match.bins_, match.weights_);
5,359,662✔
128
    int32_t n_end = match.bins_.size();
5,359,662✔
129

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

144
    // Resize the vectors to remove the unmatched bins
145
    match.bins_.resize(n_start + i);
5,359,662✔
146
  }
147
}
148

149
void MeshMaterialFilter::to_statepoint(hid_t filter_group) const
11✔
150
{
151
  Filter::to_statepoint(filter_group);
11✔
152
  write_dataset(filter_group, "mesh", model::meshes[mesh_]->id_);
11✔
153

154
  size_t n = bins_.size();
11✔
155
  xt::xtensor<size_t, 2> data({n, 2});
11✔
156
  for (int64_t i = 0; i < n; ++i) {
99✔
157
    const auto& x = bins_[i];
88✔
158
    data(i, 0) = x.index_element;
88✔
159
    data(i, 1) = model::materials[x.index_mat]->id_;
88✔
160
  }
161
  write_dataset(filter_group, "bins", data);
11✔
162

163
  if (translated_) {
11✔
NEW
164
    write_dataset(filter_group, "translation", translation_);
×
165
  }
166
}
11✔
167

168
std::string MeshMaterialFilter::text_label(int bin) const
88✔
169
{
170
  auto& x = bins_[bin];
88✔
171
  auto& mesh = *model::meshes.at(mesh_);
88✔
172
  return fmt::format("Mesh {}, {}, Material {}", mesh.id(),
88✔
173
    mesh.bin_label(x.index_element), model::materials[x.index_mat]->id_);
176✔
174
}
175

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