Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2020-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/EnergyLossHelper.hh
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include <cmath>
0011 
0012 #include "corecel/Macros.hh"
0013 #include "corecel/Types.hh"
0014 #include "celeritas/Constants.hh"
0015 #include "celeritas/Quantities.hh"
0016 #include "celeritas/em/data/FluctuationData.hh"
0017 #include "celeritas/mat/MaterialTrackView.hh"
0018 #include "celeritas/phys/CutoffView.hh"
0019 #include "celeritas/phys/ParticleTrackView.hh"
0020 
0021 namespace celeritas
0022 {
0023 //---------------------------------------------------------------------------//
0024 //! Type of energy loss distribution sampling to perform
0025 enum class EnergyLossFluctuationModel
0026 {
0027     none,  //!< Low density material: do not adjust
0028     gamma,  //!< Heavy particles with small mean energy loss
0029     gaussian,  //!< Heavy particles
0030     urban,  //!< Thin layers
0031 };
0032 
0033 //---------------------------------------------------------------------------//
0034 /*!
0035  * Precalculate energy loss fluctuation properties.
0036  *
0037  * Fluctuations in the energy loss of charged particles over a given thickness
0038  * of material arise from statistical variation in both the number of
0039  * collisions and the energy lost in each collision. Above a given energy
0040  * threshold, fluctuations are simulated through the explicit sampling of
0041  * secondaries. However, the continuous energy loss below the cutoff energy
0042  * also has fluctuations, and these are not taken into account in the
0043  * calculation of the mean loss. For continuous energy loss, fluctuation models
0044  * are used to sample the actual restricted energy loss given the mean loss.
0045  *
0046  * Different models are used depending on the value of the parameter
0047  * \f$ \kappa = \xi / T_{max} \f$, the ratio of the mean energy loss to the
0048  * maximum allowed energy transfer in a single collision.
0049  *
0050  * For large \f$ \kappa \f$,
0051  * when the particle loses all or most of its energy along the step, the number
0052  * of collisions is large and the straggling function can be approximated by a
0053  * Gaussian distribution.
0054  *
0055  * Otherwise, the Urban model for energy loss fluctuations in thin layers is
0056  * used.
0057  *
0058  * \note This performs the same sampling routine as in Geant4's
0059  * G4UniversalFluctuation, as documented in section 7.3 in the Geant4 Physics
0060  * Reference Manual and in PHYS332 and PHYS333 in GEANT3, CERN Program Library
0061  * Long Writeup, W5013 (1993).
0062  */
0063 class EnergyLossHelper
0064 {
0065   public:
0066     //!@{
0067     //! \name Type aliases
0068     using FluctuationRef = NativeCRef<FluctuationData>;
0069     using Energy = units::MevEnergy;
0070     using EnergySq = Quantity<UnitProduct<units::Mev, units::Mev>>;
0071     using Mass = units::MevMass;
0072     using Charge = units::ElementaryCharge;
0073     using Model = EnergyLossFluctuationModel;
0074     using Real2 = Array<real_type, 2>;
0075     //!@}
0076 
0077   public:
0078     // Construct from model parameters, incident particle, and mean energy loss
0079     inline CELER_FUNCTION EnergyLossHelper(FluctuationRef const& shared,
0080                                            CutoffView const& cutoffs,
0081                                            MaterialTrackView const& material,
0082                                            ParticleTrackView const& particle,
0083                                            Energy mean_loss,
0084                                            real_type step_length);
0085 
0086     //// STATIC ACCESSORS ////
0087 
0088     //! Atomic energy level corresponding to outer electrons (E_0)
0089     static CELER_CONSTEXPR_FUNCTION Energy ionization_energy()
0090     {
0091         return units::MevEnergy{1e-5};
0092     }
0093 
0094     //// ACCESSORS ////
0095 
0096     //! Shared data
0097     CELER_FORCEINLINE_FUNCTION FluctuationRef const& shared() const
0098     {
0099         return shared_;
0100     }
0101 
0102     //! Current material
0103     CELER_FORCEINLINE_FUNCTION MaterialTrackView const& material() const
0104     {
0105         return material_;
0106     }
0107 
0108     //! Type of model to select
0109     CELER_FORCEINLINE_FUNCTION Model model() const { return model_; }
0110 
0111     //! Input mean loss
0112     CELER_FUNCTION Energy mean_loss() const { return Energy{mean_loss_}; }
0113 
0114     //! Maximum allowable energy loss
0115     CELER_FUNCTION Energy max_energy() const
0116     {
0117         CELER_EXPECT(model_ != Model::none);
0118         return Energy{max_energy_};
0119     }
0120 
0121     //! Kinematics value: square of fractional speed of light
0122     CELER_FUNCTION real_type beta_sq() const
0123     {
0124         CELER_ENSURE(beta_sq_ > 0);
0125         return beta_sq_;
0126     }
0127 
0128     //! Bohr variance
0129     CELER_FUNCTION EnergySq bohr_variance() const
0130     {
0131         CELER_EXPECT(model_ != Model::none);
0132         CELER_ENSURE(bohr_var_ > 0);
0133         return EnergySq{bohr_var_};
0134     }
0135 
0136     //! Kinematics value for electrons: 2 * mass * beta^2 * gamma^2
0137     CELER_FUNCTION Mass two_mebsgs() const
0138     {
0139         CELER_ENSURE(two_mebsgs_ > 0);
0140         return Mass{two_mebsgs_};
0141     }
0142 
0143   private:
0144     //// DATA ////
0145 
0146     // Shared properties of the fluctuation model
0147     FluctuationRef const& shared_;
0148     // Current material
0149     MaterialTrackView const& material_;
0150     // Model to use for the given step
0151     Model model_{Model::none};
0152     // Average energy loss calculated from the tables
0153     real_type mean_loss_{0};
0154 
0155     // Square of the ratio of the particle velocity to the speed of light
0156     real_type beta_sq_{0};
0157     // Smaller of the delta ray production cut and maximum energy transfer
0158     real_type max_energy_{0};
0159     // two_mebg = 2 * m_e c^2 * beta^2 * gamma^2
0160     real_type two_mebsgs_{0};
0161 
0162     // Bohr's variance
0163     real_type bohr_var_{0};
0164 
0165     //// CONSTANTS ////
0166 
0167     //! Lower limit on the number of interactions in a step (kappa)
0168     static CELER_CONSTEXPR_FUNCTION size_type min_kappa() { return 10; }
0169 
0170     //! Minimum mean energy loss required to sample fluctuations
0171     static CELER_CONSTEXPR_FUNCTION real_type min_energy()
0172     {
0173         return value_as<Energy>(EnergyLossHelper::ionization_energy());
0174     }
0175 };
0176 
0177 //---------------------------------------------------------------------------//
0178 // INLINE DEFINITIONS
0179 //---------------------------------------------------------------------------//
0180 /*!
0181  * Construct from model parameters, incident particle, and mean energy loss.
0182  */
0183 CELER_FUNCTION
0184 EnergyLossHelper::EnergyLossHelper(FluctuationRef const& shared,
0185                                    CutoffView const& cutoffs,
0186                                    MaterialTrackView const& material,
0187                                    ParticleTrackView const& particle,
0188                                    Energy mean_loss,
0189                                    real_type step_length)
0190     : shared_(shared)
0191     , material_(material)
0192     , mean_loss_(value_as<Energy>(mean_loss))
0193 {
0194     CELER_EXPECT(shared_);
0195     CELER_EXPECT(mean_loss_ > 0);
0196     CELER_EXPECT(step_length > 0);
0197 
0198     if (mean_loss_ < this->min_energy())
0199     {
0200         model_ = Model::none;
0201         return;
0202     }
0203 
0204     constexpr real_type half = 0.5;
0205     real_type const gamma = particle.lorentz_factor();
0206     beta_sq_ = particle.beta_sq();
0207     two_mebsgs_ = 2 * value_as<Mass>(shared_.electron_mass) * beta_sq_
0208                   * ipow<2>(gamma);
0209 
0210     // Maximum possible energy transfer to an electron in a single collision
0211     real_type max_energy_transfer;
0212     real_type mass_ratio = 1;
0213     if (particle.particle_id() == shared_.electron_id)
0214     {
0215         max_energy_transfer = half * value_as<Energy>(particle.energy());
0216     }
0217     else
0218     {
0219         mass_ratio = value_as<Mass>(shared_.electron_mass)
0220                      / value_as<Mass>(particle.mass());
0221         max_energy_transfer = two_mebsgs_
0222                               / (1 + mass_ratio * (2 * gamma + mass_ratio));
0223     }
0224     max_energy_ = min(value_as<Energy>(cutoffs.energy(shared_.electron_id)),
0225                       max_energy_transfer);
0226 
0227     if (max_energy_ <= value_as<Energy>(this->ionization_energy()))
0228     {
0229         model_ = Model::none;
0230         return;
0231     }
0232 
0233     // Units: [len^2][MeV c^2][1/len^3][e-][MeV][len] = MeV^2
0234     // assuming implicit 1/c^2 in the formula
0235     bohr_var_ = 2 * constants::pi * ipow<2>(constants::r_electron)
0236                 * value_as<Mass>(shared_.electron_mass)
0237                 * material_.make_material_view().electron_density()
0238                 * ipow<2>(value_as<Charge>(particle.charge())) * max_energy_
0239                 * step_length * (1 / beta_sq_ - half);
0240 
0241     if (mass_ratio >= 1 || mean_loss_ < this->min_kappa() * max_energy_
0242         || max_energy_transfer > 2 * max_energy_)
0243     {
0244         model_ = Model::urban;
0245     }
0246     else if (ipow<2>(mean_loss_) >= 4 * bohr_var_)
0247     {
0248         model_ = Model::gaussian;
0249     }
0250     else
0251     {
0252         model_ = Model::gamma;
0253     }
0254 }
0255 
0256 //---------------------------------------------------------------------------//
0257 }  // namespace celeritas