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

openmc-dev / openmc / 15445019261

04 Jun 2025 02:27PM UTC coverage: 85.129% (-0.08%) from 85.204%
15445019261

Pull #3406

github

web-flow
Merge 00f34c931 into ace73ab5d
Pull Request #3406: Implement a new MeshMaterialFilter

158 of 197 new or added lines in 6 files covered. (80.2%)

427 existing lines in 30 files now uncovered.

52286 of 61420 relevant lines covered (85.13%)

36683812.12 hits per line

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

76.29
/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✔
NEW
22
    fatal_error(
×
NEW
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✔
NEW
29
    fatal_error(
×
NEW
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)
35
  auto bins = get_node_array<int32_t>(node, "bins");
11✔
36
  if (bins.size() % 2 != 0) {
11✔
NEW
37
    fatal_error(
×
NEW
38
      fmt::format("Size of mesh material bins is not even: {}", bins.size()));
×
39
  }
40

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

55
  this->set_bins(std::move(element_mats));
11✔
56

57
  if (check_for_node(node, "translation")) {
11✔
NEW
58
    set_translation(get_node_array<double>(node, "translation"));
×
59
  }
60
}
11✔
61

62
void MeshMaterialFilter::set_bins(vector<ElementMat>&& bins)
11✔
63
{
64
  // Swap internal bins_ with the provided vector to avoid copying
65
  bins_.swap(bins);
11✔
66

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

78
  n_bins_ = bins_.size();
11✔
79
}
11✔
80

81
void MeshMaterialFilter::set_mesh(int32_t mesh)
11✔
82
{
83
  // perform any additional perparation for mesh tallies here
84
  mesh_ = mesh;
11✔
85
  model::meshes[mesh_]->prepare_for_point_location();
11✔
86
}
11✔
87

NEW
88
void MeshMaterialFilter::set_translation(const Position& translation)
×
89
{
NEW
90
  translated_ = true;
×
NEW
91
  translation_ = translation;
×
92
}
93

NEW
94
void MeshMaterialFilter::set_translation(const double translation[3])
×
95
{
NEW
96
  this->set_translation({translation[0], translation[1], translation[2]});
×
97
}
98

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

107
  Position last_r = p.r_last();
5,359,662✔
108
  Position r = p.r();
5,359,662✔
109
  Position u = p.u();
5,359,662✔
110

111
  // apply translation if present
112
  if (translated_) {
5,359,662✔
NEW
113
    last_r -= translation();
×
NEW
114
    r -= translation();
×
115
  }
116

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

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

148
    // Resize the vectors to remove the unmatched bins
149
    match.bins_.resize(n_start + i);
5,359,662✔
150
  }
151
}
152

153
void MeshMaterialFilter::to_statepoint(hid_t filter_group) const
11✔
154
{
155
  Filter::to_statepoint(filter_group);
11✔
156
  write_dataset(filter_group, "mesh", model::meshes[mesh_]->id_);
11✔
157

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

167
  if (translated_) {
11✔
NEW
168
    write_dataset(filter_group, "translation", translation_);
×
169
  }
170
}
11✔
171

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

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