Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-27 08:41:12

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file celeritas/phys/ParticleTrackView.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/sys/ThreadId.hh"
0016 #include "celeritas/Quantities.hh"
0017 
0018 #include "ParticleData.hh"
0019 #include "ParticleView.hh"
0020 
0021 namespace celeritas
0022 {
0023 //---------------------------------------------------------------------------//
0024 /*!
0025  * Read/write view to the physical properties of a single particle track.
0026  *
0027  * These functions should be used in each physics Process or Interactor or
0028  * anything else that needs to access particle properties. Assume that all
0029  * these functions are expensive: when using them as accessors, locally store
0030  * the results rather than calling the function repeatedly. If any of the
0031  * calculations prove to be hot spots we will experiment with cacheing some of
0032  * the variables.
0033  */
0034 class ParticleTrackView
0035 {
0036   public:
0037     //!@{
0038     //! \name Type aliases
0039     using ParamsRef = celeritas::NativeCRef<ParticleParamsData>;
0040     using StateRef = celeritas::NativeRef<ParticleStateData>;
0041     using Initializer_t = ParticleTrackInitializer;
0042 
0043     using Charge = units::ElementaryCharge;
0044     using Energy = units::MevEnergy;
0045     using Mass = units::MevMass;
0046     using Momentum = units::MevMomentum;
0047     using MomentumSq = units::MevMomentumSq;
0048     using Speed = units::LightSpeed;
0049     //!@}
0050 
0051   public:
0052     // Construct from "dynamic" state and "static" particle definitions
0053     inline CELER_FUNCTION ParticleTrackView(ParamsRef const& params,
0054                                             StateRef const& states,
0055                                             TrackSlotId id);
0056 
0057     // Initialize the particle
0058     inline CELER_FUNCTION ParticleTrackView&
0059     operator=(Initializer_t const& other);
0060 
0061     // Change the particle's energy [MeV]
0062     inline CELER_FUNCTION void energy(Energy);
0063 
0064     // Reduce the particle's energy [MeV]
0065     inline CELER_FUNCTION void subtract_energy(Energy);
0066 
0067     //// DYNAMIC PROPERTIES (pure accessors, free) ////
0068 
0069     // Unique particle type identifier
0070     CELER_FORCEINLINE_FUNCTION ParticleId particle_id() const;
0071 
0072     // Kinetic energy [MeV]
0073     CELER_FORCEINLINE_FUNCTION Energy energy() const;
0074 
0075     // Whether the particle is stopped (zero kinetic energy)
0076     CELER_FORCEINLINE_FUNCTION bool is_stopped() const;
0077 
0078     //// STATIC PROPERTIES (requires an indirection) ////
0079 
0080     CELER_FORCEINLINE_FUNCTION ParticleView particle_view() const;
0081 
0082     // Rest mass [MeV / c^2]
0083     CELER_FORCEINLINE_FUNCTION Mass mass() const;
0084 
0085     // Charge [elemental charge e+]
0086     CELER_FORCEINLINE_FUNCTION Charge charge() const;
0087 
0088     // Decay constant [1 / time]
0089     CELER_FORCEINLINE_FUNCTION real_type decay_constant() const;
0090 
0091     // Whether it is an antiparticle
0092     CELER_FORCEINLINE_FUNCTION bool is_antiparticle() const;
0093 
0094     // Whether the particle is stable
0095     CELER_FORCEINLINE_FUNCTION bool is_stable() const;
0096 
0097     // Distinguish between light (e-/e+) and heavy (muon/hadron) particles
0098     CELER_FORCEINLINE_FUNCTION bool is_heavy() const;
0099 
0100     //// DERIVED PROPERTIES (indirection plus calculation) ////
0101 
0102     // Kinetic energy plus rest energy [MeV]
0103     inline CELER_FUNCTION Energy total_energy() const;
0104 
0105     // Square of fraction of lightspeed [unitless]
0106     inline CELER_FUNCTION real_type beta_sq() const;
0107 
0108     // Speed [1/c]
0109     inline CELER_FUNCTION Speed speed() const;
0110 
0111     // Lorentz factor [unitless]
0112     inline CELER_FUNCTION real_type lorentz_factor() const;
0113 
0114     // Relativistic momentum [MeV / c]
0115     inline CELER_FUNCTION Momentum momentum() const;
0116 
0117     // Relativistic momentum squared [MeV^2 / c^2]
0118     inline CELER_FUNCTION MomentumSq momentum_sq() const;
0119 
0120   private:
0121     ParamsRef const& params_;
0122     StateRef const& states_;
0123     TrackSlotId const track_slot_;
0124 };
0125 
0126 //---------------------------------------------------------------------------//
0127 // INLINE DEFINITIONS
0128 //---------------------------------------------------------------------------//
0129 /*!
0130  * Construct from dynamic and static particle properties.
0131  */
0132 CELER_FUNCTION
0133 ParticleTrackView::ParticleTrackView(ParamsRef const& params,
0134                                      StateRef const& states,
0135                                      TrackSlotId tid)
0136     : params_(params), states_(states), track_slot_(tid)
0137 {
0138     CELER_EXPECT(track_slot_ < states_.size());
0139 }
0140 
0141 //---------------------------------------------------------------------------//
0142 /*!
0143  * Initialize the particle.
0144  */
0145 CELER_FUNCTION ParticleTrackView&
0146 ParticleTrackView::operator=(Initializer_t const& other)
0147 {
0148     CELER_EXPECT(other.particle_id < params_.size());
0149     CELER_EXPECT(other.energy >= zero_quantity());
0150     states_.particle_id[track_slot_] = other.particle_id;
0151     states_.particle_energy[track_slot_] = other.energy.value();
0152     return *this;
0153 }
0154 
0155 //---------------------------------------------------------------------------//
0156 /*!
0157  * Change the particle's kinetic energy.
0158  *
0159  * This should only be used when the particle is in a valid state. For HEP
0160  * applications, the new energy should always be less than the starting energy.
0161  */
0162 CELER_FUNCTION
0163 void ParticleTrackView::energy(Energy quantity)
0164 {
0165     CELER_EXPECT(this->particle_id());
0166     CELER_EXPECT(quantity >= zero_quantity());
0167     states_.particle_energy[track_slot_] = quantity.value();
0168 }
0169 
0170 //---------------------------------------------------------------------------//
0171 /*!
0172  * Reduce the particle's energy without undergoing a collision [MeV].
0173  */
0174 CELER_FUNCTION void ParticleTrackView::subtract_energy(Energy eloss)
0175 {
0176     CELER_EXPECT(eloss >= zero_quantity());
0177     CELER_EXPECT(eloss <= this->energy());
0178     // TODO: save a read/write by only saving if eloss is positive?
0179     states_.particle_energy[track_slot_] -= eloss.value();
0180 }
0181 
0182 //---------------------------------------------------------------------------//
0183 // DYNAMIC PROPERTIES
0184 //---------------------------------------------------------------------------//
0185 /*!
0186  * Unique particle type identifier.
0187  */
0188 CELER_FUNCTION ParticleId ParticleTrackView::particle_id() const
0189 {
0190     return states_.particle_id[track_slot_];
0191 }
0192 
0193 //---------------------------------------------------------------------------//
0194 /*!
0195  * Kinetic energy [MeV].
0196  */
0197 CELER_FUNCTION auto ParticleTrackView::energy() const -> Energy
0198 {
0199     return Energy{states_.particle_energy[track_slot_]};
0200 }
0201 
0202 //---------------------------------------------------------------------------//
0203 /*!
0204  * Whether the track is stopped (zero kinetic energy).
0205  */
0206 CELER_FUNCTION bool ParticleTrackView::is_stopped() const
0207 {
0208     return this->energy() == zero_quantity();
0209 }
0210 
0211 //---------------------------------------------------------------------------//
0212 // STATIC PROPERTIES
0213 //---------------------------------------------------------------------------//
0214 /*!
0215  * Get static particle properties for the current state.
0216  */
0217 CELER_FUNCTION ParticleView ParticleTrackView::particle_view() const
0218 {
0219     return ParticleView(params_, states_.particle_id[track_slot_]);
0220 }
0221 
0222 //---------------------------------------------------------------------------//
0223 /*!
0224  * Rest mass [MeV / c^2].
0225  */
0226 CELER_FUNCTION auto ParticleTrackView::mass() const -> Mass
0227 {
0228     return this->particle_view().mass();
0229 }
0230 
0231 //---------------------------------------------------------------------------//
0232 /*!
0233  * Elementary charge.
0234  */
0235 CELER_FUNCTION auto ParticleTrackView::charge() const -> Charge
0236 {
0237     return this->particle_view().charge();
0238 }
0239 
0240 //---------------------------------------------------------------------------//
0241 /*!
0242  * Decay constant in native units.
0243  */
0244 CELER_FUNCTION real_type ParticleTrackView::decay_constant() const
0245 {
0246     return this->particle_view().decay_constant();
0247 }
0248 
0249 //---------------------------------------------------------------------------//
0250 /*!
0251  * Whether it is an antiparticle.
0252  */
0253 CELER_FUNCTION bool ParticleTrackView::is_antiparticle() const
0254 {
0255     return this->particle_view().is_antiparticle();
0256 }
0257 
0258 //---------------------------------------------------------------------------//
0259 /*!
0260  * Whether particle is stable.
0261  */
0262 CELER_FUNCTION bool ParticleTrackView::is_stable() const
0263 {
0264     return this->decay_constant() == constants::stable_decay_constant;
0265 }
0266 
0267 //---------------------------------------------------------------------------//
0268 /*!
0269  * Distinguish between light (e-/e+) and heavy (muon/hadron) particles.
0270  *
0271  * Light and heavy charged particles have different parameters and treatment in
0272  * continuous energy loss and Coulomb scattering. The choice of 1 MeV to
0273  * distinguish between electrons and muons is arbitrary.
0274  */
0275 CELER_FUNCTION bool ParticleTrackView::is_heavy() const
0276 {
0277     return this->mass() > units::MevMass{1};
0278 }
0279 
0280 //---------------------------------------------------------------------------//
0281 // COMBINED PROPERTIES
0282 //---------------------------------------------------------------------------//
0283 /*!
0284  * Kinetic energy plus rest energy [MeV].
0285  */
0286 CELER_FUNCTION auto ParticleTrackView::total_energy() const -> Energy
0287 {
0288     return Energy(value_as<Energy>(this->energy())
0289                   + value_as<Mass>(this->mass()));
0290 }
0291 
0292 //---------------------------------------------------------------------------//
0293 /*!
0294  * Square of \f$ \beta \f$, which is the fraction of lightspeed [unitless].
0295  *
0296  * Beta is calculated using the equality
0297  * \f[
0298  * pc/E = \beta ; \quad \beta^2 = \frac{p^2 c^2}{E^2}
0299  * \f].
0300  * Using
0301  * \f[
0302  * E^2 = p^2 c^2 + m^2 c^4
0303  * \f]
0304  * and
0305  * \f[
0306  * E = K + mc^2
0307  * \f]
0308  *
0309  * the square of the fraction of lightspeed speed is
0310  * \f[
0311  * \beta^2 = 1 - \left( \frac{mc^2}{K + mc^2} \right)^2
0312  *         = 1 - \gamma^{-2}
0313  * \f]
0314  *
0315  * where \f$ \gamma \f$ is the Lorentz factor (see below).
0316  *
0317  * By choosing not to divide out the mass, this expression will work for
0318  * massless particles.
0319  *
0320  * \todo For nonrelativistic particles (low kinetic energy) this expression
0321  * may be inaccurate due to rounding error. It is however guaranteed to be in
0322  * the exact range [0, 1].
0323  */
0324 CELER_FUNCTION real_type ParticleTrackView::beta_sq() const
0325 {
0326     // Rest mass as energy
0327     real_type const mcsq = this->mass().value();
0328     // Inverse of lorentz factor (safe for m=0)
0329     real_type inv_gamma = mcsq / (this->energy().value() + mcsq);
0330 
0331     return 1 - ipow<2>(inv_gamma);
0332 }
0333 
0334 //---------------------------------------------------------------------------//
0335 /*!
0336  * Speed [1/c].
0337  *
0338  * Speed is calculated using beta so that the expression works for massless
0339  * particles.
0340  */
0341 CELER_FUNCTION auto ParticleTrackView::speed() const -> Speed
0342 {
0343     return units::LightSpeed{std::sqrt(this->beta_sq())};
0344 }
0345 
0346 //---------------------------------------------------------------------------//
0347 /*!
0348  * Lorentz factor [unitless].
0349  *
0350  * The Lorentz factor can be viewed as a transformation from
0351  * classical quantities to relativistic quantities. It's defined as
0352  * \f[
0353   \gamma = \frac{1}{\sqrt{1 - v^2 / c^2}}
0354   \f]
0355  *
0356  * Its value is infinite for the massless photon, and greater than or equal to
0357  * 1 otherwise.
0358  *
0359  * Gamma can also be calculated from the total (rest + kinetic) energy
0360  * \f[
0361   E = \gamma mc^2 = K + mc^2
0362   \f]
0363  * which we ues here since \em K and \em m are the primary stored quantities of
0364  * the particles:
0365  * \f[
0366   \gamma = 1 + \frac{K}{mc^2}
0367  * \f]
0368  */
0369 CELER_FUNCTION real_type ParticleTrackView::lorentz_factor() const
0370 {
0371     CELER_EXPECT(this->mass() > zero_quantity());
0372 
0373     real_type k_over_mc2 = this->energy().value() / this->mass().value();
0374     return 1 + k_over_mc2;
0375 }
0376 
0377 //---------------------------------------------------------------------------//
0378 /*!
0379  * Square of relativistic momentum [MeV^2 / c^2].
0380  *
0381  * Total energy:
0382  * \f[
0383  * E = K + mc^2
0384  * \f]
0385  * Relation between energy and momentum:
0386  * \f[
0387  * E^2 = p^2 c^2 + m^2 c^4
0388  * \f]
0389  * therefore
0390  * \f[
0391  * p^2 = \frac{E^2}{c^2} - m^2 c^2
0392  * \f]
0393  * or
0394  * \f[
0395  * p^2 = \frac{K^2}{c^2} + 2 * m * K
0396  * \f]
0397  */
0398 CELER_FUNCTION auto ParticleTrackView::momentum_sq() const -> MomentumSq
0399 {
0400     real_type const energy = this->energy().value();
0401     real_type result = ipow<2>(energy) + 2 * this->mass().value() * energy;
0402     CELER_ENSURE(result >= 0);
0403     return MomentumSq{result};
0404 }
0405 
0406 //---------------------------------------------------------------------------//
0407 /*!
0408  * Relativistic momentum [MeV / c].
0409  *
0410  * This is calculated by taking the root of the square of the momentum.
0411  */
0412 CELER_FUNCTION auto ParticleTrackView::momentum() const -> Momentum
0413 {
0414     return Momentum{std::sqrt(this->momentum_sq().value())};
0415 }
0416 
0417 //---------------------------------------------------------------------------//
0418 }  // namespace celeritas