Back to home page

EIC code displayed by LXR

 
 

    


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

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/qualifiers.hpp"
0013 #include "detray/definitions/units.hpp"
0014 #include "detray/geometry/surface.hpp"
0015 #include "detray/geometry/tracking_volume.hpp"
0016 #include "detray/navigation/detail/intersection_kernel.hpp"
0017 #include "detray/navigation/intersection/ray_intersector.hpp"
0018 #include "detray/navigation/navigation_config.hpp"
0019 #include "detray/tracks/ray.hpp"
0020 #include "detray/utils/logging.hpp"
0021 
0022 namespace detray::navigation {
0023 
0024 /// A functor that fills the navigation candidates cache by intersecting
0025 /// a surface in the track position neighbourhood with the tangential to
0026 /// the track direction
0027 struct candidate_search {
0028   /// Visit the volume acceleration data structure(s): Returns a range of
0029   /// surfaces each which is passed to this functor
0030   ///
0031   /// @param sf_descr descriptor of one of the surfaces in the track
0032   ///                 neighbourhood
0033   /// @param det access to the detector
0034   /// @param ctx the geometry context
0035   /// @param track the track parameters
0036   /// @param nav_state state of navigation stream of the track
0037   /// @param mask_tol min. and max. mask tolerance
0038   /// @param mask_tol_scalor scale factor with track distance in range of
0039   ///                        @c mask_tol
0040   /// @param overstep_tol how far behind the track pos to look for
0041   /// candidates
0042   template <typename track_t, typename detector_t, typename navigation_state_t>
0043   DETRAY_HOST_DEVICE constexpr void operator()(
0044       const typename detector_t::surface_type &sf_descr, const detector_t &det,
0045       const typename detector_t::geometry_context &ctx, const track_t &track,
0046       navigation_state_t &nav_state,
0047       const intersection::config &inter_cfg) const {
0048     using algebra_t = typename detector_t::algebra_type;
0049     using scalar_t = dscalar<algebra_t>;
0050 
0051     const auto sf = detray::geometry::surface{det, sf_descr};
0052 
0053     DETRAY_DEBUG_HOST("--> Testing surface:\n" << sf);
0054 
0055     // Tangential to the track direction
0056     detray::detail::ray<algebra_t> tangential{
0057         track.pos(),
0058         static_cast<scalar_t>(nav_state.direction()) * track.dir()};
0059 
0060     // Perform intersection and add result to the navigation cache via
0061     // @c nav_state.insert()
0062     sf.template visit_mask<
0063         detray::detail::intersection_initialize<ray_intersector>>(
0064         nav_state, tangential, sf_descr, det.transform_store(), ctx, inter_cfg,
0065         nav_state.external_tol());
0066   }
0067 
0068   /// Test the volume links
0069   template <typename track_t, typename detector_t, typename navigation_state_t>
0070   DETRAY_HOST_DEVICE void operator()(
0071       const dindex & /*vol_idx*/, const detector_t & /*det*/,
0072       const typename detector_t::geometry_context & /*ctx*/,
0073       const track_t & /*track*/, navigation_state_t & /*nav_state*/,
0074       const intersection::config & /*inter_cfg*/) const {
0075     // Do not search for daughter volumes
0076   }
0077 };
0078 
0079 /// @brief Helper method that updates the intersection of a single candidate
0080 /// and checks reachability
0081 ///
0082 /// @tparam candidate_t type of navigation candidate (intersection result)
0083 /// @tparam track_t type of track, needs to provide pos() and dir() methods
0084 /// @tparam detector_t type of the detector
0085 ///
0086 /// @param nav_dir the navigation direction (forward/backward)
0087 /// @param candidate the candidate intersection to be updated
0088 /// @param track access to the track parameters
0089 /// @param det access to the detector (geometry)
0090 /// @param cfg the navigation configuration
0091 /// @param external_mask_tolerance additional mask tol. given by the caller
0092 /// @param ctx the geometry context
0093 ///
0094 /// @returns @c true if the track can reach this candidate.
0095 template <typename candidate_t, typename track_t, typename detector_t>
0096 DETRAY_HOST_DEVICE DETRAY_INLINE constexpr bool update_candidate(
0097     const navigation::direction nav_dir, candidate_t &candidate,
0098     const track_t &track, const detector_t &det,
0099     const intersection::config &cfg,
0100     const typename detector_t::scalar_type external_mask_tolerance,
0101     const typename detector_t::geometry_context &ctx) {
0102   DETRAY_VERBOSE_HOST_DEVICE("-> Updating target/candidate surface...");
0103 
0104   using algebra_t = typename detector_t::algebra_type;
0105   using scalar_t = dscalar<algebra_t>;
0106 
0107   // Invalid intersection result cannot be updated
0108   if (candidate.surface().identifier().is_invalid()) [[unlikely]] {
0109     return false;
0110   }
0111 
0112   const auto sf = detray::geometry::surface{det, candidate.surface()};
0113 
0114   // Tangential to the track direction
0115   auto tangential{detray::detail::ray<algebra_t>(
0116       track.pos(), static_cast<scalar_t>(nav_dir) * track.dir())};
0117 
0118   // Perform intersection and check whether this candidate is reachable by
0119   // the track
0120   return sf.template visit_mask<
0121       detray::detail::intersection_update<ray_intersector>>(
0122       std::move(tangential), candidate, det.transform_store(), ctx, cfg,
0123       external_mask_tolerance);
0124 }
0125 
0126 /// @returns @c true if the candidate lies on a surface
0127 template <typename candidate_t>
0128 DETRAY_HOST_DEVICE DETRAY_INLINE constexpr bool has_reached_candidate(
0129     const candidate_t &candidate, const navigation::config &cfg) {
0130   return (math::fabs(candidate.path()) < cfg.intersection.path_tolerance);
0131 }
0132 
0133 /// @brief Helper method that re-establishes the navigation status after an
0134 /// update.
0135 ///
0136 /// It checks weather the track has reached a surface or is still moving
0137 /// towards the next surface candidate. If no new next candidate can be
0138 //  found, it flags 'no trust' in order to trigger a volume initialization.
0139 ///
0140 /// @param navigation the current navigation state
0141 /// @param cfg the navigation configuration
0142 template <typename navigation_state_t>
0143 DETRAY_HOST_DEVICE DETRAY_INLINE constexpr void update_status(
0144     navigation_state_t &navigation, const navigation::config &cfg) {
0145   DETRAY_VERBOSE_HOST_DEVICE("-> Updating navigation status...");
0146 
0147   // Check whether the track reached the current candidate. Might be a
0148   // portal, in which case the navigation needs to be re-initialized
0149   if (!navigation.cache_exhausted() &&
0150       navigation::has_reached_candidate(navigation.target(), cfg)) {
0151     navigation.status((navigation.target().surface().is_portal())
0152                           ? navigation::status::e_on_portal
0153                           : navigation::status::e_on_object);
0154     // Set the next object that we want to reach (this function is only
0155     // called once the state has been freshly updated).
0156     // Might lead to exhausted cache!
0157     navigation.advance();
0158   } else {
0159     // Otherwise we are moving towards the target
0160     navigation.status(navigation::status::e_towards_object);
0161   }
0162   // Exhaustion happens when after an update no next candidate in the
0163   // cache is reachable anymore -> triggers init of [new] volume
0164   // Note: In backwards navigation or with strongly bent tracks, the cache may
0165   // not be exhausted when trying to exit the volume (the ray is seeing
0166   // the opposite side of the volume)
0167   navigation.trust_level(navigation.cache_exhausted() ||
0168                                  navigation.is_on_portal()
0169                              ? navigation::trust_level::e_no_trust
0170                              : navigation::trust_level::e_full);
0171 }
0172 
0173 /// @brief Helper method to initialize a navigation state in a given volume.
0174 ///
0175 /// Calls the volumes acceleration structure, then tests the surfaces for
0176 /// intersection and keeps the clostest one(s) ("local navigation" in the
0177 /// volume). The closest candidate is set as 'next candidate' or 'target'.
0178 ///
0179 /// @tparam track_t type of track, needs to provide pos() and dir() methods
0180 /// @tparam navigation_state_t the state type of the navigation stream
0181 /// @tparam context_t the type of geometry context
0182 ///
0183 /// @param track access to the track parameters
0184 /// @param navigation the current navigation state
0185 /// @param cfg the navigation configuration
0186 /// @param ctx the geometry context
0187 template <typename track_t, typename navigation_state_t, typename context_t>
0188 DETRAY_HOST_DEVICE DETRAY_INLINE constexpr void local_navigation(
0189     const track_t &track, navigation_state_t &navigation,
0190     const navigation::config &cfg, const context_t &ctx,
0191     const bool resolve_overstepping = true) {
0192   DETRAY_VERBOSE_HOST_DEVICE("-> (Re-)initialize detector volume (idx: %d)",
0193                              navigation.volume());
0194 
0195   // Do not resurrect a failed/finished navigation state
0196   assert(navigation.is_alive() ||
0197          navigation.status() == navigation::status::e_unknown);
0198   assert(!track.is_invalid());
0199 
0200   const auto &det = navigation.detector();
0201   const auto volume = detray::tracking_volume{det, navigation.volume()};
0202 
0203   // Clean up state
0204   navigation.clear_cache();
0205 
0206   // Overstepping resolution needed? (if not, make sure full tolerance band is
0207   // observed around surface)
0208   intersection::config intr_cfg{cfg.intersection};
0209   intr_cfg.overstep_tolerance = resolve_overstepping
0210                                     ? cfg.intersection.overstep_tolerance
0211                                     : -cfg.intersection.path_tolerance;
0212 
0213   // Search for neighboring surfaces and fill candidates into cache
0214   using volume_t = typename std::remove_cvref_t<decltype(det)>::volume_type;
0215   volume.template visit_neighborhood<volume_t::object_id::e_all,
0216                                      candidate_search>(
0217       track, cfg.search_window, ctx, det, ctx, track, navigation, intr_cfg);
0218 
0219   // Determine overall state of the navigation after updating the cache
0220   navigation::update_status(navigation, cfg);
0221 
0222   // If not successful, the propagation setup might be broken
0223   if (navigation.trust_level() != navigation::trust_level::e_full)
0224       [[unlikely]] {
0225     // Do not exit if backward navigation starts on the outmost portal
0226     if (navigation.is_on_portal()) {
0227       DETRAY_DEBUG_HOST_DEVICE(
0228           "-> Adjust trust lvl for possible \"end-of-world\"...");
0229       navigation.trust_level(
0230           detray::detail::is_invalid_value(navigation.current().volume_link())
0231               ? navigation::trust_level::e_full
0232               : navigation::trust_level::e_no_trust);
0233     } else if (!navigation.is_on_portal()) {
0234       DETRAY_VERBOSE_HOST_DEVICE("-> Unable to initialize state!");
0235     }
0236   }
0237 
0238   navigation.run_inspector(cfg, track.pos(), track.dir(), "Init complete: ");
0239 }
0240 
0241 /// @brief Perform a detector volume switch.
0242 ///
0243 /// Once a portal is reached, this function will update the navigation
0244 /// stream to continue in the new volume. If it is a valid detector volume,
0245 /// the navigation is re-initialized by performing local navigation in the
0246 /// volume. If the end of the detector geometry was reached, the navigation
0247 /// exits.
0248 ///
0249 /// @tparam track_t type of track, needs to provide pos() and dir() methods
0250 /// @tparam navigation_state_t the state type of the navigation stream
0251 /// @tparam context_t the type of geometry context
0252 ///
0253 /// @param track access to the track parameters
0254 /// @param navigation the current navigation state
0255 /// @param cfg the navigation configuration
0256 /// @param ctx the geometry context
0257 template <typename track_t, typename navigation_state_t, typename context_t>
0258 DETRAY_HOST_DEVICE DETRAY_INLINE constexpr void volume_switch(
0259     const track_t &track, navigation_state_t &navigation,
0260     const navigation::config &cfg, const context_t &ctx) {
0261   // Navigation reached the end of the detector world
0262   if (detray::detail::is_invalid_value(navigation.current().volume_link()))
0263       [[unlikely]] {
0264     DETRAY_VERBOSE_HOST_DEVICE("Reached end of detector:");
0265     navigation.exit();
0266     return;
0267   }
0268 
0269   // Set volume index to the next volume provided by the portal
0270   navigation.set_volume(navigation.current().volume_link());
0271   // Check valid volume index
0272   assert(navigation.volume() < navigation.detector().volumes().size());
0273 
0274   // Initialize new volume. Still on portal: No need to observe overstepping
0275   local_navigation(track, navigation, cfg, ctx);
0276 
0277   // Fresh initialization, reset trust even though we are on [inner] portal
0278   navigation.trust_level(navigation::trust_level::e_full);
0279 
0280   DETRAY_VERBOSE_HOST_DEVICE("-> Switched to volume %d", navigation.volume());
0281 }
0282 
0283 /// @brief Initialize the volume with loose configuration.
0284 ///
0285 /// If trust cannot be established and/or no surfaces can be found in the
0286 /// current volume anymore, try to save the navigation stream by looking
0287 /// for candidates further behind the track position.
0288 ///
0289 /// @tparam track_t type of track, needs to provide pos() and dir() methods
0290 /// @tparam navigation_state_t the state type of the navigation stream
0291 /// @tparam context_t the type of geometry context
0292 ///
0293 /// @param track access to the track parameters
0294 /// @param navigation the current navigation state
0295 /// @param loose_cfg the navigation configuration (copy on function stack)
0296 /// @param ctx the geometry context
0297 template <typename track_t, typename navigation_state_t, typename context_t>
0298 DETRAY_HOST_DEVICE DETRAY_INLINE constexpr void init_loose_cfg(
0299     const track_t &track, navigation_state_t &navigation,
0300     navigation::config loose_cfg, const context_t &ctx) {
0301   if (navigation.trust_level() != navigation::trust_level::e_full) {
0302     DETRAY_VERBOSE_HOST_DEVICE("Full trust could not be restored!");
0303   } else if (navigation.cache_exhausted()) {
0304     DETRAY_VERBOSE_HOST_DEVICE("Cache exhausted!");
0305   }
0306   DETRAY_VERBOSE_HOST_DEVICE("RESCURE MODE: Run init with large tolerances");
0307 
0308   // Use the max mask tolerance in case a track leaves the volume
0309   // when a sf is 'sticking' out of the portals due to the tol
0310   const auto new_overstep_tol{
0311       math::min(100.f * loose_cfg.intersection.overstep_tolerance,
0312                 -10.f * loose_cfg.intersection.max_mask_tolerance)};
0313   loose_cfg.intersection.overstep_tolerance = new_overstep_tol;
0314 
0315   constexpr bool resolve_overstepping{true};
0316   local_navigation(track, navigation, loose_cfg, ctx, resolve_overstepping);
0317 
0318   // Unrecoverable
0319   if (navigation.trust_level() != navigation::trust_level::e_full ||
0320       navigation.cache_exhausted()) [[unlikely]] {
0321     navigation.abort("No reachable surfaces");
0322   }
0323 }
0324 
0325 }  // namespace detray::navigation