File indexing completed on 2025-02-22 10:31:27
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010 #include <cmath>
0011
0012 #include "corecel/Assert.hh"
0013 #include "corecel/Macros.hh"
0014 #include "corecel/Types.hh"
0015 #include "corecel/data/Collection.hh"
0016 #include "corecel/math/ArrayOperators.hh"
0017 #include "corecel/math/ArrayUtils.hh"
0018 #include "celeritas/grid/GenericCalculator.hh"
0019 #include "celeritas/random/distribution/BernoulliDistribution.hh"
0020 #include "celeritas/random/distribution/RejectionSampler.hh"
0021 #include "celeritas/random/distribution/UniformRealDistribution.hh"
0022
0023 #include "CerenkovDndxCalculator.hh"
0024 #include "GeneratorDistributionData.hh"
0025 #include "MaterialView.hh"
0026 #include "TrackInitializer.hh"
0027
0028 namespace celeritas
0029 {
0030 namespace optical
0031 {
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050 class CerenkovGenerator
0051 {
0052 public:
0053
0054 inline CELER_FUNCTION
0055 CerenkovGenerator(MaterialView const& material,
0056 NativeCRef<CerenkovData> const& shared,
0057 GeneratorDistributionData const& dist);
0058
0059
0060 template<class Generator>
0061 inline CELER_FUNCTION TrackInitializer operator()(Generator& rng);
0062
0063 private:
0064
0065
0066 using UniformRealDist = UniformRealDistribution<real_type>;
0067
0068
0069
0070 GeneratorDistributionData const& dist_;
0071 GenericCalculator calc_refractive_index_;
0072 UniformRealDist sample_phi_;
0073 UniformRealDist sample_num_photons_;
0074 UniformRealDist sample_energy_;
0075 Real3 dir_;
0076 Real3 delta_pos_;
0077 units::LightSpeed delta_speed_;
0078 real_type delta_num_photons_;
0079 real_type dndx_pre_;
0080 real_type sin_max_sq_;
0081 real_type inv_beta_;
0082 };
0083
0084
0085
0086
0087
0088
0089
0090 CELER_FUNCTION
0091 CerenkovGenerator::CerenkovGenerator(MaterialView const& material,
0092 NativeCRef<CerenkovData> const& shared,
0093 GeneratorDistributionData const& dist)
0094 : dist_(dist)
0095 , calc_refractive_index_(material.make_refractive_index_calculator())
0096 , sample_phi_(0, 2 * constants::pi)
0097 {
0098 CELER_EXPECT(shared);
0099 CELER_EXPECT(dist_);
0100 CELER_EXPECT(material.material_id() == dist_.material);
0101
0102 using LS = units::LightSpeed;
0103
0104
0105
0106 auto const& pre_step = dist_.points[StepPoint::pre];
0107 auto const& post_step = dist_.points[StepPoint::post];
0108 CerenkovDndxCalculator calc_dndx(material, shared, dist_.charge);
0109 dndx_pre_ = calc_dndx(pre_step.speed);
0110 real_type dndx_post = calc_dndx(post_step.speed);
0111
0112
0113 sample_num_photons_ = UniformRealDist(0, max(dndx_pre_, dndx_post));
0114
0115
0116 auto const& energy_grid = calc_refractive_index_.grid();
0117 sample_energy_ = UniformRealDist(energy_grid.front(), energy_grid.back());
0118
0119
0120 inv_beta_
0121 = 2 / (value_as<LS>(pre_step.speed) + value_as<LS>(post_step.speed));
0122 CELER_ASSERT(inv_beta_ > 1);
0123 real_type cos_max = inv_beta_ / calc_refractive_index_(energy_grid.back());
0124 sin_max_sq_ = 1 - ipow<2>(cos_max);
0125
0126
0127 delta_pos_ = post_step.pos - pre_step.pos;
0128 delta_num_photons_ = dndx_post - dndx_pre_;
0129 delta_speed_ = post_step.speed - pre_step.speed;
0130
0131
0132 dir_ = make_unit_vector(delta_pos_);
0133 }
0134
0135
0136
0137
0138
0139 template<class Generator>
0140 CELER_FUNCTION TrackInitializer CerenkovGenerator::operator()(Generator& rng)
0141 {
0142
0143 real_type energy;
0144 real_type cos_theta;
0145 real_type sin_theta_sq;
0146 do
0147 {
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158 do
0159 {
0160 energy = sample_energy_(rng);
0161 cos_theta = inv_beta_ / calc_refractive_index_(energy);
0162 } while (cos_theta > 1);
0163 sin_theta_sq = 1 - ipow<2>(cos_theta);
0164 } while (RejectionSampler{sin_theta_sq, sin_max_sq_}(rng));
0165
0166
0167 real_type phi = sample_phi_(rng);
0168 TrackInitializer photon;
0169 photon.direction = rotate(from_spherical(cos_theta, phi), dir_);
0170 photon.energy = units::MevEnergy(energy);
0171
0172
0173 photon.polarization
0174 = rotate(from_spherical(-std::sqrt(sin_theta_sq), phi), dir_);
0175
0176
0177 UniformRealDistribution sample_step_fraction;
0178 real_type u;
0179 do
0180 {
0181 u = sample_step_fraction(rng);
0182 } while (sample_num_photons_(rng) > dndx_pre_ + u * delta_num_photons_);
0183
0184 real_type delta_time
0185 = u * dist_.step_length
0186 / (native_value_from(dist_.points[StepPoint::pre].speed)
0187 + u * real_type(0.5) * native_value_from(delta_speed_));
0188 photon.time = dist_.time + delta_time;
0189 photon.position = dist_.points[StepPoint::pre].pos;
0190 axpy(u, delta_pos_, &photon.position);
0191 return photon;
0192 }
0193
0194
0195 }
0196 }