|
|
|||
File indexing completed on 2026-03-30 07:45:48
0001 // This file is part of the ACTS project. 0002 // 0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project 0004 // 0005 // This Source Code Form is subject to the terms of the Mozilla Public 0006 // License, v. 2.0. If a copy of the MPL was not distributed with this 0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/. 0008 0009 #pragma once 0010 0011 #include "Acts/Utilities/AxisDefinitions.hpp" 0012 #include "Acts/Utilities/IAxis.hpp" 0013 0014 #include <algorithm> 0015 #include <cmath> 0016 #include <vector> 0017 0018 namespace Acts { 0019 0020 // This object can be iterated to produce up to two sequences of integer 0021 // indices, corresponding to the half-open integer ranges [begin1, end1[ and 0022 // [begin2, end2[. 0023 // 0024 // The goal is to emulate the effect of enumerating a range of neighbor 0025 // indices on an axis (which may go out of bounds and wrap around since we 0026 // have AxisBoundaryType::Closed), inserting them into an std::vector, and 0027 // discarding duplicates, without paying the price of duplicate removal 0028 // and dynamic memory allocation in hot magnetic field interpolation code. 0029 // 0030 /// Iterable indices for neighborhood lookups with optional wrap-around. 0031 class NeighborHoodIndices { 0032 public: 0033 NeighborHoodIndices() = default; 0034 0035 /// Constructor for continuous range 0036 /// @param begin Start index 0037 /// @param end End index (exclusive) 0038 NeighborHoodIndices(std::size_t begin, std::size_t end) 0039 : m_begin1(begin), m_end1(end), m_begin2(end), m_end2(end) {} 0040 0041 /// Constructor for wrapped range (two segments) 0042 /// @param begin1 Start of first segment 0043 /// @param end1 End of first segment (exclusive) 0044 /// @param begin2 Start of second segment 0045 /// @param end2 End of second segment (exclusive) 0046 NeighborHoodIndices(std::size_t begin1, std::size_t end1, std::size_t begin2, 0047 std::size_t end2) 0048 : m_begin1(begin1), m_end1(end1), m_begin2(begin2), m_end2(end2) {} 0049 0050 /// Iterator over the neighborhood index sequence. 0051 class iterator { 0052 public: 0053 iterator() = default; 0054 0055 /// Constructor for end iterator 0056 /// @param current End position 0057 explicit iterator(std::size_t current) 0058 : m_current(current), m_wrapped(true) {} 0059 0060 /// Constructor for begin iterator 0061 /// @param begin1 Start of first segment 0062 /// @param end1 End of first segment 0063 /// @param begin2 Start of second segment 0064 iterator(std::size_t begin1, std::size_t end1, std::size_t begin2) 0065 : m_current(begin1), 0066 m_end1(end1), 0067 m_begin2(begin2), 0068 m_wrapped(begin1 == begin2) {} 0069 0070 /// Dereference operator 0071 /// @return Current index 0072 std::size_t operator*() const { return m_current; } 0073 0074 /// Pre-increment operator 0075 /// @return Reference to this iterator 0076 iterator& operator++() { 0077 ++m_current; 0078 if (m_current == m_end1) { 0079 m_current = m_begin2; 0080 m_wrapped = true; 0081 } 0082 return *this; 0083 } 0084 0085 /// Equality comparison operator 0086 /// @param it Other iterator 0087 /// @return True if iterators are equal 0088 bool operator==(const iterator& it) const { 0089 return (m_current == it.m_current) && (m_wrapped == it.m_wrapped); 0090 } 0091 0092 private: 0093 std::size_t m_current = 0, m_end1 = 0, m_begin2 = 0; 0094 bool m_wrapped = false; 0095 }; 0096 0097 /// Get begin iterator 0098 /// @return Iterator to first index 0099 iterator begin() const { return iterator(m_begin1, m_end1, m_begin2); } 0100 0101 /// Get end iterator 0102 /// @return Iterator past last index 0103 iterator end() const { return iterator(m_end2); } 0104 0105 /// Get total number of indices in the sequence 0106 /// @return Number of indices 0107 std::size_t size() const { return (m_end1 - m_begin1) + (m_end2 - m_begin2); } 0108 0109 /// Collect all indices into a vector 0110 /// @return Vector containing all indices 0111 std::vector<std::size_t> collect() const { 0112 std::vector<std::size_t> result; 0113 result.reserve(this->size()); 0114 for (std::size_t idx : *this) { 0115 result.push_back(idx); 0116 } 0117 return result; 0118 } 0119 0120 private: 0121 std::size_t m_begin1 = 0, m_end1 = 0, m_begin2 = 0, m_end2 = 0; 0122 }; 0123 0124 /// @brief calculate bin indices for an equidistant binning 0125 /// 0126 /// This class provides some basic functionality for calculating bin indices 0127 /// for a given equidistant binning. 0128 template <AxisBoundaryType bdt> 0129 class Axis<AxisType::Equidistant, bdt> : public IAxis { 0130 public: 0131 /// Static type identifier for this equidistant axis specialization 0132 static constexpr AxisType type = AxisType::Equidistant; 0133 0134 /// @brief default constructor 0135 /// 0136 /// @param [in] xmin lower boundary of axis range 0137 /// @param [in] xmax upper boundary of axis range 0138 /// @param [in] nBins number of bins to divide the axis range into 0139 /// 0140 /// Divide the range \f$[\text{xmin},\text{xmax})\f$ into \f$\text{nBins}\f$ 0141 /// equidistant bins. 0142 Axis(double xmin, double xmax, std::size_t nBins) 0143 : m_min(xmin), 0144 m_max(xmax), 0145 m_width((xmax - xmin) / nBins), 0146 m_bins(nBins) {} 0147 0148 /// Constructor with a tag for the boundary type 0149 /// 0150 /// @param [in] typeTag boundary type tag 0151 /// @param [in] xmin lower boundary of axis range 0152 /// @param [in] xmax upper boundary of axis range 0153 /// @param [in] nBins number of bins to divide the axis range into 0154 /// 0155 /// Divide the range \f$[\text{xmin},\text{xmax})\f$ into \f$\text{nBins}\f$ 0156 /// equidistant bins. 0157 Axis(AxisBoundaryTypeTag<bdt> typeTag, double xmin, double xmax, 0158 std::size_t nBins) 0159 : Axis(xmin, xmax, nBins) { 0160 static_cast<void>(typeTag); 0161 } 0162 0163 /// @brief returns whether the axis is equidistant 0164 /// 0165 /// @return bool is equidistant 0166 bool isEquidistant() const final { return true; } 0167 0168 /// @brief returns whether the axis is variable 0169 /// 0170 /// @return bool is variable 0171 bool isVariable() const final { return false; } 0172 0173 /// @brief returns the type of the axis 0174 /// @return @c AxisType of this axis 0175 AxisType getType() const final { return type; } 0176 0177 /// @brief returns the boundary type set in the template param 0178 /// 0179 /// @return @c AxisBoundaryType of this axis 0180 AxisBoundaryType getBoundaryType() const final { return bdt; } 0181 0182 /// @brief Get #size bins which neighbor the one given 0183 /// 0184 /// Generic overload with symmetric size 0185 /// 0186 /// @param [in] idx requested bin index 0187 /// @param [in] size how many neighboring bins (up/down) 0188 /// @return Set of neighboring bin indices (global) 0189 NeighborHoodIndices neighborHoodIndices(std::size_t idx, 0190 std::size_t size = 1) const { 0191 return neighborHoodIndices(idx, 0192 std::make_pair(-static_cast<int>(size), size)); 0193 } 0194 0195 /// @brief Get #size bins which neighbor the one given 0196 /// 0197 /// This is the version for Open 0198 /// 0199 /// @param [in] idx requested bin index 0200 /// @param [in] sizes how many neighboring bins (up/down) 0201 /// @return Set of neighboring bin indices (global) 0202 /// @note Open varies given bin and allows 0 and NBins+1 (underflow, 0203 /// overflow) 0204 /// as neighbors 0205 NeighborHoodIndices neighborHoodIndices(std::size_t idx, 0206 std::pair<int, int> sizes = {-1, 0207 1}) const 0208 requires(bdt == AxisBoundaryType::Open) 0209 { 0210 constexpr int min = 0; 0211 const int max = getNBins() + 1; 0212 const int itmin = std::clamp(static_cast<int>(idx + sizes.first), min, max); 0213 const int itmax = 0214 std::clamp(static_cast<int>(idx + sizes.second), min, max); 0215 return NeighborHoodIndices(itmin, itmax + 1); 0216 } 0217 0218 /// @brief Get #size bins which neighbor the one given 0219 /// 0220 /// This is the version for Bound 0221 /// 0222 /// @param [in] idx requested bin index 0223 /// @param [in] sizes how many neighboring bins (up/down) 0224 /// @return Set of neighboring bin indices (global) 0225 /// @note Bound varies given bin and allows 1 and NBins (regular bins) 0226 /// as neighbors 0227 NeighborHoodIndices neighborHoodIndices(std::size_t idx, 0228 std::pair<int, int> sizes = {-1, 0229 1}) const 0230 requires(bdt == AxisBoundaryType::Bound) 0231 { 0232 if (idx <= 0 || idx >= (getNBins() + 1)) { 0233 return NeighborHoodIndices(); 0234 } 0235 constexpr int min = 1; 0236 const int max = getNBins(); 0237 const int itmin = std::clamp(static_cast<int>(idx) + sizes.first, min, max); 0238 const int itmax = 0239 std::clamp(static_cast<int>(idx) + sizes.second, min, max); 0240 return NeighborHoodIndices(itmin, itmax + 1); 0241 } 0242 0243 /// @brief Get #size bins which neighbor the one given 0244 /// 0245 /// This is the version for Closed (i.e. Wrapping) 0246 /// 0247 /// @param [in] idx requested bin index 0248 /// @param [in] sizes how many neighboring bins (up/down) 0249 /// @return Set of neighboring bin indices (global) 0250 /// @note Closed varies given bin and allows bins on the opposite 0251 /// side of the axis as neighbors. (excludes underflow / overflow) 0252 NeighborHoodIndices neighborHoodIndices(std::size_t idx, 0253 std::pair<int, int> sizes = {-1, 0254 1}) const 0255 requires(bdt == AxisBoundaryType::Closed) 0256 { 0257 // Handle invalid indices 0258 if (idx <= 0 || idx >= (getNBins() + 1)) { 0259 return NeighborHoodIndices(); 0260 } 0261 0262 // Handle corner case where user requests more neighbours than the number 0263 // of bins on the axis. All bins are returned in this case. 0264 0265 const int max = getNBins(); 0266 sizes.first = std::clamp(sizes.first, -max, max); 0267 sizes.second = std::clamp(sizes.second, -max, max); 0268 if (std::abs(sizes.first - sizes.second) >= max) { 0269 sizes.first = 1 - idx; 0270 sizes.second = max - idx; 0271 } 0272 0273 // If the entire index range is not covered, we must wrap the range of 0274 // targeted neighbor indices into the range of valid bin indices. This may 0275 // split the range of neighbor indices in two parts: 0276 // 0277 // Before wraparound - [ XXXXX]XXX 0278 // After wraparound - [ XXXX XXXX ] 0279 // 0280 const int itmin = idx + sizes.first; 0281 const int itmax = idx + sizes.second; 0282 const std::size_t itfirst = wrapBin(itmin); 0283 const std::size_t itlast = wrapBin(itmax); 0284 if (itfirst <= itlast) { 0285 return NeighborHoodIndices(itfirst, itlast + 1); 0286 } else { 0287 return NeighborHoodIndices(itfirst, max + 1, 1, itlast + 1); 0288 } 0289 } 0290 0291 /// @brief Converts bin index into a valid one for this axis. 0292 /// 0293 /// @note Open: bin index is clamped to [0, nBins+1] 0294 /// 0295 /// @param [in] bin The bin to wrap 0296 /// @return valid bin index 0297 std::size_t wrapBin(int bin) const 0298 requires(bdt == AxisBoundaryType::Open) 0299 { 0300 return std::max(std::min(bin, static_cast<int>(getNBins()) + 1), 0); 0301 } 0302 0303 /// @brief Converts bin index into a valid one for this axis. 0304 /// 0305 /// @note Bound: bin index is clamped to [1, nBins] 0306 /// 0307 /// @param [in] bin The bin to wrap 0308 /// @return valid bin index 0309 std::size_t wrapBin(int bin) const 0310 requires(bdt == AxisBoundaryType::Bound) 0311 { 0312 return std::max(std::min(bin, static_cast<int>(getNBins())), 1); 0313 } 0314 0315 /// @brief Converts bin index into a valid one for this axis. 0316 /// 0317 /// @note Closed: bin index wraps around to other side 0318 /// 0319 /// @param [in] bin The bin to wrap 0320 /// @return valid bin index 0321 std::size_t wrapBin(int bin) const 0322 requires(bdt == AxisBoundaryType::Closed) 0323 { 0324 const int w = getNBins(); 0325 return 1 + (w + ((bin - 1) % w)) % w; 0326 // return int(bin<1)*w - int(bin>w)*w + bin; 0327 } 0328 0329 /// @brief get corresponding bin index for given coordinate 0330 /// 0331 /// @param [in] x input coordinate 0332 /// @return index of bin containing the given value 0333 /// 0334 /// @note Bin intervals are defined with closed lower bounds and open upper 0335 /// bounds, that is \f$l <= x < u\f$ if the value @c x lies within a 0336 /// bin with lower bound @c l and upper bound @c u. 0337 /// @note Bin indices start at @c 1. The underflow bin has the index @c 0 0338 /// while the index <tt>nBins + 1</tt> indicates the overflow bin . 0339 std::size_t getBin(double x) const final { 0340 return wrapBin( 0341 static_cast<int>(std::floor((x - getMin()) / getBinWidth()) + 1)); 0342 } 0343 0344 /// @brief get bin width 0345 /// 0346 /// @return constant width for all bins 0347 double getBinWidth(std::size_t /*bin*/ = 0) const { return m_width; } 0348 0349 /// @brief get lower bound of bin 0350 /// 0351 /// @param [in] bin index of bin 0352 /// @return lower bin boundary 0353 /// 0354 /// @pre @c bin must be a valid bin index (excluding the underflow bin), 0355 /// i.e. \f$1 \le \text{bin} \le \text{nBins} + 1\f$ 0356 /// 0357 /// @note Bin intervals have a closed lower bound, i.e. the lower boundary 0358 /// belongs to the bin with the given bin index. 0359 double getBinLowerBound(std::size_t bin) const { 0360 return getMin() + (bin - 1) * getBinWidth(); 0361 } 0362 0363 /// @brief get upper bound of bin 0364 /// 0365 /// @param [in] bin index of bin 0366 /// @return upper bin boundary 0367 /// 0368 /// @pre @c bin must be a valid bin index (excluding the overflow bin), 0369 /// i.e. \f$0 \le \text{bin} \le \text{nBins}\f$ 0370 /// 0371 /// @note Bin intervals have an open upper bound, i.e. the upper boundary 0372 /// does @b not belong to the bin with the given bin index. 0373 double getBinUpperBound(std::size_t bin) const { 0374 return getMin() + bin * getBinWidth(); 0375 } 0376 0377 /// @brief get bin center 0378 /// 0379 /// @param [in] bin index of bin 0380 /// @return bin center position 0381 /// 0382 /// @pre @c bin must be a valid bin index (excluding under-/overflow bins), 0383 /// i.e. \f$1 \le \text{bin} \le \text{nBins}\f$ 0384 double getBinCenter(std::size_t bin) const { 0385 return getMin() + (bin - 0.5) * getBinWidth(); 0386 } 0387 0388 /// @brief get maximum of binning range 0389 /// 0390 /// @return maximum of binning range 0391 double getMax() const final { return m_max; } 0392 0393 /// @brief get minimum of binning range 0394 /// 0395 /// @return minimum of binning range 0396 double getMin() const final { return m_min; } 0397 0398 /// @brief get total number of bins 0399 /// 0400 /// @return total number of bins (excluding under-/overflow bins) 0401 std::size_t getNBins() const final { return m_bins; } 0402 0403 /// @brief check whether value is inside axis limits 0404 /// @param x The value to check 0405 /// 0406 /// @return @c true if \f$\text{xmin} \le x < \text{xmax}\f$, otherwise 0407 /// @c false 0408 /// 0409 /// @post If @c true is returned, the bin containing the given value is a 0410 /// valid bin, i.e. it is neither the underflow nor the overflow bin. 0411 bool isInside(double x) const { return (m_min <= x) && (x < m_max); } 0412 0413 /// @brief Return a vector of bin edges 0414 /// @return Vector which contains the bin edges 0415 std::vector<double> getBinEdges() const final { 0416 std::vector<double> binEdges; 0417 for (std::size_t i = 1; i <= m_bins; i++) { 0418 binEdges.push_back(getBinLowerBound(i)); 0419 } 0420 binEdges.push_back(getBinUpperBound(m_bins)); 0421 return binEdges; 0422 } 0423 0424 friend std::ostream& operator<<(std::ostream& os, const Axis& axis) { 0425 os << "Axis<Equidistant, " << bdt << ">("; 0426 os << axis.m_min << ", "; 0427 os << axis.m_max << ", "; 0428 os << axis.m_bins << ")"; 0429 return os; 0430 } 0431 0432 protected: 0433 void toStream(std::ostream& os) const final { os << *this; } 0434 0435 private: 0436 /// minimum of binning range 0437 double m_min{}; 0438 /// maximum of binning range 0439 double m_max{}; 0440 /// constant bin width 0441 double m_width{}; 0442 /// number of bins (excluding under-/overflow bins) 0443 std::size_t m_bins{}; 0444 }; 0445 0446 /// @brief calculate bin indices for a variable binning 0447 /// 0448 /// This class provides some basic functionality for calculating bin indices 0449 /// for a given binning with variable bin sizes. 0450 template <AxisBoundaryType bdt> 0451 class Axis<AxisType::Variable, bdt> : public IAxis { 0452 public: 0453 /// Static type identifier for this variable-width axis specialization 0454 static constexpr AxisType type = AxisType::Variable; 0455 0456 /// @param [in] binEdges vector of bin edges 0457 /// @pre @c binEdges must be strictly sorted in ascending order. 0458 /// @pre @c binEdges must contain at least two entries. 0459 /// 0460 /// Create a binning structure with @c nBins variable-sized bins from the 0461 /// given bin boundaries. @c nBins is given by the number of bin edges 0462 /// reduced by one. 0463 explicit Axis(std::vector<double> binEdges) 0464 : m_binEdges(std::move(binEdges)) {} 0465 0466 /// @param [in] typeTag boundary type tag 0467 /// @param [in] binEdges vector of bin edges 0468 /// @pre @c binEdges must be strictly sorted in ascending order. 0469 /// @pre @c binEdges must contain at least two entries. 0470 /// 0471 /// Create a binning structure with @c nBins variable-sized bins from the 0472 /// given bin boundaries. @c nBins is given by the number of bin edges 0473 /// reduced by one. 0474 Axis(AxisBoundaryTypeTag<bdt> typeTag, std::vector<double> binEdges) 0475 : Axis(std::move(binEdges)) { 0476 static_cast<void>(typeTag); 0477 } 0478 0479 /// @brief returns whether the axis is equidistante 0480 /// 0481 /// @return bool is equidistant 0482 bool isEquidistant() const final { return false; } 0483 0484 /// @brief returns whether the axis is variable 0485 /// 0486 /// @return bool is variable 0487 bool isVariable() const final { return true; } 0488 0489 /// @brief returns the type of the axis 0490 /// @return @c AxisType of this axis 0491 AxisType getType() const final { return type; } 0492 0493 /// @brief returns the boundary type set in the template param 0494 /// 0495 /// @return @c AxisBoundaryType of this axis 0496 AxisBoundaryType getBoundaryType() const final { return bdt; } 0497 0498 /// @brief Get #size bins which neighbor the one given 0499 /// 0500 /// Generic overload with symmetric size 0501 /// 0502 /// @param [in] idx requested bin index 0503 /// @param [in] size how many neighboring bins 0504 /// @return Set of neighboring bin indices (global) 0505 NeighborHoodIndices neighborHoodIndices(std::size_t idx, 0506 std::size_t size = 1) const { 0507 return neighborHoodIndices(idx, 0508 std::make_pair(-static_cast<int>(size), size)); 0509 } 0510 0511 /// @brief Get #size bins which neighbor the one given 0512 /// 0513 /// This is the version for Open 0514 /// 0515 /// @param [in] idx requested bin index 0516 /// @param [in] sizes how many neighboring bins (up/down) 0517 /// @return Set of neighboring bin indices (global) 0518 /// @note Open varies given bin and allows 0 and NBins+1 (underflow, 0519 /// overflow) 0520 /// as neighbors 0521 NeighborHoodIndices neighborHoodIndices(std::size_t idx, 0522 std::pair<int, int> sizes = {-1, 0523 1}) const 0524 requires(bdt == AxisBoundaryType::Open) 0525 { 0526 constexpr int min = 0; 0527 const int max = getNBins() + 1; 0528 const int itmin = std::max(min, static_cast<int>(idx) + sizes.first); 0529 const int itmax = std::min(max, static_cast<int>(idx) + sizes.second); 0530 return NeighborHoodIndices(itmin, itmax + 1); 0531 } 0532 0533 /// @brief Get #size bins which neighbor the one given 0534 /// 0535 /// This is the version for Bound 0536 /// 0537 /// @param [in] idx requested bin index 0538 /// @param [in] sizes how many neighboring bins (up/down) 0539 /// @return Set of neighboring bin indices (global) 0540 /// @note Bound varies given bin and allows 1 and NBins (regular bins) 0541 /// as neighbors 0542 NeighborHoodIndices neighborHoodIndices(std::size_t idx, 0543 std::pair<int, int> sizes = {-1, 0544 1}) const 0545 requires(bdt == AxisBoundaryType::Bound) 0546 { 0547 if (idx <= 0 || idx >= (getNBins() + 1)) { 0548 return NeighborHoodIndices(); 0549 } 0550 constexpr int min = 1; 0551 const int max = getNBins(); 0552 const int itmin = std::max(min, static_cast<int>(idx) + sizes.first); 0553 const int itmax = std::min(max, static_cast<int>(idx) + sizes.second); 0554 return NeighborHoodIndices(itmin, itmax + 1); 0555 } 0556 0557 /// @brief Get #size bins which neighbor the one given 0558 /// 0559 /// This is the version for Closed 0560 /// 0561 /// @param [in] idx requested bin index 0562 /// @param [in] sizes how many neighboring bins (up/down) 0563 /// @return Set of neighboring bin indices (global) 0564 /// @note Closed varies given bin and allows bins on the opposite 0565 /// side of the axis as neighbors. (excludes underflow / overflow) 0566 NeighborHoodIndices neighborHoodIndices(std::size_t idx, 0567 std::pair<int, int> sizes = {-1, 0568 1}) const 0569 requires(bdt == AxisBoundaryType::Closed) 0570 { 0571 // Handle invalid indices 0572 if (idx <= 0 || idx >= (getNBins() + 1)) { 0573 return NeighborHoodIndices(); 0574 } 0575 0576 // Handle corner case where user requests more neighbours than the number 0577 // of bins on the axis. All bins are returned in this case 0578 0579 const int max = getNBins(); 0580 sizes.first = std::clamp(sizes.first, -max, max); 0581 sizes.second = std::clamp(sizes.second, -max, max); 0582 if (std::abs(sizes.first - sizes.second) >= max) { 0583 sizes.first = 1 - idx; 0584 sizes.second = max - idx; 0585 } 0586 0587 // If the entire index range is not covered, we must wrap the range of 0588 // targeted neighbor indices into the range of valid bin indices. This may 0589 // split the range of neighbor indices in two parts: 0590 // 0591 // Before wraparound - [ XXXXX]XXX 0592 // After wraparound - [ XXXX XXXX ] 0593 // 0594 const int itmin = idx + sizes.first; 0595 const int itmax = idx + sizes.second; 0596 const std::size_t itfirst = wrapBin(itmin); 0597 const std::size_t itlast = wrapBin(itmax); 0598 if (itfirst <= itlast) { 0599 return NeighborHoodIndices(itfirst, itlast + 1); 0600 } else { 0601 return NeighborHoodIndices(itfirst, max + 1, 1, itlast + 1); 0602 } 0603 } 0604 0605 /// @brief Converts bin index into a valid one for this axis. 0606 /// 0607 /// @note Open: bin index is clamped to [0, nBins+1] 0608 /// 0609 /// @param [in] bin The bin to wrap 0610 /// @return valid bin index 0611 std::size_t wrapBin(int bin) const 0612 requires(bdt == AxisBoundaryType::Open) 0613 { 0614 return std::max(std::min(bin, static_cast<int>(getNBins()) + 1), 0); 0615 } 0616 0617 /// @brief Converts bin index into a valid one for this axis. 0618 /// 0619 /// @note Bound: bin index is clamped to [1, nBins] 0620 /// 0621 /// @param [in] bin The bin to wrap 0622 /// @return valid bin index 0623 std::size_t wrapBin(int bin) const 0624 requires(bdt == AxisBoundaryType::Bound) 0625 { 0626 return std::max(std::min(bin, static_cast<int>(getNBins())), 1); 0627 } 0628 0629 /// @brief Converts bin index into a valid one for this axis. 0630 /// 0631 /// @note Closed: bin index wraps around to other side 0632 /// 0633 /// @param [in] bin The bin to wrap 0634 /// @return valid bin index 0635 std::size_t wrapBin(int bin) const 0636 requires(bdt == AxisBoundaryType::Closed) 0637 { 0638 const int w = getNBins(); 0639 return 1 + (w + ((bin - 1) % w)) % w; 0640 // return int(bin<1)*w - int(bin>w)*w + bin; 0641 } 0642 0643 /// @brief get corresponding bin index for given coordinate 0644 /// 0645 /// @param [in] x input coordinate 0646 /// @return index of bin containing the given value 0647 /// 0648 /// @note Bin intervals are defined with closed lower bounds and open upper 0649 /// bounds, that is \f$l <= x < u\f$ if the value @c x lies within a 0650 /// bin with lower bound @c l and upper bound @c u. 0651 /// @note Bin indices start at @c 1. The underflow bin has the index @c 0 0652 /// while the index <tt>nBins + 1</tt> indicates the overflow bin . 0653 std::size_t getBin(double x) const final { 0654 const auto it = 0655 std::upper_bound(std::begin(m_binEdges), std::end(m_binEdges), x); 0656 return wrapBin(std::distance(std::begin(m_binEdges), it)); 0657 } 0658 0659 /// @brief get bin width 0660 /// 0661 /// @param [in] bin index of bin 0662 /// @return width of given bin 0663 /// 0664 /// @pre @c bin must be a valid bin index (excluding under-/overflow bins), 0665 /// i.e. \f$1 \le \text{bin} \le \text{nBins}\f$ 0666 double getBinWidth(std::size_t bin) const { 0667 return m_binEdges.at(bin) - m_binEdges.at(bin - 1); 0668 } 0669 0670 /// @brief get lower bound of bin 0671 /// 0672 /// @param [in] bin index of bin 0673 /// @return lower bin boundary 0674 /// 0675 /// @pre @c bin must be a valid bin index (excluding the underflow bin), 0676 /// i.e. \f$1 \le \text{bin} \le \text{nBins} + 1\f$ 0677 /// 0678 /// @note Bin intervals have a closed lower bound, i.e. the lower boundary 0679 /// belongs to the bin with the given bin index. 0680 double getBinLowerBound(std::size_t bin) const { 0681 return m_binEdges.at(bin - 1); 0682 } 0683 0684 /// @brief get upper bound of bin 0685 /// 0686 /// @param [in] bin index of bin 0687 /// @return upper bin boundary 0688 /// 0689 /// @pre @c bin must be a valid bin index (excluding the overflow bin), 0690 /// i.e. \f$0 \le \text{bin} \le \text{nBins}\f$ 0691 /// 0692 /// @note Bin intervals have an open upper bound, i.e. the upper boundary 0693 /// does @b not belong to the bin with the given bin index. 0694 double getBinUpperBound(std::size_t bin) const { return m_binEdges.at(bin); } 0695 0696 /// @brief get bin center 0697 /// 0698 /// @param [in] bin index of bin 0699 /// @return bin center position 0700 /// 0701 /// @pre @c bin must be a valid bin index (excluding under-/overflow bins), 0702 /// i.e. \f$1 \le \text{bin} \le \text{nBins}\f$ 0703 double getBinCenter(std::size_t bin) const { 0704 return 0.5 * (getBinLowerBound(bin) + getBinUpperBound(bin)); 0705 } 0706 0707 /// @brief get maximum of binning range 0708 /// 0709 /// @return maximum of binning range 0710 double getMax() const final { return m_binEdges.back(); } 0711 0712 /// @brief get minimum of binning range 0713 /// 0714 /// @return minimum of binning range 0715 double getMin() const final { return m_binEdges.front(); } 0716 0717 /// @brief get total number of bins 0718 /// 0719 /// @return total number of bins (excluding under-/overflow bins) 0720 std::size_t getNBins() const final { return m_binEdges.size() - 1; } 0721 0722 /// @brief check whether value is inside axis limits 0723 /// @param x The value to check 0724 /// 0725 /// @return @c true if \f$\text{xmin} \le x < \text{xmax}\f$, otherwise 0726 /// @c false 0727 /// 0728 /// @post If @c true is returned, the bin containing the given value is a 0729 /// valid bin, i.e. it is neither the underflow nor the overflow bin. 0730 bool isInside(double x) const { 0731 return (m_binEdges.front() <= x) && (x < m_binEdges.back()); 0732 } 0733 0734 /// @brief Return a vector of bin edges 0735 /// @return Vector which contains the bin edges 0736 std::vector<double> getBinEdges() const final { return m_binEdges; } 0737 0738 friend std::ostream& operator<<(std::ostream& os, const Axis& axis) { 0739 os << "Axis<Variable, " << bdt << ">("; 0740 os << axis.m_binEdges.front(); 0741 for (std::size_t i = 1; i < axis.m_binEdges.size(); i++) { 0742 os << ", " << axis.m_binEdges[i]; 0743 } 0744 os << ")"; 0745 return os; 0746 } 0747 0748 protected: 0749 void toStream(std::ostream& os) const final { os << *this; } 0750 0751 private: 0752 /// vector of bin edges (sorted in ascending order) 0753 std::vector<double> m_binEdges; 0754 }; 0755 } // namespace Acts
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|