|
|
|||
File indexing completed on 2026-11-01 10:19:51
0001 //------------------------------- -*- C++ -*- -------------------------------// 0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details 0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT) 0004 //---------------------------------------------------------------------------// 0005 //! \file orange/surf/Involute.hh 0006 //---------------------------------------------------------------------------// 0007 #pragma once 0008 0009 #include <cassert> 0010 #include <cmath> 0011 0012 #include "corecel/Constants.hh" 0013 #include "corecel/Types.hh" 0014 #include "corecel/cont/Array.hh" 0015 #include "corecel/cont/Span.hh" 0016 #include "corecel/math/Algorithms.hh" 0017 #include "corecel/math/ArrayUtils.hh" 0018 #include "orange/OrangeTypes.hh" 0019 0020 #include "detail/InvolutePoint.hh" 0021 #include "detail/InvoluteSolver.hh" 0022 0023 namespace celeritas 0024 { 0025 //---------------------------------------------------------------------------// 0026 /*! 0027 * Z-aligned circular involute. 0028 * 0029 * An involute is a curve created by unwinding a chord from a shape. 0030 * The involute implemented here is constructed from a circle and can be made 0031 * to be clockwise (negative) or anti-clockwise (positive). 0032 * This involute is the same type of that found in HFIR, and is necessary for 0033 * building accurate models. 0034 * 0035 * While the parameters define the curve itself have no restriction, except for 0036 * the radius of involute being positive, the involute needs to be bounded for 0037 * there to be finite solutions to the roots of the intersection points. 0038 * Additionally this bound cannot exceed an interval of size of 2 to be able to 0039 * determine if whether a particle is in, out, or on the involute surface. 0040 * Lastly the involute geometry is fixed to be z-aligned. 0041 * 0042 * \f[ 0043 * x = r_b (\cos(t+a) + t \sin(t+a)) + x_0 0044 * \f] 0045 * \f[ 0046 * y = r_b (\sin(t+a) - t \cos(t+a)) + y_0 0047 * \f] 0048 * 0049 * where \em t is the normal angle of the tangent to the circle of involute 0050 * with radius \em r_b from a starting angle of \em a (\f$r/h\f$ for a finite 0051 * cone. 0052 */ 0053 class Involute 0054 { 0055 public: 0056 //@{ 0057 //! \name Type aliases 0058 using Intersections = Array<real_type, 3>; 0059 using StorageSpan = Span<real_type const, 6>; 0060 using Real2 = Array<real_type, 2>; 0061 //@} 0062 0063 public: 0064 //// CLASS ATTRIBUTES //// 0065 0066 // Surface type identifier 0067 static CELER_CONSTEXPR_FUNCTION SurfaceType surface_type() 0068 0069 { 0070 return SurfaceType::inv; 0071 } 0072 0073 //! Safety cannot be trivially calculated 0074 static CELER_CONSTEXPR_FUNCTION bool simple_safety() { return false; } 0075 0076 public: 0077 //// CONSTRUCTORS //// 0078 0079 explicit Involute(Real2 const& origin, 0080 real_type radius, 0081 real_type displacement, 0082 Chirality sign, 0083 real_type tmin, 0084 real_type tmax); 0085 0086 // Construct from raw data 0087 template<class R> 0088 explicit inline CELER_FUNCTION Involute(Span<R, StorageSpan::extent>); 0089 0090 //// ACCESSORS //// 0091 0092 //! X-Y center of the circular base of the involute 0093 CELER_FUNCTION Real2 const& origin() const { return origin_; } 0094 0095 //! Involute circle's radius 0096 CELER_FUNCTION real_type r_b() const { return std::fabs(r_b_); } 0097 0098 //! Displacement angle 0099 CELER_FUNCTION real_type displacement_angle() const { return a_; } 0100 0101 // Orientation of the involute curve 0102 inline CELER_FUNCTION Chirality sign() const; 0103 0104 //! Get bounds of the involute 0105 CELER_FUNCTION real_type tmin() const { return tmin_; } 0106 CELER_FUNCTION real_type tmax() const { return tmax_; } 0107 0108 //! Get a view to the data for type-deleted storage 0109 CELER_FUNCTION StorageSpan data() const { return {&origin_[0], 6}; } 0110 0111 //// CALCULATION //// 0112 0113 // Determine the sense of the position relative to this surface 0114 inline CELER_FUNCTION SignedSense calc_sense(Real3 const& pos) const; 0115 0116 // Calculate all possible straight-line intersections with this surface 0117 inline CELER_FUNCTION Intersections calc_intersections( 0118 Real3 const& pos, Real3 const& dir, SurfaceState on_surface) const; 0119 0120 // Calculate outward normal at a position 0121 inline CELER_FUNCTION Real3 calc_normal(Real3 const& pos) const; 0122 0123 private: 0124 // Location of the center of circle of involute 0125 Real2 origin_; 0126 0127 // Involute parameters 0128 real_type r_b_; // Radius, negative if "clockwise" (flipped) 0129 real_type a_; 0130 0131 // Bounds 0132 real_type tmin_; 0133 real_type tmax_; 0134 }; 0135 0136 //---------------------------------------------------------------------------// 0137 // INLINE DEFINITIONS 0138 //---------------------------------------------------------------------------// 0139 /*! 0140 * Construct from raw data. 0141 */ 0142 template<class R> 0143 CELER_FUNCTION Involute::Involute(Span<R, StorageSpan::extent> data) 0144 : origin_{data[0], data[1]} 0145 , r_b_{data[2]} 0146 , a_{data[3]} 0147 , tmin_{data[4]} 0148 , tmax_{data[5]} 0149 { 0150 } 0151 0152 //---------------------------------------------------------------------------// 0153 /*! 0154 * Orientation of the involute curve. 0155 */ 0156 CELER_FUNCTION auto Involute::sign() const -> Chirality 0157 { 0158 return r_b_ > 0 ? Chirality::left : Chirality::right; 0159 } 0160 0161 //---------------------------------------------------------------------------// 0162 /*! 0163 * Determine the sense of the position relative to this surface. 0164 * 0165 * This is performed by first checking if the particle is outside the bounding 0166 * circles given by tmin and tmax. 0167 * 0168 * Then position is compared to a point on the involute at the same radius from 0169 * the origin. 0170 * 0171 * Next the point is determined to be inside if an involute that passes it, 0172 * has an \em t that is within the bounds and an \em a greater than the 0173 * involute being tested for. To do this, the tangent to the involute must be 0174 * determined by calculating the intercepts of the circle of involute and 0175 * circle centered at the midpoint of the origin and the point being tested for 0176 * that extends to the origin. After which the angle of tangent point can be 0177 * determined and used to calculate \em a via: \f[ 0178 * a = angle - t_point 0179 * \f] 0180 * 0181 * To calculate the intercept of two circles it is assumed that the two circles 0182 * are \em x_prime axis. The coordinate along \em x_prime originating from the 0183 * center of one of the circles is given by: \f[ x_prime = (d^2 - r^2 + 0184 * R^2)/(2d) \f] Where \em d is the distance between the center of the two 0185 * circles, \em r is the radius of the displaced circle, and \em R is the 0186 * radius of the circle at the origin. Then the point \em y_prime can be 0187 * obatined from: \f[ y_prime = \pm sqrt(R^2 - x_prime^2) \f] Then to convert ( 0188 * \em x_prime , \em y_prime ) to ( \em x, \em y ) the following rotation is 0189 * applied:\f[ x = x_prime*cos(theta) - y_prime*sin(theta) y = 0190 * y_prime*cos(theta) + x_prime*sin(theta) \f] Where \em theta is the angle 0191 * between the \em x_prime axis and the \em x axis. 0192 */ 0193 CELER_FUNCTION SignedSense Involute::calc_sense(Real3 const& pos) const 0194 { 0195 using constants::pi; 0196 0197 Real2 xy; 0198 xy[0] = pos[0] - origin_[0]; 0199 xy[1] = pos[1] - origin_[1]; 0200 0201 if (this->sign() == Chirality::right) 0202 { 0203 xy[0] = negate(xy[0]); 0204 } 0205 0206 // Calculate distance to origin and obtain t value for distance. 0207 real_type const t_point_sq = dot_product(xy, xy) / ipow<2>(r_b_) - 1; 0208 0209 // Check if point is in defined bounds. 0210 if (t_point_sq < ipow<2>(tmin_)) 0211 { 0212 return SignedSense::outside; 0213 } 0214 if (t_point_sq > ipow<2>(tmax_)) 0215 { 0216 return SignedSense::outside; 0217 } 0218 0219 // Check if Point is on involute. 0220 detail::InvolutePoint calc_point{this->r_b(), a_}; 0221 Real2 point = calc_point(clamp_to_nonneg(t_point_sq)); 0222 0223 if (xy == point) 0224 { 0225 return SignedSense::on; 0226 } 0227 0228 // Check if point is in interval 0229 0230 // Calculate tangent point 0231 // TODO: check that compiler avoids recomputing trig functions 0232 real_type x_prime = ipow<2>(r_b_) / norm(xy); 0233 real_type y_prime = std::sqrt(ipow<2>(r_b_) - ipow<2>(x_prime)); 0234 0235 // TODO: check that compiler avoids recomputing trig functions 0236 point[0] = (x_prime * xy[0] - y_prime * xy[1]) / norm(xy); 0237 point[1] = (y_prime * xy[0] + x_prime * xy[1]) / norm(xy); 0238 0239 // Calculate angle of tangent 0240 real_type theta = std::acos(point[0] / norm(point)); 0241 if (point[1] < 0) 0242 { 0243 theta = 2 * pi - theta; 0244 } 0245 // Count number of positive rotations around involute 0246 using namespace celeritas::literals; 0247 theta += max<real_type>(0_r, std::floor((tmax_ + a_ - theta) / (2 * pi))) 0248 * 2 * pi; 0249 0250 // Calculate the displacement angle of the point 0251 real_type a1 = theta - std::sqrt(clamp_to_nonneg(t_point_sq)); 0252 0253 // Check if point is inside bounds 0254 if (theta < tmax_ + a_ && a1 > a_) 0255 { 0256 return SignedSense::inside; 0257 } 0258 0259 return SignedSense::outside; 0260 } 0261 0262 //---------------------------------------------------------------------------// 0263 /*! 0264 * Calculate all possible straight-line intersections with this surface. 0265 */ 0266 CELER_FUNCTION auto Involute::calc_intersections( 0267 Real3 const& pos, Real3 const& dir, SurfaceState on_surface) const 0268 -> Intersections 0269 { 0270 // Expand translated positions into 'xyz' coordinate system 0271 Real3 rel_pos{pos}; 0272 rel_pos[0] -= origin_[0]; 0273 rel_pos[1] -= origin_[1]; 0274 0275 detail::InvoluteSolver solve(this->r_b(), a_, this->sign(), tmin_, tmax_); 0276 0277 return solve(rel_pos, dir, on_surface); 0278 } 0279 0280 //---------------------------------------------------------------------------// 0281 /*! 0282 * Calculate outward normal at a position on the surface. 0283 * 0284 * This is done by taking the derivative of the involute equation : \f[ 0285 * n = {\sin(t+a) - \cos(t+a), 0} 0286 * \f] 0287 */ 0288 CELER_FORCEINLINE_FUNCTION Real3 Involute::calc_normal(Real3 const& pos) const 0289 { 0290 Real2 xy; 0291 xy[0] = pos[0] - origin_[0]; 0292 xy[1] = pos[1] - origin_[1]; 0293 0294 // Calculate normal 0295 real_type const angle 0296 = std::sqrt(clamp_to_nonneg(dot_product(xy, xy) / ipow<2>(r_b_) - 1)) 0297 + a_; 0298 Real3 normal_ = {std::sin(angle), -std::cos(angle), 0}; 0299 0300 if (this->sign() == Chirality::right) 0301 { 0302 normal_[0] = negate(normal_[0]); 0303 } 0304 0305 return normal_; 0306 } 0307 0308 //---------------------------------------------------------------------------// 0309 } // namespace celeritas
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|