Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-14 10:22:26

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/Interaction.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include "corecel/Config.hh"
0010 
0011 #include "corecel/Types.hh"
0012 #include "corecel/cont/Array.hh"
0013 #include "corecel/cont/Span.hh"
0014 #include "corecel/math/ArrayUtils.hh"
0015 #include "corecel/math/SoftEqual.hh"
0016 #include "celeritas/Quantities.hh"
0017 #include "celeritas/Types.hh"
0018 
0019 #include "Secondary.hh"
0020 #if CELERITAS_DEBUG
0021 #    include "corecel/math/NumericLimits.hh"
0022 #endif
0023 
0024 namespace celeritas
0025 {
0026 //---------------------------------------------------------------------------//
0027 /*!
0028  * Change in state due to an interaction.
0029  */
0030 struct Interaction
0031 {
0032     using Energy = units::MevEnergy;
0033 
0034     //! Interaction result category
0035     enum class Action
0036     {
0037         scattered,  //!< Still alive, state has changed
0038         absorbed,  //!< Absorbed or transformed to another particle type
0039         onloaded,  //!< Transfer interaction to the host
0040         unchanged,  //!< No state change, no secondaries
0041         failed,  //!< Ran out of memory during sampling
0042     };
0043 
0044     Energy energy;  //!< Post-interaction energy
0045     Real3 direction;  //!< Post-interaction direction
0046     Span<Secondary> secondaries;  //!< Emitted secondaries
0047     Energy energy_deposition{0};  //!< Energy loss locally to material
0048     Action action{Action::scattered};  //!< Flags for interaction result
0049 
0050     // Return an interaction representing a recoverable error
0051     static inline CELER_FUNCTION Interaction from_failure();
0052 
0053     // Return an interaction representing an absorbed process
0054     static inline CELER_FUNCTION Interaction from_absorption();
0055 
0056     // Return an interaction with no change in the track state
0057     static inline CELER_FUNCTION Interaction from_unchanged();
0058 
0059     // Return an interaction with onload in the tract state
0060     static inline CELER_FUNCTION Interaction from_onloaded();
0061 
0062     //! Whether the state changed but did not fail
0063     CELER_FUNCTION bool changed() const
0064     {
0065         return static_cast<int>(action) < static_cast<int>(Action::unchanged);
0066     }
0067 };
0068 
0069 //---------------------------------------------------------------------------//
0070 /*!
0071  * Step lengths and properties needed to apply multiple scattering.
0072  *
0073  * \todo Document and/or refactor into a class that hides details
0074  * - alpha == small_step_alpha() ? "true path is very small" (true path scaling
0075  *   changes)
0076  * - is_displaced == false ? limit_min is unchanged and alpha ==
0077  *   small_step_alpha()
0078  * - true_step >= geom_path
0079  *
0080  * The value \f$ \alpha \f$ is used in the approximation of the MSC
0081  * transport cross section as a linear function over the current step. It is
0082  * the negative slope of the transport MFP from start to stop, divided by the
0083  * starting MFP. (Since the transport cross section generally decreases
0084  * monotonically with increasing energy over the step, alpha will usually be
0085  * positive or zero for the step. Some known errors in the cross sections for
0086  * positrons result in negative alpha around a discontinuity at 10 MeV.)
0087  */
0088 struct MscStep
0089 {
0090     //! Use a small step approximation for the path length correction
0091     static CELER_CONSTEXPR_FUNCTION real_type small_step_alpha() { return 0; }
0092 
0093     bool is_displaced{true};  //!< Flag for the lateral displacement
0094     real_type true_path{};  //!< True path length due to the msc [len]
0095     real_type geom_path{};  //!< Geometrical path length [len]
0096     real_type alpha = small_step_alpha();  //!< Scaled MFP slope [1/len]
0097 };
0098 
0099 //---------------------------------------------------------------------------//
0100 /*!
0101  * Persistent range properties for multiple scattering (msc) within a volume.
0102  *
0103  * These values are calculated at the first step in every msc tracking volume
0104  * and reused at subsequent steps within the same volume.
0105  *
0106  * \todo move to physics step data
0107  */
0108 struct MscRange
0109 {
0110     real_type range_init{};  //!< Initial msc range [len]
0111     real_type range_factor{};  //!< Scale factor for the msc range
0112     real_type limit_min{};  //!< Minimum of the true path limit [len]
0113 
0114     explicit CELER_FUNCTION operator bool() const
0115     {
0116         return range_init > 0 && range_factor > 0 && limit_min > 0;
0117     }
0118 };
0119 
0120 //---------------------------------------------------------------------------//
0121 /*!
0122  * Result of multiple scattering.
0123  */
0124 struct MscInteraction
0125 {
0126     //! Interaction result category
0127     enum class Action
0128     {
0129         unchanged,  //!< No state change
0130         scattered,  //!< Only direction changed
0131         displaced,  //!< Direction and position changed
0132         size_
0133     };
0134 
0135     Real3 direction;  //!< Post-step direction
0136     Real3 displacement;  //!< Lateral displacement
0137     Action action{Action::unchanged};  //!< Flags for interaction result
0138 };
0139 
0140 //---------------------------------------------------------------------------//
0141 // INLINE DEFINITIONS
0142 //---------------------------------------------------------------------------//
0143 /*!
0144  * Indicate a failure to allocate memory for secondaries.
0145  */
0146 CELER_FUNCTION Interaction Interaction::from_failure()
0147 {
0148     Interaction result;
0149     result.action = Action::failed;
0150     return result;
0151 }
0152 
0153 //---------------------------------------------------------------------------//
0154 /*!
0155  * Construct an interaction from a particle that was totally absorbed.
0156  */
0157 CELER_FUNCTION Interaction Interaction::from_absorption()
0158 {
0159     Interaction result;
0160     result.energy = zero_quantity();
0161 #if CELERITAS_DEBUG
0162     // Direction should *not* be accessed if incident particle is absorbed.
0163     constexpr auto nan = numeric_limits<real_type>::quiet_NaN();
0164     result.direction = {nan, nan, nan};
0165 #endif
0166     result.action = Action::absorbed;
0167     return result;
0168 }
0169 
0170 //---------------------------------------------------------------------------//
0171 /*!
0172  * Construct an interaction for edge cases where there is no state change.
0173  */
0174 CELER_FUNCTION Interaction Interaction::from_unchanged()
0175 {
0176     Interaction result;
0177     result.action = Action::unchanged;
0178     return result;
0179 }
0180 
0181 //---------------------------------------------------------------------------//
0182 /*!
0183  * Construct an interaction from a particle that will be onloaded.
0184  */
0185 CELER_FUNCTION Interaction Interaction::from_onloaded()
0186 {
0187     Interaction result;
0188     result.action = Action::onloaded;
0189     return result;
0190 }
0191 
0192 //---------------------------------------------------------------------------//
0193 }  // namespace celeritas