File indexing completed on 2026-05-27 07:24:13
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011
0012 #include "detray/navigation/volume_graph.hpp"
0013 #include "detray/tracks/ray.hpp"
0014 #include "detray/utils/logging.hpp"
0015
0016
0017 #include "detray/io/utils/create_path.hpp"
0018
0019
0020 #include "detray/test/common/track_generators.hpp"
0021 #include "detray/test/framework/fixture_base.hpp"
0022 #include "detray/test/framework/types.hpp"
0023 #include "detray/test/framework/whiteboard.hpp"
0024 #include "detray/test/validation/detector_scan_config.hpp"
0025 #include "detray/test/validation/detector_scan_utils.hpp"
0026 #include "detray/test/validation/detector_scanner.hpp"
0027
0028
0029 #include <iostream>
0030 #include <memory>
0031 #include <string>
0032
0033 namespace detray::test {
0034
0035
0036
0037
0038 template <typename detector_t, template <typename> class scan_type>
0039 class detector_scan : public test::fixture_base<> {
0040 using algebra_t = typename detector_t::algebra_type;
0041 using scalar_t = dscalar<algebra_t>;
0042 using free_track_parameters_t = free_track_parameters<algebra_t>;
0043 using intersection_trace_t = typename scan_type<
0044 algebra_t>::template intersection_trace_type<detector_t>;
0045 using trajectory_type = typename scan_type<algebra_t>::trajectory_type;
0046 using uniform_gen_t =
0047 detail::random_numbers<scalar_t,
0048 std::uniform_real_distribution<scalar_t>>;
0049 using track_generator_t =
0050 random_track_generator<free_track_parameters_t, uniform_gen_t>;
0051
0052
0053 static constexpr auto k_use_rays{
0054 std::is_same_v<detail::ray<algebra_t>, trajectory_type>};
0055
0056 public:
0057 using fixture_type = test::fixture_base<>;
0058 using config = detector_scan_config<track_generator_t, algebra_t>;
0059
0060 explicit detector_scan(const detector_t &det,
0061 const typename detector_t::name_map &names,
0062 const config &cfg = {},
0063 std::shared_ptr<test::whiteboard> wb = nullptr,
0064 const typename detector_t::geometry_context gctx = {})
0065 : m_cfg{cfg},
0066 m_gctx{gctx},
0067 m_det{det},
0068 m_names{names},
0069 m_whiteboard{std::move(wb)} {
0070 if (!m_whiteboard) {
0071 throw std::invalid_argument("No white board was passed to " +
0072 m_cfg.name());
0073 }
0074 }
0075
0076
0077 void TestBody() override {
0078
0079 volume_graph graph(m_det);
0080 const auto &adj_mat = graph.adjacency_matrix();
0081
0082
0083 dvector<dindex> adj_mat_scan(adj_mat.size(), 0);
0084
0085 std::unordered_set<dindex> obj_hashes = {};
0086
0087
0088 dindex start_index{0u};
0089
0090 DETRAY_INFO_HOST("Running scan on: " << m_det.name(m_names) << "\n");
0091
0092
0093 const std::size_t n_helices = fill_scan_data();
0094
0095 auto &detector_scan_traces =
0096 m_whiteboard->template get<std::vector<intersection_trace_t>>(
0097 m_cfg.name());
0098
0099 const std::string det_name{m_det.name(m_names)};
0100 const std::string prefix{k_use_rays ? det_name + "_ray"
0101 : det_name + "_helix"};
0102
0103 const auto data_path{
0104 std::filesystem::path{m_cfg.track_param_file()}.parent_path()};
0105
0106
0107 io::create_path(data_path);
0108
0109 std::ios_base::openmode io_mode = std::ios::trunc | std::ios::out;
0110 detray::io::file_handle debug_file{
0111 data_path / (prefix + "_detector_scan.txt"), io_mode};
0112
0113 DETRAY_INFO_HOST("Checking trace data...\n");
0114
0115
0116 std::size_t n_tracks{0u};
0117 for (int i = static_cast<int>(detector_scan_traces.size()) - 1; i >= 0;
0118 --i) {
0119 const auto j{static_cast<std::size_t>(i)};
0120
0121 auto &intersection_trace = detector_scan_traces[j];
0122 assert((intersection_trace.size() > 0) && "Invalid intersection trace");
0123
0124
0125 const auto &trck_param = intersection_trace.front().track_param;
0126 trajectory_type test_traj = get_parametrized_trajectory(trck_param);
0127
0128
0129
0130 if (m_cfg.overlaps_removal()) {
0131 const dindex_range overlap_idx = detector_scanner::overlaps_removal(
0132 intersection_trace, m_cfg.overlaps_tol());
0133
0134
0135 if (overlap_idx[1] - overlap_idx[0] != 0u) {
0136 constexpr bool verbose{false};
0137 detector_scanner::display_error(
0138 m_gctx, m_det, m_names, "OVERLAP_" + m_cfg.name(), test_traj,
0139 intersection_trace, m_cfg.svg_style(), n_tracks, n_helices,
0140 intersection_trace_t{}, overlap_idx, verbose);
0141 }
0142 }
0143
0144
0145 bool success = detector_scanner::check_trace<detector_t>(
0146 intersection_trace, start_index, adj_mat_scan, obj_hashes);
0147
0148
0149 if (!success) {
0150 detector_scanner::display_error(
0151 m_gctx, m_det, m_names, m_cfg.name(), test_traj, intersection_trace,
0152 m_cfg.svg_style(), n_tracks, n_helices, intersection_trace_t{});
0153 }
0154
0155 EXPECT_TRUE(success);
0156
0157
0158 if (!success) {
0159 *debug_file << detector_scanner::print_trace(intersection_trace, j);
0160
0161 DETRAY_ERROR_HOST("Skipped faulty trace no. " << j);
0162 detector_scan_traces.erase(detector_scan_traces.begin() + i);
0163 } else {
0164 ++n_tracks;
0165 }
0166 }
0167 std::clog << "------------------------------------\n"
0168 << "Tested " << n_tracks << " tracks: OK\n"
0169 << "------------------------------------\n"
0170 << std::endl;
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185 }
0186
0187 private:
0188
0189
0190 std::size_t fill_scan_data() {
0191
0192 std::vector<intersection_trace_t> intersection_traces;
0193
0194 auto trk_state_generator = track_generator_t(m_cfg.track_generator());
0195 const std::size_t n_helices{trk_state_generator.size()};
0196 intersection_traces.reserve(n_helices);
0197
0198 std::string momentum_str{""};
0199 if constexpr (!k_use_rays) {
0200 const auto pT_range = m_cfg.track_generator().mom_range();
0201
0202 momentum_str =
0203 "_" +
0204 std::to_string(std::floor(10. * static_cast<double>(pT_range[0])) /
0205 10.) +
0206 "_" +
0207 std::to_string(std::ceil(10. * static_cast<double>(pT_range[1])) /
0208 10.) +
0209 "_GeV";
0210 }
0211
0212 std::string track_param_file_name{m_cfg.track_param_file() + momentum_str +
0213 ".csv"};
0214
0215 std::string intersection_file_name{m_cfg.intersection_file() +
0216 momentum_str + ".csv"};
0217
0218 const bool data_files_exist{io::file_exists(intersection_file_name) &&
0219 io::file_exists(track_param_file_name)};
0220
0221 if (data_files_exist) {
0222 DETRAY_INFO_HOST("Reading data from file...");
0223
0224
0225 detector_scanner::read(intersection_file_name, track_param_file_name,
0226 intersection_traces);
0227 } else {
0228 DETRAY_INFO_HOST("Generating trace data...");
0229
0230 for (auto trk : trk_state_generator) {
0231
0232 trajectory_type test_traj = get_parametrized_trajectory(trk);
0233
0234
0235 const scalar_t qabs{math::fabs(m_cfg.m_trk_gen_cfg.charge())};
0236 const scalar_t q{math::copysign(qabs, trk.qop())};
0237
0238
0239
0240
0241
0242 const scalar p{q == 0.f ? 1.f * unit<scalar>::GeV : trk.p(q)};
0243 auto trace = detector_scanner::run<scan_type>(
0244 m_gctx, m_det, test_traj, m_cfg.mask_tolerance(), p);
0245
0246 intersection_traces.push_back(std::move(trace));
0247 }
0248 }
0249
0250
0251
0252
0253 if (!data_files_exist && m_cfg.write_intersections()) {
0254 detector_scanner::write_tracks(track_param_file_name,
0255 intersection_traces);
0256 detector_scanner::write_intersections(intersection_file_name,
0257 intersection_traces);
0258
0259 DETRAY_INFO_HOST(" ->Wrote " << intersection_traces.size()
0260 << " intersection traces to file");
0261 }
0262
0263 DETRAY_INFO_HOST(" ->Adding " << intersection_traces.size()
0264 << " intersection traces to whiteboard");
0265
0266
0267 m_whiteboard->add(m_cfg.name(), std::move(intersection_traces));
0268
0269 return n_helices;
0270 }
0271
0272
0273
0274 trajectory_type get_parametrized_trajectory(
0275 const free_track_parameters_t &track) {
0276 std::unique_ptr<trajectory_type> test_traj{nullptr};
0277 if constexpr (k_use_rays) {
0278 test_traj = std::make_unique<trajectory_type>(track);
0279 } else {
0280 test_traj = std::make_unique<trajectory_type>(track, m_cfg.B_vector());
0281 }
0282 return *(test_traj.release());
0283 }
0284
0285
0286 config m_cfg;
0287
0288 typename detector_t::geometry_context m_gctx{};
0289
0290 const detector_t &m_det;
0291
0292 const typename detector_t::name_map &m_names;
0293
0294 std::shared_ptr<test::whiteboard> m_whiteboard{nullptr};
0295 };
0296
0297 template <typename detector_t>
0298 using ray_scan = detector_scan<detector_t, detray::ray_scan>;
0299
0300 template <typename detector_t>
0301 using helix_scan = detector_scan<detector_t, detray::helix_scan>;
0302
0303 }