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

openmc-dev / openmc / 21489137916

29 Jan 2026 05:58PM UTC coverage: 81.248% (-0.7%) from 81.953%
21489137916

Pull #3757

github

web-flow
Merge 9d16542dd into f7a734189
Pull Request #3757: Testing point detectors

17267 of 24417 branches covered (70.72%)

Branch coverage included in aggregate %.

94 of 512 new or added lines in 26 files covered. (18.36%)

3 existing lines in 2 files now uncovered.

55822 of 65541 relevant lines covered (85.17%)

43735001.71 hits per line

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

63.37
/src/distribution_multi.cpp
1
#include "openmc/distribution_multi.h"
2

3
#include <algorithm> // for move
4
#include <cmath>     // for sqrt, sin, cos, max
5

6
#include "openmc/constants.h"
7
#include "openmc/error.h"
8
#include "openmc/math_functions.h"
9
#include "openmc/random_dist.h"
10
#include "openmc/random_lcg.h"
11
#include "openmc/xml_interface.h"
12

13
namespace openmc {
14

15
unique_ptr<UnitSphereDistribution> UnitSphereDistribution::create(
3,356✔
16
  pugi::xml_node node)
17
{
18
  // Check for type of angular distribution
19
  std::string type;
3,356✔
20
  if (check_for_node(node, "type"))
3,356!
21
    type = get_node_value(node, "type", true, true);
3,356✔
22
  if (type == "isotropic") {
3,356✔
23
    return UPtrAngle {new Isotropic(node)};
256✔
24
  } else if (type == "monodirectional") {
3,100✔
25
    return UPtrAngle {new Monodirectional(node)};
3,062✔
26
  } else if (type == "mu-phi") {
38!
27
    return UPtrAngle {new PolarAzimuthal(node)};
38✔
28
  } else {
29
    fatal_error(fmt::format(
×
30
      "Invalid angular distribution for external source: {}", type));
31
  }
32
}
3,356✔
33

34
//==============================================================================
35
// UnitSphereDistribution implementation
36
//==============================================================================
37

38
UnitSphereDistribution::UnitSphereDistribution(pugi::xml_node node)
3,356✔
39
{
40
  // Read reference directional unit vector
41
  if (check_for_node(node, "reference_uvw")) {
3,356✔
42
    auto u_ref = get_node_array<double>(node, "reference_uvw");
3,100✔
43
    if (u_ref.size() != 3)
3,100!
44
      fatal_error("Angular distribution reference direction must have "
×
45
                  "three parameters specified.");
46
    u_ref_ = Direction(u_ref.data());
3,100✔
47
    u_ref_ /= u_ref_.norm();
3,100✔
48
  }
3,100✔
49
}
3,356✔
50

51
//==============================================================================
52
// PolarAzimuthal implementation
53
//==============================================================================
54

55
PolarAzimuthal::PolarAzimuthal(Direction u, UPtrDist mu, UPtrDist phi)
×
56
  : UnitSphereDistribution {u}, mu_ {std::move(mu)}, phi_ {std::move(phi)}
×
57
{}
×
58

59
PolarAzimuthal::PolarAzimuthal(pugi::xml_node node)
38✔
60
  : UnitSphereDistribution {node}
38✔
61
{
62
  // Read reference directional unit vector
63
  if (check_for_node(node, "reference_vwu")) {
38!
64
    auto v_ref = get_node_array<double>(node, "reference_vwu");
38✔
65
    if (v_ref.size() != 3)
38!
66
      fatal_error("Angular distribution reference v direction must have "
×
67
                  "three parameters specified.");
68
    v_ref_ = Direction(v_ref.data());
38✔
69
    v_ref_ /= v_ref_.norm();
38✔
70
  }
38✔
71
  w_ref_ = u_ref_.cross(v_ref_);
38✔
72
  if (check_for_node(node, "mu")) {
38!
73
    pugi::xml_node node_dist = node.child("mu");
38✔
74
    mu_ = distribution_from_xml(node_dist);
38✔
75
  } else {
76
    mu_ = UPtrDist {new Uniform(-1., 1.)};
×
77
  }
78

79
  if (check_for_node(node, "phi")) {
38!
80
    pugi::xml_node node_dist = node.child("phi");
38✔
81
    phi_ = distribution_from_xml(node_dist);
38✔
82
  } else {
83
    phi_ = UPtrDist {new Uniform(0.0, 2.0 * PI)};
×
84
  }
85
}
38✔
86

87
std::pair<Direction, double> PolarAzimuthal::sample(uint64_t* seed) const
25,300✔
88
{
89
  return sample_impl(seed, false);
25,300✔
90
}
91

92
std::pair<Direction, double> PolarAzimuthal::sample_as_bias(
×
93
  uint64_t* seed) const
94
{
95
  return sample_impl(seed, true);
×
96
}
97

98
std::pair<Direction, double> PolarAzimuthal::sample_impl(
25,300✔
99
  uint64_t* seed, bool return_pdf) const
100
{
101
  // Sample cosine of polar angle
102
  auto [mu, mu_wgt] = mu_->sample(seed);
25,300✔
103

104
  // Sample azimuthal angle
105
  auto [phi, phi_wgt] = phi_->sample(seed);
25,300✔
106

107
  // Compute either the PDF value or the importance weight
108
  double weight =
109
    return_pdf ? (mu_->evaluate(mu) * phi_->evaluate(phi)) : (mu_wgt * phi_wgt);
25,300!
110

111
  if (mu == 1.0)
25,300✔
112
    return {u_ref_, weight};
759✔
113
  if (mu == -1.0)
24,541✔
114
    return {-u_ref_, weight};
1,628✔
115

116
  double f = std::sqrt(1 - mu * mu);
22,913✔
117
  return {mu * u_ref_ + f * std::cos(phi) * v_ref_ + f * std::sin(phi) * w_ref_,
45,826✔
118
    weight};
22,913✔
119
}
120

NEW
121
double PolarAzimuthal::evaluate(Direction u) const
×
122
{
NEW
123
  double mu = u.dot(u_ref_);
×
NEW
124
  double phi = std::acos(u.dot(v_ref_) / std::sqrt(1 - mu * mu));
×
NEW
125
  return mu_->evaluate(mu) * phi_->evaluate(phi);
×
126
}
127

128
//==============================================================================
129
// Isotropic implementation
130
//==============================================================================
131

132
Isotropic::Isotropic(pugi::xml_node node) : UnitSphereDistribution {node}
256✔
133
{
134
  if (check_for_node(node, "bias")) {
256!
135
    pugi::xml_node bias_node = node.child("bias");
×
136
    std::string bias_type = get_node_value(bias_node, "type", true, true);
×
137
    if (bias_type != "mu-phi") {
×
138
      openmc::fatal_error(
×
139
        "Isotropic distributions may only be biased by a PolarAzimuthal.");
140
    }
141
    auto bias = std::make_unique<PolarAzimuthal>(bias_node);
×
142
    if (bias->mu()->bias() || bias->phi()->bias()) {
×
143
      openmc::fatal_error(
×
144
        "Attempted to bias Isotropic distribution with a biased PolarAzimuthal "
145
        "distribution. Please ensure bias distributions are unbiased.");
146
    }
147
    this->set_bias(std::move(bias));
×
148
  }
×
149
}
256✔
150

151
Direction isotropic_direction(uint64_t* seed)
112,766,250✔
152
{
153
  double phi = uniform_distribution(0., 2.0 * PI, seed);
112,766,250✔
154
  double mu = uniform_distribution(-1., 1., seed);
112,766,250✔
155
  return {mu, std::sqrt(1.0 - mu * mu) * std::cos(phi),
112,766,250✔
156
    std::sqrt(1.0 - mu * mu) * std::sin(phi)};
112,766,250✔
157
}
158

159
std::pair<Direction, double> Isotropic::sample(uint64_t* seed) const
20,174,654✔
160
{
161
  if (bias()) {
20,174,654!
162
    auto [val, eval] = bias()->sample_as_bias(seed);
×
163
    return {val, 1.0 / (4.0 * PI * eval)};
×
164
  } else {
165
    return {isotropic_direction(seed), 1.0};
20,174,654✔
166
  }
167
}
168

NEW
169
double Isotropic::evaluate(Direction u) const
×
170
{
NEW
171
  return 1.0 / (4.0 * PI);
×
172
}
173

174
//==============================================================================
175
// Monodirectional implementation
176
//==============================================================================
177

178
std::pair<Direction, double> Monodirectional::sample(uint64_t* seed) const
14,335,854✔
179
{
180
  return {u_ref_, 1.0};
14,335,854✔
181
}
182

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