File indexing completed on 2025-02-22 10:31:28
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010 #include "corecel/Assert.hh"
0011 #include "corecel/Macros.hh"
0012 #include "celeritas/Quantities.hh"
0013 #include "celeritas/phys/ParticleTrackView.hh"
0014 #include "celeritas/random/distribution/NormalDistribution.hh"
0015 #include "celeritas/random/distribution/PoissonDistribution.hh"
0016 #include "celeritas/track/SimTrackView.hh"
0017
0018 #include "GeneratorDistributionData.hh"
0019 #include "OffloadData.hh"
0020 #include "ScintillationData.hh"
0021
0022 namespace celeritas
0023 {
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039 class ScintillationOffload
0040 {
0041 public:
0042
0043 inline CELER_FUNCTION
0044 ScintillationOffload(ParticleTrackView const& particle,
0045 SimTrackView const& sim,
0046 Real3 const& pos,
0047 units::MevEnergy energy_deposition,
0048 NativeCRef<optical::ScintillationData> const& shared,
0049 OffloadPreStepData const& step_data);
0050
0051
0052 template<class Generator>
0053 inline CELER_FUNCTION optical::GeneratorDistributionData
0054 operator()(Generator& rng);
0055
0056 private:
0057 units::ElementaryCharge charge_;
0058 real_type step_length_;
0059 OffloadPreStepData const& pre_step_;
0060 optical::GeneratorStepData post_step_;
0061 NativeCRef<optical::ScintillationData> const& shared_;
0062 real_type mean_num_photons_{0};
0063
0064 static CELER_CONSTEXPR_FUNCTION real_type poisson_threshold()
0065 {
0066 return 10;
0067 }
0068 };
0069
0070
0071
0072
0073
0074
0075
0076 CELER_FUNCTION ScintillationOffload::ScintillationOffload(
0077 ParticleTrackView const& particle,
0078 SimTrackView const& sim,
0079 Real3 const& pos,
0080 units::MevEnergy energy_deposition,
0081 NativeCRef<optical::ScintillationData> const& shared,
0082 OffloadPreStepData const& step_data)
0083 : charge_(particle.charge())
0084 , step_length_(sim.step_length())
0085 , pre_step_(step_data)
0086 , post_step_({particle.speed(), pos})
0087 , shared_(shared)
0088 {
0089 CELER_EXPECT(step_length_ > 0);
0090 CELER_EXPECT(shared_);
0091 CELER_EXPECT(pre_step_);
0092
0093 if (shared_.scintillation_by_particle())
0094 {
0095
0096
0097 CELER_ASSERT_UNREACHABLE();
0098 }
0099 else
0100 {
0101
0102 CELER_ASSERT(pre_step_.material < shared_.materials.size());
0103 auto const& material = shared_.materials[pre_step_.material];
0104
0105
0106 if (material)
0107 {
0108 mean_num_photons_ = material.yield_per_energy
0109 * energy_deposition.value();
0110 }
0111 }
0112 }
0113
0114
0115
0116
0117
0118
0119 template<class Generator>
0120 CELER_FUNCTION optical::GeneratorDistributionData
0121 ScintillationOffload::operator()(Generator& rng)
0122 {
0123
0124 optical::GeneratorDistributionData result;
0125 if (mean_num_photons_ > poisson_threshold())
0126 {
0127 real_type sigma = shared_.resolution_scale[pre_step_.material]
0128 * std::sqrt(mean_num_photons_);
0129 result.num_photons = static_cast<size_type>(clamp_to_nonneg(
0130 NormalDistribution<real_type>(mean_num_photons_, sigma)(rng)
0131 + real_type{0.5}));
0132 }
0133 else if (mean_num_photons_ > 0)
0134 {
0135 result.num_photons = static_cast<size_type>(
0136 PoissonDistribution<real_type>(mean_num_photons_)(rng));
0137 }
0138
0139 if (result.num_photons > 0)
0140 {
0141
0142 result.time = pre_step_.time;
0143 result.step_length = step_length_;
0144 result.charge = charge_;
0145 result.material = pre_step_.material;
0146 result.points[StepPoint::pre].speed = pre_step_.speed;
0147 result.points[StepPoint::pre].pos = pre_step_.pos;
0148 result.points[StepPoint::post] = post_step_;
0149 }
0150 return result;
0151 }
0152
0153
0154 }