ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
direct_navigator.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/core/detector.hpp"
14#include "detray/definitions/algorithms.hpp"
15#include "detray/definitions/containers.hpp"
16#include "detray/definitions/detail/qualifiers.hpp"
17#include "detray/definitions/indexing.hpp"
18#include "detray/definitions/navigation.hpp"
19#include "detray/definitions/units.hpp"
20#include "detray/navigation/detail/intersection_kernel.hpp"
21#include "detray/navigation/detail/navigation_functions.hpp"
22#include "detray/navigation/intersection/intersection.hpp"
23#include "detray/navigation/intersection/intersection_config.hpp"
24#include "detray/navigation/intersection/ray_intersector.hpp"
25#include "detray/navigation/navigation_config.hpp"
26#include "detray/navigation/navigation_state.hpp"
27#include "detray/tracks/ray.hpp"
28
29// System include(s)
30#include <limits>
31
32namespace detray {
33
37template <concepts::detector detector_t, typename surface_sequence_t = void>
39 using algebra_t = typename detector_t::algebra_type;
40 using scalar_t = dscalar<algebra_t>;
41
42 public:
44 using detector_type = detector_t;
46 using context_type = detector_type::geometry_context;
47
48 // Use an external surface sequence type (rather than a single surface type),
49 // perigee/external surface flows instantiate direct_navigator with
50 // single_view-like range wrappers.
52 using surface_sequence_type = std::conditional_t<
53 std::same_as<surface_sequence_t, void>,
54 vecmem::device_vector<typename detector_t::surface_type>,
55 surface_sequence_t>;
56
58 "Surface sequence must be iterable");
59
61 using surface_type = detray::ranges::range_value_t<surface_sequence_type>;
67
69 class state
70 : public navigation::base_state<state, detector_type, 2u, inspector_type,
71 intersection_type> {
72 friend class direct_navigator;
73
74 template <typename state_t>
75 friend constexpr void navigation::update_status(state_t &,
76 const navigation::config &);
77
78 using base_type = navigation::base_state<state, detector_type, 2u,
80
81 // Internal surface index
82 using dist_t = std::int_least16_t;
83
84 public:
89
91 using view_type =
92 std::conditional_t<std::same_as<surface_sequence_t, void>,
93 detail::get_view_t<surface_sequence_type>,
97 std::conditional_t<std::same_as<surface_sequence_t, void>,
98 detail::get_view_t<const surface_sequence_type>,
100
105 DETRAY_HOST_DEVICE constexpr state(const detector_t &det,
106 const view_type &sequence)
107 : base_type(det), m_sequence(sequence) {
108 assert(!m_sequence.empty());
109 reset();
110 }
111
113 DETRAY_HOST_DEVICE void reset() {
114 // Remove old navigation information
115 clear_cache();
116
117 // Set the index into the external surface sequence to the beginning
118 // or end of the container
119 m_next_external = is_forward()
120 ? dist_t{0}
121 : static_cast<dist_t>(m_sequence.size() - 1u);
122
123 // Update the target with the next external surface
124 this->target().set_surface(next_external());
125
126 // The next candidate is always stored in the second cache entry
127 this->next_index(1u);
128 this->last_index(1u);
129 }
130
132 DETRAY_HOST_DEVICE
133 constexpr auto n_candidates() const -> dindex { return 1u; }
134
136 DETRAY_HOST_DEVICE
137 constexpr scalar_t external_tol() const {
138 return std::numeric_limits<scalar_t>::max();
139 }
140
143 DETRAY_HOST_DEVICE
144 constexpr void set_direction(const navigation::direction dir) {
146 }
147
149 DETRAY_HOST_DEVICE
150 constexpr bool has_next_external() const {
151 return (is_forward() &&
152 m_next_external != static_cast<dist_t>(m_sequence.size())) ||
153 (!is_forward() && m_next_external != -1);
154 }
155
158 DETRAY_HOST_DEVICE
160 assert(has_next_external());
161 return m_sequence[static_cast<unsigned int>(m_next_external)];
162 }
163
165 DETRAY_HOST_DEVICE
166 constexpr void advance() {
167 // The target has become the current candidate
168 this->candidates()[0] = this->target();
169
170 assert(has_next_external());
171 if (is_forward()) {
172 m_next_external++;
173 } else {
174 m_next_external--;
175 }
176
177 // Update the target with the next external surface
178 // Could make the target invalid -> exit navigation
179 if (has_next_external()) {
180 // If the next external can be indexed, the cast is safe
181 this->target().set_surface(
182 m_sequence[static_cast<unsigned int>(m_next_external)]);
183 }
184
185 assert(
187 (has_next_external() && (this->target().surface().is_sensitive() ||
188 this->target().surface().has_material())));
189 }
190
192 DETRAY_HOST_DEVICE constexpr void clear_cache() {
194 this->next_index(1);
195 this->last_index(1);
196 }
197
199 DETRAY_HOST_DEVICE
200 constexpr bool finished() const {
201 // Normal exit for this navigation?
202 bool is_finished = base_type::finished();
203
204 // All external surfaces were visited?
205 is_finished =
206 is_finished &&
207 ((is_forward() &&
208 m_next_external == static_cast<dist_t>(m_sequence.size())) ||
209 (!is_forward() && m_next_external == -1));
210
211 return is_finished;
212 }
213
214 private:
216 DETRAY_HOST_DEVICE
217 constexpr bool is_forward() const {
218 return this->direction() == navigation::direction::e_forward;
219 }
220
222 sequence_type m_sequence;
223
225 dist_t m_next_external{0};
226 };
227
233 template <typename track_t>
234 DETRAY_HOST_DEVICE inline void init(const track_t &track, state &navigation,
235 const navigation::config &cfg,
236 const context_type &ctx) const {
237 DETRAY_VERBOSE_HOST_DEVICE("Called 'init()':");
238 assert(navigation.has_next_external());
239
240 // Clean up state
241 navigation.clear_cache();
242
243 // Update the next candidate
244 update(track, navigation, cfg, ctx);
245
246 DETRAY_VERBOSE_HOST_DEVICE("Init complete!");
247 }
248
256 template <typename track_t>
257 DETRAY_HOST_DEVICE inline bool update(const track_t &track, state &navigation,
258 const navigation::config &cfg,
259 const context_type &ctx = {}) const {
260 DETRAY_VERBOSE_HOST_DEVICE("Called 'update()'");
261 DETRAY_DEBUG_HOST(" -> Trust level: " << navigation.trust_level());
262
263 // Do not resurrect a failed/finished navigation state
264 assert(navigation.is_alive() ||
265 navigation.status() == navigation::status::e_unknown);
266 assert(!track.is_invalid());
267
268 // If the last external was reached, the navigation is finished
269 constexpr bool is_init{true};
270 if (!navigation.has_next_external()) {
271 DETRAY_VERBOSE_HOST_DEVICE("No next target in surface sequence: Exit");
272 navigation.exit();
273 return !is_init;
274 }
275
276 const detector_type &det = navigation.detector();
277
278 // Update only the current candidate and the corresponding next target
279 if (navigation.trust_level() != navigation::trust_level::e_full) {
280 // Use infinite tolerance to hit the target surface
281 constexpr auto inf{std::numeric_limits<float>::max()};
282 const intersection::config intr_cfg{
283 inf, inf, inf, cfg.intersection.path_tolerance, -inf};
284
285 // Tangential to the track direction
286 const detray::detail::ray<algebra_t> tangential{
287 track.pos(),
288 static_cast<scalar_t>(navigation.direction()) * track.dir()};
289
290 // Update the current target. If it cannot be reached, direct
291 // navigation is broken
292 if (!update_candidate(tangential, det, navigation, intr_cfg, ctx)) {
293 // If update fails but the track is already on the target within
294 // tolerance, treat the target as reached instead of aborting.
295 if (target_reached_within_tolerance(track, navigation, cfg)) {
296 navigation.target().set_path(static_cast<scalar_t>(0.f));
297 navigation.target().set_status(intersection::status::e_inside);
298 } else {
299 navigation.abort("Could not reach current target");
300 return !is_init;
301 }
302 }
303
304 // Update navigation flow on the new candidate information and set
305 // the next target if the surface has been reached
306 navigation::update_status(navigation, cfg);
307 // Set full trust, even if a portal was reached (no volume switch)
308 navigation.trust_level(navigation::trust_level::e_full);
309
310 // The work is done if the track has not reached the surface yet
311 if (navigation.status() == navigation::status::e_towards_object) {
312 DETRAY_VERBOSE_HOST_DEVICE("Update complete (towards object):");
313 DETRAY_DEBUG_HOST("\n"
314 << detray::navigation::print_state(navigation)
315 << detray::navigation::print_candidates(
316 navigation, cfg, track.pos(), track.dir()));
317
318 return !is_init;
319 }
320
321 // Otherwise, track is on surface: Update the next target
322 if (navigation.has_next_external() &&
323 !update_candidate(tangential, det, navigation, intr_cfg, ctx)) {
324 navigation.abort("Could not find new target after surface was reached");
325 return !is_init;
326 }
327
328 // At this point, the track has to be on surface:
329 // Set volume index to the volume the current surface is in
330 navigation.set_volume(navigation.current().surface().volume());
331
332 // Set full trust again: no volume switch needed
333 navigation.trust_level(navigation::trust_level::e_full);
334
335 DETRAY_VERBOSE_HOST_DEVICE("Update complete (on surface):");
336 DETRAY_DEBUG_HOST("\n"
337 << detray::navigation::print_state(navigation)
338 << detray::navigation::print_candidates(
339 navigation, cfg, track.pos(), track.dir()));
340
341 // Return true to reset the step size of the RKN algorithm
342 return is_init;
343 }
344
345 DETRAY_VERBOSE_HOST_DEVICE(" -> Full trust: Nothing left to do");
346
347 return !is_init;
348 }
349
350 private:
353 DETRAY_HOST_DEVICE DETRAY_INLINE constexpr bool update_candidate(
354 const detray::detail::ray<algebra_t> &tangential, const detector_t &det,
355 state &navigation, const intersection::config &intr_cfg,
356 [[maybe_unused]] const context_type &ctx) const {
357 if constexpr (std::same_as<surface_sequence_t, void>) {
358 // Update a detector surface.
359 return navigation::update_candidate(navigation.target(), tangential, det,
360 intr_cfg, navigation.external_tol(),
361 ctx);
362 } else {
363 // Update a standalone surface.
364 return update_external_candidate(navigation.target(), tangential,
365 navigation.next_external(), intr_cfg,
366 navigation.external_tol());
367 }
368 }
369
371 DETRAY_HOST_DEVICE DETRAY_INLINE constexpr bool update_external_candidate(
372 typename state::value_type &candidate,
373 const detray::detail::ray<algebra_t> &tangential, const surface_type &sf,
374 const intersection::config &cfg,
375 const scalar_t external_mask_tolerance) const {
376 constexpr ray_intersector<typename surface_type::mask_type::shape,
377 algebra_t, !intersection::contains_pos>
378 intersector{};
379
380 // Intersect the standalone surface.
381 typename decltype(intersector)::result_type result{};
382 if constexpr (concepts::cylindrical<typename surface_type::mask_type>) {
383 result = intersector.point_of_intersection(
384 tangential, sf.transform(), sf.mask(), cfg.overstep_tolerance);
385 } else {
386 result = intersector.point_of_intersection(tangential, sf.transform(),
387 cfg.overstep_tolerance);
388 }
389
390 // Build resulting intersection candidate(s).
391 if constexpr (decltype(intersector)::n_solutions > 1) {
392 resolve_mask(candidate, tangential, result[0], candidate.surface(),
393 sf.mask(), sf.transform(), cfg, external_mask_tolerance);
394 } else {
395 resolve_mask(candidate, tangential, result, candidate.surface(),
396 sf.mask(), sf.transform(), cfg, external_mask_tolerance);
397 }
398
399 return candidate.is_probably_inside();
400 }
401
403 template <typename track_t>
404 DETRAY_HOST_DEVICE DETRAY_INLINE constexpr bool
405 target_reached_within_tolerance(const track_t &track, const state &navigation,
406 const navigation::config &cfg) const {
407 if constexpr (std::same_as<surface_sequence_t, void>) {
408 return false;
409 } else {
410 const surface_type target_sf = navigation.target().surface();
411 const auto inside = target_sf.mask().is_inside(
412 target_sf.transform(), track.pos(),
413 static_cast<scalar_t>(cfg.intersection.path_tolerance));
414
415 if constexpr (std::is_scalar_v<decltype(inside)>) {
416 return inside;
417 } else {
418 return detray::detail::any_of(inside);
419 }
420 }
421 }
422};
423
424} // namespace detray
Mutable state for traversing the external surface sequence.
Definition direct_navigator.hpp:71
constexpr bool finished() const
Definition direct_navigator.hpp:200
surface_sequence_type sequence_type
Range type retained by the navigation state.
Definition direct_navigator.hpp:88
void reset()
Reset the navigation state.
Definition direct_navigator.hpp:113
std::conditional_t< std::same_as< surface_sequence_t, void >, detail::get_view_t< const surface_sequence_type >, surface_sequence_type > const_view_type
Const view type corresponding to the configured sequence type.
Definition direct_navigator.hpp:96
constexpr void set_direction(const navigation::direction dir)
Set direction in which the navigator should search for candidates.
Definition direct_navigator.hpp:144
intersection_type value_type
Candidate value type stored in the base navigation state.
Definition direct_navigator.hpp:86
std::conditional_t< std::same_as< surface_sequence_t, void >, detail::get_view_t< surface_sequence_type >, surface_sequence_type > view_type
View used to access the sequence during navigation.
Definition direct_navigator.hpp:91
constexpr scalar_t external_tol() const
Definition direct_navigator.hpp:137
constexpr void advance()
Advance the iterator (navigation status needs to be up to date!).
Definition direct_navigator.hpp:166
constexpr auto n_candidates() const -> dindex
Definition direct_navigator.hpp:133
constexpr state(const detector_t &det, const view_type &sequence)
Constructor using the detector and an externally provided sequence of detector surfaces.
Definition direct_navigator.hpp:105
constexpr surface_type next_external()
Advance the iterator.
Definition direct_navigator.hpp:159
constexpr bool has_next_external() const
Definition direct_navigator.hpp:150
constexpr void clear_cache()
Clear the state.
Definition direct_navigator.hpp:192
Navigator that visits an externally supplied sequence of surfaces in order.
Definition direct_navigator.hpp:38
void init(const track_t &track, state &navigation, const navigation::config &cfg, const context_type &ctx) const
Initialize the direct navigation flow on the first/last external surface.
Definition direct_navigator.hpp:234
detector_t detector_type
Detector whose surfaces are navigated.
Definition direct_navigator.hpp:44
navigation::void_inspector inspector_type
Inspector policy used by the direct navigation flow.
Definition direct_navigator.hpp:66
detray::ranges::range_value_t< surface_sequence_type > surface_type
Descriptor type stored in the surface sequence.
Definition direct_navigator.hpp:61
intersection2D< surface_type, algebra_t, !intersection::contains_pos > intersection_type
Intersection record stored in the navigation state.
Definition direct_navigator.hpp:63
bool update(const track_t &track, state &navigation, const navigation::config &cfg, const context_type &ctx={}) const
Update the navigation status on the current next external and switch to the following external surfac...
Definition direct_navigator.hpp:257
std::conditional_t< std::same_as< surface_sequence_t, void >, vecmem::device_vector< typename detector_t::surface_type >, surface_sequence_t > surface_sequence_type
Range containing the surfaces visited by this navigator.
Definition direct_navigator.hpp:52
detector_type::geometry_context context_type
Geometry context expected by the detector.
Definition direct_navigator.hpp:46
This class holds the intersection information.
Definition intersection.hpp:212
A navigation state object used to cache the information of the current navigation stream.
Definition navigation_state.hpp:81
constexpr auto candidates() const -> const candidate_cache_t &
Definition navigation_state.hpp:317
constexpr void set_direction(const navigation::direction dir)
Definition navigation_state.hpp:207
constexpr auto target() const -> const candidate_t &
Definition navigation_state.hpp:344
constexpr auto direction() const -> navigation::direction
Definition navigation_state.hpp:200
constexpr dist_t last_index() const
Definition navigation_state.hpp:537
constexpr dist_t next_index() const
Definition navigation_state.hpp:533
Range concept.
Definition ranges.hpp:97
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
constexpr void resolve_mask(intersection_t &is, const trajectory_t &traj, const intersection_point< algebra_t, point_t, intersection::contains_pos > &ip, const surface_descr_t sf_desc, const mask_t &mask, const transform3_t &trf, const intersection::config &cfg={}, const scalar_t external_mask_tolerance=0.f)
Fill an intersection with the result of the intersection alg.
Definition intersector_base.hpp:189
unsigned int dindex
Default index type.
Definition indexing.hpp:18
intersector_base< ray_intersector_impl< typename shape_t::template local_frame_type< algebra_t >, algebra_t, resolve_pos > > ray_intersector
Select the ray intersector specialization for a shape's local frame.
Definition ray_intersector.hpp:36
float path_tolerance
Maximal absolute path distance for a track to be considered 'on surface'.
Definition intersection_config.hpp:32
Navigation configuration.
Definition navigation_config.hpp:24
intersection::config intersection
Tolerance on the mask 'is_inside' check:
Definition navigation_config.hpp:26
A void inpector that does nothing.
Definition navigation_state.hpp:38