Back to home page

EIC code displayed by LXR

 
 

    


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

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/AxisDefinitions.hpp"
0012 #include "Acts/Utilities/IAxis.hpp"
0013 
0014 #include <memory>
0015 #include <optional>
0016 #include <ostream>
0017 #include <string>
0018 #include <variant>
0019 #include <vector>
0020 
0021 namespace Acts {
0022 
0023 /// @brief Axis properties supplied by the consumer of an @c AxisSpec at build
0024 /// time
0025 ///
0026 /// Each property fills in the corresponding one of the spec if that is unset,
0027 /// and validates it otherwise. Spelled @c AxisSpec::Options at the use sites;
0028 /// it only lives at namespace scope so that it is complete where
0029 /// @c AxisSpec::buildAxis defaults it.
0030 struct AxisSpecOptions {
0031   /// Minimum edge of the axis
0032   std::optional<double> min = std::nullopt;
0033   /// Maximum edge of the axis
0034   std::optional<double> max = std::nullopt;
0035   /// Boundary type of the axis
0036   std::optional<AxisBoundaryType> boundaryType = std::nullopt;
0037   /// Direction of the axis
0038   std::optional<AxisDirection> direction = std::nullopt;
0039 };
0040 
0041 /// @brief Variant-like spec of an axis that builds @c IAxis objects
0042 ///
0043 /// Every property except the binning structure itself is optional. What the
0044 /// spec leaves open is supplied by the consumer as @c Options at build time,
0045 /// e.g. from the bounds of the surface the axis is attached to. This models
0046 /// proto material binning, where a configuration may fix the number of bins
0047 /// but not the range, or a range but not whether the axis wraps.
0048 ///
0049 /// Per property the rule is the same: it has to be given by exactly one side,
0050 /// or by both with the same value. Supplying a property that the spec already
0051 /// fixes therefore validates it instead of overriding it, and a property that
0052 /// neither side gives is an error.
0053 class AxisSpec {
0054  public:
0055   /// Axis properties supplied by the consumer at build time
0056   using Options = AxisSpecOptions;
0057 
0058   /// Parameters for an equidistant axis
0059   struct EquidistantParams {
0060     /// Number of bins
0061     std::size_t nBins = 0;
0062     /// Minimum edge of the axis
0063     std::optional<double> min = std::nullopt;
0064     /// Maximum edge of the axis
0065     std::optional<double> max = std::nullopt;
0066 
0067     /// Check if two parameter sets are equal, required for comparing the
0068     /// enclosing spec
0069     /// @param lhs first parameter set
0070     /// @param rhs second parameter set
0071     /// @return true if the parameter sets are equal
0072     friend bool operator==(const EquidistantParams& lhs,
0073                            const EquidistantParams& rhs) = default;
0074   };
0075 
0076   /// Parameters for a variable axis with absolute bin edges
0077   struct VariableParams {
0078     /// Bin edges, strictly increasing
0079     std::vector<double> edges;
0080 
0081     /// Check if two parameter sets are equal, required for comparing the
0082     /// enclosing spec
0083     /// @param lhs first parameter set
0084     /// @param rhs second parameter set
0085     /// @return true if the parameter sets are equal
0086     friend bool operator==(const VariableParams& lhs,
0087                            const VariableParams& rhs) = default;
0088   };
0089 
0090   /// Parameters for a variable axis whose bin edges are relative and scaled
0091   /// onto the range supplied by the consumer
0092   struct DeferredVariableParams {
0093     /// Relative bin edges, strictly increasing, with first value 0 and last
0094     /// value 1
0095     std::vector<double> normalizedEdges;
0096 
0097     /// Check if two parameter sets are equal, required for comparing the
0098     /// enclosing spec
0099     /// @param lhs first parameter set
0100     /// @param rhs second parameter set
0101     /// @return true if the parameter sets are equal
0102     friend bool operator==(const DeferredVariableParams& lhs,
0103                            const DeferredVariableParams& rhs) = default;
0104   };
0105 
0106  private:
0107   /// Underlying variant type
0108   using Variant =
0109       std::variant<EquidistantParams, VariableParams, DeferredVariableParams>;
0110 
0111   /// Construct from variant
0112   /// @param variant the alternative to hold
0113   /// @param boundaryType the optional axis boundary type
0114   /// @param direction the optional axis direction
0115   explicit AxisSpec(Variant variant,
0116                     std::optional<AxisBoundaryType> boundaryType,
0117                     std::optional<AxisDirection> direction);
0118 
0119  public:
0120   /// Equidistant axis; every property but the number of bins may be left to
0121   /// the consumer
0122   /// @param nBins the number of bins
0123   /// @param min the optional minimum edge of the axis
0124   /// @param max the optional maximum edge of the axis
0125   /// @param boundaryType the optional boundary type of the axis
0126   /// @param direction the optional direction of the axis
0127   /// @throws std::invalid_argument if min >= max or nBins == 0
0128   /// @return the equidistant spec
0129   static AxisSpec Equidistant(
0130       std::size_t nBins, std::optional<double> min = std::nullopt,
0131       std::optional<double> max = std::nullopt,
0132       std::optional<AxisBoundaryType> boundaryType = std::nullopt,
0133       std::optional<AxisDirection> direction = std::nullopt);
0134 
0135   /// Equidistant axis with only the number of bins fixed
0136   /// @param nBins the number of bins
0137   /// @param direction the optional direction of the axis
0138   /// @throws std::invalid_argument if nBins == 0
0139   /// @return the equidistant spec
0140   static AxisSpec DeferredEquidistant(
0141       std::size_t nBins, std::optional<AxisDirection> direction = std::nullopt);
0142 
0143   /// Variable axis with absolute bin edges
0144   /// @param edges the bin edges, strictly increasing
0145   /// @param boundaryType the optional boundary type of the axis
0146   /// @param direction the optional direction of the axis
0147   /// @throws std::invalid_argument if fewer than two edges are given or the
0148   ///         edges are not strictly increasing
0149   /// @return the variable spec
0150   static AxisSpec Variable(
0151       std::vector<double> edges,
0152       std::optional<AxisBoundaryType> boundaryType = std::nullopt,
0153       std::optional<AxisDirection> direction = std::nullopt);
0154 
0155   /// Variable axis whose normalized edges are scaled onto the range supplied
0156   /// by the consumer
0157   /// @param normalizedEdges the relative bin edges, strictly increasing, with
0158   ///        first value 0 and last value 1
0159   /// @param boundaryType the optional boundary type of the axis
0160   /// @param direction the optional direction of the axis
0161   /// @throws std::invalid_argument if fewer than two values are given, the
0162   ///         values are not strictly increasing, or the first and last values
0163   ///         are not exactly 0 and 1
0164   /// @return the deferred variable spec
0165   static AxisSpec DeferredVariable(
0166       std::vector<double> normalizedEdges,
0167       std::optional<AxisBoundaryType> boundaryType = std::nullopt,
0168       std::optional<AxisDirection> direction = std::nullopt);
0169 
0170   /// Capture an existing axis as a fully specified spec
0171   /// @param axis the axis to decompose
0172   /// @return the equidistant or variable spec of the given axis, including
0173   ///         its direction if set
0174   static AxisSpec FromAxis(const IAxis& axis);
0175 
0176   /// Get a copy of this spec with the given direction attached
0177   /// @param direction the direction to attach
0178   /// @return the spec with the direction set
0179   AxisSpec withDirection(AxisDirection direction) const;
0180 
0181   /// Get the counterpart that leaves every property to the consumer: an
0182   /// equidistant spec keeps only its number of bins, a variable one its edges
0183   /// normalized to [0, 1]
0184   /// @return the deferred spec
0185   AxisSpec toDeferred() const;
0186 
0187   /// Check if the spec needs @c Options to build, i.e. leaves at least one
0188   /// property to the consumer
0189   /// @return true if the spec is deferred
0190   bool isDeferred() const;
0191 
0192   /// Check if the spec produces an equidistant axis
0193   /// @return true for the equidistant alternative
0194   bool isEquidistant() const;
0195 
0196   /// Check if the spec produces a variable axis
0197   /// @return true for the two variable alternatives
0198   bool isVariable() const;
0199 
0200   /// Check if the spec holds normalized instead of absolute bin edges
0201   /// @return true for the deferred variable alternative
0202   bool isDeferredVariable() const;
0203 
0204   /// Get the number of bins
0205   /// @return the number of bins, defined for all alternatives
0206   std::size_t nBins() const;
0207 
0208   /// Get the boundary type of the axis
0209   /// @return the boundary type if the spec fixes it
0210   std::optional<AxisBoundaryType> boundaryType() const;
0211 
0212   /// Get the direction of the axis
0213   /// @return the direction if the spec fixes it
0214   std::optional<AxisDirection> direction() const;
0215 
0216   /// Get the spec as equidistant parameters
0217   /// @throws std::bad_variant_access if another alternative is held
0218   /// @return reference to the equidistant parameters
0219   const EquidistantParams& asEquidistant() const;
0220 
0221   /// Get the spec as variable parameters
0222   /// @throws std::bad_variant_access if another alternative is held
0223   /// @return reference to the variable parameters
0224   const VariableParams& asVariable() const;
0225 
0226   /// Get the spec as deferred variable parameters
0227   /// @throws std::bad_variant_access if another alternative is held
0228   /// @return reference to the deferred variable parameters
0229   const DeferredVariableParams& asDeferredVariable() const;
0230 
0231   /// Build the axis, filling in the properties the spec leaves open
0232   /// and validating the ones it fixes
0233   /// @param options the properties supplied by the consumer
0234   /// @throws std::domain_error if a property is given by neither side
0235   /// @throws std::invalid_argument if a property is given by both sides with
0236   ///         different values, or the resulting range is invalid
0237   /// @return the created axis
0238   std::unique_ptr<IAxis> buildAxis(const Options& options = {}) const;
0239 
0240   /// Get a string representation of this spec
0241   /// @return the string representation
0242   std::string toString() const;
0243 
0244   /// Check if two specs are equal
0245   /// @param lhs first spec
0246   /// @param rhs second spec
0247   /// @return true if alternative, parameters and direction are equal
0248   friend bool operator==(const AxisSpec& lhs, const AxisSpec& rhs) = default;
0249 
0250   /// Output stream operator
0251   /// @param os output stream
0252   /// @param axisSpec the spec to be printed
0253   /// @return the output stream
0254   friend std::ostream& operator<<(std::ostream& os, const AxisSpec& axisSpec) {
0255     return os << axisSpec.toString();
0256   }
0257 
0258  private:
0259   Variant m_variant;
0260   std::optional<AxisBoundaryType> m_boundaryType;
0261   std::optional<AxisDirection> m_direction;
0262 };
0263 
0264 }  // namespace Acts