File indexing completed on 2026-05-27 07:24:01
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011
0012 #include "detray/core/detail/container_views.hpp"
0013 #include "detray/definitions/containers.hpp"
0014 #include "detray/definitions/detail/qualifiers.hpp"
0015 #include "detray/definitions/indexing.hpp"
0016 #include "detray/definitions/navigation.hpp"
0017 #include "detray/geometry/identifier.hpp"
0018 #include "detray/geometry/tracking_surface.hpp"
0019 #include "detray/geometry/tracking_volume.hpp"
0020 #include "detray/navigation/detail/intersection_kernel.hpp"
0021 #include "detray/navigation/detail/print_state.hpp"
0022 #include "detray/navigation/intersection/intersection.hpp"
0023 #include "detray/navigation/intersection/ray_intersector.hpp"
0024 #include "detray/navigation/navigation_config.hpp"
0025 #include "detray/utils/invalid_values.hpp"
0026 #include "detray/utils/logging.hpp"
0027 #include "detray/utils/ranges.hpp"
0028
0029 namespace detray::navigation {
0030
0031
0032
0033
0034 struct void_inspector {
0035 struct void_view : public detray::detail::dbase_view {};
0036
0037 using view_type = void_view;
0038 using const_view_type = const void_view;
0039
0040 constexpr void_inspector() = default;
0041
0042 DETRAY_HOST_DEVICE
0043 constexpr explicit void_inspector(
0044 const void_view & ) { }
0045
0046 template <typename state_t>
0047 DETRAY_HOST_DEVICE constexpr void operator()(const state_t & ,
0048 const char * ) const {
0049
0050 }
0051 };
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 template <typename derived_t, typename detector_t, std::size_t k_cache_capacity,
0068 typename inspector_t, typename intersection_t>
0069 class base_state : public detray::ranges::view_interface<
0070 base_state<derived_t, detector_t, k_cache_capacity,
0071 inspector_t, intersection_t>> {
0072
0073 static_assert(k_cache_capacity >= 2u,
0074 "Navigation cache needs to have a capacity larger than 1");
0075
0076
0077
0078 DETRAY_HOST_DEVICE
0079 constexpr auto cast_impl() -> derived_t & {
0080 return static_cast<derived_t &>(*this);
0081 }
0082 DETRAY_HOST_DEVICE
0083 constexpr auto cast_impl() const -> const derived_t & {
0084 return static_cast<const derived_t &>(*this);
0085 }
0086
0087
0088 protected:
0089
0090 using algebra_t = typename detector_t::algebra_type;
0091 using scalar_t = dscalar<algebra_t>;
0092 using point3_t = dpoint3D<algebra_t>;
0093 using vector3_t = dvector3D<algebra_t>;
0094
0095
0096 using candidate_t = intersection_t;
0097 using candidate_cache_t = darray<candidate_t, k_cache_capacity>;
0098 using candidate_itr_t = typename candidate_cache_t::iterator;
0099 using candidate_const_itr_t = typename candidate_cache_t::const_iterator;
0100 using dist_t = std::int_least8_t;
0101
0102
0103 using nav_link_t = typename detector_t::surface_type::navigation_link;
0104
0105 public:
0106 using detector_type = detector_t;
0107
0108
0109 base_state() = delete;
0110
0111
0112 DETRAY_HOST_DEVICE
0113 constexpr explicit base_state(const detector_t &det) : m_detector(&det) {}
0114
0115
0116 template <concepts::device_view view_t>
0117 DETRAY_HOST_DEVICE constexpr base_state(const detector_t &det, view_t view)
0118 : m_detector(&det), m_inspector(view) {}
0119
0120
0121 DETRAY_HOST_DEVICE
0122 constexpr auto detector() const -> const detector_t & {
0123 return (*m_detector);
0124 }
0125
0126
0127 DETRAY_HOST_DEVICE
0128 constexpr auto begin() const -> candidate_const_itr_t {
0129 candidate_const_itr_t itr = m_candidates.cbegin();
0130 const dist_t idx{next_index()};
0131 detray::ranges::advance(itr,
0132 (is_on_surface() && (idx >= 1)) ? idx - 1 : idx);
0133 return itr;
0134 }
0135
0136 DETRAY_HOST_DEVICE
0137 constexpr auto cbegin() const -> candidate_const_itr_t {
0138 return std::as_const(*this).begin();
0139 }
0140
0141
0142 DETRAY_HOST_DEVICE
0143 constexpr auto end() const -> candidate_const_itr_t {
0144 candidate_const_itr_t itr = m_candidates.cbegin();
0145 detray::ranges::advance(itr, m_last + 1);
0146 return itr;
0147 }
0148
0149 DETRAY_HOST_DEVICE
0150 constexpr auto cend() const -> candidate_const_itr_t {
0151 return std::as_const(*this).end();
0152 }
0153
0154
0155 DETRAY_HOST_DEVICE
0156 constexpr auto last() const -> const candidate_t & {
0157 assert(!cache_exhausted());
0158 assert(next_index() >= 0);
0159 return m_candidates[static_cast<std::size_t>(next_index())];
0160 }
0161
0162
0163 static consteval std::size_t capacity() { return k_cache_capacity; }
0164
0165
0166 DETRAY_HOST_DEVICE
0167 constexpr auto status() const -> navigation::status { return m_status; }
0168
0169
0170 DETRAY_HOST_DEVICE
0171 constexpr bool is_alive() const {
0172 return cast_impl().status() > navigation::status::e_unknown;
0173 }
0174
0175
0176 DETRAY_HOST_DEVICE
0177 constexpr auto direction() const -> navigation::direction {
0178 return m_direction;
0179 }
0180
0181
0182 DETRAY_HOST_DEVICE
0183 constexpr void set_direction(const navigation::direction dir) {
0184 if (m_direction != dir) {
0185
0186 cast_impl().set_no_trust();
0187 DETRAY_VERBOSE_HOST_DEVICE("Re-navigate after explicit direction change");
0188
0189 m_direction = dir;
0190 }
0191 }
0192
0193
0194 DETRAY_HOST_DEVICE
0195 constexpr scalar_t external_tol() const { return m_external_mask_tol; }
0196
0197
0198 DETRAY_HOST_DEVICE
0199 constexpr void set_external_tol(const scalar_t tol) {
0200 DETRAY_VERBOSE_HOST("Setting external mask tolerance: " << tol);
0201 m_external_mask_tol = tol;
0202 }
0203
0204
0205 DETRAY_HOST_DEVICE
0206 constexpr auto trust_level() const -> navigation::trust_level {
0207 return m_trust_level;
0208 }
0209
0210
0211
0212 DETRAY_HOST_DEVICE
0213 constexpr void set_no_trust() {
0214 DETRAY_VERBOSE_HOST_DEVICE("Flagging re-navigation: \"no trust\"");
0215 m_trust_level = navigation::trust_level::e_no_trust;
0216 }
0217
0218
0219 DETRAY_HOST_DEVICE
0220 constexpr void set_high_trust() { cast_impl().set_no_trust(); }
0221
0222
0223 DETRAY_HOST_DEVICE
0224 constexpr void set_fair_trust() { cast_impl().set_no_trust(); }
0225
0226
0227
0228 DETRAY_HOST_DEVICE
0229 constexpr auto is_on_surface() const -> bool {
0230 return (m_status == navigation::status::e_on_object ||
0231 m_status == navigation::status::e_on_portal);
0232 }
0233
0234
0235 DETRAY_HOST_DEVICE
0236 constexpr auto is_on_sensitive() const -> bool {
0237 return (m_status == navigation::status::e_on_object) &&
0238 (cast_impl().geometry_identifier().id() == surface_id::e_sensitive);
0239 }
0240
0241
0242 DETRAY_HOST_DEVICE
0243 constexpr auto is_on_passive() const -> bool {
0244 return (m_status == navigation::status::e_on_object) &&
0245 (cast_impl().geometry_identifier().id() == surface_id::e_passive);
0246 }
0247
0248
0249 DETRAY_HOST_DEVICE
0250 constexpr auto is_on_portal() const -> bool {
0251 return m_status == navigation::status::e_on_portal;
0252 }
0253
0254
0255 DETRAY_HOST_DEVICE
0256 constexpr auto encountered_sf_material() const -> bool {
0257 return (cast_impl().is_on_surface()) &&
0258 (cast_impl().current().surface().has_material());
0259 }
0260
0261
0262 DETRAY_HOST_DEVICE
0263 constexpr bool finished() const {
0264
0265 return (m_status == navigation::status::e_exit);
0266 }
0267
0268
0269 DETRAY_HOST_DEVICE
0270 constexpr auto volume() const -> nav_link_t { return m_volume_index; }
0271
0272
0273 DETRAY_HOST_DEVICE
0274 constexpr void set_volume(dindex v) {
0275 assert(detray::detail::is_invalid_value(static_cast<nav_link_t>(v)) ||
0276 v < cast_impl().detector().volumes().size());
0277 if (v != m_volume_index) {
0278 DETRAY_VERBOSE_HOST_DEVICE("Setting new volume %d", v);
0279
0280 cast_impl().set_no_trust();
0281 }
0282 m_volume_index = static_cast<nav_link_t>(v);
0283 }
0284
0285
0286 DETRAY_HOST_DEVICE
0287 constexpr auto candidates() const -> const candidate_cache_t & {
0288 return m_candidates;
0289 }
0290
0291
0292 DETRAY_HOST_DEVICE
0293 constexpr auto n_candidates() const -> dindex {
0294 assert(m_last - cast_impl().next_index() + 1 >= 0);
0295 return static_cast<dindex>(m_last - cast_impl().next_index() + 1);
0296 }
0297
0298
0299 DETRAY_HOST_DEVICE
0300 constexpr bool cache_exhausted() const {
0301 return cast_impl().n_candidates() == 0u;
0302 }
0303
0304
0305 DETRAY_HOST_DEVICE
0306 constexpr auto current() const -> const candidate_t & {
0307 assert(cast_impl().is_on_surface());
0308 assert(m_next > 0);
0309 return m_candidates[static_cast<std::size_t>(m_next - 1)];
0310 }
0311
0312
0313 DETRAY_HOST_DEVICE
0314 constexpr auto target() const -> const candidate_t & {
0315 assert(m_next >= 0);
0316 return m_candidates[static_cast<std::size_t>(m_next)];
0317 }
0318
0319
0320
0321 DETRAY_HOST_DEVICE
0322 constexpr auto geometry_identifier() const -> geometry::identifier {
0323 return cast_impl().current().surface().identifier();
0324 }
0325
0326
0327 DETRAY_HOST_DEVICE
0328 constexpr bool is_edge_candidate() const {
0329 assert(cast_impl().is_on_surface());
0330 return cast_impl().current().is_edge();
0331 }
0332
0333
0334 DETRAY_HOST_DEVICE
0335 constexpr bool is_good_candidate() const {
0336 assert(cast_impl().is_on_surface());
0337 return cast_impl().current().is_inside();
0338 }
0339
0340
0341
0342 DETRAY_HOST_DEVICE
0343 constexpr bool is_probably_candidate() const {
0344 assert(cast_impl().is_on_surface());
0345 return cast_impl().current().is_probably_inside();
0346 }
0347
0348
0349
0350 DETRAY_HOST_DEVICE
0351 constexpr scalar_t operator()() const {
0352 assert(math::isfinite(cast_impl().target().path()));
0353 return static_cast<scalar_t>(cast_impl().direction()) *
0354 cast_impl().target().path();
0355 }
0356
0357
0358
0359 template <template <typename> class surface_t = tracking_surface>
0360 DETRAY_HOST_DEVICE constexpr auto current_surface() const {
0361 assert(cast_impl().is_on_surface());
0362 return surface_t<detector_t>{*m_detector, current().surface()};
0363 }
0364
0365
0366
0367 template <template <typename> class volume_t = tracking_volume>
0368 DETRAY_HOST_DEVICE constexpr auto current_volume() const {
0369 return volume_t<detector_t>{*m_detector, m_volume_index};
0370 }
0371
0372
0373
0374 template <template <typename> class surface_t = tracking_surface>
0375 DETRAY_HOST_DEVICE constexpr auto next_surface() const {
0376 return surface_t<detector_t>{*m_detector, cast_impl().target().surface()};
0377 }
0378
0379
0380
0381 template <template <typename> class volume_t = tracking_volume>
0382 DETRAY_HOST_DEVICE constexpr auto next_volume() const {
0383 return volume_t<detector_t>{*m_detector,
0384 cast_impl().target().surface().volume()};
0385 }
0386
0387
0388
0389 DETRAY_HOST_DEVICE constexpr void exit() {
0390 m_status = navigation::status::e_exit;
0391 DETRAY_VERBOSE_HOST_DEVICE("Exited");
0392 cast_impl().run_inspector({}, point3_t{0.f, 0.f, 0.f},
0393 vector3_t{0.f, 0.f, 0.f}, "Exited: ");
0394 }
0395
0396
0397
0398 DETRAY_HOST_DEVICE constexpr void pause() {
0399 DETRAY_VERBOSE_HOST_DEVICE("Paused by actor");
0400 cast_impl().run_inspector({}, point3_t{0.f, 0.f, 0.f},
0401 vector3_t{0.f, 0.f, 0.f}, "Paused by actor: ");
0402 }
0403
0404
0405
0406
0407
0408 DETRAY_HOST_DEVICE constexpr void abort(
0409 const char *custom_msg = "Navigator (unknown reason)") {
0410 m_status = navigation::status::e_abort;
0411
0412
0413
0414 struct message_wrapper {
0415 const char *const m_msg{nullptr};
0416
0417 DETRAY_HOST_DEVICE
0418 constexpr const char *operator()() const { return m_msg; }
0419 };
0420
0421 assert(custom_msg != nullptr);
0422 DETRAY_ERROR_HOST("Aborted: " << custom_msg);
0423
0424 cast_impl().run_inspector({}, point3_t{0.f, 0.f, 0.f},
0425 vector3_t{0.f, 0.f, 0.f},
0426 "Aborted: ", message_wrapper{custom_msg});
0427 }
0428
0429
0430
0431
0432
0433
0434 template <typename debug_msg_generator_t>
0435 requires(!std::same_as<char *, debug_msg_generator_t>)
0436 DETRAY_HOST_DEVICE constexpr void abort(
0437 const debug_msg_generator_t &debug_msg_generator) {
0438 m_status = navigation::status::e_abort;
0439
0440 DETRAY_ERROR_HOST("Aborted: " << debug_msg_generator());
0441
0442 cast_impl().run_inspector({}, point3_t{0.f, 0.f, 0.f},
0443 vector3_t{0.f, 0.f, 0.f},
0444 "Aborted: ", debug_msg_generator);
0445 }
0446
0447
0448 DETRAY_HOST_DEVICE
0449 constexpr const auto &inspector() const { return m_inspector; }
0450
0451
0452 DETRAY_HOST_DEVICE
0453 constexpr auto &inspector() { return m_inspector; }
0454
0455 protected:
0456
0457 DETRAY_HOST_DEVICE
0458 constexpr auto begin() -> candidate_itr_t {
0459 candidate_itr_t itr = m_candidates.begin();
0460 const dist_t idx{cast_impl().next_index()};
0461 detray::ranges::advance(
0462 itr, (cast_impl().is_on_surface() && (idx >= 1)) ? idx - 1 : idx);
0463 return itr;
0464 }
0465
0466
0467 DETRAY_HOST_DEVICE
0468 constexpr auto end() -> candidate_itr_t {
0469 candidate_itr_t itr = m_candidates.begin();
0470 detray::ranges::advance(itr, m_last + 1);
0471 return itr;
0472 }
0473
0474
0475 DETRAY_HOST_DEVICE
0476 constexpr auto last() -> candidate_t & {
0477 assert(static_cast<std::size_t>(m_last) < m_candidates.size());
0478 return m_candidates[static_cast<std::size_t>(m_last)];
0479 }
0480
0481
0482 DETRAY_HOST_DEVICE
0483 constexpr void set_next(candidate_const_itr_t new_next) {
0484 const auto new_idx{
0485 detray::ranges::distance(m_candidates.cbegin(), new_next)};
0486 cast_impl().next_index(static_cast<dist_t>(new_idx));
0487 assert(cast_impl().next_index() <= m_last + 1);
0488 }
0489
0490
0491 DETRAY_HOST_DEVICE
0492 constexpr void set_last(candidate_const_itr_t new_last) {
0493 const auto new_idx{
0494 detray::ranges::distance(m_candidates.cbegin(), new_last) - 1};
0495 last_index(static_cast<dist_t>(new_idx));
0496 assert(m_last < static_cast<dist_t>(k_cache_capacity));
0497 }
0498
0499
0500 DETRAY_HOST_DEVICE
0501 constexpr dist_t next_index() const { return m_next; }
0502
0503
0504 DETRAY_HOST_DEVICE
0505 constexpr dist_t last_index() const { return m_last; }
0506
0507
0508 DETRAY_HOST_DEVICE
0509 constexpr void next_index(dist_t pos) {
0510 m_next = pos;
0511 assert(m_next >= 0);
0512 assert(m_next < static_cast<dist_t>(k_cache_capacity) + 1);
0513 }
0514
0515
0516 DETRAY_HOST_DEVICE
0517 constexpr void last_index(dist_t pos) {
0518 m_last = pos;
0519 assert(m_last >= -1);
0520 assert(m_last < static_cast<dist_t>(k_cache_capacity));
0521 }
0522
0523
0524 DETRAY_HOST_DEVICE
0525 constexpr auto advance() -> void {
0526 ++m_next;
0527 assert(m_next < static_cast<dist_t>(k_cache_capacity) + 1);
0528 assert(cast_impl().next_index() <= cast_impl().last_index() + 1);
0529 }
0530
0531
0532 DETRAY_HOST_DEVICE
0533 constexpr auto candidates() -> candidate_cache_t & { return m_candidates; }
0534
0535
0536 DETRAY_HOST_DEVICE
0537 constexpr auto current() -> candidate_t & {
0538 assert(cast_impl().is_on_surface());
0539 assert(m_next > 0);
0540 return m_candidates[static_cast<std::size_t>(m_next - 1)];
0541 }
0542
0543
0544 DETRAY_HOST_DEVICE
0545 constexpr auto target() -> candidate_t & {
0546 assert(static_cast<std::size_t>(m_next) < m_candidates.size());
0547 return m_candidates[static_cast<std::size_t>(m_next)];
0548 }
0549
0550
0551 DETRAY_HOST_DEVICE
0552 constexpr void status(navigation::status s) {
0553 DETRAY_DEBUG_HOST("Setting nav. status: " << s);
0554 m_status = s;
0555 }
0556
0557
0558 DETRAY_HOST_DEVICE
0559 constexpr void trust_level(navigation::trust_level t) {
0560 DETRAY_DEBUG_HOST("Setting trust level: " << t);
0561 m_trust_level = t;
0562 }
0563
0564
0565 DETRAY_HOST_DEVICE
0566 constexpr void clear_cache() {
0567
0568 for (std::size_t i = 0u; i < k_cache_capacity; ++i) {
0569 m_candidates[i].set_path(std::numeric_limits<scalar_t>::max());
0570 }
0571 m_next = 0;
0572 m_last = -1;
0573 }
0574
0575
0576 DETRAY_HOST_DEVICE constexpr void run_inspector(
0577 [[maybe_unused]] const navigation::config &cfg,
0578 [[maybe_unused]] const point3_t &track_pos,
0579 [[maybe_unused]] const vector3_t &track_dir,
0580 [[maybe_unused]] const char *message) {
0581 [[maybe_unused]] auto derived = static_cast<const derived_t &>(*this);
0582
0583 if constexpr (!std::is_same_v<inspector_t, navigation::void_inspector>) {
0584 cast_impl().inspector()(derived, cfg, track_pos, track_dir, message);
0585 }
0586
0587 DETRAY_DEBUG_HOST("" << message << "\n"
0588 << detray::navigation::print_state(derived)
0589 << detray::navigation::print_candidates(
0590 derived, cfg, track_pos, track_dir));
0591 }
0592
0593
0594 template <typename debug_msg_generator_t>
0595 DETRAY_HOST_DEVICE constexpr void run_inspector(
0596 [[maybe_unused]] const navigation::config &cfg,
0597 [[maybe_unused]] const point3_t &track_pos,
0598 [[maybe_unused]] const vector3_t &track_dir,
0599 [[maybe_unused]] const char *message,
0600 [[maybe_unused]] const debug_msg_generator_t &msg_gen) {
0601 [[maybe_unused]] auto derived = static_cast<const derived_t &>(*this);
0602
0603 if constexpr (!std::is_same_v<inspector_t, navigation::void_inspector>) {
0604 cast_impl().inspector()(derived, cfg, track_pos, track_dir, message,
0605 msg_gen);
0606 }
0607
0608 DETRAY_DEBUG_HOST("" << message << msg_gen() << "\n"
0609 << detray::navigation::print_state(derived)
0610 << detray::navigation::print_candidates(
0611 derived, cfg, track_pos, track_dir));
0612 }
0613
0614 private:
0615
0616 DETRAY_HOST
0617 friend std::ostream &operator<<(std::ostream &os, const derived_t &s) {
0618 os << detray::navigation::print_state(s)
0619 << detray::navigation::print_candidates(s, {}, point3_t{0.f, 0.f, 0.f},
0620 vector3_t{0.f, 0.f, 0.f});
0621 return os;
0622 }
0623
0624
0625 candidate_cache_t m_candidates;
0626
0627
0628 const detector_t *m_detector{nullptr};
0629
0630
0631 navigation::status m_status{navigation::status::e_unknown};
0632
0633
0634 navigation::direction m_direction{navigation::direction::e_forward};
0635
0636
0637
0638 navigation::trust_level m_trust_level{navigation::trust_level::e_no_trust};
0639
0640
0641 scalar_t m_external_mask_tol{0.f * unit<scalar_t>::mm};
0642
0643
0644
0645 dist_t m_next{0};
0646
0647
0648
0649 dist_t m_last{-1};
0650
0651
0652 nav_link_t m_volume_index{0u};
0653
0654
0655 DETRAY_NO_UNIQUE_ADDRESS inspector_t m_inspector;
0656 };
0657
0658 }