Back to home page

EIC code displayed by LXR

 
 

    


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

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/core/detector.hpp"
0013 #include "detray/definitions/containers.hpp"
0014 #include "detray/definitions/detail/qualifiers.hpp"
0015 #include "detray/definitions/indexing.hpp"
0016 #include "detray/definitions/navigation.hpp"
0017 #include "detray/definitions/units.hpp"
0018 #include "detray/navigation/detail/intersection_kernel.hpp"
0019 #include "detray/navigation/detail/navigation_functions.hpp"
0020 #include "detray/navigation/intersection/intersection.hpp"
0021 #include "detray/navigation/intersection/intersection_config.hpp"
0022 #include "detray/navigation/intersection/ray_intersector.hpp"
0023 #include "detray/navigation/navigation_config.hpp"
0024 #include "detray/navigation/navigation_state.hpp"
0025 
0026 namespace detray {
0027 
0028 template <typename detector_t, typename surface_t = void>
0029 class direct_navigator {
0030   using algebra_t = typename detector_t::algebra_type;
0031   using scalar_t = dscalar<algebra_t>;
0032 
0033  public:
0034   using detector_type = detector_t;
0035   using context_type = detector_type::geometry_context;
0036 
0037   // Use an external surface type, if one was provided
0038   using surface_type =
0039       std::conditional_t<std::same_as<surface_t, void>,
0040                          typename detector_t::surface_type, surface_t>;
0041   using intersection_type =
0042       intersection2D<surface_type, algebra_t, !intersection::contains_pos>;
0043   using inspector_type = navigation::void_inspector;
0044 
0045   class state
0046       : public navigation::base_state<state, detector_type, 2u, inspector_type,
0047                                       intersection_type> {
0048     friend class direct_navigator;
0049     friend struct detail::intersection_update<ray_intersector>;
0050 
0051     template <typename state_t>
0052     friend constexpr void navigation::update_status(state_t &,
0053                                                     const navigation::config &);
0054 
0055     using base_type = navigation::base_state<state, detector_type, 2u,
0056                                              inspector_type, intersection_type>;
0057 
0058     // Internal surface index
0059     using dist_t = std::int_least16_t;
0060 
0061    public:
0062     using value_type = intersection_type;
0063     using sequence_type = vecmem::device_vector<surface_type>;
0064 
0065     using view_type = dvector_view<surface_type>;
0066     using const_view_type = dvector_view<const surface_type>;
0067 
0068     /// Constructor using the detector and an externally provided sequence
0069     /// of detector surfaces
0070     DETRAY_HOST_DEVICE constexpr state(const detector_t &det,
0071                                        const view_type &sequence)
0072         : base_type(det), m_sequence(sequence) {
0073       assert(!m_sequence.empty());
0074       reset();
0075     }
0076 
0077     /// Reset the navigation state
0078     DETRAY_HOST_DEVICE void reset() {
0079       // Remove old navigation information
0080       clear_cache();
0081 
0082       // Set the index into the external surface sequence to the beginning
0083       // or end of the container
0084       m_next_external =
0085           is_forward() ? 0 : static_cast<dist_t>(m_sequence.size()) - 1;
0086 
0087       // Update the target with the next external surface
0088       this->target().set_surface(next_external());
0089 
0090       // The next candidate is always stored in the second cache entry
0091       this->next_index(1u);
0092       this->last_index(1u);
0093     }
0094 
0095     /// @returns the direct navigator always has only one candidate
0096     DETRAY_HOST_DEVICE
0097     constexpr auto n_candidates() const -> dindex { return 1u; }
0098 
0099     /// @returns the externally provided mask tolerance - const
0100     DETRAY_HOST_DEVICE
0101     constexpr scalar_t external_tol() const {
0102       return std::numeric_limits<scalar_t>::max();
0103     }
0104 
0105     /// Set direction in which the navigator should search for candidates
0106     DETRAY_HOST_DEVICE
0107     constexpr void set_direction(const navigation::direction dir) {
0108       base_type::set_direction(dir);
0109     }
0110 
0111     /// @returns true if the the next external is available in the sequence
0112     DETRAY_HOST_DEVICE
0113     constexpr bool has_next_external() const {
0114       return (is_forward() &&
0115               m_next_external != static_cast<dist_t>(m_sequence.size())) ||
0116              (!is_forward() && m_next_external != -1);
0117     }
0118 
0119     /// Advance the iterator
0120     DETRAY_HOST_DEVICE
0121     constexpr surface_type next_external() {
0122       assert(has_next_external());
0123       return m_sequence[static_cast<unsigned int>(m_next_external)];
0124     }
0125 
0126     /// Advance the iterator (navigation status needs to be up to date!)
0127     DETRAY_HOST_DEVICE
0128     constexpr void advance() {
0129       // The target has become the current candidate
0130       this->candidates()[0] = this->target();
0131 
0132       assert(has_next_external());
0133       if (is_forward()) {
0134         m_next_external++;
0135       } else {
0136         m_next_external--;
0137       }
0138 
0139       // Update the target with the next external surface
0140       // Could make the target invalid -> exit navigation
0141       if (has_next_external()) {
0142         // If the next external can be indexed, the cast is safe
0143         this->target().set_surface(
0144             m_sequence[static_cast<unsigned int>(m_next_external)]);
0145       }
0146 
0147       assert(
0148           !has_next_external() ||
0149           (has_next_external() && (this->target().surface().is_sensitive() ||
0150                                    this->target().surface().has_material())));
0151     }
0152 
0153     /// Clear the state
0154     DETRAY_HOST_DEVICE constexpr void clear_cache() {
0155       base_type::clear_cache();
0156       this->next_index(1);
0157       this->last_index(1);
0158     }
0159 
0160     /// @returns flag that indicates whether navigation was successful
0161     DETRAY_HOST_DEVICE
0162     constexpr bool finished() const {
0163       // Normal exit for this navigation?
0164       bool is_finished = base_type::finished();
0165 
0166       // All external surfaces were visited?
0167       is_finished =
0168           is_finished &&
0169           ((is_forward() &&
0170             m_next_external == static_cast<dist_t>(m_sequence.size())) ||
0171            (!is_forward() && m_next_external == -1));
0172 
0173       return is_finished;
0174     }
0175 
0176    private:
0177     /// @returns 'true' if the navigation direction is 'forward'
0178     DETRAY_HOST_DEVICE
0179     constexpr bool is_forward() const {
0180       return this->direction() == navigation::direction::e_forward;
0181     }
0182 
0183     /// Target surfaces
0184     sequence_type m_sequence;
0185 
0186     /// Index of the next (target) surface descriptor in the sequence
0187     dist_t m_next_external{0};
0188   };
0189 
0190   /// Initialize the direct navigation flow on the first/last external surface
0191   template <typename track_t>
0192   DETRAY_HOST_DEVICE inline void init(const track_t &track, state &navigation,
0193                                       const navigation::config &cfg,
0194                                       const context_type &ctx) const {
0195     DETRAY_VERBOSE_HOST_DEVICE("Called 'init()':");
0196     assert(navigation.has_next_external());
0197 
0198     // Clean up state
0199     navigation.clear_cache();
0200 
0201     // Update the next candidate
0202     update(track, navigation, cfg, ctx);
0203 
0204     DETRAY_VERBOSE_HOST_DEVICE("Init complete!");
0205   }
0206 
0207   /// Update the navigation status on the current next external and switch
0208   /// to the following external surface if the current one was reached
0209   template <typename track_t>
0210   DETRAY_HOST_DEVICE inline bool update(const track_t &track, state &navigation,
0211                                         const navigation::config &cfg,
0212                                         const context_type &ctx = {}) const {
0213     DETRAY_VERBOSE_HOST_DEVICE("Called 'update()'");
0214     DETRAY_DEBUG_HOST(" -> Trust level: " << navigation.trust_level());
0215 
0216     // Do not resurrect a failed/finished navigation state
0217     assert(navigation.is_alive() ||
0218            navigation.status() == navigation::status::e_unknown);
0219     assert(!track.is_invalid());
0220 
0221     // If the last external was reached, the navigation is finished
0222     constexpr bool is_init{true};
0223     if (!navigation.has_next_external()) {
0224       DETRAY_VERBOSE_HOST_DEVICE("No next target in surface sequence: Exit");
0225       navigation.exit();
0226       return !is_init;
0227     }
0228 
0229     const detector_type &det = navigation.detector();
0230 
0231     // Update only the current candidate and the corresponding next target
0232     if (navigation.trust_level() != navigation::trust_level::e_full) {
0233       // Use infinite tolerance to hit the target surface
0234       constexpr auto inf{std::numeric_limits<float>::max()};
0235       const intersection::config intr_cfg{
0236           inf, inf, inf, cfg.intersection.path_tolerance, -inf};
0237 
0238       // Update the current target. If it cannot be reached, direct
0239       // navigation is broken
0240       if (!navigation::update_candidate(
0241               navigation.direction(), navigation.target(), track, det, intr_cfg,
0242               navigation.external_tol(), ctx)) {
0243         navigation.abort("Could not reach current target");
0244         return !is_init;
0245       }
0246 
0247       // Update navigation flow on the new candidate information and set
0248       // the next target if the surface has been reached
0249       navigation::update_status(navigation, cfg);
0250       // Set full trust, even if a portal was reached (no volume switch)
0251       navigation.trust_level(navigation::trust_level::e_full);
0252 
0253       // The work is done if the track has not reached the surface yet
0254       if (navigation.status() == navigation::status::e_towards_object) {
0255         DETRAY_VERBOSE_HOST_DEVICE("Update complete (towards object):");
0256         DETRAY_DEBUG_HOST("\n"
0257                           << detray::navigation::print_state(navigation)
0258                           << detray::navigation::print_candidates(
0259                                  navigation, cfg, track.pos(), track.dir()));
0260 
0261         return !is_init;
0262       }
0263 
0264       // Otherwise, track is on surface: Update the next target
0265       if (navigation.has_next_external() &&
0266           !navigation::update_candidate(
0267               navigation.direction(), navigation.target(), track, det, intr_cfg,
0268               navigation.external_tol(), ctx)) {
0269         navigation.abort("Could not find new target after surface was reached");
0270         return !is_init;
0271       }
0272 
0273       // At this point, the track has to be on surface:
0274       // Set volume index to the volume the current surface is in
0275       navigation.set_volume(navigation.current().surface().volume());
0276 
0277       // Set full trust again: no volume switch needed
0278       navigation.trust_level(navigation::trust_level::e_full);
0279 
0280       DETRAY_VERBOSE_HOST_DEVICE("Update complete (on surface):");
0281       DETRAY_DEBUG_HOST("\n"
0282                         << detray::navigation::print_state(navigation)
0283                         << detray::navigation::print_candidates(
0284                                navigation, cfg, track.pos(), track.dir()));
0285 
0286       // Return true to reset the step size of the RKN algorithm
0287       return is_init;
0288     }
0289 
0290     DETRAY_VERBOSE_HOST_DEVICE(" -> Full trust: Nothing left to do");
0291 
0292     return !is_init;
0293   }
0294 };
0295 
0296 }  // namespace detray