File indexing completed on 2026-05-27 07:24:20
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include "detray/definitions/detail/qualifiers.hpp"
0011 #include "detray/definitions/units.hpp"
0012 #include "detray/geometry/mask.hpp"
0013 #include "detray/geometry/shapes/unbounded.hpp"
0014 #include "detray/navigation/caching_navigator.hpp"
0015 #include "detray/propagator/line_stepper.hpp"
0016 #include "detray/propagator/propagation_config.hpp"
0017 #include "detray/propagator/rk_stepper.hpp"
0018 #include "detray/tracks/tracks.hpp"
0019 #include "detray/utils/consistency_checker.hpp"
0020
0021
0022 #include "detray/test/common/build_telescope_detector.hpp"
0023 #include "detray/test/framework/types.hpp"
0024 #include "detray/test/utils/inspectors.hpp"
0025
0026
0027 #include <vecmem/memory/host_memory_resource.hpp>
0028
0029
0030 #include <covfie/core/backend/primitive/constant.hpp>
0031 #include <covfie/core/field.hpp>
0032 #include <covfie/core/vector.hpp>
0033
0034
0035 #include <gtest/gtest.h>
0036
0037
0038 #include <utility>
0039
0040 namespace detray {
0041
0042 namespace {
0043
0044 using test_algebra = test::algebra;
0045 using scalar = test::scalar;
0046 using vector3 = test::vector3;
0047
0048
0049 template <typename stepping_t, typename navigation_t>
0050 struct prop_state {
0051 using context_t = typename navigation_t::detector_type::geometry_context;
0052
0053 template <typename track_t, typename field_type>
0054 prop_state(const track_t &t_in, const field_type &field,
0055 const typename navigation_t::detector_type &det,
0056 const context_t &ctx = {})
0057 : m_stepping(t_in, field), m_navigation(det), m_context(ctx) {}
0058
0059 constexpr navigation_t &navigation() { return m_navigation; }
0060 constexpr stepping_t &stepping() { return m_stepping; }
0061
0062 stepping_t m_stepping;
0063 navigation_t m_navigation;
0064 context_t m_context;
0065 };
0066
0067 inline constexpr bool verbose_check = true;
0068
0069 const propagation::config prop_cfg{};
0070
0071 }
0072
0073 }
0074
0075
0076 GTEST_TEST(detray_detectors, telescope_detector) {
0077 using namespace detray;
0078
0079
0080 mask<rectangle2D, test_algebra> rectangle{0u, 20.f * unit<scalar>::mm,
0081 20.f * unit<scalar>::mm};
0082 tel_det_config<test_algebra> tel_cfg{rectangle};
0083
0084 using const_bfield_bknd_t =
0085 covfie::backend::constant<covfie::vector::vector_d<scalar, 3>,
0086 covfie::vector::vector_d<scalar, 3>>;
0087 using b_field_t = covfie::field<const_bfield_bknd_t>;
0088
0089 using rk_stepper_t = rk_stepper<b_field_t::view_t, test_algebra>;
0090 using inspector_t = navigation::print_inspector;
0091 constexpr std::size_t cache_size{navigation::default_cache_size};
0092
0093
0094 constexpr scalar tol{1e-4f};
0095
0096 vecmem::host_memory_resource host_mr;
0097
0098
0099 vector3 B_z{static_cast<scalar>(0.f), static_cast<scalar>(0.f),
0100 1.f * unit<scalar>::T};
0101 vector3 B_x{1.f * unit<scalar>::T, static_cast<scalar>(0.f),
0102 static_cast<scalar>(0.f)};
0103 b_field_t b_field_z{covfie::make_parameter_pack(
0104 b_field_t::backend_t::configuration_t{B_z[0], B_z[1], B_z[2]})};
0105 b_field_t b_field_x{covfie::make_parameter_pack(
0106 b_field_t::backend_t::configuration_t{B_x[0], B_x[1], B_x[2]})};
0107 b_field_t::view_t b_field_z_view(b_field_z);
0108 b_field_t::view_t b_field_x_view(b_field_x);
0109
0110
0111 rk_stepper_t rk_stepper_z;
0112 rk_stepper_t rk_stepper_x;
0113
0114
0115
0116
0117
0118
0119 std::vector<scalar> positions = {0.f, 50.f, 100.f, 150.f, 200.f, 250.f,
0120 300.f, 350.f, 400.f, 450.f, 500.f};
0121
0122 const auto [z_tel_det1, z_tel_names1] =
0123 build_telescope_detector<test_algebra>(host_mr,
0124 tel_cfg.positions(positions));
0125
0126
0127 const auto vol0 = tracking_volume{z_tel_det1, 0u};
0128 ASSERT_EQ(vol0.portals().size(), 6u);
0129 ASSERT_EQ(vol0.surfaces().size(), positions.size() + 6u);
0130 ASSERT_EQ(vol0.template surfaces<surface_id::e_sensitive>().size(),
0131 positions.size());
0132
0133
0134 EXPECT_EQ(z_tel_names1.get_detector_name(), "telescope_detector");
0135 EXPECT_EQ(z_tel_names1.at(0u), "telescope_world_0");
0136
0137
0138 detail::check_consistency(z_tel_det1, verbose_check, z_tel_names1);
0139
0140
0141
0142 tel_cfg.positions({}).n_surfaces(11u).length(500.f * unit<scalar>::mm);
0143 const auto [z_tel_det2, z_tel_names2] =
0144 build_telescope_detector<test_algebra>(host_mr, tel_cfg);
0145
0146
0147 detail::check_consistency(z_tel_det2, verbose_check, z_tel_names2);
0148
0149
0150 for (std::size_t i{0u}; i < z_tel_det1.surfaces().size(); ++i) {
0151 geometry::identifier geo_id{};
0152 geo_id.set_volume(0u).set_index(i);
0153 geo_id.set_id((i == z_tel_det1.surfaces().size() - 1u)
0154 ? surface_id::e_portal
0155 : surface_id::e_sensitive);
0156 EXPECT_TRUE(z_tel_det1.surface(geo_id) == z_tel_det2.surface(geo_id));
0157 }
0158
0159
0160
0161
0162
0163
0164 detail::ray<test_algebra> x_track({0.f, 0.f, 0.f}, 0.f, {1.f, 0.f, 0.f},
0165 -1.f);
0166
0167 const auto [x_tel_det, x_tel_names] = build_telescope_detector<test_algebra>(
0168 host_mr, tel_cfg.pilot_track(x_track));
0169
0170
0171 detail::check_consistency(x_tel_det, verbose_check, x_tel_names);
0172
0173
0174
0175
0176
0177
0178 vector3 pos = {0.f, 0.f, 0.f};
0179 vector3 mom = {0.f, 0.f, 1.f};
0180 free_track_parameters<test_algebra> test_track_z1(pos, 0.f, mom, -1.f);
0181 free_track_parameters<test_algebra> test_track_z2(pos, 0.f, mom, -1.f);
0182 mom = {1.f, 0.f, 0.f};
0183 free_track_parameters<test_algebra> test_track_x(pos, 0.f, mom, -1.f);
0184
0185
0186 caching_navigator<decltype(z_tel_det1), cache_size, inspector_t> navigator_z1;
0187 caching_navigator<decltype(z_tel_det2), cache_size, inspector_t> navigator_z2;
0188 caching_navigator<decltype(x_tel_det), cache_size, inspector_t> navigator_x;
0189 using navigation_state_t = decltype(navigator_z1)::state;
0190 using stepping_state_t = rk_stepper_t::state;
0191
0192
0193 prop_state<stepping_state_t, navigation_state_t> propgation_z1(
0194 test_track_z1, b_field_z_view, z_tel_det1);
0195 prop_state<stepping_state_t, navigation_state_t> propgation_z2(
0196 test_track_z2, b_field_z_view, z_tel_det2);
0197 prop_state<stepping_state_t, navigation_state_t> propgation_x(
0198 test_track_x, b_field_x_view, x_tel_det);
0199
0200 stepping_state_t &stepping_z1 = propgation_z1.stepping();
0201 stepping_state_t &stepping_z2 = propgation_z2.stepping();
0202 stepping_state_t &stepping_x = propgation_x.stepping();
0203
0204 navigation_state_t &navigation_z1 = propgation_z1.navigation();
0205 navigation_state_t &navigation_z2 = propgation_z2.navigation();
0206 navigation_state_t &navigation_x = propgation_x.navigation();
0207
0208
0209 navigator_z1.init(stepping_z1(), navigation_z1, prop_cfg.navigation,
0210 prop_cfg.context);
0211 navigator_z2.init(stepping_z2(), navigation_z2, prop_cfg.navigation,
0212 prop_cfg.context);
0213 navigator_x.init(stepping_x(), navigation_x, prop_cfg.navigation,
0214 prop_cfg.context);
0215
0216 bool heartbeat_z1 = navigation_z1.is_alive();
0217 bool heartbeat_z2 = navigation_z2.is_alive();
0218 bool heartbeat_x = navigation_x.is_alive();
0219
0220 bool do_reset_z1{true};
0221 bool do_reset_z2{true};
0222 bool do_reset_x{true};
0223
0224 while (heartbeat_z1 && heartbeat_z2 && heartbeat_x) {
0225
0226 EXPECT_TRUE(heartbeat_z1);
0227 EXPECT_TRUE(heartbeat_z2);
0228 EXPECT_TRUE(heartbeat_x);
0229
0230 heartbeat_z1 =
0231 heartbeat_z1 && rk_stepper_z.step(navigation_z1(), stepping_z1,
0232 prop_cfg.stepping, do_reset_z1);
0233 heartbeat_z2 =
0234 heartbeat_z2 && rk_stepper_z.step(navigation_z2(), stepping_z2,
0235 prop_cfg.stepping, do_reset_z2);
0236 heartbeat_x =
0237 heartbeat_x && rk_stepper_x.step(navigation_x(), stepping_x,
0238 prop_cfg.stepping, do_reset_x);
0239
0240 navigation_z1.set_high_trust();
0241 navigation_z2.set_high_trust();
0242 navigation_x.set_high_trust();
0243
0244 do_reset_z1 = navigator_z1.update(stepping_z1(), navigation_z1,
0245 prop_cfg.navigation, prop_cfg.context);
0246 do_reset_z2 = navigator_z2.update(stepping_z2(), navigation_z2,
0247 prop_cfg.navigation, prop_cfg.context);
0248 do_reset_x = navigator_x.update(stepping_x(), navigation_x,
0249 prop_cfg.navigation, prop_cfg.context);
0250
0251
0252 do_reset_z1 = do_reset_z1 || navigation_z1.is_on_surface();
0253 do_reset_z2 = do_reset_z2 || navigation_z2.is_on_surface();
0254 do_reset_x = do_reset_x || navigation_x.is_on_surface();
0255
0256 heartbeat_z1 = heartbeat_z1 && navigation_z1.is_alive();
0257 heartbeat_z2 = heartbeat_z2 && navigation_z2.is_alive();
0258 heartbeat_x = heartbeat_x && navigation_x.is_alive();
0259
0260
0261 EXPECT_NEAR(
0262 std::abs(stepping_z1.path_length() - stepping_z2.path_length()) /
0263 stepping_z1.path_length(),
0264 0.f, tol);
0265 EXPECT_NEAR(std::abs(stepping_z1.path_length() - stepping_x.path_length()) /
0266 stepping_x.path_length(),
0267 0.f, tol);
0268
0269 EXPECT_NEAR(vector::norm(stepping_z1().pos() - stepping_z2().pos()) /
0270 vector::norm(stepping_z1().pos()),
0271 0.f, tol);
0272 EXPECT_NEAR(vector::norm(stepping_z1().dir() - stepping_z2().dir()) /
0273 vector::norm(stepping_z1().dir()),
0274 0.f, tol);
0275 }
0276
0277
0278 ASSERT_TRUE(navigation_z1.finished())
0279 << navigation_z1.inspector().to_string();
0280 ASSERT_TRUE(navigation_z2.finished())
0281 << navigation_z2.inspector().to_string();
0282 ASSERT_TRUE(navigation_x.finished()) << navigation_x.inspector().to_string();
0283
0284
0285
0286
0287 pos = {0.f, 0.f, 0.f};
0288 mom = {0.f, 1.f, 0.f};
0289
0290 auto pilot_track = free_track_parameters<test_algebra>(pos, 0.f, mom, -1.f);
0291
0292 detail::helix<test_algebra> helix_bz(pilot_track, B_z);
0293
0294 tel_det_config htel_cfg{rectangle, helix_bz};
0295 htel_cfg.n_surfaces(11u).length(500.f * unit<scalar>::mm);
0296 const auto [tel_detector, tel_names] =
0297 build_telescope_detector<test_algebra>(host_mr, htel_cfg);
0298
0299
0300 detail::check_consistency(tel_detector, verbose_check, tel_names);
0301
0302
0303 caching_navigator<decltype(tel_detector), cache_size, inspector_t>
0304 tel_navigator;
0305
0306 prop_state<stepping_state_t, navigation_state_t> tel_propagation(
0307 pilot_track, b_field_z_view, tel_detector);
0308 navigation_state_t &tel_navigation = tel_propagation.navigation();
0309 stepping_state_t &tel_stepping = tel_propagation.stepping();
0310
0311
0312 tel_navigator.init(tel_stepping(), tel_navigation, prop_cfg.navigation,
0313 prop_cfg.context);
0314 bool heartbeat_tel = tel_navigation.is_alive();
0315
0316 bool do_reset_tel{true};
0317
0318 while (heartbeat_tel) {
0319 heartbeat_tel =
0320 heartbeat_tel && rk_stepper_z.step(tel_navigation(), tel_stepping,
0321 prop_cfg.stepping, do_reset_tel);
0322
0323 tel_navigation.set_high_trust();
0324
0325 do_reset_tel = tel_navigator.update(tel_stepping(), tel_navigation,
0326 prop_cfg.navigation, prop_cfg.context);
0327
0328 do_reset_tel = do_reset_tel || navigation_z1.is_on_surface();
0329 heartbeat_tel = heartbeat_tel && tel_navigation.is_alive();
0330 }
0331
0332 ASSERT_TRUE(tel_navigation.finished())
0333 << tel_navigation.inspector().to_string();
0334 }