Back to home page

EIC code displayed by LXR

 
 

    


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

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/algebra.hpp"
0013 #include "detray/definitions/detail/qualifiers.hpp"
0014 #include "detray/definitions/geometry.hpp"
0015 #include "detray/geometry/mask.hpp"
0016 #include "detray/geometry/shapes/line.hpp"
0017 #include "detray/geometry/tracking_volume.hpp"
0018 #include "detray/navigation/caching_navigator.hpp"
0019 #include "detray/navigation/intersection/ray_intersector.hpp"
0020 #include "detray/propagator/base_actor.hpp"
0021 #include "detray/propagator/constrained_step.hpp"
0022 #include "detray/tracks/ray.hpp"
0023 #include "detray/utils/curvilinear_frame.hpp"
0024 
0025 namespace detray {
0026 
0027 /// Actor that exits from a navigation stream, if it has reached the perigee
0028 /// @Note Currently only works with step constraints (will be changed in the
0029 /// future)
0030 template <concepts::algebra algebra_t>
0031 struct perigee_stopper : public base_actor {
0032   using scalar_t = dscalar<algebra_t>;
0033 
0034   struct state {
0035     /// Radius around the beamline, where to test against the perigee
0036     /// Outside this radius, the track is considered as not originating
0037     /// from the IP
0038     scalar_t m_stopping_radius{10.f * unit<scalar_t>::mm};
0039     /// Tolerance under which to consider the track at the perigee
0040     // @TODO Make smaller once overstepping is solved
0041     scalar_t m_on_perigee_tol{100.f * unit<scalar_t>::um};
0042     /// Index of the innermost volume for this detector: Convention is 0
0043     unsigned int m_inner_vol_idx{0u};
0044   };
0045 
0046   /// Intersects a linear track approximation with the perigee and exits
0047   /// the navigation, if the perigee is reached.
0048   ///
0049   /// @param prop_state state of the propagation
0050   template <typename propagator_state_t>
0051   DETRAY_HOST_DEVICE void operator()(state &actor_state,
0052                                      propagator_state_t &prop_state) const {
0053     using detector_t = typename propagator_state_t::detector_type;
0054     using perigee_intersector_t = ray_intersector<line_circular, algebra_t>;
0055 
0056     // Nothing left to do. Propagation will exit successfully on its own
0057     auto &navigation = prop_state.navigation();
0058     if (navigation.finished()) {
0059       return;
0060     }
0061 
0062     // Only check this in the innermost volume and during backward nav.
0063     if (navigation.volume() != actor_state.m_inner_vol_idx ||
0064         navigation.direction() != navigation::direction::e_backward) {
0065       return;
0066     }
0067 
0068     // Volume that contains the IP
0069     const tracking_volume inner_vol{navigation.detector(),
0070                                     actor_state.m_inner_vol_idx};
0071 
0072     // Stop at the perigee (cylindrical detectors only)
0073     if (inner_vol.id() != volume_id::e_cylinder) {
0074       return;
0075     }
0076 
0077     // At least the exit portal should be reachable
0078     if (navigation.cache_exhausted()) {
0079       prop_state._heartbeat =
0080           prop_state._heartbeat &&
0081           navigation.abort("Pergigee stopper has no next candidate");
0082       return;
0083     }
0084 
0085     auto &stepping = prop_state.stepping();
0086     auto &track = stepping();
0087 
0088     // Linear track approximation
0089     const detail::ray<algebra_t> trk_approx{track.pos(), -1.f * track.dir()};
0090 
0091     // Check the stopping radius (outside the track will not be stopped)
0092     assert(actor_state.m_stopping_radius > 0.f);
0093     constexpr scalar_t max_hz{detail::invalid_value<scalar_t>()};
0094 
0095     const mask<line_circular, algebra_t> perigee_mask{
0096         actor_state.m_inner_vol_idx, actor_state.m_stopping_radius, max_hz};
0097 
0098     // The perigee is not linked to any detector surface
0099     constexpr typename detector_t::surface_type inv_sf{};
0100     const dtransform3D<algebra_t> identity{};
0101     constexpr scalar_t mask_tolerance{0.f};
0102     constexpr scalar_t overstep_tolerance{-detail::invalid_value<scalar_t>()};
0103 
0104     const auto perigee_intr =
0105         perigee_intersector_t{}(trk_approx, inv_sf, perigee_mask, identity,
0106                                 mask_tolerance, overstep_tolerance);
0107 
0108     scalar_t dist_to_cand{std::as_const(navigation).target().path()};
0109     if (perigee_intr.is_probably_inside() &&
0110         math::fabs(perigee_intr.path()) < math::fabs(dist_to_cand)) {
0111       assert(actor_state.m_on_perigee_tol > 0.f);
0112 
0113       // The track has reached the perigee: "exit success"
0114       if (math::fabs(perigee_intr.path()) <= actor_state.m_on_perigee_tol) {
0115         prop_state._heartbeat = prop_state._heartbeat && navigation.exit();
0116       } else {
0117         // @TODO: Use a guided navigator for this in order to catch
0118         // overstepping correctly
0119         stepping.template set_constraint<step::constraint::e_actor>(
0120             perigee_intr.path());
0121       }
0122     }
0123   }
0124 };
0125 
0126 }  // namespace detray