File indexing completed on 2026-05-27 07:24:03
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011
0012 #include "detray/definitions/detail/macros.hpp"
0013 #include "detray/definitions/detail/qualifiers.hpp"
0014 #include "detray/navigation/intersection/intersection.hpp"
0015 #include "detray/propagator/actor_chain.hpp"
0016 #include "detray/propagator/base_stepper.hpp"
0017 #include "detray/propagator/concepts.hpp"
0018 #include "detray/propagator/detail/noise_estimation.hpp"
0019 #include "detray/propagator/propagation_config.hpp"
0020 #include "detray/tracks/tracks.hpp"
0021 #include "detray/utils/logging.hpp"
0022
0023
0024 #include <iomanip>
0025
0026 namespace detray {
0027
0028
0029
0030
0031
0032
0033 template <typename stepper_t, typename navigator_t,
0034 concepts::actor_chain actor_chain_t>
0035 struct propagator {
0036 using stepper_type = stepper_t;
0037 using navigator_type = navigator_t;
0038 using actor_chain_type = actor_chain_t;
0039
0040 using detector_type = typename navigator_type::detector_type;
0041 using algebra_type = typename detector_type::algebra_type;
0042 using scalar_type = dscalar<algebra_type>;
0043 using intersection_type = typename navigator_type::intersection_type;
0044 using free_track_parameters_type =
0045 typename stepper_t::free_track_parameters_type;
0046 using bound_track_parameters_type =
0047 typename stepper_t::bound_track_parameters_type;
0048
0049 const propagation::config &m_cfg;
0050
0051 stepper_t m_stepper{};
0052 navigator_t m_navigator{};
0053
0054
0055 const actor_chain_type run_actors{};
0056
0057
0058 DETRAY_HOST_DEVICE
0059 explicit constexpr propagator(const propagation::config &cfg) : m_cfg{cfg} {}
0060
0061
0062
0063 template <bool states_as_reference = false>
0064 struct state_base {
0065 using detector_type = typename navigator_t::detector_type;
0066 using context_type = typename detector_type::geometry_context;
0067 using algebra_type = typename detector_type::algebra_type;
0068 using scalar_type = typename detector_type::scalar_type;
0069
0070 using stepper_state_type = typename stepper_t::state;
0071 using navigator_state_type = typename navigator_t::state;
0072 using actor_chain_type = actor_chain_t;
0073
0074 static constexpr bool stepper_uses_gradient = stepper_type::uses_gradient;
0075
0076
0077 DETRAY_HOST_DEVICE state_base(const free_track_parameters_type &free_params,
0078 const detector_type &det,
0079 const context_type &ctx)
0080 requires(!states_as_reference)
0081 : m_stepping(free_params), m_navigation(det), m_context(ctx) {}
0082
0083
0084 template <typename field_t>
0085 requires(!states_as_reference &&
0086 concepts::is_field_of<stepper_type, field_t>)
0087 DETRAY_HOST_DEVICE state_base(const free_track_parameters_type &free_params,
0088 const field_t &magnetic_field,
0089 const detector_type &det,
0090 const context_type &ctx = {})
0091 : m_stepping(free_params, magnetic_field),
0092 m_navigation(det),
0093 m_context(ctx) {}
0094
0095
0096 DETRAY_HOST_DEVICE state_base(
0097 const free_track_parameters_type &free_params, const detector_type &det,
0098 typename navigator_type::state::view_type nav_view,
0099 const context_type &ctx = {})
0100 requires(!states_as_reference)
0101 : m_stepping(free_params),
0102 m_navigation(det, nav_view),
0103 m_context(ctx) {}
0104
0105
0106 template <typename field_t>
0107 requires(!states_as_reference &&
0108 concepts::is_field_of<stepper_type, field_t>)
0109 DETRAY_HOST_DEVICE state_base(
0110 const free_track_parameters_type &free_params,
0111 const field_t &magnetic_field, const detector_type &det,
0112 typename navigator_type::state::view_type nav_view,
0113 const context_type &ctx = {})
0114 : m_stepping(free_params, magnetic_field),
0115 m_navigation(det, nav_view),
0116 m_context(ctx) {}
0117
0118
0119 DETRAY_HOST_DEVICE state_base(const bound_track_parameters_type ¶m,
0120 const detector_type &det,
0121 const context_type &ctx = {})
0122 requires(!states_as_reference)
0123 : m_stepping(param, det, ctx), m_navigation(det), m_context(ctx) {
0124 m_navigation.set_volume(param.surface_link().volume());
0125 }
0126
0127
0128
0129 DETRAY_HOST_DEVICE state_base(stepper_state_type &stepping,
0130 navigator_state_type &navigation,
0131 const context_type &ctx = {})
0132 requires(states_as_reference)
0133 : m_stepping(stepping), m_navigation(navigation), m_context(ctx) {}
0134
0135
0136 template <typename field_t>
0137 requires concepts::is_field_of<stepper_type, field_t>
0138 DETRAY_HOST_DEVICE state_base(const bound_track_parameters_type ¶m,
0139 const field_t &magnetic_field,
0140 const detector_type &det,
0141 const context_type &ctx = {})
0142 : m_stepping(param, magnetic_field, det, ctx),
0143 m_navigation(det),
0144 m_context(ctx) {
0145 m_navigation.set_volume(param.surface_link().volume());
0146 }
0147
0148
0149
0150 template <typename field_t>
0151 requires concepts::is_field_of<stepper_type, field_t>
0152 DETRAY_HOST_DEVICE state_base(
0153 const bound_track_parameters_type ¶m, const field_t &magnetic_field,
0154 const detector_type &det,
0155 typename navigator_type::state::view_type nav_view,
0156 const context_type &ctx = {})
0157 : m_stepping(param, magnetic_field, det, ctx),
0158 m_navigation(det, nav_view),
0159 m_context(ctx) {
0160 m_navigation.set_volume(param.surface_link().volume());
0161 }
0162
0163
0164 DETRAY_HOST_DEVICE
0165 void set_particle(const pdg_particle<scalar_type> &ptc) {
0166 m_stepping.set_particle(ptc);
0167 }
0168
0169
0170 DETRAY_HOST_DEVICE
0171 bool is_alive() const { return m_heartbeat; }
0172
0173
0174 DETRAY_HOST_DEVICE
0175 bool heartbeat() const { return m_heartbeat; }
0176
0177
0178 DETRAY_HOST_DEVICE
0179 void heartbeat(bool heartbeat) { m_heartbeat = heartbeat; }
0180
0181 DETRAY_HOST_DEVICE
0182 const stepper_state_type &stepping() const { return m_stepping; }
0183
0184 DETRAY_HOST_DEVICE
0185 stepper_state_type &stepping() { return m_stepping; }
0186
0187 DETRAY_HOST_DEVICE
0188 const navigator_state_type &navigation() const { return m_navigation; }
0189
0190 DETRAY_HOST_DEVICE
0191 navigator_state_type &navigation() { return m_navigation; }
0192
0193 DETRAY_HOST_DEVICE
0194 const context_type &context() const { return m_context; }
0195
0196 DETRAY_HOST_DEVICE
0197 context_type &context() { return m_context; }
0198
0199 DETRAY_HOST_DEVICE
0200 bool debug() const { return m_do_debug; }
0201
0202 DETRAY_HOST_DEVICE
0203 void debug(bool b) { m_do_debug = b; }
0204
0205 private:
0206 std::conditional_t<states_as_reference, stepper_state_type &,
0207 stepper_state_type>
0208 m_stepping;
0209 std::conditional_t<states_as_reference, navigator_state_type &,
0210 navigator_state_type>
0211 m_navigation;
0212
0213 context_type m_context;
0214
0215
0216 bool m_heartbeat = false;
0217 bool m_do_debug = false;
0218 };
0219
0220 using state = state_base<false>;
0221
0222
0223
0224
0225
0226
0227
0228 template <bool is_owning>
0229 DETRAY_HOST_DEVICE bool finished(
0230 const state_base<is_owning> &propagation) const {
0231 return propagation.navigation().finished();
0232 }
0233
0234
0235 template <bool is_owning>
0236 DETRAY_HOST_DEVICE inline auto is_paused(
0237 const state_base<is_owning> &propagation) const -> bool {
0238 return !propagation.is_alive() && propagation.navigation().is_alive();
0239 }
0240
0241
0242 template <bool is_owning>
0243 DETRAY_HOST_DEVICE inline void resume(
0244 state_base<is_owning> &propagation) const {
0245 assert(propagation.navigation().is_alive());
0246 propagation.heartbeat(true);
0247 }
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257 template <typename actor_states_t, bool is_owning>
0258 requires(concepts::is_state_of<actor_states_t, actor_chain_type>)
0259 DETRAY_HOST_DEVICE bool propagate(
0260 state_base<is_owning> &propagation,
0261 actor_states_t actor_state_refs = dtuple<>{}) const {
0262 auto &navigation = propagation.navigation();
0263 auto &stepping = propagation.stepping();
0264 auto &context = propagation.context();
0265 const auto &track = stepping();
0266 assert(!track.is_invalid());
0267
0268 DETRAY_VERBOSE_HOST("Starting propagation for track:\n" << track);
0269
0270 bool is_init = false;
0271 if (this->is_paused(propagation)) {
0272 DETRAY_VERBOSE_HOST("Resuming propagation...");
0273 } else {
0274
0275 DETRAY_VERBOSE_HOST("Initialize navigation...");
0276 m_navigator.init(track, navigation, m_cfg.navigation, context);
0277 propagation.heartbeat(navigation.is_alive());
0278
0279 is_init = true;
0280 }
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294 scalar_type path_length{0.f};
0295 unsigned int stall_counter{0u};
0296 for (unsigned int i = 0; i % 2 == 0 || propagation.is_alive(); ++i) {
0297 if (i % 2 == 0) {
0298 DETRAY_VERBOSE_HOST_DEVICE("Propagation step: %d", i / 2);
0299 DETRAY_VERBOSE_HOST_DEVICE("-> Path length: %f mm",
0300 stepping.path_length());
0301
0302
0303 run_actors(actor_state_refs, propagation);
0304
0305
0306 if (!propagation.is_alive()) {
0307 continue;
0308 }
0309
0310 path_length = stepping.path_length();
0311
0312 assert(!track.is_invalid());
0313 } else {
0314 assert(!track.is_invalid());
0315
0316
0317 auto vol = navigation.current_volume();
0318 const material<scalar_type> *vol_mat_ptr =
0319 vol.has_material() ? vol.material_parameters(track.pos()) : nullptr;
0320
0321
0322
0323
0324 const bool reset_stepsize{navigation.is_on_surface() || is_init};
0325
0326
0327 DETRAY_VERBOSE_HOST("Calling stepper...");
0328 propagation.heartbeat(propagation.heartbeat() &&
0329 m_stepper.step(navigation(), stepping,
0330 m_cfg.stepping, reset_stepsize,
0331 vol_mat_ptr));
0332
0333
0334 DETRAY_VERBOSE_HOST("-> Evaluate stepper navigation policy:");
0335 typename stepper_t::policy_type{}(stepping.policy_state(), propagation);
0336
0337 if (i > 0) {
0338 is_init = false;
0339 }
0340
0341
0342 if (math::fabs(stepping.path_length()) <=
0343 math::fabs(path_length) +
0344 m_cfg.navigation.intersection.path_tolerance) {
0345 if (stall_counter >= 10u) {
0346 propagation.heartbeat(false);
0347 navigation.abort("Propagation stalled");
0348 DETRAY_ERROR_HOST("Propagation stalled");
0349 } else if (stall_counter > 2u) {
0350
0351
0352 DETRAY_WARN_HOST("Propagation is stalling (counter "
0353 << stall_counter << ")");
0354 DETRAY_VERBOSE_DEVICE("Propagation is stalling (counter %d)",
0355 stall_counter);
0356 DETRAY_WARN_HOST(print(propagation));
0357 DETRAY_WARN_HOST("-> Track: " << stepping());
0358 }
0359 DETRAY_DEBUG_HOST_DEVICE("-> Step stalled. Counter %d",
0360 stall_counter);
0361 stall_counter++;
0362 } else {
0363 stall_counter = 0u;
0364 }
0365 }
0366
0367
0368 DETRAY_VERBOSE_HOST("Calling navigator...");
0369 const bool nav_is_init =
0370 m_navigator.update(track, navigation, m_cfg.navigation, context);
0371 is_init = is_init || nav_is_init;
0372
0373 propagation.heartbeat(propagation.heartbeat() && navigation.is_alive());
0374
0375 if (i % 2 == 0 && i > 0 && propagation.debug()) {
0376 DETRAY_VERBOSE_HOST(print(propagation));
0377 }
0378 }
0379
0380
0381 DETRAY_VERBOSE_HOST("Finished propagation for track:\n" << track);
0382 if (finished(propagation)) {
0383 DETRAY_VERBOSE_HOST_DEVICE("Status: SUCCESS");
0384 } else if (is_paused(propagation)) {
0385 DETRAY_VERBOSE_HOST_DEVICE("Status: PAUSED");
0386 } else {
0387 DETRAY_VERBOSE_HOST_DEVICE("Status: ABORT");
0388 }
0389
0390 return finished(propagation) || is_paused(propagation);
0391 }
0392
0393
0394 template <bool is_owning>
0395 DETRAY_HOST_DEVICE bool propagate(state_base<is_owning> &propagation) {
0396
0397 actor_chain<>::state empty_state{};
0398
0399 return propagate(propagation, empty_state);
0400 }
0401
0402 template <bool is_owning>
0403 DETRAY_HOST std::string print(state_base<is_owning> &propagation) const {
0404 const auto &navigation = propagation.navigation();
0405 const auto &stepping = propagation.stepping();
0406
0407 std::stringstream debug_stream{};
0408 debug_stream << std::left << std::setw(10);
0409 debug_stream << "\nstatus: " << navigation.status() << std::endl;
0410
0411 debug_stream << "volume: " << std::setw(10);
0412 if (detail::is_invalid_value(navigation.volume())) {
0413 debug_stream << "invalid";
0414 } else {
0415 debug_stream << navigation.volume();
0416 }
0417 debug_stream << std::endl;
0418
0419 debug_stream << "navigation:" << std::endl;
0420 if (navigation.is_on_surface()) {
0421 debug_stream << std::setw(10)
0422 << " -> on surface: " << navigation.geometry_identifier();
0423 } else {
0424 debug_stream << std::setw(10) << " -> target: "
0425 << navigation.target().surface().identifier();
0426 }
0427 debug_stream << std::endl;
0428 debug_stream << std::setw(10) << " -> path: " << navigation() << " mm"
0429 << std::endl;
0430
0431 debug_stream << "stepping:" << std::endl;
0432 debug_stream << std::setw(10) << " -> step size: " << stepping.step_size()
0433 << " mm" << std::endl;
0434 debug_stream << " -> " << detail::ray<algebra_type>(stepping());
0435
0436 return debug_stream.str();
0437 }
0438 };
0439 }