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/cuboid_portal_generator.hpp"
0013 #include "detray/builders/detector_builder.hpp"
0014 #include "detray/builders/homogeneous_material_builder.hpp"
0015 #include "detray/builders/homogeneous_material_generator.hpp"
0016 #include "detray/builders/homogeneous_volume_material_builder.hpp"
0017 #include "detray/core/detector.hpp"
0018 #include "detray/definitions/algebra.hpp"
0019 #include "detray/definitions/units.hpp"
0020 #include "detray/detectors/telescope_metadata.hpp"
0021 #include "detray/geometry/mask.hpp"
0022 #include "detray/material/predefined_materials.hpp"
0023 #include "detray/tracks/trajectories.hpp"
0024 #include "detray/utils/consistency_checker.hpp"
0025 #include "detray/utils/print_detector.hpp"
0026 
0027 // Detray test include(s)
0028 #include "detray/test/common/factories/telescope_generator.hpp"
0029 
0030 // Vecmem include(s)
0031 #include <vecmem/memory/memory_resource.hpp>
0032 
0033 // System include(s)
0034 #include <algorithm>
0035 #include <limits>
0036 #include <memory>
0037 #include <vector>
0038 
0039 namespace detray {
0040 
0041 /// Configure the toy detector
0042 template <concepts::algebra algebra_t, typename mask_shape_t = rectangle2D,
0043           template <typename> class trajectory_t = detail::ray>
0044 struct tel_det_config {
0045   using scalar_t = dscalar<algebra_t>;
0046 
0047   /// Construct from existing mask
0048   explicit tel_det_config(const mask<mask_shape_t, algebra_t> &m,
0049                           const trajectory_t<algebra_t> &t = {})
0050       : m_mask(m), m_trajectory(t) {
0051     // Configure the material generation
0052     m_material_config.sensitive_material(silicon_tml<scalar_t>())
0053         .passive_material(vacuum<scalar_t>())
0054         .portal_material(vacuum<scalar_t>())
0055         .thickness(80.f * unit<scalar_t>::um);
0056   }
0057 
0058   /// Construct from from mask parameter vector
0059   explicit tel_det_config(const std::vector<scalar_t> &params,
0060                           const trajectory_t<algebra_t> &t = {})
0061       : tel_det_config(mask<mask_shape_t, algebra_t>{params, 0u}, t) {}
0062 
0063   /// Construct from mask parameters (except volume link, which is not needed)
0064   template <typename... Args>
0065     requires(std::is_same_v<Args, scalar_t> && ...)
0066   explicit tel_det_config(Args &&...args)
0067       : tel_det_config(
0068             mask<mask_shape_t, algebra_t>{0u, std::forward<Args>(args)...}) {}
0069 
0070   /// Mask of the test surfaces
0071   mask<mask_shape_t, algebra_t> m_mask;
0072   /// No. of test surfaces in the telescope
0073   unsigned int m_n_surfaces{10u};
0074   /// Length of the telescope
0075   scalar_t m_length{500.f * unit<scalar_t>::mm};
0076   /// Concrete positions where to place the surfaces along the pilot track
0077   std::vector<scalar_t> m_positions{};
0078   /// Configuration for the homogeneous material generator
0079   hom_material_config<scalar_t> m_material_config{};
0080   /// Material for volume
0081   material<scalar_t> m_volume_material = vacuum<scalar_t>();
0082   /// Pilot track along which to place the surfaces
0083   trajectory_t<algebra_t> m_trajectory{};
0084   /// Safety envelope between the test surfaces and the portals
0085   scalar_t m_envelope{0.1f * unit<scalar_t>::mm};
0086   /// Run detector consistency check after reading
0087   bool m_do_check{true};
0088 
0089   /// Setters
0090   /// @{
0091   constexpr tel_det_config &module_mask(
0092       const mask<mask_shape_t, algebra_t> &m) {
0093     m_mask = m;
0094     return *this;
0095   }
0096   constexpr tel_det_config &n_surfaces(const unsigned int n) {
0097     m_n_surfaces = n;
0098     return *this;
0099   }
0100   constexpr tel_det_config &length(const scalar_t l) {
0101     assert((l > 0.f) && "Telescope detector length must be greater than zero");
0102     m_length = l;
0103     return *this;
0104   }
0105   constexpr tel_det_config &positions(const std::vector<scalar_t> &dists) {
0106     m_positions.clear();
0107     std::ranges::copy_if(dists, std::back_inserter(m_positions),
0108                          [](scalar_t d) { return (d >= 0.f); });
0109     return *this;
0110   }
0111   constexpr tel_det_config &module_material(const material<scalar_t> &mat) {
0112     m_material_config.sensitive_material(mat);
0113     return *this;
0114   }
0115   constexpr tel_det_config &volume_material(const material<scalar_t> &mat) {
0116     m_volume_material = mat;
0117     return *this;
0118   }
0119   constexpr tel_det_config &mat_thickness(const scalar_t t) {
0120     assert(t >= 0.f && "Material thickness must be non-negative");
0121     m_material_config.thickness(t);
0122     return *this;
0123   }
0124   constexpr tel_det_config &pilot_track(const trajectory_t<algebra_t> &traj) {
0125     m_trajectory = traj;
0126     return *this;
0127   }
0128   constexpr tel_det_config &envelope(const scalar_t e) {
0129     assert(e > 0.f && "Portal envelope must be greater than zero");
0130     m_envelope = e;
0131     return *this;
0132   }
0133   tel_det_config &do_check(const bool check) {
0134     m_do_check = check;
0135     return *this;
0136   }
0137   /// @}
0138 
0139   /// Getters
0140   /// @{
0141   constexpr const mask<mask_shape_t, algebra_t> &module_mask() const {
0142     return m_mask;
0143   }
0144   constexpr unsigned int n_surfaces() const { return m_n_surfaces; }
0145   constexpr scalar_t length() const { return m_length; }
0146   const std::vector<scalar_t> &positions() const { return m_positions; }
0147   constexpr const auto &material_config() const { return m_material_config; }
0148   constexpr auto &material_config() { return m_material_config; }
0149   constexpr const material<scalar_t> &module_material() const {
0150     return m_material_config.sensitive_material();
0151   }
0152   constexpr const material<scalar_t> &volume_material() const {
0153     return m_volume_material;
0154   }
0155   constexpr scalar_t mat_thickness() const {
0156     return m_material_config.thickness();
0157   }
0158   const trajectory_t<algebra_t> &pilot_track() const { return m_trajectory; }
0159   constexpr scalar_t envelope() const { return m_envelope; }
0160   bool do_check() const { return m_do_check; }
0161   /// @}
0162 };
0163 
0164 /// Deduce the type of telescope config
0165 template <concepts::algebra algebra_t, typename shape_t,
0166           template <typename> class trajectory_t>
0167 DETRAY_HOST_DEVICE tel_det_config(const mask<shape_t, algebra_t> &,
0168                                   const trajectory_t<algebra_t> &)
0169     -> tel_det_config<algebra_t, shape_t, trajectory_t>;
0170 
0171 /// Builds a detray geometry that contains only one volume with one type of
0172 /// surfaces. The detector is auto-constructed by following a trajectory
0173 /// through space, along which the surfaces are placed. The portals are built
0174 /// from the bounding box around the sensors.
0175 ///
0176 /// @tparam mask_shape_t the type of mask for the telescope surfaces
0177 /// @tparam trajectory_t the type of the pilot trajectory (ray/helix)
0178 ///
0179 /// @param resource the memory resource for the detector containers
0180 /// @param cfg configuration struct of the telescope detector
0181 ///
0182 /// @returns a complete detector object
0183 template <concepts::algebra algebra_t, typename mask_shape_t = rectangle2D,
0184           template <typename> class trajectory_t = detail::ray>
0185 inline auto build_telescope_detector(
0186     vecmem::memory_resource &resource,
0187     const tel_det_config<algebra_t, mask_shape_t, trajectory_t> &cfg =
0188         tel_det_config<algebra_t, mask_shape_t, trajectory_t>{
0189             20.f * unit<dscalar<algebra_t>>::mm,
0190             20.f * unit<dscalar<algebra_t>>::mm}) {
0191   using scalar_t = dscalar<algebra_t>;
0192   using metadata_t = telescope_metadata<algebra_t, mask_shape_t>;
0193   using builder_t = detector_builder<metadata_t, volume_builder>;
0194   using detector_t = typename builder_t::detector_type;
0195 
0196   builder_t det_builder;
0197   det_builder.set_name("telescope_detector");
0198 
0199   // Create an empty cuboid volume
0200   auto v_builder = det_builder.new_volume(volume_id::e_cuboid);
0201   v_builder->set_name("telescope_world_0");
0202 
0203   // Identity transform (volume is centered at origin)
0204   v_builder->add_volume_placement();
0205 
0206   // Add module surfaces to volume
0207   using telescope_factory =
0208       telescope_generator<detector_t, mask_shape_t, trajectory_t<algebra_t>>;
0209   std::unique_ptr<surface_factory_interface<detector_t>> tel_generator;
0210 
0211   if (cfg.positions().empty()) {
0212     // Automatically position the modules along pilot track
0213     tel_generator = std::make_unique<telescope_factory>(
0214         cfg.length(), cfg.n_surfaces(), cfg.module_mask().values(),
0215         cfg.pilot_track());
0216   } else {
0217     // Put the modules in the requested portions along pilot track
0218     tel_generator = std::make_unique<telescope_factory>(
0219         cfg.positions(), cfg.module_mask().values(), cfg.pilot_track());
0220   }
0221 
0222   // Add homogeneous material description if a valid material was configured
0223   volume_builder_interface<detector_t> *vm_builder{v_builder};
0224   std::shared_ptr<surface_factory_interface<detector_t>> module_generator;
0225 
0226   if (cfg.module_material() != detray::vacuum<scalar_t>{}) {
0227     // Decorate the builders with homogeneous material
0228     vm_builder =
0229         det_builder.template decorate<homogeneous_material_builder<detector_t>>(
0230             v_builder);
0231 
0232     if (!vm_builder) {
0233       throw std::runtime_error("Surface material decoration failed");
0234     }
0235 
0236     auto tel_mat_generator =
0237         std::make_shared<homogeneous_material_generator<detector_t>>(
0238             std::move(tel_generator), cfg.material_config());
0239 
0240     module_generator = std::move(tel_mat_generator);
0241 
0242   } else {
0243     module_generator = std::move(tel_generator);
0244   }
0245 
0246   // Add a bounding box of portals to the cuboid volume
0247   auto portal_generator =
0248       std::make_shared<cuboid_portal_generator<detector_t>>(cfg.envelope());
0249 
0250   vm_builder->add_surfaces(module_generator);
0251   // (!) The portals must be added after the modules to fit them correctly
0252   vm_builder->add_surfaces(portal_generator);
0253 
0254   // TODO: Add brute force volume searcher
0255 
0256   // If requested, add homogeneous volume material
0257   if (cfg.volume_material() != detray::vacuum<scalar_t>{}) {
0258     auto full_v_builder =
0259         det_builder
0260             .template decorate<homogeneous_volume_material_builder<detector_t>>(
0261                 vm_builder);
0262 
0263     if (full_v_builder) {
0264       full_v_builder->set_material(cfg.volume_material());
0265     } else {
0266       throw std::runtime_error("Volume material decoration failed");
0267     }
0268   }
0269 
0270   // Build and return the detector and fill the name map
0271   typename detector_t::name_map name_map{};
0272   auto det = det_builder.build(resource, name_map);
0273 
0274   if (cfg.do_check()) {
0275     const bool verbose_check{false};
0276     detray::detail::check_consistency(det, verbose_check, name_map);
0277   }
0278 
0279   DETRAY_DEBUG_HOST("\n" << detray::utils::print_detector(det, name_map));
0280 
0281   return std::make_pair(std::move(det), std::move(name_map));
0282 }
0283 
0284 }  // namespace detray