![]() |
|
|||
File indexing completed on 2025-09-17 08:53:33
0001 //------------------------------- -*- C++ -*- -------------------------------// 0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details 0003 // SPDmu-License-Identifier: (Apache-2.0 OR MIT) 0004 //---------------------------------------------------------------------------// 0005 //! \file celeritas/em/distribution/UrbanLargeAngleDistribution.hh 0006 //---------------------------------------------------------------------------// 0007 #pragma once 0008 0009 #include <cmath> 0010 0011 #include "corecel/Assert.hh" 0012 #include "corecel/Macros.hh" 0013 #include "corecel/Types.hh" 0014 #include "corecel/math/Algorithms.hh" 0015 #include "corecel/random/distribution/BernoulliDistribution.hh" 0016 #include "corecel/random/distribution/PowerDistribution.hh" 0017 #include "corecel/random/distribution/UniformRealDistribution.hh" 0018 #include "corecel/random/engine/CachedRngEngine.hh" 0019 0020 namespace celeritas 0021 { 0022 //---------------------------------------------------------------------------// 0023 /*! 0024 * Sample the large-angle MSC scattering cosine. 0025 * 0026 * \citet{urban-msc-2006, 0027 * https://cds.cern.ch/record/1004190/} proposes a convex combination of three 0028 * probability distribution functions: 0029 * \f[ 0030 * \begin{aligned} 0031 * g_0(\mu) &\sim \exp(-a(1 - \mu)), \\ 0032 * g_1(\mu) &\sim (b - \mu)^{-d}, \\ 0033 * g_2(\mu) &\sim 1 0034 * \end{aligned} 0035 * \f] 0036 * which have normalizing constants and sum to 0037 * \f[ 0038 * g(\mu) = p_1 p_2 g_0(\mu) + p_1(1-p_2) g_1(\mu) + (1-p_1) g_2(\mu). 0039 * \f] 0040 * 0041 * In this distribution for large angles, \f$ p_2 = 1 \f$ so only the 0042 * exponential and constant terms are sampled. 0043 * 0044 * 0045 * The Goudsmit-Saunderson moments for the expected angular deflection 0046 * \f$ \theta \f$ over a physical path length \f$ s \f$ are: \f[ 0047 \langle \cos \theta \rangle 0048 \equiv \langle \mu \rangle 0049 = \ee^{-s/\lambda_1} \ , 0050 * \f] and \f[ 0051 \langle \cos^2 \theta \rangle 0052 \equiv \langle \mu^2 \rangle 0053 = \frac{1}{3}\left(1 + 2 \ee^{-s / \lambda_2}\right) \ , 0054 * \f] 0055 * where the transport mean free paths \f$ \lambda_l \f$ are related to the 0056 * \f$ l \f$th angular moment of the elastic cross section scattering (see 0057 * Eqs. 6-8, 15-16 from \citet{fernandez-msc-1993, 0058 * https://doi.org/10.1016/0168-583X(93)95827-R} 0059 * ). 0060 * 0061 * Given the number of mean free paths \f[ 0062 \tau \equiv \frac{s}{\lambda_1} \ , 0063 * \f] 0064 * and from \citet{kawrakow-condensedhistory-1998, 0065 * https://doi.org/10.1016/S0168-583X(98)00274-2} that for kinetic energies 0066 * between a few keV and infinity, \f[ 0067 2 < \frac{\lambda_2}{\lambda_1} < \infty \ , 0068 * \f] 0069 * this class calculates the mean scattering angle and approximates the second 0070 * moment of the scattering cosine using 0071 * \f$ \lambda_2 \approx 2.5 \lambda_1 \f$. 0072 * 0073 * Using these moments, Urban calculates: \f[ 0074 a = \frac{2\langle \mu \rangle + 9\langle \mu^2 \rangle - 3} 0075 {2\langle \mu \rangle - 3\langle \mu^2 \rangle + 1} 0076 * \f] and 0077 * \f[ 0078 p_1 = \frac{(a + 2)\langle \mu \rangle}{a} \,. 0079 * \f] 0080 */ 0081 class UrbanLargeAngleDistribution 0082 { 0083 public: 0084 // Construct with mean free path tau 0085 explicit inline CELER_FUNCTION UrbanLargeAngleDistribution(real_type tau); 0086 0087 // Sample cos(theta) 0088 template<class Engine> 0089 inline CELER_FUNCTION real_type operator()(Engine& rng); 0090 0091 private: 0092 BernoulliDistribution select_pow_{0}; 0093 PowerDistribution<> sample_pow_{0}; 0094 UniformRealDistribution<> sample_uniform_{}; 0095 }; 0096 0097 //---------------------------------------------------------------------------// 0098 // INLINE DEFINITIONS 0099 //---------------------------------------------------------------------------// 0100 /*! 0101 * Construct with mean values. 0102 */ 0103 CELER_FUNCTION 0104 UrbanLargeAngleDistribution::UrbanLargeAngleDistribution(real_type tau) 0105 { 0106 CELER_EXPECT(tau > 0); 0107 // Eq. 8.2 and \f$ \cos^2\theta \f$ term in Eq. 8.3 in PRM 0108 real_type mumean = std::exp(-tau); 0109 // NOTE: tau_big = 8 -> ~0.0003 < mumean < 1 0110 0111 real_type musqmean = (1 + 2 * std::exp(real_type(-2.5) * tau)) / 3; 0112 real_type a = (2 * mumean + 9 * musqmean - 3) 0113 / (2 * mumean - 3 * musqmean + 1); 0114 0115 select_pow_ = BernoulliDistribution{mumean * (1 + 2 / a)}; 0116 sample_pow_ = PowerDistribution<>{a}; 0117 } 0118 0119 //---------------------------------------------------------------------------// 0120 /*! 0121 * Sample from two parameters of the model function. 0122 * 0123 * \todo The cached RNG value is not necessary and is only for reproducing 0124 * previous results. It should be deleted the next time a rebaselining is 0125 * performed. 0126 */ 0127 template<class Engine> 0128 CELER_FUNCTION real_type UrbanLargeAngleDistribution::operator()(Engine& rng) 0129 { 0130 // Save the RNG result to preserve RNG stream from older Celeritas 0131 auto temp_rng = cache_rng_values<real_type, 1>(rng); 0132 // Sample u = (cos \theta + 1)/ 2 0133 real_type half_angle = select_pow_(rng) ? sample_pow_(temp_rng) 0134 : sample_uniform_(temp_rng); 0135 CELER_ASSERT(half_angle >= 0 && half_angle <= 1); 0136 0137 // Transform back to [-1, 1] 0138 return 2 * half_angle - 1; 0139 } 0140 0141 //---------------------------------------------------------------------------// 0142 } // 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 |
![]() ![]() |