File indexing completed on 2025-09-17 09:07:49
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <cmath>
0010
0011 #include "corecel/Constants.hh"
0012 #include "corecel/Types.hh"
0013 #include "corecel/cont/Array.hh"
0014 #include "corecel/math/Algorithms.hh"
0015 #include "corecel/math/ArrayOperators.hh"
0016 #include "corecel/math/BisectionRootFinder.hh"
0017 #include "corecel/math/IllinoisRootFinder.hh"
0018 #include "corecel/math/RegulaFalsiRootFinder.hh"
0019 #include "orange/OrangeTypes.hh"
0020
0021 #include "InvolutePoint.hh"
0022
0023 namespace celeritas
0024 {
0025 namespace detail
0026 {
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 class InvoluteSolver
0043 {
0044 public:
0045
0046
0047 using Intersections = Array<real_type, 3>;
0048 using SurfaceState = celeritas::SurfaceState;
0049 using Real2 = Array<real_type, 2>;
0050
0051
0052 static inline CELER_FUNCTION real_type line_angle_param(real_type u,
0053 real_type v);
0054
0055 public:
0056
0057 inline CELER_FUNCTION InvoluteSolver(real_type r_b,
0058 real_type a,
0059 Chirality sign,
0060 real_type tmin,
0061 real_type tmax);
0062
0063
0064 inline CELER_FUNCTION Intersections operator()(
0065 Real3 const& pos, Real3 const& dir, SurfaceState on_surface) const;
0066
0067
0068
0069 inline CELER_FUNCTION real_type calc_dist(
0070 real_type x, real_type y, real_type u, real_type v, real_type t) const;
0071
0072 static CELER_CONSTEXPR_FUNCTION real_type tol()
0073 {
0074 if constexpr (std::is_same_v<real_type, double>)
0075 return 1e-8;
0076 else if constexpr (std::is_same_v<real_type, float>)
0077 return 1e-5;
0078 }
0079
0080
0081
0082
0083 CELER_FUNCTION real_type r_b() const { return r_b_; }
0084 CELER_FUNCTION real_type a() const { return a_; }
0085 CELER_FUNCTION Chirality sign() const { return sign_; }
0086
0087
0088 CELER_FUNCTION real_type tmin() const { return tmin_; }
0089 CELER_FUNCTION real_type tmax() const { return tmax_; }
0090
0091 private:
0092
0093
0094 real_type r_b_;
0095 real_type a_;
0096 Chirality sign_;
0097
0098
0099 real_type tmin_;
0100 real_type tmax_;
0101 };
0102
0103
0104
0105
0106
0107
0108
0109 CELER_FUNCTION InvoluteSolver::InvoluteSolver(
0110 real_type r_b, real_type a, Chirality sign, real_type tmin, real_type tmax)
0111 : r_b_(r_b), a_(a), sign_(sign), tmin_(tmin), tmax_(tmax)
0112 {
0113 CELER_EXPECT(r_b > 0);
0114 CELER_EXPECT(a >= -constants::pi && a_ <= 2 * constants::pi);
0115 CELER_EXPECT(tmax > 0);
0116 CELER_EXPECT(tmin >= 0);
0117 CELER_EXPECT(tmax < 2 * constants::pi + tmin);
0118 }
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138 CELER_FUNCTION auto
0139 InvoluteSolver::operator()(Real3 const& pos,
0140 Real3 const& dir,
0141 SurfaceState on_surface) const -> Intersections
0142 {
0143 using constants::pi;
0144
0145 real_type x = pos[0];
0146 real_type const y = pos[1];
0147
0148 real_type u = dir[0];
0149 real_type v = dir[1];
0150
0151
0152 if (sign_ == Chirality::right)
0153 {
0154 x = -x;
0155 u = -u;
0156 }
0157
0158
0159 Intersections result;
0160 int j = 0;
0161
0162 result = {no_intersection(), no_intersection(), no_intersection()};
0163
0164
0165 if (u == 0 && v == 0)
0166 {
0167 return result;
0168 }
0169
0170
0171
0172 real_type convert = 1 / hypot(v, u);
0173 u *= convert;
0174 v *= convert;
0175
0176
0177
0178 real_type beta = line_angle_param(u, v);
0179
0180
0181
0182 real_type t_lower = 0;
0183 real_type t_upper = beta - a_;
0184
0185
0186 t_upper += max<real_type>(real_type{0}, -std::floor(t_upper / pi)) * pi;
0187
0188
0189 int i = 1;
0190
0191
0192 auto calc_t_intersect = [&](real_type t) {
0193 real_type alpha = u * std::sin(t + a_) - v * std::cos(t + a_);
0194 real_type beta = t * (u * std::cos(t + a_) + v * std::sin(t + a_));
0195 return r_b_ * (alpha - beta) + x * v - y * u;
0196 };
0197
0198
0199
0200
0201
0202
0203
0204 real_type tol_point
0205 = (on_surface == SurfaceState::on ? r_b_ * tol() * 100 : 0);
0206
0207
0208
0209 IllinoisRootFinder find_root_between{calc_t_intersect, r_b_ * tol()};
0210
0211
0212 while (t_lower < tmax_)
0213 {
0214
0215 real_type ft_lower = calc_t_intersect(t_lower);
0216 real_type ft_upper = calc_t_intersect(t_upper);
0217
0218
0219 if (signum<real_type>(ft_lower) != signum<real_type>(ft_upper))
0220 {
0221
0222 real_type t_gamma = find_root_between(t_lower, t_upper);
0223
0224
0225 real_type dist = calc_dist(x, y, u, v, t_gamma);
0226 if (dist > tol_point)
0227 {
0228 result[j] = convert * dist;
0229 j++;
0230 }
0231
0232
0233 t_lower = t_upper;
0234 t_upper += pi;
0235 }
0236 else
0237 {
0238
0239
0240 t_lower = t_upper;
0241 t_upper += pi / i;
0242 i++;
0243 }
0244 }
0245 return result;
0246 }
0247
0248
0249
0250
0251
0252
0253
0254 CELER_FUNCTION real_type InvoluteSolver::line_angle_param(real_type u,
0255 real_type v)
0256 {
0257 using constants::pi;
0258
0259 if (u != 0)
0260 {
0261
0262 return std::atan(-v / u);
0263 }
0264 else if (-v < 0)
0265 {
0266
0267 return pi * -0.5;
0268 }
0269 else
0270 {
0271 return pi * 0.5;
0272 }
0273 }
0274
0275
0276
0277
0278
0279
0280 CELER_FUNCTION real_type InvoluteSolver::calc_dist(
0281 real_type x, real_type y, real_type u, real_type v, real_type t) const
0282 {
0283 detail::InvolutePoint calc_point{r_b_, a_};
0284 Real2 point = calc_point(clamp_to_nonneg(t));
0285 real_type dist = 0;
0286
0287
0288 if (t >= tmin_ && t <= tmax_)
0289 {
0290
0291 real_type u_point = point[0] - x;
0292 real_type v_point = point[1] - y;
0293
0294
0295 real_type dot = u * u_point + v * v_point;
0296 real_type dot_sign = signum<real_type>(dot);
0297
0298 dist = std::sqrt(ipow<2>(u_point) + ipow<2>(v_point)) * dot_sign;
0299 }
0300 return dist;
0301 }
0302
0303
0304 }
0305 }