Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:02:03

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/PointerTraits.hpp"
0013 
0014 #include <algorithm>
0015 #include <array>
0016 #include <iostream>
0017 #include <limits>
0018 #include <memory>
0019 #include <type_traits>
0020 #include <vector>
0021 
0022 #define ACTS_CHECK_BIT(value, mask) ((value & mask) == mask)
0023 
0024 namespace Acts {
0025 
0026 /// Helper function to unpack a vector of smart pointers (e.g. @c shared_ptr ) into a vector of raw
0027 /// const pointers
0028 /// @tparam T the stored type
0029 /// @param items The vector of smart pointers
0030 /// @return The unpacked vector
0031 
0032 template <SmartPointerConcept T>
0033 std::vector<std::add_pointer_t<std::add_const_t<typename T::element_type>>>
0034 unpackConstSmartPointers(const std::vector<T>& items) {
0035   std::vector<std::add_pointer_t<std::add_const_t<typename T::element_type>>>
0036       rawPtrs{};
0037   rawPtrs.reserve(items.size());
0038   for (const auto& ptr : items) {
0039     rawPtrs.push_back(ptr.operator->());
0040   }
0041   return rawPtrs;
0042 }
0043 
0044 /// Helper function to unpack a vector of @c shared_ptr into a vector of raw
0045 /// pointers
0046 /// @tparam T the stored type
0047 /// @param items The vector of @c shared_ptr
0048 /// @return The unpacked vector
0049 template <SmartPointerConcept T>
0050 std::vector<std::add_pointer_t<typename T::element_type>> unpackSmartPointers(
0051     const std::vector<T>& items) {
0052   std::vector<std::add_pointer_t<typename T::element_type>> rawPtrs{};
0053   rawPtrs.reserve(items.size());
0054   for (const auto& ptr : items) {
0055     rawPtrs.push_back(&*ptr);
0056   }
0057   return rawPtrs;
0058 }
0059 
0060 /// Helper function to unpack a vector of @c shared_ptr into a vector of raw
0061 /// pointers (const version)
0062 /// @tparam T the stored type
0063 /// @param items The vector of @c shared_ptr
0064 /// @return The unpacked vector
0065 template <typename T>
0066 std::vector<const T*> unpackSmartPointers(
0067     const std::vector<std::shared_ptr<const T>>& items) {
0068   std::vector<const T*> rawPtrs;
0069   rawPtrs.reserve(items.size());
0070   for (const std::shared_ptr<const T>& item : items) {
0071     rawPtrs.push_back(item.get());
0072   }
0073   return rawPtrs;
0074 }
0075 
0076 /// @brief Converts a vector to a fixed-size array with truncating or padding.
0077 ///
0078 /// This function copies elements from the input vector into a fixed-size array.
0079 /// If the vector contains more than `kDIM` elements, the array is truncated to
0080 /// fit. If the vector contains fewer elements than `kDIM`, the remaining array
0081 /// elements are value-initialized (default-initialized, i.e., filled with zero
0082 /// or default values).
0083 ///
0084 /// @tparam kDIM The size of the resulting array.
0085 /// @tparam value_t The type of elements in the vector and the array.
0086 /// @param vecvals The input vector to be converted to an array.
0087 ///
0088 /// @return An array containing the first `kDIM` elements of the vector.
0089 template <std::size_t kDIM, typename value_t>
0090 std::array<value_t, kDIM> toArray(const std::vector<value_t>& vecvals) {
0091   std::array<value_t, kDIM> arr = {};
0092   std::copy_n(vecvals.begin(), std::min(vecvals.size(), kDIM), arr.begin());
0093   return arr;
0094 }
0095 
0096 /// @brief Dispatch a call based on a runtime value on a function taking the
0097 /// value at compile time.
0098 ///
0099 /// This function allows to write a templated functor, which accepts a @c std::size_t
0100 /// like parameter at compile time. It is then possible to make a call to the
0101 /// corresponding instance of the functor based on a runtime value. To achieve
0102 /// this, the function essentially created a if cascade between @c N and @c
0103 /// NMAX, attempting to find the right instance. Because the cascade is visible
0104 /// to the compiler entirely, it should be able to optimize.
0105 ///
0106 /// @tparam Callable Type which takes a std::size_t as a compile time param
0107 /// @tparam N Value from which to start the dispatch chain, i.e. 0 in most cases
0108 /// @tparam NMAX Maximum value up to which to attempt a dispatch
0109 /// @param v The runtime value to dispatch on
0110 /// @param args Additional arguments passed to @c Callable::invoke().
0111 /// @note @c Callable is expected to have a static member function @c invoke
0112 /// that is callable with @c Args
0113 template <template <std::size_t> class Callable, std::size_t N,
0114           std::size_t NMAX, typename... Args>
0115 auto template_switch(std::size_t v, Args&&... args) {
0116   if (v == N) {
0117     return Callable<N>::invoke(std::forward<Args>(args)...);
0118   }
0119   if (v == 0) {
0120     std::cerr << "template_switch<Fn, " << N << ", " << NMAX << ">(v=" << v
0121               << ") is not valid (v == 0 and N != 0)" << std::endl;
0122     std::abort();
0123   }
0124   if constexpr (N < NMAX) {
0125     return template_switch<Callable, N + 1, NMAX>(v,
0126                                                   std::forward<Args>(args)...);
0127   }
0128   std::cerr << "template_switch<Fn, " << N << ", " << NMAX << ">(v=" << v
0129             << ") is not valid (v > NMAX)" << std::endl;
0130   std::abort();
0131 }
0132 
0133 /// Alternative version of @c template_switch which accepts a generic
0134 /// lambda and communicates the dimension via an integral constant type
0135 /// @tparam N Value from which to start the dispatch chain, i.e. 0 in most cases
0136 /// @tparam NMAX Maximum value up to which to attempt a dispatch
0137 /// @param v The runtime value to dispatch on
0138 /// @param func The lambda to invoke
0139 /// @param args Additional arguments passed to @p func
0140 template <std::size_t N, std::size_t NMAX, typename Lambda, typename... Args>
0141 auto template_switch_lambda(std::size_t v, Lambda&& func, Args&&... args) {
0142   if (v == N) {
0143     return func(std::integral_constant<std::size_t, N>{},
0144                 std::forward<Args>(args)...);
0145   }
0146   if (v == 0) {
0147     std::cerr << "template_switch<Fn, " << N << ", " << NMAX << ">(v=" << v
0148               << ") is not valid (v == 0 and N != 0)" << std::endl;
0149     std::abort();
0150   }
0151   if constexpr (N < NMAX) {
0152     return template_switch_lambda<N + 1, NMAX>(v, func,
0153                                                std::forward<Args>(args)...);
0154   }
0155   std::cerr << "template_switch<Fn, " << N << ", " << NMAX << ">(v=" << v
0156             << ") is not valid (v > NMAX)" << std::endl;
0157   std::abort();
0158 }
0159 
0160 /// Clamp a numeric value to another type, respecting range of the target type
0161 /// @tparam T the target type
0162 /// @tparam U the source type
0163 /// @param value the value to clamp
0164 /// @return the clamped value
0165 template <typename T, typename U>
0166 T clampValue(U value) {
0167   return std::clamp(value, static_cast<U>(std::numeric_limits<T>::lowest()),
0168                     static_cast<U>(std::numeric_limits<T>::max()));
0169 }
0170 
0171 /// Return range and medium of an unsorted numeric series
0172 ///
0173 /// @tparam T a numeric series
0174 ///
0175 /// @param tseries is the number series
0176 ///
0177 /// @return [ range, medium ] in an tuple
0178 template <typename T>
0179 std::tuple<typename T::value_type, double> range_medium(const T& tseries) {
0180   auto [minIt, maxIt] = std::ranges::minmax_element(tseries);
0181   typename T::value_type range = (*maxIt - *minIt);
0182   double medium = static_cast<double>((*maxIt + *minIt) * 0.5);
0183   return {range, medium};
0184 }
0185 
0186 template <typename enum_t>
0187 constexpr std::underlying_type_t<enum_t> toUnderlying(enum_t value) {
0188   return static_cast<std::underlying_type_t<enum_t>>(value);
0189 }
0190 
0191 /// This can be replaced with C++23 to use the std::ranges::contains method
0192 ///
0193 /// This function searches through the given range for a specified value
0194 /// and returns `true` if the value is found, or `false` otherwise.
0195 ///
0196 /// @tparam R The type of the range (e.g., vector, list, array).
0197 /// @tparam T The type of the value to search for within the range.
0198 ///
0199 /// @param range The range to search within. This can be any range-compatible container.
0200 /// @param value The value to search for in the range.
0201 ///
0202 /// @return `true` if the value is found within the range, `false` otherwise.
0203 template <typename R, typename T>
0204 bool rangeContainsValue(const R& range, const T& value) {
0205   return std::ranges::find(range, value) != std::ranges::end(range);
0206 }
0207 
0208 /// Helper struct that can turn a set of lambdas into a single entity with
0209 /// overloaded call operator. This can be useful for example in a std::visit
0210 /// call.
0211 /// ```cpp
0212 /// std::visit(overloaded{
0213 ///  [](const int& i) { std::cout << "int: " << i << std::endl; },
0214 ///  [](const std::string& s) { std::cout << "string: " << s << std::endl; },
0215 /// }, variant);
0216 /// ```
0217 template <class... Ts>
0218 struct overloaded : Ts... {
0219   using Ts::operator()...;
0220 };
0221 
0222 template <class... Ts>
0223 overloaded(Ts...) -> overloaded<Ts...>;
0224 
0225 namespace detail {
0226 
0227 /// Computes the minimum, maximum, and bin count for a given vector of values.
0228 ///
0229 /// This function processes a vector of doubles to compute:
0230 /// - The minimum value (@c xMin)
0231 /// - The maximum value (@c xMax), adjusted to include an additional bin
0232 /// - The bin count (@c xBinCount) based on the number of unique values
0233 ///
0234 /// The computation is performed as follows:
0235 /// 1. Sorts the input vector using @c std::ranges::sort to prepare for uniqueness.
0236 /// 2. Determines the number of unique values using @c std::unique and calculates the bin count.
0237 /// 3. Calculates the minimum and maximum using @c std::ranges::minmax.
0238 /// 4. Adjusts the maximum to include an additional bin by adding the bin step
0239 /// size.
0240 ///
0241 /// @param xPos A reference to a vector of doubles.
0242 /// @return A tuple containing:
0243 ///         - The minimum value (double)
0244 ///         - The adjusted maximum value (double)
0245 ///         - The bin count (std::size_t)
0246 ///
0247 /// @note The vector xPos will be modified during the call.
0248 inline auto getMinMaxAndBinCount(std::vector<double>& xPos) {
0249   // sort the values for unique()
0250   std::ranges::sort(xPos);
0251 
0252   // get the number of bins over unique values
0253   auto it = std::unique(xPos.begin(), xPos.end());
0254   const std::size_t xBinCount = std::distance(xPos.begin(), it);
0255 
0256   // get the minimum and maximum
0257   auto [xMin, xMax] = std::ranges::minmax(xPos);
0258 
0259   // calculate maxima (add one last bin, because bin value always corresponds to
0260   // left boundary)
0261   const double stepX = (xMax - xMin) / static_cast<double>(xBinCount - 1);
0262   xMax += stepX;
0263 
0264   // Return all values as a tuple
0265   return std::make_tuple(xMin, xMax, xBinCount);
0266 }
0267 
0268 }  // namespace detail
0269 
0270 }  // namespace Acts