File indexing completed on 2026-07-26 08:22:02
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010
0011 #include "traccc/edm/track_parameters.hpp"
0012 #include "traccc/utils/logging.hpp"
0013 #include "traccc/utils/particle.hpp"
0014 #include "traccc/utils/trigonometric_helpers.hpp"
0015
0016
0017 #include <detray/definitions/navigation.hpp> // < navigation::direction
0018 #include <detray/geometry/identifier.hpp>
0019 #include <detray/geometry/tracking_surface.hpp>
0020 #include <detray/propagator/actors/pointwise_material_interactor.hpp>
0021
0022
0023 #include <random>
0024
0025 namespace traccc {
0026
0027
0028 template <typename detector_t>
0029 struct seed_generator {
0030 using algebra_type = typename detector_t::algebra_type;
0031 using ctx_t = typename detector_t::geometry_context;
0032
0033
0034 struct config {
0035
0036
0037 double sigma_loc0 = 20 * traccc::unit<scalar>::um;
0038
0039
0040 double sigma_loc0_pT_a = 30 * traccc::unit<scalar>::um;
0041 double sigma_loc0_pT_b = 0.3 / traccc::unit<scalar>::GeV;
0042
0043 double sigma_loc1 = 20 * traccc::unit<scalar>::um;
0044
0045
0046 double sigma_loc1_pT_a = 30 * traccc::unit<scalar>::um;
0047 double sigma_loc1_pT_b = 0.3 / traccc::unit<scalar>::GeV;
0048
0049 double sigma_time = 1 * traccc::unit<scalar>::ns;
0050
0051 double sigma_phi = 1 * traccc::unit<scalar>::degree;
0052
0053 double sigma_theta = 1 * traccc::unit<scalar>::degree;
0054
0055 double sigma_pT_rel = 0.05;
0056
0057
0058
0059 std::optional<std::array<double, e_bound_size>> initial_sigmas;
0060
0061
0062 double initialsigma_qopt =
0063 0.1 * traccc::unit<scalar>::e / traccc::unit<scalar>::GeV;
0064
0065
0066 double initialsigma_pT_rel = 0.1;
0067
0068
0069 std::array<double, e_bound_size> cov_inflation{1., 1., 1., 1., 1., 1.};
0070 };
0071
0072
0073
0074
0075
0076 explicit seed_generator(const detector_t& det, const config& cfg = {},
0077 const std::size_t sd = std::mt19937::default_seed,
0078 ctx_t ctx = {})
0079 : m_detector(det), m_ctx(ctx), m_cfg(cfg) {
0080 m_generator.seed(static_cast<std::mt19937::result_type>(sd));
0081 }
0082
0083
0084
0085
0086
0087 bound_track_parameters<algebra_type> operator()(
0088 const detray::geometry::identifier surface_link,
0089 const free_track_parameters<algebra_type>& free_param,
0090 const traccc::pdg_particle<scalar>& ptc_type) {
0091
0092 const detray::tracking_surface sf{m_detector, surface_link};
0093
0094 TRACCC_DEBUG_HOST("Surface:\n" << sf);
0095 TRACCC_DEBUG_HOST("Input free param. on surface:\n" << free_param);
0096
0097 auto bound_vec = sf.free_to_bound_vector(m_ctx, free_param);
0098 auto bound_cov = matrix::identity<traccc::bound_matrix<algebra_type>>();
0099
0100 bound_track_parameters<algebra_type> bound_param{surface_link, bound_vec,
0101 bound_cov};
0102
0103 TRACCC_DEBUG_HOST("-> Bound param.:\n" << bound_param);
0104
0105
0106 using interactor_type =
0107 detray::actor::pointwise_material_interactor<algebra_type>;
0108
0109 assert(ptc_type.charge() * bound_param.qop() > 0.f);
0110
0111
0112 TRACCC_DEBUG_HOST("Update material:");
0113 if (sf.has_material()) {
0114 typename interactor_type::state interactor_state;
0115 interactor_state.do_multiple_scattering = false;
0116 interactor_type{}.update(
0117 m_ctx, ptc_type, bound_param, interactor_state,
0118 static_cast<int>(detray::navigation::direction::e_backward), sf);
0119 }
0120
0121
0122 (*this)(bound_param, ptc_type);
0123
0124 bound_param.set_surface_link(surface_link);
0125
0126 return bound_param;
0127 }
0128
0129
0130
0131
0132
0133 void operator()(bound_track_parameters<algebra_type>& bound_param,
0134 const traccc::pdg_particle<scalar>& ptc_type) {
0135 const scalar q{ptc_type.charge()};
0136 const auto pos = bound_param.bound_local();
0137 const auto time = bound_param.time();
0138 const auto phi = bound_param.phi();
0139 const auto theta = bound_param.theta();
0140 const auto pt = bound_param.pT(q);
0141 const auto qop = bound_param.qop();
0142
0143
0144 const auto sigmas = generate_smearing_sigmas(pt, qop, theta);
0145
0146
0147
0148 const double smeared_loc0 = std::normal_distribution<double>(
0149 pos[0], sigmas[e_bound_loc0])(m_generator);
0150 const double smeared_loc1 = std::normal_distribution<double>(
0151 pos[1], sigmas[e_bound_loc1])(m_generator);
0152 bound_param.set_bound_local(
0153 {static_cast<scalar>(smeared_loc0), static_cast<scalar>(smeared_loc1)});
0154
0155
0156 bound_param.set_time(static_cast<scalar>(std::normal_distribution<double>(
0157 time, sigmas[e_bound_time])(m_generator)));
0158
0159
0160 const double smeared_phi =
0161 std::normal_distribution<double>(phi, sigmas[e_bound_phi])(m_generator);
0162 const double smeared_theta = std::normal_distribution<double>(
0163 theta, sigmas[e_bound_theta])(m_generator);
0164 const auto [new_phi, new_theta] = detail::wrap_phi_theta(
0165 static_cast<scalar>(smeared_phi), static_cast<scalar>(smeared_theta));
0166 bound_param.set_phi(static_cast<scalar>(new_phi));
0167 bound_param.set_theta(static_cast<scalar>(new_theta));
0168
0169
0170 bound_param.set_qop(static_cast<scalar>(std::normal_distribution<double>(
0171 qop, sigmas[e_bound_qoverp])(m_generator)));
0172
0173
0174 generate_initial_covariance(bound_param, ptc_type);
0175
0176
0177 bound_param.set_surface_link(detray::geometry::identifier{});
0178 }
0179
0180
0181
0182
0183
0184
0185
0186
0187 std::array<double, e_bound_size> generate_smearing_sigmas(
0188 const double pt, const double qop, const double theta) {
0189 if (m_cfg.initial_sigmas.has_value()) {
0190 return *m_cfg.initial_sigmas;
0191 } else {
0192
0193 const double sigma_loc_0 =
0194 m_cfg.sigma_loc0 +
0195 m_cfg.sigma_loc0_pT_a *
0196 math::exp(-1.0 * math::fabs(m_cfg.sigma_loc0_pT_b) * pt);
0197
0198 const double sigma_loc_1 =
0199 m_cfg.sigma_loc1 +
0200 m_cfg.sigma_loc1_pT_a *
0201 math::exp(-1.0 * math::fabs(m_cfg.sigma_loc1_pT_b) * pt);
0202
0203 const double sigma_qop = math::sqrt(
0204 math::pow(m_cfg.sigma_pT_rel * qop, 2) +
0205 math::pow(m_cfg.sigma_theta * (qop * math::tan(theta)), 2));
0206
0207 return {sigma_loc_0, sigma_loc_1, m_cfg.sigma_phi,
0208 m_cfg.sigma_theta, sigma_qop, m_cfg.sigma_time};
0209 }
0210 }
0211
0212
0213
0214
0215
0216 void generate_initial_covariance(
0217 bound_track_parameters<algebra_type>& bound_param,
0218 const traccc::pdg_particle<scalar>& ptc_type) {
0219 const scalar q{ptc_type.charge()};
0220
0221
0222 const auto sigmas = generate_smearing_sigmas(
0223 bound_param.pT(q), bound_param.qop(), bound_param.theta());
0224
0225 for (std::size_t i = e_bound_loc0; i < e_bound_size; ++i) {
0226 double sigma = sigmas[i];
0227 double variance = sigma * sigma;
0228
0229
0230 variance *= m_cfg.cov_inflation[i];
0231
0232 getter::element(bound_param.covariance(), i, i) =
0233 static_cast<scalar>(variance);
0234 }
0235
0236 assert(!bound_param.is_invalid());
0237 }
0238
0239 private:
0240
0241 std::random_device m_rd{};
0242 std::mt19937 m_generator{m_rd()};
0243
0244
0245 const detector_t& m_detector;
0246
0247 ctx_t m_ctx;
0248
0249
0250 config m_cfg{};
0251 };
0252
0253 }