Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-27 07:23:58

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/containers.hpp"
0014 #include "detray/definitions/detail/qualifiers.hpp"
0015 #include "detray/definitions/indexing.hpp"
0016 #include "detray/definitions/math.hpp"
0017 #include "detray/definitions/units.hpp"
0018 #include "detray/geometry/coordinates/cartesian3D.hpp"
0019 #include "detray/geometry/coordinates/line2D.hpp"
0020 #include "detray/geometry/detail/shape_utils.hpp"
0021 
0022 // System include(s)
0023 #include <limits>
0024 #include <ostream>
0025 #include <string_view>
0026 #include <type_traits>
0027 
0028 namespace detray {
0029 
0030 /// @brief Geometrical shape of a line surface.
0031 ///
0032 /// @tparam kSquareCrossSect determines whether the line has a cricular or
0033 ///         square cross section. This also changes the local coord. frame.m
0034 ///
0035 /// The line can either have a circular or a square cross section. In the first
0036 /// case bounds[0] refers to the radius, while in the second case it is the
0037 /// half length of the square. The second boundary bounds[1] is the half length
0038 /// in z.
0039 template <bool kSquareCrossSect = false>
0040 class line {
0041  public:
0042   /// The name for this shape
0043   static constexpr std::string_view name = "line";
0044 
0045   /// Geometrical cross section of the line
0046   static constexpr bool square_cross_sect = kSquareCrossSect;
0047 
0048   enum boundaries : unsigned int {
0049     e_cross_section = 0u,
0050     e_half_z = 1u,
0051     e_size = 2u
0052   };
0053 
0054   /// Container definition for the shape boundary values
0055   template <concepts::scalar scalar_t>
0056   using bounds_type = darray<scalar_t, boundaries::e_size>;
0057 
0058   /// Local coordinate frame for boundary checks
0059   template <concepts::algebra algebra_t>
0060   using local_frame_type = line2D<algebra_t>;
0061 
0062   /// Result type of a boundary check
0063   template <typename bool_t>
0064   using result_type = detail::boundary_check_result<bool_t>;
0065 
0066   /// Dimension of the local coordinate system
0067   static constexpr std::size_t dim{2u};
0068 
0069   /// @brief Find the minimum distance to any boundary.
0070   ///
0071   /// @note the point is expected to be given in local coordinates by the
0072   /// caller.
0073   ///
0074   /// @param bounds the boundary values for this shape
0075   /// @param loc_p the point to be checked in the local coordinate system
0076   ///
0077   /// @return the minimum distance.
0078   template <concepts::scalar scalar_t, concepts::point point_t>
0079   DETRAY_HOST_DEVICE inline scalar_t min_dist_to_boundary(
0080       const bounds_type<scalar_t> &bounds, const point_t &loc_p) const {
0081     if constexpr (square_cross_sect) {
0082       const scalar_t dist_x = math::fabs(
0083           math::fabs(loc_p[0] * math::cos(loc_p[2])) - bounds[e_cross_section]);
0084       const scalar_t dist_y = math::fabs(
0085           math::fabs(loc_p[0] * math::sin(loc_p[2])) - bounds[e_cross_section]);
0086       const scalar_t dist_z =
0087           math::fabs(math::fabs(loc_p[1]) - bounds[e_half_z]);
0088 
0089       return math::min(math::min(dist_x, dist_y), dist_z);
0090 
0091     } else {
0092       return math::min(
0093           math::fabs(math::fabs(loc_p[0]) - bounds[e_cross_section]),
0094           math::fabs(math::fabs(loc_p[1]) - bounds[e_half_z]));
0095     }
0096   }
0097 
0098   /// @brief Check boundary values for a local point.
0099   /// @{
0100   /// @param bounds the boundary values for this shape
0101   /// @param trf the surface transform
0102   /// @param glob_p the point to be checked in the global coordinate system
0103   /// @param tol dynamic tolerance determined by caller
0104   ///
0105   /// @return true if the local point lies within the given boundaries.
0106   template <concepts::algebra algebra_t>
0107   DETRAY_HOST_DEVICE constexpr result_type<dbool<algebra_t>> check_boundaries(
0108       const bounds_type<dscalar<algebra_t>> &bounds,
0109       const dtransform3D<algebra_t> &trf, const dpoint3D<algebra_t> &glob_p,
0110       const dscalar<algebra_t> tol =
0111           std::numeric_limits<dscalar<algebra_t>>::epsilon(),
0112       const dscalar<algebra_t> edge_tol = 0.f) const {
0113     const auto loc_3D{cartesian3D<algebra_t>::global_to_local(trf, glob_p, {})};
0114 
0115     if constexpr (square_cross_sect) {
0116       using scalar_t = dscalar<algebra_t>;
0117 
0118       const scalar_t loc_0{math::fabs(loc_3D[0])};
0119       const scalar_t loc_1{math::fabs(loc_3D[1])};
0120       const scalar_t loc_2{math::fabs(loc_3D[2])};
0121 
0122       // Check in local cartesian coordinates instead of line coordinates
0123       auto inside_mask{(loc_0 <= (bounds[e_cross_section] + tol) &&
0124                         loc_1 <= (bounds[e_cross_section] + tol) &&
0125                         loc_2 <= (bounds[e_half_z] + tol))};
0126 
0127       decltype(inside_mask) inside_edge{false};
0128       if (detail::any_of(edge_tol > 0.f)) {
0129         const scalar_t full_tol{tol + edge_tol};
0130 
0131         inside_edge = (loc_0 <= (bounds[e_cross_section] + full_tol) &&
0132                        loc_1 <= (bounds[e_cross_section] + full_tol) &&
0133                        loc_2 <= (bounds[e_half_z] + full_tol));
0134       }
0135 
0136       return result_type<dbool<algebra_t>>{inside_mask, inside_edge};
0137     } else {
0138       // Check in local 2D line coordinates (sign not needed)
0139       return check_boundaries(
0140           bounds, dpoint2D<algebra_t>{vector::perp(loc_3D), loc_3D[2]}, tol,
0141           edge_tol);
0142     }
0143   }
0144 
0145   /// @note the point is expected to be given in local coordinates by the
0146   /// caller. For the conversion from global cartesian coordinates, the
0147   /// nested @c shape struct can be used. The point is assumed to be in
0148   /// the cylinder 2D frame (sgn * r, z, phi) or (sgn * r, z), the latter only
0149   /// works for the circular cross section line shape.
0150   ///
0151   /// @param bounds the boundary values for this shape
0152   /// @param loc_p the point to be checked in the local coordinate system
0153   /// @param tol dynamic tolerance determined by caller
0154   ///
0155   /// @return true if the local point lies within the given boundaries.
0156   template <concepts::scalar scalar_t, concepts::point point_t>
0157   DETRAY_HOST_DEVICE constexpr auto check_boundaries(
0158       const bounds_type<scalar_t> &bounds, const point_t &loc_p,
0159       const scalar_t tol = std::numeric_limits<scalar_t>::epsilon(),
0160       const scalar_t edge_tol = 0.f) const {
0161     // For a square cross section (e.g. a cell of drift chamber), we check
0162     // if (1) x and y of the local cart. point is less than the half cell
0163     // size and (2) the distance to the point of closest approach on the
0164     // line from the line center is less than the half line length
0165     if constexpr (square_cross_sect) {
0166       const scalar_t loc_0{math::fabs(loc_p[0] * math::cos(loc_p[2]))};
0167       const scalar_t loc_1{math::fabs(loc_p[0] * math::sin(loc_p[2]))};
0168       const scalar_t loc_2{math::fabs(loc_p[1])};
0169 
0170       auto inside_mask{(loc_0 <= (bounds[e_cross_section] + tol) &&
0171                         loc_1 <= (bounds[e_cross_section] + tol) &&
0172                         loc_2 <= bounds[e_half_z] + tol)};
0173 
0174       decltype(inside_mask) inside_edge{false};
0175       if (detail::any_of(edge_tol > 0.f)) {
0176         const scalar_t full_tol{tol + edge_tol};
0177 
0178         inside_edge = (loc_0 <= (bounds[e_cross_section] + full_tol) &&
0179                        loc_1 <= (bounds[e_cross_section] + full_tol) &&
0180                        loc_2 <= bounds[e_half_z] + full_tol);
0181       }
0182 
0183       return result_type<decltype(inside_mask)>{inside_mask, inside_edge};
0184     }
0185     // For a circular cross section (e.g. straw tube), we check if (1) the
0186     // radial distance is within the scope and (2) the distance to the point
0187     // of closest approach on the line from the line center is less than the
0188     // line half length
0189     else {
0190       const scalar_t loc_0{math::fabs(loc_p[0])};
0191       const scalar_t loc_1{math::fabs(loc_p[1])};
0192 
0193       auto inside_mask{(loc_0 <= (bounds[e_cross_section] + tol) &&
0194                         loc_1 <= (bounds[e_half_z] + tol))};
0195 
0196       decltype(inside_mask) inside_edge{false};
0197       if (detail::any_of(edge_tol > 0.f)) {
0198         const scalar_t full_tol{tol + edge_tol};
0199 
0200         inside_edge = (loc_0 <= (bounds[e_cross_section] + full_tol) &&
0201                        loc_1 <= (bounds[e_half_z] + full_tol));
0202       }
0203 
0204       return result_type<decltype(inside_mask)>{inside_mask, inside_edge};
0205     }
0206   }
0207   /// @}
0208 
0209   /// @brief Measure of the shape: Volume
0210   ///
0211   /// @param bounds the boundary values for this shape
0212   ///
0213   /// @returns the line volume.
0214   template <concepts::scalar scalar_t>
0215   DETRAY_HOST_DEVICE constexpr scalar_t measure(
0216       const bounds_type<scalar_t> &bounds) const {
0217     if constexpr (square_cross_sect) {
0218       return 8.f * bounds[e_half_z] * bounds[e_cross_section] *
0219              bounds[e_cross_section];
0220     } else {
0221       return constant<scalar_t>::pi * 2.f * bounds[e_half_z] *
0222              bounds[e_cross_section] * bounds[e_cross_section];
0223     }
0224   }
0225 
0226   /// @brief The area of a the shape
0227   ///
0228   /// @param bounds the boundary values for this shape
0229   ///
0230   /// @returns the stereo annulus area.
0231   template <concepts::scalar scalar_t>
0232   DETRAY_HOST_DEVICE constexpr scalar_t area(
0233       const bounds_type<scalar_t> &bounds) const {
0234     if constexpr (square_cross_sect) {
0235       return 16.f * bounds[e_half_z] * bounds[e_cross_section];
0236     } else {
0237       return 4.f * constant<scalar_t>::pi * bounds[e_cross_section] *
0238              bounds[e_half_z];
0239     }
0240   }
0241 
0242   /// @brief Merge two line shapes
0243   ///
0244   /// @param bounds the boundary values for this shape
0245   /// @param o_bounds the boundary values for the other shape
0246   ///
0247   /// @returns merged bound values
0248   template <concepts::scalar scalar_t>
0249   DETRAY_HOST_DEVICE constexpr bounds_type<scalar_t> merge(
0250       const bounds_type<scalar_t> &bounds,
0251       const bounds_type<scalar_t> &o_bounds) const {
0252     bounds_type<scalar_t> new_bounds{};
0253 
0254     new_bounds[e_cross_section] =
0255         math::max(bounds[e_cross_section], o_bounds[e_cross_section]);
0256     new_bounds[e_half_z] = math::max(bounds[e_half_z], o_bounds[e_half_z]);
0257 
0258     return new_bounds;
0259   }
0260 
0261   /// @brief Lower and upper point for minimal axis aligned bounding box.
0262   ///
0263   /// Computes the min and max vertices in a local cartesian frame.
0264   ///
0265   /// @param bounds the boundary values for this shape
0266   /// @param env dynamic envelope around the shape
0267   ///
0268   /// @returns and array of coordinates that contains the lower point (first
0269   /// three values) and the upper point (latter three values) .
0270   template <concepts::algebra algebra_t>
0271   DETRAY_HOST_DEVICE inline darray<dscalar<algebra_t>, 6> local_min_bounds(
0272       const bounds_type<dscalar<algebra_t>> &bounds,
0273       const dscalar<algebra_t> env =
0274           std::numeric_limits<dscalar<algebra_t>>::epsilon()) const {
0275     using scalar_t = dscalar<algebra_t>;
0276 
0277     assert(env > 0.f);
0278     const scalar_t xy_bound{bounds[e_cross_section] + env};
0279     const scalar_t z_bound{bounds[e_half_z] + env};
0280 
0281     return {-xy_bound, -xy_bound, -z_bound, xy_bound, xy_bound, z_bound};
0282   }
0283 
0284   /// @returns the shapes centroid in local cartesian coordinates
0285   template <concepts::algebra algebra_t>
0286   DETRAY_HOST_DEVICE dpoint3D<algebra_t> centroid(
0287       const bounds_type<dscalar<algebra_t>> & /*unused*/) const {
0288     return {0.f, 0.f, 0.f};
0289   }
0290 
0291   /// Generate vertices in local cartesian frame
0292   ///
0293   /// @param bounds the boundary values for the line
0294   /// @param n_seg is the number of line segments
0295   ///
0296   /// @return a generated list of vertices
0297   template <concepts::algebra algebra_t>
0298   DETRAY_HOST dvector<dpoint3D<algebra_t>> vertices(
0299       const bounds_type<dscalar<algebra_t>> &bounds, dindex /*ignored*/) const {
0300     using point3_t = dpoint3D<algebra_t>;
0301 
0302     point3_t lc = {0.f, 0.f, -bounds[e_half_z]};
0303     point3_t rc = {0.f, 0.f, bounds[e_half_z]};
0304 
0305     return {lc, rc};
0306   }
0307 
0308   /// @brief Check consistency of boundary values.
0309   ///
0310   /// @param bounds the boundary values for this shape
0311   /// @param os output stream for error messages
0312   ///
0313   /// @return true if the bounds are consistent.
0314   template <concepts::scalar scalar_t>
0315   DETRAY_HOST constexpr bool check_consistency(
0316       const bounds_type<scalar_t> &bounds, std::ostream &os) const {
0317     constexpr auto tol{10.f * std::numeric_limits<scalar_t>::epsilon()};
0318 
0319     if (bounds[e_cross_section] < tol) {
0320       os << "DETRAY ERROR (HOST): Radius/sides must be in the range (0, "
0321             "numeric_max)"
0322          << std::endl;
0323       return false;
0324     }
0325     if (bounds[e_half_z] < tol) {
0326       os << "DETRAY ERROR (HOST): Half length z must be in the range (0, "
0327             "numeric_max)"
0328          << std::endl;
0329       return false;
0330     }
0331 
0332     return true;
0333   }
0334 };
0335 
0336 // Radial crossection, boundary check in polar coordinates
0337 using line_circular = line<false>;
0338 // Square crossection, boundary check in cartesian coordinates
0339 using line_square = line<true>;
0340 
0341 }  // namespace detray