File indexing completed on 2026-11-07 10:11:36
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include "corecel/Macros.hh"
0010 #include "corecel/data/StackAllocator.hh"
0011 #include "celeritas/mucf/data/DTMixMucfData.hh"
0012 #include "celeritas/phys/Interaction.hh"
0013 #include "celeritas/phys/Secondary.hh"
0014
0015 #include "detail/MucfInteractorUtils.hh"
0016
0017 namespace celeritas
0018 {
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 class DTMucfInteractor
0036 {
0037 public:
0038 enum class Channel
0039 {
0040 alpha_muon_neutron,
0041 muonicalpha_neutron,
0042 size_
0043 };
0044
0045
0046 inline CELER_FUNCTION DTMucfInteractor(
0047 NativeCRef<DTMixMucfData> const& data,
0048 Channel channel,
0049 StackAllocator<Secondary>& allocate);
0050
0051
0052 template<class Engine>
0053 inline CELER_FUNCTION Interaction operator()(Engine& rng);
0054
0055 private:
0056
0057 NativeCRef<DTMixMucfData> const& data_;
0058
0059 Channel channel_{Channel::size_};
0060
0061 StackAllocator<Secondary>& allocate_;
0062
0063 EnumArray<Channel, size_type> num_secondaries_{
0064 3,
0065 2
0066 };
0067
0068
0069 inline CELER_FUNCTION units::MevEnergy neutron_kinetic_energy() const
0070 {
0071 return units::MevEnergy{14.1};
0072 }
0073
0074
0075 inline CELER_FUNCTION units::MevEnergy total_kinetic_energy() const
0076 {
0077 return units::MevEnergy{17.6};
0078 }
0079 };
0080
0081
0082
0083
0084
0085
0086
0087 CELER_FUNCTION DTMucfInteractor::DTMucfInteractor(
0088 NativeCRef<DTMixMucfData> const& data,
0089 Channel const channel,
0090 StackAllocator<Secondary>& allocate)
0091 : data_(data), channel_(channel), allocate_(allocate)
0092 {
0093 CELER_EXPECT(data_);
0094 CELER_EXPECT(channel_ < Channel::size_);
0095 }
0096
0097
0098
0099
0100
0101 template<class Engine>
0102 CELER_FUNCTION Interaction DTMucfInteractor::operator()(Engine& rng)
0103 {
0104
0105 Secondary* sec = allocate_(num_secondaries_[channel_]);
0106 if (sec == nullptr)
0107 {
0108
0109 return Interaction::from_failure();
0110 }
0111
0112 size_type const neutron_idx{0};
0113 size_type const muon_idx{1}, alpha_idx{2};
0114 size_type const muonicalpha_idx{1};
0115
0116 IsotropicDistribution sample_isotropic;
0117
0118
0119 sec[neutron_idx] = detail::sample_mucf_secondary(
0120 data_.particle_ids.neutron, this->neutron_kinetic_energy(), rng);
0121
0122 switch (channel_)
0123 {
0124 case Channel::alpha_muon_neutron: {
0125
0126 sec[muon_idx] = detail::sample_mucf_muon(
0127 data_.particle_ids.mu_minus,
0128 NonuniformGridCalculator{data_.muon_energy_cdf, data_.reals},
0129 rng);
0130
0131
0132 sec[alpha_idx]
0133 = detail::calc_third_secondary(sec[neutron_idx],
0134 data_.particle_masses.neutron,
0135 sec[muon_idx],
0136 data_.particle_masses.mu_minus,
0137 data_.particle_ids.alpha,
0138 data_.particle_masses.alpha);
0139 break;
0140 }
0141
0142 case Channel::muonicalpha_neutron: {
0143
0144 sec[muonicalpha_idx].particle_id = data_.particle_ids.muonic_alpha;
0145 sec[muonicalpha_idx].energy = this->total_kinetic_energy()
0146 - this->neutron_kinetic_energy();
0147 sec[muonicalpha_idx].direction
0148 = detail::opposite(sec[neutron_idx].direction);
0149 break;
0150 }
0151
0152 default:
0153 CELER_ASSERT_UNREACHABLE();
0154 }
0155
0156
0157 Interaction result = Interaction::from_absorption();
0158 result.secondaries = {sec, num_secondaries_[channel_]};
0159 return result;
0160 }
0161
0162
0163 }