Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:31:15

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2022-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/distribution/EnergyLossGaussianDistribution.hh
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include <cmath>
0011 
0012 #include "corecel/Assert.hh"
0013 #include "corecel/Macros.hh"
0014 #include "corecel/Types.hh"
0015 #include "corecel/math/Algorithms.hh"
0016 #include "celeritas/random/distribution/NormalDistribution.hh"
0017 
0018 #include "EnergyLossHelper.hh"
0019 
0020 namespace celeritas
0021 {
0022 //---------------------------------------------------------------------------//
0023 /*!
0024  * Sample energy loss from a Gaussian distribution.
0025  *
0026  * In a thick absorber, the total energy transfer is a result of many small
0027  * energy losses from a large number of collisions. The central limit theorem
0028  * applies, and the energy loss fluctuations can be described by a Gaussian
0029  * distribution. See section 7.3.1 of the Geant4 Physics Reference Manual and
0030  * GEANT3 PHYS332 section 2.3.
0031  *
0032  * The Gaussian approximation is valid for heavy particles and in the
0033  * regime \f$ \kappa = \xi / T_\textrm{max} > 10 \f$.
0034  * Fluctuations of the unrestricted energy loss
0035  * follow a Gaussian distribution if \f$ \Delta E > \kappa T_{max} \f$,
0036  * where \f$ T_{max} \f$ is the maximum energy transfer (PHYS332 section
0037  * 2). For fluctuations of the \em restricted energy loss, the condition is
0038  * modified to \f$ \Delta E > \kappa T_{c} \f$ and \f$ T_{max} \le 2 T_c
0039  * \f$, where \f$ T_c \f$ is the delta ray cutoff energy (PRM Eq. 7.6-7.7).
0040  */
0041 class EnergyLossGaussianDistribution
0042 {
0043   public:
0044     //!@{
0045     //! \name Type aliases
0046     using Energy = units::MevEnergy;
0047     using EnergySq = Quantity<UnitProduct<units::Mev, units::Mev>>;
0048     //!@}
0049 
0050   public:
0051     // Construct from distribution parameters
0052     inline CELER_FUNCTION
0053     EnergyLossGaussianDistribution(Energy mean_loss, Energy bohr_stddev);
0054 
0055     // Construct from helper distribution parameters
0056     inline CELER_FUNCTION
0057     EnergyLossGaussianDistribution(Energy mean_loss, EnergySq bohr_var);
0058 
0059     // Construct from helper-calculated data
0060     explicit inline CELER_FUNCTION
0061     EnergyLossGaussianDistribution(EnergyLossHelper const& helper);
0062 
0063     // Sample energy loss according to the distribution
0064     template<class Generator>
0065     inline CELER_FUNCTION Energy operator()(Generator& rng);
0066 
0067   private:
0068     real_type const max_loss_;
0069     NormalDistribution<real_type> sample_normal_;
0070 };
0071 
0072 //---------------------------------------------------------------------------//
0073 // INLINE DEFINITIONS
0074 //---------------------------------------------------------------------------//
0075 /*!
0076  * Construct from mean/stddev.
0077  *
0078  * This formulation is used internally by the Urban distribution.
0079  */
0080 CELER_FUNCTION EnergyLossGaussianDistribution::EnergyLossGaussianDistribution(
0081     Energy mean_loss, Energy bohr_stddev)
0082     : max_loss_(2 * mean_loss.value())
0083     , sample_normal_(mean_loss.value(), bohr_stddev.value())
0084 
0085 {
0086     CELER_EXPECT(mean_loss > zero_quantity());
0087     CELER_EXPECT(bohr_stddev > zero_quantity());
0088 }
0089 
0090 //---------------------------------------------------------------------------//
0091 /*!
0092  * Construct from distribution parameters.
0093  *
0094  * The mean loss is the energy lost over the step, and the standard deviation
0095  * is the square root of Bohr's variance (PRM Eq. 7.8). For thick absorbers,
0096  * the straggling function approaches a Gaussian distribution with this
0097  * standard deviation.
0098  */
0099 CELER_FUNCTION EnergyLossGaussianDistribution::EnergyLossGaussianDistribution(
0100     Energy mean_loss, EnergySq bohr_var)
0101     : EnergyLossGaussianDistribution{mean_loss,
0102                                      Energy{std::sqrt(bohr_var.value())}}
0103 {
0104 }
0105 
0106 //---------------------------------------------------------------------------//
0107 /*!
0108  * Construct from helper-calculated data.
0109  */
0110 CELER_FUNCTION EnergyLossGaussianDistribution::EnergyLossGaussianDistribution(
0111     EnergyLossHelper const& helper)
0112     : EnergyLossGaussianDistribution{helper.mean_loss(), helper.bohr_variance()}
0113 {
0114 }
0115 
0116 //---------------------------------------------------------------------------//
0117 /*!
0118  * Sample energy loss according to the distribution.
0119  */
0120 template<class Generator>
0121 CELER_FUNCTION auto
0122 EnergyLossGaussianDistribution::operator()(Generator& rng) -> Energy
0123 {
0124     real_type result;
0125     do
0126     {
0127         result = sample_normal_(rng);
0128     } while (result <= 0 || result > max_loss_);
0129     return Energy{result};
0130 }
0131 
0132 //---------------------------------------------------------------------------//
0133 }  // namespace celeritas