File indexing completed on 2026-05-27 07:24:22
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include "detray/definitions/units.hpp"
0011 #include "detray/tracks/helix.hpp"
0012 #include "detray/tracks/tracks.hpp"
0013
0014
0015 #include "detray/test/framework/types.hpp"
0016
0017
0018 #include <gtest/gtest.h>
0019
0020 using namespace detray;
0021
0022 using scalar = test::scalar;
0023
0024 constexpr const scalar tol{1e-5f};
0025
0026
0027 GTEST_TEST(detray_intersection, helix_trajectory) {
0028 using test_algebra = test::algebra;
0029 using vector3 = test::vector3;
0030 using point3 = test::point3;
0031
0032 const point3 pos{0.f, 0.f, 0.f};
0033 const scalar time{0.f};
0034 const vector3 mom{static_cast<scalar>(1.f), static_cast<scalar>(0.f),
0035 1.f * unit<scalar>::GeV};
0036 const scalar q{static_cast<scalar>(-1.) * unit<scalar>::e};
0037
0038
0039 free_track_parameters<test_algebra> vertex(pos, time, mom, q);
0040
0041
0042 const vector3 B{static_cast<scalar>(0.f), static_cast<scalar>(0.f),
0043 1.f * unit<scalar>::T};
0044
0045 const scalar p_mag{vector::norm(mom)};
0046 const scalar B_mag{vector::norm(B)};
0047 const scalar pz_along{vector::dot(mom, vector::normalize(B))};
0048 const scalar pt{std::sqrt(p_mag * p_mag - pz_along * pz_along)};
0049
0050
0051 detail::helix helix_traj(vertex, B);
0052 EXPECT_NEAR(helix_traj.time(), 0.f, tol);
0053 EXPECT_NEAR(helix_traj.qop(), -constant<scalar>::inv_sqrt2, tol);
0054
0055
0056 scalar R{helix_traj.radius()};
0057 EXPECT_NEAR(R, pt / B_mag, tol);
0058
0059
0060 EXPECT_NEAR(R, 3.33564095f * unit<scalar>::m, 10.f * tol);
0061
0062
0063 scalar S = 2.f * p_mag / B_mag * constant<scalar>::pi;
0064
0065
0066 point3 half_loop_pos = helix_traj(S / 2.f);
0067 EXPECT_NEAR(half_loop_pos[0], 0.f, R * tol);
0068 EXPECT_NEAR(half_loop_pos[1], 2.f * R, R * tol);
0069 EXPECT_NEAR(half_loop_pos[2], pz_along / B_mag * constant<scalar>::pi,
0070 R * tol);
0071
0072 point3 half_loop_dir = helix_traj.dir(S / 2.f);
0073 EXPECT_NEAR(half_loop_dir[0], -vertex.dir()[0], R * tol);
0074 EXPECT_NEAR(half_loop_dir[1], -vertex.dir()[1], R * tol);
0075 EXPECT_NEAR(half_loop_dir[2], vertex.dir()[2], R * tol);
0076
0077
0078 half_loop_pos = helix_traj(-S / 2.f);
0079 EXPECT_NEAR(half_loop_pos[0], 0.f, R * tol);
0080 EXPECT_NEAR(half_loop_pos[1], 2.f * R, R * tol);
0081 EXPECT_NEAR(half_loop_pos[2], -pz_along / B_mag * constant<scalar>::pi,
0082 R * tol);
0083
0084 half_loop_dir = helix_traj.dir(-S / 2.f);
0085 EXPECT_NEAR(half_loop_dir[0], -vertex.dir()[0], R * tol);
0086 EXPECT_NEAR(half_loop_dir[1], -vertex.dir()[1], R * tol);
0087 EXPECT_NEAR(half_loop_dir[2], vertex.dir()[2], R * tol);
0088
0089
0090 point3 one_loop_pos = helix_traj(S);
0091 EXPECT_NEAR(one_loop_pos[0], 0.f, R * tol);
0092 EXPECT_NEAR(one_loop_pos[1], 0.f, R * tol);
0093 EXPECT_NEAR(one_loop_pos[2], 2.f * pz_along / B_mag * constant<scalar>::pi,
0094 R * tol);
0095
0096 point3 one_loop_dir = helix_traj.dir(S);
0097 EXPECT_NEAR(one_loop_dir[0], vertex.dir()[0], R * tol);
0098 EXPECT_NEAR(one_loop_dir[1], vertex.dir()[1], R * tol);
0099 EXPECT_NEAR(one_loop_dir[2], vertex.dir()[2], R * tol);
0100
0101
0102 one_loop_pos = helix_traj(-S);
0103 EXPECT_NEAR(one_loop_pos[0], 0.f, R * tol);
0104 EXPECT_NEAR(one_loop_pos[1], 0.f, R * tol);
0105 EXPECT_NEAR(one_loop_pos[2], -2.f * pz_along / B_mag * constant<scalar>::pi,
0106 R * tol);
0107
0108 one_loop_dir = helix_traj.dir(-S);
0109 EXPECT_NEAR(one_loop_dir[0], vertex.dir()[0], R * tol);
0110 EXPECT_NEAR(one_loop_dir[1], vertex.dir()[1], R * tol);
0111 EXPECT_NEAR(one_loop_dir[2], vertex.dir()[2], R * tol);
0112
0113
0114
0115
0116
0117 free_track_parameters<test_algebra> vertex2(pos, time, mom, -q);
0118
0119
0120 detail::helix helix_traj2(vertex2, B);
0121
0122 EXPECT_NEAR(R, helix_traj2.radius(), tol);
0123
0124
0125 half_loop_pos = helix_traj2(S / 2.f);
0126 EXPECT_NEAR(half_loop_pos[0], 0.f, R * tol);
0127 EXPECT_NEAR(half_loop_pos[1], -2.f * R, R * tol);
0128 EXPECT_NEAR(half_loop_pos[2], pz_along / B_mag * constant<scalar>::pi,
0129 R * tol);
0130
0131 half_loop_dir = helix_traj2.dir(S / 2.f);
0132 EXPECT_NEAR(half_loop_dir[0], -vertex2.dir()[0], R * tol);
0133 EXPECT_NEAR(half_loop_dir[1], -vertex2.dir()[1], R * tol);
0134 EXPECT_NEAR(half_loop_dir[2], vertex2.dir()[2], R * tol);
0135
0136
0137 half_loop_pos = helix_traj2(-S / 2.f);
0138 EXPECT_NEAR(half_loop_pos[0], 0.f, R * tol);
0139 EXPECT_NEAR(half_loop_pos[1], -2.f * R, R * tol);
0140 EXPECT_NEAR(half_loop_pos[2], -pz_along / B_mag * constant<scalar>::pi,
0141 R * tol);
0142
0143 half_loop_dir = helix_traj.dir(-S / 2.f);
0144 EXPECT_NEAR(half_loop_dir[0], -vertex.dir()[0], R * tol);
0145 EXPECT_NEAR(half_loop_dir[1], -vertex.dir()[1], R * tol);
0146 EXPECT_NEAR(half_loop_dir[2], vertex.dir()[2], R * tol);
0147
0148
0149 one_loop_pos = helix_traj2(S);
0150 EXPECT_NEAR(one_loop_pos[0], 0.f, R * tol);
0151 EXPECT_NEAR(one_loop_pos[1], 0.f, R * tol);
0152 EXPECT_NEAR(one_loop_pos[2], 2.f * pz_along / B_mag * constant<scalar>::pi,
0153 R * tol);
0154
0155 one_loop_dir = helix_traj2.dir(S);
0156 EXPECT_NEAR(one_loop_dir[0], vertex2.dir()[0], R * tol);
0157 EXPECT_NEAR(one_loop_dir[1], vertex2.dir()[1], R * tol);
0158 EXPECT_NEAR(one_loop_dir[2], vertex2.dir()[2], R * tol);
0159
0160
0161 one_loop_pos = helix_traj2(-S);
0162 EXPECT_NEAR(one_loop_pos[0], 0.f, R * tol);
0163 EXPECT_NEAR(one_loop_pos[1], 0.f, R * tol);
0164 EXPECT_NEAR(one_loop_pos[2], -2.f * pz_along / B_mag * constant<scalar>::pi,
0165 R * tol);
0166
0167 one_loop_dir = helix_traj2.dir(-S);
0168 EXPECT_NEAR(one_loop_dir[0], vertex2.dir()[0], R * tol);
0169 EXPECT_NEAR(one_loop_dir[1], vertex2.dir()[1], R * tol);
0170 EXPECT_NEAR(one_loop_dir[2], vertex2.dir()[2], R * tol);
0171 }
0172
0173 GTEST_TEST(detray_intersection, helix_trajectory_small_pT) {
0174 using test_algebra = test::algebra;
0175 using vector3 = test::vector3;
0176 using point3 = test::point3;
0177
0178 const point3 pos{0.f, 0.f, 0.f};
0179 const scalar time{0.f};
0180 const vector3 mom{static_cast<scalar>(0.f), tol, 1.f * unit<scalar>::GeV};
0181 const scalar q{static_cast<scalar>(-1.) * unit<scalar>::e};
0182
0183
0184 free_track_parameters<test_algebra> vertex(pos, time, mom, q);
0185
0186
0187 const vector3 B{static_cast<scalar>(0.f), static_cast<scalar>(0.f),
0188 1.f * unit<scalar>::T};
0189
0190
0191 detail::helix helix_traj(vertex, B);
0192 EXPECT_NEAR(helix_traj.time(), 0.f, tol);
0193 EXPECT_NEAR(helix_traj.qop(), -1.f, tol);
0194
0195
0196 const scalar path_length{10.f * unit<scalar>::mm};
0197 const point3 helix_pos = helix_traj(path_length);
0198 const point3 true_pos = pos + path_length * vector::normalize(mom);
0199
0200 EXPECT_NEAR(true_pos[0], helix_pos[0], tol);
0201 EXPECT_NEAR(true_pos[1], helix_pos[1], tol);
0202 EXPECT_NEAR(true_pos[2], helix_pos[2], tol);
0203 }
0204
0205 GTEST_TEST(detray_intersection, helix_direction_stability) {
0206 using test_algebra = test::algebra;
0207 using vector3 = test::vector3;
0208 using point3 = test::point3;
0209
0210
0211 const vector3 B{static_cast<scalar>(0.f), static_cast<scalar>(0.f),
0212 1.f * unit<scalar>::T};
0213
0214 const point3 pos{0.f, 0.f, 0.f};
0215 const scalar time{0.f};
0216 const vector3 mom{1.f * unit<scalar>::GeV, 1.f * unit<scalar>::GeV,
0217 1.f * unit<scalar>::GeV};
0218 const scalar q{static_cast<scalar>(-1.) * unit<scalar>::e};
0219
0220
0221 free_track_parameters<test_algebra> vertex(pos, time, mom, q);
0222
0223
0224 detail::helix hlx(vertex, B);
0225
0226 for (int i = 0; i < 100; i++) {
0227 const auto d = hlx.dir(static_cast<scalar>(i) * 10.f);
0228 ASSERT_FLOAT_EQ(static_cast<float>(vector::theta(d)),
0229 static_cast<float>(vector::theta(mom)));
0230 }
0231 }