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 #include "traccc/seeding/grids/axis.hpp"
0014 
0015 // Detray include(s).
0016 #include <detray/utils/concepts.hpp>
0017 #include <detray/utils/invalid_values.hpp>
0018 #include <detray/utils/tuple.hpp>
0019 
0020 // VecMem include(s).
0021 #include <vecmem/containers/data/buffer_type.hpp>
0022 #include <vecmem/memory/memory_resource.hpp>
0023 
0024 // System include(s)
0025 #include <algorithm>
0026 
0027 namespace traccc {
0028 
0029 /** A two-dimensional grid for object storage
0030  *
0031  * @tparam populator_t  is a prescription what to do when a bin gets
0032  * populated, it broadcasts also the value type
0033  * @tparam tparam axis_p0_t the type of the first axis
0034  * @tparam tparam axis_p1_t the type of the second axis
0035  * @tparam serialzier_t  type of the serializer to the storage represenations
0036  *
0037  **/
0038 template <template <template <typename...> class, template <typename...> class,
0039                     template <typename, std::size_t> class, typename, bool,
0040                     unsigned int> class populator_t,
0041           template <template <typename, std::size_t> class,
0042                     template <typename...> class> class axis_p0_t,
0043           template <template <typename, std::size_t> class,
0044                     template <typename...> class> class axis_p1_t,
0045           typename serializer_t,
0046           template <typename...> class vector_t = vecmem::vector,
0047           template <typename...> class jagged_vector_t = vecmem::jagged_vector,
0048           template <typename, std::size_t> class array_t = std::array,
0049           template <typename...> class tuple_t = detray::tuple,
0050           typename value_t = unsigned int, bool kSORT = false,
0051           unsigned int kDIM = 1u>
0052 class grid2 {
0053  public:
0054   using populator_type =
0055       populator_t<vector_t, jagged_vector_t, array_t, value_t, kSORT, kDIM>;
0056   using serializer_type = serializer_t;
0057   using axis_p0_type = axis_p0_t<array_t, vector_t>;
0058   using axis_p1_type = axis_p1_t<array_t, vector_t>;
0059   using bare_value = typename populator_type::bare_value;
0060   using serialized_storage = typename populator_type::serialized_storage;
0061 
0062   template <typename neighbor_t>
0063   using neighborhood = array_t<array_t<neighbor_t, 2>, 2>;
0064 
0065   static constexpr array_t<unsigned int, 2> hermit1 = {0u, 0u};
0066   static constexpr neighborhood<unsigned int> hermit2 = {hermit1, hermit1};
0067 
0068   grid2() = default;
0069 
0070   DETRAY_HOST
0071   grid2(
0072       vecmem::memory_resource &mr,
0073       const bare_value m_invalid = detray::detail::invalid_value<bare_value>())
0074       : _axis_p0(mr),
0075         _axis_p1(mr),
0076         _data_serialized(&mr),
0077         _populator(m_invalid) {}
0078 
0079   /** Constructor from axes - copy semantics
0080    *
0081    * @param axis_p0 is the axis in the first coordinate
0082    * @param axis_p1 is the axis in the second coordinate
0083    *
0084    **/
0085   DETRAY_HOST
0086   grid2(
0087       const axis_p0_type &axis_p0, const axis_p1_type &axis_p1,
0088       vecmem::memory_resource &mr,
0089       const bare_value m_invalid = detray::detail::invalid_value<bare_value>())
0090       : _axis_p0(axis_p0, mr),
0091         _axis_p1(axis_p1, mr),
0092         _data_serialized(&mr),
0093         _populator(m_invalid) {
0094     _data_serialized = serialized_storage(_axis_p0.bins() * _axis_p1.bins(),
0095                                           _populator.init());
0096   }
0097 
0098   /** Constructor from axes - move semantics
0099    *
0100    * @param axis_p0 is the axis in the first coordinate
0101    * @param axis_p1 is the axis in the second coordinate
0102    *
0103    **/
0104   DETRAY_HOST
0105   grid2(
0106       axis_p0_type &&axis_p0, axis_p1_type &&axis_p1,
0107       vecmem::memory_resource &mr,
0108       const bare_value m_invalid = detray::detail::invalid_value<bare_value>())
0109       : _axis_p0(std::move(axis_p0), mr),
0110         _axis_p1(std::move(axis_p1), mr),
0111         _data_serialized(&mr),
0112         _populator(m_invalid) {
0113     _data_serialized = serialized_storage(_axis_p0.bins() * _axis_p1.bins(),
0114                                           _populator.init());
0115   }
0116 
0117   /** Constructor from grid data
0118    **/
0119   template <typename grid_view_t>
0120     requires(!std::is_same_v<grid2, grid_view_t>) &&
0121                 (!std::is_base_of_v<vecmem::memory_resource, grid_view_t>)
0122   DETRAY_HOST_DEVICE grid2(
0123       const grid_view_t &grid_data,
0124       const bare_value m_invalid = detray::detail::invalid_value<bare_value>())
0125       : _axis_p0(grid_data._axis_p0_view),
0126         _axis_p1(grid_data._axis_p1_view),
0127         _data_serialized(grid_data._data_view),
0128         _populator(m_invalid) {}
0129 
0130   /** Allow for grid shift, when using a centralized store and indices
0131    *
0132    * @param offset is the applied offset shift
0133    *
0134    **/
0135   void shift(const typename populator_type::bare_value &offset) {
0136     std::ranges::for_each(_data_serialized,
0137                           [&](auto &ds) { _populator.shift(ds, offset); });
0138   }
0139 
0140   /** Fill/populate operation
0141    *
0142    * @tparam point2_t the 2D local point type
0143    *
0144    * @param p2 the point in p2 local frame
0145    * @param fvalue is a single fill value to be filled
0146    *
0147    **/
0148   template <detray::concepts::point2D point2_t>
0149   DETRAY_HOST_DEVICE void populate(
0150       const point2_t &p2, typename populator_type::bare_value &&fvalue) {
0151     auto sbin = _serializer.template serialize<axis_p0_type, axis_p1_type>(
0152         _axis_p0, _axis_p1, _axis_p0.bin(p2[0]), _axis_p1.bin(p2[1]));
0153     _populator(_data_serialized[sbin], std::move(fvalue));
0154   }
0155 
0156   /** Fill/populate operation - with bin entry
0157    *
0158    * @param bin The two-dimensional bin2
0159    * @param fvalue is a single fill value to be filled
0160    *
0161    **/
0162   DETRAY_HOST_DEVICE
0163   void populate(unsigned int bin0, unsigned int bin1,
0164                 typename populator_type::bare_value &&fvalue) {
0165     auto sbin = _serializer.template serialize<axis_p0_type, axis_p1_type>(
0166         _axis_p0, _axis_p1, bin0, bin1);
0167     _populator(_data_serialized[sbin], std::move(fvalue));
0168   }
0169 
0170   DETRAY_HOST_DEVICE
0171   void populate(unsigned int gbin,
0172                 typename populator_type::bare_value &&fvalue) {
0173     unsigned int bin0 = gbin % _axis_p0.bins();
0174     unsigned int bin1 = gbin / _axis_p0.bins();
0175     populate(bin0, bin1, std::move(fvalue));
0176   }
0177 
0178   /** Return the value of a single bin - with direct bin acess
0179    *
0180    * @param bin0 the index of bin 0
0181    * @param bin1 the index of bin 1
0182    *
0183    * @return the const reference to the value in this bin
0184    **/
0185   DETRAY_HOST_DEVICE
0186   typename serialized_storage::const_reference bin(unsigned int bin0,
0187                                                    unsigned int bin1) const {
0188     return _data_serialized[_serializer.template serialize<
0189         axis_p0_type, axis_p1_type>(_axis_p0, _axis_p1, bin0, bin1)];
0190   }
0191 
0192   DETRAY_HOST_DEVICE
0193   typename serialized_storage::reference bin(unsigned int bin0,
0194                                              unsigned int bin1) {
0195     return _data_serialized.at(
0196         _serializer.template serialize<axis_p0_type, axis_p1_type>(
0197             _axis_p0, _axis_p1, bin0, bin1));
0198   }
0199 
0200   DETRAY_HOST_DEVICE
0201   typename serialized_storage::const_reference bin(unsigned int gbin) const {
0202     unsigned int bin0 = gbin % _axis_p0.bins();
0203     unsigned int bin1 = gbin / _axis_p0.bins();
0204     return bin(bin0, bin1);
0205   }
0206 
0207   DETRAY_HOST_DEVICE
0208   typename serialized_storage::reference bin(unsigned int gbin) {
0209     unsigned int bin0 = gbin % _axis_p0.bins();
0210     unsigned int bin1 = gbin / _axis_p0.bins();
0211     return bin(bin0, bin1);
0212   }
0213 
0214   /** Return the value of a single bin
0215    *
0216    * @param p2 is point in the local frame
0217    *
0218    * @return the const reference to the value in this bin
0219    **/
0220   template <detray::concepts::point2D point2_t>
0221     requires(!std::is_scalar_v<point2_t>)
0222   DETRAY_HOST_DEVICE typename serialized_storage::const_reference bin(
0223       const point2_t &p2) const {
0224     return _data_serialized[_serializer.template serialize<axis_p0_type,
0225                                                            axis_p1_type>(
0226         _axis_p0, _axis_p1, _axis_p0.bin(p2[0]), _axis_p1.bin(p2[1]))];
0227   }
0228 
0229   /** Return the value of a single bin - non-const access
0230    *
0231    * @param p2 is point in the local frame
0232    *
0233    * @return the const reference to the value in this bin
0234    **/
0235   template <detray::concepts::point2D point2_t>
0236     requires(!std::is_scalar_v<point2_t>)
0237   DETRAY_HOST_DEVICE typename serialized_storage::reference bin(
0238       const point2_t &p2) {
0239     return _data_serialized[_serializer.template serialize<axis_p0_type,
0240                                                            axis_p1_type>(
0241         _axis_p0, _axis_p1, _axis_p0.bin(p2[0]), _axis_p1.bin(p2[1]))];
0242   }
0243 
0244   /** Return a zone around a single bin, either with binned or scalar
0245    *neighborhood
0246    *
0247    * The zone is done with a neighborhood around the bin which is defined by
0248    *p2
0249    *
0250    * @param p2 is point in the local frame
0251    * @param nhood is the binned/scalar neighborhood
0252    * @param sort is a directive whether to sort or not
0253    *
0254    * @return the sequence of values
0255    **/
0256   template <typename neighbor_t, detray::concepts::point2D point2_t>
0257   DETRAY_HOST_DEVICE vector_t<typename populator_type::bare_value> zone_t(
0258       const point2_t &p2, const neighborhood<neighbor_t> &nhood,
0259       bool sort) const {
0260     auto zone0 = _axis_p0.zone(p2[0], nhood[0]);
0261     auto zone1 = _axis_p1.zone(p2[1], nhood[1]);
0262 
0263     vector_t<typename populator_type::bare_value> zone;
0264 
0265     // Specialization for bare value equal to store value
0266     if constexpr (std::is_same_v<typename populator_type::bare_value,
0267                                  typename populator_type::store_value>) {
0268       unsigned int iz = 0u;
0269       zone = vector_t<typename populator_type::bare_value>(
0270           zone0.size() * zone1.size(), {});
0271       for (const auto z1 : zone1) {
0272         for (const auto z0 : zone0) {
0273           auto sbin =
0274               _serializer.template serialize<axis_p0_type, axis_p1_type>(
0275                   _axis_p0, _axis_p1, z0, z1);
0276           zone[iz++] = _data_serialized[sbin];
0277         }
0278       }
0279     } else {
0280       zone.reserve(10u);
0281       for (const auto z1 : zone1) {
0282         for (const auto z0 : zone0) {
0283           auto sbin =
0284               _serializer.template serialize<axis_p0_type, axis_p1_type>(
0285                   _axis_p0, _axis_p1, z0, z1);
0286           auto bin_data = _data_serialized[sbin];
0287           auto bin_content = _populator.sequence(bin_data);
0288           zone.insert(zone.end(), bin_content.begin(), bin_content.end());
0289         }
0290       }
0291     }
0292 
0293     if (sort) {
0294       std::ranges::sort(zone);
0295     }
0296     return zone;
0297   }
0298 
0299   /** Return a zone around a single bin, either with binned neighborhood
0300    *
0301    * The zone is done with a neighborhood around the bin which is defined by
0302    *p2
0303    *
0304    * @param p2 is point in the local frame
0305    * @param nhood is the binned neighborhood
0306    * @param sort is a directive whether to sort or not
0307    *
0308    * @return the sequence of values
0309    **/
0310   template <detray::concepts::point2D point2_t>
0311   DETRAY_HOST_DEVICE vector_t<typename populator_type::bare_value> zone(
0312       const point2_t &p2, const neighborhood<unsigned int> &nhood = hermit2,
0313       bool sort = false) const {
0314     return zone_t<unsigned int>(p2, nhood, sort);
0315   }
0316 
0317   /** Return a zone around a single bin, either with scalar neighborhood
0318    *
0319    * The zone is done with a neighborhood around the bin which is defined by
0320    *p2
0321    *
0322    * @param p2 is point in the local frame
0323    * @param nhood is the binned neighborhood
0324    * @param sort is a directive whether to sort or not
0325    *
0326    * @return the sequence of values
0327    **/
0328   template <detray::concepts::point2D point2_t>
0329   DETRAY_HOST_DEVICE vector_t<typename populator_type::bare_value> zone(
0330       const point2_t &p2, const neighborhood<scalar> &nhood,
0331       bool sort = false) const {
0332     return zone_t<scalar>(p2, nhood, sort);
0333   }
0334 
0335   /** Const access to axis p0  */
0336   DETRAY_HOST_DEVICE
0337   const axis_p0_type &axis_p0() const { return _axis_p0; }
0338 
0339   /** Non-const access to axis p0  */
0340   DETRAY_HOST_DEVICE
0341   axis_p0_type &axis_p0() { return _axis_p0; }
0342 
0343   /** Const access to axis p1 */
0344   DETRAY_HOST_DEVICE
0345   const axis_p1_type &axis_p1() const { return _axis_p1; }
0346 
0347   /** Non-const access to axis p1 */
0348   DETRAY_HOST_DEVICE
0349   axis_p1_type &axis_p1() { return _axis_p1; }
0350 
0351   /* Copy of axes in a tuple */
0352   DETRAY_HOST_DEVICE
0353   tuple_t<axis_p0_type, axis_p1_type> axes() const {
0354     return std::tie(_axis_p0, _axis_p1);
0355   }
0356 
0357   /* Get the total number of bins */
0358   DETRAY_HOST_DEVICE
0359   unsigned int nbins() const { return _axis_p0.bins() * _axis_p1.bins(); }
0360 
0361   /** Const acess to the serializer */
0362   DETRAY_HOST_DEVICE
0363   const serializer_type &serializer() const { return _serializer; }
0364 
0365   /** Const acess to the polulator */
0366   DETRAY_HOST_DEVICE
0367   const populator_type &populator() const { return _populator; }
0368 
0369   DETRAY_HOST_DEVICE
0370   serialized_storage &data() { return _data_serialized; }
0371   DETRAY_HOST_DEVICE
0372   const serialized_storage &data() const { return _data_serialized; }
0373 
0374  private:
0375   axis_p0_type _axis_p0;
0376   axis_p1_type _axis_p1;
0377   serialized_storage _data_serialized;
0378   populator_type _populator;
0379   serializer_type _serializer;
0380 };
0381 
0382 /// Helper function creating a @c vecmem::data::vector_view object
0383 template <typename TYPE, typename ALLOC>
0384 DETRAY_HOST vecmem::data::vector_view<TYPE> get_data(
0385     std::vector<TYPE, ALLOC> &vec, vecmem::memory_resource &) {
0386   return vecmem::get_data(vec);
0387 }
0388 
0389 /// Helper function creating a @c vecmem::data::vector_view object
0390 template <typename TYPE, typename ALLOC>
0391 DETRAY_HOST vecmem::data::vector_view<const TYPE> get_data(
0392     const std::vector<TYPE, ALLOC> &vec, vecmem::memory_resource &) {
0393   return vecmem::get_data(vec);
0394 }
0395 
0396 /// Helper function creating a @c vecmem::data::jagged_vector_data object
0397 template <typename TYPE, typename ALLOC1, typename ALLOC2>
0398 DETRAY_HOST vecmem::data::jagged_vector_data<TYPE> get_data(
0399     std::vector<std::vector<TYPE, ALLOC1>, ALLOC2> &vec,
0400     vecmem::memory_resource &resource) {
0401   return vecmem::get_data(vec, &resource);
0402 }
0403 
0404 /// Helper function creating a @c vecmem::data::vector_view object
0405 template <typename TYPE, typename ALLOC1, typename ALLOC2>
0406 DETRAY_HOST vecmem::data::jagged_vector_data<const TYPE> get_data(
0407     const std::vector<std::vector<TYPE, ALLOC1>, ALLOC2> &vec,
0408     vecmem::memory_resource &resource) {
0409   return vecmem::get_data(vec, &resource);
0410 }
0411 
0412 /** A two-dimensional (non-const) grid view for gpu device usage
0413  **/
0414 template <typename grid2_t>
0415 struct grid2_view {
0416   axis_data<typename grid2_t::axis_p0_type, scalar> _axis_p0_view;
0417   axis_data<typename grid2_t::axis_p1_type, scalar> _axis_p1_view;
0418   typename grid2_t::populator_type::vector_view_type _data_view;
0419 };
0420 
0421 /** A two-dimensional (const) grid view for gpu device usage
0422  **/
0423 template <typename grid2_t>
0424 struct const_grid2_view {
0425   /// Declare that a default constructor can/should be generated
0426   const_grid2_view() = default;
0427   /// Constructor with the 3 member variables
0428   DETRAY_HOST_DEVICE
0429   const_grid2_view(
0430       const axis_data<typename grid2_t::axis_p0_type, const scalar>
0431           &axis_p0_view,
0432       const axis_data<typename grid2_t::axis_p1_type, const scalar>
0433           &axis_p1_view,
0434       const typename grid2_t::populator_type::const_vector_view_type &data_view)
0435       : _axis_p0_view(axis_p0_view),
0436         _axis_p1_view(axis_p1_view),
0437         _data_view(data_view) {}
0438   /// Construct a const data object from a non-const one
0439   DETRAY_HOST_DEVICE
0440   const_grid2_view(const grid2_view<grid2_t> &parent)
0441       : _axis_p0_view(parent._axis_p0_view),
0442         _axis_p1_view(parent._axis_p1_view),
0443         _data_view(parent._data_view) {}
0444 
0445   axis_data<typename grid2_t::axis_p0_type, const scalar> _axis_p0_view;
0446   axis_data<typename grid2_t::axis_p1_type, const scalar> _axis_p1_view;
0447   typename grid2_t::populator_type::const_vector_view_type _data_view;
0448 };
0449 
0450 /** A two-dimensional (non-const) grid data for gpu device usage
0451  **/
0452 template <typename grid2_t>
0453 struct grid2_data : public grid2_view<grid2_t> {
0454   /** Constructor from grid
0455    *
0456    * @param grid is the input grid from host
0457    * @param resource is the vecmem memory resource
0458    *
0459    **/
0460   grid2_data(grid2_t &grid, vecmem::memory_resource &resource)
0461       : _axis_p0(grid.axis_p0(), resource),
0462         _axis_p1(grid.axis_p1(), resource),
0463         _data(traccc::get_data(grid.data(), resource)) {
0464     grid2_view<grid2_t>::_axis_p0_view = traccc::get_data(_axis_p0);
0465     grid2_view<grid2_t>::_axis_p1_view = traccc::get_data(_axis_p1);
0466     grid2_view<grid2_t>::_data_view = _data;
0467   }
0468 
0469   typename grid2_t::axis_p0_type _axis_p0;
0470   typename grid2_t::axis_p1_type _axis_p1;
0471   typename grid2_t::populator_type::vector_data_type _data;
0472 };
0473 
0474 /** A two-dimensional (const) grid data for gpu device usage
0475  **/
0476 template <typename grid2_t>
0477 struct const_grid2_data : public const_grid2_view<grid2_t> {
0478   /** Constructor from grid
0479    *
0480    * @param grid is the input grid from host
0481    * @param resource is the vecmem memory resource
0482    *
0483    **/
0484   const_grid2_data(const grid2_t &grid, vecmem::memory_resource &resource)
0485       : _axis_p0(grid.axis_p0(), resource),
0486         _axis_p1(grid.axis_p1(), resource),
0487         _data(traccc::get_data(grid.data(), resource)) {
0488     const typename grid2_t::axis_p0_type &const_axis_p0 = _axis_p0;
0489     const_grid2_view<grid2_t>::_axis_p0_view = traccc::get_data(const_axis_p0);
0490     const typename grid2_t::axis_p1_type &const_axis_p1 = _axis_p1;
0491     const_grid2_view<grid2_t>::_axis_p1_view = traccc::get_data(const_axis_p1);
0492     const_grid2_view<grid2_t>::_data_view = _data;
0493   }
0494 
0495   typename grid2_t::axis_p0_type _axis_p0;
0496   typename grid2_t::axis_p1_type _axis_p1;
0497   typename grid2_t::populator_type::const_vector_data_type _data;
0498 };
0499 
0500 /** A two-dimensional grid buffer
0501  **/
0502 template <typename grid2_t>
0503 struct grid2_buffer : public grid2_view<grid2_t> {
0504   using populator_type = typename grid2_t::populator_type;
0505   using axis_p0_type = typename grid2_t::axis_p0_type;
0506   using axis_p1_type = typename grid2_t::axis_p1_type;
0507 
0508   /** Constructor
0509    *
0510    * @param axis_p0 is the first axis
0511    * @param axis_p1 is the second axis
0512    * @param capacities is the capacity of vector
0513    * @param resource is the vecmem memory resource
0514    * @param host_resurce is the host accessible memory resource
0515    * @param buffer_type is whether the buffer is resizable or of fixed size
0516    *
0517    **/
0518   grid2_buffer(const axis_p0_type &axis_p0, const axis_p1_type &axis_p1,
0519                typename populator_type::buffer_size_type capacities,
0520                vecmem::memory_resource &resource,
0521                vecmem::memory_resource *host_resource = nullptr,
0522                vecmem::data::buffer_type buffer_type =
0523                    vecmem::data::buffer_type::fixed_size)
0524       : _axis_p0(axis_p0),
0525         _axis_p1(axis_p1),
0526         _buffer(capacities, resource, host_resource, buffer_type) {
0527     grid2_view<grid2_t>::_axis_p0_view = traccc::get_data(_axis_p0);
0528     grid2_view<grid2_t>::_axis_p1_view = traccc::get_data(_axis_p1);
0529     grid2_view<grid2_t>::_data_view = _buffer;
0530   }
0531 
0532   axis_p0_type _axis_p0;
0533   axis_p1_type _axis_p1;
0534   typename populator_type::vector_buffer_type _buffer;
0535 };
0536 
0537 /** Get grid2_data from grid and memory resource
0538  **/
0539 template <template <template <typename...> class, template <typename...> class,
0540                     template <typename, std::size_t> class, typename, bool,
0541                     unsigned int> class populator_t,
0542           template <template <typename, std::size_t> class,
0543                     template <typename...> class> class axis_p0_t,
0544           template <template <typename, std::size_t> class,
0545                     template <typename...> class> class axis_p1_t,
0546           typename serializer_t, template <typename...> class vector_t,
0547           template <typename...> class jagged_vector_t,
0548           template <typename, std::size_t> class array_t,
0549           template <typename...> class tuple_t, typename value_t = unsigned int,
0550           bool kSORT = false, unsigned int kDIM = 1>
0551 inline grid2_data<
0552     grid2<populator_t, axis_p0_t, axis_p1_t, serializer_t, vector_t,
0553           jagged_vector_t, array_t, tuple_t, value_t, kSORT, kDIM>>
0554 get_data(grid2<populator_t, axis_p0_t, axis_p1_t, serializer_t, vector_t,
0555                jagged_vector_t, array_t, tuple_t, value_t, kSORT, kDIM> &grid,
0556          vecmem::memory_resource &resource) {
0557   return {grid, resource};
0558 }
0559 
0560 /** Get const_grid2_data from grid and memory resource
0561  **/
0562 template <template <template <typename...> class, template <typename...> class,
0563                     template <typename, std::size_t> class, typename, bool,
0564                     unsigned int> class populator_t,
0565           template <template <typename, std::size_t> class,
0566                     template <typename...> class> class axis_p0_t,
0567           template <template <typename, std::size_t> class,
0568                     template <typename...> class> class axis_p1_t,
0569           typename serializer_t, template <typename...> class vector_t,
0570           template <typename...> class jagged_vector_t,
0571           template <typename, std::size_t> class array_t,
0572           template <typename...> class tuple_t, typename value_t = unsigned int,
0573           bool kSORT = false, unsigned int kDIM = 1>
0574 inline const_grid2_data<
0575     grid2<populator_t, axis_p0_t, axis_p1_t, serializer_t, vector_t,
0576           jagged_vector_t, array_t, tuple_t, value_t, kSORT, kDIM>>
0577 get_data(
0578     const grid2<populator_t, axis_p0_t, axis_p1_t, serializer_t, vector_t,
0579                 jagged_vector_t, array_t, tuple_t, value_t, kSORT, kDIM> &grid,
0580     vecmem::memory_resource &resource) {
0581   return {grid, resource};
0582 }
0583 
0584 }  // namespace traccc