Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-16 08:16:56

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/Utilities/AxisSpec.hpp"
0012 #include "Acts/Utilities/IMultiAxis.hpp"
0013 
0014 #include <array>
0015 #include <memory>
0016 #include <ostream>
0017 #include <span>
0018 #include <string>
0019 #include <vector>
0020 
0021 namespace Acts {
0022 
0023 class Surface;
0024 
0025 /// @brief Specification of a multi-dimensional binning that builds the axes of
0026 /// a grid
0027 ///
0028 /// Bundles one @c AxisSpec per grid dimension, mirroring the
0029 /// @c IMultiAxis / @c IMultiAxisXD split: the dimension is known at runtime
0030 /// here and at compile time in the derived @c MultiAxisSpecXD . Unlike
0031 /// @c IMultiAxis this is a value type and can be held by configuration
0032 /// objects.
0033 ///
0034 /// The build API mirrors @c AxisSpec : fully specified specs build
0035 /// without input, deferred ones need one @c AxisSpec::Options per axis, in
0036 /// storage order.
0037 class MultiAxisSpec {
0038  public:
0039   /// Consumer supplied inputs, one @c AxisSpec::Options per axis, in axis
0040   /// order
0041   using Options = std::vector<AxisSpec::Options>;
0042 
0043   /// Construct from one axis spec per dimension
0044   /// @param axisSpecs the axis specs, in axis order
0045   /// @throws std::invalid_argument if no axis spec is given
0046   explicit MultiAxisSpec(std::vector<AxisSpec> axisSpecs);
0047 
0048   /// Copy constructor
0049   /// @param other the spec to copy from
0050   MultiAxisSpec(const MultiAxisSpec& other) = default;
0051   /// Move constructor
0052   /// @param other the spec to move from
0053   MultiAxisSpec(MultiAxisSpec&& other) noexcept = default;
0054   /// Copy assignment
0055   /// @param other the spec to copy from
0056   /// @return reference to this
0057   MultiAxisSpec& operator=(const MultiAxisSpec& other) = default;
0058   /// Move assignment
0059   /// @param other the spec to move from
0060   /// @return reference to this
0061   MultiAxisSpec& operator=(MultiAxisSpec&& other) noexcept = default;
0062 
0063   virtual ~MultiAxisSpec() = default;
0064 
0065   /// Get the number of axes spanning the grid
0066   /// @return number of axes (i.e. the dimension of the grid)
0067   std::size_t size() const;
0068 
0069   /// Get the axis spec at the given dimension
0070   /// @param i index of the axis
0071   /// @return const reference to the requested axis spec
0072   const AxisSpec& axisSpec(std::size_t i) const;
0073 
0074   /// Get all axis specs
0075   /// @return view onto the axis specs, in axis order
0076   std::span<const AxisSpec> axisSpecs() const;
0077 
0078   /// Check if any of the contained specs is deferred, i.e. requires
0079   /// consumer supplied options to produce axes
0080   /// @return true if any axis spec is deferred
0081   bool isDeferred() const;
0082 
0083   /// Build a multi-axis, one option set per axis or none at all
0084   /// @param options one option set per axis, in axis order, or empty
0085   /// @throws std::domain_error if a property is given by neither side, or the
0086   ///         dimension exceeds the supported maximum of 3
0087   /// @throws std::invalid_argument if the number of option sets is neither
0088   ///         zero nor the number of axes, or a property mismatches
0089   /// @return the created multi-axis
0090   std::unique_ptr<IMultiAxis> buildMultiAxis(const Options& options = {}) const;
0091 
0092  protected:
0093   /// Build a multi-axis from a view onto the option sets
0094   /// @param options one option set per axis, in axis order, or empty
0095   /// @return the created multi-axis
0096   std::unique_ptr<IMultiAxis> buildMultiAxisImpl(
0097       std::span<const AxisSpec::Options> options) const;
0098 
0099  public:
0100   /// Get a string representation of this spec
0101   /// @return the string representation
0102   std::string toString() const;
0103 
0104   /// Check if two specs are equal
0105   /// @param lhs first spec
0106   /// @param rhs second spec
0107   /// @return true if all axis specs are equal
0108   friend bool operator==(const MultiAxisSpec& lhs,
0109                          const MultiAxisSpec& rhs) = default;
0110 
0111   /// Output stream operator
0112   /// @param os output stream
0113   /// @param multiAxisSpec the spec to be printed
0114   /// @return the output stream
0115   friend std::ostream& operator<<(std::ostream& os,
0116                                   const MultiAxisSpec& multiAxisSpec) {
0117     return os << multiAxisSpec.toString();
0118   }
0119 
0120  private:
0121   std::vector<AxisSpec> m_axisSpecs;
0122 };
0123 
0124 /// @brief Multi-dimensional binning spec of a compile-time dimension
0125 ///
0126 /// Adds a statically sized construction and build API on top of
0127 /// @c MultiAxisSpec , mirroring @c IMultiAxis and @c IMultiAxisXD .
0128 ///
0129 /// @tparam DIM number of axes (dimension of the grid)
0130 template <std::size_t DIM>
0131 class MultiAxisSpecXD : public MultiAxisSpec {
0132  public:
0133   static_assert(DIM >= 1 && DIM <= 3,
0134                 "MultiAxisSpecXD supports 1 to 3 dimensions");
0135 
0136   /// Construct from one axis spec per dimension
0137   /// @param axisSpecs the axis specs, in axis order
0138   explicit MultiAxisSpecXD(std::array<AxisSpec, DIM> axisSpecs)
0139       : MultiAxisSpec(
0140             std::vector<AxisSpec>(std::make_move_iterator(axisSpecs.begin()),
0141                                   std::make_move_iterator(axisSpecs.end()))) {}
0142 
0143   /// Consumer supplied inputs, one @c AxisSpec::Options per axis, in axis
0144   /// order; an all-default set leaves every property to the spec
0145   using Options = std::array<AxisSpec::Options, DIM>;
0146 
0147   /// Build a multi-axis, one option set per axis
0148   /// @param options one option set per axis, in axis order
0149   /// @throws std::domain_error if a property is given by neither side
0150   /// @throws std::invalid_argument if a property mismatches
0151   /// @return the created multi-axis of dimension @c DIM
0152   std::unique_ptr<IMultiAxisXD<DIM>> buildMultiAxis(
0153       const Options& options = {}) const {
0154     return downcast(buildMultiAxisImpl(options));
0155   }
0156 
0157  private:
0158   /// Downcast a runtime-dimension multi-axis to the compile-time dimension
0159   /// @param multiAxis the multi-axis to downcast
0160   /// @return the downcasted multi-axis
0161   static std::unique_ptr<IMultiAxisXD<DIM>> downcast(
0162       std::unique_ptr<IMultiAxis> multiAxis) {
0163     auto* xd = dynamic_cast<IMultiAxisXD<DIM>*>(multiAxis.get());
0164     if (xd == nullptr) {
0165       throw std::logic_error(
0166           "MultiAxisSpecXD: unexpected multi-axis dimension");
0167     }
0168     multiAxis.release();
0169     return std::unique_ptr<IMultiAxisXD<DIM>>(xd);
0170   }
0171 };
0172 
0173 /// Type alias for a multi-axis spec of dimension 1
0174 using MultiAxisSpec1D = MultiAxisSpecXD<1>;
0175 /// Type alias for a multi-axis spec of dimension 2
0176 using MultiAxisSpec2D = MultiAxisSpecXD<2>;
0177 
0178 /// @brief Build the multi-axis of a surface binning against that surface
0179 ///
0180 /// A surface spans two local coordinates, so the binning is strictly
0181 /// two-dimensional; use a single bin in one direction to bin along the other
0182 /// only. Both specs are matched to the canonical local axis directions
0183 /// of the surface (see @c Surface::localAxes ), either positionally if
0184 /// neither carries a direction, or by direction if both do. Mixing the two is
0185 /// rejected. The axes are returned in canonical direction order.
0186 ///
0187 /// @param multiAxisSpec the binning spec to build from
0188 /// @param surface the surface to resolve the ranges against
0189 /// @throws std::invalid_argument if the directions cannot be matched or the
0190 ///         surface is unsupported
0191 /// @throws std::domain_error if any spec is fully specified instead
0192 ///         of deferred
0193 /// @return the created multi-axis, in canonical direction order
0194 std::unique_ptr<IMultiAxis2D> resolveMultiAxis(
0195     const MultiAxisSpec2D& multiAxisSpec, const Surface& surface);
0196 
0197 }  // namespace Acts