ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
caching_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/definitions/algorithms.hpp"
14#include "detray/definitions/detail/qualifiers.hpp"
15#include "detray/definitions/indexing.hpp"
16#include "detray/definitions/navigation.hpp"
17#include "detray/definitions/units.hpp"
18#include "detray/geometry/surface.hpp"
19#include "detray/navigation/detail/navigation_functions.hpp"
20#include "detray/navigation/intersection/intersection.hpp"
21#include "detray/navigation/intersection/ray_intersector.hpp"
22#include "detray/navigation/navigation_config.hpp"
23#include "detray/navigation/navigation_state.hpp"
24#include "detray/navigation/navigator_base.hpp"
25#include "detray/tracks/ray.hpp"
26#include "detray/utils/logging.hpp"
27
28// System include(s)
29#include <limits>
30
31namespace detray {
32
33namespace navigation {
34
35static constexpr std::size_t default_cache_size{8u};
36
37} // namespace navigation
38
51template <concepts::detector detector_t,
52 std::size_t k_cache_capacity = navigation::default_cache_size,
53 typename inspector_t = navigation::void_inspector,
54 typename intersection_t = intersection2D<
55 typename detector_t::surface_type,
56 typename detector_t::algebra_type, !intersection::contains_pos>>
58 : public navigator_base<caching_navigator<detector_t, k_cache_capacity,
59 inspector_t, intersection_t>> {
61
63
64 public:
66 using detector_type = detector_t;
68 using context_type = typename detector_type::geometry_context;
70 using intersection_type = intersection_t;
72 using inspector_type = inspector_t;
73
81 class state
82 : public navigation::base_state<state, detector_type, k_cache_capacity,
83 inspector_type, intersection_type> {
84 // Allow the navigator classes to access methods that update the state
85 friend class caching_navigator;
86 friend class navigator_base<caching_navigator>;
87
88 // Allow the filling of candidates
89 friend struct detail::intersection_initialize<ray_intersector>;
90
91 // Navigation utility functions that need to modify the state
92 template <typename state_t>
93 friend constexpr void navigation::update_status(state_t &,
94 const navigation::config &);
95
96 template <typename track_t, typename state_t, typename ctx_t>
97 friend constexpr void navigation::local_navigation(
98 const track_t &, state_t &, const navigation::config &, const ctx_t &,
99 const bool);
100
101 template <typename track_t, typename state_t, typename ctx_t>
102 friend constexpr void navigation::volume_switch(const track_t &, state_t &,
103 const navigation::config &,
104 const ctx_t &);
105
106 using base_type =
107 navigation::base_state<state, detector_type, k_cache_capacity,
109
110 // Result of a geometry object evaluation
111 using candidate_t = typename base_type::candidate_t;
112 using candidate_cache_t = typename base_type::candidate_cache_t;
113 using candidate_itr_t = typename base_type::candidate_itr_t;
114 using candidate_const_itr_t = typename base_type::candidate_const_itr_t;
115 using dist_t = typename base_type::dist_t;
116
117 public:
119 using value_type = candidate_t;
120
122 using view_type = detail::get_view_t<inspector_t>;
124 using const_view_type = detail::get_view_t<const inspector_t>;
125
127 using base_type::base_type;
128
130 DETRAY_HOST_DEVICE
131 constexpr void set_high_trust() {
132 DETRAY_VERBOSE_HOST_DEVICE("Flagging re-navigation: \"high trust\"");
133 this->trust_level(this->trust_level() < navigation::trust_level::e_high
134 ? this->trust_level()
135 : navigation::trust_level::e_high);
136 }
137
139 DETRAY_HOST_DEVICE
140 constexpr void set_fair_trust() {
141 DETRAY_VERBOSE_HOST_DEVICE("Flagging re-navigation: \"fair trust\"");
142 this->trust_level(this->trust_level() < navigation::trust_level::e_fair
143 ? this->trust_level()
144 : navigation::trust_level::e_fair);
145 }
146
147 private:
149 DETRAY_HOST_DEVICE
150 constexpr void insert(candidate_const_itr_t pos,
151 const intersection_type &new_candidate) {
152 // Candidate is too far away to be placed in cache
153 if (pos == this->candidates().end()) {
154 return;
155 }
156
157 assert(detail::is_invalid_value(new_candidate.volume_link()) ||
158 new_candidate.volume_link() < this->detector().volumes().size());
159
160 // Insert the first candidate
161 if (this->n_candidates() == 0) [[unlikely]] {
162 this->candidates()[0] = new_candidate;
163 this->last_index(static_cast<dist_t>(this->last_index() + 1));
164 assert(this->next_index() <= this->last_index() + 1);
165 assert(static_cast<std::size_t>(this->last_index()) < k_cache_capacity);
166 return;
167 }
168
169 // Position where to insert the new candidate
170 auto idx{static_cast<dist_t>(
171 detray::ranges::distance(this->candidates().cbegin(), pos))};
172 assert(idx >= 0);
173
174 // Do not add the same surface (intersection) multiple times
175 const auto is_overlap_at_pos = [this, &new_candidate](std::size_t index) {
176 return (math::fabs(this->candidates()[index].path() -
177 new_candidate.path()) <= 1.f * unit<scalar_t>::um);
178 };
179
180 // Make sure that surfaces don't appear multiple times in the navigation
181 // cache. If the search window is opened on a grid that contains an entire
182 // neighbourhood in every bin, a neighbourhood lookup will result in
183 // surfaces appearing multiple times in the cache. If this appears too
184 // often, the cache can contain only this surface, leading to the
185 // navigator getting stuck on that surface.
186 const auto is_clash_at_pos = [this, &new_candidate,
187 &is_overlap_at_pos](std::size_t index) {
188 return (this->candidates()[index].surface().identifier() ==
189 new_candidate.surface().identifier()) &&
190 is_overlap_at_pos(index);
191 };
192
193 const auto idxu{static_cast<std::size_t>(idx)};
194 if (is_clash_at_pos(idxu) || ((idxu > 0u) && is_clash_at_pos(idxu - 1u)))
195 [[unlikely]] {
196 return;
197 }
198
199 // Shift all following candidates and evict the last element,
200 // if the cache is already full
201 constexpr auto shift_max{static_cast<dist_t>(k_cache_capacity - 2)};
202 const dist_t shift_begin{math::min(this->last_index(), shift_max)};
203
204 // In case of overlaps, prefer sensitives over portals and
205 // direct hits over edge hits
206 if (is_overlap_at_pos(idxu) &&
207 (new_candidate.is_edge() || new_candidate.surface().is_portal())) {
208 // Don't shift the overlapping candidate and put the new
209 // candidate behind it
210 idx++;
211 idx = idx > shift_begin ? shift_begin : idx;
212 }
213
214 for (dist_t i = shift_begin; i >= idx; --i) {
215 const auto j{static_cast<std::size_t>(i)};
216 this->candidates()[j + 1u] = this->candidates()[j];
217 }
218
219 // Now insert the new candidate and update candidate range
220 this->candidates()[static_cast<std::size_t>(idx)] = new_candidate;
221 this->last_index(math::min(static_cast<dist_t>(this->last_index() + 1),
222 static_cast<dist_t>(k_cache_capacity - 1)));
223
224 assert(this->next_index() <= this->last_index() + 1);
225 assert(static_cast<std::size_t>(this->last_index()) < k_cache_capacity);
226 }
227
229 DETRAY_HOST_DEVICE constexpr void clear_cache() {
231 this->next_index(0);
232 this->last_index(-1);
233 }
234 };
235
236 private:
247 template <typename track_t>
248 DETRAY_HOST_DEVICE constexpr bool update_impl(const track_t &track,
249 state &navigation,
250 const navigation::config &cfg,
251 const context_type &ctx) const {
252 const auto &det = navigation.detector();
253 constexpr bool is_init{true};
254
255 using algebra_t = typename detector_t::algebra_type;
256
257 assert(navigation.trust_level() != navigation::trust_level::e_full);
258
259 // Tangential to the track direction
260 const detray::detail::ray<algebra_t> tangential{
261 track.pos(),
262 static_cast<scalar_t>(navigation.direction()) * track.dir()};
263
264 // Update only the current candidate and the corresponding next target
265 // - do this only when the navigation state is still coherent
266 if (navigation.trust_level() == navigation::trust_level::e_high) {
267 DETRAY_VERBOSE_HOST_DEVICE("Called 'update()' - high trust");
268
269 // Update next candidate: If not reachable, 'high trust' is broken
270 if (!navigation::update_candidate(navigation.target(), tangential, det,
271 cfg.intersection,
272 navigation.external_tol(), ctx)) {
273 DETRAY_VERBOSE_HOST_DEVICE(
274 "-> Candidate not reachable! High trust broken:");
275
276 navigation.status(navigation::status::e_unknown);
277 // This will run into the fair trust case below.
278 navigation.set_fair_trust();
279 } else {
280 // Update navigation flow on the new candidate information
281 navigation::update_status(navigation, cfg);
282
283 navigation.run_inspector(cfg, track.pos(), track.dir(),
284 "Update complete: high trust: ");
285
286 // The work is done if: the track has not reached a surface yet
287 // or trust is gone (portal was reached or the cache is broken).
288 if (navigation.status() == navigation::status::e_towards_object ||
289 navigation.is_on_portal()) {
290 if (navigation.status() == navigation::status::e_towards_object) {
291 DETRAY_VERBOSE_HOST_DEVICE("-> Towards surface: %d",
292 navigation.next_surface().index());
293 } else {
294 DETRAY_VERBOSE_HOST_DEVICE("-> On portal: idx %d",
295 navigation.current_surface().index());
296 }
297 return !is_init;
298 }
299 // Else (if full trust): Track is on non-portal surface and
300 // cache is not exhausted. Ready the next target
301 if (navigation.trust_level() == navigation::trust_level::e_full &&
302 navigation::update_candidate(navigation.target(), tangential, det,
303 cfg.intersection,
304 navigation.external_tol(), ctx)) {
305 DETRAY_VERBOSE_HOST_DEVICE(
306 "-> On non-portal surface (idx %d) and next candidate "
307 "in cache is reachable",
308 navigation.current_surface().index());
309 return !is_init;
310 }
311 DETRAY_VERBOSE_HOST_DEVICE(
312 "-> Next candidate no longer reachable: High trust broken");
313
314 // If next candidate is not reachable, don't 'return', but
315 // escalate the trust level.
316 // This will run into the fair trust case below or the no trust
317 // case if the cache is broken
318 navigation.set_fair_trust();
319 }
320 }
321 // Re-evaluate all currently available candidates and sort again
322 // - do this when your navigation state is stale, but not invalid
323 if (navigation.trust_level() == navigation::trust_level::e_fair &&
324 !navigation.cache_exhausted()) {
325 DETRAY_VERBOSE_HOST_DEVICE("Called 'update()' - fair trust");
326
327 for (auto &candidate : navigation) {
328 // Disregard this candidate if it is not reachable
329 if (!navigation::update_candidate(candidate, tangential, det,
330 cfg.intersection,
331 navigation.external_tol(), ctx)) {
332 // Forcefully set dist to numeric max for sorting
333 candidate.set_path(std::numeric_limits<scalar_t>::max());
334 }
335 }
336 detray::sequential_sort(navigation.begin(), navigation.end());
337 // Take the nearest (sorted) candidate first
338 navigation.set_next(navigation.begin());
339 // Ignore unreachable elements (needed to determine exhaustion)
340 navigation.set_last(find_invalid(navigation.candidates()));
341 // Update navigation flow on the new candidate information
342 navigation::update_status(navigation, cfg);
343
344 navigation.run_inspector(cfg, track.pos(), track.dir(),
345 "Update complete: fair trust: ");
346
347 // If there are no reachable candidates in the cache after
348 // re-evaluation, re-initialize the volume
349 if (navigation.cache_exhausted()) {
350 navigation.set_no_trust();
351 }
352 }
353 // Re-initialize the volume (actor flagged 'no trust' or previous trust
354 // level update failed)
355 if (navigation.trust_level() == navigation::trust_level::e_no_trust) {
356 DETRAY_VERBOSE_HOST_DEVICE("Called 'update()' - no trust");
357
358 constexpr bool resolve_overstepping{true};
359 navigation::local_navigation(track, navigation, cfg, ctx,
360 resolve_overstepping);
361 return is_init;
362 }
363
364 return !is_init;
365 }
366
374 DETRAY_HOST_DEVICE constexpr auto find_invalid(
375 const typename state::candidate_cache_t &candidates) const {
376 // Depends on previous invalidation of unreachable candidates!
377 auto not_reachable = [](const intersection_type &candidate) {
378 return candidate.path() == std::numeric_limits<scalar_t>::max();
379 };
380
381 return detray::find_if(candidates.begin(), candidates.end(), not_reachable);
382 }
383};
384
385} // namespace detray
Navigation state that contains a cache of candidates.
Definition caching_navigator.hpp:83
constexpr void set_high_trust()
Update navigation trust level to high trust.
Definition caching_navigator.hpp:131
candidate_t value_type
Value type stored in the bins or result.
Definition caching_navigator.hpp:119
detail::get_view_t< const inspector_t > const_view_type
Const view type exposing inspector state.
Definition caching_navigator.hpp:124
constexpr void set_fair_trust()
Update navigation trust level to fair trust.
Definition caching_navigator.hpp:140
detail::get_view_t< inspector_t > view_type
View type exposing inspector state.
Definition caching_navigator.hpp:122
Navigation class which caches a 'road' through the detector.
Definition caching_navigator.hpp:59
typename detector_type::geometry_context context_type
Geometry context expected by the detector.
Definition caching_navigator.hpp:68
inspector_t inspector_type
Policy used to expose navigation diagnostics.
Definition caching_navigator.hpp:72
intersection_t intersection_type
Intersection result type associated with a surface descriptor.
Definition caching_navigator.hpp:70
detector_t detector_type
Detector whose surfaces are navigated.
Definition caching_navigator.hpp:66
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
darray< candidate_t, k_cache_capacity > candidate_cache_t
Definition navigation_state.hpp:113
constexpr auto candidates() const -> const candidate_cache_t &
Definition navigation_state.hpp:317
constexpr auto end() const -> candidate_const_itr_t
Definition navigation_state.hpp:165
constexpr auto cbegin() const -> candidate_const_itr_t
Definition navigation_state.hpp:159
typename candidate_cache_t::iterator candidate_itr_t
Definition navigation_state.hpp:115
constexpr auto trust_level() const -> navigation::trust_level
Definition navigation_state.hpp:231
typename candidate_cache_t::const_iterator candidate_const_itr_t
Definition navigation_state.hpp:117
Navigation base class - interface towards the propagator.
Definition navigator_base.hpp:45
Check if a type can be used as a detector.
Definition concepts.hpp:47
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
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
void sequential_sort(rand_iter_t first, sentinel_t last)
sequential (single thread) sort function
Definition algorithms.hpp:29
auto find_if(rand_iter_t first, sentinel_t last, Predicate &&comp)
find_if implementation for host/device (single thread)
Definition algorithms.hpp:48
Navigation configuration.
Definition navigation_config.hpp:24
A void inpector that does nothing.
Definition navigation_state.hpp:38
static constexpr scalar_t um
Length, native unit mm.
Definition units.hpp:25