![]() |
|
|||
File indexing completed on 2025-02-22 10:31:18
0001 //----------------------------------*-C++-*----------------------------------// 0002 // Copyright 2023-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 celeritas/em/msc/detail/MscStepFromGeo.hh 0007 //---------------------------------------------------------------------------// 0008 #pragma once 0009 0010 #include <cmath> 0011 0012 #include "corecel/math/Algorithms.hh" 0013 #include "corecel/math/NumericLimits.hh" 0014 #include "corecel/math/SoftEqual.hh" 0015 #include "celeritas/Types.hh" 0016 #include "celeritas/em/data/UrbanMscData.hh" 0017 #include "celeritas/phys/Interaction.hh" 0018 0019 namespace celeritas 0020 { 0021 namespace detail 0022 { 0023 //---------------------------------------------------------------------------// 0024 /*! 0025 * Convert the "geometrical" path traveled to the true path with MSC. 0026 * 0027 * The "true" step length is the physical path length taken along the 0028 * geometrical path length (which is straight without magnetic fields or curved 0029 * with them), accounting for the extra distance taken between 0030 * along-step elastic collisions. 0031 * 0032 * The transformation can be written as 0033 * \f[ 0034 * t(z) = \langle t \rangle = -\lambda_{1} \log(1 - \frac{z}{\lambda_{1}}) 0035 * \f] 0036 * or \f$ t(z) = \frac{1}{\alpha} [ 1 - (1-\alpha w z)^{1/w}] \f$ if the 0037 * geom path is small, where \f$ w = 1 + \frac{1}{\alpha \lambda_{10}}\f$. 0038 * 0039 * \param true_path the proposed step before transportation. 0040 * \param gstep the proposed step after transportation. 0041 * \param alpha variable from UrbanMscStepLimit. 0042 */ 0043 class MscStepFromGeo 0044 { 0045 public: 0046 //!@{ 0047 //! \name Type aliases 0048 using MscParameters = UrbanMscParameters; 0049 //!@} 0050 0051 public: 0052 // Construct with path length data 0053 inline CELER_FUNCTION MscStepFromGeo(MscParameters const& params_, 0054 MscStep const& step, 0055 real_type range, 0056 real_type lambda); 0057 0058 // Calculate the true path 0059 inline CELER_FUNCTION real_type operator()(real_type gstep) const; 0060 0061 private: 0062 // Urban MSC parameters 0063 MscParameters const& params_; 0064 //! Physical path length limited and transformed by MSC 0065 real_type true_step_; 0066 //! Scaled slope of the MFP 0067 real_type alpha_; 0068 //! Range for checking edge cases 0069 real_type range_; 0070 //! MFP at the start of step 0071 real_type lambda_; 0072 }; 0073 0074 //---------------------------------------------------------------------------// 0075 // INLINE DEFINITIONS 0076 //---------------------------------------------------------------------------// 0077 /*! 0078 * Construct from MSC data. 0079 */ 0080 CELER_FUNCTION MscStepFromGeo::MscStepFromGeo(MscParameters const& params, 0081 MscStep const& step, 0082 real_type range, 0083 real_type lambda) 0084 : params_(params) 0085 , true_step_(step.true_path) 0086 , alpha_(step.alpha) 0087 , range_(range) 0088 , lambda_(lambda) 0089 { 0090 CELER_EXPECT(lambda_ > 0); 0091 CELER_EXPECT(true_step_ <= range_); 0092 // TODO: expect that the "skip sampling" conditions are false. 0093 } 0094 0095 //---------------------------------------------------------------------------// 0096 /*! 0097 * Calculate and return the true path from the input "geometrical" step. 0098 * 0099 * This should only be applied if the step was geometry-limited. Otherwise, the 0100 * original interaction length is correct. 0101 */ 0102 CELER_FUNCTION real_type MscStepFromGeo::operator()(real_type gstep) const 0103 { 0104 CELER_EXPECT(gstep >= 0 && gstep <= true_step_); 0105 0106 if (gstep < params_.min_step()) 0107 { 0108 // Geometrical path length is true path length for a very small step 0109 return gstep; 0110 } 0111 0112 real_type tstep = [&] { 0113 if (alpha_ == MscStep::small_step_alpha()) 0114 { 0115 // Cross section was assumed to be constant over the step: 0116 // z = lambda * (1 - exp(-g / lambda)) 0117 // => g = -lambda * log(1 - g / lambda) 0118 real_type tstep = -lambda_ * std::log1p(-gstep / lambda_); 0119 if (tstep < params_.min_step()) 0120 { 0121 // Geometrical path length = true path length for a very small 0122 // step 0123 return gstep; 0124 } 0125 return tstep; 0126 } 0127 0128 real_type w = 1 + 1 / (alpha_ * lambda_); 0129 real_type x = alpha_ * w * gstep; // = (1 - (1 - alpha * true)^w) 0130 // Range-limited step results in x = 1, which gives the correct 0131 // result in the inverted equation below for alpha = 1/range. 0132 // x >= 1 corresponds to the stopping MFP being <= 0: x=1 meaning 0133 // ending MFP of zero is correct when the step is the range. Precision 0134 // loss means this conversion also may result in x > 1, which we guard 0135 // against. 0136 x = min(x, real_type(1)); 0137 // Near x=1, (1 - (1-x)^(1/w)) suffers from numerical precision loss; 0138 // the maximum value of the expression should be range_. 0139 // TODO: we should use the action ID to avoid applying this 0140 // transformation if not range-limited. 0141 real_type temp = 1 - fastpow(1 - x, 1 / w); 0142 real_type result = temp / alpha_; 0143 return min(result, range_); 0144 }(); 0145 0146 // The result can be no less than the geometry path (effectively no 0147 // scattering took place) and no more than the original calculated true 0148 // path (if the step is path-limited). 0149 // The result can be slightly outside the bounds due to numerical 0150 // imprecision and edge cases: 0151 // - a few ULP due to inexactness of log1p/expm1 0152 // - small travel distance results in roundoff error inside (1 - 0153 // alpha/true)^w 0154 // - gstep is just above min_step so that the updated recalculation of 0155 // tstep is just below min_step 0156 return clamp(tstep, gstep, true_step_); 0157 } 0158 0159 //---------------------------------------------------------------------------// 0160 } // namespace detail 0161 } // 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 |
![]() ![]() |