Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-26 08:22:01

0001 /** TRACCC library, part of the ACTS project (R&D line)
0002  *
0003  * (c) 2020-2026 CERN for the benefit of the ACTS project
0004  *
0005  * Mozilla Public License Version 2.0
0006  */
0007 
0008 #pragma once
0009 
0010 // Project include(s).
0011 #include "traccc/definitions/primitives.hpp"
0012 #include "traccc/definitions/qualifiers.hpp"
0013 
0014 // Detray include(s)
0015 #include <detray/utils/concepts.hpp>
0016 
0017 // VecMem include(s).
0018 #include <vecmem/containers/data/vector_view.hpp>
0019 #include <vecmem/containers/device_vector.hpp>
0020 #include <vecmem/memory/memory_resource.hpp>
0021 
0022 // System include(s).
0023 #include <algorithm>
0024 #include <cstddef>
0025 #include <type_traits>
0026 
0027 namespace traccc {
0028 
0029 namespace axis2 {
0030 
0031 /** A regular closed axis.
0032  *
0033  * The axis is closed, i.e. each underflow bin is mapped to 0
0034  * and henceforth each overflow bin is mapped to bins-1
0035  */
0036 template <template <typename, std::size_t> class array_t = std::array,
0037           template <typename...> class vector_t = vecmem::vector>
0038 struct regular {
0039   unsigned int n_bins;
0040   scalar min;
0041   scalar max;
0042 
0043   static constexpr unsigned int axis_identifier = 0u;
0044 
0045   /** Defualt constructor for dummy axis **/
0046   DETRAY_HOST_DEVICE
0047   regular()
0048       : n_bins(std::numeric_limits<unsigned int>::max()),
0049         min(static_cast<scalar>(0.)),
0050         max(static_cast<scalar>(n_bins)) {}
0051 
0052   /** Constructor with vecmem memory resource **/
0053   DETRAY_HOST
0054   explicit regular(vecmem::memory_resource & /*resource*/)
0055       : n_bins(std::numeric_limits<unsigned int>::max()),
0056         min(static_cast<scalar>(0.)),
0057         max(static_cast<scalar>(n_bins)) {}
0058 
0059   /** Constructor with vecmem memory resource **/
0060   DETRAY_HOST
0061   regular(unsigned int axis_bins, scalar axis_min, scalar axis_max,
0062           vecmem::memory_resource & /*resource*/)
0063       : n_bins(axis_bins), min(axis_min), max(axis_max) {}
0064 
0065   /** Constructor with vecmem memory resource **/
0066   DETRAY_HOST
0067   regular(const regular &axis, vecmem::memory_resource & /*resource*/)
0068       : n_bins(axis.n_bins), min(axis.min), max(axis.max) {}
0069 
0070   /** Constructor with axis_data **/
0071   template <typename axis_data_t>
0072     requires(!std::is_same_v<regular, axis_data_t>)
0073   DETRAY_HOST_DEVICE explicit regular(const axis_data_t &axis_data)
0074       : n_bins(axis_data.n_bins), min(axis_data.min), max(axis_data.max) {}
0075 
0076   /** Return the number of bins */
0077   DETRAY_HOST_DEVICE
0078   unsigned int bins() const { return n_bins; }
0079 
0080   /** Access function to a single bin from a value v
0081    *
0082    * @param v is the value for the bin search
0083    *
0084    * As the axis is closed it @returns a unsigned int type
0085    **/
0086   DETRAY_HOST_DEVICE
0087   unsigned int bin(scalar v) const {
0088     auto ibin =
0089         static_cast<int>((v - min) / (max - min) * static_cast<scalar>(n_bins));
0090     if (ibin >= 0 && ibin < static_cast<int>(n_bins)) {
0091       return static_cast<unsigned int>(ibin);
0092     } else {
0093       if (ibin < 0) {
0094         return 0;
0095       } else {
0096         return n_bins - 1u;
0097       }
0098     }
0099   }
0100 
0101   /** Access function to a range with binned neighborhood
0102    *
0103    * @param v is the value for the bin search
0104    * @param nhood is the neighborhood range (in #bins)
0105    *
0106    * As the axis is closed it @returns an index range
0107    **/
0108   DETRAY_HOST_DEVICE
0109   std::array<unsigned int, 2> range(scalar v,
0110                                     const array_t<unsigned int, 2> &nhood = {
0111                                         0u, 0u}) const {
0112     auto ibin =
0113         static_cast<int>((v - min) / (max - min) * static_cast<scalar>(n_bins));
0114     int ibinmin = ibin - static_cast<int>(nhood[0]);
0115     int ibinmax = ibin + static_cast<int>(nhood[1]);
0116     unsigned int min_bin =
0117         (ibinmin >= 0) ? static_cast<unsigned int>(ibinmin) : 0u;
0118     unsigned int max_bin = (ibinmax < static_cast<int>(n_bins))
0119                                ? static_cast<unsigned int>(ibinmax)
0120                                : n_bins - 1u;
0121     return {min_bin, max_bin};
0122   }
0123 
0124   /** Access function to a range with scalar neighborhood
0125    *
0126    * @param v is the value for the bin search
0127    * @param nhood is the neighborhood range (scalar)
0128    *
0129    * As the axis is closed it @returns an index range
0130    **/
0131   DETRAY_HOST_DEVICE
0132   std::array<unsigned int, 2> range(scalar v,
0133                                     const array_t<scalar, 2> &nhood) const {
0134     auto nbin = static_cast<int>((v - nhood[0] - min) / (max - min) *
0135                                  static_cast<scalar>(n_bins));
0136     auto pbin = static_cast<int>((v + nhood[1] - min) / (max - min) *
0137                                  static_cast<scalar>(n_bins));
0138     unsigned int min_bin = (nbin >= 0) ? static_cast<unsigned int>(nbin) : 0u;
0139     unsigned int max_bin = (pbin < static_cast<int>(n_bins))
0140                                ? static_cast<unsigned int>(pbin)
0141                                : n_bins - 1;
0142     return {min_bin, max_bin};
0143   }
0144 
0145   /** Access function to a zone with binned neighborhood
0146    *
0147    *
0148    * @tparam neighbor_t is the neighborhood size
0149    *
0150    * @param v is the value for the bin search
0151    * @param nhood is the neighborhood range (in #bins)
0152    *
0153    * As the axis is closed it @returns an index sequence
0154    **/
0155   template <typename neighbor_t>
0156   DETRAY_HOST_DEVICE vecmem::vector<unsigned int> zone_t(
0157       scalar v, const array_t<neighbor_t, 2> &nhood) const {
0158     std::array<unsigned int, 2> nh_range = range(v, nhood);
0159     vecmem::vector<unsigned int> sequence(
0160         static_cast<vecmem::vector<unsigned int>::size_type>(nh_range[1] -
0161                                                              nh_range[0] + 1u),
0162         nh_range[0]);
0163     unsigned int m = 0u;
0164     std::ranges::for_each(sequence, [&](auto &n) { n += m++; });
0165     return sequence;
0166   }
0167 
0168   /** Access function to a zone with binned neighborhood
0169    *
0170    * @param v is the value for the bin search
0171    * @param nhood is the neighborhood range (#bins)
0172    *
0173    * As the axis is closed it @returns an index sequence
0174    **/
0175   DETRAY_HOST_DEVICE
0176   vecmem::vector<unsigned int> zone(
0177       scalar v, const array_t<unsigned int, 2> &nhood) const {
0178     return zone_t<unsigned int>(v, nhood);
0179   }
0180 
0181   /** Access function to a zone with scalar neighborhood
0182    *
0183    * @param v is the value for the bin search
0184    * @param nhood is the neighborhood range (scalar)
0185    *
0186    * As the axis is closed it @returns an index sequence
0187    **/
0188   DETRAY_HOST_DEVICE
0189   vecmem::vector<unsigned int> zone(scalar v,
0190                                     const array_t<scalar, 2> &nhood) const {
0191     return zone_t<scalar>(v, nhood);
0192   }
0193 
0194   /** @return the bin boundaries for a given @param ibin */
0195   DETRAY_HOST_DEVICE
0196   array_t<scalar, 2> borders(unsigned int ibin) const {
0197     scalar step = (max - min) / static_cast<scalar>(n_bins);
0198     return {min + static_cast<scalar>(ibin) * step,
0199             min + static_cast<scalar>(ibin + 1u) * step};
0200   }
0201 
0202   /** @return the values of the borders */
0203   DETRAY_HOST_DEVICE
0204   vector_t<scalar> all_borders() const {
0205     vector_t<scalar> borders;
0206     borders.reserve(n_bins + 1u);
0207     scalar step = (max - min) / static_cast<scalar>(n_bins);
0208     for (unsigned int ib = 0u; ib < n_bins + 1u; ++ib) {
0209       borders.push_back(min + static_cast<scalar>(ib) * step);
0210     }
0211     return borders;
0212   }
0213 
0214   /** @return the axis span [min, max) */
0215   DETRAY_HOST_DEVICE
0216   array_t<scalar, 2> span() const { return {min, max}; }
0217 };
0218 
0219 /** A regular circular axis.
0220  *
0221  * The axis is circular, i.e. the underflow bins map into the circular sequence
0222  */
0223 template <template <typename, std::size_t> class array_t = std::array,
0224           template <typename...> class vector_t = vecmem::vector>
0225 struct circular {
0226   unsigned int n_bins;
0227   scalar min;
0228   scalar max;
0229 
0230   static constexpr unsigned int axis_identifier = 1u;
0231 
0232   /** Defualt constructor for dummy axis **/
0233   DETRAY_HOST_DEVICE
0234   circular()
0235       : n_bins(std::numeric_limits<unsigned int>::max()),
0236         min(static_cast<scalar>(0.)),
0237         max(static_cast<scalar>(n_bins)) {}
0238 
0239   /** Constructor with vecmem memory resource **/
0240   DETRAY_HOST
0241   explicit circular(vecmem::memory_resource & /*resource*/)
0242       : n_bins(std::numeric_limits<unsigned int>::max()),
0243         min(static_cast<scalar>(0.)),
0244         max(static_cast<scalar>(n_bins)) {}
0245 
0246   /** Constructor with vecmem memory resource **/
0247   DETRAY_HOST
0248   circular(unsigned int axis_bins, scalar axis_min, scalar axis_max,
0249            vecmem::memory_resource & /*resource*/)
0250       : n_bins(axis_bins), min(axis_min), max(axis_max) {}
0251 
0252   /** Constructor with vecmem memory resource **/
0253   DETRAY_HOST
0254   circular(const circular &axis, vecmem::memory_resource & /*resource*/)
0255       : n_bins(axis.n_bins), min(axis.min), max(axis.max) {}
0256 
0257   /** Constructor with axis_data **/
0258   template <typename axis_data_t>
0259     requires(!std::is_same_v<circular, axis_data_t>)
0260   DETRAY_HOST_DEVICE explicit circular(const axis_data_t &axis_data)
0261       : n_bins(axis_data.n_bins), min(axis_data.min), max(axis_data.max) {}
0262 
0263   /** Return the number of bins */
0264   DETRAY_HOST_DEVICE
0265   unsigned int bins() const { return n_bins; }
0266 
0267   /** Access function to a single bin from a value v
0268    *
0269    * @param v is the value for the bin search
0270    *
0271    * As the axis is closed it @returns an index
0272    **/
0273   DETRAY_HOST_DEVICE
0274   unsigned int bin(scalar v) const {
0275     auto ibin =
0276         static_cast<int>((v - min) / (max - min) * static_cast<scalar>(n_bins));
0277     if (ibin >= 0 && ibin < static_cast<int>(n_bins)) {
0278       return static_cast<unsigned int>(ibin);
0279     } else {
0280       if (ibin < 0) {
0281         return n_bins + static_cast<unsigned int>(ibin);
0282       } else {
0283         return static_cast<unsigned int>(ibin) - n_bins;
0284       }
0285     }
0286   }
0287 
0288   /** Access function to a range with binned neighborhood
0289    *
0290    * @param v is the value for the bin search
0291    * @param nhood is the  neighborhood range (in #bins)
0292    *
0293    * As the axis is circular it @returns an index range
0294    **/
0295   DETRAY_HOST_DEVICE
0296   std::array<unsigned int, 2> range(scalar v,
0297                                     const array_t<unsigned int, 2> nhood = {
0298                                         0u, 0u}) const {
0299     unsigned int gbin = bin(v);
0300     unsigned int min_bin = remap(gbin, -static_cast<int>(nhood[0]));
0301     unsigned int max_bin = remap(gbin, static_cast<int>(nhood[1]));
0302     return {min_bin, max_bin};
0303   }
0304 
0305   /** Access function to a range with scalar neighborhood
0306    *
0307    * @param v is the value for the bin search
0308    * @param nhood is the neighborhood range (scalar)
0309    *
0310    * As the axis is circular it @returns an index range
0311    **/
0312   DETRAY_HOST_DEVICE
0313   std::array<unsigned int, 2> range(scalar v,
0314                                     const array_t<scalar, 2> &nhood) const {
0315     unsigned int nbin = bin(v - nhood[0]);
0316     unsigned int pbin = bin(v + nhood[1]);
0317     return {nbin, pbin};
0318   }
0319 
0320   /** Access function to a zone with binned/scalar neighborhood
0321    *
0322    * @tparam neighbor_t is the neighborhood size
0323    *
0324    * @param v is the value for the bin search
0325    * @param nhood is the neighborhood range (in #bins/scalar)
0326    *
0327    * As the axis is closed it @returns an index sequence
0328    **/
0329   template <typename neighbor_t>
0330   DETRAY_HOST_DEVICE vecmem::vector<unsigned int> zone_t(
0331       scalar v, const array_t<neighbor_t, 2> &nhood) const {
0332     std::array<unsigned int, 2> nh_range = range(v, nhood);
0333     if (nh_range[0] < nh_range[1]) {
0334       vecmem::vector<unsigned int> sequence(
0335           static_cast<vecmem::vector<unsigned int>::size_type>(
0336               nh_range[1] - nh_range[0] + 1u),
0337           nh_range[0]);
0338       unsigned int m = 0;
0339       std::ranges::for_each(sequence, [&](auto &n) { n += m++; });
0340       return sequence;
0341     }
0342     unsigned int vl = n_bins - nh_range[0] + nh_range[1] + 1u;
0343     unsigned int mi = 0;
0344     unsigned int mo = 0;
0345     vecmem::vector<unsigned int> sequence(
0346         static_cast<vecmem::vector<unsigned int>::size_type>(vl), nh_range[0]);
0347     std::ranges::for_each(sequence, [&](auto &n) {
0348       n += mi++;
0349       if (n > n_bins - 1u) {
0350         n = mo++;
0351       }
0352     });
0353     return sequence;
0354   }
0355 
0356   /** Access function to a zone with binned neighborhood
0357    *
0358    * @param v is the value for the bin search
0359    * @param nhood is the neighborhood range (#bins)
0360    *
0361    * As the axis is closed it @returns an index sequence
0362    **/
0363   DETRAY_HOST_DEVICE
0364   vecmem::vector<unsigned int> zone(
0365       scalar v, const array_t<unsigned int, 2> &nhood) const {
0366     return zone_t<unsigned int>(v, nhood);
0367   }
0368 
0369   /** Access function to a zone with scalar neighborhood
0370    *
0371    * @param v is the value for the bin search
0372    * @param nhood is the neighborhood range (scalar)
0373    *
0374    * As the axis is closed it @returns an index sequence
0375    **/
0376   DETRAY_HOST_DEVICE
0377   vecmem::vector<unsigned int> zone(scalar v,
0378                                     const array_t<scalar, 2> &nhood) const {
0379     return zone_t<scalar>(v, nhood);
0380   }
0381 
0382   /** Helper function to remap onto a circular range
0383    *
0384    * @param ibin is the optional binning value
0385    * @param shood is the sided neighbour hood
0386    *
0387    * @return an index, remapped bin
0388    **/
0389   DETRAY_HOST_DEVICE
0390   unsigned int remap(unsigned int ibin, int shood) const {
0391     int opt_bin = static_cast<int>(ibin) + shood;
0392     if (opt_bin >= 0 && opt_bin < static_cast<int>(n_bins)) {
0393       return static_cast<unsigned int>(opt_bin);
0394     }
0395     if (opt_bin < 0) {
0396       return static_cast<unsigned int>(static_cast<int>(n_bins) + opt_bin);
0397     }
0398     return static_cast<unsigned int>(opt_bin) - n_bins;
0399   }
0400 
0401   /** @return the bin boundaries for a given @param ibin */
0402   DETRAY_HOST_DEVICE
0403   array_t<scalar, 2> borders(unsigned int ibin) const {
0404     scalar step = (max - min) / n_bins;
0405     return {min + static_cast<scalar>(ibin) * step,
0406             min + static_cast<scalar>(ibin + 1u) * step};
0407   }
0408 
0409   /** @return the values of the borders */
0410   DETRAY_HOST_DEVICE
0411   vector_t<scalar> all_borders() const {
0412     vector_t<scalar> borders;
0413     borders.reserve(n_bins + 1u);
0414     scalar step = (max - min) / static_cast<scalar>(n_bins);
0415     for (unsigned int ib = 0u; ib < n_bins + 1u; ++ib) {
0416       borders.push_back(min + static_cast<scalar>(ib) * step);
0417     }
0418     return borders;
0419   }
0420 
0421   /** @return the range  */
0422   DETRAY_HOST_DEVICE
0423   array_t<scalar, 2> span() const { return {min, max}; }
0424 };
0425 
0426 /** An iregular circular axis.
0427  *
0428  * The axis is closed, i.e. the underflow is mapped into the first,
0429  * the overflow is mapped into the last.
0430  */
0431 template <template <typename, std::size_t> class array_t = std::array,
0432           template <typename...> class vector_t = vecmem::vector>
0433 struct irregular {
0434   /* dummy bin size, min and max */
0435   unsigned int n_bins;
0436   scalar min;
0437   scalar max;
0438 
0439   vector_t<scalar> boundaries;
0440 
0441   static constexpr unsigned int axis_identifier = 2u;
0442 
0443   /** Defualt constructor for dummy axis **/
0444   DETRAY_HOST_DEVICE
0445   irregular()
0446       : n_bins(std::numeric_limits<unsigned int>::max()),
0447         min(0.f),
0448         max(static_cast<scalar>(n_bins)),
0449         boundaries({}) {}
0450 
0451   /** Constructor with vecmem memory resource **/
0452   DETRAY_HOST
0453   explicit irregular(vecmem::memory_resource &resource)
0454       : n_bins(std::numeric_limits<unsigned int>::max()),
0455         min(0.f),
0456         max(static_cast<scalar>(n_bins)),
0457         boundaries(&resource) {}
0458 
0459   /** Constructor with vecmem memory resource - rvalue **/
0460   DETRAY_HOST irregular(vector_t<scalar> &&bins,
0461                         vecmem::memory_resource &resource)
0462       : n_bins(static_cast<unsigned int>(bins.size()) - 1u),
0463         min(bins[0]),
0464         max(bins[n_bins]),
0465         boundaries(bins, &resource) {}
0466 
0467   /** Constructor with vecmem memory resource - lvalue **/
0468   DETRAY_HOST irregular(const vector_t<scalar> &bins,
0469                         vecmem::memory_resource &resource)
0470       : n_bins(static_cast<unsigned int>(bins.size()) - 1u),
0471         min(bins[0]),
0472         max(bins[n_bins]),
0473         boundaries(bins, &resource) {}
0474 
0475   /** Constructor with vecmem memory resource **/
0476   DETRAY_HOST
0477   irregular(const irregular &axis, vecmem::memory_resource &resource)
0478       : n_bins(axis.n_bins),
0479         min(axis.min),
0480         max(axis.max),
0481         boundaries(axis.boundaries, &resource) {}
0482 
0483   /** Constructor with axis_data **/
0484   template <typename axis_data_t>
0485     requires(!std::is_same_v<irregular, axis_data_t>)
0486   DETRAY_HOST_DEVICE explicit irregular(const axis_data_t &axis_data)
0487       : n_bins(axis_data.n_bins),
0488         min(axis_data.min),
0489         max(axis_data.max),
0490         boundaries(axis_data.boundaries) {}
0491 
0492   /** Return the number of bins */
0493   DETRAY_HOST_DEVICE
0494   unsigned int bins() const {
0495     return static_cast<unsigned int>(boundaries.size() - 1u);
0496   }
0497 
0498   /** Access function to a single bin from a value v
0499    *
0500    * @param v is the value for the bin search
0501    *
0502    * As the axis is closed it @returns a unsigned int type
0503    **/
0504   DETRAY_HOST_DEVICE
0505   unsigned int bin(scalar v) const {
0506     auto ibin = static_cast<int>(std::ranges::lower_bound(boundaries, v) -
0507                                  boundaries.begin());
0508     if (ibin > 0 && ibin < static_cast<int>(boundaries.size())) {
0509       return static_cast<unsigned int>(--ibin);
0510     } else {
0511       if (ibin == 0) {
0512         return static_cast<unsigned int>(ibin);
0513       } else {
0514         return static_cast<unsigned int>(boundaries.size() - 2u);
0515       }
0516     }
0517   }
0518 
0519   /** Access function to a range with binned neighborhood
0520    *
0521    * @param v is the value for the bin search
0522    * @param nhood is the neighborhood range (#bins)
0523    *
0524    * As the axis is closed it @returns an index range
0525    **/
0526   DETRAY_HOST_DEVICE
0527   std::array<unsigned int, 2> range(scalar v,
0528                                     const array_t<unsigned int, 2> &nhood = {
0529                                         0u, 0u}) const {
0530     unsigned int ibin = bin(v);
0531     int bins = static_cast<int>(boundaries.size()) - 1;
0532     int ibinmin = static_cast<int>(ibin) - static_cast<int>(nhood[0]);
0533     int ibinmax = static_cast<int>(ibin + nhood[1]);
0534     auto min_bin = (ibinmin >= 0) ? static_cast<unsigned int>(ibinmin) : 0u;
0535     auto max_bin = (ibinmax < bins) ? static_cast<unsigned int>(ibinmax)
0536                                     : static_cast<unsigned int>(bins - 1);
0537     return {min_bin, max_bin};
0538   }
0539 
0540   /** Access function to a range with scalar neighborhood
0541    *
0542    * @param v is the value for the bin search
0543    * @param nhood is the neighborhood range (scalar)
0544    *
0545    * As the axis is closed it @returns an index range
0546    **/
0547   DETRAY_HOST_DEVICE
0548   std::array<unsigned int, 2> range(scalar v,
0549                                     const array_t<scalar, 2> &nhood) const {
0550     unsigned int nbin = bin(v - nhood[0]);
0551     unsigned int pbin = bin(v + nhood[1]);
0552     return {nbin, pbin};
0553   }
0554 
0555   /** Access function to a zone with binned/scalar neighborhood
0556    *
0557    * @tparam neighbor_t is the neighborhood type
0558    *
0559    * @param v is the value for the bin search
0560    * @param nhood is the neighborhood range (binned/scalar)
0561    *
0562    * As the axis is closed it @returns an index sequence
0563    **/
0564   template <typename neighbor_t>
0565   DETRAY_HOST_DEVICE vecmem::vector<unsigned int> zone_t(
0566       scalar v, const array_t<neighbor_t, 2> nhood) const {
0567     std::array<unsigned int, 2> nh_range = range(v, nhood);
0568     vecmem::vector<unsigned int> sequence(
0569         static_cast<vecmem::vector<unsigned int>::size_type>(nh_range[1] -
0570                                                              nh_range[0] + 1u),
0571         nh_range[0]);
0572     unsigned int m = 0u;
0573     std::ranges::for_each(sequence, [&](auto &n) { n += m++; });
0574     return sequence;
0575   }
0576 
0577   /** Access function to a zone with binned neighborhood
0578    *
0579    * @param v is the value for the bin search
0580    * @param nhood is the neighborhood range (#bins)
0581    *
0582    * As the axis is closed it @returns an index sequence
0583    **/
0584   DETRAY_HOST_DEVICE
0585   vecmem::vector<unsigned int> zone(scalar v,
0586                                     const array_t<unsigned int, 2> &nhood = {
0587                                         0u, 0u}) const {
0588     return zone_t<unsigned int>(v, nhood);
0589   }
0590 
0591   /** Access function to a zone with scalar neighborhood
0592    *
0593    * @param v is the value for the bin search
0594    * @param nhood is the neighborhood range (scalar)
0595    *
0596    * As the axis is closed it @returns an index sequence
0597    **/
0598   DETRAY_HOST_DEVICE
0599   vecmem::vector<unsigned int> zone(scalar v,
0600                                     const array_t<scalar, 2> &nhood) const {
0601     return zone_t<scalar>(v, nhood);
0602   }
0603 
0604   DETRAY_HOST_DEVICE
0605   /** @return the bin boundaries for a given @param ibin */
0606   array_t<scalar, 2> borders(unsigned int ibin) const {
0607     return {boundaries[ibin], boundaries[ibin + 1u]};
0608   }
0609 
0610   /** @return the values of the borders of all bins */
0611   DETRAY_HOST
0612   vector_t<scalar> all_borders() const { return boundaries; }
0613 
0614   /** @return the range  */
0615   DETRAY_HOST_DEVICE
0616   array_t<scalar, 2> span() const {
0617     return {boundaries[0], boundaries[boundaries.size() - 1u]};
0618   }
0619 };
0620 
0621 }  // namespace axis2
0622 
0623 /**
0624  * static implementation of axis data for device
0625  */
0626 template <typename axis_t, detray::concepts::scalar scalar_t,
0627           typename Enable = void>
0628 struct axis_data;
0629 
0630 template <typename axis_t, detray::concepts::scalar scalar_t>
0631   requires(axis_t::axis_identifier == 0u) || (axis_t::axis_identifier == 1u)
0632 struct axis_data<axis_t, scalar_t> {
0633   /// Declare that a default constructor can/should be generated
0634   axis_data() = default;
0635   /// Constructor with the 3 member values
0636   DETRAY_HOST_DEVICE
0637   axis_data(unsigned int _n_bins, std::remove_cv_t<scalar_t> _min,
0638             std::remove_cv_t<scalar_t> _max)
0639       : n_bins(_n_bins), min(_min), max(_max) {}
0640   /// Construct a const data object from a non-const one
0641   template <typename other_scalar_t>
0642     requires detray::concepts::same_as_no_const<scalar_t, other_scalar_t>
0643   DETRAY_HOST_DEVICE explicit axis_data(
0644       const axis_data<axis_t, other_scalar_t, void> &parent)
0645       : n_bins(parent.n_bins), min(parent.min), max(parent.max) {}
0646 
0647   unsigned int n_bins;
0648   std::remove_cv_t<scalar_t> min;
0649   std::remove_cv_t<scalar_t> max;
0650 };
0651 
0652 template <typename axis_t, detray::concepts::scalar scalar_t>
0653   requires(axis_t::axis_identifier == 2)
0654 struct axis_data<axis_t, scalar_t> {
0655   /// Declare that a default constructor can/should be generated
0656   axis_data() = default;
0657   /// Constructor with the 4 member values
0658   DETRAY_HOST_DEVICE
0659   axis_data(unsigned int _n_bins, std::remove_cv_t<scalar_t> _min,
0660             std::remove_cv_t<scalar_t> _max,
0661             const vecmem::data::vector_view<scalar_t> &_boundaries)
0662       : n_bins(_n_bins), min(_min), max(_max), boundaries(_boundaries) {}
0663   /// Construct a const data object from a non-const one
0664   template <typename other_scalar_t>
0665     requires detray::concepts::same_as_no_const<scalar_t, other_scalar_t>
0666   DETRAY_HOST_DEVICE explicit axis_data(
0667       const axis_data<axis_t, other_scalar_t, void> &parent)
0668       : n_bins(parent.n_bins),
0669         min(parent.min),
0670         max(parent.max),
0671         boundaries(parent.boundaries) {}
0672 
0673   unsigned int n_bins;
0674   std::remove_cv_t<scalar_t> min;
0675   std::remove_cv_t<scalar_t> max;
0676   vecmem::data::vector_view<scalar_t> boundaries;
0677 };
0678 
0679 /**
0680  * standalone function to get axis_data (non-const)
0681  */
0682 template <template <template <typename, std::size_t> class,
0683                     template <typename...> class> class axis_t,
0684           template <typename, std::size_t> class array_t,
0685           template <typename...> class vector_t>
0686   requires(axis_t<array_t, vector_t>::axis_identifier == 0u) ||
0687           (axis_t<array_t, vector_t>::axis_identifier == 1u)
0688 inline axis_data<axis_t<array_t, vector_t>, scalar> get_data(
0689     axis_t<array_t, vector_t> &axis) {
0690   axis_data<axis_t<array_t, vector_t>, scalar> result{axis.n_bins, axis.min,
0691                                                       axis.max};
0692   return result;
0693 }
0694 
0695 /**
0696  * standalone function to get axis_data (non-const)
0697  */
0698 template <template <template <typename, std::size_t> class,
0699                     template <typename...> class> class axis_t,
0700           template <typename, std::size_t> class array_t,
0701           template <typename...> class vector_t>
0702   requires(axis_t<array_t, vector_t>::axis_identifier == 2u)
0703 inline axis_data<axis_t<array_t, vector_t>, scalar> get_data(
0704     axis_t<array_t, vector_t> &axis) {
0705   axis_data<axis_t<array_t, vector_t>, scalar> result{
0706       axis.n_bins, axis.min, axis.max, vecmem::get_data(axis.boundaries)};
0707   return result;
0708 }
0709 
0710 /**
0711  * standalone function to get axis_data (const)
0712  */
0713 template <template <template <typename, std::size_t> class,
0714                     template <typename...> class> class axis_t,
0715           template <typename, std::size_t> class array_t,
0716           template <typename...> class vector_t>
0717   requires(axis_t<array_t, vector_t>::axis_identifier == 0u) ||
0718           (axis_t<array_t, vector_t>::axis_identifier == 1u)
0719 inline axis_data<axis_t<array_t, vector_t>, const scalar> get_data(
0720     const axis_t<array_t, vector_t> &axis) {
0721   axis_data<axis_t<array_t, vector_t>, const scalar> result{axis.n_bins,
0722                                                             axis.min, axis.max};
0723   return result;
0724 }
0725 
0726 /**
0727  * standalone function to get axis_data (const)
0728  */
0729 template <template <template <typename, std::size_t> class,
0730                     template <typename...> class> class axis_t,
0731           template <typename, std::size_t> class array_t,
0732           template <typename...> class vector_t>
0733   requires(axis_t<array_t, vector_t>::axis_identifier == 2u)
0734 inline axis_data<axis_t<array_t, vector_t>, const scalar> get_data(
0735     const axis_t<array_t, vector_t> &axis) {
0736   axis_data<axis_t<array_t, vector_t>, const scalar> result{
0737       axis.n_bins, axis.min, axis.max, vecmem::get_data(axis.boundaries)};
0738   return result;
0739 }
0740 
0741 }  // namespace traccc