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