Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-14 09:20:35

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/Definitions/Common.hpp"
0013 #include "Acts/Geometry/GeometryContext.hpp"
0014 #include "Acts/Geometry/Polyhedron.hpp"
0015 #include "Acts/Utilities/Enumerate.hpp"
0016 #include "Acts/Utilities/GridAccessHelpers.hpp"
0017 #include "Acts/Utilities/Helpers.hpp"
0018 #include "Acts/Utilities/IAxis.hpp"
0019 #include "Acts/Utilities/Logger.hpp"
0020 
0021 #include <algorithm>
0022 #include <array>
0023 #include <set>
0024 #include <string>
0025 #include <vector>
0026 
0027 namespace Acts {
0028 
0029 /// @brief Helper method to generate completely populated bin sequences
0030 /// that respect the boundary type of the axis
0031 ///
0032 /// @param minMaxBins estimated bin range (aka binning boundary box)
0033 /// @param expand the parameter to expand the view (extra window)
0034 /// @param nBins the maximum number of bins on this axis
0035 /// @param type the boundary type of the axis (for correct bin closure)
0036 ///
0037 /// @note for closed binning a span over half the bins flips direction
0038 ///
0039 /// @return a vector of bins to be filled
0040 std::vector<std::size_t> binSequence(std::array<std::size_t, 2u> minMaxBins,
0041                                      std::size_t expand, std::size_t nBins,
0042                                      Acts::AxisBoundaryType type);
0043 
0044 /// @brief Helper method to expand the grid queries along a given dimension
0045 /// @tparam queries_type the type of the grid queries
0046 /// @tparam expansion_type the type of the reference expansion
0047 /// @tparam kDIM the dimension to be expanded
0048 /// @param gridQueries the grid queries to be expanded
0049 /// @param referenceExpansion the reference expansion values
0050 template <typename queries_type, typename expansion_type, std::size_t kDIM>
0051 void expand(queries_type& gridQueries,
0052             const expansion_type& referenceExpansion) {
0053   queries_type copiedQueries = gridQueries;
0054   // Sort them for smaller bigger
0055   std::ranges::sort(copiedQueries, [](const auto& a, const auto& b) {
0056     return a[kDIM] < b[kDIM];
0057   });
0058   // Get a mid point
0059   auto midPoint =
0060       0.5 * (copiedQueries.front()[kDIM] + copiedQueries.back()[kDIM]);
0061   // Loop and correct the first coordinate
0062   for (auto& pq : gridQueries) {
0063     if (pq[kDIM] < midPoint) {
0064       pq[kDIM] -= referenceExpansion[kDIM];
0065     } else {
0066       pq[kDIM] += referenceExpansion[kDIM];
0067     }
0068   }
0069 }
0070 
0071 /// Run the reference expansion
0072 /// @tparam grid_type the type of the grid
0073 /// @param gridQueries the grid queries to be expanded
0074 /// @param referenceExpansion the reference expansion values
0075 template <typename grid_type>
0076 void applyReferenceExpansion(
0077     std::vector<typename grid_type::point_t>& gridQueries,
0078     const std::vector<double>& referenceExpansion) {
0079   if (referenceExpansion.empty()) {
0080     return;
0081   }
0082   if (referenceExpansion.size() != grid_type::DIM) {
0083     throw std::runtime_error(
0084         "IndexedSurfaceGridFiller: wrong dimension of reference expansion "
0085         "given.");
0086   }
0087   expand<decltype(gridQueries), decltype(referenceExpansion), 0u>(
0088       gridQueries, referenceExpansion);
0089   if constexpr (grid_type::DIM >= 2u) {
0090     expand<decltype(gridQueries), decltype(referenceExpansion), 1u>(
0091         gridQueries, referenceExpansion);
0092   }
0093   if constexpr (grid_type::DIM == 3u) {
0094     expand<decltype(gridQueries), decltype(referenceExpansion), 2u>(
0095         gridQueries, referenceExpansion);
0096   }
0097 }
0098 
0099 /// @brief Helper method to fill local bins given a set of query points
0100 /// bin in between the extra points are filled, and a possible expansion
0101 /// of the bin window can be chosen
0102 ///
0103 /// @tparam grid_type the type of the grid that determines locall binning
0104 ///
0105 /// @param grid the grid used for this
0106 /// @param queries the grid positions for the bin queries
0107 /// @param expansion are the additional (configured) number of bins to expand
0108 /// the view
0109 ///
0110 /// @return a set of unique indices
0111 template <typename grid_type>
0112 std::set<typename grid_type::index_t> localIndices(
0113     const grid_type& grid,
0114     const std::vector<typename grid_type::point_t>& queries,
0115     const std::vector<std::size_t>& expansion = {}) {
0116   // Return indices
0117   std::set<typename grid_type::index_t> lIndices;
0118 
0119   if (queries.empty()) {
0120     throw std::runtime_error("IndexedSurfaceGridFiller: no query point given.");
0121   }
0122 
0123   if (!expansion.empty() && expansion.size() != grid_type::DIM) {
0124     throw std::runtime_error(
0125         "IndexedSurfaceGridFiller: wrong dimension of bin expansion given.");
0126   }
0127 
0128   /// These are the axis bounds type parameters - for correct bin sequences
0129   std::array<Acts::AxisBoundaryType, grid_type::DIM> axisTypes{};
0130   std::array<std::size_t, grid_type::DIM> axisBins{};
0131   // Fill the axis types
0132   for (auto [ia, a] : enumerate(grid.axes())) {
0133     axisTypes[ia] = a->getBoundaryType();
0134     axisBins[ia] = a->getNBins();
0135   }
0136 
0137   // Initialize the bin ranges
0138   std::array<std::array<std::size_t, 2u>, grid_type::DIM> binRanges = {};
0139   for (auto& br : binRanges) {
0140     br[0u] = std::numeric_limits<std::size_t>::max();
0141     br[1u] = 0u;
0142   }
0143   // Bin range bounding box - estimated from the query points
0144   for (const auto& q : queries) {
0145     auto qbin = grid.localBinsFromPosition(q);
0146     for (std::size_t ib = 0; ib < grid_type::DIM; ++ib) {
0147       auto iqb = qbin[ib];
0148       binRanges[ib][0u] = std::min(iqb, binRanges[ib][0u]);
0149       binRanges[ib][1u] = std::max(iqb, binRanges[ib][1u]);
0150     }
0151   }
0152   // Fill the bins - 1D case
0153   if constexpr (grid_type::DIM == 1u) {
0154     // Take the expansion if available & generate the local bin sequence
0155     std::size_t expand = expansion.empty() ? 0u : expansion[0u];
0156     auto localBins0 =
0157         binSequence(binRanges[0u], expand, axisBins[0u], axisTypes[0u]);
0158     for (auto l0 : localBins0) {
0159       typename grid_type::index_t b;
0160       b[0u] = l0;
0161       lIndices.insert(b);
0162     }
0163   }
0164   // Fill the bins - 2D case
0165   if constexpr (grid_type::DIM == 2u) {
0166     // Take the expansion if available & generate the local bin sequence
0167     std::size_t expand = expansion.empty() ? 0u : expansion[0u];
0168     auto localBins0 =
0169         binSequence(binRanges[0u], expand, axisBins[0u], axisTypes[0u]);
0170     expand = expansion.empty() ? 0u : expansion[1u];
0171     auto localBins1 =
0172         binSequence(binRanges[1u], expand, axisBins[1u], axisTypes[1u]);
0173     for (auto l0 : localBins0) {
0174       for (auto l1 : localBins1) {
0175         typename grid_type::index_t b;
0176         b[0u] = l0;
0177         b[1u] = l1;
0178         lIndices.insert(b);
0179       }
0180     }
0181   }
0182   return lIndices;
0183 }
0184 
0185 /// @brief Helper method to screen output the local bins
0186 ///
0187 /// @tparam local_bin the type of the local bins
0188 ///
0189 /// @param lbins the local bins
0190 ///
0191 /// @return a string containing the local bins ordered in a set
0192 template <typename local_bin>
0193 std::string outputIndices(const std::set<local_bin>& lbins) {
0194   std::string rString;
0195   for (auto [ilb, lb] : Acts::enumerate(lbins)) {
0196     if (ilb == 0) {
0197       rString = "bins: [";
0198     } else {
0199       rString += ", [";
0200     }
0201     for (auto [ib, b] : Acts::enumerate(lb)) {
0202       if (ib != 0u) {
0203         rString += ", ";
0204       }
0205       rString += std::to_string(b);
0206     }
0207     rString += "]";
0208   }
0209   return rString;
0210 }
0211 
0212 /// @brief  This is an index grid based navigation state updator, it uses
0213 /// an extractor type and a filler type to handle the navigation state
0214 ///
0215 /// @note a transform is applied `p3l = transform * p3` in order to allow
0216 /// shifted, transformed grids
0217 ///
0218 /// It can be used for volumes, surfaces at convenience
0219 ///
0220 /// @tparam navigation_type distinguishes between internal and external navigation
0221 /// @tparam grid_t is the type of the grid
0222 /// @tparam extractor_type is the helper to extract the object
0223 /// @tparam filler_type is the helper to fill the object into the nState
0224 template <typename grid_t>
0225 class IndexGrid {
0226  public:
0227   /// Broadcast the grid type
0228   using grid_type = grid_t;
0229 
0230   /// The grid where the indices are stored
0231   grid_type grid;
0232 
0233   /// These are the cast parameters - copied from constructor
0234   std::array<AxisDirection, grid_type::DIM> casts{};
0235 
0236   /// A transform to be applied to the position
0237   Transform3 transform = Transform3::Identity();
0238 
0239   /// @brief  Constructor for a grid based surface attacher
0240   /// @param igrid the grid that is moved into this attacher
0241   /// @param icasts is the cast values array
0242   /// @param itr a transform applied to the global position
0243   IndexGrid(grid_type&& igrid,
0244             const std::array<AxisDirection, grid_type::DIM>& icasts,
0245             const Transform3& itr = Transform3::Identity())
0246       : grid(std::move(igrid)), casts(icasts), transform(itr) {}
0247 
0248   IndexGrid() = delete;
0249 };
0250 
0251 /// A helper class that fills surfaces into predefined grids
0252 struct IndexGridFiller {
0253   /// Bin expansion where needed - in integer bins
0254   std::vector<std::size_t> binExpansion = {};
0255 
0256   /// Reference expansion - is applied before bin expansion
0257   std::vector<double> referenceExpansion = {};
0258 
0259   /// Screen output logger
0260   std::unique_ptr<const Logger> oLogger =
0261       getDefaultLogger("IndexGridFiller", Logging::INFO);
0262 
0263   /// @brief This method takes a collection of objects and fills them
0264   /// into an index grid - it uses a reference generator for grid query points
0265   /// and then completes the bins in between.
0266   ///
0267   /// It also allows for expanding the fill view.
0268   ///
0269   /// @tparam index_grid the type of the index grid
0270   /// @tparam indexed_objects the type of the object container
0271   /// @tparam reference_generator the generator for reference points to be filled
0272   ///
0273   /// @param gctx the geometry context of the operation
0274   /// @param iGrid [in,out] the index grid object to be filled
0275   /// @param iObjects the object container to be indexed
0276   /// @param rGenerator the reference point generator for position queries
0277   /// @param aToAll the indices that are assigned to all bins
0278   ///
0279   /// @note as this is a Detector module, the objects within the indexed_objects container
0280   /// are assumed to have pointer semantics
0281   ///
0282   template <typename index_grid, typename indexed_objects,
0283             typename reference_generator>
0284   void fill(
0285       const GeometryContext& gctx, index_grid& iGrid,
0286       const indexed_objects& iObjects, const reference_generator& rGenerator,
0287       const typename index_grid::grid_type::value_type& aToAll = {}) const {
0288     // Loop over the surfaces to be filled
0289     for (auto [io, o] : enumerate(iObjects)) {
0290       // Exclude indices that should be handled differently
0291       if (rangeContainsValue(aToAll, io)) {
0292         continue;
0293       }
0294       // Get the reference positions
0295       auto refs = rGenerator.references(gctx, *o);
0296       std::vector<typename index_grid::grid_type::point_t> gridQueries;
0297       gridQueries.reserve(refs.size());
0298       for (const auto& ref : refs) {
0299         // Cast the transform according to the grid binning
0300         gridQueries.push_back(
0301             GridAccessHelpers::castPosition<decltype(iGrid.grid)>(
0302                 iGrid.transform * ref, iGrid.casts));
0303       }
0304       ACTS_DEBUG(gridQueries.size() << " reference points generated.");
0305       // These are now in the grid frame, can be expanded
0306       if (!referenceExpansion.empty()) {
0307         ACTS_DEBUG("Applying reference expansion.");
0308         applyReferenceExpansion<decltype(iGrid.grid)>(gridQueries,
0309                                                       referenceExpansion);
0310       }
0311       // Now generate the local indices
0312       auto lIndices = localIndices<decltype(iGrid.grid)>(
0313           iGrid.grid, gridQueries, binExpansion);
0314       ACTS_DEBUG(lIndices.size() << " indices assigned.");
0315       if (oLogger->level() <= Logging::VERBOSE) {
0316         ACTS_VERBOSE("- list of indices: " << outputIndices(lIndices));
0317       }
0318       // Now fill the surface indices
0319       for (const auto& li : lIndices) {
0320         auto& bContent = iGrid.grid.atLocalBins(li);
0321         if (!rangeContainsValue(bContent, io)) {
0322           bContent.push_back(io);
0323         }
0324       }
0325     }
0326 
0327     // Assign the indices into all
0328     if (!aToAll.empty()) {
0329       assignToAll(iGrid, aToAll);
0330     }
0331   }
0332 
0333   /// Helper method to fill a dedicated list of indices into the entire grid
0334   ///
0335   /// This is useful if e.g. certain objects are to be attempted in any case,
0336   /// regardless of their binning.
0337   ///
0338   template <typename index_grid, typename indices>
0339   void assignToAll(index_grid& iGrid, const indices& idcs) const {
0340     for (std::size_t gi = 0; gi < iGrid.grid.size(true); ++gi) {
0341       auto& bContent = iGrid.grid.at(gi);
0342       for (const auto& io : idcs) {
0343         if (!rangeContainsValue(bContent, io)) {
0344           bContent.push_back(io);
0345         }
0346       }
0347     }
0348   }
0349 
0350   /// Access to the logger
0351   ///
0352   /// @return a const reference to the logger
0353   const Logger& logger() const { return (*oLogger); }
0354 };
0355 
0356 }  // namespace Acts