Back to home page

EIC code displayed by LXR

 
 

    


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

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/builders/surface_factory_interface.hpp"
0013 #include "detray/core/detail/data_context.hpp"
0014 #include "detray/definitions/detail/qualifiers.hpp"
0015 #include "detray/definitions/geometry.hpp"
0016 #include "detray/definitions/indexing.hpp"
0017 #include "detray/geometry/mask.hpp"
0018 #include "detray/geometry/shapes/rectangle2D.hpp"
0019 #include "detray/tracks/ray.hpp"
0020 #include "detray/utils/axis_rotation.hpp"
0021 #include "detray/utils/logging.hpp"
0022 #include "detray/utils/unit_vectors.hpp"
0023 
0024 // System include(s)
0025 #include <cassert>
0026 #include <limits>
0027 
0028 namespace detray {
0029 
0030 /// @brief Generates a number of surfaces along a given direction
0031 ///
0032 /// @tparam detector_t the type of detector the volume belongs to.
0033 template <typename detector_t, typename mask_shape_t = rectangle2D,
0034           typename trajectory_t =
0035               detail::ray<typename detector_t::algebra_type>>
0036 class telescope_generator final : public surface_factory_interface<detector_t> {
0037   using algebra_t = typename detector_t::algebra_type;
0038   using scalar_t = dscalar<algebra_t>;
0039   using transform3_t = dtransform3D<algebra_t>;
0040   using point3_t = dpoint3D<algebra_t>;
0041   using vector3_t = dvector3D<algebra_t>;
0042 
0043  public:
0044   /// Build a surface at with extent given in @param boundaries at every
0045   /// position in @param positions along the pilot-track @param traj.
0046   DETRAY_HOST
0047   telescope_generator(
0048       std::vector<scalar_t> positions,
0049       const darray<scalar_t, mask_shape_t::boundaries::e_size> &boundaries,
0050       trajectory_t traj)
0051       : m_traj{traj},
0052         m_positions{std::move(positions)},
0053         m_boundaries{boundaries} {}
0054 
0055   /// Infer the sensitive surface placement from the telescope @param length
0056   /// if no concrete positions were given.
0057   /// @param n_surfaces number of surfaces to be generated
0058   /// @param boundaries mask boundaries of the surfaces
0059   /// @param traj pilot track along which to build the telescope
0060   DETRAY_HOST
0061   telescope_generator(
0062       scalar_t length, std::size_t n_surfaces,
0063       darray<scalar_t, mask_shape_t::boundaries::e_size> boundaries,
0064       trajectory_t traj)
0065       : m_traj{traj}, m_positions{}, m_boundaries{boundaries} {
0066     scalar_t pos{0.f};
0067     scalar_t dist{n_surfaces > 1u
0068                       ? length / static_cast<scalar_t>(n_surfaces - 1u)
0069                       : 0.f};
0070     for (std::size_t i = 0u; i < n_surfaces; ++i) {
0071       m_positions.push_back(pos);
0072       pos += dist;
0073     }
0074   }
0075 
0076   /// @returns the number of surfaces this factory will produce
0077   DETRAY_HOST
0078   auto size() const -> dindex override {
0079     return static_cast<dindex>(m_positions.size());
0080   }
0081 
0082   /// Clear the positions and boundaries of the surfaces.
0083   DETRAY_HOST
0084   void clear() override {
0085     m_positions.clear();
0086     m_boundaries = {};
0087   };
0088 
0089   /// This is a surface generator, no external surface data needed
0090   /// @{
0091   DETRAY_HOST
0092   void push_back(
0093       surface_data<detector_t> && /*unused*/) override { /*Do nothing*/ }
0094   DETRAY_HOST
0095   auto push_back(std::vector<surface_data<detector_t>> && /*unused*/)
0096       -> void override { /*Do nothing*/ }
0097   /// @}
0098 
0099   /// Create a surface telescope.
0100   ///
0101   /// @param volume the volume the portals need to be added to.
0102   /// @param surfaces the surface collection to wrap and to add the portals to
0103   /// @param transforms the transforms of the surfaces.
0104   /// @param masks the masks of the surfaces.
0105   /// @param ctx the geometry context (not needed for portals).
0106   DETRAY_HOST
0107   auto operator()(typename detector_t::volume_type &volume,
0108                   typename detector_t::surface_lookup_container &surfaces,
0109                   typename detector_t::transform_container &transforms,
0110                   typename detector_t::mask_container &masks,
0111                   typename detector_t::geometry_context ctx = {})
0112       -> dindex_range override {
0113     DETRAY_VERBOSE_HOST("Generate telescope modules...");
0114     DETRAY_VERBOSE_HOST("-> Generate " << size() << " surfaces");
0115 
0116     using surface_t = typename detector_t::surface_type;
0117     using nav_link_t = typename surface_t::navigation_link;
0118     using mask_link_t = typename surface_t::mask_link;
0119     using material_link_t = typename surface_t::material_link;
0120 
0121     const dindex surfaces_offset{static_cast<dindex>(surfaces.size())};
0122     constexpr auto invalid_src_link{detail::invalid_value<std::uint64_t>()};
0123 
0124     // The type id of the surface mask shape
0125     constexpr auto mask_id{
0126         types::id<typename detector_t::masks, mask<mask_shape_t, algebra_t>>};
0127 
0128     // The material will be added in a later step
0129     constexpr auto no_material{surface_t::material_id::e_none};
0130 
0131     auto volume_idx{volume.index()};
0132 
0133     // Create the module centers
0134     const auto mod_placements = module_positions(m_traj, m_positions);
0135 
0136     // Create geometry data
0137     for (const auto &mod_placement : mod_placements) {
0138       auto mask_volume_link{static_cast<nav_link_t>(volume_idx)};
0139 
0140       // Surfaces with the linking into the local containers
0141       mask_link_t mask_link{mask_id, masks.template size<mask_id>()};
0142       material_link_t material_link{no_material, dindex_invalid};
0143 
0144       const auto trf_index = transforms.size(ctx);
0145       surfaces.push_back({trf_index, mask_link, material_link, volume_idx,
0146                           surface_id::e_sensitive},
0147                          invalid_src_link);
0148 
0149       // The rectangle bounds for this module
0150       masks.template emplace_back<mask_id>(empty_context{}, m_boundaries,
0151                                            mask_volume_link);
0152 
0153       // Build the transform
0154       // Local z axis is the global normal vector
0155       vector3_t m_local_z = vector::normalize(mod_placement.dir);
0156 
0157       if constexpr (std::is_same_v<mask_shape_t, detray::line_square> ||
0158                     std::is_same_v<mask_shape_t, detray::line_circular>) {
0159         // For a telescope with wires, rotate z axis 90
0160         // degree around vector on x-y plane
0161         auto curvi_u =
0162             unit_vectors<vector3_t>().make_curvilinear_unit_u(m_local_z);
0163         axis_rotation<algebra_t> axis_rot(curvi_u,
0164                                           -constant<scalar_t>::pi / 2.f);
0165         m_local_z = axis_rot(m_local_z);
0166       }
0167 
0168       // Local x axis is the curvilinear vector with respect to local_z
0169       auto m_local_x =
0170           unit_vectors<vector3_t>().make_curvilinear_unit_u(m_local_z);
0171 
0172       // Create the global-to-local transform of the module
0173       transforms.emplace_back(ctx, mod_placement.pos, m_local_z, m_local_x);
0174     }
0175 
0176     return {surfaces_offset, static_cast<dindex>(surfaces.size())};
0177   }
0178 
0179  private:
0180   /// Where and how to place the telescope modules.
0181   struct module_placement {
0182     /// Module position
0183     point3_t pos;
0184     /// Module normal
0185     vector3_t dir;
0186   };
0187 
0188   /// Helper method for positioning the surfaces.
0189   ///
0190   /// @param traj pilot trajectory along which the modules should be placed.
0191   /// @param steps lengths along the trajectory where surfaces should be
0192   ///              placed.
0193   ///
0194   /// @return a vector of the @c module_placements along the trajectory.
0195   inline std::vector<module_placement> module_positions(
0196       const trajectory_t &traj, const std::vector<scalar_t> &steps) const {
0197     // create and fill the module placements
0198     std::vector<module_placement> placements;
0199     placements.reserve(steps.size());
0200 
0201     for (const auto s : steps) {
0202       placements.push_back({traj.pos(s), traj.dir(s)});
0203     }
0204 
0205     return placements;
0206   }
0207 
0208   /// "pilot-track" along which to place the surfaces
0209   trajectory_t m_traj;
0210   /// Positions of the surfaces in the telescope along the pilot track
0211   std::vector<scalar_t> m_positions;
0212   /// The boundary values for the surface mask
0213   darray<scalar_t, mask_shape_t::boundaries::e_size> m_boundaries;
0214 };
0215 
0216 }  // namespace detray