Skip to content

Commit bcd691a

Browse files
allow RotationalPeriodicBC around x,y, or z axis
1 parent 4011b7a commit bcd691a

File tree

2 files changed

+47
-46
lines changed

2 files changed

+47
-46
lines changed

include/openmc/boundary_condition.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,18 +138,23 @@ class TranslationalPeriodicBC : public PeriodicBC {
138138
//==============================================================================
139139
//! A BC that rotates particles about a global axis.
140140
//
141-
//! Currently only rotations about the z-axis are supported.
141+
//! Only rotations about the x, y, and z axes are supported.
142142
//==============================================================================
143143

144144
class RotationalPeriodicBC : public PeriodicBC {
145145
public:
146146
RotationalPeriodicBC(int i_surf, int j_surf);
147-
147+
float compute_periodic_rotation(float rise_1, float run_1, float rise_2, float run_2) const;
148148
void handle_particle(Particle& p, const Surface& surf) const override;
149149

150150
protected:
151151
//! Angle about the axis by which particle coordinates will be rotated
152152
double angle_;
153+
enum PeriodicAxis {x, y, z};
154+
//! Ensure that choice of axes is right handed. axis_1_idx_ corresponds to the independent axis and axis_2_idx_ corresponds to the dependent axis in the 2D plane perpendicular to the planes' axis of rotation
155+
int zero_axis_idx;
156+
int axis_1_idx_;
157+
int axis_2_idx_;
153158
};
154159

155160
} // namespace openmc

src/boundary_condition.cpp

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -158,56 +158,46 @@ void TranslationalPeriodicBC::handle_particle(
158158
// RotationalPeriodicBC implementation
159159
//==============================================================================
160160

161-
RotationalPeriodicBC::RotationalPeriodicBC(int i_surf, int j_surf)
161+
RotationalPeriodicBC::RotationalPeriodicBC(int i_surf, int j_surf, PeriodicAxis axis)
162162
: PeriodicBC(i_surf, j_surf)
163163
{
164164
Surface& surf1 {*model::surfaces[i_surf_]};
165165
Surface& surf2 {*model::surfaces[j_surf_]};
166166

167-
// Check the type of the first surface
168-
bool surf1_is_xyplane;
169-
if (const auto* ptr = dynamic_cast<const SurfaceXPlane*>(&surf1)) {
170-
surf1_is_xyplane = true;
171-
} else if (const auto* ptr = dynamic_cast<const SurfaceYPlane*>(&surf1)) {
172-
surf1_is_xyplane = true;
173-
} else if (const auto* ptr = dynamic_cast<const SurfacePlane*>(&surf1)) {
174-
surf1_is_xyplane = false;
175-
} else {
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.",
180-
surf1.id_));
167+
// below convention for right handed coordinate system
168+
switch(axis) {
169+
case x:
170+
zero_axis_idx = 0; // x component of plane must be zero
171+
axis_1_idx_ = 1; // y component independent
172+
axis_2_idx_ = 2; // z component dependent
173+
break;
174+
case y:
175+
zero_axis_idx = 1; // y component of plane must be zero
176+
axis_1_idx_ = 2; // z component independent
177+
axis_2_idx_ = 0; // x component dependent
178+
break;
179+
case z:
180+
zero_axis_idx = 2; // z component of plane must be zero
181+
axis_1_idx_ = 0; // x component independent
182+
axis_2_idx_ = 1; // y component dependent
183+
break;
184+
default:
185+
throw std::invalid_argument(fmt::format("You've specified an axis {} that is not x, y, or z."),axis)
181186
}
182187

183-
// Check the type of the second surface
184-
bool surf2_is_xyplane;
185-
if (const auto* ptr = dynamic_cast<const SurfaceXPlane*>(&surf2)) {
186-
surf2_is_xyplane = true;
187-
} else if (const auto* ptr = dynamic_cast<const SurfaceYPlane*>(&surf2)) {
188-
surf2_is_xyplane = true;
189-
} else if (const auto* ptr = dynamic_cast<const SurfacePlane*>(&surf2)) {
190-
surf2_is_xyplane = false;
191-
} else {
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.",
196-
surf2.id_));
197-
}
198188

199189
// Compute the surface normal vectors and make sure they are perpendicular
200-
// to the z-axis
190+
// to the correct axis
201191
Direction norm1 = surf1.normal({0, 0, 0});
202192
Direction norm2 = surf2.normal({0, 0, 0});
203-
if (std::abs(norm1.z) > FP_PRECISION) {
193+
if (std::abs(norm1[zero_axis_idx]) > FP_PRECISION) {
204194
throw std::invalid_argument(fmt::format(
205195
"Rotational periodic BCs are only "
206196
"supported for rotations about the z-axis, but surface {} is not "
207197
"perpendicular to the z-axis.",
208198
surf1.id_));
209199
}
210-
if (std::abs(norm2.z) > FP_PRECISION) {
200+
if (std::abs(norm2[zero_axis_idx]) > FP_PRECISION) {
211201
throw std::invalid_argument(fmt::format(
212202
"Rotational periodic BCs are only "
213203
"supported for rotations about the z-axis, but surface {} is not "
@@ -231,15 +221,7 @@ RotationalPeriodicBC::RotationalPeriodicBC(int i_surf, int j_surf)
231221
surf2.id_));
232222
}
233223

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);
241-
double theta2 = std::atan2(norm2.y, norm2.x) + PI;
242-
angle_ = theta2 - theta1;
224+
angle_ = compute_periodic_rotation(norm1[axis_2_idx_], norm1[axis_1_idx_], norm2[axis_2_idx_], norm2[axis_1_idx_])
243225

244226
// Warn the user if the angle does not evenly divide a circle
245227
double rem = std::abs(std::remainder((2 * PI / angle_), 1.0));
@@ -251,6 +233,20 @@ RotationalPeriodicBC::RotationalPeriodicBC(int i_surf, int j_surf)
251233
}
252234
}
253235

236+
float RotationalPeriodicBC::compute_periodic_rotation(
237+
float rise_1, float run_1, float rise_2, float run_2) const
238+
{
239+
// Compute the BC rotation angle. Here it is assumed that both surface
240+
// normal vectors point inwards---towards the valid geometry region.
241+
// Consequently, the rotation angle is not the difference between the two
242+
// normals, but is instead the difference between one normal and one
243+
// anti-normal. (An incident ray on one surface must be an outgoing ray on
244+
// the other surface after rotation hence the anti-normal.)
245+
double theta1 = std::atan2(rise_1, run_1);
246+
double theta2 = std::atan2(rise_2, run_2) + PI;
247+
return theta2 - theta1;
248+
}
249+
254250
void RotationalPeriodicBC::handle_particle(
255251
Particle& p, const Surface& surf) const
256252
{
@@ -279,9 +275,9 @@ void RotationalPeriodicBC::handle_particle(
279275
double cos_theta = std::cos(theta);
280276
double sin_theta = std::sin(theta);
281277
Position new_r = {
282-
cos_theta * r.x - sin_theta * r.y, sin_theta * r.x + cos_theta * r.y, r.z};
278+
cos_theta * r[axis_1_idx_] - sin_theta * r[axis_2_idx_], sin_theta * r[axis_1_idx_] + cos_theta * r[axis_2_idx_], r[zero_axis_idx]};
283279
Direction new_u = {
284-
cos_theta * u.x - sin_theta * u.y, sin_theta * u.x + cos_theta * u.y, u.z};
280+
cos_theta * u[axis_1_idx_] - sin_theta * u[axis_2_idx_], sin_theta * u[axis_1_idx_] + cos_theta * u[axis_2_idx_], u[zero_axis_idx]};
285281

286282
// Handle the effects of the surface albedo on the particle's weight.
287283
BoundaryCondition::handle_albedo(p, surf);

0 commit comments

Comments
 (0)