Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-27 07:24:03

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 // Project include(s).
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 // System include(s).
0024 #include <iomanip>
0025 
0026 namespace detray {
0027 
0028 /// Templated propagator class, using a stepper and a navigator object in
0029 /// succession.
0030 ///
0031 /// @tparam stepper_t for the transport
0032 /// @tparam navigator_t for the navigation
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   /// Register the actor types
0055   const actor_chain_type run_actors{};
0056 
0057   /// Construct from a propagator configuration
0058   DETRAY_HOST_DEVICE
0059   explicit constexpr propagator(const propagation::config &cfg) : m_cfg{cfg} {}
0060 
0061   /// Propagation that state aggregates a stepping and a navigation state.
0062   /// It also keeps references to the actor states.
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     /// Construct the propagation state with free parameter
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     /// Construct the propagation state with free parameter
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     /// Construct the propagation state from the navigator state view
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     /// Construct the propagation state from the navigator state view
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     /// Construct the propagation state with bound parameter
0119     DETRAY_HOST_DEVICE state_base(const bound_track_parameters_type &param,
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     /// Construct the propagation state with propagation and navigation
0128     /// state
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     /// Construct the propagation state with bound parameter
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 &param,
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     /// Construct the propagation state with bound parameter and
0149     /// navigator state view
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 &param, 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     /// Set the particle hypothesis
0164     DETRAY_HOST_DEVICE
0165     void set_particle(const pdg_particle<scalar_type> &ptc) {
0166       m_stepping.set_particle(ptc);
0167     }
0168 
0169     /// @returns the propagation heartbeat
0170     DETRAY_HOST_DEVICE
0171     bool is_alive() const { return m_heartbeat; }
0172 
0173     /// @returns the propagation heartbeat
0174     DETRAY_HOST_DEVICE
0175     bool heartbeat() const { return m_heartbeat; }
0176 
0177     /// @returns the propagation heartbeat
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     // Is the propagation still alive?
0216     bool m_heartbeat = false;
0217     bool m_do_debug = false;
0218   };
0219 
0220   using state = state_base<false>;
0221 
0222   /// Propagate method finale: Return whether or not the propagation
0223   /// completed successfully.
0224   ///
0225   /// @param propagation the state of a propagation flow
0226   ///
0227   /// @return propagation success.
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   /// @returns true if the @param propagation is suspended
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   /// Revive the propagation
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   /// Propagate method: Coordinates the calls of the stepper, navigator
0250   /// and all registered actors.
0251   ///
0252   /// @param propagation the state of a propagation flow
0253   /// @param actor_state_refs tuple containing references to the actor
0254   /// states
0255   ///
0256   /// @return propagation success.
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       // Initialize the navigation
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     // Run while there is a heartbeat. In order to help the compiler
0283     // optimize this, and in order to make the code more GPU-friendly,
0284     // this code is run as a flat loop, but this loop has a defined
0285     // structure. Indeed, the structure is always to run either the
0286     // actors or the stepper (in alternating order) followed by the
0287     // navigation update.
0288     //
0289     // A = actors
0290     // N = navigation update
0291     // S = propagation step
0292     //
0293     // ANSNANSNANSNANSNANSNANS...
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         // Run all registered actors/aborters
0303         run_actors(actor_state_refs, propagation);
0304 
0305         // Don't run another navigation update, if already exited
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         // Set access to the volume material for the stepper
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         // Break automatic step size scaling by the stepper when a
0322         // surface was reached and whenever the navigation is
0323         // (re-)initialized
0324         const bool reset_stepsize{navigation.is_on_surface() || is_init};
0325 
0326         // Take the step
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         // Reduce navigation trust level according to stepper update
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         // Check if the propagation makes progress
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             // Print a warning if the propagation starts stalling
0351             // (no overlap)
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       // Find next candidate
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     // Pass on the whether the propagation was successful
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   /// Overload for empty actor chain
0394   template <bool is_owning>
0395   DETRAY_HOST_DEVICE bool propagate(state_base<is_owning> &propagation) {
0396     // Will not be used
0397     actor_chain<>::state empty_state{};
0398     // Run propagation
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 }  // namespace detray