Skip to content

Commit 5eac5c8

Browse files
authored
Fix navigation print inspector (#968)
Fix a few bugs in the print inspector and make navigation state printing available outside the inspector. This way it can be printed with std::cout during host side debugging
1 parent 29cbe32 commit 5eac5c8

File tree

3 files changed

+244
-106
lines changed

3 files changed

+244
-106
lines changed
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
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/definitions/algebra.hpp"
12+
#include "detray/definitions/detail/qualifiers.hpp"
13+
#include "detray/definitions/math.hpp"
14+
#include "detray/definitions/units.hpp"
15+
#include "detray/geometry/surface.hpp"
16+
#include "detray/navigation/detail/print_state.hpp"
17+
#include "detray/navigation/navigation_config.hpp"
18+
19+
// System include(s)
20+
#include <iomanip>
21+
#include <sstream>
22+
#include <string>
23+
24+
namespace detray::navigation {
25+
26+
/// Print basic information about the state of a navigation stream @param state
27+
template <typename state_type>
28+
DETRAY_HOST inline std::string print_state(const state_type &state) {
29+
30+
// Gathers navigation information accross navigator update calls
31+
std::stringstream debug_stream{};
32+
// Column width in output
33+
constexpr int cw{20};
34+
35+
debug_stream << std::left << std::setw(cw) << "Volume:" << state.volume()
36+
<< std::endl;
37+
38+
// Navigation direction
39+
debug_stream << std::setw(cw) << "direction:";
40+
switch (state.direction()) {
41+
using enum direction;
42+
case e_backward:
43+
debug_stream << "backward";
44+
break;
45+
case e_forward:
46+
debug_stream << "forward";
47+
break;
48+
default:
49+
break;
50+
}
51+
debug_stream << std::endl;
52+
53+
// Navigation status
54+
debug_stream << std::setw(cw) << "status:";
55+
switch (state.status()) {
56+
using enum status;
57+
case e_abort:
58+
debug_stream << "abort";
59+
break;
60+
case e_on_target:
61+
debug_stream << "on_target";
62+
break;
63+
case e_unknown:
64+
debug_stream << "unknowm";
65+
break;
66+
case e_towards_object:
67+
debug_stream << "towards_object";
68+
break;
69+
case e_on_module:
70+
debug_stream << "on_object";
71+
break;
72+
case e_on_portal:
73+
debug_stream << "on_portal";
74+
break;
75+
default:
76+
break;
77+
}
78+
debug_stream << std::endl;
79+
80+
// Navigation trust level
81+
debug_stream << std::setw(cw) << "trust:";
82+
switch (state.trust_level()) {
83+
using enum trust_level;
84+
case e_no_trust:
85+
debug_stream << "no_trust";
86+
break;
87+
case e_fair:
88+
debug_stream << "fair_trust";
89+
break;
90+
case e_high:
91+
debug_stream << "high_trust";
92+
break;
93+
case e_full:
94+
debug_stream << "full_trust";
95+
break;
96+
default:
97+
break;
98+
}
99+
debug_stream << std::endl;
100+
101+
// Number of reachable candidates
102+
debug_stream << std::setw(cw) << "No. reachable:" << state.n_candidates()
103+
<< std::endl;
104+
105+
// Current surface
106+
debug_stream << std::setw(cw) << "current object:";
107+
if (state.is_on_surface()) {
108+
// If "exit" is called twice, the state has been cleared
109+
debug_stream << state.barcode() << std::endl;
110+
} else if (state.status() == status::e_on_target) {
111+
debug_stream << "exited" << std::endl;
112+
} else {
113+
debug_stream << "undefined" << std::endl;
114+
}
115+
116+
// Next surface
117+
if (!state.candidates().empty()) {
118+
debug_stream << std::setw(cw) << "next object:";
119+
if (state.n_candidates() == 0u) {
120+
debug_stream << "exhausted" << std::endl;
121+
} else {
122+
debug_stream << state.next_surface().barcode() << std::endl;
123+
}
124+
}
125+
126+
// Distance to next
127+
debug_stream << std::setw(cw) << "distance to next:";
128+
if (!state.is_exhausted() && state.is_on_surface()) {
129+
debug_stream << "on obj (within tol)" << std::endl;
130+
} else if (state.is_exhausted()) {
131+
debug_stream << "no target" << std::endl;
132+
} else {
133+
debug_stream << state() << std::endl;
134+
}
135+
136+
return debug_stream.str();
137+
}
138+
139+
/// Print candidate and cofiguration information of a navigation state
140+
///
141+
/// @param state the state object of the navigation stream
142+
/// @param cfg the navigation confuration object
143+
/// @param track_pos the current track position
144+
/// @param track_dir the current track direction
145+
template <typename state_type, concepts::point3D point3_t,
146+
concepts::vector3D vector3_t>
147+
DETRAY_HOST inline std::string print_candidates(const state_type &state,
148+
const navigation::config &cfg,
149+
const point3_t &track_pos,
150+
const vector3_t &track_dir) {
151+
152+
using detector_t = typename state_type::detector_type;
153+
using geo_ctx_t = typename detector_t::geometry_context;
154+
using scalar_t = typename detector_t::scalar_type;
155+
156+
// Gathers navigation information accross navigator update calls
157+
std::stringstream debug_stream{};
158+
// Column width in output
159+
constexpr int cw{20};
160+
161+
debug_stream << std::left << std::setw(cw) << "Overstep tol.:"
162+
<< cfg.overstep_tolerance / detray::unit<scalar_t>::mm << " mm"
163+
<< std::endl;
164+
165+
debug_stream << std::setw(cw) << "Track:"
166+
<< "pos: [r = " << vector::perp(track_pos)
167+
<< ", z = " << track_pos[2] << "]," << std::endl;
168+
169+
debug_stream << std::setw(cw) << " "
170+
<< "dir: [" << track_dir[0] << ", " << track_dir[1] << ", "
171+
<< track_dir[2] << "]" << std::endl;
172+
173+
debug_stream << "Surface candidates: " << std::endl;
174+
175+
for (const auto &sf_cand : state) {
176+
177+
debug_stream << std::left << std::setw(6) << "-> " << sf_cand;
178+
179+
assert(!sf_cand.sf_desc.barcode().is_invalid());
180+
181+
// Use additional debug information that was gathered on the cand.
182+
if constexpr (state_type::value_type::is_debug()) {
183+
const auto &local = sf_cand.local;
184+
if (!sf_cand.sf_desc.barcode().is_invalid()) {
185+
point3_t pos =
186+
geometry::surface{state.detector(), sf_cand.sf_desc}
187+
.local_to_global(geo_ctx_t{}, local, track_dir);
188+
debug_stream << " glob: [r = " << vector::perp(pos)
189+
<< ", z = " << pos[2] << "]" << std::endl;
190+
}
191+
}
192+
}
193+
194+
return debug_stream.str();
195+
}
196+
197+
} // namespace detray::navigation

core/include/detray/navigation/navigator.hpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,22 +210,26 @@ class navigator {
210210
return static_cast<dindex>(m_last - m_next + 1);
211211
}
212212

213-
/// @returns current/previous object that was reached
213+
/// @returns the current/previous object, if available in the cache.
214214
DETRAY_HOST_DEVICE
215215
inline auto current() const -> const candidate_t & {
216-
assert(m_next > 0);
217-
return m_candidates[static_cast<std::size_t>(m_next - 1)];
216+
assert(is_on_surface());
217+
const auto curr_idx{
218+
static_cast<std::size_t>(m_next >= 1 ? m_next - 1 : 0)};
219+
return m_candidates[curr_idx];
218220
}
219221

220-
/// @returns next object that we want to reach (current target) - const
222+
/// @returns next object that we want to reach (target) - const
221223
DETRAY_HOST_DEVICE
222224
inline auto target() const -> const candidate_t & {
225+
assert(!is_exhausted());
223226
return m_candidates[static_cast<std::size_t>(m_next)];
224227
}
225228

226229
/// @returns last valid candidate (by position in the cache) - const
227230
DETRAY_HOST_DEVICE
228231
inline auto last() const -> const candidate_t & {
232+
assert(!is_exhausted());
229233
return m_candidates[static_cast<std::size_t>(m_last)];
230234
}
231235

@@ -885,13 +889,13 @@ class navigator {
885889
// portal, in which case the navigation needs to be re-initialized
886890
if (!navigation.is_exhausted() &&
887891
navigation.is_on_surface(navigation.target(), cfg)) {
892+
navigation.m_status = (navigation.target().sf_desc.is_portal())
893+
? navigation::status::e_on_portal
894+
: navigation::status::e_on_module;
888895
// Set the next object that we want to reach (this function is only
889896
// called once the cache has been updated to a full trust state).
890897
// Might lead to exhausted cache.
891898
navigation.next();
892-
navigation.m_status = (navigation.current().sf_desc.is_portal())
893-
? navigation::status::e_on_portal
894-
: navigation::status::e_on_module;
895899
} else {
896900
// Otherwise the track is moving towards a surface
897901
navigation.m_status = navigation::status::e_towards_object;

0 commit comments

Comments
 (0)