Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:10:09

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2022 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 /// This file implements the tools for a hough transform.
0010 
0011 #pragma once
0012 #include "Acts/Utilities/Delegate.hpp"
0013 #include "Acts/Utilities/Logger.hpp"
0014 #include "Acts/Utilities/Result.hpp"
0015 
0016 #include <algorithm>
0017 #include <array>
0018 #include <map>
0019 #include <optional>
0020 #include <set>
0021 #include <unordered_set>
0022 
0023 #include "HoughVectors.hpp"
0024 
0025 namespace Acts::HoughTransformUtils {
0026 
0027 /// this type is responsible for encoding the parameters of our hough space
0028 using CoordType = double;
0029 
0030 // this type is used to encode hit counts.
0031 // Floating point to allow hit weights to be applied
0032 using YieldType = float;
0033 
0034 /// @brief this function represents a mapping of a coordinate point in detector space to a line in
0035 /// hough space. Given the value of the first hough coordinate, it shall return
0036 /// the corresponding second coordinate according to the line parametrisation.
0037 /// Should be implemented by the user.
0038 /// @tparam PointType: The class representing a point in detector space (can differ between implementations)
0039 template <class PointType>
0040 using LineParametrisation =
0041     std::function<CoordType(CoordType, const PointType&)>;
0042 
0043 /// @brief struct to define the ranges of the hough histogram.
0044 /// Used to move between parameter and bin index coordinates.
0045 /// Disconnected from the hough plane binning to be able to re-use
0046 /// a plane with a given binning for several parameter ranges
0047 struct HoughAxisRanges {
0048   CoordType xMin = 0.0f;  // minimum value of the first coordinate
0049   CoordType xMax = 0.0f;  // maximum value of the first coordinate
0050   CoordType yMin = 0.0f;  // minimum value of the second coordinate
0051   CoordType yMax = 0.0f;  // maximum value of the second coordinate
0052 };
0053 
0054 /// convenience functions to link bin indices to axis coordinates
0055 
0056 /// @brief find the bin index corresponding to a certain abscissa
0057 /// of the coordinate axis, based on the axis limits and binning.
0058 /// @param min: Start of axis range
0059 /// @param max: End of axis range
0060 /// @param nSteps: Number of bins in axis
0061 /// @param val: value to find the corresponding bin for
0062 /// @return the bin number.
0063 /// No special logic to prevent over-/underflow, checking these is
0064 /// left to the caller
0065 inline int binIndex(double min, double max, unsigned nSteps, double val) {
0066   return static_cast<int>((val - min) / (max - min) * nSteps);
0067 }
0068 // Returns the lower bound of the bin specified by step
0069 /// @param min: Start of axis range
0070 /// @param max: End of axis range
0071 /// @param nSteps: Number of bins in axis
0072 /// @param binIndex: The index of the bin
0073 /// @return the parameter value at the lower bin edge.
0074 /// No special logic to prevent over-/underflow, checking these is
0075 /// left to the caller
0076 inline double lowerBinEdge(double min, double max, unsigned nSteps,
0077                            std::size_t binIndex) {
0078   return min + (max - min) * binIndex / nSteps;
0079 }
0080 // Returns the lower bound of the bin specified by step
0081 /// @param min: Start of axis range
0082 /// @param max: End of axis range
0083 /// @param nSteps: Number of bins in axis
0084 /// @param binIndex: The index of the bin
0085 /// @return the parameter value at the bin center.
0086 /// No special logic to prevent over-/underflow, checking these is
0087 /// left to the caller
0088 inline double binCenter(double min, double max, unsigned nSteps,
0089                         std::size_t binIndex) {
0090   return min + (max - min) * 0.5 * (2 * binIndex + 1) / nSteps;
0091 }
0092 
0093 /// @brief data class for the information to store for each
0094 /// cell of the hough histogram.
0095 /// @tparam identifier_t: Type of the identifier to associate to the hits
0096 ///                       Should be sortable. Used to uniquely identify each
0097 ///                       hit and to eventually return the list of hits per cell
0098 template <class identifier_t>
0099 class HoughCell {
0100  public:
0101   /// @brief construct the cell as empty
0102   HoughCell() = default;
0103   /// @brief add an entry to this cell
0104   /// @param identifier: Identifier of the hit (used to distinguish hits from another)
0105   /// @param layer: Layer of the hit (used when counting layers)
0106   /// @param weight: Optional weight to assign to the hit
0107   void fill(const identifier_t& identifier, unsigned int layer,
0108             YieldType weight = 1.);
0109   /// @brief access the number of layers with hits compatible with this cell
0110   YieldType nLayers() const { return m_nLayers; }
0111   /// @brief access the number of unique hits compatible with this cell
0112   YieldType nHits() const { return m_nHits; }
0113   /// @brief access the set of layers compatible with this cell
0114   const std::unordered_set<unsigned>& layers() const { return m_layers; }
0115   /// @brief access the set of unique hits compatible with this cell
0116   const std::unordered_set<identifier_t>& hits() const { return m_hits; }
0117   /// @brief reset this cell, removing any existing content.
0118   void reset();
0119 
0120  private:
0121   /// data members
0122 
0123   YieldType m_nLayers =
0124       0;                  // (weighted) number of layers with hits on this cell
0125   YieldType m_nHits = 0;  // (weighted) number of unique hits on this cell
0126   std::unordered_set<unsigned> m_layers =
0127       {};  // set of layers with hits on this cell
0128   std::unordered_set<identifier_t> m_hits =
0129       {};  // set of unique hits on this cell
0130 };
0131 
0132 /// @brief Configuration - number of bins in each axis.
0133 /// The Hough plane is agnostic of how the bins map to
0134 /// coordinates, allowing to re-use a plane for several
0135 /// (sub) detectors of different dimensions if the bin number
0136 /// remains applicable
0137 struct HoughPlaneConfig {
0138   std::size_t nBinsX = 0;  // number of bins in the first coordinate
0139   std::size_t nBinsY = 0;  // number of bins in the second coordinate
0140 };
0141 
0142 /// @brief Representation of the hough plane - the histogram used
0143 /// for the hough transform with methods to fill and evaluate
0144 /// the histogram. Templated to a class used as identifier for the hits
0145 template <class identifier_t>
0146 class HoughPlane {
0147  public:
0148   /// @brief hough histogram representation as a 2D-indexable vector of hough cells
0149   using HoughHist = MultiIndexedVector2D<HoughCell<identifier_t>>;
0150 
0151   /// @brief instantiate the (empty) hough plane
0152   /// @param cfg: configuration
0153   HoughPlane(const HoughPlaneConfig& cfg);
0154 
0155   /// fill and reset methods to modify the grid content
0156 
0157   /// @brief add one measurement to the hough plane
0158   /// @tparam PointType: Type of the objects to use when adding measurements (e.g. experiment EDM object)
0159   /// @param measurement: The measurement to add
0160   /// @param axisRanges: Ranges of the hough axes, used to map the bin numbers to parameter values
0161   /// @param linePar: The function y(x) parametrising the hough space line for a given measurement
0162   /// @param widthPar: The function dy(x) parametrising the width of the y(x) curve
0163   ///                   for a given measurement
0164   /// @param identifier: The unique identifier for the given hit
0165   /// @param layer: A layer index for this hit
0166   /// @param weight: An optional weight to assign to this hit
0167   template <class PointType>
0168   void fill(const PointType& measurement, const HoughAxisRanges& axisRanges,
0169             LineParametrisation<PointType> linePar,
0170             LineParametrisation<PointType> widthPar,
0171             const identifier_t& identifier, unsigned layer = 0,
0172             YieldType weight = 1.0f);
0173   /// @brief resets the contents of the grid. Can be used to avoid reallocating the histogram
0174   /// when switching regions / (sub)detectors
0175   void reset();
0176 
0177   //// user-facing accessors
0178 
0179   /// @brief get the layers with hits in one cell of the histogram
0180   /// @param xBin: bin index in the first coordinate
0181   /// @param yBin: bin index in the second coordinate
0182   /// @return the set of layer indices that have hits for this cell
0183   const std::unordered_set<unsigned>& layers(std::size_t xBin,
0184                                              std::size_t yBin) const {
0185     return m_houghHist(xBin, yBin).layers();
0186   }
0187 
0188   /// @brief get the (weighted) number of layers  with hits in one cell of the histogram
0189   /// @param xBin: bin index in the first coordinate
0190   /// @param yBin: bin index in the second coordinate
0191   /// @return the (weighed) number of layers that have hits for this cell
0192   YieldType nLayers(std::size_t xBin, std::size_t yBin) const {
0193     return m_houghHist(xBin, yBin).nLayers();
0194   }
0195 
0196   /// @brief get the identifiers of all hits in one cell of the histogram
0197   /// @param xBin: bin index in the first coordinate
0198   /// @param yBin: bin index in the second coordinate
0199   /// @return the set of identifiers of the hits for this cell
0200   const std::unordered_set<identifier_t>& hitIds(std::size_t xBin,
0201                                                  std::size_t yBin) const {
0202     return m_houghHist(xBin, yBin).hits();
0203   }
0204   /// @brief get the (weighted) number of hits in one cell of the histogram
0205   /// @param xBin: bin index in the first coordinate
0206   /// @param yBin: bin index in the second coordinate
0207   /// @return the (weighted) number of hits for this cell
0208   YieldType nHits(std::size_t xBin, std::size_t yBin) const {
0209     return m_houghHist(xBin, yBin).nHits();
0210   }
0211 
0212   /// @brief get the number of bins on the first coordinate
0213   std::size_t nBinsX() const { return m_cfg.nBinsX; }
0214   /// @brief get the number of bins on the second coordinate
0215   std::size_t nBinsY() const { return m_cfg.nBinsY; }
0216 
0217   /// @brief get the maximum number of (weighted) hits seen in a single
0218   /// cell across the entire histrogram.
0219   YieldType maxHits() const { return m_maxHits; }
0220 
0221   /// @brief get the list of cells with non-zero content.
0222   /// Useful for peak-finders in sparse data
0223   /// to avoid looping over all cells
0224   const std::set<std::pair<std::size_t, std::size_t>>& getNonEmptyBins() const {
0225     return m_touchedBins;
0226   }
0227 
0228   /// @brief get the bin indices of the cell containing the largest number
0229   /// of (weighted) hits across the entire histogram
0230   std::pair<std::size_t, std::size_t> locMaxHits() const {
0231     return m_maxLocHits;
0232   }
0233 
0234   /// @brief get the maximum number of (weighted) layers with hits  seen
0235   /// in a single cell across the entire histrogram.
0236   YieldType maxLayers() const { return m_maxLayers; }
0237 
0238   /// @brief get the bin indices of the cell containing the largest number
0239   /// of (weighted) layers with hits across the entire histogram
0240   std::pair<std::size_t, std::size_t> locMaxLayers() const {
0241     return m_maxLocLayers;
0242   }
0243 
0244  private:
0245   /// @brief Helper method to fill a bin of the hough histogram.
0246   /// Updates the internal helper data structures (maximum tracker etc).
0247   /// @param binX: bin number along x
0248   /// @param binY: bin number along y
0249   /// @param identifier: hit identifier
0250   /// @param layer: layer index
0251   /// @param w: optional hit weight
0252   void fillBin(std::size_t binX, std::size_t binY,
0253                const identifier_t& identifier, unsigned layer, double w = 1.0f);
0254 
0255   YieldType m_maxHits = 0.0f;    // track the maximum number of hits seen
0256   YieldType m_maxLayers = 0.0f;  // track the maximum number of layers seen
0257   std::pair<std::size_t, std::size_t> m_maxLocHits = {
0258       0, 0};  // track the location of the maximum in hits
0259   std::pair<std::size_t, std::size_t> m_maxLocLayers = {
0260       0, 0};  // track the location of the maximum in layers
0261   std::set<std::pair<std::size_t, std::size_t>> m_touchedBins =
0262       {};                  // track the bins with non-trivial content
0263   HoughPlaneConfig m_cfg;  // the configuration object
0264   HoughHist m_houghHist;   // the histogram data object
0265 };
0266 
0267 /// example peak finders.
0268 namespace PeakFinders {
0269 /// configuration for the LayerGuidedCombinatoric peak finder
0270 struct LayerGuidedCombinatoricConfig {
0271   YieldType threshold = 3.0f;  // min number of layers to obtain a maximum
0272   int localMaxWindowSize = 0;  // Only create candidates from a local maximum
0273 };
0274 
0275 /// @brief Peak finder inspired by ATLAS ITk event filter developments.
0276 /// Builds peaks based on layer counts and allows for subsequent resolution
0277 /// of the combinatorics by building multiple candidates per peak if needed.
0278 /// In flat regions, peak positions are moved towards smaller values of the
0279 /// second and first coordinate.
0280 /// @tparam identifier_t: The identifier type to use. Should match the one used in the hough plane.
0281 template <class identifier_t>
0282 class LayerGuidedCombinatoric {
0283  public:
0284   /// @brief data class representing the found maxima.
0285   /// Here, we just have a list of cluster identifiers
0286   struct Maximum {
0287     std::unordered_set<identifier_t> hitIdentifiers =
0288         {};  // identifiers of contributing hits
0289   };
0290   /// @brief constructor
0291   /// @param cfg: Configuration object
0292   LayerGuidedCombinatoric(const LayerGuidedCombinatoricConfig& cfg);
0293 
0294   /// @brief main peak finder method.
0295   /// @param plane: Filled hough plane to search
0296   /// @return vector of found maxima
0297   std::vector<Maximum> findPeaks(const HoughPlane<identifier_t>& plane) const;
0298 
0299  private:
0300   /// @brief check if a given bin is a local maximum.
0301   /// @param plane: The filled hough plane
0302   /// @param xBin: x bin index
0303   /// @param yBin: y bin index
0304   /// @return true if a maximum, false otherwise
0305   bool passThreshold(const HoughPlane<identifier_t>& plane, std::size_t xBin,
0306                      std::size_t yBin) const;  // did we pass extensions?
0307 
0308   LayerGuidedCombinatoricConfig m_cfg;  // configuration data object
0309 };
0310 /// @brief Configuration for the IslandsAroundMax peak finder
0311 struct IslandsAroundMaxConfig {
0312   YieldType threshold =
0313       3.0f;  // min number of weigted hits required in a maximum
0314   YieldType fractionCutoff =
0315       0;  // Fraction of the global maximum at which to cut off maxima
0316   std::pair<CoordType, CoordType> minSpacingBetweenPeaks = {
0317       0.0f, 0.0f};  // minimum distance of a new peak from existing peaks in
0318                     // parameter space
0319 };
0320 /// @brief Peak finder inspired by ATLAS muon reconstruction.
0321 /// Looks for regions above a given fraction of the global maximum
0322 /// hit count and connects them into islands comprising adjacent bins
0323 /// above the threshold. Peak positions are averaged across cells in the island,
0324 /// weighted by hit counts
0325 /// @tparam identifier_t: The identifier type to use. Should match the one used in the hough plane.
0326 template <class identifier_t>
0327 class IslandsAroundMax {
0328  public:
0329   /// @brief data struct representing a local maximum.
0330   /// Comes with a position estimate and a list of hits within the island
0331   struct Maximum {
0332     CoordType x = 0;   // x value of the maximum
0333     CoordType y = 0;   // y value of the maximum
0334     CoordType wx = 0;  // x width of the maximum
0335     CoordType wy = 0;  // y width of the maximum
0336     std::unordered_set<identifier_t> hitIdentifiers =
0337         {};  // identifiers of contributing hits
0338   };
0339   /// @brief constructor.
0340   /// @param cfg: configuration object
0341   IslandsAroundMax(const IslandsAroundMaxConfig& cfg);
0342 
0343   /// @brief main peak finder method.
0344   /// @param plane: The filled hough plane to search
0345   /// @param ranges: The axis ranges used for mapping between parameter space and bins.
0346   /// @return List of the found maxima
0347   std::vector<Maximum> findPeaks(const HoughPlane<identifier_t>& plane,
0348                                  const HoughAxisRanges& ranges);
0349 
0350  private:
0351   /// @brief method to incrementally grow an island by adding adjacent cells
0352   /// Performs a breadth-first search for neighbours above threshold and adds
0353   /// them to candidate. Stops when no suitable neighbours are left.
0354   /// @param inMaximum: List of cells found in the island. Incrementally populated by calls to the method
0355   /// @param toExplore: List of neighbour cell candidates left to explore. Method will not do anything once this is empty
0356   /// @param threshold: the threshold to apply to check if a cell should be added to an island
0357   /// @param yieldMap: A map of the hit content of above-threshold cells. Used cells will be set to empty content to avoid re-use by subsequent calls
0358   void extendMaximum(
0359       std::vector<std::pair<std::size_t, std::size_t>>& inMaximum,
0360       std::vector<std::pair<std::size_t, std::size_t>>& toExplore,
0361       YieldType threshold,
0362       std::map<std::pair<std::size_t, std::size_t>, YieldType>& yieldMap);
0363 
0364   IslandsAroundMaxConfig m_cfg;  // configuration data object
0365 
0366   /// @brief array of steps to consider when exploring neighbouring cells.
0367   const std::array<std::pair<int, int>, 8> m_stepDirections{
0368       std::make_pair(-1, -1), std::make_pair(0, -1), std::make_pair(1, -1),
0369       std::make_pair(-1, 0),  std::make_pair(1, 0),  std::make_pair(-1, 1),
0370       std::make_pair(0, 1),   std::make_pair(1, 1)};
0371 };
0372 }  // namespace PeakFinders
0373 }  // namespace Acts::HoughTransformUtils
0374 
0375 #include "HoughTransformUtils.ipp"