File indexing completed on 2026-05-27 07:24:22
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include "detray/definitions/indexing.hpp"
0011 #include "detray/geometry/shapes/cuboid3D.hpp"
0012 #include "detray/navigation/accelerators/concepts.hpp"
0013 #include "detray/utils/grid/concepts.hpp"
0014 #include "detray/utils/grid/grid.hpp"
0015
0016
0017 #include "detray/test/framework/types.hpp"
0018
0019
0020 #include <vecmem/containers/device_vector.hpp>
0021 #include <vecmem/containers/vector.hpp>
0022 #include <vecmem/memory/host_memory_resource.hpp>
0023
0024
0025 #include <gtest/gtest.h>
0026
0027
0028 #include <algorithm>
0029 #include <limits>
0030 #include <random>
0031
0032 using namespace detray;
0033 using namespace detray::axis;
0034
0035 namespace {
0036
0037
0038 using test_algebra = test::algebra;
0039 using scalar = test::scalar;
0040 using point3 = test::point3;
0041
0042
0043 template <bool ownership = true, typename containers = host_container_types>
0044 using cartesian_3D =
0045 coordinate_axes<axes<cuboid3D>, test_algebra, ownership, containers>;
0046
0047
0048 bool constexpr is_owning = true;
0049 bool constexpr is_n_owning = false;
0050
0051
0052 dvector<scalar> bin_edges = {-10.f, 10.f, -20.f, 20.f, 0.f, 100.f};
0053
0054 dvector<dsized_index_range> edge_ranges = {{0u, 20u}, {2u, 40u}, {4u, 50u}};
0055
0056
0057 cartesian_3D<is_n_owning, host_container_types> ax_n_own(edge_ranges,
0058 bin_edges);
0059
0060
0061 template <typename populator_t, typename bin_t>
0062 struct bin_content_sequence {
0063 using entry_t = typename bin_t::entry_type;
0064 entry_t entry{0};
0065
0066 auto operator()() {
0067 entry += entry_t{1};
0068 bin_t bin{};
0069 populator_t{}(bin, entry);
0070 return bin;
0071 }
0072 };
0073
0074 }
0075
0076
0077 GTEST_TEST(detray_acceleration_structures, spatial_grid) {
0078
0079 using grid_t = grid<test_algebra, axes<cuboid3D>, bins::single<scalar>>;
0080 using spatial_grid_t = spatial_grid_impl<grid_t>;
0081
0082 static_assert(concepts::grid<spatial_grid_t>);
0083 static_assert(concepts::accelerator<spatial_grid_t>);
0084
0085
0086
0087 spatial_grid_t::bin_container_type bin_data{};
0088 bin_data.resize(40'000u);
0089 std::ranges::generate_n(
0090 bin_data.begin(), 40'000u,
0091 bin_content_sequence<replace<>, bins::single<scalar>>());
0092
0093
0094 dvector<scalar> bin_edges_cp(bin_edges);
0095 dvector<dsized_index_range> edge_ranges_cp(edge_ranges);
0096 spatial_grid_t::bin_container_type bin_data_cp(bin_data);
0097
0098
0099 cartesian_3D<is_owning, host_container_types> axes_own(
0100 std::move(edge_ranges_cp), std::move(bin_edges_cp));
0101 spatial_grid_t grid_3D(std::move(bin_data_cp), std::move(axes_own));
0102
0103
0104 point3 p = {-10.f, -20.f, 0.f};
0105
0106 std::array<dindex, 2> search_window_size{0, 0};
0107 axis::multi_bin_range<3> search_window{
0108 axis::bin_range{0, 1}, axis::bin_range{0, 1}, axis::bin_range{0, 1}};
0109
0110 const auto bview1 = axis::detail::bin_view(grid_3D, search_window);
0111 const auto joined_view1 = detray::views::join(bview1);
0112 const auto grid_search1 = grid_3D.search(p, search_window_size);
0113
0114 static_assert(detray::ranges::bidirectional_range<decltype(bview1)>);
0115 static_assert(detray::ranges::bidirectional_range<decltype(joined_view1)>);
0116 static_assert(detray::ranges::bidirectional_range<decltype(grid_search1)>);
0117
0118 ASSERT_EQ(bview1.size(), 1u);
0119 ASSERT_EQ(joined_view1.size(), 1u);
0120 ASSERT_EQ(grid_search1.size(), 1u);
0121
0122 for (auto bin : bview1) {
0123 for (auto entry : bin) {
0124 EXPECT_EQ(entry, grid_3D.bin(0).value()) << "bin entry: " << entry;
0125 }
0126 }
0127
0128 for (scalar entry : joined_view1) {
0129 EXPECT_EQ(entry, grid_3D.bin(0).value()) << "bin entry: " << entry;
0130 }
0131
0132 for (scalar entry : grid_search1) {
0133 EXPECT_EQ(entry, grid_3D.bin(0).value()) << "bin entry: " << entry;
0134 }
0135
0136
0137
0138
0139 search_window_size[0] = 1;
0140 search_window_size[1] = 1;
0141 search_window[0] = axis::bin_range{0, 2};
0142 search_window[1] = axis::bin_range{0, 2};
0143 search_window[2] = axis::bin_range{0, 2};
0144
0145 std::vector<scalar> expected{1, 801, 21, 821, 2, 802, 22, 822};
0146
0147 const auto bview2 = axis::detail::bin_view(grid_3D, search_window);
0148 const auto joined_view2 = detray::views::join(bview2);
0149 const auto grid_search2 = grid_3D.search(p, search_window_size);
0150
0151 static_assert(detray::ranges::bidirectional_range<decltype(bview2)>);
0152 static_assert(detray::ranges::bidirectional_range<decltype(joined_view2)>);
0153 static_assert(detray::ranges::bidirectional_range<decltype(grid_search2)>);
0154
0155 ASSERT_EQ(bview2.size(), 8u);
0156 ASSERT_EQ(joined_view2.size(), 8u);
0157 ASSERT_EQ(grid_search2.size(), 8u);
0158
0159 for (auto [i, bin] : detray::views::enumerate(bview2)) {
0160 for (scalar entry : bin) {
0161 EXPECT_EQ(entry, expected[i]) << "bin entry: " << entry;
0162 }
0163 }
0164
0165 for (auto [i, entry] : detray::views::enumerate(joined_view2)) {
0166 EXPECT_EQ(entry, expected[i]) << "bin entry: " << entry;
0167 }
0168
0169 for (auto [i, entry] : detray::views::enumerate(grid_search2)) {
0170 EXPECT_EQ(entry, expected[i]) << "bin entry: " << entry;
0171 }
0172
0173
0174
0175
0176 p = {-9.f, -19.f, 2.f};
0177 search_window[0] = axis::bin_range{0, 3};
0178 search_window[1] = axis::bin_range{0, 3};
0179 search_window[2] = axis::bin_range{0, 3};
0180
0181 expected = {1, 801, 1601, 21, 821, 1621, 41, 841, 1641,
0182 2, 802, 1602, 22, 822, 1622, 42, 842, 1642,
0183 3, 803, 1603, 23, 823, 1623, 43, 843, 1643};
0184
0185 const auto bview3 = axis::detail::bin_view(grid_3D, search_window);
0186 const auto joined_view3 = detray::views::join(bview3);
0187 const auto grid_search3 = grid_3D.search(p, search_window_size);
0188
0189 static_assert(detray::ranges::bidirectional_range<decltype(bview3)>);
0190 static_assert(detray::ranges::bidirectional_range<decltype(joined_view3)>);
0191 static_assert(detray::ranges::bidirectional_range<decltype(grid_search3)>);
0192
0193 ASSERT_EQ(bview3.size(), 27u);
0194 ASSERT_EQ(joined_view3.size(), 27u);
0195 ASSERT_EQ(grid_search3.size(), 27u);
0196
0197 for (auto [i, bin] : detray::views::enumerate(bview3)) {
0198 for (scalar entry : bin) {
0199 EXPECT_EQ(entry, expected[i]) << "bin entry: " << entry;
0200 }
0201 }
0202
0203 for (auto [i, entry] : detray::views::enumerate(joined_view3)) {
0204 EXPECT_EQ(entry, expected[i]) << "bin entry: " << entry;
0205 }
0206
0207 for (auto [i, entry] : detray::views::enumerate(grid_search3)) {
0208 EXPECT_EQ(entry, expected[i]) << "bin entry: " << entry;
0209 }
0210 }
0211
0212
0213 GTEST_TEST(detray_acceleration_structures, spatial_grid_complete_population) {
0214
0215 using grid_t =
0216 grid<test_algebra, decltype(ax_n_own), bins::static_array<scalar, 4>,
0217 simple_serializer, host_container_types, false>;
0218 using spatial_grid_t = spatial_grid_impl<grid_t>;
0219
0220 static_assert(concepts::grid<spatial_grid_t>);
0221 static_assert(concepts::accelerator<spatial_grid_t>);
0222
0223
0224 spatial_grid_t::bin_container_type bin_data{};
0225 bin_data.resize(40'000u, spatial_grid_t::bin_type{});
0226
0227 // Create non-owning grid
0228 spatial_grid_t g3c(&bin_data, ax_n_own);
0229 // Fill and read
0230 point3 p = {-4.5f, -4.5f, 4.5f};
0231 g3c.template populate<complete<>>(p, 4.f);
0232
0233 // Test search without search window
0234 for (scalar entry : g3c.search(p)) {
0235 EXPECT_EQ(entry, 4.f);
0236 }
0237
0238 std::array<dindex, 2> search_window_size{0, 0};
0239
0240 const auto grid_search1 = g3c.search(p, search_window_size);
0241
0242 static_assert(detray::ranges::bidirectional_range<decltype(grid_search1)>);
0243
0244 ASSERT_EQ(grid_search1.size(), 4u);
0245
0246 for (scalar entry : grid_search1) {
0247 EXPECT_EQ(entry, 4.f);
0248 }
0249
0250 // No neighbors were filled, expect the same candidates
0251 search_window_size[0] = 1;
0252 search_window_size[1] = 1;
0253
0254 const auto grid_search2 = g3c.search(p, search_window_size);
0255
0256 static_assert(detray::ranges::bidirectional_range<decltype(grid_search2)>);
0257
0258 ASSERT_EQ(grid_search2.size(), 4u);
0259
0260 for (scalar entry : grid_search2) {
0261 EXPECT_EQ(entry, 4.f);
0262 }
0263
0264 // Populate some neighboring bins
0265 point3 p2 = {-5.5f, -4.5f, 4.5f};
0266 g3c.template populate<complete<>>(p2, 4.f);
0267 p2 = {-3.5f, -4.5f, 4.5f};
0268 g3c.template populate<complete<>>(p2, 4.f);
0269 p2 = {-4.5f, -5.5f, 4.5f};
0270 g3c.template populate<complete<>>(p2, 4.f);
0271 p2 = {-4.5f, -3.5f, 4.5f};
0272 g3c.template populate<complete<>>(p2, 4.f);
0273
0274 const auto grid_search3 = g3c.search(p, search_window_size);
0275 ASSERT_EQ(grid_search3.size(), 20u);
0276
0277 for (scalar entry : grid_search3) {
0278 EXPECT_EQ(entry, 4.f);
0279 }
0280 }
0281
0282 /// Test bin entry retrieval
0283 GTEST_TEST(detray_acceleration_structures,
0284 spatial_grid_regular_attach_population) {
0285 // Non-owning, 3D cartesian, completing grid (4 dims and sort)
0286 using grid_t =
0287 grid<test_algebra, decltype(ax_n_own), bins::static_array<scalar, 4>,
0288 simple_serializer, host_container_types, false>;
0289 using spatial_grid_t = spatial_grid_impl<grid_t>;
0290
0291 static_assert(concepts::grid<spatial_grid_t>);
0292 static_assert(concepts::accelerator<spatial_grid_t>);
0293
0294 // init
0295 spatial_grid_t::bin_container_type bin_data{};
0296 bin_data.resize(40'000u, spatial_grid_t::bin_type{});
0297
0298
0299 spatial_grid_t g3ra(&bin_data, ax_n_own);
0300
0301 point3 p = {-4.5f, -4.5f, 4.5f};
0302 g3ra.template populate<attach<>>(p, 5.f);
0303
0304
0305 for (scalar entry : g3ra.search(p)) {
0306 EXPECT_EQ(entry, 5.f);
0307 }
0308
0309 std::array<dindex, 2> search_window_size{0, 0};
0310
0311 const auto grid_search1 = g3ra.search(p, search_window_size);
0312
0313 static_assert(detray::ranges::bidirectional_range<decltype(grid_search1)>);
0314
0315 ASSERT_EQ(grid_search1.size(), 1u);
0316
0317 for (scalar entry : grid_search1) {
0318 EXPECT_EQ(entry, 5.f);
0319 }
0320
0321
0322 search_window_size[0] = 1;
0323 search_window_size[1] = 1;
0324
0325 const auto grid_search2 = g3ra.search(p, search_window_size);
0326
0327 static_assert(detray::ranges::bidirectional_range<decltype(grid_search2)>);
0328
0329 ASSERT_EQ(grid_search2.size(), 1u);
0330
0331 for (scalar entry : grid_search2) {
0332 EXPECT_EQ(entry, 5.f);
0333 }
0334
0335
0336 g3ra.template populate<attach<>>(p, 6.f);
0337 g3ra.template populate<attach<>>(p, 7.f);
0338 std::vector<scalar> entries{5.f, 6.f, 7.f};
0339
0340 const auto grid_search3 = g3ra.search(p, search_window_size);
0341 ASSERT_EQ(grid_search3.size(), 3u);
0342
0343 for (auto [i, entry] : detray::views::enumerate(grid_search3)) {
0344 EXPECT_EQ(entry, entries[i]);
0345 }
0346
0347
0348 point3 p2 = {-5.5f, -4.5f, 4.5f};
0349 g3ra.template populate<attach<>>(p2, 5.f);
0350 p2 = {-3.5f, -4.5f, 4.5f};
0351 g3ra.template populate<attach<>>(p2, 5.f);
0352 p2 = {-4.5f, -5.5f, 4.5f};
0353 g3ra.template populate<attach<>>(p2, 5.f);
0354 p2 = {-4.5f, -3.5f, 4.5f};
0355 g3ra.template populate<attach<>>(p2, 5.f);
0356
0357 const auto grid_search4 = g3ra.search(p, search_window_size);
0358 ASSERT_EQ(grid_search4.size(), 7u);
0359
0360 for (scalar entry : grid_search4) {
0361 EXPECT_TRUE(entry == 5.f || entry == 6.f || entry == 7.f);
0362 }
0363 }