File indexing completed on 2026-07-27 08:32:53
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Utilities/IAxis.hpp"
0012 #include "Acts/Utilities/detail/MultiAxisHelper.hpp"
0013
0014 #include <algorithm>
0015 #include <iostream>
0016 #include <memory>
0017 #include <stdexcept>
0018
0019 #include <boost/container/small_vector.hpp>
0020
0021 namespace Acts {
0022
0023 template <std::size_t _DIM>
0024 class IMultiAxisXD;
0025
0026 using IMultiAxis1D = IMultiAxisXD<1>;
0027
0028 using IMultiAxis2D = IMultiAxisXD<2>;
0029
0030 using IMultiAxis3D = IMultiAxisXD<3>;
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 class IMultiAxis {
0049 private:
0050
0051
0052 template <typename T>
0053 using SmallVector = boost::container::small_vector<T, 3>;
0054
0055 public:
0056
0057 using GlobalBin = std::size_t;
0058
0059 using AnyLocalBins = SmallVector<std::size_t>;
0060
0061 using AnyPoint = SmallVector<double>;
0062
0063 using AnyAxesVector = SmallVector<const IAxis*>;
0064
0065
0066
0067
0068 static std::unique_ptr<IMultiAxis1D> create(const IAxis& axis1);
0069
0070
0071
0072
0073
0074 static std::unique_ptr<IMultiAxis2D> create(const IAxis& axis1,
0075 const IAxis& axis2);
0076
0077
0078
0079
0080
0081
0082 static std::unique_ptr<IMultiAxis3D> create(const IAxis& axis1,
0083 const IAxis& axis2,
0084 const IAxis& axis3);
0085
0086 virtual ~IMultiAxis() = default;
0087
0088
0089
0090 virtual std::size_t getNAxes() const = 0;
0091
0092
0093
0094
0095 virtual const IAxis& getAxis(std::size_t i) const = 0;
0096
0097
0098
0099 virtual AnyLocalBins getNBinsAny() const {
0100 AnyLocalBins result;
0101 result.reserve(getNAxes());
0102 for (const IAxis& axis : *this) {
0103 result.push_back(axis.getNBins());
0104 }
0105 return result;
0106 }
0107
0108
0109
0110
0111
0112 virtual std::size_t getNTotalBins(bool includeOverflowBins = false) const {
0113 std::size_t result = 1;
0114 for (const IAxis& axis : *this) {
0115 result *= axis.getNBins() + (includeOverflowBins ? 2 : 0);
0116 }
0117 return result;
0118 }
0119
0120
0121
0122 virtual AnyAxesVector getAnyAxesVector() const {
0123 AnyAxesVector result;
0124 std::ranges::transform(*this, std::back_inserter(result),
0125 [](const IAxis& axis) { return &axis; });
0126 return result;
0127 }
0128
0129
0130
0131 virtual AnyPoint getMinPointAny() const {
0132 AnyPoint result;
0133 result.reserve(getNAxes());
0134 for (const IAxis& axis : *this) {
0135 result.push_back(axis.getMin());
0136 }
0137 return result;
0138 }
0139
0140
0141
0142 virtual AnyPoint getMaxPointAny() const {
0143 AnyPoint result;
0144 result.reserve(getNAxes());
0145 for (const IAxis& axis : *this) {
0146 result.push_back(axis.getMax());
0147 }
0148 return result;
0149 }
0150
0151
0152
0153
0154
0155
0156 virtual bool isInsideAny(const AnyPoint& point) const {
0157 if (point.size() != getNAxes()) {
0158 throw std::invalid_argument("Invalid number of coordinates");
0159 }
0160 for (std::size_t i = 0; i < point.size(); ++i) {
0161 const IAxis& axis = getAxis(i);
0162 if (!axis.isInside(point[i])) {
0163 return false;
0164 }
0165 }
0166 return true;
0167 }
0168
0169
0170
0171
0172 virtual AnyPoint getLowerLeftBinEdgeAny(const AnyLocalBins& indices) const {
0173 AnyPoint result;
0174 result.reserve(getNAxes());
0175 for (std::size_t i = 0; i < indices.size(); ++i) {
0176 const IAxis& axis = getAxis(i);
0177 result.push_back(axis.getBinLowerBound(indices[i]));
0178 }
0179 return result;
0180 }
0181
0182
0183
0184
0185 virtual AnyPoint getUpperRightBinEdgeAny(const AnyLocalBins& indices) const {
0186 AnyPoint result;
0187 result.reserve(getNAxes());
0188 for (std::size_t i = 0; i < indices.size(); ++i) {
0189 const IAxis& axis = getAxis(i);
0190 result.push_back(axis.getBinUpperBound(indices[i]));
0191 }
0192 return result;
0193 }
0194
0195
0196
0197
0198 virtual AnyPoint getBinCenterAny(const AnyLocalBins& indices) const {
0199 AnyPoint result;
0200 result.reserve(getNAxes());
0201 for (std::size_t i = 0; i < indices.size(); ++i) {
0202 const IAxis& axis = getAxis(i);
0203 result.push_back(axis.getBinCenter(indices[i]));
0204 }
0205 return result;
0206 }
0207
0208
0209
0210 class iterator {
0211 public:
0212
0213 using value_type = const IAxis;
0214
0215 using difference_type = std::ptrdiff_t;
0216
0217 using pointer = const IAxis*;
0218
0219 using reference = const IAxis&;
0220
0221
0222 using iterator_category = std::random_access_iterator_tag;
0223
0224 using iterator_concept = std::random_access_iterator_tag;
0225
0226 constexpr iterator() noexcept = default;
0227
0228
0229
0230 constexpr iterator(const IMultiAxis& multiAxis, std::size_t index) noexcept
0231 : m_multiAxis(&multiAxis), m_index(index) {}
0232
0233
0234
0235 constexpr reference operator*() const {
0236 return m_multiAxis->getAxis(m_index);
0237 }
0238
0239
0240 constexpr iterator& operator++() noexcept {
0241 ++m_index;
0242 return *this;
0243 }
0244
0245
0246 constexpr iterator operator++(int) noexcept {
0247 auto tmp = *this;
0248 ++(*this);
0249 return tmp;
0250 }
0251
0252
0253 constexpr iterator& operator--() noexcept {
0254 --m_index;
0255 return *this;
0256 }
0257
0258
0259 constexpr iterator operator--(int) noexcept {
0260 auto tmp = *this;
0261 --(*this);
0262 return tmp;
0263 }
0264
0265
0266
0267 constexpr iterator& operator+=(difference_type n) noexcept {
0268 m_index += n;
0269 return *this;
0270 }
0271
0272
0273
0274 constexpr iterator& operator-=(difference_type n) noexcept {
0275 m_index -= n;
0276 return *this;
0277 }
0278
0279 private:
0280 const IMultiAxis* m_multiAxis{};
0281 std::size_t m_index{};
0282
0283 friend constexpr iterator operator+(iterator it,
0284 difference_type n) noexcept {
0285 return it += n;
0286 }
0287
0288 friend constexpr iterator operator+(difference_type n,
0289 iterator it) noexcept {
0290 return it += n;
0291 }
0292
0293 friend constexpr iterator operator-(iterator it,
0294 difference_type n) noexcept {
0295 return it -= n;
0296 }
0297
0298 friend constexpr difference_type operator-(const iterator& lhs,
0299 const iterator& rhs) noexcept {
0300 return lhs.m_index - rhs.m_index;
0301 }
0302
0303 friend constexpr auto operator<=>(const iterator& a,
0304 const iterator& b) noexcept {
0305 return a.m_index <=> b.m_index;
0306 }
0307
0308 friend constexpr bool operator==(const iterator& a,
0309 const iterator& b) noexcept {
0310 return a.m_index == b.m_index;
0311 }
0312 };
0313
0314
0315 iterator begin() const { return iterator(*this, 0); }
0316
0317
0318 iterator end() const { return iterator(*this, getNAxes()); }
0319
0320 protected:
0321
0322
0323 virtual void toStream(std::ostream& os) const {
0324 for (std::size_t i = 0; i < getNAxes(); ++i) {
0325 os << getAxis(i);
0326 if (i < getNAxes() - 1) {
0327 os << ", ";
0328 }
0329 }
0330 }
0331
0332 private:
0333
0334
0335
0336
0337
0338 friend bool operator==(const IMultiAxis& lhs, const IMultiAxis& rhs) {
0339 if (lhs.getNAxes() != rhs.getNAxes()) {
0340 return false;
0341 }
0342 return std::ranges::equal(lhs, rhs);
0343 }
0344
0345
0346
0347
0348
0349 friend std::ostream& operator<<(std::ostream& os,
0350 const IMultiAxis& multiAxis) {
0351 multiAxis.toStream(os);
0352 return os;
0353 }
0354 };
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366 template <std::size_t _DIM>
0367 class IMultiAxisXD : public IMultiAxis {
0368 public:
0369
0370 static constexpr std::size_t DIM = _DIM;
0371
0372 static_assert(DIM > 0, "MultiAxis dimension must be greater than zero");
0373
0374
0375 using LocalBins = std::array<std::size_t, DIM>;
0376
0377 using Point = std::array<double, DIM>;
0378
0379 using AnyAxesArray = std::array<const IAxis*, DIM>;
0380
0381 using AnyAxesTuple = decltype(std::apply(
0382 [](auto&&... xs) { return std::tie(*xs...); }, AnyAxesArray{}));
0383
0384
0385
0386 std::size_t getNAxes() const override { return DIM; }
0387
0388
0389
0390 virtual AnyAxesArray getAnyAxesArray() const {
0391 AnyAxesArray result{};
0392 std::ranges::transform(*this, result.begin(),
0393 [](const IAxis& axis) { return &axis; });
0394 return result;
0395 }
0396
0397
0398
0399 virtual AnyAxesTuple getAnyAxesTuple() const {
0400 return std::apply([](auto&&... xs) { return std::tie(*xs...); },
0401 getAnyAxesArray());
0402 }
0403
0404
0405
0406 virtual LocalBins getNBins() const {
0407 LocalBins result{};
0408 for (std::size_t i = 0; i < DIM; ++i) {
0409 result[i] = getAxis(i).getNBins();
0410 }
0411 return result;
0412 }
0413
0414
0415
0416 virtual Point getMinPoint() const {
0417 Point result{};
0418 for (std::size_t i = 0; i < DIM; ++i) {
0419 result[i] = getAxis(i).getMin();
0420 }
0421 return result;
0422 }
0423
0424
0425
0426 virtual Point getMaxPoint() const {
0427 Point result{};
0428 for (std::size_t i = 0; i < DIM; ++i) {
0429 result[i] = getAxis(i).getMax();
0430 }
0431 return result;
0432 }
0433
0434
0435
0436
0437 virtual bool isInside(const Point& point) const {
0438 for (std::size_t i = 0; i < DIM; ++i) {
0439 if (!getAxis(i).isInside(point[i])) {
0440 return false;
0441 }
0442 }
0443 return true;
0444 }
0445
0446
0447
0448
0449 virtual Point getLowerLeftBinEdge(const LocalBins& localBins) const {
0450 Point result{};
0451 for (std::size_t i = 0; i < DIM; ++i) {
0452 result[i] = getAxis(i).getBinLowerBound(localBins[i]);
0453 }
0454 return result;
0455 }
0456
0457
0458
0459
0460 virtual Point getUpperRightBinEdge(const LocalBins& localBins) const {
0461 Point result{};
0462 for (std::size_t i = 0; i < DIM; ++i) {
0463 result[i] = getAxis(i).getBinUpperBound(localBins[i]);
0464 }
0465 return result;
0466 }
0467
0468
0469
0470
0471 virtual Point getBinCenter(const LocalBins& localBins) const {
0472 Point result{};
0473 for (std::size_t i = 0; i < DIM; ++i) {
0474 result[i] = getAxis(i).getBinCenter(localBins[i]);
0475 }
0476 return result;
0477 }
0478
0479
0480
0481
0482 virtual Point getBinWidth(const LocalBins& localBins) const {
0483 Point result{};
0484 for (std::size_t i = 0; i < DIM; ++i) {
0485 result[i] = getAxis(i).getBinWidth(localBins[i]);
0486 }
0487 return result;
0488 }
0489
0490
0491
0492
0493 virtual GlobalBin getGlobalBinFromPoint(const Point& point) const {
0494 return getGlobalBinFromLocalBins(getLocalBinsFromPoint(point));
0495 }
0496
0497
0498
0499
0500
0501 virtual GlobalBin getGlobalBinFromLocalBins(
0502 const LocalBins& localBins) const {
0503 return detail::MultiAxisHelper::getGlobalBinFromLocalBins(
0504 localBins, getAnyAxesTuple());
0505 }
0506
0507
0508
0509
0510 virtual LocalBins getLocalBinsFromPoint(const Point& point) const {
0511 return detail::MultiAxisHelper::getLocalBinsFromPoint(point,
0512 getAnyAxesTuple());
0513 }
0514
0515
0516
0517
0518
0519 virtual LocalBins getLocalBinsFromGlobalBin(GlobalBin globalBin) const {
0520 return detail::MultiAxisHelper::getLocalBinsFromGlobalBin(
0521 globalBin, getAnyAxesTuple());
0522 }
0523
0524
0525
0526
0527
0528 virtual detail::FlatNeighborHoodIndices<DIM> getNeighborHoodIndices(
0529 const LocalBins& localBins, std::size_t size = 1u) const = 0;
0530
0531
0532
0533
0534
0535
0536 virtual detail::FlatNeighborHoodIndices<DIM> getNeighborHoodIndices(
0537 const LocalBins& localBins, const std::pair<int, int>& size) const = 0;
0538
0539
0540
0541
0542
0543
0544 virtual detail::FlatNeighborHoodIndices<DIM> getNeighborHoodIndices(
0545 const LocalBins& localBins,
0546 const std::array<std::pair<int, int>, DIM>& sizePerAxis) const = 0;
0547
0548
0549
0550
0551
0552 virtual detail::FlatNeighborHoodIndices<DIM> getClosestPointsIndices(
0553 const LocalBins& localBins) const = 0;
0554
0555
0556
0557
0558 virtual detail::FlatNeighborHoodIndices<DIM> getClosestPointsIndices(
0559 const Point& point) const {
0560 return getClosestPointsIndices(getLocalBinsFromPoint(point));
0561 }
0562 };
0563
0564 }