Back to home page

EIC code displayed by LXR

 
 

    


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

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/indexing.hpp"
0016 #include "detray/geometry/mask.hpp"
0017 #include "detray/geometry/shapes/unmasked.hpp"
0018 #include "detray/material/material_rod.hpp"
0019 #include "detray/material/material_slab.hpp"
0020 #include "detray/utils/logging.hpp"
0021 #include "detray/utils/ranges.hpp"
0022 #include "detray/utils/type_registry.hpp"
0023 
0024 // System include(s)
0025 #include <algorithm>
0026 #include <cassert>
0027 #include <concepts>
0028 #include <exception>
0029 #include <memory>
0030 #include <type_traits>
0031 #include <vector>
0032 
0033 namespace detray {
0034 
0035 /// @brief Generates a number of surfaces for a volume (can be portals, passives
0036 /// or sensitives) and fills them into the containers of a volume builder.
0037 ///
0038 /// @tparam detector_t the type of detector the volume belongs to.
0039 /// @tparam mask_shape_t the shape of the surface.
0040 template <typename detector_t, typename mask_shape_t>
0041 class surface_factory : public surface_factory_interface<detector_t> {
0042   using algebra_t = typename detector_t::algebra_type;
0043   using volume_link_t = typename detector_t::surface_type::navigation_link;
0044   using scalar_t = dscalar<algebra_t>;
0045 
0046   // Set individual volume link for portals, but only the mother volume index
0047   // for other surfaces. The container holds one volume link per portal for
0048   // all surfaces
0049   using volume_link_collection = std::vector<std::vector<volume_link_t>>;
0050 
0051  public:
0052   using detector_type = detector_t;
0053 
0054   /// shorthad for a collection of surface data that can be read by a surface
0055   /// factory
0056   using surface_data_t = surface_data<detector_t>;
0057   using sf_data_collection = std::vector<surface_data_t>;
0058 
0059   /// Empty factory.
0060   surface_factory() = default;
0061 
0062   /// @returns the current number of surfaces that will be built by this
0063   /// factory
0064   DETRAY_HOST
0065   auto size() const -> dindex override {
0066     check();
0067     return static_cast<dindex>(m_bounds.size());
0068   }
0069 
0070   /// @returns the surface types
0071   DETRAY_HOST
0072   auto types() const -> const std::vector<surface_id> & { return m_types; }
0073 
0074   /// @returns the mask boundaries currently held by the factory
0075   DETRAY_HOST
0076   auto bounds() const
0077       -> const std::vector<std::vector<std::vector<scalar_t>>> & {
0078     return m_bounds;
0079   }
0080 
0081   /// @returns the transforms currently held by the factory
0082   DETRAY_HOST
0083   auto transforms() const
0084       -> const std::vector<typename detector_t::transform3_type> & {
0085     return m_transforms;
0086   }
0087 
0088   /// @returns the volume link(s) currently held by the factory
0089   DETRAY_HOST
0090   const auto &volume_links() const { return m_volume_links; }
0091 
0092   /// Add all necessary components to the factory for a single surface
0093   DETRAY_HOST
0094   void push_back(surface_data_t &&sf_data) override {
0095     auto [type, vlinks, index, source, bounds, trf] =
0096         std::move(sf_data).get_data();
0097 
0098     assert(bounds.front().size() == mask_shape_t::boundaries::e_size);
0099 
0100     m_types.push_back(type);
0101     m_volume_links.push_back(std::move(vlinks));
0102     m_indices.push_back(index);
0103     m_sources.push_back(source);
0104     m_bounds.push_back(std::move(bounds));
0105     m_transforms.push_back(trf);
0106   }
0107 
0108   /// Add all necessary components to the factory from bundled surface
0109   /// data in @param surface_data .
0110   DETRAY_HOST
0111   auto push_back(sf_data_collection &&surface_data) -> void override {
0112     const auto n_surfaces{static_cast<dindex>(size() + surface_data.size())};
0113 
0114     m_volume_links.reserve(n_surfaces);
0115     m_indices.reserve(n_surfaces);
0116     m_sources.reserve(n_surfaces);
0117     m_bounds.reserve(n_surfaces);
0118     m_transforms.reserve(n_surfaces);
0119 
0120     // Get per-surface data into detector level container layout
0121     for (auto &sf_data : surface_data) {
0122       push_back(std::move(sf_data));
0123     }
0124   }
0125 
0126   /// Clear old data
0127   DETRAY_HOST
0128   auto clear() -> void override {
0129     m_types.clear();
0130     m_volume_links.clear();
0131     m_indices.clear();
0132     m_sources.clear();
0133     m_bounds.clear();
0134     m_transforms.clear();
0135   }
0136 
0137   /// Generate the surfaces and add them to given data collections.
0138   ///
0139   /// @param volume the volume they will be added to in the detector.
0140   /// @param surfaces the resulting surface objects.
0141   /// @param transforms the transforms of the surfaces.
0142   /// @param masks the masks of the surfaces (all of the same shape).
0143   /// @param ctx the geometry context.
0144   ///
0145   /// @returns index range of inserted surfaces in @param surfaces container
0146   DETRAY_HOST
0147   auto operator()([[maybe_unused]] typename detector_t::volume_type &volume,
0148                   [[maybe_unused]]
0149                   typename detector_t::surface_lookup_container &surfaces,
0150                   [[maybe_unused]]
0151                   typename detector_t::transform_container &transforms,
0152                   [[maybe_unused]] typename detector_t::mask_container &masks,
0153                   [[maybe_unused]]
0154                   typename detector_t::geometry_context ctx = {})
0155       -> dindex_range override {
0156     DETRAY_VERBOSE_HOST("Add geometric surfaces...");
0157 
0158     // In case the surfaces container is prefilled with other surfaces
0159     const auto surfaces_offset{static_cast<dindex>(surfaces.size())};
0160 
0161     DETRAY_VERBOSE_HOST("-> Adding " << size() << " surfaces");
0162 
0163     // Nothing to construct
0164     if (size() == 0u) {
0165       return {surfaces_offset, surfaces_offset};
0166     }
0167 
0168     using mask_t = mask<mask_shape_t, algebra_t, volume_link_t>;
0169 
0170     if constexpr (!types::contains<typename detector_t::masks, mask_t>) {
0171       std::stringstream err_str{};
0172       err_str << "Could not find mask type '" << mask_shape_t::name
0173               << "' in detector";
0174 
0175       DETRAY_FATAL_HOST(err_str.str());
0176       throw std::invalid_argument(err_str.str());
0177     } else {
0178       using surface_t = typename detector_t::surface_type;
0179       using mask_link_t = typename surface_t::mask_link;
0180       using material_link_t = typename surface_t::material_link;
0181 
0182       constexpr auto mask_id{types::id<typename detector_t::masks, mask_t>};
0183 
0184       // The material will be added in a later step
0185       constexpr auto no_material{surface_t::material_id::e_none};
0186 
0187       for (const auto [idx, bounds_per_mask] :
0188            detray::views::enumerate(m_bounds)) {
0189         // Append the surfaces relative to the current number of
0190         // surfaces in the stores
0191         const dindex sf_idx{detail::is_invalid_value(m_indices[idx])
0192                                 ? dindex_invalid
0193                                 : m_indices[idx]};
0194 
0195         // Add transform
0196         const dindex trf_idx = this->insert_in_container(
0197             transforms, m_transforms[idx], sf_idx, ctx);
0198 
0199         // Masks are simply appended, since they are distributed onto
0200         // multiple containers, their ordering is different from the
0201         // surfaces
0202         auto v_links_per_mask = m_volume_links[idx];
0203         assert(v_links_per_mask.size() == bounds_per_mask.size());
0204         std::size_t n_masks = bounds_per_mask.size();
0205         if constexpr (std::is_same_v<mask_shape_t,
0206                                      unmasked<mask_shape_t::dim>>) {
0207           masks.template emplace_back<mask_id>(
0208               empty_context{}, v_links_per_mask.front(),
0209               detail::invalid_value<scalar_t>());
0210         } else {
0211           for (std::size_t i = 0u; i < n_masks; ++i) {
0212             masks.template emplace_back<mask_id>(
0213                 empty_context{}, bounds_per_mask[i], v_links_per_mask[i]);
0214           }
0215         }
0216 
0217         // Add surface with all links set (relative to the given
0218         // containers)
0219         mask_link_t mask_link{};
0220         mask_link.set_id(mask_id);
0221         const auto mask_idx{
0222             static_cast<dindex>(masks.template size<mask_id>() - n_masks)};
0223         if constexpr (concepts::index<typename mask_link_t::index_type>) {
0224           mask_link.set_index(mask_idx);
0225         } else {
0226           mask_link.set_index({mask_idx, static_cast<dindex>(n_masks)});
0227         }
0228         // If material is present, it is added in a later step
0229         material_link_t material_link{no_material, dindex_invalid};
0230 
0231         // Add the surface descriptor at the position given by 'sf_idx'
0232         this->insert_in_container(surfaces,
0233                                   {surface_t{trf_idx, mask_link, material_link,
0234                                              volume.index(), m_types[idx]},
0235                                    m_sources[idx]},
0236                                   sf_idx);
0237       }
0238     }
0239 
0240     return {surfaces_offset, static_cast<dindex>(surfaces.size())};
0241   }
0242 
0243  private:
0244   /// Run internal consistency check of surface data in the builder
0245   DETRAY_HOST
0246   void check() const {
0247     // This should not happen (need same number and ordering of data)
0248     assert(m_bounds.size() == m_types.size());
0249     assert(m_bounds.size() == m_volume_links.size());
0250     assert(m_bounds.size() == m_indices.size());
0251     assert(m_bounds.size() == m_sources.size());
0252     assert(m_bounds.size() == m_transforms.size());
0253   }
0254 
0255   /// Types of the surface (portal|sensitive|passive)
0256   std::vector<surface_id> m_types{};
0257   /// Mask volume link (used for navigation)
0258   volume_link_collection m_volume_links{};
0259   /// Indices of surfaces for the placement in container
0260   /// (counted as "volume-local": 0 to n_sf_in_volume)
0261   std::vector<dindex> m_indices{};
0262   /// Source links of surfaces
0263   std::vector<std::uint64_t> m_sources{};
0264   /// Mask boundaries of surfaces
0265   std::vector<std::vector<std::vector<scalar_t>>> m_bounds{};
0266   /// Transforms of surfaces
0267   std::vector<typename detector_t::transform3_type> m_transforms{};
0268 };
0269 
0270 }  // namespace detray