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

openmc-dev / openmc / 16323087537

16 Jul 2025 03:01PM UTC coverage: 85.185% (+0.01%) from 85.174%
16323087537

Pull #3502

github

web-flow
Merge d100d055f into 6372c29cf
Pull Request #3502: A new FissionYieldsFilter for tallying fission yields.

77 of 83 new or added lines in 7 files covered. (92.77%)

1 existing line in 1 file now uncovered.

52627 of 61780 relevant lines covered (85.18%)

36785923.42 hits per line

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

92.21
/src/chain.cpp
1
//! \file chain.cpp
2
//! \brief Depletion chain and associated information
3

4
#include "openmc/chain.h"
5

6
#include <cstdlib> // for getenv
7
#include <memory>  // for make_unique
8
#include <string>  // for stod
9
#include <unordered_map>
10
#include <utility>
11

12
#include <fmt/core.h>
13
#include <pugixml.hpp>
14

15
#include "openmc/distribution.h" // for distribution_from_xml
16
#include "openmc/error.h"
17
#include "openmc/reaction.h"
18
#include "openmc/xml_interface.h" // for get_node_value
19

20
namespace openmc {
21

22
//==============================================================================
23
// FissionYields implementation
24
//==============================================================================
25

26
FissionYields::FissionYields(pugi::xml_node node)
7,758✔
27
{
28
  std::unordered_map<std::string, vector<std::pair<double, double>>> temp;
7,758✔
29
  auto energies = get_node_array<double>(node, "energies");
7,758✔
30
  for (pugi::xml_node fy : node.children("fission_yields")) {
15,516✔
31
    double energy = std::stod(get_node_value(fy, "energy"));
7,758✔
32
    auto products = get_node_array<std::string>(fy, "products");
7,758✔
33
    auto data = get_node_array<double>(fy, "data");
7,758✔
34
    for (int32_t i = 0; i < products.size(); ++i) {
54,306✔
35
      temp.insert({products[i], {}});
46,548✔
36
      temp[products[i]].push_back(std::make_pair(energy, data[i]));
46,548✔
37
    }
38
  }
7,758✔
39
  for (const auto& pair : temp) {
54,306✔
40
    vector<double> x_;
46,548✔
41
    vector<double> y_;
46,548✔
42
    for (const auto& v : pair.second) {
93,096✔
43
      x_.push_back(v.first);
46,548✔
44
      y_.push_back(v.second);
46,548✔
45
    }
46
    yields_[pair.first] = Tabulated1D(x_, y_);
46,548✔
47
  }
46,548✔
48
}
7,758✔
49

50
//==============================================================================
51
// ChainNuclide implementation
52
//==============================================================================
53

54
ChainNuclide::ChainNuclide(pugi::xml_node node)
23,505✔
55
{
56
  name_ = get_node_value(node, "name");
23,505✔
57
  if (check_for_node(node, "half_life")) {
23,505✔
58
    half_life_ = std::stod(get_node_value(node, "half_life"));
5,304✔
59
  }
60
  if (check_for_node(node, "decay_energy")) {
23,505✔
61
    decay_energy_ = std::stod(get_node_value(node, "decay_energy"));
5,304✔
62
  }
63

64
  // Read reactions to store MT -> product map
65
  for (pugi::xml_node reaction_node : node.children("reaction")) {
42,014✔
66
    std::string rx_name = get_node_value(reaction_node, "type");
18,509✔
67
    if (!reaction_node.attribute("target"))
18,509✔
68
      continue;
7,879✔
69
    std::string rx_target = get_node_value(reaction_node, "target");
10,630✔
70
    double branching_ratio = 1.0;
10,630✔
71
    if (reaction_node.attribute("branching_ratio")) {
10,630✔
72
      branching_ratio =
73
        std::stod(get_node_value(reaction_node, "branching_ratio"));
×
74
    }
75
    int mt = reaction_type(rx_name);
10,630✔
76
    reaction_products_[mt].push_back({rx_target, branching_ratio});
10,630✔
77
  }
18,509✔
78

79
  for (pugi::xml_node source_node : node.children("source")) {
23,538✔
80
    auto particle = get_node_value(source_node, "particle");
10,498✔
81
    if (particle == "photon") {
10,498✔
82
      photon_energy_ = distribution_from_xml(source_node);
10,465✔
83
      break;
10,465✔
84
    }
85
  }
10,498✔
86

87
  if (check_for_node(node, "neutron_fission_yields")) {
23,505✔
88
    pugi::xml_node nfy = node.child("neutron_fission_yields");
7,758✔
89
    if (check_for_node(nfy, "parent")) {
7,758✔
NEW
90
      fission_yields_parent_ = get_node_value(nfy, "parent");
×
91
    } else {
92
      data::fission_yields.push_back(std::make_unique<FissionYields>(nfy));
7,758✔
93
      fission_yields_ = data::fission_yields.back().get();
7,758✔
94
    }
95
  }
96

97
  // Set entry in mapping
98
  data::chain_nuclide_map[name_] = data::chain_nuclides.size();
23,505✔
99
}
23,505✔
100

101
ChainNuclide::~ChainNuclide()
23,505✔
102
{
103
  data::chain_nuclide_map.erase(name_);
23,505✔
104
}
23,505✔
105

106
FissionYields* ChainNuclide::fission_yields()
52,129✔
107
{
108
  if (fission_yields_parent_.size() > 0) {
52,129✔
NEW
109
    return data::chain_nuclides[data::chain_nuclide_map[fission_yields_parent_]]
×
NEW
110
      ->fission_yields();
×
111
  } else {
112
    return fission_yields_;
52,129✔
113
  }
114
}
115
//==============================================================================
116
// DecayPhotonAngleEnergy implementation
117
//==============================================================================
118

119
void DecayPhotonAngleEnergy::sample(
54,725✔
120
  double E_in, double& E_out, double& mu, uint64_t* seed) const
121
{
122
  E_out = photon_energy_->sample(seed);
54,725✔
123
  mu = Uniform(-1., 1.).sample(seed);
54,725✔
124
}
54,725✔
125

126
//==============================================================================
127
// Global variables
128
//==============================================================================
129

130
namespace data {
131

132
std::unordered_map<std::string, int> chain_nuclide_map;
133
vector<unique_ptr<ChainNuclide>> chain_nuclides;
134
vector<unique_ptr<FissionYields>> fission_yields;
135

136
} // namespace data
137

138
//==============================================================================
139
// Non-member functions
140
//==============================================================================
141

142
void read_chain_file_xml()
6,854✔
143
{
144
  char* chain_file_path = std::getenv("OPENMC_CHAIN_FILE");
6,854✔
145
  if (!chain_file_path) {
6,854✔
146
    return;
4,257✔
147
  }
148

149
  write_message(5, "Reading chain file: {}...", chain_file_path);
2,597✔
150

151
  pugi::xml_document doc;
2,597✔
152
  auto result = doc.load_file(chain_file_path);
2,597✔
153
  if (!result) {
2,597✔
154
    fatal_error(
×
155
      fmt::format("Error processing chain file: {}", chain_file_path));
×
156
  }
157

158
  // Get root element
159
  pugi::xml_node root = doc.document_element();
2,597✔
160

161
  for (auto node : root.children("nuclide")) {
26,102✔
162
    data::chain_nuclides.push_back(std::make_unique<ChainNuclide>(node));
23,505✔
163
  }
164
}
2,597✔
165

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