File indexing completed on 2026-05-27 07:24:03
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011
0012 #if defined(__GNUC__) && !defined(__clang__)
0013 #pragma GCC diagnostic warning "-Wmaybe-uninitialized"
0014 #endif
0015
0016
0017 #include "detray/definitions/algebra.hpp"
0018 #include "detray/definitions/math.hpp"
0019 #include "detray/tracks/free_track_parameters.hpp"
0020 #include "detray/utils/invalid_values.hpp"
0021
0022
0023 #include <ostream>
0024
0025 namespace detray::detail {
0026
0027
0028
0029
0030
0031
0032 template <concepts::algebra algebra_t>
0033 class helix {
0034 public:
0035 using algebra_type = algebra_t;
0036 using scalar_type = dscalar<algebra_t>;
0037 using point3_type = dpoint3D<algebra_t>;
0038 using vector3_type = dvector3D<algebra_t>;
0039 using transform3_type = dtransform3D<algebra_t>;
0040
0041
0042 using free_track_parameters_type = free_track_parameters<algebra_t>;
0043
0044
0045 template <std::size_t ROWS, std::size_t COLS>
0046 using matrix_type = dmatrix<algebra_t, ROWS, COLS>;
0047 using free_matrix_t = free_matrix<algebra_t>;
0048
0049 DETRAY_HOST_DEVICE
0050 helix() = delete;
0051
0052
0053
0054
0055
0056
0057
0058
0059 DETRAY_HOST_DEVICE
0060 helix(const point3_type &pos, const scalar_type time, const vector3_type &dir,
0061 const scalar_type qop, const vector3_type &mag_field)
0062 : _pos(pos),
0063 _time(time),
0064 _qop(qop),
0065 _B{vector::norm(mag_field)},
0066 _h0{vector::normalize(mag_field)},
0067 _t0{dir} {
0068 assert((math::fabs(vector::norm(_t0) - 1.f) < 1e-5f) &&
0069 "The helix direction must be normalized");
0070
0071
0072 const vector3_type mom =
0073 (1.f / static_cast<scalar_type>(math::fabs(qop))) * _t0;
0074
0075
0076 _n0 = vector::normalize(vector::cross(_h0, _t0));
0077
0078
0079 _alpha = vector::norm(vector::cross(_h0, _t0));
0080
0081
0082 _delta = vector::dot(_h0, _t0);
0083
0084
0085 _K = -_qop * _B;
0086
0087
0088 scalar_type pz = vector::dot(mom, _h0);
0089
0090
0091 vector3_type pT = mom - pz * _h0;
0092
0093
0094 _R = vector::norm(pT) / _B;
0095
0096
0097 if (vector::norm(pT) < 1e-6f) {
0098 _vz_over_vt = detail::invalid_value<scalar_type>();
0099 } else {
0100
0101 _vz_over_vt = pz / vector::norm(pT);
0102 }
0103 }
0104
0105 DETRAY_HOST_DEVICE
0106 helix(const free_track_parameters_type &track, const vector3_type &mag_field)
0107 : helix(track.pos(), track.time(), track.dir(), track.qop(), mag_field) {
0108 assert(!track.is_invalid());
0109 }
0110
0111
0112 template <typename field_view_t>
0113 requires(!concepts::vector3D<field_view_t>)
0114 DETRAY_HOST_DEVICE helix(const free_track_parameters_type &track,
0115 const field_view_t mag_field)
0116 : helix(track.pos(), track.time(), track.dir(), track.qop(),
0117 sample_field(mag_field, track.pos())) {}
0118
0119
0120 DETRAY_HOST_DEVICE
0121 scalar_type radius() const { return _R; }
0122
0123
0124 DETRAY_HOST_DEVICE
0125 point3_type operator()(const scalar_type s) const { return this->pos(s); }
0126
0127
0128 DETRAY_HOST_DEVICE
0129 point3_type pos(const scalar_type s) const {
0130
0131 if (_vz_over_vt == detail::invalid_value<scalar_type>()) {
0132 return _pos + s * _h0;
0133 }
0134
0135 point3_type ret = _pos;
0136 ret = ret + _delta / _K * (_K * s - math::sin(_K * s)) * _h0;
0137 ret = ret + math::sin(_K * s) / _K * _t0;
0138 ret = ret + _alpha / _K * (1.f - math::cos(_K * s)) * _n0;
0139
0140 return ret;
0141 }
0142
0143 DETRAY_HOST_DEVICE
0144 point3_type pos() const { return _pos; }
0145
0146
0147 DETRAY_HOST_DEVICE
0148 vector3_type dir(const scalar_type s) const {
0149
0150 if (_vz_over_vt == detail::invalid_value<scalar_type>()) {
0151 return _t0;
0152 }
0153
0154 vector3_type ret{0.f, 0.f, 0.f};
0155
0156 ret = ret + _delta * (1 - math::cos(_K * s)) * _h0;
0157 ret = ret + math::cos(_K * s) * _t0;
0158 ret = ret + _alpha * math::sin(_K * s) * _n0;
0159
0160 return vector::normalize(ret);
0161 }
0162
0163 DETRAY_HOST_DEVICE
0164 point3_type dir() const { return _t0; }
0165
0166 DETRAY_HOST_DEVICE
0167 scalar_type time() const { return _time; }
0168
0169 DETRAY_HOST_DEVICE
0170 scalar_type qop() const { return _qop; }
0171
0172 DETRAY_HOST_DEVICE
0173 scalar_type B() const { return _B; }
0174
0175 DETRAY_HOST_DEVICE
0176 vector3_type b_field() const { return _B * _h0; }
0177
0178
0179 DETRAY_HOST_DEVICE
0180 free_matrix_t jacobian(const scalar_type s) const {
0181 free_matrix_t ret = matrix::zero<free_matrix_t>();
0182
0183 const matrix_type<3, 3> I33 = matrix::identity<matrix_type<3, 3>>();
0184 const matrix_type<3, 3> Z33 = matrix::zero<matrix_type<3, 3>>();
0185
0186
0187
0188
0189
0190
0191
0192 auto drdr = I33;
0193 getter::set_block(ret, drdr, e_free_pos0, e_free_pos0);
0194
0195
0196 auto dtdr = Z33;
0197 getter::set_block(ret, dtdr, e_free_dir0, e_free_pos0);
0198
0199
0200 auto drdt = Z33;
0201
0202 const scalar_type sin_ks = math::sin(_K * s);
0203 const scalar_type cos_ks = math::cos(_K * s);
0204 drdt = drdt + sin_ks / _K * I33;
0205
0206 matrix_type<3, 1> H0 = matrix::zero<matrix_type<3, 1>>();
0207 getter::element(H0, 0u, 0u) = _h0[0u];
0208 getter::element(H0, 1u, 0u) = _h0[1u];
0209 getter::element(H0, 2u, 0u) = _h0[2u];
0210 const matrix_type<1, 3> H0_T = matrix::transpose(H0);
0211 const matrix_type<3, 3> H0H0_T = H0 * H0_T;
0212
0213 drdt = drdt + (_K * s - sin_ks) / _K * H0H0_T;
0214
0215 drdt = drdt + (cos_ks - 1.f) / _K * matrix::column_wise_cross(I33, _h0);
0216
0217 getter::set_block(ret, drdt, e_free_pos0, e_free_dir0);
0218
0219
0220 auto dtdt = Z33;
0221 dtdt = dtdt + cos_ks * I33;
0222 dtdt = dtdt + (1 - cos_ks) * H0H0_T;
0223 dtdt = dtdt - sin_ks * matrix::column_wise_cross(I33, _h0);
0224
0225 getter::set_block(ret, dtdt, e_free_dir0, e_free_dir0);
0226
0227
0228 vector3_type drdl = 1.f / _qop * (s * this->dir(s) + _pos - this->pos(s));
0229
0230 getter::set_block(ret, drdl, e_free_pos0, e_free_qoverp);
0231
0232
0233 vector3_type dtdl =
0234 -_B * s *
0235 (sin_ks * ((H0H0_T - I33) * _t0) + cos_ks * vector::cross(_h0, _t0));
0236
0237 getter::set_block(ret, dtdl, e_free_dir0, e_free_qoverp);
0238
0239
0240 getter::element(ret, e_free_time, e_free_time) = 1.f;
0241 getter::element(ret, e_free_qoverp, e_free_qoverp) = 1.f;
0242
0243 return ret;
0244 }
0245
0246 private:
0247
0248 DETRAY_HOST
0249 friend std::ostream &operator<<(std::ostream &os, const helix &h) {
0250 os << "helix: ";
0251 os << "ori = " << h._pos;
0252 os << ", dir = " << h._t0 << std::endl;
0253
0254 return os;
0255 }
0256
0257
0258 template <typename field_view_t>
0259 constexpr vector3_type sample_field(const field_view_t field,
0260 const point3_type &pos) const {
0261 const auto bvec = field.at(pos[0], pos[1], pos[2]);
0262
0263 return {bvec[0], bvec[1], bvec[2]};
0264 }
0265
0266
0267 point3_type _pos;
0268
0269
0270 scalar_type _time;
0271
0272
0273 scalar_type _qop;
0274
0275
0276 scalar_type _B;
0277
0278
0279 vector3_type _h0;
0280
0281
0282 vector3_type _t0;
0283
0284
0285 vector3_type _n0;
0286
0287
0288 scalar_type _alpha;
0289
0290
0291 scalar_type _delta;
0292
0293
0294 scalar_type _K;
0295
0296
0297 scalar_type _R;
0298
0299
0300 scalar_type _vz_over_vt;
0301 };
0302
0303 template <concepts::algebra algebra_t, typename field_view_t>
0304 requires(!concepts::vector3D<field_view_t>)
0305 DETRAY_HOST_DEVICE helix(const free_track_parameters<algebra_t> &,
0306 const field_view_t) -> helix<algebra_t>;
0307
0308 }