Skip to content

Commit 166c9a6

Browse files
committed
Implement direct navigator
1 parent 92a537e commit 166c9a6

File tree

10 files changed

+623
-19
lines changed

10 files changed

+623
-19
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
/** Detray library, part of the ACTS project (R&D line)
2+
*
3+
* (c) 2025 CERN for the benefit of the ACTS project
4+
*
5+
* Mozilla Public License Version 2.0
6+
*/
7+
8+
#pragma once
9+
10+
// Project include(s)
11+
#include "detray/core/detector.hpp"
12+
#include "detray/definitions/algorithms.hpp"
13+
#include "detray/definitions/containers.hpp"
14+
#include "detray/definitions/detail/qualifiers.hpp"
15+
#include "detray/definitions/indexing.hpp"
16+
#include "detray/definitions/units.hpp"
17+
#include "detray/geometry/barcode.hpp"
18+
#include "detray/navigation/intersection/intersection.hpp"
19+
#include "detray/navigation/intersection/ray_intersector.hpp"
20+
#include "detray/navigation/intersection_kernel.hpp"
21+
#include "detray/navigation/navigation_config.hpp"
22+
#include "detray/navigation/navigator.hpp"
23+
#include "detray/tracks/ray.hpp"
24+
#include "detray/utils/ranges.hpp"
25+
26+
namespace detray {
27+
28+
template <typename detector_t>
29+
class direct_navigator {
30+
31+
public:
32+
using detector_type = detector_t;
33+
using context_type = detector_type::geometry_context;
34+
using algebra_type = typename detector_type::algebra_type;
35+
using scalar_type = dscalar<algebra_type>;
36+
using intersection_type =
37+
intersection2D<typename detector_t::surface_type,
38+
typename detector_t::algebra_type, false>;
39+
40+
class state {
41+
42+
friend struct intersection_update<ray_intersector>;
43+
44+
using candidate_t = intersection_type;
45+
46+
public:
47+
using sequence_t = vecmem::device_vector<detray::geometry::barcode>;
48+
using detector_type = direct_navigator::detector_type;
49+
using nav_link_type =
50+
typename detector_type::surface_type::navigation_link;
51+
using view_type = dvector_view<detray::geometry::barcode>;
52+
53+
state() = delete;
54+
55+
DETRAY_HOST_DEVICE explicit state(const detector_t &det,
56+
const view_type &sequence)
57+
: m_detector(&det), m_sequence(sequence) {
58+
59+
m_it = m_sequence.begin();
60+
m_it_rev = m_sequence.rbegin();
61+
}
62+
63+
/// Scalar representation of the navigation state,
64+
/// @returns distance to next
65+
DETRAY_HOST_DEVICE
66+
scalar_type operator()() const {
67+
return static_cast<scalar_type>(direction()) * target().path;
68+
}
69+
70+
/// @returns a pointer of detector
71+
DETRAY_HOST_DEVICE
72+
const detector_type &detector() const { return (*m_detector); }
73+
74+
/// @returns the navigation heartbeat
75+
DETRAY_HOST_DEVICE
76+
bool is_alive() const { return m_heartbeat; }
77+
78+
/// @returns current/previous object that was reached
79+
DETRAY_HOST_DEVICE
80+
inline auto current() const -> const candidate_t & {
81+
return m_candidate_prev;
82+
}
83+
84+
/// @returns next object that we want to reach (current target) - const
85+
DETRAY_HOST_DEVICE
86+
inline auto target() const -> const candidate_t & {
87+
return m_candidate;
88+
}
89+
90+
DETRAY_HOST_DEVICE
91+
inline auto target() -> candidate_t & { return m_candidate; }
92+
93+
DETRAY_HOST_DEVICE
94+
void update_candidate(bool update_candidate_prev = true) {
95+
96+
if (update_candidate_prev) {
97+
m_candidate_prev = m_candidate;
98+
}
99+
100+
if (!is_complete()) {
101+
m_candidate.sf_desc = m_detector->surface(get_target_barcode());
102+
m_candidate.volume_link =
103+
tracking_surface{*m_detector, m_candidate.sf_desc}
104+
.volume_link();
105+
m_candidate.path = std::numeric_limits<scalar_type>::max();
106+
set_volume(m_candidate.volume_link);
107+
}
108+
}
109+
110+
/// @returns current detector surface the navigator is on
111+
/// (cannot be used when not on surface) - const
112+
DETRAY_HOST_DEVICE
113+
inline auto get_surface() const -> tracking_surface<detector_type> {
114+
assert(is_on_surface());
115+
return tracking_surface<detector_type>{*m_detector,
116+
current().sf_desc};
117+
}
118+
119+
/// @returns current navigation status - const
120+
DETRAY_HOST_DEVICE
121+
inline auto status() const -> navigation::status { return m_status; }
122+
123+
DETRAY_HOST_DEVICE
124+
inline bool is_init() {
125+
if (m_direction == navigation::direction::e_forward) {
126+
return m_it == m_sequence.begin();
127+
} else {
128+
return m_it_rev == m_sequence.rbegin();
129+
}
130+
}
131+
132+
DETRAY_HOST_DEVICE
133+
detray::geometry::barcode get_target_barcode() const {
134+
if (m_direction == navigation::direction::e_forward) {
135+
return *m_it;
136+
} else {
137+
return *m_it_rev;
138+
}
139+
}
140+
141+
DETRAY_HOST_DEVICE
142+
detray::geometry::barcode get_current_barcode() const {
143+
if (m_direction == navigation::direction::e_forward) {
144+
return *(m_it - 1);
145+
} else {
146+
return *(m_it_rev - 1);
147+
}
148+
}
149+
150+
/// Advance the iterator
151+
DETRAY_HOST_DEVICE
152+
void next() {
153+
if (m_direction == navigation::direction::e_forward) {
154+
m_it++;
155+
} else {
156+
m_it_rev++;
157+
}
158+
}
159+
160+
/// @return true if the iterator reaches the end of vector
161+
DETRAY_HOST_DEVICE
162+
bool is_complete() {
163+
if ((m_direction == navigation::direction::e_forward) &&
164+
m_it == m_sequence.end()) {
165+
return true;
166+
} else if ((m_direction == navigation::direction::e_backward) &&
167+
m_it_rev == m_sequence.rend()) {
168+
return true;
169+
}
170+
return false;
171+
}
172+
173+
/// @returns current navigation direction - const
174+
DETRAY_HOST_DEVICE
175+
inline auto direction() const -> navigation::direction {
176+
return m_direction;
177+
}
178+
179+
/// Helper method to check the track has reached a module surface
180+
DETRAY_HOST_DEVICE
181+
inline auto is_on_surface() const -> bool {
182+
return (m_status == navigation::status::e_on_module ||
183+
m_status == navigation::status::e_on_portal);
184+
}
185+
186+
/// Helper method to check if a candidate lies on a surface - const
187+
DETRAY_HOST_DEVICE inline auto is_on_surface(
188+
const intersection_type &candidate,
189+
const navigation::config &cfg) const -> bool {
190+
return (math::fabs(candidate.path) < cfg.path_tolerance);
191+
}
192+
193+
/// Helper method to check the track has encountered material
194+
DETRAY_HOST_DEVICE
195+
inline auto encountered_sf_material() const -> bool {
196+
return (is_on_surface()) && (current().sf_desc.material().id() !=
197+
detector_t::materials::id::e_none);
198+
}
199+
200+
/// Helper method to check the track has reached a sensitive surface
201+
DETRAY_HOST_DEVICE
202+
inline auto is_on_sensitive() const -> bool {
203+
return (m_status == navigation::status::e_on_module) &&
204+
(get_current_barcode().id() == surface_id::e_sensitive);
205+
}
206+
207+
DETRAY_HOST_DEVICE
208+
inline auto barcode() const -> geometry::barcode {
209+
return m_candidate.sf_desc.barcode();
210+
}
211+
212+
/// @returns current volume (index) - const
213+
DETRAY_HOST_DEVICE
214+
inline auto volume() const -> nav_link_type { return m_volume_index; }
215+
216+
/// Set start/new volume
217+
DETRAY_HOST_DEVICE
218+
inline void set_volume(dindex v) {
219+
assert(detail::is_invalid_value(static_cast<nav_link_type>(v)) ||
220+
v < detector().volumes().size());
221+
m_volume_index = static_cast<nav_link_type>(v);
222+
}
223+
224+
/// @returns current detector volume of the navigation stream
225+
DETRAY_HOST_DEVICE
226+
inline auto get_volume() const {
227+
return tracking_volume<detector_type>{*m_detector, m_volume_index};
228+
}
229+
230+
/// Set direction
231+
DETRAY_HOST_DEVICE
232+
inline void set_direction(const navigation::direction dir) {
233+
m_direction = dir;
234+
}
235+
236+
DETRAY_HOST_DEVICE
237+
inline void set_no_trust() { return; }
238+
239+
DETRAY_HOST_DEVICE
240+
inline void set_full_trust() { return; }
241+
242+
DETRAY_HOST_DEVICE
243+
inline void set_high_trust() { return; }
244+
245+
DETRAY_HOST_DEVICE
246+
inline void set_fair_trust() { return; }
247+
248+
/// Intersection candidate
249+
candidate_t m_candidate;
250+
candidate_t m_candidate_prev;
251+
252+
/// Detector pointer
253+
const detector_type *m_detector{nullptr};
254+
255+
/// Index in the detector volume container of current navigation volume
256+
nav_link_type m_volume_index{0u};
257+
258+
/// Target surfaces
259+
sequence_t m_sequence;
260+
261+
// iterator for forward direction
262+
typename sequence_t::iterator m_it;
263+
264+
// iterator for backward direction
265+
typename sequence_t::reverse_iterator m_it_rev;
266+
267+
/// The navigation direction
268+
navigation::direction m_direction{navigation::direction::e_forward};
269+
270+
/// The navigation status
271+
navigation::status m_status{navigation::status::e_unknown};
272+
273+
/// Step size when the valid intersection is not found for the target
274+
scalar_type safe_step_size = 10.f * unit<scalar_type>::mm;
275+
276+
/// Heartbeat of this navigation flow signals navigation is alive
277+
bool m_heartbeat{false};
278+
};
279+
280+
template <typename track_t>
281+
DETRAY_HOST_DEVICE inline void init(const track_t &track, state &navigation,
282+
const navigation::config &cfg,
283+
const context_type &ctx) const {
284+
if (navigation.is_complete()) {
285+
navigation.m_heartbeat = false;
286+
return;
287+
}
288+
289+
navigation.m_heartbeat = true;
290+
navigation.update_candidate(!navigation.is_init());
291+
update_intersection(track, navigation, cfg, ctx);
292+
293+
return;
294+
}
295+
296+
template <typename track_t>
297+
DETRAY_HOST_DEVICE inline bool update(const track_t &track,
298+
state &navigation,
299+
const navigation::config &cfg,
300+
const context_type &ctx = {}) const {
301+
302+
if (navigation.is_complete()) {
303+
navigation.m_heartbeat = false;
304+
return true;
305+
}
306+
307+
assert(!navigation.get_target_barcode().is_invalid());
308+
update_intersection(track, navigation, cfg, ctx);
309+
310+
if (navigation.is_on_surface(navigation.target(), cfg)) {
311+
navigation.m_status = (navigation.target().sf_desc.is_portal())
312+
? navigation::status::e_on_portal
313+
: navigation::status::e_on_module;
314+
navigation.next();
315+
navigation.update_candidate(true);
316+
assert(navigation.is_on_surface(navigation.current(), cfg));
317+
318+
if (!navigation.is_complete()) {
319+
update_intersection(track, navigation, cfg, ctx);
320+
}
321+
322+
// Return true to reset the step size
323+
return true;
324+
} else {
325+
// Otherwise the track is moving towards a surface
326+
navigation.m_status = navigation::status::e_towards_object;
327+
328+
// Return false to scale the step size with RK4
329+
return false;
330+
}
331+
}
332+
333+
template <typename track_t>
334+
DETRAY_HOST_DEVICE inline void update_intersection(
335+
const track_t &track, state &navigation, const navigation::config &cfg,
336+
const context_type &ctx = {}) const {
337+
338+
const auto &det = navigation.detector();
339+
const auto sf = tracking_surface{det, navigation.target().sf_desc};
340+
341+
const bool res =
342+
sf.template visit_mask<intersection_update<ray_intersector>>(
343+
detail::ray<algebra_type>(
344+
track.pos(),
345+
static_cast<scalar_type>(navigation.direction()) *
346+
track.dir()),
347+
navigation.target(), det.transform_store(), ctx,
348+
darray<scalar_type, 2>{cfg.min_mask_tolerance,
349+
cfg.max_mask_tolerance},
350+
static_cast<scalar_type>(cfg.mask_tolerance_scalor),
351+
static_cast<scalar_type>(cfg.overstep_tolerance));
352+
353+
// If an intersection is not found, proceed the track with safe step
354+
// size
355+
if (!res) {
356+
const auto path = navigation.target().path;
357+
navigation.update_candidate(false);
358+
navigation.target().path =
359+
math::copysign(navigation.safe_step_size, path);
360+
}
361+
}
362+
};
363+
364+
} // namespace detray

core/include/detray/navigation/intersection/ray_cylinder_intersector.hpp

+6-7
Original file line numberDiff line numberDiff line change
@@ -187,25 +187,24 @@ struct ray_intersector_impl<cylindrical2D<algebra_t>, algebra_t, do_debug> {
187187
const point3_type &ro = ray.pos();
188188
const vector3_type &rd = ray.dir();
189189

190-
is.path = path;
191-
const point3_type p3 = ro + is.path * rd;
190+
const point3_type p3 = ro + path * rd;
192191

193192
const auto loc{mask_t::to_local_frame(trf, p3)};
194193
if constexpr (intersection_type<surface_descr_t>::is_debug()) {
195194
is.local = loc;
196195
}
197196
// Tolerance: per mille of the distance
198197
is.status = mask.is_inside(
199-
loc,
200-
math::max(mask_tolerance[0],
201-
math::min(mask_tolerance[1],
202-
mask_tol_scalor * math::fabs(is.path))));
203-
is.direction = !detail::signbit(is.path);
198+
loc, math::max(mask_tolerance[0],
199+
math::min(mask_tolerance[1],
200+
mask_tol_scalor * math::fabs(path))));
201+
is.direction = !detail::signbit(path);
204202
is.volume_link = mask.volume_link();
205203
} else {
206204
is.status = false;
207205
}
208206

207+
is.path = path;
209208
return is;
210209
}
211210
};

0 commit comments

Comments
 (0)