File indexing completed on 2025-12-15 10:10:51
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include "corecel/Macros.hh"
0010 #include "corecel/math/ArrayUtils.hh"
0011 #include "celeritas/Constants.hh"
0012 #include "celeritas/Quantities.hh"
0013 #include "celeritas/Types.hh"
0014 #include "celeritas/em/data/CoulombScatteringData.hh"
0015 #include "celeritas/em/data/WentzelOKVIData.hh"
0016 #include "celeritas/em/distribution/WentzelDistribution.hh"
0017 #include "celeritas/em/xs/WentzelHelper.hh"
0018 #include "celeritas/mat/ElementView.hh"
0019 #include "celeritas/mat/MaterialView.hh"
0020 #include "celeritas/phys/CutoffView.hh"
0021 #include "celeritas/phys/Interaction.hh"
0022 #include "celeritas/phys/InteractionUtils.hh"
0023 #include "celeritas/phys/ParticleTrackView.hh"
0024
0025 #include "detail/PhysicsConstants.hh"
0026
0027 namespace celeritas
0028 {
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 class CoulombScatteringInteractor
0045 {
0046 public:
0047
0048
0049 using Energy = units::MevEnergy;
0050 using Mass = units::MevMass;
0051 using MomentumSq = units::MevMomentumSq;
0052
0053
0054 public:
0055
0056 inline CELER_FUNCTION
0057 CoulombScatteringInteractor(CoulombScatteringData const& shared,
0058 NativeCRef<WentzelOKVIData> const& wentzel,
0059 ParticleTrackView const& particle,
0060 Real3 const& inc_direction,
0061 MaterialView const& material,
0062 IsotopeView const& target,
0063 ElementId el_id,
0064 CutoffView const& cutoffs);
0065
0066
0067 template<class Engine>
0068 inline CELER_FUNCTION Interaction operator()(Engine& rng);
0069
0070 private:
0071
0072
0073
0074 Real3 const& inc_direction_;
0075
0076
0077 ParticleTrackView const& particle_;
0078
0079
0080 IsotopeView const& target_;
0081
0082
0083 WentzelHelper const helper_;
0084
0085
0086 WentzelDistribution const sample_angle_;
0087
0088
0089
0090
0091 inline CELER_FUNCTION real_type calc_recoil_energy(real_type cos_theta) const;
0092 };
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103 CELER_FUNCTION
0104 CoulombScatteringInteractor::CoulombScatteringInteractor(
0105 CoulombScatteringData const& shared,
0106 NativeCRef<WentzelOKVIData> const& wentzel,
0107 ParticleTrackView const& particle,
0108 Real3 const& inc_direction,
0109 MaterialView const& material,
0110 IsotopeView const& target,
0111 ElementId el_id,
0112 CutoffView const& cutoffs)
0113 : inc_direction_(inc_direction)
0114 , particle_(particle)
0115 , target_(target)
0116 , helper_(particle,
0117 material,
0118 target.atomic_number(),
0119 wentzel,
0120 shared.ids,
0121 cutoffs.energy(shared.ids.electron))
0122 , sample_angle_(wentzel,
0123 helper_,
0124 particle,
0125 target,
0126 el_id,
0127 helper_.cos_thetamax_nuclear(),
0128 shared.cos_thetamax())
0129 {
0130 CELER_EXPECT(particle_.particle_id() == shared.ids.electron
0131 || particle_.particle_id() == shared.ids.positron);
0132 CELER_EXPECT(particle_.energy() > zero_quantity()
0133 && particle_.energy() < detail::high_energy_limit());
0134 }
0135
0136
0137
0138
0139
0140 template<class Engine>
0141 CELER_FUNCTION Interaction CoulombScatteringInteractor::operator()(Engine& rng)
0142 {
0143
0144 Interaction result;
0145
0146
0147 real_type cos_theta = sample_angle_(rng);
0148 result.direction = ExitingDirectionSampler{cos_theta, inc_direction_}(rng);
0149
0150
0151 real_type inc_energy = value_as<Energy>(particle_.energy());
0152 real_type recoil_energy = this->calc_recoil_energy(cos_theta);
0153 CELER_ASSERT(0 <= recoil_energy && recoil_energy <= inc_energy);
0154 result.energy = Energy{inc_energy - recoil_energy};
0155
0156
0157 result.energy_deposition = Energy{recoil_energy};
0158
0159 return result;
0160 }
0161
0162
0163
0164
0165
0166
0167 CELER_FUNCTION real_type
0168 CoulombScatteringInteractor::calc_recoil_energy(real_type cos_theta) const
0169 {
0170 real_type projectile_momsq = value_as<MomentumSq>(particle_.momentum_sq());
0171 real_type projectile_mass = value_as<Mass>(particle_.mass())
0172 + value_as<Energy>(particle_.energy());
0173 real_type target_mass = value_as<Mass>(target_.nuclear_mass());
0174
0175 return projectile_momsq * (1 - cos_theta)
0176 / (target_mass + projectile_mass * (1 - cos_theta));
0177 }
0178
0179
0180 }