Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-26 08:01:31

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 <array>
0012 #include <bit>
0013 #include <cassert>
0014 
0015 namespace Acts {
0016 
0017 namespace Concepts {
0018 
0019 /// @brief check types for requirements needed by interpolation
0020 ///
0021 /// This helper struct provides compile-time information whether the provided
0022 /// @c Point and @c Value types can be used in the Acts::interpolate function.
0023 ///
0024 /// @tparam T type of values to be interpolated
0025 /// @tparam N number of hyper box corners
0026 /// @tparam P1 type for specifying the input point
0027 /// @tparam P2 type for specifying the lower corner of the hyper box
0028 /// @tparam P3 type for specifying the upper corner of the hyper box
0029 template <typename T, std::size_t N, typename P1, typename P2, typename P3>
0030 concept Interpolatable = requires {
0031   std::has_single_bit(N);
0032   {
0033     std::declval<double>() * std::declval<T>() +
0034         std::declval<double>() * std::declval<T>()
0035   } -> std::convertible_to<T>;
0036   { std::declval<P1>()[0] } -> std::convertible_to<double>;
0037   { std::declval<P2>()[0] } -> std::convertible_to<double>;
0038   { std::declval<P3>()[0] } -> std::convertible_to<double>;
0039 };
0040 
0041 }  // namespace Concepts
0042 
0043 /// performs linear interpolation inside a hyper box
0044 ///
0045 /// @tparam T type of values to be interpolated
0046 /// @tparam N number of hyper box corners
0047 /// @tparam Point1 type specifying the input point
0048 /// @tparam Point2 type specifying the lower corner of the hyper box
0049 /// @tparam Point3 type specifying the upper corner of the hyper box
0050 ///
0051 /// @param point point to which to interpolate
0052 /// @param lowerCorner generalized lower-left corner of hyper box
0053 /// (containing the minima of the hyper box along each dimension)
0054 /// @param upperCorner generalized upper-right corner of hyper box
0055 /// (containing the maxima of the hyper box along each dimension)
0056 /// @param values field values at the hyper box corners sorted in the
0057 /// canonical order defined below.
0058 ///
0059 /// @return interpolated value at given point
0060 ///
0061 /// @pre @c point must be inside the given hyper box, that
0062 /// is \f$\text{lowerCorner}[i] \le \text{point}[i] \le
0063 /// \text{upperCorner}[i] \quad \forall i=0, \dots, d-1\f$.
0064 ///
0065 /// @note
0066 /// - Given @c U and @c V of value type @c T as well as two @c double @c a and
0067 /// @c b, then the following must be a valid expression <tt>a * U + b * V</tt>
0068 /// yielding an object which is (implicitly) convertible to @c T.
0069 /// - All @c Point types must represent d-dimensional points and support
0070 /// coordinate access using @c operator[] which should return a @c double (or a
0071 /// value which is implicitly convertible). Coordinate indices must start at 0.
0072 /// - @c N is the number of hyper box corners which is \f$2^d\f$ where \f$d\f$
0073 /// is the dimensionality of the hyper box. The dimensionality must be
0074 /// consistent with the provided @c Point types.
0075 /// - Definition of the canonical order for sorting the field values: The hyper
0076 /// box corners are numbered according to the following scheme. Each corner is
0077 /// defined by the set of lower/upper boundary limits in each dimension @c i.
0078 /// This can be represented by a binary code (from left to right) where a @c 0
0079 /// stands for a lower bound along this axis and a @c 1 stand for the upper
0080 /// bound along this axis. The left most bit corresponds to the first dimension
0081 /// and the bits to the left correspond to the 2nd, 3rd... dimension. The binary
0082 /// code can be interpreted as integer which gives the number of the
0083 /// corresponding hyper box corner. The field values are ordered according to
0084 /// ascending hyper box corner numbers.<br />
0085 /// As an example assume we have a 3D box with @c lowerCorner = (1,2,3) and @c
0086 /// upperCorner = (4,5,6). The eight corners with their bit patterns and corner
0087 /// numbers are:
0088 ///    - (1,2,3): 000 = 0
0089 ///    - (1,2,6): 001 = 1
0090 ///    - (1,5,3): 010 = 2
0091 ///    - (1,5,6): 011 = 3
0092 ///    - (4,2,3): 100 = 4
0093 ///    - (4,2,6): 101 = 5
0094 ///    - (4,5,3): 110 = 6
0095 ///    - (4,5,6): 111 = 7
0096 template <typename T, std::size_t N, class Point1, class Point2 = Point1,
0097           class Point3 = Point2>
0098 T interpolate(const Point1& point, const Point2& lowerCorner,
0099               const Point3& upperCorner, const std::array<T, N>& values)
0100   requires Concepts::Interpolatable<T, N, Point1, Point2, Point3>
0101 {
0102   static constexpr std::size_t D = std::bit_width(N) - 1;
0103   static constexpr std::size_t I = D - 1;
0104 
0105   // get distance to lower boundary relative to total bin width
0106   const double f =
0107       (point[I] - lowerCorner[I]) / (upperCorner[I] - lowerCorner[I]);
0108   assert(f >= 0 && f <= 1 && "point must be inside the given hyper box");
0109 
0110   std::array<T, N / 2> newValues{};
0111   for (std::size_t i = 0; i < N / 2; ++i) {
0112     newValues[i] = (1 - f) * values[2 * i] + f * values[2 * i + 1];
0113   }
0114 
0115   if constexpr (D == 1) {
0116     return newValues[0];
0117   } else {
0118     return interpolate(point, lowerCorner, upperCorner, newValues);
0119   }
0120 }
0121 
0122 }  // namespace Acts