Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/Acts/Detector/KdtSurfacesProvider.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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