Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-11 08:19:43

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/Utilities/AxisDefinitions.hpp"
0013 #include "Acts/Utilities/BinningData.hpp"
0014 #include "Acts/Utilities/BinningType.hpp"
0015 #include "Acts/Utilities/Diagnostics.hpp"
0016 #include "Acts/Utilities/Enumerate.hpp"
0017 #include "Acts/Utilities/IMultiAxis.hpp"
0018 #include "Acts/Utilities/ProtoAxis.hpp"
0019 
0020 #include <algorithm>
0021 #include <array>
0022 #include <cstddef>
0023 #include <iostream>
0024 #include <stdexcept>
0025 #include <string>
0026 #include <vector>
0027 
0028 namespace Acts {
0029 
0030 /// @class BinUtility
0031 ///
0032 /// The BinUtility class that translated global and local position into a bins
0033 /// of a BinnedArray, most performant is equidistant binning without a
0034 /// transform,
0035 /// however, optionally a transform can be provided, e.g. for binning on shifted
0036 /// object, the transform is usually shared with the geometric object the Array
0037 /// is
0038 /// defined on, for performance reasons, also the inverse transform is stored.
0039 ///
0040 class BinUtility {
0041  public:
0042   /// Constructor for equidistant
0043   BinUtility()
0044       : m_binningData(),
0045         m_transform(Transform3::Identity()),
0046         m_itransform(Transform3::Identity()) {
0047     m_binningData.reserve(3);
0048   }
0049 
0050   /// Constructor with only a Transform3
0051   ///
0052   /// @param tForm is the local to global transform
0053   explicit BinUtility(const Transform3& tForm)
0054       : m_binningData(), m_transform(tForm), m_itransform(tForm.inverse()) {
0055     m_binningData.reserve(3);
0056   }
0057 
0058   /// Constructor from BinningData directly
0059   ///
0060   /// @param bData is the provided binning data
0061   /// @param tForm is the (optional) transform
0062   explicit BinUtility(const BinningData& bData,
0063                       const Transform3& tForm = Transform3::Identity())
0064       : m_binningData(), m_transform(tForm), m_itransform(tForm.inverse()) {
0065     m_binningData.reserve(3);
0066     m_binningData.emplace_back(bData);
0067   }
0068 
0069   /// Constructor for equidistant
0070   ///
0071   /// @param bins is the number of bins
0072   /// @param min in the minimal value
0073   /// @param max is the maximal value
0074   /// @param opt is the binning option : open, closed
0075   /// @param value is the axis direction : AxisX, AxisY, AxisZ, etc.
0076   /// @param tForm is the (optional) transform
0077   BinUtility(std::size_t bins, float min, float max, BinningOption opt = open,
0078              AxisDirection value = AxisDirection::AxisX,
0079              const Transform3& tForm = Transform3::Identity())
0080       : m_binningData(), m_transform(tForm), m_itransform(tForm.inverse()) {
0081     m_binningData.reserve(3);
0082     m_binningData.emplace_back(opt, value, bins, min, max);
0083   }
0084 
0085   /// Constructor for arbitrary
0086   ///
0087   /// @param bValues is the boundary values of the binning
0088   /// @param opt is the binning option : open, closed
0089   /// @param value is the axis direction : AxisX, AxisY, AxisZ, etc.
0090   /// @param tForm is the (optional) transform
0091   explicit BinUtility(std::vector<float>& bValues, BinningOption opt = open,
0092                       AxisDirection value = AxisDirection::AxisPhi,
0093                       const Transform3& tForm = Transform3::Identity())
0094       : m_binningData(), m_transform(tForm), m_itransform(tForm.inverse()) {
0095     m_binningData.reserve(3);
0096     m_binningData.emplace_back(opt, value, bValues);
0097   }
0098 
0099   /// Create from a type-erased axis carrying its axis direction
0100   ///
0101   /// @param axis the axis to be used, its direction must be set
0102   explicit BinUtility(const IAxis& axis)
0103       : m_binningData(),
0104         m_transform(Transform3::Identity()),
0105         m_itransform(Transform3::Identity()) {
0106     m_binningData.reserve(3);
0107     m_binningData.emplace_back(axis);
0108   }
0109 
0110   /// Create from a multi-axis, with the axes carrying their axis directions
0111   ///
0112   /// @param axes the multi-axis to be used, the axis directions must be set
0113   explicit BinUtility(const IMultiAxis& axes)
0114       : m_binningData(),
0115         m_transform(Transform3::Identity()),
0116         m_itransform(Transform3::Identity()) {
0117     m_binningData.reserve(3);
0118     for (const IAxis& axis : axes) {
0119       m_binningData.emplace_back(axis);
0120     }
0121   }
0122 
0123   /// Create from a DirectedProtoAxis
0124   ///
0125   /// @param dpAxis the DirectedProtoAxis to be used
0126   /// @deprecated Use BinUtility(const IAxis&) with a directed axis instead
0127   [[deprecated("Use BinUtility(const IAxis&) with a directed axis instead")]]
0128   explicit BinUtility(const DirectedProtoAxis& dpAxis)
0129       : m_binningData(),
0130         m_transform(Transform3::Identity()),
0131         m_itransform(Transform3::Identity()) {
0132     m_binningData.reserve(3);
0133     m_binningData.emplace_back(dpAxis.getAxisDirection(), dpAxis.getAxis());
0134   }
0135 
0136   // A deprecated declaration only silences directly named types, not the ones
0137   // it names as template arguments
0138   ACTS_PUSH_IGNORE_DEPRECATED()
0139   /// Create from several DirectedProtoAxis objects
0140   ///
0141   /// @param dpAxes the DirectedProtoAxis to be used with axis directions
0142   /// @deprecated Use BinUtility(const IMultiAxis&) with directed axes instead
0143   [[deprecated("Use BinUtility(const IMultiAxis&) with directed axes instead")]]
0144   explicit BinUtility(const std::vector<DirectedProtoAxis>& dpAxes)
0145       : m_binningData(),
0146         m_transform(Transform3::Identity()),
0147         m_itransform(Transform3::Identity()) {
0148     m_binningData.reserve(3);
0149     for (const auto& dpAxis : dpAxes) {
0150       m_binningData.emplace_back(dpAxis.getAxisDirection(), dpAxis.getAxis());
0151     }
0152   }
0153   ACTS_POP_IGNORE_DEPRECATED()
0154 
0155   /// Operator+= to make multidimensional BinUtility
0156   ///
0157   /// @param gbu is the additional BinUtility to be chosen
0158   /// @return Reference to this BinUtility after addition
0159   BinUtility& operator+=(const BinUtility& gbu) {
0160     const std::vector<BinningData>& bData = gbu.binningData();
0161 
0162     m_transform = m_transform * gbu.transform();
0163     m_itransform = m_transform.inverse();
0164     if (m_binningData.size() + bData.size() > 3) {
0165       throw std::runtime_error{"BinUtility does not support dim > 3"};
0166     }
0167     m_binningData.insert(m_binningData.end(), bData.begin(), bData.end());
0168     return (*this);
0169   }
0170 
0171   /// Equality operator
0172   /// @param other The other BinUtility to compare with
0173   /// @return True if the BinUtilities are equal, false otherwise
0174   bool operator==(const BinUtility& other) const {
0175     return (m_transform.isApprox(other.m_transform) &&
0176             m_binningData == other.binningData());
0177   }
0178 
0179   /// Return the binning data vector
0180   /// @return Reference to the vector of binning data
0181   const std::vector<BinningData>& binningData() const { return m_binningData; }
0182 
0183   /// Return the total number of bins
0184   /// @return Total number of bins across all dimensions
0185   std::size_t bins() const { return bins(0) * bins(1) * bins(2); }
0186 
0187   /// Bin-triple fast access
0188   ///
0189   /// - calculate the bin triple with one transform
0190   ///
0191   /// @param position is the 3D position to be evaluated
0192   ///
0193   /// @return is the bin value in 3D
0194   std::array<std::size_t, 3> binTriple(const Vector3& position) const {
0195     /// transform or not
0196     const Vector3 bPosition = m_itransform * position;
0197     // get the dimension
0198     std::size_t mdim = m_binningData.size();
0199     /// now get the bins
0200     std::size_t bin0 = m_binningData[0].searchGlobal(bPosition);
0201     std::size_t bin1 = mdim > 1 ? m_binningData[1].searchGlobal(bPosition) : 0;
0202     std::size_t bin2 = mdim > 2 ? m_binningData[2].searchGlobal(bPosition) : 0;
0203     /// return the triple
0204     return {{bin0, bin1, bin2}};
0205   }
0206 
0207   /// Bin from a 3D vector (already in binning frame)
0208   ///
0209   /// @param position is the 3D position to be evaluated
0210   /// @param ba is the bin dimension
0211   ///
0212   /// @return is the bin value
0213   std::size_t bin(const Vector3& position, std::size_t ba = 0) const {
0214     if (ba >= m_binningData.size()) {
0215       return 0;
0216     }
0217     std::size_t bEval = m_binningData[ba].searchGlobal(m_itransform * position);
0218     return bEval;
0219   }
0220 
0221   /// Bin from a 2D vector (following local parameters definitions)
0222   /// - no optional transform applied
0223   /// - USE WITH CARE !!
0224   ///
0225   /// You need to make sure that the local position is actually in the binning
0226   /// frame of the BinUtility
0227   ///
0228   /// @param lposition is the local position to be set
0229   /// @param ba is the bin dimension
0230   ///
0231   /// @return bin calculated from local
0232   std::size_t bin(const Vector2& lposition, std::size_t ba = 0) const {
0233     if (ba >= m_binningData.size()) {
0234       return 0;
0235     }
0236     return m_binningData[ba].searchLocal(lposition);
0237   }
0238 
0239   /// Bin from a scalar (following local parameters definitions)
0240   /// - no optional transform applied
0241   /// - USE WITH CARE !!
0242   ///
0243   /// You need to make sure that the local position is actually in the binning
0244   /// frame of the BinUtility
0245   ///
0246   /// @param value is the scalar value to be evaluated
0247   /// @param ba is the bin dimension
0248   ///
0249   /// @return bin calculated from local
0250   std::size_t bin(float value, std::size_t ba = 0) const {
0251     if (ba >= m_binningData.size()) {
0252       return 0;
0253     }
0254     return m_binningData[ba].search(value);
0255   }
0256 
0257   /// Return the other direction for fast interlinking
0258   ///
0259   /// @param position is the global position for the next search
0260   /// @param direction is the global position for the next search
0261   /// @param ba is the bin accessor
0262   ///
0263   /// @todo the
0264   ///
0265   /// @return the next bin
0266   int nextDirection(const Vector3& position, const Vector3& direction,
0267                     std::size_t ba = 0) const {
0268     if (ba >= m_binningData.size()) {
0269       return 0;
0270     }
0271     return m_binningData[ba].nextDirection(position, direction);
0272   }
0273 
0274   /// Check if bin is inside from Vector2 - optional transform applied
0275   ///
0276   /// @param position is the global position to be evaluated
0277   /// @return is a boolean check
0278   bool inside(const Vector3& position) const {
0279     /// transform or not
0280     const Vector3& bPosition = m_itransform * position;
0281     return std::ranges::all_of(m_binningData, [&](const auto& bData) {
0282       return bData.inside(bPosition);
0283     });
0284   }
0285 
0286   /// First bin maximal value
0287   /// @return the dimension of the binning data
0288   std::size_t dimensions() const { return m_binningData.size(); }
0289 
0290   /// First bin maximal value
0291   ///
0292   /// @param ba is the binaccessor
0293   ///
0294   /// @return std::size_t is the maximal bin of the accessor entry
0295   std::size_t max(std::size_t ba = 0) const {
0296     if (ba >= m_binningData.size()) {
0297       return 0;
0298     }
0299     return (m_binningData[ba].bins() - 1);
0300   }
0301 
0302   /// Number of bins
0303   ///
0304   /// @param ba is the binaccessor
0305   ///
0306   /// @return std::size_t is the bins of the accessor entry
0307   std::size_t bins(std::size_t ba) const {
0308     if (ba >= m_binningData.size()) {
0309       return 1;
0310     }
0311     return (m_binningData[ba].bins());
0312   }
0313 
0314   /// Transform applied to global positions before lookup
0315   ///
0316   /// @return Shared pointer to transform
0317   const Transform3& transform() const { return m_transform; }
0318 
0319   /// The type/value of the binning
0320   ///
0321   /// @param ba is the binaccessor
0322   ///
0323   /// @return the binning value of the accessor entry
0324   AxisDirection binningValue(std::size_t ba = 0) const {
0325     if (ba >= m_binningData.size()) {
0326       throw std::runtime_error{"Dimension out of bounds"};
0327     }
0328     return (m_binningData[ba].binvalue);
0329   }
0330 
0331   /// Serialize the bin triple
0332   /// - this creates a simple std::size_t from a triple object
0333   ///
0334   /// @param bin is the bin to be serialized
0335   /// @return Serialized bin index as a single std::size_t value
0336   std::size_t serialize(const std::array<std::size_t, 3>& bin) const {
0337     std::size_t serializedBin = bin[0];
0338     if (m_binningData.size() == 2) {
0339       serializedBin += bin[1] * m_binningData[0].bins();
0340     } else if (m_binningData.size() == 3) {
0341       serializedBin +=
0342           (bin[1] * m_binningData[0].bins() * bin[2] * m_binningData[1].bins());
0343     }
0344     return serializedBin;
0345   }
0346 
0347   /// Output Method for std::ostream, to be overloaded by child classes
0348   ///
0349   /// @param sl is the ostream to be dumped into
0350   /// @param indent the current indentation
0351   ///
0352   /// @return the input stream
0353   std::ostream& toStream(std::ostream& sl,
0354                          const std::string& indent = "") const {
0355     sl << indent << "BinUtility for " << m_binningData.size()
0356        << "- dimensional array:" << std::endl;
0357     for (auto [ibd, bd] : enumerate(m_binningData)) {
0358       sl << indent << "dimension     : " << ibd << std::endl;
0359       sl << bd.toString(indent) << std::endl;
0360     }
0361     return sl;
0362   }
0363 
0364   /// Output into a string
0365   ///
0366   /// @param indent the current indentation
0367   ///
0368   /// @return a string with the stream information
0369   std::string toString(const std::string& indent = "") const {
0370     std::stringstream ss;
0371     toStream(ss, indent);
0372     return ss.str();
0373   }
0374 
0375   /// Overload of << operator for std::ostream for debug output
0376   friend std::ostream& operator<<(std::ostream& sl, const BinUtility& bgen) {
0377     return bgen.toStream(sl);
0378   }
0379 
0380  private:
0381   std::vector<BinningData> m_binningData;  /// vector of BinningData
0382   Transform3 m_transform;                  /// shared transform
0383   Transform3 m_itransform;                 /// unique inverse transform
0384 };
0385 
0386 }  // namespace Acts