Back to home page

EIC code displayed by LXR

 
 

    


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

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/geometry.hpp"
0014 #include "detray/definitions/indexing.hpp"
0015 
0016 // System include(s)
0017 #include <ostream>
0018 #include <utility>
0019 
0020 namespace detray {
0021 
0022 /// @brief The detray detector volume descriptor.
0023 ///
0024 /// Contains the data and links to describe a detector volume. This is the type
0025 /// that is stored in the detector data stores.
0026 ///
0027 /// @tparam ID enum of object types contained in the volume
0028 ///         (@see @c default_metadata ).
0029 /// @tparam link_t the type of link to the volumes surfaces finder(s)
0030 ///         (accelerator structure, e.g. a grid). The surface finder types
0031 ///         cannot be given directly, since the containers differ between host
0032 ///         and device. The surface finders reside in an 'unrollable tuple
0033 ///         container' and are called per volume in the navigator during local
0034 ///         navigation.
0035 template <typename ID, typename acc_link_t = dtyped_index<dindex, dindex>,
0036           typename mat_link_t = dtyped_index<dindex, dindex>>
0037 class volume_descriptor {
0038  public:
0039   /// Ids of objects that can be distinguished by the volume
0040   using object_id = ID;
0041 
0042   /// How to access the surface ranges in the detector surface lookup
0043   using sf_link_type =
0044       dmulti_index<dindex_range,
0045                    static_cast<std::size_t>(
0046                        static_cast<std::underlying_type_t<surface_id>>(
0047                            surface_id::e_all))>;
0048 
0049   /// How to access objects (e.g. sensitives/passives/portals) in this
0050   /// volume. Keeps one accelerator structure link per object type (by ID):
0051   ///
0052   /// acc_link_t : id and index of the accelerator structure in the detector's
0053   ///          surface store.
0054   ///
0055   /// E.g. a 'portal' can be found under @c ID::e_portal in this link,
0056   /// and will then receive link to the @c brute_force acceleration structure
0057   /// that holds the portals (the accelerator structure's id and index).
0058   using accel_link_type = dmulti_index<acc_link_t, ID::e_size>;
0059 
0060   /// How to link to the volume material, if any
0061   using material_link = mat_link_t;
0062   using material_id = typename material_link::id_type;
0063 
0064   /// Default constructor builds an ~infinitely long cylinder
0065   constexpr volume_descriptor() = default;
0066 
0067   /// Constructor from shape id.
0068   ///
0069   /// @param id id values that determines how to interpret the bounds.
0070   explicit constexpr volume_descriptor(const volume_id id) : m_id{id} {}
0071 
0072   /// @returns true if the object ID corresponds to a surface
0073   static consteval bool is_surface_id(const object_id id) {
0074     return (id == object_id::e_portal || id == object_id::e_sensitive ||
0075             id == object_id::e_passive);
0076   }
0077 
0078   /// @returns true if the object ID corresponds to a [daughter] volume
0079   static consteval bool is_volume_id(const object_id id) {
0080     return (id == object_id::e_volume);
0081   }
0082 
0083   /// @returns the volume shape id, e.g. 'cylinder'
0084   DETRAY_HOST_DEVICE
0085   constexpr auto id() const -> volume_id { return m_id; }
0086 
0087   /// @returns the index of the volume in the detector volume container.
0088   DETRAY_HOST_DEVICE
0089   constexpr auto index() const -> dindex { return m_index; }
0090 
0091   /// @param index the index of the volume in the detector volume container.
0092   DETRAY_HOST
0093   constexpr auto set_index(const dindex index) -> void { m_index = index; }
0094 
0095   /// @returns the index of the volume transform in the transform store.
0096   DETRAY_HOST_DEVICE
0097   constexpr auto transform() const -> dindex { return m_transform; }
0098 
0099   /// @param index the index of the volume in the detector volume container.
0100   DETRAY_HOST
0101   constexpr auto set_transform(const dindex trf_idx) -> void {
0102     m_transform = trf_idx;
0103   }
0104 
0105   /// @returns surface link for all object types - const
0106   DETRAY_HOST_DEVICE constexpr auto sf_link() const -> const sf_link_type& {
0107     return m_sf_links;
0108   }
0109 
0110   /// @returns surface descriptor link for a specific type of object - const
0111   template <surface_id id>
0112   DETRAY_HOST_DEVICE constexpr auto sf_link() const -> const
0113       typename sf_link_type::index_type& {
0114     return detail::get<static_cast<uint>(id)>(m_sf_links);
0115   }
0116 
0117   /// @returns surface descriptor link for a specific type of object
0118   template <surface_id id>
0119   DETRAY_HOST_DEVICE constexpr auto sf_link() ->
0120       typename sf_link_type::index_type& {
0121     return detail::get<static_cast<uint>(id)>(m_sf_links);
0122   }
0123 
0124   /// @returns surface descriptor link for all surface types
0125   DETRAY_HOST_DEVICE constexpr auto full_sf_range() const ->
0126       typename sf_link_type::index_type {
0127     using idx_range_t = typename sf_link_type::index_type;
0128 
0129     const auto& pt_range = sf_link<surface_id::e_portal>();
0130     const auto& sen_range = sf_link<surface_id::e_sensitive>();
0131     const auto& psv_range = sf_link<surface_id::e_passive>();
0132 
0133     // Portal range is never empty
0134     dindex min{detail::get<0>(pt_range)};
0135     dindex max{detail::get<1>(pt_range)};
0136 
0137     constexpr idx_range_t empty{};
0138     if (sen_range != empty) {
0139       min = detail::get<0>(sen_range) < min ? detail::get<0>(sen_range) : min;
0140       max = detail::get<1>(sen_range) > max ? detail::get<1>(sen_range) : max;
0141     }
0142 
0143     if (psv_range != empty) {
0144       min = detail::get<0>(psv_range) < min ? detail::get<0>(psv_range) : min;
0145       max = detail::get<1>(psv_range) > max ? detail::get<1>(psv_range) : max;
0146     }
0147 
0148     return idx_range_t{min, max};
0149   }
0150 
0151   /// @returns the total number of surfaces contained in the volume
0152   DETRAY_HOST_DEVICE constexpr dindex n_surfaces() const {
0153     const auto sf_idx_range = full_sf_range();
0154 
0155     assert(sf_idx_range[1] > sf_idx_range[0]);
0156     return sf_idx_range[1] - sf_idx_range[0];
0157   }
0158 
0159   /// @returns a surface index with respect to the volume surface range
0160   DETRAY_HOST_DEVICE constexpr dindex to_local_sf_index(dindex sf_idx) const {
0161     auto full_range = full_sf_range();
0162 
0163     assert(full_range[0] <= sf_idx);
0164     assert(sf_idx < full_range[1]);
0165 
0166     return sf_idx - full_range[0];
0167   }
0168 
0169   /// @returns a surface index with respect to the global detector containers
0170   DETRAY_HOST_DEVICE constexpr dindex to_global_sf_index(dindex sf_idx) const {
0171     auto full_range = full_sf_range();
0172     dindex glob_index{sf_idx + full_range[0]};
0173 
0174     assert(full_range[0] <= glob_index);
0175     assert(glob_index < full_range[1]);
0176 
0177     return glob_index;
0178   }
0179 
0180   /// Set or update the index into a geometry container identified by the
0181   /// obj_id.
0182   ///
0183   /// @note There is no check of overlapping index ranges between the object
0184   /// types. Use with care!
0185   ///
0186   /// @param other Surface index range
0187   template <surface_id id>
0188   DETRAY_HOST auto update_sf_link(
0189       const typename sf_link_type::index_type& other) noexcept -> void {
0190     auto& rg = sf_link<id>();
0191     // Range not set yet - initialize
0192     if (constexpr typename sf_link_type::index_type empty{}; rg == empty) {
0193       rg = other;
0194     } else {
0195       // Update upper border
0196       assert(detail::get<1>(rg) == detail::get<0>(other));
0197       rg.set_upper(other.upper());
0198     }
0199   }
0200 
0201   /// Set or update the index into a geometry container identified by the
0202   /// obj_id.
0203   ///
0204   /// @note There is no check of overlapping index ranges between the object
0205   /// types. Use with care!
0206   ///
0207   /// @param shift shift of the surface range in a larger container.
0208   /// @param n_surfaces the number of surfaces in this range.
0209   template <surface_id id>
0210   DETRAY_HOST auto update_sf_link(std::size_t shift,
0211                                   std::size_t n_surfaces = 0) noexcept -> void {
0212     auto& rg = sf_link<id>();
0213     // Range not set yet - initialize
0214     if (constexpr typename sf_link_type::index_type empty{}; rg == empty) {
0215       rg = {0u, static_cast<dindex>(n_surfaces)};
0216     }
0217     // Update
0218     rg.shift(static_cast<dindex>(shift));
0219   }
0220 
0221   /// @returns the volume material link
0222   DETRAY_HOST_DEVICE
0223   constexpr auto material() const -> const material_link& { return m_mat_link; }
0224 
0225   /// Set the volume material link to @param mat_link
0226   DETRAY_HOST
0227   constexpr auto set_material(const material_link& mat_link) -> void {
0228     m_mat_link = mat_link;
0229   }
0230 
0231   /// Set the volume material link using the given material type id
0232   /// @param mat_id and index of the material instance @param mat_idx
0233   DETRAY_HOST
0234   constexpr auto set_material(const material_id mat_id, const dindex mat_idx)
0235       -> void {
0236     m_mat_link = {mat_id,
0237                   static_cast<typename material_link::index_type>(mat_idx)};
0238   }
0239 
0240   /// @returns true if the volume descriptor has a valid material link
0241   DETRAY_HOST_DEVICE
0242   constexpr auto has_material() const -> bool {
0243     return (m_mat_link.id() != material_link::id_type::e_none) &&
0244            !m_mat_link.is_invalid();
0245   }
0246 
0247   /// @returns link to all acceleration data structures - const access
0248   DETRAY_HOST_DEVICE constexpr auto accel_link() const
0249       -> const accel_link_type& {
0250     return m_accel_links;
0251   }
0252 
0253   /// @returns acc data structure link for a specific type of object - const
0254   /// version with runtime indexing
0255   DETRAY_HOST_DEVICE constexpr auto accel_link(const ID& id) const
0256       -> const acc_link_t& {
0257     static_assert(static_cast<std::size_t>(ID::e_size) >= 1);
0258     assert(static_cast<std::size_t>(id) < static_cast<std::size_t>(ID::e_size));
0259     return accel_link_helper<static_cast<ID>(
0260         static_cast<std::size_t>(ID::e_size) - 1)>(id);
0261   }
0262 
0263   /// @returns acc data structure link for a specific type of object - const
0264   template <ID obj_id>
0265   DETRAY_HOST_DEVICE constexpr auto accel_link() const -> const acc_link_t& {
0266     return detail::get<obj_id>(m_accel_links);
0267   }
0268 
0269   /// Set surface finder link from @param link
0270   template <ID obj_id>
0271   DETRAY_HOST constexpr auto set_accel_link(const acc_link_t link) -> void {
0272     detail::get<obj_id>(m_accel_links) = link;
0273   }
0274 
0275   /// Set link from @param id and @param index of the acceleration data
0276   /// structure (e.g. type and index of a grid in the accelerator store)
0277   template <ID obj_id>
0278   DETRAY_HOST constexpr auto set_accel_link(
0279       const typename acc_link_t::id_type id,
0280       const typename acc_link_t::index_type index) -> void {
0281     detail::get<obj_id>(m_accel_links) = acc_link_t{id, index};
0282   }
0283 
0284   /// Set link for a type of surfaces ( @param obj_id ) from @param id
0285   /// and @param index of the acceleration data structure (e.g. type and
0286   /// index of a grid in the accelerator store)
0287   DETRAY_HOST constexpr auto set_accel_link(
0288       const ID obj_id, const typename acc_link_t::id_type accel_id,
0289       const typename acc_link_t::index_type index) -> void {
0290     m_accel_links[obj_id] = acc_link_t{accel_id, index};
0291   }
0292 
0293   /// Equality operator
0294   ///
0295   /// @param rhs is the right-hand side to compare against.
0296   DETRAY_HOST_DEVICE
0297   constexpr auto operator==(const volume_descriptor& rhs) const -> bool {
0298     return (m_id == rhs.m_id && m_index == rhs.m_index &&
0299             m_accel_links == rhs.m_accel_links);
0300   }
0301 
0302   /// @returns a string stream that prints the volume details
0303   DETRAY_HOST
0304   friend std::ostream& operator<<(std::ostream& os,
0305                                   const volume_descriptor& v_desc) {
0306     os << "id = " << v_desc.id() << "(" << static_cast<int>(v_desc.id()) << ")";
0307     os << " | index = " << v_desc.index();
0308     os << " | trf. = " << v_desc.transform();
0309     os << " | acc link: " << v_desc.accel_link();
0310     os << " | sf link: " << v_desc.sf_link();
0311     os << " | mat link: " << v_desc.material();
0312     return os;
0313   }
0314 
0315  private:
0316   /// @returns acc data structure link for a specific type of object - const
0317   /// version with compile-time indexing
0318   template <ID obj_id>
0319   DETRAY_HOST_DEVICE constexpr auto accel_link_helper(const ID& id) const
0320       -> const acc_link_t& {
0321     if (id == obj_id) {
0322       return accel_link<obj_id>();
0323     } else if constexpr (static_cast<std::size_t>(obj_id) > 0) {
0324       return accel_link_helper<static_cast<ID>(
0325           static_cast<std::size_t>(obj_id) - 1)>(id);
0326     } else {
0327       __builtin_unreachable();
0328     }
0329   }
0330 
0331   /// How to interpret the boundary values
0332   volume_id m_id{volume_id::e_unknown};
0333 
0334   /// Volume index in the detector's volume container
0335   dindex m_index{dindex_invalid};
0336 
0337   /// Volume index in the detector's volume container
0338   dindex m_transform{dindex_invalid};
0339 
0340   /// Index range for every object type
0341   sf_link_type m_sf_links{};
0342 
0343   /// Volume material link
0344   material_link m_mat_link = {};
0345 
0346   /// Links for every object type to an acceleration data structure
0347   accel_link_type m_accel_links{};
0348 };
0349 
0350 }  // namespace detray