Skip to content

Commit 737247b

Browse files
authored
feat: abort messages (#979)
Allow to pass additional messages to the navigator abort function that contain the reason for the failure. This will make it easier to debug, because it can be seen right away from where abort was called and why. The reason for the error is also preserved in the print inspector, which makes it easier to print it to the user in tests outside the debug file.
1 parent e8d0998 commit 737247b

File tree

5 files changed

+120
-28
lines changed

5 files changed

+120
-28
lines changed

core/include/detray/navigation/direct_navigator.hpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,18 @@ class direct_navigator {
222222
}
223223

224224
DETRAY_HOST_DEVICE
225-
inline auto abort() -> bool {
225+
inline auto abort(const char * = nullptr) -> bool {
226226
m_status = navigation::status::e_abort;
227227
m_heartbeat = false;
228228
return m_heartbeat;
229229
}
230230

231+
template <typename debug_msg_generator_t>
232+
DETRAY_HOST_DEVICE inline auto abort(const debug_msg_generator_t &)
233+
-> bool {
234+
return abort();
235+
}
236+
231237
DETRAY_HOST_DEVICE
232238
inline auto exit() -> bool {
233239
m_status = navigation::status::e_on_target;

core/include/detray/navigation/navigator.hpp

+56-3
Original file line numberDiff line numberDiff line change
@@ -394,15 +394,54 @@ class navigator {
394394
/// Navigation state that cannot be recovered from. Leave the other
395395
/// data for inspection.
396396
///
397+
/// @param custom_msg additional information on the reason for the error
398+
///
397399
/// @return navigation heartbeat (dead)
398400
DETRAY_HOST_DEVICE
399-
inline auto abort() -> bool {
401+
inline auto abort(const char *custom_msg = "Navigator (unkown reason)")
402+
-> bool {
400403
m_status = navigation::status::e_abort;
401404
m_heartbeat = false;
402405
// Don't do anything if aborted
403406
m_trust_level = navigation::trust_level::e_full;
407+
408+
/// Wrapper around the custom message that a print inspector can
409+
/// understand
410+
struct message_wrapper {
411+
const char *const m_msg{nullptr};
412+
413+
DETRAY_HOST_DEVICE
414+
constexpr const char *operator()() const { return m_msg; }
415+
};
416+
417+
assert(custom_msg != nullptr);
418+
run_inspector({}, point3_type{0.f, 0.f, 0.f},
419+
vector3_type{0.f, 0.f, 0.f},
420+
"Aborted: ", message_wrapper{custom_msg});
421+
422+
return m_heartbeat;
423+
}
424+
425+
/// Navigation state that cannot be recovered from. Leave the other
426+
/// data for inspection.
427+
///
428+
/// @param debug_msg_generator functor that returns additional
429+
/// information on the reason for the error
430+
///
431+
/// @return navigation heartbeat (dead)
432+
template <typename debug_msg_generator_t>
433+
requires(!std::same_as<char *, debug_msg_generator_t>)
434+
DETRAY_HOST_DEVICE
435+
inline auto abort(const debug_msg_generator_t &debug_msg_generator)
436+
-> bool {
437+
m_status = navigation::status::e_abort;
438+
m_heartbeat = false;
439+
m_trust_level = navigation::trust_level::e_full;
440+
404441
run_inspector({}, point3_type{0.f, 0.f, 0.f},
405-
vector3_type{0.f, 0.f, 0.f}, "Aborted: ");
442+
vector3_type{0.f, 0.f, 0.f},
443+
"Aborted: ", debug_msg_generator);
444+
406445
return m_heartbeat;
407446
}
408447

@@ -579,6 +618,20 @@ class navigator {
579618
}
580619
}
581620

621+
/// Call the navigation inspector
622+
template <typename debug_msg_generator_t>
623+
DETRAY_HOST_DEVICE inline void run_inspector(
624+
[[maybe_unused]] const navigation::config &cfg,
625+
[[maybe_unused]] const point3_type &track_pos,
626+
[[maybe_unused]] const vector3_type &track_dir,
627+
[[maybe_unused]] const char *message,
628+
[[maybe_unused]] const debug_msg_generator_t &msg_gen) {
629+
if constexpr (!std::is_same_v<inspector_t,
630+
navigation::void_inspector>) {
631+
m_inspector(*this, cfg, track_pos, track_dir, message, msg_gen);
632+
}
633+
}
634+
582635
/// Our cache of candidates (intersections with any kind of surface)
583636
candidate_cache_t m_candidates;
584637

@@ -788,7 +841,7 @@ class navigator {
788841
// Unrecoverable
789842
if (navigation.trust_level() != navigation::trust_level::e_full ||
790843
navigation.is_exhausted()) {
791-
navigation.abort();
844+
navigation.abort("Navigator: No reachable surfaces");
792845
}
793846

794847
return is_init;

core/include/detray/propagator/actors/aborters.hpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ struct pathlimit_aborter : actor {
5858
// Check the path limit
5959
if (step_limit <= 0.f) {
6060
// Stop navigation
61-
prop_state._heartbeat &= nav_state.abort();
61+
prop_state._heartbeat &=
62+
nav_state.abort("Aborter: Maximal path length reached");
6263
}
6364

6465
// Don't go over the path limit in the next step
@@ -123,7 +124,8 @@ struct momentum_aborter : actor {
123124

124125
if (mag <= abrt_state.p_limit()) {
125126
// Stop navigation
126-
prop_state._heartbeat &= nav_state.abort();
127+
prop_state._heartbeat &=
128+
nav_state.abort("Aborter: Minimum momentum reached");
127129
}
128130
}
129131
};
@@ -153,7 +155,8 @@ struct target_aborter : actor {
153155
if (navigation.is_on_surface() &&
154156
(navigation.barcode() == abrt_state._target_surface) &&
155157
(stepping.path_length() > 0.f)) {
156-
prop_state._heartbeat &= navigation.abort();
158+
prop_state._heartbeat &=
159+
navigation.abort("Aborter: Reached target surface");
157160
}
158161
}
159162
};

tests/include/detray/test/utils/inspectors.hpp

+48-18
Original file line numberDiff line numberDiff line change
@@ -56,32 +56,38 @@ struct aggregate_inspector {
5656

5757
/// Inspector interface
5858
template <unsigned int current_id = 0, typename state_type,
59-
concepts::point3D point3_t, concepts::vector3D vector3_t>
59+
concepts::point3D point3_t, concepts::vector3D vector3_t,
60+
typename... Args>
6061
DETRAY_HOST_DEVICE auto operator()(state_type &state,
6162
const navigation::config &cfg,
6263
const point3_t &pos,
6364
const vector3_t &dir,
64-
const char *message) {
65+
const char *message, Args &&... args) {
6566
// Call inspector
66-
std::get<current_id>(_inspectors)(state, cfg, pos, dir, message);
67+
std::get<current_id>(_inspectors)(state, cfg, pos, dir, message,
68+
std::forward<Args>(args)...);
6769

6870
// Next inspector
6971
if constexpr (current_id <
7072
std::tuple_size<inspector_tuple_t>::value - 1) {
71-
return operator()<current_id + 1>(state, cfg, pos, dir, message);
73+
return operator()<current_id + 1>(state, cfg, pos, dir, message,
74+
std::forward<Args>(args)...);
7275
}
7376
}
7477

7578
/// Inspector interface
76-
template <unsigned int current_id = 0, typename state_type>
77-
DETRAY_HOST_DEVICE auto operator()(state_type &state, const char *message) {
79+
template <unsigned int current_id = 0, typename state_type,
80+
typename... Args>
81+
DETRAY_HOST_DEVICE auto operator()(state_type &state, const char *message,
82+
Args &&... args) {
7883
// Call inspector
7984
std::get<current_id>(_inspectors)(state, message);
8085

8186
// Next inspector
8287
if constexpr (current_id <
8388
std::tuple_size<inspector_tuple_t>::value - 1) {
84-
return operator()<current_id + 1>(state, message);
89+
return operator()<current_id + 1>(state, message,
90+
std::forward<Args>(args)...);
8591
}
8692
}
8793

@@ -191,12 +197,12 @@ struct object_tracer {
191197

192198
/// Inspector interface
193199
template <typename state_type, concepts::point3D point3_t,
194-
concepts::vector3D vector3_t>
200+
concepts::vector3D vector3_t, typename... Args>
195201
DETRAY_HOST_DEVICE auto operator()(const state_type &state,
196202
const navigation::config &,
197203
const point3_t &pos,
198204
const vector3_t &dir,
199-
const char * /*message*/) {
205+
const char * /*message*/, Args &&...) {
200206

201207
// Record the candidate of an encountered object
202208
if ((is_status(state.status(), navigation_status) || ...)) {
@@ -245,6 +251,8 @@ struct print_inspector {
245251
using view_type = dvector_view<char>;
246252
using const_view_type = dvector_view<const char>;
247253

254+
struct void_generator {};
255+
248256
/// Default constructor
249257
print_inspector() = default;
250258

@@ -272,17 +280,24 @@ struct print_inspector {
272280
/// Move assignemten operator
273281
print_inspector &operator=(print_inspector &&other) = default;
274282

275-
/// Gathers navigation information accross navigator update calls
276-
std::stringstream debug_stream{};
277-
278283
/// Inspector interface. Gathers detailed information during navigation
279284
template <typename state_type, concepts::point3D point3_t,
280-
concepts::vector3D vector3_t>
285+
concepts::vector3D vector3_t,
286+
typename message_generator_t = void_generator>
281287
auto operator()(const state_type &state, const navigation::config &cfg,
282288
const point3_t &track_pos, const vector3_t &track_dir,
283-
const char *message) {
289+
const char *message,
290+
const message_generator_t &msg_gen = {}) {
284291
std::string msg(message);
285-
debug_stream << msg << std::endl;
292+
debug_stream << msg;
293+
if constexpr (!std::same_as<message_generator_t, void_generator>) {
294+
debug_stream << msg_gen();
295+
296+
if (state.status() == navigation::status::e_abort) {
297+
fata_error_msg = msg_gen();
298+
}
299+
}
300+
debug_stream << std::endl;
286301
debug_stream << "----------------------------------------" << std::endl;
287302

288303
debug_stream << navigation::print_state(state);
@@ -293,10 +308,20 @@ struct print_inspector {
293308
}
294309

295310
/// Inspector interface. Print basic state information
296-
template <typename state_type>
297-
auto operator()(const state_type &state, const char *message) {
311+
template <typename state_type,
312+
typename message_generator_t = void_generator>
313+
auto operator()(const state_type &state, const char *message,
314+
const message_generator_t &msg_gen = {}) {
298315
std::string msg(message);
299-
debug_stream << msg << std::endl;
316+
debug_stream << msg;
317+
if constexpr (!std::same_as<message_generator_t, void_generator>) {
318+
debug_stream << msg_gen();
319+
320+
if (state.status() == navigation::status::e_abort) {
321+
fata_error_msg = msg_gen();
322+
}
323+
}
324+
debug_stream << std::endl;
300325
debug_stream << "----------------------------------------" << std::endl;
301326

302327
debug_stream << navigation::print_state(state);
@@ -306,6 +331,11 @@ struct print_inspector {
306331

307332
/// @returns a string representation of the gathered information
308333
std::string to_string() const { return debug_stream.str(); }
334+
335+
/// Gathers navigation information accross navigator update calls
336+
std::stringstream debug_stream{};
337+
/// Special message that is collected if the navigator hits a fatal error
338+
std::string fata_error_msg{""};
309339
};
310340

311341
} // namespace navigation

tests/include/detray/test/validation/navigation_validation_utils.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -1074,10 +1074,10 @@ auto compare_to_navigation(
10741074

10751075
// Fatal propagation error: Data unreliable
10761076
if (!success) {
1077-
std::cout << "ERROR: Propagation failure" << std::endl;
1077+
std::cout << "ERROR: Propagation aborted! "
1078+
<< nav_printer.fata_error_msg << std::endl;
10781079

1079-
*debug_file << "ERROR: Propagation failure:\n"
1080-
<< "TEST TRACK " << i;
1080+
*debug_file << "ERROR: Propagation aborted:" << std::endl;
10811081

10821082
n_fatal_error++;
10831083
}

0 commit comments

Comments
 (0)