Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-27 07:24:25

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 // Detray test include(s)
0010 #include <detray/test/framework/assert.hpp>
0011 
0012 #include "sf_finders_grid_cuda_kernel.hpp"
0013 
0014 // VecMem include(s).
0015 #include <vecmem/memory/cuda/managed_memory_resource.hpp>
0016 
0017 // GTest include(s).
0018 #include <gtest/gtest.h>
0019 
0020 // System include(s).
0021 #include <limits>
0022 
0023 using namespace detray;
0024 
0025 namespace {
0026 
0027 /// Test single entry bin content element by element
0028 template <typename bin_content_t, typename content_t>
0029 void test_content(const bin_content_t& bin_content, const content_t& expected) {
0030   unsigned int i{0u};
0031   for (const auto& elem : bin_content) {
0032     ASSERT_NEAR(elem, expected[i++], tol);
0033   }
0034 }
0035 
0036 /// Test collection entries in a bin element by element
0037 template <typename content_t, typename expected_content_t>
0038 void test_entry_collection(const content_t& bin_content,
0039                            const expected_content_t& expected) {
0040   // Running indices for the points in the collection and the elements of a
0041   // single point3
0042   unsigned int i = 0u;
0043   unsigned int j = 0u;
0044   for (const auto& entry : bin_content) {
0045     const auto& expt_entry = expected[i++];
0046     j = 0u;
0047     for (const auto& elem : entry) {
0048       ASSERT_NEAR(elem, expt_entry[j++], tol);
0049     }
0050   }
0051 }
0052 
0053 }  // anonymous namespace
0054 
0055 TEST(grids_cuda, grid3_replace_populator) {
0056   // memory resource
0057   vecmem::cuda::managed_memory_resource mng_mr;
0058 
0059   // Build multi-axis
0060   using axes_t = host_grid3_single::axes_type;
0061   using bin_t = host_grid3_single::bin_type;
0062 
0063   typename axes_t::edge_offset_container_type axis_data(&mng_mr);
0064   typename axes_t::edges_container_type bin_edges(&mng_mr);
0065 
0066   axis_data.reserve(3);
0067   axis_data.insert(axis_data.begin(),
0068                    {dsized_index_range{0u, 3u}, dsized_index_range{2u, 6u},
0069                     dsized_index_range{4u, 10u}});
0070   bin_edges.reserve(6);
0071   bin_edges.insert(bin_edges.begin(), {-1.f, 2.f, 0.f, 6.f, -5.f, 5.f});
0072 
0073   axes_t axes(std::move(axis_data), std::move(bin_edges));
0074 
0075   // build host grid
0076   host_grid3_single::bin_container_type bin_data(&mng_mr);
0077   bin_data.resize(3u * 6u * 10u, bin_t{});
0078 
0079   host_grid3_single g3(std::move(bin_data), std::move(axes));
0080 
0081   const auto& axis_x = g3.template get_axis<axis::label::e_x>();
0082   const auto& axis_y = g3.template get_axis<axis::label::e_y>();
0083   const auto& axis_z = g3.template get_axis<axis::label::e_z>();
0084 
0085   // pre-check
0086   for (unsigned int i_x = 0u; i_x < axis_x.nbins(); i_x++) {
0087     for (unsigned int i_y = 0u; i_y < axis_y.nbins(); i_y++) {
0088       for (unsigned int i_z = 0u; i_z < axis_z.nbins(); i_z++) {
0089         const auto& bin = g3.bin(i_x, i_y, i_z);
0090         auto invalid_bin = bin_t{};
0091         test_content(bin.value(), invalid_bin.value());
0092       }
0093     }
0094   }
0095   // run device side test, which populates the grid
0096   grid_replace_test(get_data(g3), axis_x.nbins(), axis_y.nbins(),
0097                     axis_z.nbins());
0098   // post-check
0099   for (unsigned int i_x = 0u; i_x < axis_x.nbins(); i_x++) {
0100     for (unsigned int i_y = 0u; i_y < axis_y.nbins(); i_y++) {
0101       for (unsigned int i_z = 0u; i_z < axis_z.nbins(); i_z++) {
0102         const dindex gbin = g3.serialize({i_x, i_y, i_z});
0103 
0104         const auto& bin = g3.bin(gbin);
0105 
0106         const scalar gbin_f{static_cast<scalar>(gbin)};
0107         const point3 tp{axis_x.min() + gbin_f * axis_x.bin_width(),
0108                         axis_y.min() + gbin_f * axis_y.bin_width(),
0109                         axis_z.min() + gbin_f * axis_z.bin_width()};
0110 
0111         test_content(bin.value(), tp);
0112       }
0113     }
0114   }
0115 
0116   // Print the grid on device
0117   // print_grid<device_grid3_single>(get_data(g3), axis_x.nbins(),
0118   // axis_y.nbins(), axis_z.nbins());
0119 }
0120 
0121 TEST(grids_cuda, grid2_replace_populator_ci) {
0122   vecmem::cuda::managed_memory_resource mng_mr;
0123 
0124   // Build multi-axis
0125   using axes_t = host_grid2_single_ci::axes_type;
0126   using bin_t = host_grid2_single_ci::bin_type;
0127 
0128   typename axes_t::edge_offset_container_type axis_data(&mng_mr);
0129   typename axes_t::edges_container_type bin_edges(&mng_mr);
0130 
0131   axis_data.reserve(2u);
0132   axis_data.insert(axis_data.end(),
0133                    {dsized_index_range{0u, 4u}, dsized_index_range{5u, 2u}});
0134   bin_edges.reserve(7u);
0135   bin_edges.insert(bin_edges.end(), {1.f, 3.f, 9.f, 27.f, 81.f, -2.f, 4.f});
0136 
0137   axes_t axes(std::move(axis_data), std::move(bin_edges));
0138 
0139   // build host grid
0140   host_grid2_single_ci::bin_container_type bin_data(&mng_mr);
0141   bin_data.resize(4u * 2u, bin_t{});
0142 
0143   host_grid2_single_ci g2(std::move(bin_data), std::move(axes));
0144 
0145   const auto& axis_r = g2.template get_axis<axis::label::e_r>();
0146   const auto& axis_phi = g2.template get_axis<axis::label::e_phi>();
0147 
0148   // pre-check
0149   for (unsigned int i_r = 0u; i_r < axis_r.nbins(); i_r++) {
0150     for (unsigned int i_phi = 0u; i_phi < axis_phi.nbins(); i_phi++) {
0151       const auto& bin = g2.bin(i_r, i_phi);
0152       auto invalid_bin = bin_t{};
0153 
0154       test_content(bin.value(), invalid_bin.value());
0155     }
0156   }
0157 
0158   // run device side test, which populates the grid
0159   grid_replace_ci_test(get_data(g2), axis_r.nbins(), axis_phi.nbins());
0160 
0161   // post-check
0162   for (unsigned int i_r = 0u; i_r < axis_r.nbins(); i_r++) {
0163     for (unsigned int i_phi = 0u; i_phi < axis_phi.nbins(); i_phi++) {
0164       const dindex gbin = g2.serialize({i_r, i_phi});
0165       const auto& bin = g2.bin(gbin);
0166 
0167       const scalar gbin_f{static_cast<scalar>(gbin)};
0168       const point3 tp{axis_r.min() + gbin_f * axis_r.bin_width(i_r),
0169                       axis_phi.min() + gbin_f * axis_phi.bin_width(), 0.5f};
0170 
0171       test_content(bin.value(), tp);
0172     }
0173   }
0174 
0175   // Print the grid on device
0176   // print_grid<device_grid2_single_ci>(get_data(g2), axis_r.nbins(),
0177   // axis_phi.nbins());
0178 }
0179 
0180 TEST(grids_cuda, grid2_complete_populator) {
0181   // memory resource
0182   vecmem::cuda::managed_memory_resource mng_mr;
0183 
0184   // Build multi-axis
0185   using axes_t = host_grid2_array::axes_type;
0186   using bin_t = host_grid2_array::bin_type;
0187 
0188   typename axes_t::edge_offset_container_type axis_data(&mng_mr);
0189   typename axes_t::edges_container_type bin_edges(&mng_mr);
0190 
0191   axis_data.reserve(2u);
0192   axis_data.insert(axis_data.begin(),
0193                    {dsized_index_range{0u, 3u}, dsized_index_range{2u, 7u}});
0194   bin_edges.reserve(4);
0195   bin_edges.insert(bin_edges.begin(), {0.f, 3.f, -1.f, 6.f});
0196 
0197   axes_t axes(std::move(axis_data), std::move(bin_edges));
0198 
0199   // build host grid
0200   const point3 first_tp{3.f, 3.f, 3.f};
0201 
0202   host_grid2_array::bin_container_type bin_data(&mng_mr);
0203   bin_data.resize(3u * 7u, bin_t{}.init(first_tp));
0204 
0205   host_grid2_array g2(std::move(bin_data), std::move(axes));
0206 
0207   const auto& axis_r = g2.template get_axis<axis::label::e_r>();
0208   const auto& axis_phi = g2.template get_axis<axis::label::e_phi>();
0209 
0210   auto width_r = axis_r.bin_width();
0211   auto width_phi = axis_phi.bin_width();
0212 
0213   // pre-check
0214   for (unsigned int i_r = 0u; i_r < axis_r.nbins(); i_r++) {
0215     for (unsigned int i_phi = 0u; i_phi < axis_phi.nbins(); i_phi++) {
0216       const auto& bin = g2.bin(i_r, i_phi);
0217       auto invalid_bin = bin_t{}.init(first_tp);
0218 
0219       test_entry_collection(bin, invalid_bin);
0220     }
0221   }
0222 
0223   // run device side test, which populates the grid
0224   grid_complete_test(get_data(g2), axis_r.nbins(), axis_phi.nbins());
0225 
0226   // post-check
0227   for (unsigned int i_r = 0u; i_r < axis_r.nbins(); i_r++) {
0228     for (unsigned int i_phi = 0u; i_phi < axis_phi.nbins(); i_phi++) {
0229       const dindex gbin = g2.serialize({i_r, i_phi});
0230       const auto& bin = g2.bin(gbin);
0231 
0232       // Other point with which the bin has been completed
0233       const scalar gbin_f{static_cast<scalar>(gbin)};
0234       const point3 tp{axis_r.min() + gbin_f * width_r,
0235                       axis_phi.min() + gbin_f * width_phi,
0236                       static_cast<scalar>(0.5)};
0237 
0238       // Go through all points and compare
0239       int pt_idx{0};
0240       for (const auto& pt : bin) {
0241         if (pt_idx == 0) {
0242           EXPECT_EQ(pt, first_tp);
0243         } else {
0244           EXPECT_EQ(pt, tp);
0245         }
0246         pt_idx++;
0247       }
0248     }
0249   }
0250 
0251   // Print the grid on device
0252   // print_grid<device_grid2_array>(get_data(g2), axis_r.nbins(),
0253   // axis_phi.nbins());
0254 }
0255 
0256 // Test both the attach population and the const grid reading
0257 TEST(grids_cuda, grid2_attach_populator) {
0258   // memory resource
0259   vecmem::cuda::managed_memory_resource mng_mr;
0260 
0261   // Build multi-axis
0262   using axes_t = host_grid2_array::axes_type;
0263   using bin_t = host_grid2_array::bin_type;
0264 
0265   typename axes_t::edge_offset_container_type axis_data(&mng_mr);
0266   typename axes_t::edges_container_type bin_edges(&mng_mr);
0267 
0268   axis_data.reserve(2);
0269   axis_data.insert(axis_data.begin(),
0270                    {dsized_index_range{0u, 2u}, dsized_index_range{2u, 65u}});
0271   bin_edges.reserve(4);
0272   bin_edges.insert(bin_edges.begin(),
0273                    {0.f, 6.f, -constant<scalar>::pi, constant<scalar>::pi});
0274 
0275   axes_t axes(std::move(axis_data), std::move(bin_edges));
0276 
0277   // build host grid
0278   const point3 first_tp{3.f, 3.f, 3.f};
0279   const point3 invalid_tp{0.f, 0.f, 0.f};
0280 
0281   host_grid2_array::bin_container_type bin_data(&mng_mr);
0282   bin_data.resize(2u * 65u, bin_t{}.init(first_tp));
0283 
0284   host_grid2_array g2(std::move(bin_data), std::move(axes));
0285 
0286   const auto& axis_r = g2.template get_axis<axis::label::e_r>();
0287   const auto& axis_phi = g2.template get_axis<axis::label::e_phi>();
0288 
0289   auto width_r = axis_r.bin_width();
0290   auto width_phi = axis_phi.bin_width();
0291 
0292   // pre-check
0293   for (unsigned int i_r = 0u; i_r < axis_r.nbins(); i_r++) {
0294     for (unsigned int i_phi = 0u; i_phi < axis_phi.nbins(); i_phi++) {
0295       auto bin = g2.bin(i_r, i_phi);
0296       auto invalid_bin = bin_t{}.init(first_tp);
0297 
0298       test_entry_collection(bin, invalid_bin);
0299     }
0300   }
0301 
0302   // run device side test, which populates the grid
0303   grid_attach_test(get_data(g2), axis_r.nbins(), axis_phi.nbins());
0304 
0305   // post-check
0306   for (unsigned int i_r = 0u; i_r < axis_r.nbins(); i_r++) {
0307     for (unsigned int i_phi = 0u; i_phi < axis_phi.nbins(); i_phi++) {
0308       const dindex gbin = g2.serialize({i_r, i_phi});
0309       const auto& bin = g2.bin(gbin);
0310 
0311       // Other point with which the bin has been completed
0312       const scalar gbin_f{static_cast<scalar>(gbin)};
0313       const point3 tp{axis_r.min() + gbin_f * width_r,
0314                       axis_phi.min() + gbin_f * width_phi,
0315                       static_cast<scalar>(0.5)};
0316 
0317       // Go through all points and compare
0318       int pt_idx{0};
0319       for (const auto& pt : bin) {
0320         if (pt_idx == 0) {
0321           EXPECT_POINT3_NEAR(pt, first_tp, 1e-6);
0322         } else if (pt_idx == 1) {
0323           EXPECT_POINT3_NEAR(pt, tp, 1e-6);
0324         } else {
0325           EXPECT_POINT3_NEAR(pt, invalid_tp, 1e-6);
0326         }
0327         pt_idx++;
0328       }
0329     }
0330   }
0331 
0332   // Print the grid on device
0333   // print_grid<device_grid2_array>(get_data(g2), axis_r.nbins(),
0334   // axis_phi.nbins());
0335 }
0336 
0337 // Test the attach population on a grid with dynamic bin capacities
0338 TEST(grids_cuda, grid2_dynamic_attach_populator) {
0339   // memory resource
0340   vecmem::cuda::managed_memory_resource mng_mr;
0341 
0342   // Build multi-axis
0343   using axes_t = host_grid2_dynamic_array::axes_type;
0344   using bin_t = host_grid2_dynamic_array::bin_type;
0345 
0346   typename axes_t::edge_offset_container_type axis_data(&mng_mr);
0347   typename axes_t::edges_container_type bin_edges(&mng_mr);
0348 
0349   axis_data.reserve(2);
0350   axis_data.insert(axis_data.begin(),
0351                    {dsized_index_range{0u, 2u}, dsized_index_range{2u, 65u}});
0352   bin_edges.reserve(4);
0353   bin_edges.insert(bin_edges.begin(),
0354                    {0.f, 6.f, -constant<scalar>::pi, constant<scalar>::pi});
0355 
0356   axes_t axes(std::move(axis_data), std::move(bin_edges));
0357 
0358   // build host grid
0359   const point3 first_tp{3.f, 3.f, 3.f};
0360   const point3 invalid_tp{0.f, 0.f, 0.f};
0361 
0362   host_grid2_dynamic_array::bin_container_type bin_data{&mng_mr};
0363   vecmem::vector<bin_t::entry_type> entries{&mng_mr};
0364   bin_data.bins.resize(2 * 65);
0365   bin_data.entries.resize(4 * bin_data.bins.size());
0366 
0367   int i{0};
0368   dindex offset{0u};
0369   attach<> attacher{};
0370 
0371   // bin content with different bin capacities
0372   for (auto& data : bin_data.bins) {
0373     data.offset = offset;
0374     // Every second bin holds one element, otherwise three
0375     data.capacity = (i % 2) ? 1u : 3u;
0376 
0377     detray::bins::dynamic_array bin{bin_data.entries.data(), data};
0378 
0379     ASSERT_TRUE(bin.capacity() == (i % 2 ? 1u : 3u));
0380     ASSERT_TRUE(bin.size() == 0);
0381 
0382     offset += bin.capacity();
0383 
0384     // Populate the bin
0385     attacher(bin, first_tp);
0386     ++i;
0387   }
0388 
0389   host_grid2_dynamic_array g2(std::move(bin_data), std::move(axes));
0390 
0391   const auto& axis_r = g2.template get_axis<axis::label::e_r>();
0392   const auto& axis_phi = g2.template get_axis<axis::label::e_phi>();
0393 
0394   auto width_r = axis_r.bin_width();
0395   auto width_phi = axis_phi.bin_width();
0396 
0397   // pre-check
0398   for (unsigned int i_phi = 0u; i_phi < axis_phi.nbins(); i_phi++) {
0399     for (unsigned int i_r = 0u; i_r < axis_r.nbins(); i_r++) {
0400       int pt_idx{0};
0401       for (auto e : g2.bin(i_r, i_phi)) {
0402         if (pt_idx == 0) {
0403           EXPECT_EQ(e, first_tp);
0404         } else {
0405           EXPECT_EQ(e, invalid_tp);
0406         }
0407       }
0408     }
0409   }
0410 
0411   // run device side test, which populates the grid
0412   grid_dynamic_attach_test(get_data(g2), axis_r.nbins(), axis_phi.nbins());
0413 
0414   // post-check
0415   for (unsigned int i_r = 0u; i_r < axis_r.nbins(); i_r++) {
0416     for (unsigned int i_phi = 0u; i_phi < axis_phi.nbins(); i_phi++) {
0417       const dindex gbin = g2.serialize({i_r, i_phi});
0418       const auto& bin = g2.bin(gbin);
0419 
0420       // Other point with which the bin has been completed
0421       const scalar gbin_f{static_cast<scalar>(gbin)};
0422       const point3 tp{axis_r.min() + gbin_f * width_r,
0423                       axis_phi.min() + gbin_f * width_phi,
0424                       static_cast<scalar>(0.5)};
0425 
0426       // Go through all points and compare
0427       int pt_idx{0};
0428       for (const auto& e : bin) {
0429         if (pt_idx == 0) {
0430           EXPECT_POINT3_NEAR(e, first_tp, 1e-6);
0431         } else if (pt_idx == 1) {
0432           EXPECT_POINT3_NEAR(e, tp, 1e-6);
0433         } else {
0434           EXPECT_POINT3_NEAR(e, invalid_tp, 1e-6);
0435         }
0436         pt_idx++;
0437       }
0438     }
0439   }
0440 
0441   // Print the grid on device
0442   // print_grid<device_grid2_dynamic_array>(get_data(g2), axis_r.nbins(),
0443   // axis_phi.nbins());
0444 }
0445 
0446 TEST(grids_cuda, cylindrical3D_collection) {
0447   // Data-owning grid collection
0448   vecmem::cuda::managed_memory_resource mng_mr;
0449 
0450   using grid_collection_t = grid_collection<n_own_host_grid3_array>;
0451   using bin_t = grid_collection_t::value_type::bin_type;
0452 
0453   vecmem::vector<typename grid_collection_t::size_type> grid_offsets(&mng_mr);
0454   typename grid_collection_t::bin_container_type bin_data(&mng_mr);
0455   typename grid_collection_t::edge_offset_container_type edge_ranges(&mng_mr);
0456   typename grid_collection_t::edges_container_type bin_edges(&mng_mr);
0457 
0458   // Offsets for the grids into the bin storage
0459   grid_offsets.reserve(3u);
0460   grid_offsets.insert(grid_offsets.begin(), {0u, 48u, 72u});
0461 
0462   // Offsets into edges container and #bins for all axes
0463   edge_ranges.reserve(9u);
0464   edge_ranges.insert(edge_ranges.begin(),
0465                      {dsized_index_range{0u, 2u}, dsized_index_range{2u, 4u},
0466                       dsized_index_range{4u, 6u}, dsized_index_range{6u, 1u},
0467                       dsized_index_range{8u, 3u}, dsized_index_range{10u, 8u},
0468                       dsized_index_range{12u, 5u}, dsized_index_range{14u, 5u},
0469                       dsized_index_range{16u, 5u}});
0470 
0471   // Bin edges for all axes (two boundaries for regular binned axes)
0472   bin_edges.reserve(18u);
0473   bin_edges.insert(bin_edges.begin(),
0474                    {-10.f, 10.f, -20.f, 20.f, 0.f, 120.f, -5.f, 5.f, -15.f,
0475                     15.f, 0.f, 50.f, -15.f, 15.f, -35.f, 35.f, 0.f, 550.f});
0476 
0477   // Bin test entries
0478   bin_data.resize(197u, bin_t{});
0479 
0480   // Read the number of bins and bin entries on device
0481   vecmem::vector<unsigned int> n_bins(9u, &mng_mr);
0482   vecmem::vector<std::array<dindex, 3>> result_bins(bin_data.size(), &mng_mr);
0483 
0484   grid_collection_t grid_coll(std::move(grid_offsets), std::move(bin_data),
0485                               std::move(edge_ranges), std::move(bin_edges));
0486 
0487   // Call test function
0488   const auto& axis_r = grid_coll[2].template get_axis<axis::label::e_r>();
0489   const auto& axis_phi = grid_coll[2].template get_axis<axis::label::e_phi>();
0490   const auto& axis_z = grid_coll[2].template get_axis<axis::label::e_z>();
0491 
0492   grid_collection_test(get_data(grid_coll), vecmem::get_data(n_bins),
0493                        vecmem::get_data(result_bins), grid_coll.size(),
0494                        axis_r.nbins(), axis_phi.nbins(), axis_z.nbins());
0495 
0496   // Compare results
0497   EXPECT_EQ(4u, n_bins[0]);
0498   EXPECT_EQ(4u, n_bins[1]);
0499   EXPECT_EQ(8u, n_bins[2]);
0500   EXPECT_EQ(3u, n_bins[3]);
0501   EXPECT_EQ(3u, n_bins[4]);
0502   EXPECT_EQ(10u, n_bins[5]);
0503   EXPECT_EQ(7u, n_bins[6]);
0504   EXPECT_EQ(5u, n_bins[7]);
0505   EXPECT_EQ(7u, n_bins[8]);
0506 
0507   for (unsigned int i{0u}; i < bin_data.size(); ++i) {
0508     test_content(bin_data[i], result_bins[i]);
0509   }
0510 }