File indexing completed on 2026-05-27 07:24:20
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include "detray/builders/grid_builder.hpp"
0011
0012 #include "detray/builders/surface_factory.hpp"
0013 #include "detray/builders/volume_builder.hpp"
0014 #include "detray/core/detector.hpp"
0015 #include "detray/definitions/indexing.hpp"
0016 #include "detray/geometry/mask.hpp"
0017 #include "detray/geometry/shapes/annulus2D.hpp"
0018 #include "detray/utils/type_list.hpp"
0019
0020
0021 #include "detray/test/framework/types.hpp"
0022
0023
0024 #include <vecmem/memory/host_memory_resource.hpp>
0025
0026
0027 #include <gtest/gtest.h>
0028
0029
0030 #include <limits>
0031
0032 using namespace detray;
0033 using namespace detray::axis;
0034
0035 namespace {
0036
0037 test::transform3 Identity{};
0038
0039 using detector_t = detector<test::toy_metadata>;
0040 using algebra_t = typename detector_t::algebra_type;
0041 using scalar = dscalar<algebra_t>;
0042 using point3 = dpoint3D<algebra_t>;
0043 using vector3 = dvector3D<algebra_t>;
0044
0045
0046 struct mock_volume_builder : public volume_builder_interface<detector_t> {
0047 auto vol_index() const -> dindex override { return 0; }
0048 void has_accel(bool ) override { }
0049 bool has_accel() const override { return false; }
0050 void set_name(std::string ) override { }
0051 std::string_view name() override { return "test_volume_0"; }
0052 auto operator()() const -> const typename detector_t::volume_type& override {
0053 return m_vol;
0054 }
0055 auto operator()() -> typename detector_t::volume_type& override {
0056 return m_vol;
0057 }
0058 auto build(detector_t& ,
0059 typename detector_t::geometry_context = {}) ->
0060 typename detector_t::volume_type* override {
0061 return &m_vol;
0062 }
0063 void add_volume_placement(
0064 const typename detector_t::transform3_type& = {})
0065 override { }
0066 void add_volume_placement(const typename detector_t::point3_type& )
0067 override { }
0068 void add_volume_placement(const typename detector_t::point3_type& ,
0069 const typename detector_t::vector3_type& ,
0070 const typename detector_t::vector3_type& )
0071 override { }
0072 void add_surfaces(std::shared_ptr<surface_factory_interface<detector_t>>,
0073 typename detector_t::geometry_context = {})
0074 override { }
0075
0076 protected:
0077 typename detector_t::surface_lookup_container& surfaces() override {
0078 return m_sf_lookup;
0079 }
0080 typename detector_t::transform_container& transforms() override {
0081 return m_transforms;
0082 }
0083 typename detector_t::mask_container& masks() override { return m_masks; }
0084
0085 private:
0086 detector_t::volume_type m_vol{};
0087 detector_t::surface_lookup_container m_sf_lookup{};
0088 detector_t::transform_container m_transforms{};
0089 detector_t::mask_container m_masks{};
0090 };
0091
0092 }
0093
0094
0095 GTEST_TEST(detray_builders, grid_factory_static) {
0096
0097 vecmem::host_memory_resource host_mr;
0098 auto gr_factory =
0099 grid_factory<bins::static_array<dindex, 3>, simple_serializer, algebra_t>{
0100 host_mr};
0101
0102
0103 const scalar minR{0.f};
0104 const scalar maxR{10.f};
0105 const scalar minPhi{0.f};
0106 const scalar maxPhi{constant<scalar>::pi};
0107 mask<annulus2D, algebra_t> ann2{0u, minR, maxR, minPhi,
0108 maxPhi, 0.f, 0.f, 0.f};
0109
0110
0111 auto ann_gr = gr_factory.new_grid(ann2, {5, 10});
0112
0113
0114 const auto& ann_axis_r = ann_gr.template get_axis<label::e_r>();
0115 EXPECT_EQ(ann_axis_r.label(), label::e_r);
0116 EXPECT_EQ(ann_axis_r.bounds(), bounds::e_closed);
0117 EXPECT_EQ(ann_axis_r.binning(), binning::e_regular);
0118 EXPECT_EQ(ann_axis_r.nbins(), 5u);
0119 EXPECT_NEAR(ann_axis_r.span()[0], 0.f,
0120 std::numeric_limits<scalar>::epsilon());
0121 EXPECT_NEAR(ann_axis_r.span()[1], 10.f,
0122 std::numeric_limits<scalar>::epsilon());
0123
0124
0125 point3 p = {0.5f, 2.f, 0.f};
0126 vector3 d{};
0127 auto loc_p = ann_gr.project(Identity, p, d);
0128 ann_gr.template populate<attach<>>(loc_p, 3u);
0129 ann_gr.template populate<attach<>>(loc_p, 5u);
0130 auto bin2 = ann_gr.bin(loc_p);
0131
0132 EXPECT_TRUE(bin2.size() == 2u);
0133 EXPECT_FALSE(bin2.empty());
0134 EXPECT_EQ(bin2[0], 3u);
0135 EXPECT_EQ(bin2[1], 5u);
0136
0137
0138 const std::vector<scalar> bin_edges_z{-10.f, -8.f, -6.5f, -1.f,
0139 4.f, 5.f, 6.f, 9.f};
0140 const std::vector<scalar> bin_edges_phi{};
0141
0142 auto cyl_gr = gr_factory.template new_grid<cylinder2D>(
0143 std::vector<scalar>{0.f, 2.f * constant<scalar>::pi, bin_edges_z.front(),
0144 bin_edges_z.back()},
0145 {10u, bin_edges_z.size() - 1}, {}, {bin_edges_phi, bin_edges_z},
0146 types::list<circular<label::e_rphi>, closed<label::e_cyl_z>>{},
0147 types::list<regular<scalar>, irregular<scalar>>{});
0148
0149
0150 const auto& cyl_axis_rphi = cyl_gr.template get_axis<label::e_rphi>();
0151 EXPECT_EQ(cyl_axis_rphi.label(), label::e_rphi);
0152 EXPECT_EQ(cyl_axis_rphi.bounds(), bounds::e_circular);
0153 EXPECT_EQ(cyl_axis_rphi.binning(), binning::e_regular);
0154 EXPECT_EQ(cyl_axis_rphi.nbins(), 10u);
0155 EXPECT_NEAR(cyl_axis_rphi.span()[0], 0.f,
0156 std::numeric_limits<scalar>::epsilon());
0157 EXPECT_NEAR(cyl_axis_rphi.span()[1], 2.f * constant<scalar>::pi,
0158 std::numeric_limits<scalar>::epsilon());
0159
0160 const auto& cyl_axis_z = cyl_gr.template get_axis<label::e_cyl_z>();
0161 EXPECT_EQ(cyl_axis_z.label(), label::e_cyl_z);
0162 EXPECT_EQ(cyl_axis_z.bounds(), bounds::e_closed);
0163 EXPECT_EQ(cyl_axis_z.binning(), binning::e_irregular);
0164 EXPECT_EQ(cyl_axis_z.nbins(), 7u);
0165 EXPECT_NEAR(cyl_axis_z.span()[0], -10.f,
0166 std::numeric_limits<scalar>::epsilon());
0167 EXPECT_NEAR(cyl_axis_z.span()[1], 9.f,
0168 std::numeric_limits<scalar>::epsilon());
0169
0170
0171 loc_p = cyl_gr.project(Identity, p, d);
0172 cyl_gr.template populate<attach<>>(loc_p, 33u);
0173 cyl_gr.template populate<attach<>>(loc_p, 55u);
0174
0175 EXPECT_EQ(cyl_gr.bin(loc_p)[0], 33u);
0176 EXPECT_EQ(cyl_gr.bin(loc_p)[1], 55u);
0177
0178
0179 const scalar r{5.f};
0180 const scalar n_half_z{-10.f};
0181 const scalar p_half_z{9.f};
0182 mask<cylinder2D, algebra_t> cyl2{0u, r, n_half_z, p_half_z};
0183
0184 auto cyl_gr2 =
0185 gr_factory
0186 .template new_grid<circular<label::e_rphi>, closed<label::e_cyl_z>,
0187 regular<scalar>, irregular<scalar>>(
0188 cyl2, {bin_edges_z.size() - 1, 10u}, {},
0189 {bin_edges_phi, bin_edges_z});
0190 }
0191
0192
0193 GTEST_TEST(detray_builders, grid_factory_dynamic) {
0194
0195 vecmem::host_memory_resource host_mr;
0196 auto gr_factory =
0197 grid_factory<bins::dynamic_array<dindex>, simple_serializer, algebra_t>{
0198 host_mr};
0199
0200
0201 const scalar minR{0.f};
0202 const scalar maxR{10.f};
0203 const scalar minPhi{0.f};
0204 const scalar maxPhi{constant<scalar>::pi};
0205 mask<annulus2D, algebra_t> ann2{0u, minR, maxR, minPhi,
0206 maxPhi, 0.f, 0.f, 0.f};
0207
0208
0209 using ann_grid_t =
0210 typename decltype(gr_factory)::template grid_type<annulus2D>;
0211 std::vector<std::pair<typename ann_grid_t::loc_bin_index, dindex>> capacities;
0212
0213 auto bin_indexer2D = detray::views::cartesian_product{
0214 detray::views::iota{0u, 2u}, detray::views::iota{0u, 3u}};
0215 dindex capacity{0u};
0216 for (const auto [bin_idx0, bin_idx1] : bin_indexer2D) {
0217 typename ann_grid_t::loc_bin_index mbin{bin_idx0, bin_idx1};
0218 capacities.emplace_back(mbin, ++capacity);
0219 }
0220
0221 ann_grid_t ann_gr = gr_factory.new_grid(ann2, {2, 3}, capacities);
0222
0223
0224 const auto& ann_axis_r = ann_gr.template get_axis<label::e_r>();
0225 EXPECT_EQ(ann_axis_r.label(), label::e_r);
0226 EXPECT_EQ(ann_axis_r.bounds(), bounds::e_closed);
0227 EXPECT_EQ(ann_axis_r.binning(), binning::e_regular);
0228 EXPECT_EQ(ann_axis_r.nbins(), 2u);
0229 EXPECT_NEAR(ann_axis_r.span()[0], 0.f,
0230 std::numeric_limits<scalar>::epsilon());
0231 EXPECT_NEAR(ann_axis_r.span()[1], 10.f,
0232 std::numeric_limits<scalar>::epsilon());
0233
0234
0235 EXPECT_EQ(ann_gr.bins().size(), 6u);
0236 for (const auto& bin : ann_gr.bins()) {
0237 EXPECT_EQ(bin.size(), 0u);
0238 EXPECT_TRUE(bin.capacity() >= 1u);
0239 }
0240 EXPECT_EQ(ann_gr.size(), 0u);
0241
0242 EXPECT_EQ(ann_gr.bins().entry_data().size(), 21u);
0243 EXPECT_EQ(ann_gr.bins().entry_data().capacity(), 21u);
0244
0245
0246 point3 p = {0.5f, 2.f, 0.f};
0247 vector3 d{};
0248 auto loc_p = ann_gr.project(Identity, p, d);
0249 auto bin2 = ann_gr.bin(loc_p);
0250 EXPECT_TRUE(bin2.capacity() == 2u);
0251 EXPECT_TRUE(bin2.empty());
0252 EXPECT_TRUE(bin2.size() == 0u);
0253 ann_gr.template populate<attach<>>(loc_p, 3u);
0254 ann_gr.template populate<attach<>>(loc_p, 5u);
0255
0256 EXPECT_TRUE(bin2.capacity() == 2u);
0257 EXPECT_TRUE(bin2.size() == 2u);
0258 EXPECT_FALSE(bin2.empty());
0259 EXPECT_EQ(bin2[0], 3u);
0260 EXPECT_EQ(bin2[1], 5u);
0261
0262 EXPECT_EQ(ann_gr.size(), 2u);
0263
0264
0265 const std::vector<scalar> bin_edges_z{-10.f, -8.f, -6.5f, -1.f,
0266 4.f, 5.f, 6.f, 9.f};
0267 const std::vector<scalar> bin_edges_phi{};
0268
0269 bin_indexer2D = detray::views::cartesian_product{detray::views::iota{0u, 10u},
0270 detray::views::iota{0u, 7u}};
0271 capacity = 0u;
0272 capacities.clear();
0273 for (const auto [bin_idx0, bin_idx1] : bin_indexer2D) {
0274 typename ann_grid_t::loc_bin_index mbin{bin_idx0, bin_idx1};
0275 capacities.emplace_back(mbin, ++capacity);
0276 }
0277
0278 auto cyl_gr = gr_factory.template new_grid<concentric_cylinder2D>(
0279 std::vector<scalar>{0.f, 2.f * constant<scalar>::pi, bin_edges_z.front(),
0280 bin_edges_z.back()},
0281 {10u, bin_edges_z.size() - 1}, capacities, {bin_edges_phi, bin_edges_z},
0282 types::list<circular<label::e_rphi>, closed<label::e_cyl_z>>{},
0283 types::list<regular<scalar>, irregular<scalar>>{});
0284
0285
0286 const auto& cyl_axis_rphi = cyl_gr.template get_axis<label::e_rphi>();
0287 EXPECT_EQ(cyl_axis_rphi.label(), label::e_rphi);
0288 EXPECT_EQ(cyl_axis_rphi.bounds(), bounds::e_circular);
0289 EXPECT_EQ(cyl_axis_rphi.binning(), binning::e_regular);
0290 EXPECT_EQ(cyl_axis_rphi.nbins(), 10u);
0291 EXPECT_NEAR(cyl_axis_rphi.span()[0], 0.f,
0292 std::numeric_limits<scalar>::epsilon());
0293 EXPECT_NEAR(cyl_axis_rphi.span()[1], 2.f * constant<scalar>::pi,
0294 std::numeric_limits<scalar>::epsilon());
0295
0296 const auto& cyl_axis_z = cyl_gr.template get_axis<label::e_cyl_z>();
0297 EXPECT_EQ(cyl_axis_z.label(), label::e_cyl_z);
0298 EXPECT_EQ(cyl_axis_z.bounds(), bounds::e_closed);
0299 EXPECT_EQ(cyl_axis_z.binning(), binning::e_irregular);
0300 EXPECT_EQ(cyl_axis_z.nbins(), 7u);
0301 EXPECT_NEAR(cyl_axis_z.span()[0], -10.f,
0302 std::numeric_limits<scalar>::epsilon());
0303 EXPECT_NEAR(cyl_axis_z.span()[1], 9.f,
0304 std::numeric_limits<scalar>::epsilon());
0305
0306
0307 EXPECT_EQ(cyl_gr.bins().size(), 70u);
0308 for (const auto& bin : cyl_gr.bins()) {
0309 EXPECT_EQ(bin.size(), 0u);
0310 EXPECT_TRUE(bin.capacity() >= 1u);
0311 }
0312 EXPECT_EQ(cyl_gr.size(), 0u);
0313
0314 EXPECT_EQ(cyl_gr.bins().entry_data().size(), 2485u);
0315 EXPECT_EQ(cyl_gr.bins().entry_data().capacity(), 2485u);
0316
0317
0318 loc_p = cyl_gr.project(Identity, p, d);
0319 auto bin3 = cyl_gr.bin(loc_p);
0320
0321 EXPECT_TRUE(bin3.capacity() == 18u);
0322 EXPECT_TRUE(bin3.empty());
0323 EXPECT_TRUE(bin3.size() == 0u);
0324
0325 cyl_gr.template populate<attach<>>(loc_p, 33u);
0326 cyl_gr.template populate<attach<>>(loc_p, 55u);
0327 cyl_gr.template populate<attach<>>(loc_p, 77u);
0328
0329 EXPECT_TRUE(bin3.capacity() == 18u);
0330 EXPECT_FALSE(bin3.empty());
0331 EXPECT_TRUE(bin3.size() == 3u);
0332 EXPECT_EQ(bin3[0], 33u);
0333 EXPECT_EQ(bin3[1], 55u);
0334 EXPECT_EQ(bin3[2], 77u);
0335
0336 EXPECT_EQ(cyl_gr.size(), 3u);
0337
0338
0339 const scalar r{5.f};
0340 const scalar n_half_z{-10.f};
0341 const scalar p_half_z{9.f};
0342 mask<cylinder2D, algebra_t> cyl2{0u, r, n_half_z, p_half_z};
0343
0344 auto cyl_gr2 =
0345 gr_factory
0346 .template new_grid<circular<label::e_rphi>, closed<label::e_cyl_z>,
0347 regular<scalar>, irregular<scalar>>(
0348 cyl2, {10u, bin_edges_z.size() - 1}, capacities,
0349 {bin_edges_phi, bin_edges_z});
0350 }
0351
0352
0353 GTEST_TEST(detray_builders, grid_builder) {
0354
0355 using cyl_grid_t = grid<algebra_t, axes<concentric_cylinder2D>,
0356 bins::static_array<detector_t::surface_type, 1>,
0357 simple_serializer, host_container_types, false>;
0358
0359 auto gbuilder = grid_builder<detector_t, cyl_grid_t, detray::bin_associator>{
0360 std::make_unique<mock_volume_builder>()};
0361
0362
0363 const auto cyl_mask =
0364 mask<concentric_cylinder2D, algebra_t>{0u, 10.f, -500.f, 500.f};
0365 std::size_t n_phi_bins{5u};
0366 std::size_t n_z_bins{4u};
0367
0368
0369 gbuilder.init_grid(cyl_mask, {n_phi_bins, n_z_bins});
0370 auto cyl_grid = gbuilder.get();
0371
0372 const auto& cyl_axis_z = cyl_grid.template get_axis<label::e_cyl_z>();
0373 EXPECT_EQ(cyl_axis_z.label(), label::e_cyl_z);
0374 EXPECT_EQ(cyl_axis_z.bounds(), bounds::e_closed);
0375 EXPECT_EQ(cyl_axis_z.binning(), binning::e_regular);
0376 EXPECT_EQ(cyl_axis_z.nbins(), 4u);
0377 EXPECT_NEAR(cyl_axis_z.span()[0], -500.f,
0378 std::numeric_limits<scalar>::epsilon());
0379 EXPECT_NEAR(cyl_axis_z.span()[1], 500.f,
0380 std::numeric_limits<scalar>::epsilon());
0381 }