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