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

openmc-dev / openmc / 13134187828

04 Feb 2025 11:13AM UTC coverage: 84.945% (+0.08%) from 84.869%
13134187828

Pull #3252

github

web-flow
Merge 6f397fdd5 into 59c398be8
Pull Request #3252: Adding vtkhdf option to write vtk data

80 of 92 new or added lines in 1 file covered. (86.96%)

1267 existing lines in 48 files now uncovered.

50221 of 59122 relevant lines covered (84.94%)

35221818.06 hits per line

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

80.95
/src/boundary_condition.cpp
1
#include "openmc/boundary_condition.h"
2

3
#include <exception>
4

5
#include <fmt/core.h>
6

7
#include "openmc/constants.h"
8
#include "openmc/error.h"
9
#include "openmc/random_ray/random_ray.h"
10
#include "openmc/surface.h"
11

12
namespace openmc {
13

14
//==============================================================================
15
// VacuumBC implementation
16
//==============================================================================
17

18
void VacuumBC::handle_particle(Particle& p, const Surface& surf) const
26,999,791✔
19
{
20
  // Random ray and Monte Carlo need different treatments at vacuum BCs
21
  if (settings::solver_type == SolverType::RANDOM_RAY) {
26,999,791✔
22
    // Reflect ray off of the surface
23
    ReflectiveBC().handle_particle(p, surf);
5,190,492✔
24

25
    // Set ray's angular flux spectrum to vacuum conditions (zero)
26
    RandomRay* r = static_cast<RandomRay*>(&p);
5,190,492✔
27
    std::fill(r->angular_flux_.begin(), r->angular_flux_.end(), 0.0);
5,190,492✔
28

29
  } else {
30
    p.cross_vacuum_bc(surf);
21,809,299✔
31
  }
32
}
26,999,791✔
33

34
//==============================================================================
35
// ReflectiveBC implementation
36
//==============================================================================
37

38
void ReflectiveBC::handle_particle(Particle& p, const Surface& surf) const
661,486,274✔
39
{
40
  Direction u = surf.reflect(p.r(), p.u(), &p);
661,486,274✔
41
  u /= u.norm();
661,486,274✔
42

43
  // Handle the effects of the surface albedo on the particle's weight.
44
  BoundaryCondition::handle_albedo(p, surf);
661,486,274✔
45

46
  p.cross_reflective_bc(surf, u);
661,486,274✔
47
}
661,486,274✔
48

49
//==============================================================================
50
// WhiteBC implementation
51
//==============================================================================
52

53
void WhiteBC::handle_particle(Particle& p, const Surface& surf) const
1,109,436✔
54
{
55
  Direction u = surf.diffuse_reflect(p.r(), p.u(), p.current_seed());
1,109,436✔
56
  u /= u.norm();
1,109,436✔
57

58
  // Handle the effects of the surface albedo on the particle's weight.
59
  BoundaryCondition::handle_albedo(p, surf);
1,109,436✔
60

61
  p.cross_reflective_bc(surf, u);
1,109,436✔
62
}
1,109,436✔
63

64
//==============================================================================
65
// TranslationalPeriodicBC implementation
66
//==============================================================================
67

68
TranslationalPeriodicBC::TranslationalPeriodicBC(int i_surf, int j_surf)
180✔
69
  : PeriodicBC(i_surf, j_surf)
180✔
70
{
71
  Surface& surf1 {*model::surfaces[i_surf_]};
180✔
72
  Surface& surf2 {*model::surfaces[j_surf_]};
180✔
73

74
  // Make sure the first surface has an appropriate type.
75
  if (const auto* ptr = dynamic_cast<const SurfaceXPlane*>(&surf1)) {
180✔
76
  } else if (const auto* ptr = dynamic_cast<const SurfaceYPlane*>(&surf1)) {
146✔
77
  } else if (const auto* ptr = dynamic_cast<const SurfaceZPlane*>(&surf1)) {
146✔
78
  } else if (const auto* ptr = dynamic_cast<const SurfacePlane*>(&surf1)) {
68✔
79
  } else {
80
    throw std::invalid_argument(fmt::format(
×
81
      "Surface {} is an invalid type for "
82
      "translational periodic BCs. Only planes are supported for these BCs.",
83
      surf1.id_));
×
84
  }
85

86
  // Make sure the second surface has an appropriate type.
87
  if (const auto* ptr = dynamic_cast<const SurfaceXPlane*>(&surf2)) {
180✔
88
  } else if (const auto* ptr = dynamic_cast<const SurfaceYPlane*>(&surf2)) {
146✔
89
  } else if (const auto* ptr = dynamic_cast<const SurfaceZPlane*>(&surf2)) {
146✔
90
  } else if (const auto* ptr = dynamic_cast<const SurfacePlane*>(&surf2)) {
102✔
91
  } else {
92
    throw std::invalid_argument(fmt::format(
×
93
      "Surface {} is an invalid type for "
94
      "translational periodic BCs. Only planes are supported for these BCs.",
95
      surf2.id_));
×
96
  }
97

98
  // Compute the distance from the first surface to the origin.  Check the
99
  // surface evaluate function to decide if the distance is positive, negative,
100
  // or zero.
101
  Position origin {0, 0, 0};
180✔
102
  Direction u = surf1.normal(origin);
180✔
103
  double d1;
104
  double e1 = surf1.evaluate(origin);
180✔
105
  if (e1 > FP_COINCIDENT) {
180✔
106
    d1 = -surf1.distance(origin, -u, false);
78✔
107
  } else if (e1 < -FP_COINCIDENT) {
102✔
108
    d1 = surf1.distance(origin, u, false);
102✔
109
  } else {
110
    d1 = 0.0;
×
111
  }
112

113
  // Compute the distance from the second surface to the origin.
114
  double d2;
115
  double e2 = surf2.evaluate(origin);
180✔
116
  if (e2 > FP_COINCIDENT) {
180✔
117
    d2 = -surf2.distance(origin, -u, false);
102✔
118
  } else if (e2 < -FP_COINCIDENT) {
78✔
119
    d2 = surf2.distance(origin, u, false);
78✔
120
  } else {
121
    d2 = 0.0;
×
122
  }
123

124
  // Set the translation vector; it's length is the difference in the two
125
  // distances.
126
  translation_ = u * (d2 - d1);
180✔
127
}
180✔
128

129
void TranslationalPeriodicBC::handle_particle(
326,232✔
130
  Particle& p, const Surface& surf) const
131
{
132
  int i_particle_surf = p.surface_index();
326,232✔
133

134
  // Figure out which of the two BC surfaces were struck then find the
135
  // particle's new location and surface.
136
  Position new_r;
326,232✔
137
  int new_surface;
138
  if (i_particle_surf == i_surf_) {
326,232✔
139
    new_r = p.r() + translation_;
161,454✔
140
    new_surface = p.surface() > 0 ? j_surf_ + 1 : -(j_surf_ + 1);
161,454✔
141
  } else if (i_particle_surf == j_surf_) {
164,778✔
142
    new_r = p.r() - translation_;
164,778✔
143
    new_surface = p.surface() > 0 ? i_surf_ + 1 : -(i_surf_ + 1);
164,778✔
144
  } else {
UNCOV
145
    throw std::runtime_error(
×
146
      "Called BoundaryCondition::handle_particle after "
UNCOV
147
      "hitting a surface, but that surface is not recognized by the BC.");
×
148
  }
149

150
  // Handle the effects of the surface albedo on the particle's weight.
151
  BoundaryCondition::handle_albedo(p, surf);
326,232✔
152

153
  // Pass the new location and surface to the particle.
154
  p.cross_periodic_bc(surf, new_r, p.u(), new_surface);
326,232✔
155
}
326,232✔
156

157
//==============================================================================
158
// RotationalPeriodicBC implementation
159
//==============================================================================
160

161
RotationalPeriodicBC::RotationalPeriodicBC(int i_surf, int j_surf)
68✔
162
  : PeriodicBC(i_surf, j_surf)
68✔
163
{
164
  Surface& surf1 {*model::surfaces[i_surf_]};
68✔
165
  Surface& surf2 {*model::surfaces[j_surf_]};
68✔
166

167
  // Check the type of the first surface
168
  bool surf1_is_xyplane;
169
  if (const auto* ptr = dynamic_cast<const SurfaceXPlane*>(&surf1)) {
68✔
170
    surf1_is_xyplane = true;
34✔
171
  } else if (const auto* ptr = dynamic_cast<const SurfaceYPlane*>(&surf1)) {
34✔
UNCOV
172
    surf1_is_xyplane = true;
×
173
  } else if (const auto* ptr = dynamic_cast<const SurfacePlane*>(&surf1)) {
34✔
174
    surf1_is_xyplane = false;
34✔
175
  } else {
UNCOV
176
    throw std::invalid_argument(fmt::format(
×
177
      "Surface {} is an invalid type for "
178
      "rotational periodic BCs. Only x-planes, y-planes, or general planes "
179
      "(that are perpendicular to z) are supported for these BCs.",
UNCOV
180
      surf1.id_));
×
181
  }
182

183
  // Check the type of the second surface
184
  bool surf2_is_xyplane;
185
  if (const auto* ptr = dynamic_cast<const SurfaceXPlane*>(&surf2)) {
68✔
UNCOV
186
    surf2_is_xyplane = true;
×
187
  } else if (const auto* ptr = dynamic_cast<const SurfaceYPlane*>(&surf2)) {
68✔
188
    surf2_is_xyplane = true;
34✔
189
  } else if (const auto* ptr = dynamic_cast<const SurfacePlane*>(&surf2)) {
34✔
190
    surf2_is_xyplane = false;
34✔
191
  } else {
UNCOV
192
    throw std::invalid_argument(fmt::format(
×
193
      "Surface {} is an invalid type for "
194
      "rotational periodic BCs. Only x-planes, y-planes, or general planes "
195
      "(that are perpendicular to z) are supported for these BCs.",
UNCOV
196
      surf2.id_));
×
197
  }
198

199
  // Compute the surface normal vectors and make sure they are perpendicular
200
  // to the z-axis
201
  Direction norm1 = surf1.normal({0, 0, 0});
68✔
202
  Direction norm2 = surf2.normal({0, 0, 0});
68✔
203
  if (std::abs(norm1.z) > FP_PRECISION) {
68✔
UNCOV
204
    throw std::invalid_argument(fmt::format(
×
205
      "Rotational periodic BCs are only "
206
      "supported for rotations about the z-axis, but surface {} is not "
207
      "perpendicular to the z-axis.",
UNCOV
208
      surf1.id_));
×
209
  }
210
  if (std::abs(norm2.z) > FP_PRECISION) {
68✔
UNCOV
211
    throw std::invalid_argument(fmt::format(
×
212
      "Rotational periodic BCs are only "
213
      "supported for rotations about the z-axis, but surface {} is not "
214
      "perpendicular to the z-axis.",
UNCOV
215
      surf2.id_));
×
216
  }
217

218
  // Make sure both surfaces intersect the origin
219
  if (std::abs(surf1.evaluate({0, 0, 0})) > FP_COINCIDENT) {
68✔
UNCOV
220
    throw std::invalid_argument(fmt::format(
×
221
      "Rotational periodic BCs are only "
222
      "supported for rotations about the origin, but surface {} does not "
223
      "intersect the origin.",
UNCOV
224
      surf1.id_));
×
225
  }
226
  if (std::abs(surf2.evaluate({0, 0, 0})) > FP_COINCIDENT) {
68✔
UNCOV
227
    throw std::invalid_argument(fmt::format(
×
228
      "Rotational periodic BCs are only "
229
      "supported for rotations about the origin, but surface {} does not "
230
      "intersect the origin.",
UNCOV
231
      surf2.id_));
×
232
  }
233

234
  // Compute the BC rotation angle.  Here it is assumed that both surface
235
  // normal vectors point inwards---towards the valid geometry region.
236
  // Consequently, the rotation angle is not the difference between the two
237
  // normals, but is instead the difference between one normal and one
238
  // anti-normal.  (An incident ray on one surface must be an outgoing ray on
239
  // the other surface after rotation hence the anti-normal.)
240
  double theta1 = std::atan2(norm1.y, norm1.x);
68✔
241
  double theta2 = std::atan2(norm2.y, norm2.x) + PI;
68✔
242
  angle_ = theta2 - theta1;
68✔
243

244
  // Warn the user if the angle does not evenly divide a circle
245
  double rem = std::abs(std::remainder((2 * PI / angle_), 1.0));
68✔
246
  if (rem > FP_REL_PRECISION && rem < 1 - FP_REL_PRECISION) {
68✔
247
    warning(fmt::format(
34✔
248
      "Rotational periodic BC specified with a rotation "
249
      "angle of {} degrees which does not evenly divide 360 degrees.",
250
      angle_ * 180 / PI));
68✔
251
  }
252
}
68✔
253

254
void RotationalPeriodicBC::handle_particle(
400,932✔
255
  Particle& p, const Surface& surf) const
256
{
257
  int i_particle_surf = p.surface_index();
400,932✔
258

259
  // Figure out which of the two BC surfaces were struck to figure out if a
260
  // forward or backward rotation is required.  Specify the other surface as
261
  // the particle's new surface.
262
  double theta;
263
  int new_surface;
264
  if (i_particle_surf == i_surf_) {
400,932✔
265
    theta = angle_;
201,240✔
266
    new_surface = p.surface() > 0 ? -(j_surf_ + 1) : j_surf_ + 1;
201,240✔
267
  } else if (i_particle_surf == j_surf_) {
199,692✔
268
    theta = -angle_;
199,692✔
269
    new_surface = p.surface() > 0 ? -(i_surf_ + 1) : i_surf_ + 1;
199,692✔
270
  } else {
UNCOV
271
    throw std::runtime_error(
×
272
      "Called BoundaryCondition::handle_particle after "
273
      "hitting a surface, but that surface is not recognized by the BC.");
×
274
  }
275

276
  // Rotate the particle's position and direction about the z-axis.
277
  Position r = p.r();
400,932✔
278
  Direction u = p.u();
400,932✔
279
  double cos_theta = std::cos(theta);
400,932✔
280
  double sin_theta = std::sin(theta);
400,932✔
281
  Position new_r = {
282
    cos_theta * r.x - sin_theta * r.y, sin_theta * r.x + cos_theta * r.y, r.z};
400,932✔
283
  Direction new_u = {
284
    cos_theta * u.x - sin_theta * u.y, sin_theta * u.x + cos_theta * u.y, u.z};
400,932✔
285

286
  // Handle the effects of the surface albedo on the particle's weight.
287
  BoundaryCondition::handle_albedo(p, surf);
400,932✔
288

289
  // Pass the new location, direction, and surface to the particle.
290
  p.cross_periodic_bc(surf, new_r, new_u, new_surface);
400,932✔
291
}
400,932✔
292

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