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/algebra.hpp"
0013 #include "detray/definitions/detail/qualifiers.hpp"
0014 #include "detray/definitions/indexing.hpp"
0015 #include "detray/definitions/math.hpp"
0016 #include "detray/definitions/units.hpp"
0017 #include "detray/utils/invalid_values.hpp"
0018 
0019 // System include(s)
0020 #include <cstdint>
0021 #include <limits>
0022 #include <ostream>
0023 
0024 namespace detray {
0025 
0026 namespace intersection {
0027 
0028 /// Whether the intersector result will contain the local position
0029 inline constexpr bool contains_pos{true};
0030 
0031 /// Intersection status
0032 enum class status : std::uint_least8_t {
0033   e_inside = 0u,   ///< Inside the mask within numeric uncertainty
0034   e_edge = 1u,     ///< Inside the mask's external tolerance band
0035   e_outside = 2u,  ///< Outside of mask (including all tolerances)
0036 };
0037 
0038 }  // namespace intersection
0039 
0040 /// Result of intersector: Point of intersection on a surface
0041 template <concepts::algebra algebra_t, concepts::point point_t,
0042           bool has_pos = true>
0043 struct intersection_point {};
0044 
0045 /// Result of intersector: Only contains the distance (production)
0046 template <concepts::algebra algebra_t, concepts::point point_t>
0047 struct intersection_point<algebra_t, point_t, !intersection::contains_pos> {
0048   using scalar_type = dscalar<algebra_t>;
0049 
0050   /// @returns true if debug information needs to be filled
0051   static consteval bool contains_pos() { return !intersection::contains_pos; }
0052 
0053   /// Distance between track position and surface along test trajectory
0054   scalar_type path = detail::invalid_value<dvalue<algebra_t>>();
0055 
0056   /// @returns true if the data represents a valid intersection solution
0057   constexpr bool is_valid() const {
0058     constexpr auto inv_path{10.f * unit<dvalue<algebra_t>>::m};
0059     return detray::detail::any_of(math::fabs(path) < inv_path);
0060   }
0061 
0062   /// Transform to a string for output debugging
0063   DETRAY_HOST
0064   friend std::ostream &operator<<(std::ostream &out_stream,
0065                                   const intersection_point &ip) {
0066     out_stream << "dist:" << ip.path;
0067 
0068     return out_stream;
0069   }
0070 };
0071 
0072 /// Result of intersector: Distance and intersection point (debug)
0073 template <concepts::algebra algebra_t, concepts::point point_t>
0074 struct intersection_point<algebra_t, point_t, intersection::contains_pos>
0075     : public intersection_point<algebra_t, point_t,
0076                                 !intersection::contains_pos> {
0077  private:
0078   using base_type =
0079       intersection_point<algebra_t, point_t, !intersection::contains_pos>;
0080 
0081  public:
0082   using scalar_type = dscalar<algebra_t>;
0083   using point_type = point_t;
0084 
0085   constexpr intersection_point() = default;
0086 
0087   DETRAY_HOST_DEVICE
0088   explicit constexpr intersection_point(const base_type ip) : base_type{ip} {}
0089 
0090   DETRAY_HOST_DEVICE
0091   constexpr intersection_point(const scalar_type p, const point_type &pnt)
0092       : base_type{p}, point{pnt} {}
0093 
0094   /// @returns true if debug information needs to be filled
0095   static consteval bool contains_pos() { return intersection::contains_pos; }
0096 
0097   /// Local position of the intersection on the surface
0098   point_type point{init_point()};
0099 
0100   /// Transform to a string for output debugging
0101   DETRAY_HOST
0102   friend std::ostream &operator<<(std::ostream &out_stream,
0103                                   const intersection_point &ip) {
0104     using base_t =
0105         intersection_point<algebra_t, point_t, !intersection::contains_pos>;
0106 
0107     out_stream << static_cast<base_t>(ip);
0108 
0109     out_stream << ", point [" << ip.point[0] << ", " << ip.point[1];
0110 
0111     if constexpr (std::same_as<point_t, dpoint3D<algebra_t>>) {
0112       out_stream << ", " << ip.point[2] << "]";
0113     } else {
0114       out_stream << "]";
0115     }
0116 
0117     return out_stream;
0118   }
0119 
0120  private:
0121   /// Initialize points of different dimensionality correctly
0122   DETRAY_HOST_DEVICE
0123   constexpr point_t init_point() const {
0124     constexpr auto inv{detail::invalid_value<dvalue<algebra_t>>()};
0125     if constexpr (std::same_as<point_t, dpoint2D<algebra_t>>) {
0126       return {inv, inv};
0127     } else if constexpr (std::same_as<point_t, dpoint3D<algebra_t>>) {
0128       return {inv, inv, inv};
0129     } else {
0130       assert(false);
0131       return {};
0132     }
0133   }
0134 };
0135 
0136 /// Result of intersector: Distance, intersection point (2D or 3D,
0137 /// local/global) and error estimate on distance (for mask resolution)
0138 template <concepts::algebra algebra_t>
0139 struct intersection_point_err
0140     : public intersection_point<algebra_t, dpoint3D<algebra_t>,
0141                                 intersection::contains_pos> {
0142  private:
0143   using base_type = intersection_point<algebra_t, dpoint3D<algebra_t>,
0144                                        intersection::contains_pos>;
0145 
0146   static constexpr auto inv{detail::invalid_value<dscalar<algebra_t>>()};
0147 
0148  public:
0149   using scalar_type = dscalar<algebra_t>;
0150   using point3_type = dpoint3D<algebra_t>;
0151   using point2_type = dpoint2D<algebra_t>;
0152   using point_type = point3_type;
0153 
0154   constexpr intersection_point_err() = default;
0155 
0156   DETRAY_HOST_DEVICE
0157   explicit constexpr intersection_point_err(const base_type &base_ip)
0158       : base_type{base_ip} {}
0159 
0160   DETRAY_HOST_DEVICE
0161   explicit constexpr intersection_point_err(
0162       const intersection_point<algebra_t, point3_type,
0163                                !intersection::contains_pos> &ip)
0164       : base_type{ip.path, point3_type{inv, inv, inv}} {}
0165 
0166   DETRAY_HOST_DEVICE
0167   explicit constexpr intersection_point_err(
0168       const intersection_point<algebra_t, point2_type,
0169                                !intersection::contains_pos> &ip)
0170       : base_type{ip.path, point3_type{inv, inv, inv}} {}
0171 
0172   DETRAY_HOST_DEVICE
0173   constexpr intersection_point_err(const scalar_type p, const point3_type &pnt,
0174                                    const scalar_type p_err)
0175       : base_type{p, pnt}, path_err{p_err} {}
0176 
0177   /// Error estimation on the path
0178   scalar_type path_err{inv};
0179 };
0180 
0181 /// @brief This class holds the intersection information.
0182 ///
0183 /// @tparam surface_t is the type of surface descriptor
0184 /// @tparam algebra_t linear algebra and memory layout
0185 /// @tparam has_pos whether the local position is saved or not
0186 template <typename surface_t, concepts::algebra algebra_t,
0187           bool has_pos = intersection::contains_pos>
0188 class intersection2D {
0189   using T = dvalue<algebra_t>;
0190   using bool_type = dbool<algebra_t>;
0191   using scalar_type = dscalar<algebra_t>;
0192   using point2_type = dpoint2D<algebra_t>;
0193   using point3_type = dpoint3D<algebra_t>;
0194   using vector3_type = dvector3D<algebra_t>;
0195 
0196  public:
0197   using algebra_type = algebra_t;
0198   using surface_type = surface_t;
0199   // This is needed for the SIMD implementation, where the boolean type that
0200   // results from the mask tolerance check has to match the SIMD vector type
0201   // on which it is used on for a masked assignment of the different status
0202   // codes
0203   using status_type =
0204       std::conditional_t<concepts::soa<algebra_t>, T, intersection::status>;
0205   using nav_link_type = typename surface_type::navigation_link;
0206 
0207   /// Default constructor
0208   constexpr intersection2D() = default;
0209 
0210   /// Fully parametrized constructor - contains local position
0211   template <bool B = has_pos>
0212     requires B
0213   DETRAY_HOST_DEVICE constexpr intersection2D(
0214       const surface_type &sf, const scalar_type path, const point3_type &local,
0215       const nav_link_type nl, const dsimd<algebra_t, status_type> status,
0216       const bool_type dir)
0217       : m_surface{sf},
0218         m_ip{path, local},
0219         m_volume_link{nl},
0220         m_status{status},
0221         m_direction{dir} {}
0222 
0223   /// Fully parametrized constructor - contains no local position
0224   template <bool B = has_pos>
0225     requires(!B)
0226   DETRAY_HOST_DEVICE constexpr intersection2D(
0227       const surface_type &sf, const scalar_type path, const nav_link_type nl,
0228       const dsimd<algebra_t, status_type> status, const bool_type dir)
0229       : m_surface{sf},
0230         m_ip{path},
0231         m_volume_link{nl},
0232         m_status{status},
0233         m_direction{dir} {}
0234 
0235   /// @returns true if debug information needs to be filled
0236   static consteval bool contains_pos() { return has_pos; }
0237 
0238   /// @returns the intersected surface
0239   DETRAY_HOST_DEVICE
0240   constexpr surface_type surface() const { return m_surface; }
0241 
0242   /// @returns the intersected surface - non-const
0243   DETRAY_HOST_DEVICE
0244   constexpr surface_type &surface() { return m_surface; }
0245 
0246   /// Set the surface for this intersection to @param sf
0247   DETRAY_HOST_DEVICE
0248   constexpr void set_surface(const surface_type sf) { m_surface = sf; }
0249 
0250   /// @returns the link to the target volume to the navigator
0251   DETRAY_HOST_DEVICE
0252   constexpr nav_link_type volume_link() const { return m_volume_link; }
0253 
0254   /// Set the volume link to @param nl
0255   DETRAY_HOST_DEVICE
0256   constexpr void set_volume_link(const nav_link_type nl) { m_volume_link = nl; }
0257 
0258   /// @returns the direction of the intersection (before or behind the track)
0259   DETRAY_HOST_DEVICE
0260   constexpr bool_type is_along() const { return m_direction; }
0261 
0262   /// Set the direction to @param dir
0263   DETRAY_HOST_DEVICE
0264   constexpr void set_direction(const bool_type dir) { m_direction = dir; }
0265 
0266   /// @returns the distance of to the intersection point along the test traj.
0267   DETRAY_HOST_DEVICE
0268   constexpr scalar_type path() const { return m_ip.path; }
0269 
0270   /// Set the path to @param p
0271   DETRAY_HOST_DEVICE
0272   constexpr void set_path(scalar_type p) { m_ip.path = p; }
0273 
0274   /// @returns the local 3D intersection point (only debug)
0275   template <bool B = has_pos>
0276     requires B
0277   DETRAY_HOST_DEVICE constexpr point3_type local() const {
0278     return m_ip.point;
0279   }
0280 
0281   /// Set the intersection position to @param p
0282   template <bool B = has_pos>
0283     requires B
0284   DETRAY_HOST_DEVICE constexpr void set_local(const point3_type p) {
0285     m_ip.point = p;
0286   }
0287 
0288   /// @returns the intersection status
0289   DETRAY_HOST_DEVICE
0290   constexpr dsimd<algebra_t, status_type> status() const { return m_status; }
0291 
0292   /// Set the intersection status according to enum value @param s
0293   DETRAY_HOST_DEVICE
0294   constexpr void set_status(intersection::status s) {
0295     m_status = static_cast<status_type>(s);
0296   }
0297 
0298   /// Set the intersection status according to enum value @param s
0299   DETRAY_HOST_DEVICE
0300   constexpr void set_status_if(intersection::status s,
0301                                dbool<algebra_t> result_mask) {
0302     // @TODO find a unified conditional assignment in algebra_plugins
0303     if constexpr (concepts::soa<algebra_t>) {
0304       m_status(result_mask) = static_cast<status_type>(s);
0305     } else {
0306       m_status = result_mask ? static_cast<status_type>(s) : m_status;
0307     }
0308   }
0309 
0310   /// @note: Three way comparison cannot be used easily with SoA boolean masks
0311   /// @{
0312   /// @param rhs is the right hand side intersection for comparison
0313   DETRAY_HOST_DEVICE
0314   friend constexpr bool_type operator<(const intersection2D &lhs,
0315                                        const intersection2D &rhs) noexcept {
0316     return (math::fabs(lhs.path()) < math::fabs(rhs.path()));
0317   }
0318 
0319   /// @param rhs is the right hand side intersection for comparison
0320   DETRAY_HOST_DEVICE
0321   friend constexpr bool_type operator<=(const intersection2D &lhs,
0322                                         const intersection2D &rhs) noexcept {
0323     return (math::fabs(lhs.path()) <= math::fabs(rhs.path()));
0324   }
0325 
0326   /// @param rhs is the left hand side intersection for comparison
0327   DETRAY_HOST_DEVICE
0328   friend constexpr bool_type operator>(const intersection2D &lhs,
0329                                        const intersection2D &rhs) noexcept {
0330     return (math::fabs(lhs.path()) > math::fabs(rhs.path()));
0331   }
0332 
0333   /// @param rhs is the left hand side intersection for comparison
0334   DETRAY_HOST_DEVICE
0335   friend constexpr bool_type operator>=(const intersection2D &lhs,
0336                                         const intersection2D &rhs) noexcept {
0337     return (math::fabs(lhs.path()) > math::fabs(rhs.path()));
0338   }
0339   /// @}
0340 
0341   /// @param rhs is the left hand side intersection for comparison
0342   DETRAY_HOST_DEVICE
0343   friend constexpr bool_type operator==(const intersection2D &lhs,
0344                                         const intersection2D &rhs) noexcept {
0345     return math::fabs(lhs.path() - rhs.path()) <
0346            std::numeric_limits<float>::epsilon();
0347   }
0348 
0349   /// @returns true if any of the intersection results is 'inside'
0350   DETRAY_HOST_DEVICE
0351   constexpr bool is_inside() const {
0352     const dsimd<algebra_t, status_type> comp(
0353         static_cast<status_type>(intersection::status::e_inside));
0354     return detail::any_of(this->m_status == comp);
0355   }
0356 
0357   /// @returns true if any of the intersection results is 'edge'
0358   DETRAY_HOST_DEVICE
0359   constexpr bool is_edge() const {
0360     const dsimd<algebra_t, status_type> comp(
0361         static_cast<status_type>(intersection::status::e_edge));
0362     return detail::any_of(this->m_status == comp);
0363   }
0364 
0365   /// @returns true if any of the intersection results is 'inside' or 'edge'
0366   DETRAY_HOST_DEVICE
0367   constexpr bool is_probably_inside() const {
0368     const dsimd<algebra_t, status_type> comp(
0369         static_cast<status_type>(intersection::status::e_edge));
0370     return detail::any_of(this->m_status <= comp);
0371   }
0372 
0373   /// @returns true if all of the intersection results are 'outside'
0374   DETRAY_HOST_DEVICE
0375   constexpr bool is_outside() const {
0376     const dsimd<algebra_t, status_type> comp(
0377         static_cast<status_type>(intersection::status::e_outside));
0378     return detail::all_of(this->m_status == comp);
0379   }
0380 
0381  private:
0382   /// Transform to a string for output debugging
0383   DETRAY_HOST
0384   friend std::ostream &operator<<(std::ostream &out_stream,
0385                                   const intersection2D &is) {
0386     out_stream << is.m_ip << ", "
0387                << ", surface: " << is.surface().identifier()
0388                << ", type: " << static_cast<int>(is.surface().mask().id())
0389                << ", links to vol:" << is.volume_link() << ")";
0390 
0391     if (is.is_inside()) {
0392       out_stream << ", status: inside";
0393     } else if (is.is_edge()) {
0394       out_stream << ", status: edge";
0395     } else {
0396       out_stream << ", status: outside";
0397     }
0398     if constexpr (std::is_scalar_v<bool_type>) {
0399       out_stream << (is.is_along() ? ", direction: along"
0400                                    : ", direction: opposite");
0401     } else {
0402       out_stream << ", status: " << is.status();
0403       out_stream << ", direction: " << is.is_along();
0404     }
0405 
0406     return out_stream;
0407   }
0408 
0409   /// Descriptor of the surface this intersection belongs to
0410   surface_type m_surface{};
0411 
0412   /// The intersection point (only saves the local point in debug mode)
0413   intersection_point<algebra_type, dpoint3D<algebra_type>, has_pos> m_ip{};
0414 
0415   /// Navigation information (next volume to go to)
0416   nav_link_type m_volume_link{detail::invalid_value<nav_link_type>()};
0417 
0418   /// Result of the intersection
0419   dsimd<algebra_t, status_type> m_status =
0420       static_cast<status_type>(intersection::status::e_outside);
0421 
0422   /// Direction of the intersection with respect to the track (true = along,
0423   /// false = opposite)
0424   bool_type m_direction{true};
0425 };
0426 
0427 }  // namespace detray