File indexing completed on 2025-07-01 07:52:39
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Utilities/AxisDefinitions.hpp"
0013 #include "Acts/Utilities/BinningType.hpp"
0014 #include "Acts/Utilities/Helpers.hpp"
0015 #include "Acts/Utilities/ProtoAxis.hpp"
0016 #include "Acts/Utilities/ThrowAssert.hpp"
0017 #include "Acts/Utilities/VectorHelpers.hpp"
0018
0019 #include <algorithm>
0020 #include <cmath>
0021 #include <memory>
0022 #include <sstream>
0023 #include <string>
0024 #include <utility>
0025 #include <vector>
0026
0027 namespace Acts {
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 class BinningData {
0045 public:
0046 BinningType type{};
0047 BinningOption option{};
0048 AxisDirection binvalue{};
0049 float min{};
0050 float max{};
0051 float step{};
0052 bool zdim{};
0053
0054
0055 std::unique_ptr<const BinningData> subBinningData;
0056
0057 bool subBinningAdditive{};
0058
0059
0060
0061
0062
0063
0064 BinningData(AxisDirection bValue, float bMin, float bMax)
0065 : type(equidistant),
0066 option(open),
0067 binvalue(bValue),
0068 min(bMin),
0069 max(bMax),
0070 step((bMax - bMin)),
0071 zdim(true),
0072 subBinningData(nullptr),
0073 m_bins(1),
0074 m_boundaries({{min, max}}),
0075 m_totalBins(1),
0076 m_totalBoundaries(std::vector<float>()),
0077 m_functionPtr(&searchEquidistantWithBoundary) {}
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090 BinningData(BinningOption bOption, AxisDirection bValue, std::size_t bBins,
0091 float bMin, float bMax,
0092 std::unique_ptr<const BinningData> sBinData = nullptr,
0093 bool sBinAdditive = false)
0094 : type(equidistant),
0095 option(bOption),
0096 binvalue(bValue),
0097 min(bMin),
0098 max(bMax),
0099 step((bMax - bMin) / bBins),
0100 zdim(bBins == 1 ? true : false),
0101 subBinningData(std::move(sBinData)),
0102 subBinningAdditive(sBinAdditive),
0103 m_bins(bBins),
0104 m_boundaries(std::vector<float>()),
0105 m_totalBins(bBins),
0106 m_totalBoundaries(std::vector<float>()) {
0107
0108 m_functionPtr = &searchEquidistantWithBoundary;
0109
0110 m_boundaries.reserve(m_bins + 1);
0111 for (std::size_t ib = 0; ib < m_bins + 1; ++ib) {
0112 m_boundaries.push_back(min + ib * step);
0113 }
0114
0115 checkSubStructure();
0116 }
0117
0118
0119
0120
0121
0122
0123
0124 BinningData(BinningOption bOption, AxisDirection bValue,
0125 const std::vector<float>& bBoundaries,
0126 std::unique_ptr<const BinningData> sBinData = nullptr)
0127 : type(arbitrary),
0128 option(bOption),
0129 binvalue(bValue),
0130 zdim(bBoundaries.size() == 2 ? true : false),
0131 subBinningData(std::move(sBinData)),
0132 subBinningAdditive(true),
0133 m_bins(bBoundaries.size() - 1),
0134 m_boundaries(bBoundaries),
0135 m_totalBins(bBoundaries.size() - 1),
0136 m_totalBoundaries(bBoundaries) {
0137
0138 throw_assert(m_boundaries.size() > 1, "Must have more than one boundary");
0139 min = m_boundaries[0];
0140 max = m_boundaries[m_boundaries.size() - 1];
0141
0142 m_functionPtr = &searchInVectorWithBoundary;
0143
0144 checkSubStructure();
0145 }
0146
0147
0148
0149
0150 BinningData(const BinningData& bdata)
0151 : type(bdata.type),
0152 option(bdata.option),
0153 binvalue(bdata.binvalue),
0154 min(bdata.min),
0155 max(bdata.max),
0156 step(bdata.step),
0157 zdim(bdata.zdim),
0158 subBinningData(nullptr),
0159 subBinningAdditive(bdata.subBinningAdditive),
0160 m_bins(bdata.m_bins),
0161 m_boundaries(bdata.m_boundaries),
0162 m_totalBins(bdata.m_totalBins),
0163 m_totalBoundaries(bdata.m_totalBoundaries) {
0164
0165 subBinningData =
0166 bdata.subBinningData
0167 ? std::make_unique<const BinningData>(*bdata.subBinningData)
0168 : nullptr;
0169
0170
0171 if (type == equidistant) {
0172 m_functionPtr = &searchEquidistantWithBoundary;
0173 } else {
0174 m_functionPtr = &searchInVectorWithBoundary;
0175 }
0176 }
0177
0178
0179
0180
0181
0182 explicit BinningData(const DirectedProtoAxis& dpAxis)
0183 : binvalue(dpAxis.getAxisDirection()), subBinningData(nullptr) {
0184 const auto& axis = dpAxis.getAxis();
0185 type = axis.getType() == AxisType::Equidistant ? equidistant : arbitrary;
0186 option = axis.getBoundaryType() == AxisBoundaryType::Closed ? closed : open;
0187 min = static_cast<float>(axis.getMin());
0188 max = static_cast<float>(axis.getMax());
0189 m_bins = axis.getNBins();
0190 step = (max - min) / static_cast<float>(m_bins);
0191 zdim = (m_bins == 1);
0192 m_boundaries.reserve(axis.getBinEdges().size());
0193 for (const auto& edge : axis.getBinEdges()) {
0194 m_boundaries.push_back(static_cast<float>(edge));
0195 }
0196 m_totalBins = m_bins;
0197 m_totalBoundaries = m_boundaries;
0198
0199 m_functionPtr = (type == equidistant) ? &searchEquidistantWithBoundary
0200 : &searchInVectorWithBoundary;
0201 }
0202
0203
0204
0205
0206 BinningData& operator=(const BinningData& bdata) {
0207 if (this != &bdata) {
0208 type = bdata.type;
0209 option = bdata.option;
0210 binvalue = bdata.binvalue;
0211 min = bdata.min;
0212 max = bdata.max;
0213 step = bdata.step;
0214 zdim = bdata.zdim;
0215 subBinningAdditive = bdata.subBinningAdditive;
0216 subBinningData =
0217 bdata.subBinningData
0218 ? std::make_unique<const BinningData>(*bdata.subBinningData)
0219 : nullptr;
0220 m_bins = bdata.m_bins;
0221 m_boundaries = bdata.m_boundaries;
0222 m_totalBins = bdata.m_totalBins;
0223 m_totalBoundaries = bdata.m_totalBoundaries;
0224
0225 if (type == equidistant) {
0226 m_functionPtr = &searchEquidistantWithBoundary;
0227 } else {
0228 m_functionPtr = &searchInVectorWithBoundary;
0229 }
0230 }
0231 return (*this);
0232 }
0233
0234 BinningData() = default;
0235 ~BinningData() = default;
0236
0237
0238
0239
0240
0241
0242 bool operator==(const BinningData& bData) const {
0243 return (type == bData.type && option == bData.option &&
0244 binvalue == bData.binvalue && min == bData.min &&
0245 max == bData.max && step == bData.step && zdim == bData.zdim &&
0246 ((subBinningData == nullptr && bData.subBinningData == nullptr) ||
0247 (subBinningData != nullptr && bData.subBinningData != nullptr &&
0248 (*subBinningData == *bData.subBinningData))) &&
0249 subBinningAdditive == bData.subBinningAdditive);
0250 }
0251
0252
0253 std::size_t bins() const { return m_totalBins; }
0254
0255
0256
0257 const std::vector<float>& boundaries() const {
0258 if (subBinningData) {
0259 return m_totalBoundaries;
0260 }
0261 return m_boundaries;
0262 }
0263
0264
0265
0266
0267
0268
0269 float value(const Vector2& lposition) const {
0270
0271 if (binvalue == AxisDirection::AxisR ||
0272 binvalue == AxisDirection::AxisRPhi ||
0273 binvalue == AxisDirection::AxisX ||
0274 binvalue == AxisDirection::AxisTheta) {
0275 return lposition[0];
0276 }
0277
0278 return lposition[1];
0279 }
0280
0281
0282
0283
0284
0285
0286 float value(const Vector3& position) const {
0287 using VectorHelpers::eta;
0288 using VectorHelpers::perp;
0289 using VectorHelpers::phi;
0290
0291 if (binvalue == AxisDirection::AxisR ||
0292 binvalue == AxisDirection::AxisTheta) {
0293 return (perp(position));
0294 }
0295 if (binvalue == AxisDirection::AxisRPhi) {
0296 return (perp(position) * phi(position));
0297 }
0298 if (binvalue == AxisDirection::AxisEta) {
0299 return (eta(position));
0300 }
0301 if (toUnderlying(binvalue) < 3) {
0302 return static_cast<float>(position[toUnderlying(binvalue)]);
0303 }
0304
0305 return phi(position);
0306 }
0307
0308
0309
0310
0311
0312
0313 float center(std::size_t bin) const {
0314 const std::vector<float>& bvals = boundaries();
0315
0316 float value =
0317 bin < (bvals.size() - 1) ? 0.5 * (bvals[bin] + bvals[bin + 1]) : 0.;
0318 return value;
0319 }
0320
0321
0322
0323
0324
0325
0326 float width(std::size_t bin) const {
0327 const std::vector<float>& bvals = boundaries();
0328
0329 float value = bin < (bvals.size() - 1) ? bvals[bin + 1] - bvals[bin] : 0.;
0330 return value;
0331 }
0332
0333
0334
0335
0336
0337
0338 bool inside(const Vector3& position) const {
0339
0340 if (option == closed) {
0341 return true;
0342 }
0343
0344
0345 float val = value(position);
0346 return (val > min - 0.001 && val < max + 0.001);
0347 }
0348
0349
0350
0351
0352
0353
0354 bool inside(const Vector2& lposition) const {
0355
0356 if (option == closed) {
0357 return true;
0358 }
0359
0360
0361 float val = value(lposition);
0362 return (val > min - 0.001 && val < max + 0.001);
0363 }
0364
0365
0366
0367
0368
0369
0370 std::size_t searchLocal(const Vector2& lposition) const {
0371 if (zdim) {
0372 return 0;
0373 }
0374 return search(value(lposition));
0375 }
0376
0377
0378
0379
0380
0381
0382 std::size_t searchGlobal(const Vector3& position) const {
0383 if (zdim) {
0384 return 0;
0385 }
0386 return search(value(position));
0387 }
0388
0389
0390
0391
0392
0393
0394 std::size_t search(float value) const {
0395 if (zdim) {
0396 return 0;
0397 }
0398 assert(m_functionPtr != nullptr);
0399 return (!subBinningData) ? (*m_functionPtr)(value, *this)
0400 : searchWithSubStructure(value);
0401 }
0402
0403
0404
0405
0406
0407
0408
0409 std::size_t searchWithSubStructure(float value) const {
0410
0411 std::size_t masterbin = (*m_functionPtr)(value, *this);
0412
0413 if (subBinningAdditive) {
0414
0415 return masterbin + subBinningData->search(value);
0416 }
0417
0418 float gvalue =
0419 value - masterbin * (subBinningData->max - subBinningData->min);
0420
0421 std::size_t subbin = subBinningData->search(gvalue);
0422
0423 return masterbin * subBinningData->bins() + subbin;
0424 }
0425
0426
0427
0428
0429
0430
0431
0432
0433 int nextDirection(const Vector3& position, const Vector3& dir) const {
0434 if (zdim) {
0435 return 0;
0436 }
0437 float val = value(position);
0438 Vector3 probe = position + dir.normalized();
0439 float nextval = value(probe);
0440 return (nextval > val) ? 1 : -1;
0441 }
0442
0443
0444
0445
0446
0447
0448
0449
0450 float centerValue(std::size_t bin) const {
0451 if (zdim) {
0452 return 0.5 * (min + max);
0453 }
0454 float bmin = m_boundaries[bin];
0455 float bmax = bin < m_boundaries.size() ? m_boundaries[bin + 1] : max;
0456 return 0.5 * (bmin + bmax);
0457 }
0458
0459 private:
0460 std::size_t m_bins{};
0461 std::vector<float> m_boundaries;
0462 std::size_t m_totalBins{};
0463 std::vector<float> m_totalBoundaries;
0464
0465 std::size_t (*m_functionPtr)(float,
0466 const BinningData&){};
0467
0468
0469 void checkSubStructure() {
0470
0471 if (subBinningData) {
0472 m_totalBoundaries.clear();
0473
0474 if (subBinningAdditive) {
0475
0476 m_totalBins = m_bins + subBinningData->bins() - 1;
0477
0478 m_totalBoundaries.reserve(m_totalBins + 1);
0479
0480 const std::vector<float>& subBinBoundaries =
0481 subBinningData->boundaries();
0482 float sBinMin = subBinBoundaries[0];
0483
0484 std::vector<float>::const_iterator mbvalue = m_boundaries.begin();
0485 for (; mbvalue != m_boundaries.end(); ++mbvalue) {
0486
0487 if (std::abs((*mbvalue) - sBinMin) < 10e-10) {
0488
0489 m_totalBoundaries.insert(m_totalBoundaries.begin(),
0490 subBinBoundaries.begin(),
0491 subBinBoundaries.end());
0492 ++mbvalue;
0493 } else {
0494 m_totalBoundaries.push_back(*mbvalue);
0495 }
0496 }
0497 } else {
0498
0499 m_totalBins = m_bins * subBinningData->bins();
0500 m_totalBoundaries.reserve(m_totalBins + 1);
0501
0502 const std::vector<float>& subBinBoundaries =
0503 subBinningData->boundaries();
0504
0505 m_totalBoundaries.push_back(min);
0506 for (std::size_t ib = 0; ib < m_bins; ++ib) {
0507 float offset = ib * step;
0508 for (std::size_t isb = 1; isb < subBinBoundaries.size(); ++isb) {
0509 m_totalBoundaries.push_back(offset + subBinBoundaries[isb]);
0510 }
0511 }
0512 }
0513
0514 std::ranges::sort(m_totalBoundaries);
0515 }
0516 }
0517
0518
0519
0520 static std::size_t searchEquidistantWithBoundary(float value,
0521 const BinningData& bData) {
0522
0523
0524 int bin = static_cast<int>((value - bData.min) / bData.step);
0525
0526 if (bData.option == closed) {
0527 if (value < bData.min) {
0528 return (bData.m_bins - 1);
0529 }
0530 if (value > bData.max) {
0531 return 0;
0532 }
0533 }
0534
0535 bin = bin < 0 ? ((bData.option == open) ? 0 : (bData.m_bins - 1)) : bin;
0536 return static_cast<std::size_t>(
0537 (bin <= static_cast<int>(bData.m_bins - 1))
0538 ? bin
0539 : ((bData.option == open) ? (bData.m_bins - 1) : 0));
0540 }
0541
0542
0543 static std::size_t searchInVectorWithBoundary(float value,
0544 const BinningData& bData) {
0545
0546 if (value <= bData.m_boundaries[0]) {
0547 return (bData.option == closed) ? (bData.m_bins - 1) : 0;
0548 }
0549
0550 if (value >= bData.max) {
0551 return (bData.option == closed) ? 0 : (bData.m_bins - 1);
0552 }
0553
0554 auto lb = std::lower_bound(bData.m_boundaries.begin(),
0555 bData.m_boundaries.end(), value);
0556 return static_cast<std::size_t>(
0557 std::distance(bData.m_boundaries.begin(), lb) - 1);
0558 }
0559
0560 public:
0561
0562
0563
0564 std::string toString(const std::string& indent = "") const {
0565 std::stringstream sl;
0566 sl << indent << "BinningData object:" << '\n';
0567 sl << indent << " - type : " << static_cast<std::size_t>(type)
0568 << '\n';
0569 sl << indent << " - option : " << static_cast<std::size_t>(option)
0570 << '\n';
0571 sl << indent << " - value : " << static_cast<std::size_t>(binvalue)
0572 << '\n';
0573 sl << indent << " - bins : " << bins() << '\n';
0574 sl << indent << " - min/max : " << min << " / " << max << '\n';
0575 if (type == equidistant) {
0576 sl << indent << " - step : " << step << '\n';
0577 }
0578 sl << indent << " - boundaries : | ";
0579 for (const auto& b : boundaries()) {
0580 sl << b << " | ";
0581 }
0582 sl << '\n';
0583 return sl.str();
0584 }
0585 };
0586 }