@@ -158,63 +158,44 @@ void TranslationalPeriodicBC::handle_particle(
158158// RotationalPeriodicBC implementation
159159// ==============================================================================
160160
161- RotationalPeriodicBC::RotationalPeriodicBC (int i_surf, int j_surf)
161+ RotationalPeriodicBC::RotationalPeriodicBC (
162+ int i_surf, int j_surf, PeriodicAxis axis)
162163 : PeriodicBC(i_surf, j_surf)
163164{
164165 Surface& surf1 {*model::surfaces[i_surf_]};
165166 Surface& surf2 {*model::surfaces[j_surf_]};
166167
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_ ));
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)) {
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_ ));
168+ // below convention for right handed coordinate system
169+ switch (axis) {
170+ case x:
171+ zero_axis_idx_ = 0 ; // x component of plane must be zero
172+ axis_1_idx_ = 1 ; // y component independent
173+ axis_2_idx_ = 2 ; // z component dependent
174+ break ;
175+ case y:
176+ // for a right handed coordinate system, z should be the independent axis
177+ // but this would cause the y-rotation case to be different than the other
178+ // two. using a left handed coordinate system and a negative rotation the
179+ // compute angle and rotation matrix behavior mimics that of the x and z
180+ // cases
181+ zero_axis_idx_ = 1 ; // y component of plane must be zero
182+ axis_1_idx_ = 0 ; // x component independent
183+ axis_2_idx_ = 2 ; // z component dependent
184+ break ;
185+ case z:
186+ zero_axis_idx_ = 2 ; // z component of plane must be zero
187+ axis_1_idx_ = 0 ; // x component independent
188+ axis_2_idx_ = 1 ; // y component dependent
189+ break ;
190+ default :
191+ throw std::invalid_argument (
192+ fmt::format (" You've specified an axis that is not x, y, or z." ));
197193 }
198194
199195 // Compute the surface normal vectors and make sure they are perpendicular
200- // to the z- axis
196+ // to the correct axis
201197 Direction norm1 = surf1.normal ({0 , 0 , 0 });
202198 Direction norm2 = surf2.normal ({0 , 0 , 0 });
203- if (std::abs (norm1.z ) > FP_PRECISION) {
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." ,
208- surf1.id_ ));
209- }
210- if (std::abs (norm2.z ) > FP_PRECISION) {
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." ,
215- surf2.id_ ));
216- }
217-
218199 // Make sure both surfaces intersect the origin
219200 if (std::abs (surf1.evaluate ({0 , 0 , 0 })) > FP_COINCIDENT) {
220201 throw std::invalid_argument (fmt::format (
@@ -231,15 +212,8 @@ RotationalPeriodicBC::RotationalPeriodicBC(int i_surf, int j_surf)
231212 surf2.id_ ));
232213 }
233214
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;
215+ angle_ = compute_periodic_rotation (norm1[axis_2_idx_], norm1[axis_1_idx_],
216+ norm2[axis_2_idx_], norm2[axis_1_idx_]);
243217
244218 // Warn the user if the angle does not evenly divide a circle
245219 double rem = std::abs (std::remainder ((2 * PI / angle_), 1.0 ));
@@ -251,6 +225,20 @@ RotationalPeriodicBC::RotationalPeriodicBC(int i_surf, int j_surf)
251225 }
252226}
253227
228+ double RotationalPeriodicBC::compute_periodic_rotation (
229+ double rise_1, double run_1, double rise_2, double run_2) const
230+ {
231+ // Compute the BC rotation angle. Here it is assumed that both surface
232+ // normal vectors point inwards---towards the valid geometry region.
233+ // Consequently, the rotation angle is not the difference between the two
234+ // normals, but is instead the difference between one normal and one
235+ // anti-normal. (An incident ray on one surface must be an outgoing ray on
236+ // the other surface after rotation hence the anti-normal.)
237+ double theta1 = std::atan2 (rise_1, run_1);
238+ double theta2 = std::atan2 (rise_2, run_2) + PI;
239+ return theta2 - theta1;
240+ }
241+
254242void RotationalPeriodicBC::handle_particle (
255243 Particle& p, const Surface& surf) const
256244{
@@ -278,10 +266,16 @@ void RotationalPeriodicBC::handle_particle(
278266 Direction u = p.u ();
279267 double cos_theta = std::cos (theta);
280268 double sin_theta = std::sin (theta);
281- Position new_r = {
282- cos_theta * r.x - sin_theta * r.y , sin_theta * r.x + cos_theta * r.y , r.z };
283- Direction new_u = {
284- cos_theta * u.x - sin_theta * u.y , sin_theta * u.x + cos_theta * u.y , u.z };
269+
270+ Position new_r;
271+ new_r[zero_axis_idx_] = r[zero_axis_idx_];
272+ new_r[axis_1_idx_] = cos_theta * r[axis_1_idx_] - sin_theta * r[axis_2_idx_];
273+ new_r[axis_2_idx_] = sin_theta * r[axis_1_idx_] + cos_theta * r[axis_2_idx_];
274+
275+ Direction new_u;
276+ new_u[zero_axis_idx_] = u[zero_axis_idx_];
277+ new_u[axis_1_idx_] = cos_theta * u[axis_1_idx_] - sin_theta * u[axis_2_idx_];
278+ new_u[axis_2_idx_] = sin_theta * u[axis_1_idx_] + cos_theta * u[axis_2_idx_];
285279
286280 // Handle the effects of the surface albedo on the particle's weight.
287281 BoundaryCondition::handle_albedo (p, surf);
0 commit comments