Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-02 07:50:58

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