File indexing completed on 2025-09-17 08:53:43
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include "corecel/Macros.hh"
0010 #include "corecel/Types.hh"
0011 #include "corecel/data/StackAllocator.hh"
0012 #include "corecel/random/distribution/ExponentialDistribution.hh"
0013 #include "corecel/random/distribution/PoissonDistribution.hh"
0014 #include "corecel/random/distribution/UniformRealDistribution.hh"
0015 #include "geocel/random/IsotropicDistribution.hh"
0016 #include "celeritas/Types.hh"
0017 #include "celeritas/grid/NonuniformGridCalculator.hh"
0018 #include "celeritas/optical/Interaction.hh"
0019 #include "celeritas/optical/ParticleTrackView.hh"
0020 #include "celeritas/optical/TrackInitializer.hh"
0021 #include "celeritas/optical/WavelengthShiftData.hh"
0022 #include "celeritas/phys/InteractionUtils.hh"
0023
0024 namespace celeritas
0025 {
0026 namespace optical
0027 {
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 class WavelengthShiftInteractor
0046 {
0047 public:
0048
0049
0050 using Energy = units::MevEnergy;
0051 using ParamsRef = NativeCRef<WavelengthShiftData>;
0052 using SecondaryAllocator = StackAllocator<TrackInitializer>;
0053
0054
0055 public:
0056
0057 inline CELER_FUNCTION
0058 WavelengthShiftInteractor(ParamsRef const& shared,
0059 ParticleTrackView const& particle,
0060 OptMatId const& mat_id,
0061 SecondaryAllocator& allocate);
0062
0063
0064 template<class Engine>
0065 inline CELER_FUNCTION Interaction operator()(Engine& rng);
0066
0067 private:
0068
0069
0070
0071 Energy const inc_energy_;
0072
0073 PoissonDistribution<real_type> sample_num_photons_;
0074 ExponentialDistribution<real_type> sample_time_;
0075
0076 NonuniformGridCalculator calc_cdf_;
0077
0078 SecondaryAllocator& allocate_;
0079 };
0080
0081
0082
0083
0084
0085
0086
0087 CELER_FUNCTION
0088 WavelengthShiftInteractor::WavelengthShiftInteractor(
0089 ParamsRef const& shared,
0090 ParticleTrackView const& particle,
0091 OptMatId const& mat_id,
0092 SecondaryAllocator& allocate)
0093 : inc_energy_(particle.energy())
0094 , sample_num_photons_(shared.wls_record[mat_id].mean_num_photons)
0095 , sample_time_(real_type{1} / shared.wls_record[mat_id].time_constant)
0096 , calc_cdf_(shared.energy_cdf[mat_id], shared.reals)
0097 , allocate_(allocate)
0098 {
0099 CELER_EXPECT(inc_energy_.value() > calc_cdf_.grid().front());
0100 }
0101
0102
0103
0104
0105
0106
0107
0108 template<class Engine>
0109 CELER_FUNCTION Interaction WavelengthShiftInteractor::operator()(Engine& rng)
0110 {
0111
0112
0113
0114
0115
0116 unsigned int num_photons = sample_num_photons_(rng);
0117
0118 if (num_photons == 0)
0119 {
0120
0121 return Interaction::from_absorption();
0122 }
0123
0124
0125
0126 TrackInitializer* secondaries = allocate_(num_photons);
0127
0128 if (secondaries == nullptr)
0129 {
0130
0131 return Interaction::from_failure();
0132 }
0133
0134
0135 Interaction result = Interaction::from_absorption();
0136 result.secondaries = {secondaries, num_photons};
0137
0138 IsotropicDistribution sample_direction{};
0139 NonuniformGridCalculator calc_energy = calc_cdf_.make_inverse();
0140 for (size_type i : range(num_photons))
0141 {
0142
0143
0144
0145 real_type energy = calc_energy(generate_canonical(rng));
0146 if (CELER_UNLIKELY(energy > inc_energy_.value()))
0147 {
0148
0149 real_type cdf_max = calc_cdf_(inc_energy_.value());
0150 UniformRealDistribution<real_type> sample_cdf(0, cdf_max);
0151 energy = calc_energy(sample_cdf(rng));
0152 }
0153 CELER_ENSURE(energy < inc_energy_.value());
0154 secondaries[i].energy = Energy{energy};
0155
0156
0157 secondaries[i].direction = sample_direction(rng);
0158 secondaries[i].polarization
0159 = ExitingDirectionSampler{0, secondaries[i].direction}(rng);
0160
0161 CELER_ENSURE(is_soft_unit_vector(secondaries[i].direction));
0162 CELER_ENSURE(is_soft_unit_vector(secondaries[i].polarization));
0163 CELER_ENSURE(soft_zero(dot_product(secondaries[i].direction,
0164 secondaries[i].polarization)));
0165
0166
0167 secondaries[i].time = sample_time_(rng);
0168 }
0169
0170 CELER_ENSURE(result.action == Interaction::Action::absorbed);
0171
0172 return result;
0173 }
0174
0175
0176 }
0177 }