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

openmc-dev / openmc / 19041149218

03 Nov 2025 04:12PM UTC coverage: 81.294% (-0.6%) from 81.872%
19041149218

Pull #3550

github

web-flow
Merge cc7c3a5ec into fd964bc9b
Pull Request #3550: [Point Detector] Add distribution get_pdf functionality

16664 of 23490 branches covered (70.94%)

Branch coverage included in aggregate %.

2 of 387 new or added lines in 13 files covered. (0.52%)

3 existing lines in 1 file now uncovered.

54148 of 63616 relevant lines covered (85.12%)

43073383.89 hits per line

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

74.67
/src/reaction_product.cpp
1
#include "openmc/reaction_product.h"
2

3
#include <string> // for string
4

5
#include <fmt/core.h>
6

7
#include "openmc/endf.h"
8
#include "openmc/error.h"
9
#include "openmc/hdf5_interface.h"
10
#include "openmc/memory.h"
11
#include "openmc/particle.h"
12
#include "openmc/random_lcg.h"
13
#include "openmc/secondary_correlated.h"
14
#include "openmc/secondary_kalbach.h"
15
#include "openmc/secondary_nbody.h"
16
#include "openmc/secondary_uncorrelated.h"
17

18
namespace openmc {
19

20
//==============================================================================
21
// ReactionProduct implementation
22
//==============================================================================
23

24
ReactionProduct::ReactionProduct(hid_t group)
3,458,019✔
25
{
26
  // Read particle type
27
  std::string temp;
3,458,019✔
28
  read_attribute(group, "particle", temp);
3,458,019✔
29
  particle_ = str_to_particle_type(temp);
3,458,019✔
30

31
  // Read emission mode and decay rate
32
  read_attribute(group, "emission_mode", temp);
3,458,019✔
33
  if (temp == "prompt") {
3,458,019✔
34
    emission_mode_ = EmissionMode::prompt;
3,379,431✔
35
  } else if (temp == "delayed") {
78,588!
36
    emission_mode_ = EmissionMode::delayed;
78,588✔
37
  } else if (temp == "total") {
×
38
    emission_mode_ = EmissionMode::total;
×
39
  }
40

41
  // Read decay rate for delayed emission
42
  if (emission_mode_ == EmissionMode::delayed) {
3,458,019✔
43
    if (attribute_exists(group, "decay_rate")) {
78,588!
44
      read_attribute(group, "decay_rate", decay_rate_);
78,588✔
45
    } else if (particle_ == ParticleType::neutron) {
×
46
      warning(fmt::format("Decay rate doesn't exist for delayed neutron "
×
47
                          "emission ({}).",
48
        object_name(group)));
×
49
    }
50
  }
51

52
  // Read secondary particle yield
53
  yield_ = read_function(group, "yield");
3,458,019✔
54

55
  int n;
56
  read_attribute(group, "n_distribution", n);
3,458,019✔
57

58
  for (int i = 0; i < n; ++i) {
6,917,091✔
59
    std::string s {"distribution_"};
3,459,072✔
60
    s.append(std::to_string(i));
3,459,072✔
61
    hid_t dgroup = open_group(group, s.c_str());
3,459,072✔
62

63
    // Read applicability
64
    if (n > 1) {
3,459,072✔
65
      hid_t app = open_dataset(dgroup, "applicability");
2,010✔
66
      applicability_.emplace_back(app);
2,010✔
67
      close_dataset(app);
2,010✔
68
    }
69

70
    // Determine distribution type and read data
71
    read_attribute(dgroup, "type", temp);
3,459,072✔
72
    if (temp == "uncorrelated") {
3,459,072✔
73
      distribution_.push_back(make_unique<UncorrelatedAngleEnergy>(dgroup));
3,340,200✔
74
    } else if (temp == "correlated") {
118,872✔
75
      distribution_.push_back(make_unique<CorrelatedAngleEnergy>(dgroup));
49,906✔
76
    } else if (temp == "nbody") {
68,966✔
77
      distribution_.push_back(make_unique<NBodyPhaseSpace>(dgroup));
735✔
78
    } else if (temp == "kalbach-mann") {
68,231!
79
      distribution_.push_back(make_unique<KalbachMann>(dgroup));
68,231✔
80
    }
81

82
    close_group(dgroup);
3,459,072✔
83
  }
3,459,072✔
84
}
3,458,019✔
85

86
ReactionProduct::ReactionProduct(const ChainNuclide::Product& product)
132✔
87
{
88
  particle_ = ParticleType::photon;
132✔
89
  emission_mode_ = EmissionMode::delayed;
132✔
90

91
  // Get chain nuclide object for radionuclide
92
  parent_nuclide_ = data::chain_nuclide_map.at(product.name);
132✔
93
  const auto& chain_nuc = data::chain_nuclides[parent_nuclide_].get();
132✔
94

95
  // Determine decay constant in [s^-1]
96
  decay_rate_ = chain_nuc->decay_constant();
132✔
97

98
  // Determine number of photons per decay and set yield
99
  double photon_per_sec = chain_nuc->photon_energy()->integral();
132✔
100
  double photon_per_decay = photon_per_sec / decay_rate_;
132✔
101
  vector<double> coef = {product.branching_ratio * photon_per_decay};
132✔
102
  yield_ = make_unique<Polynomial>(coef);
132✔
103

104
  // Set decay photon angle-energy distribution
105
  distribution_.push_back(
132✔
106
    make_unique<DecayPhotonAngleEnergy>(chain_nuc->photon_energy()));
264✔
107
}
132✔
108

109
void ReactionProduct::sample(
49,994,198✔
110
  double E_in, double& E_out, double& mu, uint64_t* seed) const
111
{
112
  auto n = applicability_.size();
49,994,198✔
113
  if (n > 1) {
49,994,198✔
114
    double prob = 0.0;
1,078✔
115
    double c = prn(seed);
1,078✔
116
    for (int i = 0; i < n; ++i) {
1,837!
117
      // Determine probability that i-th energy distribution is sampled
118
      prob += applicability_[i](E_in);
1,837✔
119

120
      // If i-th distribution is sampled, sample energy from the distribution
121
      if (c <= prob) {
1,837✔
122
        distribution_[i]->sample(E_in, E_out, mu, seed);
1,078✔
123
        break;
1,078✔
124
      }
125
    }
126
  } else {
127
    // If only one distribution is present, go ahead and sample it
128
    distribution_[0]->sample(E_in, E_out, mu, seed);
49,993,120✔
129
  }
130
}
49,994,198✔
131

NEW
132
double ReactionProduct::sample_energy_and_pdf(
×
133
  double E_in, double mu, double& E_out, uint64_t* seed) const
134
{
135

136
  int distribution_index;
NEW
137
  auto n = applicability_.size();
×
NEW
138
  if (n > 1) {
×
NEW
139
    double prob = 0.0;
×
NEW
140
    double c = prn(seed);
×
NEW
141
    for (int i = 0; i < n; ++i) {
×
142
      // Determine probability that i-th energy distribution is sampled
NEW
143
      prob += applicability_[i](E_in);
×
144

145
      // If i-th distribution is sampled, sample energy from the distribution
NEW
146
      if (c <= prob) {
×
147
        // distribution_[i]->sample(E_in, E_out, mu, seed);
NEW
148
        distribution_index = i;
×
NEW
149
        break;
×
150
      }
151
    }
152
  } else {
NEW
153
    distribution_index = 0;
×
154
  }
155
  // now extract pdf
156

NEW
157
  AngleEnergy* angleEnergyPtr = distribution_[distribution_index].get();
×
NEW
158
  return angleEnergyPtr->sample_energy_and_pdf(E_in, mu, E_out, seed);
×
159
}
160

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

© 2025 Coveralls, Inc