File indexing completed on 2025-02-22 10:31:19
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010 #include "corecel/Assert.hh"
0011 #include "corecel/Macros.hh"
0012 #include "corecel/Types.hh"
0013 #include "corecel/math/ArrayOperators.hh"
0014 #include "celeritas/Types.hh"
0015 #include "celeritas/em/data/UrbanMscData.hh"
0016 #include "celeritas/global/CoreTrackView.hh"
0017
0018 #include "detail/MscStepFromGeo.hh" // IWYU pragma: associated
0019 #include "detail/MscStepToGeo.hh" // IWYU pragma: associated
0020 #include "detail/UrbanMscHelper.hh" // IWYU pragma: associated
0021 #include "detail/UrbanMscMinimalStepLimit.hh" // IWYU pragma: associated
0022 #include "detail/UrbanMscSafetyStepLimit.hh" // IWYU pragma: associated
0023 #include "detail/UrbanMscScatter.hh" // IWYU pragma: associated
0024
0025 namespace celeritas
0026 {
0027
0028
0029
0030
0031 class UrbanMsc
0032 {
0033 public:
0034
0035
0036 using ParamsRef = NativeCRef<UrbanMscData>;
0037
0038
0039 public:
0040
0041 explicit inline CELER_FUNCTION UrbanMsc(ParamsRef const& shared);
0042
0043
0044 inline CELER_FUNCTION bool
0045 is_applicable(CoreTrackView const&, real_type step) const;
0046
0047
0048 inline CELER_FUNCTION void limit_step(CoreTrackView const&);
0049
0050
0051 inline CELER_FUNCTION void apply_step(CoreTrackView const&);
0052
0053 private:
0054 ParamsRef const shared_;
0055
0056
0057 static inline CELER_FUNCTION bool is_geo_limited(CoreTrackView const&);
0058 };
0059
0060
0061
0062
0063
0064
0065
0066 CELER_FUNCTION UrbanMsc::UrbanMsc(ParamsRef const& shared) : shared_(shared)
0067 {
0068 CELER_EXPECT(shared_);
0069 }
0070
0071
0072
0073
0074
0075 CELER_FUNCTION bool
0076 UrbanMsc::is_applicable(CoreTrackView const& track, real_type step) const
0077 {
0078 if (step <= shared_.params.geom_limit)
0079 return false;
0080
0081 if (track.make_sim_view().status() != TrackStatus::alive)
0082 return false;
0083
0084 auto par = track.make_particle_view();
0085 if (par.particle_id() != shared_.ids.electron
0086 && par.particle_id() != shared_.ids.positron)
0087 return false;
0088
0089 return par.energy() > shared_.params.low_energy_limit
0090 && par.energy() < shared_.params.high_energy_limit;
0091 }
0092
0093
0094
0095
0096
0097 CELER_FUNCTION void UrbanMsc::limit_step(CoreTrackView const& track)
0098 {
0099 auto phys = track.make_physics_view();
0100 auto par = track.make_particle_view();
0101 auto sim = track.make_sim_view();
0102 detail::UrbanMscHelper msc_helper(shared_, par, phys);
0103
0104 bool displaced = false;
0105
0106
0107 real_type const true_path = [&] {
0108 if (sim.step_length() <= shared_.params.limit_min_fix())
0109 {
0110
0111 return sim.step_length();
0112 }
0113
0114 auto geo = track.make_geo_view();
0115
0116 real_type safety = 0;
0117 if (!geo.is_on_boundary())
0118 {
0119
0120
0121
0122
0123 real_type const max_step = msc_helper.max_step();
0124 safety = geo.find_safety(max_step);
0125 if (safety >= max_step)
0126 {
0127
0128
0129 return sim.step_length();
0130 }
0131 }
0132
0133 auto rng = track.make_rng_engine();
0134 displaced = true;
0135
0136 if (phys.scalars().step_limit_algorithm
0137 == MscStepLimitAlgorithm::minimal)
0138 {
0139
0140 detail::UrbanMscMinimalStepLimit calc_limit(shared_,
0141 msc_helper,
0142 &phys,
0143 geo.is_on_boundary(),
0144 sim.step_length());
0145 return calc_limit(rng);
0146 }
0147
0148
0149 detail::UrbanMscSafetyStepLimit calc_limit(shared_,
0150 msc_helper,
0151 par.energy(),
0152 &phys,
0153 phys.material_id(),
0154 geo.is_on_boundary(),
0155 safety,
0156 sim.step_length());
0157 return calc_limit(rng);
0158
0159
0160 }();
0161 CELER_ASSERT(true_path <= sim.step_length());
0162
0163 bool limited = (true_path < sim.step_length());
0164
0165
0166
0167
0168 auto gp = [&] {
0169 detail::MscStepToGeo calc_geom_path(shared_,
0170 msc_helper,
0171 par.energy(),
0172 msc_helper.msc_mfp(),
0173 phys.dedx_range());
0174 auto gp = calc_geom_path(true_path);
0175
0176
0177 if (gp.step > msc_helper.msc_mfp())
0178 {
0179 gp.step = msc_helper.msc_mfp();
0180 limited = true;
0181 }
0182
0183 return gp;
0184 }();
0185 CELER_ASSERT(0 < gp.step && gp.step <= true_path);
0186
0187
0188 track.make_physics_step_view().msc_step([&] {
0189 MscStep result;
0190 result.is_displaced = displaced;
0191 result.true_path = true_path;
0192 result.geom_path = gp.step;
0193 result.alpha = gp.alpha;
0194 return result;
0195 }());
0196
0197 sim.step_length(gp.step);
0198 if (limited)
0199 {
0200
0201 sim.post_step_action(phys.scalars().msc_action());
0202 }
0203 }
0204
0205
0206
0207
0208
0209 CELER_FUNCTION void UrbanMsc::apply_step(CoreTrackView const& track)
0210 {
0211 auto par = track.make_particle_view();
0212 auto geo = track.make_geo_view();
0213 auto phys = track.make_physics_view();
0214 auto sim = track.make_sim_view();
0215
0216
0217 detail::UrbanMscHelper msc_helper(shared_, par, phys);
0218 auto msc_step = track.make_physics_step_view().msc_step();
0219 if (this->is_geo_limited(track))
0220 {
0221
0222
0223
0224 msc_step.geom_path = sim.step_length();
0225 detail::MscStepFromGeo geo_to_true(
0226 shared_.params, msc_step, phys.dedx_range(), msc_helper.msc_mfp());
0227 msc_step.true_path = geo_to_true(msc_step.geom_path);
0228 CELER_ASSERT(msc_step.true_path >= msc_step.geom_path);
0229
0230
0231 msc_step.is_displaced = false;
0232 }
0233
0234
0235
0236 sim.step_length(msc_step.true_path);
0237
0238 auto msc_result = [&] {
0239 real_type safety = 0;
0240 if (msc_step.is_displaced)
0241 {
0242 CELER_ASSERT(!geo.is_on_boundary());
0243
0244 real_type displ = detail::UrbanMscScatter::calc_displacement(
0245 msc_step.geom_path, msc_step.true_path);
0246
0247
0248
0249
0250
0251 displ = max(displ * (1 + 2 * shared_.params.safety_tol),
0252 shared_.params.geom_limit);
0253 safety = geo.find_safety(displ);
0254 if (CELER_UNLIKELY(safety == 0))
0255 {
0256
0257
0258
0259 msc_step.is_displaced = false;
0260 }
0261 }
0262
0263 auto mat = track.make_material_view().make_material_view();
0264 detail::UrbanMscScatter sample_scatter(
0265 shared_, msc_helper, par, phys, mat, geo.dir(), safety, msc_step);
0266
0267 auto rng = track.make_rng_engine();
0268 return sample_scatter(rng);
0269 }();
0270
0271
0272 if (msc_result.action != MscInteraction::Action::unchanged)
0273 {
0274
0275 geo.set_dir(msc_result.direction);
0276 }
0277 if (msc_result.action == MscInteraction::Action::displaced)
0278 {
0279
0280 CELER_ASSERT(!geo.is_on_boundary());
0281 geo.move_internal(geo.pos() + msc_result.displacement);
0282 }
0283 }
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293 CELER_FUNCTION bool UrbanMsc::is_geo_limited(CoreTrackView const& track)
0294 {
0295 auto sim = track.make_sim_view();
0296 return (sim.post_step_action() == track.boundary_action()
0297 || sim.post_step_action() == track.propagation_limit_action());
0298 }
0299
0300
0301 }