Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-15 09:23:54

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 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Geometry/ISurfacesProvider.hpp"
0013 #include "Acts/Geometry/ReferenceGenerators.hpp"
0014 #include "Acts/Surfaces/Surface.hpp"
0015 #include "Acts/Utilities/AxisDefinitions.hpp"
0016 #include "Acts/Utilities/KDTree.hpp"
0017 
0018 #include <array>
0019 #include <ranges>
0020 #include <stdexcept>
0021 #include <tuple>
0022 #include <vector>
0023 
0024 namespace Acts {
0025 
0026 /// @brief A wrapper class around a KDTree of surfaces
0027 ///
0028 /// It also deals with the conversion from global query to
0029 /// KDTree lookup positions
0030 ///
0031 template <std::size_t kDIM = 2u, std::size_t bSize = 100u>
0032 class KdtSurfaces {
0033  public:
0034   /// Broadcast the surface KDT type
0035   using KDTS =
0036       KDTree<kDIM, std::shared_ptr<Surface>, double, std::array, bSize>;
0037 
0038   /// Broadcast the query definition
0039   using Query = std::array<double, kDIM>;
0040 
0041   /// Broadcast the entry
0042   using Entry = std::pair<Query, std::shared_ptr<Surface>>;
0043 
0044   /// Constructor from a vector of surfaces
0045   ///
0046   /// @param gctx the geometry context of this call
0047   /// @param surfaces the surfaces to be filled into the tree
0048   /// @param casts the cast list from global position into kdtree local
0049   /// @param rgen the reference point generator
0050   KdtSurfaces(const GeometryContext& gctx,
0051               const std::vector<std::shared_ptr<Surface>>& surfaces,
0052               const std::array<AxisDirection, kDIM>& casts,
0053               const std::shared_ptr<IReferenceGenerator>& rgen =
0054                   std::make_shared<PolyhedronReferenceGenerator>())
0055       : m_kdt(nullptr), m_casts(casts), m_rGenerator(rgen) {
0056     // Simple check if the dimension is correct
0057     if (kDIM == 0u) {
0058       throw std::invalid_argument(
0059           "KdtSurfaces: dimension and/or cast rules are incorrect.");
0060     }
0061     // Fill the tree from surfaces
0062     std::vector<Entry> kdtEntries;
0063     kdtEntries.reserve(surfaces.size());
0064     for (auto& s : surfaces) {
0065       // Generate the references and the center of gravity from it
0066       const auto references = m_rGenerator->references(gctx, *s);
0067       std::vector<Query> castedReferences;
0068       castedReferences.reserve(references.size());
0069       for (const auto& r : references) {
0070         //  Now cast into the correct fill position
0071         Query rc = {};
0072         fillCasts(r, rc, std::make_integer_sequence<std::size_t, kDIM>{});
0073         castedReferences.push_back(rc);
0074       }
0075       // Calculate the center of gravity in casted frame
0076       kdtEntries.push_back({cog(castedReferences), s});
0077     }
0078     // Create the KDTree
0079     m_kdt = std::make_unique<KDTS>(std::move(kdtEntries));
0080   }
0081 
0082   /// Query with a Range object
0083   ///
0084   /// @param range is the range to be queried
0085   ///
0086   /// @return the matching surfaces from the KDT structure
0087   std::vector<std::shared_ptr<Surface>> surfaces(
0088       const RangeXD<kDIM, double>& range) const {
0089     // Strip the surfaces
0090     std::vector<std::shared_ptr<Surface>> surfacePtrs;
0091     auto surfaceQuery = m_kdt->rangeSearchWithKey(range);
0092     std::ranges::for_each(
0093         surfaceQuery, [&](auto& surf) { surfacePtrs.push_back(surf.second); });
0094     return surfacePtrs;
0095   }
0096 
0097   /// Query with an Extent object
0098   ///
0099   /// @param extent is the range Extent to be queried
0100   ///
0101   /// @return the matching surfaces fpulled from the KDT structure
0102   std::vector<std::shared_ptr<Surface>> surfaces(const Extent& extent) const {
0103     RangeXD<kDIM, double> qRange;
0104     for (auto [ibv, v] : enumerate(m_casts)) {
0105       qRange[ibv] = extent.range(v);
0106     }
0107     return surfaces(qRange);
0108   }
0109 
0110  private:
0111   /// The KDTree as single source for the surfaces (maybe shared)
0112   std::unique_ptr<KDTS> m_kdt = nullptr;
0113 
0114   /// Cast values that turn a global position to lookup position
0115   std::array<AxisDirection, kDIM> m_casts = {};
0116 
0117   /// Helper to generate reference points for filling
0118   std::shared_ptr<IReferenceGenerator> m_rGenerator{nullptr};
0119 
0120   /// Unroll the cast loop
0121   /// @param position is the position of the update call
0122   /// @param a is the array to be filled
0123   template <typename Array, std::size_t... idx>
0124   void fillCasts(const Vector3& position, Array& a,
0125                  std::index_sequence<idx...> /*indices*/) const {
0126     ((a[idx] = VectorHelpers::cast(position, m_casts[idx])), ...);
0127   }
0128 
0129   /// Helper method to calculate the center of gravity in the
0130   /// casted frame (i.e. query frame)
0131   ///
0132   /// @param cQueries are the casted query positions
0133   /// @note will do nothing if vector size is equal to 1
0134   ///
0135   /// @note no checking on qQueries.empty() is done as the
0136   /// positions are to be provided by a generator which itself
0137   /// is tested for consistency
0138   ///
0139   /// @return the center of gravity as a query object
0140   Query cog(const std::vector<Query>& cQueries) const {
0141     // If there is only one position, return it
0142     if (cQueries.size() == 1) {
0143       return cQueries.front();
0144     }
0145     // Build the center of gravity of the n positions
0146     Query c{};
0147     float weight = 1. / cQueries.size();
0148     for (auto& q : cQueries) {
0149       std::transform(c.begin(), c.end(), q.begin(), c.begin(),
0150                      std::plus<double>());
0151     }
0152     std::ranges::for_each(c, [&](auto& v) { v *= weight; });
0153     return c;
0154   }
0155 };
0156 
0157 /// @brief Callable struct wrapper around the KDT surface structure
0158 ///
0159 /// This allows to create small region based callable structs at
0160 /// configuration level that are then connected to an InternalStructureBuilder
0161 template <std::size_t kDIM = 2u, std::size_t bSize = 100u>
0162 class KdtSurfacesProvider : public ISurfacesProvider {
0163  public:
0164   /// The prefilled surfaces in a KD tree structure, it is generally shared
0165   /// amongst different providers
0166   ///
0167   /// @param kdts the prefilled KDTree structure
0168   /// @param kregion the region where these are pulled from
0169   KdtSurfacesProvider(std::shared_ptr<KdtSurfaces<kDIM, bSize>> kdts,
0170                       const Extent& kregion)
0171       : m_kdt(std::move(kdts)), m_region(kregion) {
0172     /// Sanity check that the KDTree is not empty
0173     if (m_kdt == nullptr) {
0174       throw std::invalid_argument(
0175           "KdtSurfacesProvider: no KDTree structure provided.");
0176     }
0177   }
0178 
0179   /// The call to provide the surfaces
0180   /// @param gctx Geometry context (not used in KDT provider)
0181   /// @return Vector of surfaces from the KDT query
0182   std::vector<std::shared_ptr<Surface>> surfaces(
0183       [[maybe_unused]] const GeometryContext& gctx) const final {
0184     return m_kdt->surfaces(m_region);
0185   }
0186 
0187  private:
0188   std::shared_ptr<KdtSurfaces<kDIM, bSize, reference_generator>> m_kdt =
0189       nullptr;
0190   /// The query region
0191   Extent m_region;
0192 };
0193 
0194 }  // namespace Acts