ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
detector_scanner.hpp
1// This file is part of the ACTS project.
2//
3// Copyright (C) 2016 CERN for the benefit of the ACTS project
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9#pragma once
10
11// Project include(s)
12#include "detray/core/concepts.hpp"
13#include "detray/definitions/algebra.hpp"
14#include "detray/geometry/surface.hpp"
15#include "detray/navigation/detail/intersection_kernel.hpp"
16#include "detray/navigation/intersection/intersection.hpp"
17#include "detray/navigation/intersector.hpp"
18#include "detray/tracks/free_track_parameters.hpp"
19#include "detray/tracks/trajectories.hpp"
20
21// Detray IO include(s)
22#include "detray/io/csv/intersection2D.hpp"
23#include "detray/io/csv/track_parameters.hpp"
24
25// Test include(s)
26#include "detray/test/utils/data_record.hpp"
27
28// System include(s)
29#include <algorithm>
30#include <sstream>
31#include <stdexcept>
32#include <type_traits>
33
34namespace detray {
35
40template <typename trajectory_t>
43 template <typename D>
46 using trajectory_type = trajectory_t;
47
55 template <concepts::detector detector_t>
56 inline auto operator()(const typename detector_t::geometry_context ctx,
57 const detector_t &detector, const trajectory_t &traj,
58 const typename detector_t::scalar_type mask_tol = 0.f,
59 const typename detector_t::scalar_type p =
60 1.f *
62 using algebra_t = typename detector_t::algebra_type;
63 using scalar_t = dscalar<algebra_t>;
64 using sf_desc_t = typename detector_t::surface_type;
65 using nav_link_t = typename detector_t::surface_type::navigation_link;
66
67 using intersection_t =
69 using intersection_kernel_t = detail::intersection_initialize<intersector>;
70
71 constexpr scalar_t external_mask_tol{0.f};
72 const intersection::config intr_cfg{
73 .min_mask_tolerance = static_cast<float>(mask_tol),
74 .max_mask_tolerance = static_cast<float>(mask_tol),
75 .mask_tolerance_scalor = 0.f,
76 .overstep_tolerance = 0.f};
77
78 intersection_trace_type<detector_t> intersection_trace{};
79
80 const auto &trf_store = detector.transform_store();
81
82 assert(p > 0.f);
83 const scalar_t q{p * traj.qop()};
84
85 dvector<intersection_t> intersections{};
86 intersections.reserve(100u);
87
88 // Loop over all surfaces in the detector
89 for (const sf_desc_t &sf_desc : detector.surfaces()) {
90 // Retrieve candidate(s) from the surface
91 const auto sf = geometry::surface{detector, sf_desc};
92 DETRAY_DEBUG_HOST("Intersecting sf: " << sf.identifier());
93
94 sf.template visit_mask<intersection_kernel_t>(
95 intersections, traj, sf_desc, trf_store, ctx, intr_cfg,
96 external_mask_tol);
97
98 // Candidate is invalid if it lies in the opposite direction
99 const std::size_t n_records{intersection_trace.size()};
100 for (auto &sfi : intersections) {
101 if (sfi.is_along()) {
102 sfi.surface() = sf_desc;
103 // Record the intersection
104 intersection_trace.emplace_back(traj.pos(sfi.path()),
105 traj.dir(sfi.path()), sfi, q, p,
106 sf.volume());
107 DETRAY_DEBUG_HOST("Recorded intersection: " << sfi);
108 }
109 }
110 intersections.clear();
111
112 if (n_records == intersection_trace.size()) {
113 DETRAY_DEBUG_HOST("No valid intersection found with this surface");
114 }
115 }
116
117 // Need to have at least an exit portal
118 if (intersection_trace.empty()) {
119 std::stringstream stream;
120 stream << "No intersections found for traj: " << traj << std::endl;
121
122 // At least a portal intersection has to be found
123 DETRAY_FATAL_HOST(stream.str());
124 throw std::runtime_error(stream.str());
125 }
126
127 // Save initial track position as dummy intersection record
128 const auto &first_record = intersection_trace.front();
129 intersection_t start_intersection{};
130 // Must not be invalid, since it will otherwise throw the navigation
131 // validation off
132 start_intersection.set_surface(first_record.intersection().surface());
133 start_intersection.surface().set_id(surface_id::e_passive);
134 start_intersection.surface().set_index(0);
135 start_intersection.surface()
136 .material()
137 .set_id(detector_t::material::id::e_none)
138 .set_index(dindex_invalid);
139 start_intersection.set_path(0.f);
140 start_intersection.set_local({0.f, 0.f, 0.f});
141 start_intersection.set_volume_link(
142 static_cast<nav_link_t>(first_record.volume()));
143
145 traj.pos(), traj.dir(), start_intersection,
146 q, p, first_record.volume()};
147
148 intersection_trace.insert(intersection_trace.begin(), start_record);
149
150 return intersection_trace;
151 }
152};
153
155template <concepts::algebra algebra_t>
157
159template <concepts::algebra algebra_t>
161
163namespace detector_scanner {
164
171template <template <typename> class scan_type, concepts::detector detector_t,
172 typename trajectory_t, typename... Args>
173inline auto run(const typename detector_t::geometry_context gctx,
174 const detector_t &detector, const trajectory_t &traj,
175 Args &&...args) {
176 using algebra_t = typename detector_t::algebra_type;
177 using nav_link_t = typename detector_t::surface_type::navigation_link;
178
179 DETRAY_DEBUG_HOST("Trajectory: " << traj);
180
181 auto intersection_trace =
182 scan_type<algebra_t>{}(gctx, detector, traj, std::forward<Args>(args)...);
183
184 using record_t = intersection_record<detector_t>;
185
186 // HACK: For whatever reason, std::stable_sort really dislikes custom
187 // aligned types like the ones in Eigen and Fastor, so we have to sort
188 // by indices and then reconstruct the sorted intersection record.
189 auto sort_path = [&](const record_t &a, const record_t &b) -> bool {
190 return (a.intersection() < b.intersection());
191 };
192
193 std::ranges::stable_sort(intersection_trace, sort_path);
194
195 // Make sure the intersection record terminates at world portals
196 auto is_world_exit = [](const record_t &r) {
197 return r.intersection().volume_link() ==
198 detray::detail::invalid_value<nav_link_t>();
199 };
200
201 if (auto it = std::ranges::find_if(intersection_trace, is_world_exit);
202 it != intersection_trace.end()) {
203 auto n{static_cast<std::size_t>(it - intersection_trace.begin())};
204 intersection_trace.resize(n + 1u);
205 }
206
207 return intersection_trace;
208}
209
214template <concepts::detector detector_t, typename allocator_t>
216 const std::string &intersection_file_name,
217 const std::vector<dvector<intersection_record<detector_t>>, allocator_t>
218 &intersection_traces) {
219 using record_t = intersection_record<detector_t>;
220 using intersection_t = typename record_t::intersection_type;
221
222 std::vector<std::vector<intersection_t>> intersections{};
223
224 // Split data
225 for (const auto &trace : intersection_traces) {
226 auto &intrs = intersections.emplace_back();
227 intrs.reserve(trace.size());
228
229 for (const auto &record : trace) {
230 intrs.push_back(record.intersection());
231 }
232 }
233
234 // Write to file
235 io::csv::write_intersection2D(intersection_file_name, intersections);
236}
237
242template <concepts::detector detector_t, typename allocator_t>
243inline auto write_tracks(
244 const std::string &track_param_file_name,
245 const std::vector<dvector<intersection_record<detector_t>>, allocator_t>
246 &intersection_traces) {
249 using track_param_t =
251
252 std::vector<std::vector<std::pair<scalar_t, track_param_t>>> track_params{};
253
254 // Split data
255 for (const auto &trace : intersection_traces) {
256 track_params.push_back({});
257 track_params.back().reserve(trace.size());
258
259 for (const auto &record : trace) {
260 track_params.back().emplace_back(record.template charge<value_t>(),
261 record.track_param());
262 }
263 }
264
265 // Write to file
266 io::csv::write_free_track_params(track_param_file_name, track_params);
267}
268
274template <concepts::detector detector_t, typename allocator_t>
275inline auto read(
276 const std::string &intersection_file_name,
277 const std::string &track_param_file_name,
278 std::vector<std::vector<intersection_record<detector_t>, allocator_t>>
279 &intersection_traces) {
281
282 // Read from file
283 auto intersections_per_track =
284 io::csv::read_intersection2D<detector_t>(intersection_file_name);
285 auto track_params_per_track =
286 io::csv::read_free_track_params<detector_t>(track_param_file_name);
287
288 if (intersections_per_track.size() != track_params_per_track.size()) {
289 throw std::invalid_argument(
290 "Detector scanner: intersection and track parameters collections have "
291 "different size");
292 }
293
294 // Interleave data
295 for (dindex trk_idx = 0u; trk_idx < intersections_per_track.size();
296 ++trk_idx) {
297 const auto &intersections = intersections_per_track[trk_idx];
298 const auto &track_params = track_params_per_track[trk_idx];
299
300 // Check track id
301 if (intersections.size() != track_params.size()) {
302 throw std::invalid_argument(
303 "Detector scanner: Found different number of intersections and track "
304 "parameters for track no." +
305 std::to_string(trk_idx));
306 }
307
308 // Check for empty input traces
309 if (intersections.empty()) {
310 throw std::invalid_argument("Detector scanner: Found empty trace no." +
311 std::to_string(trk_idx));
312 }
313
314 // Add new trace
315 if (intersection_traces.size() <= trk_idx) {
316 intersection_traces.push_back({});
317 }
318
319 // Add records to trace
320 for (dindex i = 0u; i < intersections.size(); ++i) {
321 const track_t &free_param = track_params[i].second;
322 intersection_traces[trk_idx].push_back(intersection_record<detector_t>{
323 free_param.pos(), free_param.dir(), intersections[i],
324 track_params[i].first, free_param.p(track_params[i].first),
325 intersections[i].surface().volume()});
326 }
327 }
328}
329
330} // namespace detector_scanner
331
332} // namespace detray
auto transform_store(const geometry_context &={}) const -> const transform_container &
Definition detector.hpp:301
auto surfaces() const -> const surface_lookup_container &
Definition detector.hpp:286
Facade for a detray detector surface.
Definition surface.hpp:36
Check if a type can be used as a detector.
Definition concepts.hpp:47
Run a scan on detector object by shooting test particles through it.
Definition detector_scan_utils.hpp:39
auto write_intersections(const std::string &intersection_file_name, const std::vector< dvector< intersection_record< detector_t > >, allocator_t > &intersection_traces)
Write the intersection_traces to file.
Definition detector_scanner.hpp:215
auto run(const typename detector_t::geometry_context gctx, const detector_t &detector, const trajectory_t &traj, Args &&...args)
Run a scan on detector object by shooting test particles through it.
Definition detector_scanner.hpp:173
auto read(const std::string &intersection_file_name, const std::string &track_param_file_name, std::vector< std::vector< intersection_record< detector_t >, allocator_t > > &intersection_traces)
Read the intersection_record from file.
Definition detector_scanner.hpp:275
auto write_tracks(const std::string &track_param_file_name, const std::vector< dvector< intersection_record< detector_t > >, allocator_t > &intersection_traces)
Write the intersection_traces to file.
Definition detector_scanner.hpp:243
Detray include(s).
Definition array_operators.hpp:18
get_scalar_t< A, T > dscalar
Scalar type for algebra A and value type T.
Definition algebra.hpp:64
vecmem::vector< value_t > dvector
Vector container backed by vecmem.
Definition containers.hpp:34
brute_force_scan< detail::ray< algebra_t > > ray_scan
Type of a ray scan for the selected algebra.
Definition detector_scanner.hpp:156
unsigned int dindex
Default index type.
Definition indexing.hpp:18
constexpr dindex dindex_invalid
Global invalid index definition.
Definition indexing.hpp:21
get_value_t< A > dvalue
Value scalar type of the algebra backend.
Definition algebra.hpp:48
brute_force_scan< detail::helix< algebra_t > > helix_scan
Type of a helix scan for the selected algebra.
Definition detector_scanner.hpp:160
free_parameters_vector< algebra_t > free_track_parameters
The free track parameters consist only of the parameter vector.
Definition free_track_parameters.hpp:249
struct that holds functionality to shoot a parametrized particle trajectory through a detector.
Definition detector_scanner.hpp:41
dvector< intersection_record< D > > intersection_trace_type
Type of the intersection trace produced for a detector.
Definition detector_scanner.hpp:44
trajectory_t trajectory_type
Type of trajectory scanned by this functor.
Definition detector_scanner.hpp:46
auto operator()(const typename detector_t::geometry_context ctx, const detector_t &detector, const trajectory_t &traj, const typename detector_t::scalar_type mask_tol=0.f, const typename detector_t::scalar_type p=1.f *unit< typename detector_t::scalar_type >::GeV)
Scan a detector along the configured trajectory.
Definition detector_scanner.hpp:56
Intersector configuration.
Definition intersection_config.hpp:21
Record of a surface intersection along a track.
Definition data_record.hpp:27
intersection2D< typename detector_t::surface_type, typename detector_t::algebra_type, intersection::contains_pos > intersection_type
Intersection result type stored by this record.
Definition data_record.hpp:41
static constexpr scalar_t GeV
Native energy unit, the gigaelectronvolt.
Definition units.hpp:81