File indexing completed on 2025-09-19 08:49:42
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include "corecel/Constants.hh"
0010 #include "corecel/Macros.hh"
0011 #include "corecel/Types.hh"
0012 #include "corecel/data/StackAllocator.hh"
0013 #include "corecel/math/Algorithms.hh"
0014 #include "corecel/random/distribution/RejectionSampler.hh"
0015 #include "geocel/random/IsotropicDistribution.hh"
0016 #include "celeritas/Quantities.hh"
0017 #include "celeritas/decay/data/MuDecayData.hh"
0018 #include "celeritas/phys/FourVector.hh"
0019 #include "celeritas/phys/Interaction.hh"
0020 #include "celeritas/phys/ParticleTrackView.hh"
0021 #include "celeritas/phys/Secondary.hh"
0022
0023 namespace celeritas
0024 {
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062 class MuDecayInteractor
0063 {
0064 public:
0065
0066 inline CELER_FUNCTION
0067 MuDecayInteractor(MuDecayData const& shared,
0068 ParticleTrackView const& particle,
0069 Real3 const& inc_direction,
0070 StackAllocator<Secondary>& allocate);
0071
0072
0073 template<class Engine>
0074 inline CELER_FUNCTION Interaction operator()(Engine& rng);
0075
0076 private:
0077
0078
0079 using Energy = units::MevEnergy;
0080 using Momentum = units::MevMomentum;
0081 using Mass = units::MevMass;
0082
0083
0084
0085
0086 MuDecayData const& shared_;
0087
0088 Energy const inc_energy_;
0089
0090 StackAllocator<Secondary>& allocate_;
0091
0092 ParticleId sec_id_;
0093
0094 FourVector inc_fourvec_;
0095
0096 real_type max_energy_;
0097
0098
0099
0100
0101 inline CELER_FUNCTION FourVector to_lab_frame(Real3 const& dir,
0102 Momentum momentum,
0103 Mass mass) const;
0104
0105
0106 inline CELER_FUNCTION Momentum calc_momentum(real_type energy_frac,
0107 Mass mass) const;
0108 };
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123 CELER_FUNCTION
0124 MuDecayInteractor::MuDecayInteractor(MuDecayData const& shared,
0125 ParticleTrackView const& particle,
0126 Real3 const& inc_direction,
0127 StackAllocator<Secondary>& allocate)
0128 : shared_(shared)
0129 , inc_energy_(particle.energy())
0130 , allocate_(allocate)
0131 , sec_id_((particle.particle_id() == shared_.mu_minus_id)
0132 ? shared_.electron_id
0133 : shared_.positron_id)
0134 , inc_fourvec_{FourVector::from_particle(particle, inc_direction)}
0135 , max_energy_(real_type{0.5} * shared_.muon_mass.value()
0136 - shared_.electron_mass.value())
0137 {
0138 CELER_EXPECT(shared_);
0139 CELER_EXPECT(particle.particle_id() == shared_.mu_minus_id
0140 || particle.particle_id() == shared_.mu_plus_id);
0141 }
0142
0143
0144
0145
0146
0147 template<class Engine>
0148 CELER_FUNCTION Interaction MuDecayInteractor::operator()(Engine& rng)
0149 {
0150
0151 Secondary* secondaries = allocate_(1);
0152 if (secondaries == nullptr)
0153 {
0154
0155 return Interaction::from_failure();
0156 }
0157
0158 real_type electron_energy_frac{};
0159 real_type electron_nu_energy_frac{};
0160 do
0161 {
0162 do
0163 {
0164 electron_nu_energy_frac = generate_canonical(rng);
0165 } while (RejectionSampler(
0166 electron_nu_energy_frac * (real_type{1} - electron_nu_energy_frac),
0167 real_type{0.25})(rng));
0168
0169 electron_energy_frac = generate_canonical(rng);
0170 } while (electron_nu_energy_frac + electron_energy_frac < real_type{1});
0171
0172
0173 auto charged_lep_fv = this->to_lab_frame(
0174 IsotropicDistribution{}(rng),
0175 this->calc_momentum(electron_energy_frac, shared_.electron_mass),
0176 shared_.electron_mass);
0177
0178
0179 Interaction result = Interaction::from_absorption();
0180 result.secondaries = {secondaries, 1};
0181 result.secondaries[0].particle_id = sec_id_;
0182
0183 result.secondaries[0].energy
0184 = Energy{charged_lep_fv.energy - shared_.electron_mass.value()};
0185 result.secondaries[0].direction = make_unit_vector(charged_lep_fv.mom);
0186
0187 return result;
0188 }
0189
0190
0191
0192
0193
0194
0195
0196
0197 CELER_FUNCTION FourVector MuDecayInteractor::to_lab_frame(Real3 const& dir,
0198 Momentum momentum,
0199 Mass mass) const
0200 {
0201 CELER_EXPECT(is_soft_unit_vector(dir));
0202 CELER_EXPECT(momentum > zero_quantity());
0203 CELER_EXPECT(mass >= zero_quantity());
0204
0205 auto lepton_fv = FourVector::from_mass_momentum(mass, momentum, dir);
0206 boost(boost_vector(inc_fourvec_), &lepton_fv);
0207
0208 return lepton_fv;
0209 }
0210
0211
0212
0213
0214
0215
0216 CELER_FUNCTION auto
0217 MuDecayInteractor::calc_momentum(real_type energy_frac,
0218 Mass mass) const -> Momentum
0219 {
0220 return Momentum{std::sqrt(ipow<2>(energy_frac * max_energy_)
0221 + 2 * energy_frac * max_energy_ * mass.value())};
0222 }
0223
0224
0225 }