File indexing completed on 2026-07-26 08:22:01
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010
0011 #include "traccc/definitions/primitives.hpp"
0012 #include "traccc/definitions/qualifiers.hpp"
0013
0014
0015 #include <detray/utils/concepts.hpp>
0016
0017
0018 #include <vecmem/containers/data/vector_view.hpp>
0019 #include <vecmem/containers/device_vector.hpp>
0020 #include <vecmem/memory/memory_resource.hpp>
0021
0022
0023 #include <algorithm>
0024 #include <cstddef>
0025 #include <type_traits>
0026
0027 namespace traccc {
0028
0029 namespace axis2 {
0030
0031
0032
0033
0034
0035
0036 template <template <typename, std::size_t> class array_t = std::array,
0037 template <typename...> class vector_t = vecmem::vector>
0038 struct regular {
0039 unsigned int n_bins;
0040 scalar min;
0041 scalar max;
0042
0043 static constexpr unsigned int axis_identifier = 0u;
0044
0045
0046 DETRAY_HOST_DEVICE
0047 regular()
0048 : n_bins(std::numeric_limits<unsigned int>::max()),
0049 min(static_cast<scalar>(0.)),
0050 max(static_cast<scalar>(n_bins)) {}
0051
0052
0053 DETRAY_HOST
0054 explicit regular(vecmem::memory_resource & )
0055 : n_bins(std::numeric_limits<unsigned int>::max()),
0056 min(static_cast<scalar>(0.)),
0057 max(static_cast<scalar>(n_bins)) {}
0058
0059
0060 DETRAY_HOST
0061 regular(unsigned int axis_bins, scalar axis_min, scalar axis_max,
0062 vecmem::memory_resource & )
0063 : n_bins(axis_bins), min(axis_min), max(axis_max) {}
0064
0065
0066 DETRAY_HOST
0067 regular(const regular &axis, vecmem::memory_resource & )
0068 : n_bins(axis.n_bins), min(axis.min), max(axis.max) {}
0069
0070
0071 template <typename axis_data_t>
0072 requires(!std::is_same_v<regular, axis_data_t>)
0073 DETRAY_HOST_DEVICE explicit regular(const axis_data_t &axis_data)
0074 : n_bins(axis_data.n_bins), min(axis_data.min), max(axis_data.max) {}
0075
0076
0077 DETRAY_HOST_DEVICE
0078 unsigned int bins() const { return n_bins; }
0079
0080
0081
0082
0083
0084
0085
0086 DETRAY_HOST_DEVICE
0087 unsigned int bin(scalar v) const {
0088 auto ibin =
0089 static_cast<int>((v - min) / (max - min) * static_cast<scalar>(n_bins));
0090 if (ibin >= 0 && ibin < static_cast<int>(n_bins)) {
0091 return static_cast<unsigned int>(ibin);
0092 } else {
0093 if (ibin < 0) {
0094 return 0;
0095 } else {
0096 return n_bins - 1u;
0097 }
0098 }
0099 }
0100
0101
0102
0103
0104
0105
0106
0107
0108 DETRAY_HOST_DEVICE
0109 std::array<unsigned int, 2> range(scalar v,
0110 const array_t<unsigned int, 2> &nhood = {
0111 0u, 0u}) const {
0112 auto ibin =
0113 static_cast<int>((v - min) / (max - min) * static_cast<scalar>(n_bins));
0114 int ibinmin = ibin - static_cast<int>(nhood[0]);
0115 int ibinmax = ibin + static_cast<int>(nhood[1]);
0116 unsigned int min_bin =
0117 (ibinmin >= 0) ? static_cast<unsigned int>(ibinmin) : 0u;
0118 unsigned int max_bin = (ibinmax < static_cast<int>(n_bins))
0119 ? static_cast<unsigned int>(ibinmax)
0120 : n_bins - 1u;
0121 return {min_bin, max_bin};
0122 }
0123
0124
0125
0126
0127
0128
0129
0130
0131 DETRAY_HOST_DEVICE
0132 std::array<unsigned int, 2> range(scalar v,
0133 const array_t<scalar, 2> &nhood) const {
0134 auto nbin = static_cast<int>((v - nhood[0] - min) / (max - min) *
0135 static_cast<scalar>(n_bins));
0136 auto pbin = static_cast<int>((v + nhood[1] - min) / (max - min) *
0137 static_cast<scalar>(n_bins));
0138 unsigned int min_bin = (nbin >= 0) ? static_cast<unsigned int>(nbin) : 0u;
0139 unsigned int max_bin = (pbin < static_cast<int>(n_bins))
0140 ? static_cast<unsigned int>(pbin)
0141 : n_bins - 1;
0142 return {min_bin, max_bin};
0143 }
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155 template <typename neighbor_t>
0156 DETRAY_HOST_DEVICE vecmem::vector<unsigned int> zone_t(
0157 scalar v, const array_t<neighbor_t, 2> &nhood) const {
0158 std::array<unsigned int, 2> nh_range = range(v, nhood);
0159 vecmem::vector<unsigned int> sequence(
0160 static_cast<vecmem::vector<unsigned int>::size_type>(nh_range[1] -
0161 nh_range[0] + 1u),
0162 nh_range[0]);
0163 unsigned int m = 0u;
0164 std::ranges::for_each(sequence, [&](auto &n) { n += m++; });
0165 return sequence;
0166 }
0167
0168
0169
0170
0171
0172
0173
0174
0175 DETRAY_HOST_DEVICE
0176 vecmem::vector<unsigned int> zone(
0177 scalar v, const array_t<unsigned int, 2> &nhood) const {
0178 return zone_t<unsigned int>(v, nhood);
0179 }
0180
0181
0182
0183
0184
0185
0186
0187
0188 DETRAY_HOST_DEVICE
0189 vecmem::vector<unsigned int> zone(scalar v,
0190 const array_t<scalar, 2> &nhood) const {
0191 return zone_t<scalar>(v, nhood);
0192 }
0193
0194
0195 DETRAY_HOST_DEVICE
0196 array_t<scalar, 2> borders(unsigned int ibin) const {
0197 scalar step = (max - min) / static_cast<scalar>(n_bins);
0198 return {min + static_cast<scalar>(ibin) * step,
0199 min + static_cast<scalar>(ibin + 1u) * step};
0200 }
0201
0202
0203 DETRAY_HOST_DEVICE
0204 vector_t<scalar> all_borders() const {
0205 vector_t<scalar> borders;
0206 borders.reserve(n_bins + 1u);
0207 scalar step = (max - min) / static_cast<scalar>(n_bins);
0208 for (unsigned int ib = 0u; ib < n_bins + 1u; ++ib) {
0209 borders.push_back(min + static_cast<scalar>(ib) * step);
0210 }
0211 return borders;
0212 }
0213
0214
0215 DETRAY_HOST_DEVICE
0216 array_t<scalar, 2> span() const { return {min, max}; }
0217 };
0218
0219
0220
0221
0222
0223 template <template <typename, std::size_t> class array_t = std::array,
0224 template <typename...> class vector_t = vecmem::vector>
0225 struct circular {
0226 unsigned int n_bins;
0227 scalar min;
0228 scalar max;
0229
0230 static constexpr unsigned int axis_identifier = 1u;
0231
0232
0233 DETRAY_HOST_DEVICE
0234 circular()
0235 : n_bins(std::numeric_limits<unsigned int>::max()),
0236 min(static_cast<scalar>(0.)),
0237 max(static_cast<scalar>(n_bins)) {}
0238
0239
0240 DETRAY_HOST
0241 explicit circular(vecmem::memory_resource & )
0242 : n_bins(std::numeric_limits<unsigned int>::max()),
0243 min(static_cast<scalar>(0.)),
0244 max(static_cast<scalar>(n_bins)) {}
0245
0246
0247 DETRAY_HOST
0248 circular(unsigned int axis_bins, scalar axis_min, scalar axis_max,
0249 vecmem::memory_resource & )
0250 : n_bins(axis_bins), min(axis_min), max(axis_max) {}
0251
0252
0253 DETRAY_HOST
0254 circular(const circular &axis, vecmem::memory_resource & )
0255 : n_bins(axis.n_bins), min(axis.min), max(axis.max) {}
0256
0257
0258 template <typename axis_data_t>
0259 requires(!std::is_same_v<circular, axis_data_t>)
0260 DETRAY_HOST_DEVICE explicit circular(const axis_data_t &axis_data)
0261 : n_bins(axis_data.n_bins), min(axis_data.min), max(axis_data.max) {}
0262
0263
0264 DETRAY_HOST_DEVICE
0265 unsigned int bins() const { return n_bins; }
0266
0267
0268
0269
0270
0271
0272
0273 DETRAY_HOST_DEVICE
0274 unsigned int bin(scalar v) const {
0275 auto ibin =
0276 static_cast<int>((v - min) / (max - min) * static_cast<scalar>(n_bins));
0277 if (ibin >= 0 && ibin < static_cast<int>(n_bins)) {
0278 return static_cast<unsigned int>(ibin);
0279 } else {
0280 if (ibin < 0) {
0281 return n_bins + static_cast<unsigned int>(ibin);
0282 } else {
0283 return static_cast<unsigned int>(ibin) - n_bins;
0284 }
0285 }
0286 }
0287
0288
0289
0290
0291
0292
0293
0294
0295 DETRAY_HOST_DEVICE
0296 std::array<unsigned int, 2> range(scalar v,
0297 const array_t<unsigned int, 2> nhood = {
0298 0u, 0u}) const {
0299 unsigned int gbin = bin(v);
0300 unsigned int min_bin = remap(gbin, -static_cast<int>(nhood[0]));
0301 unsigned int max_bin = remap(gbin, static_cast<int>(nhood[1]));
0302 return {min_bin, max_bin};
0303 }
0304
0305
0306
0307
0308
0309
0310
0311
0312 DETRAY_HOST_DEVICE
0313 std::array<unsigned int, 2> range(scalar v,
0314 const array_t<scalar, 2> &nhood) const {
0315 unsigned int nbin = bin(v - nhood[0]);
0316 unsigned int pbin = bin(v + nhood[1]);
0317 return {nbin, pbin};
0318 }
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329 template <typename neighbor_t>
0330 DETRAY_HOST_DEVICE vecmem::vector<unsigned int> zone_t(
0331 scalar v, const array_t<neighbor_t, 2> &nhood) const {
0332 std::array<unsigned int, 2> nh_range = range(v, nhood);
0333 if (nh_range[0] < nh_range[1]) {
0334 vecmem::vector<unsigned int> sequence(
0335 static_cast<vecmem::vector<unsigned int>::size_type>(
0336 nh_range[1] - nh_range[0] + 1u),
0337 nh_range[0]);
0338 unsigned int m = 0;
0339 std::ranges::for_each(sequence, [&](auto &n) { n += m++; });
0340 return sequence;
0341 }
0342 unsigned int vl = n_bins - nh_range[0] + nh_range[1] + 1u;
0343 unsigned int mi = 0;
0344 unsigned int mo = 0;
0345 vecmem::vector<unsigned int> sequence(
0346 static_cast<vecmem::vector<unsigned int>::size_type>(vl), nh_range[0]);
0347 std::ranges::for_each(sequence, [&](auto &n) {
0348 n += mi++;
0349 if (n > n_bins - 1u) {
0350 n = mo++;
0351 }
0352 });
0353 return sequence;
0354 }
0355
0356
0357
0358
0359
0360
0361
0362
0363 DETRAY_HOST_DEVICE
0364 vecmem::vector<unsigned int> zone(
0365 scalar v, const array_t<unsigned int, 2> &nhood) const {
0366 return zone_t<unsigned int>(v, nhood);
0367 }
0368
0369
0370
0371
0372
0373
0374
0375
0376 DETRAY_HOST_DEVICE
0377 vecmem::vector<unsigned int> zone(scalar v,
0378 const array_t<scalar, 2> &nhood) const {
0379 return zone_t<scalar>(v, nhood);
0380 }
0381
0382
0383
0384
0385
0386
0387
0388
0389 DETRAY_HOST_DEVICE
0390 unsigned int remap(unsigned int ibin, int shood) const {
0391 int opt_bin = static_cast<int>(ibin) + shood;
0392 if (opt_bin >= 0 && opt_bin < static_cast<int>(n_bins)) {
0393 return static_cast<unsigned int>(opt_bin);
0394 }
0395 if (opt_bin < 0) {
0396 return static_cast<unsigned int>(static_cast<int>(n_bins) + opt_bin);
0397 }
0398 return static_cast<unsigned int>(opt_bin) - n_bins;
0399 }
0400
0401
0402 DETRAY_HOST_DEVICE
0403 array_t<scalar, 2> borders(unsigned int ibin) const {
0404 scalar step = (max - min) / n_bins;
0405 return {min + static_cast<scalar>(ibin) * step,
0406 min + static_cast<scalar>(ibin + 1u) * step};
0407 }
0408
0409
0410 DETRAY_HOST_DEVICE
0411 vector_t<scalar> all_borders() const {
0412 vector_t<scalar> borders;
0413 borders.reserve(n_bins + 1u);
0414 scalar step = (max - min) / static_cast<scalar>(n_bins);
0415 for (unsigned int ib = 0u; ib < n_bins + 1u; ++ib) {
0416 borders.push_back(min + static_cast<scalar>(ib) * step);
0417 }
0418 return borders;
0419 }
0420
0421
0422 DETRAY_HOST_DEVICE
0423 array_t<scalar, 2> span() const { return {min, max}; }
0424 };
0425
0426
0427
0428
0429
0430
0431 template <template <typename, std::size_t> class array_t = std::array,
0432 template <typename...> class vector_t = vecmem::vector>
0433 struct irregular {
0434
0435 unsigned int n_bins;
0436 scalar min;
0437 scalar max;
0438
0439 vector_t<scalar> boundaries;
0440
0441 static constexpr unsigned int axis_identifier = 2u;
0442
0443
0444 DETRAY_HOST_DEVICE
0445 irregular()
0446 : n_bins(std::numeric_limits<unsigned int>::max()),
0447 min(0.f),
0448 max(static_cast<scalar>(n_bins)),
0449 boundaries({}) {}
0450
0451
0452 DETRAY_HOST
0453 explicit irregular(vecmem::memory_resource &resource)
0454 : n_bins(std::numeric_limits<unsigned int>::max()),
0455 min(0.f),
0456 max(static_cast<scalar>(n_bins)),
0457 boundaries(&resource) {}
0458
0459
0460 DETRAY_HOST irregular(vector_t<scalar> &&bins,
0461 vecmem::memory_resource &resource)
0462 : n_bins(static_cast<unsigned int>(bins.size()) - 1u),
0463 min(bins[0]),
0464 max(bins[n_bins]),
0465 boundaries(bins, &resource) {}
0466
0467
0468 DETRAY_HOST irregular(const vector_t<scalar> &bins,
0469 vecmem::memory_resource &resource)
0470 : n_bins(static_cast<unsigned int>(bins.size()) - 1u),
0471 min(bins[0]),
0472 max(bins[n_bins]),
0473 boundaries(bins, &resource) {}
0474
0475
0476 DETRAY_HOST
0477 irregular(const irregular &axis, vecmem::memory_resource &resource)
0478 : n_bins(axis.n_bins),
0479 min(axis.min),
0480 max(axis.max),
0481 boundaries(axis.boundaries, &resource) {}
0482
0483
0484 template <typename axis_data_t>
0485 requires(!std::is_same_v<irregular, axis_data_t>)
0486 DETRAY_HOST_DEVICE explicit irregular(const axis_data_t &axis_data)
0487 : n_bins(axis_data.n_bins),
0488 min(axis_data.min),
0489 max(axis_data.max),
0490 boundaries(axis_data.boundaries) {}
0491
0492
0493 DETRAY_HOST_DEVICE
0494 unsigned int bins() const {
0495 return static_cast<unsigned int>(boundaries.size() - 1u);
0496 }
0497
0498
0499
0500
0501
0502
0503
0504 DETRAY_HOST_DEVICE
0505 unsigned int bin(scalar v) const {
0506 auto ibin = static_cast<int>(std::ranges::lower_bound(boundaries, v) -
0507 boundaries.begin());
0508 if (ibin > 0 && ibin < static_cast<int>(boundaries.size())) {
0509 return static_cast<unsigned int>(--ibin);
0510 } else {
0511 if (ibin == 0) {
0512 return static_cast<unsigned int>(ibin);
0513 } else {
0514 return static_cast<unsigned int>(boundaries.size() - 2u);
0515 }
0516 }
0517 }
0518
0519
0520
0521
0522
0523
0524
0525
0526 DETRAY_HOST_DEVICE
0527 std::array<unsigned int, 2> range(scalar v,
0528 const array_t<unsigned int, 2> &nhood = {
0529 0u, 0u}) const {
0530 unsigned int ibin = bin(v);
0531 int bins = static_cast<int>(boundaries.size()) - 1;
0532 int ibinmin = static_cast<int>(ibin) - static_cast<int>(nhood[0]);
0533 int ibinmax = static_cast<int>(ibin + nhood[1]);
0534 auto min_bin = (ibinmin >= 0) ? static_cast<unsigned int>(ibinmin) : 0u;
0535 auto max_bin = (ibinmax < bins) ? static_cast<unsigned int>(ibinmax)
0536 : static_cast<unsigned int>(bins - 1);
0537 return {min_bin, max_bin};
0538 }
0539
0540
0541
0542
0543
0544
0545
0546
0547 DETRAY_HOST_DEVICE
0548 std::array<unsigned int, 2> range(scalar v,
0549 const array_t<scalar, 2> &nhood) const {
0550 unsigned int nbin = bin(v - nhood[0]);
0551 unsigned int pbin = bin(v + nhood[1]);
0552 return {nbin, pbin};
0553 }
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564 template <typename neighbor_t>
0565 DETRAY_HOST_DEVICE vecmem::vector<unsigned int> zone_t(
0566 scalar v, const array_t<neighbor_t, 2> nhood) const {
0567 std::array<unsigned int, 2> nh_range = range(v, nhood);
0568 vecmem::vector<unsigned int> sequence(
0569 static_cast<vecmem::vector<unsigned int>::size_type>(nh_range[1] -
0570 nh_range[0] + 1u),
0571 nh_range[0]);
0572 unsigned int m = 0u;
0573 std::ranges::for_each(sequence, [&](auto &n) { n += m++; });
0574 return sequence;
0575 }
0576
0577
0578
0579
0580
0581
0582
0583
0584 DETRAY_HOST_DEVICE
0585 vecmem::vector<unsigned int> zone(scalar v,
0586 const array_t<unsigned int, 2> &nhood = {
0587 0u, 0u}) const {
0588 return zone_t<unsigned int>(v, nhood);
0589 }
0590
0591
0592
0593
0594
0595
0596
0597
0598 DETRAY_HOST_DEVICE
0599 vecmem::vector<unsigned int> zone(scalar v,
0600 const array_t<scalar, 2> &nhood) const {
0601 return zone_t<scalar>(v, nhood);
0602 }
0603
0604 DETRAY_HOST_DEVICE
0605
0606 array_t<scalar, 2> borders(unsigned int ibin) const {
0607 return {boundaries[ibin], boundaries[ibin + 1u]};
0608 }
0609
0610
0611 DETRAY_HOST
0612 vector_t<scalar> all_borders() const { return boundaries; }
0613
0614
0615 DETRAY_HOST_DEVICE
0616 array_t<scalar, 2> span() const {
0617 return {boundaries[0], boundaries[boundaries.size() - 1u]};
0618 }
0619 };
0620
0621 }
0622
0623
0624
0625
0626 template <typename axis_t, detray::concepts::scalar scalar_t,
0627 typename Enable = void>
0628 struct axis_data;
0629
0630 template <typename axis_t, detray::concepts::scalar scalar_t>
0631 requires(axis_t::axis_identifier == 0u) || (axis_t::axis_identifier == 1u)
0632 struct axis_data<axis_t, scalar_t> {
0633
0634 axis_data() = default;
0635
0636 DETRAY_HOST_DEVICE
0637 axis_data(unsigned int _n_bins, std::remove_cv_t<scalar_t> _min,
0638 std::remove_cv_t<scalar_t> _max)
0639 : n_bins(_n_bins), min(_min), max(_max) {}
0640
0641 template <typename other_scalar_t>
0642 requires detray::concepts::same_as_no_const<scalar_t, other_scalar_t>
0643 DETRAY_HOST_DEVICE explicit axis_data(
0644 const axis_data<axis_t, other_scalar_t, void> &parent)
0645 : n_bins(parent.n_bins), min(parent.min), max(parent.max) {}
0646
0647 unsigned int n_bins;
0648 std::remove_cv_t<scalar_t> min;
0649 std::remove_cv_t<scalar_t> max;
0650 };
0651
0652 template <typename axis_t, detray::concepts::scalar scalar_t>
0653 requires(axis_t::axis_identifier == 2)
0654 struct axis_data<axis_t, scalar_t> {
0655
0656 axis_data() = default;
0657
0658 DETRAY_HOST_DEVICE
0659 axis_data(unsigned int _n_bins, std::remove_cv_t<scalar_t> _min,
0660 std::remove_cv_t<scalar_t> _max,
0661 const vecmem::data::vector_view<scalar_t> &_boundaries)
0662 : n_bins(_n_bins), min(_min), max(_max), boundaries(_boundaries) {}
0663
0664 template <typename other_scalar_t>
0665 requires detray::concepts::same_as_no_const<scalar_t, other_scalar_t>
0666 DETRAY_HOST_DEVICE explicit axis_data(
0667 const axis_data<axis_t, other_scalar_t, void> &parent)
0668 : n_bins(parent.n_bins),
0669 min(parent.min),
0670 max(parent.max),
0671 boundaries(parent.boundaries) {}
0672
0673 unsigned int n_bins;
0674 std::remove_cv_t<scalar_t> min;
0675 std::remove_cv_t<scalar_t> max;
0676 vecmem::data::vector_view<scalar_t> boundaries;
0677 };
0678
0679
0680
0681
0682 template <template <template <typename, std::size_t> class,
0683 template <typename...> class> class axis_t,
0684 template <typename, std::size_t> class array_t,
0685 template <typename...> class vector_t>
0686 requires(axis_t<array_t, vector_t>::axis_identifier == 0u) ||
0687 (axis_t<array_t, vector_t>::axis_identifier == 1u)
0688 inline axis_data<axis_t<array_t, vector_t>, scalar> get_data(
0689 axis_t<array_t, vector_t> &axis) {
0690 axis_data<axis_t<array_t, vector_t>, scalar> result{axis.n_bins, axis.min,
0691 axis.max};
0692 return result;
0693 }
0694
0695
0696
0697
0698 template <template <template <typename, std::size_t> class,
0699 template <typename...> class> class axis_t,
0700 template <typename, std::size_t> class array_t,
0701 template <typename...> class vector_t>
0702 requires(axis_t<array_t, vector_t>::axis_identifier == 2u)
0703 inline axis_data<axis_t<array_t, vector_t>, scalar> get_data(
0704 axis_t<array_t, vector_t> &axis) {
0705 axis_data<axis_t<array_t, vector_t>, scalar> result{
0706 axis.n_bins, axis.min, axis.max, vecmem::get_data(axis.boundaries)};
0707 return result;
0708 }
0709
0710
0711
0712
0713 template <template <template <typename, std::size_t> class,
0714 template <typename...> class> class axis_t,
0715 template <typename, std::size_t> class array_t,
0716 template <typename...> class vector_t>
0717 requires(axis_t<array_t, vector_t>::axis_identifier == 0u) ||
0718 (axis_t<array_t, vector_t>::axis_identifier == 1u)
0719 inline axis_data<axis_t<array_t, vector_t>, const scalar> get_data(
0720 const axis_t<array_t, vector_t> &axis) {
0721 axis_data<axis_t<array_t, vector_t>, const scalar> result{axis.n_bins,
0722 axis.min, axis.max};
0723 return result;
0724 }
0725
0726
0727
0728
0729 template <template <template <typename, std::size_t> class,
0730 template <typename...> class> class axis_t,
0731 template <typename, std::size_t> class array_t,
0732 template <typename...> class vector_t>
0733 requires(axis_t<array_t, vector_t>::axis_identifier == 2u)
0734 inline axis_data<axis_t<array_t, vector_t>, const scalar> get_data(
0735 const axis_t<array_t, vector_t> &axis) {
0736 axis_data<axis_t<array_t, vector_t>, const scalar> result{
0737 axis.n_bins, axis.min, axis.max, vecmem::get_data(axis.boundaries)};
0738 return result;
0739 }
0740
0741 }