File indexing completed on 2025-01-18 10:10:44
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #ifndef ROOT7_RHistImpl
0017 #define ROOT7_RHistImpl
0018
0019 #include <cassert>
0020 #include <cctype>
0021 #include <functional>
0022 #include <tuple>
0023 #include "ROOT/RSpan.hxx"
0024
0025 #include "ROOT/RAxis.hxx"
0026 #include "ROOT/RHistBinIter.hxx"
0027 #include "ROOT/RHistUtils.hxx"
0028 #include "ROOT/RLogger.hxx"
0029
0030 class TRootIOCtor;
0031
0032 namespace ROOT {
0033 namespace Experimental {
0034
0035 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
0036 class RHist;
0037
0038 namespace Hist {
0039
0040 template <int NDIMS>
0041 using AxisIter_t = std::array<RAxisBase::const_iterator, NDIMS>;
0042
0043 template <int NDIMS>
0044 using AxisIterRange_t = std::array<AxisIter_t<NDIMS>, 2>;
0045
0046
0047 enum class EOverflow {
0048 kNoOverflow = 0x0,
0049 kUnderflow = 0x1,
0050 kOverflow = 0x2,
0051 kUnderOver = 0x3,
0052 };
0053
0054 inline bool operator&(EOverflow a, EOverflow b)
0055 {
0056 return static_cast<int>(a) & static_cast<int>(b);
0057 }
0058 }
0059
0060 namespace Detail {
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071 template <int DIMENSIONS>
0072 class RHistImplPrecisionAgnosticBase {
0073 public:
0074
0075 using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
0076
0077 using BinArray_t = std::array<int, DIMENSIONS>;
0078
0079 using AxisIterRange_t = Hist::AxisIterRange_t<DIMENSIONS>;
0080
0081 RHistImplPrecisionAgnosticBase() = default;
0082 RHistImplPrecisionAgnosticBase(const RHistImplPrecisionAgnosticBase &) = default;
0083 RHistImplPrecisionAgnosticBase(RHistImplPrecisionAgnosticBase &&) = default;
0084 RHistImplPrecisionAgnosticBase(std::string_view title): fTitle(title) {}
0085 virtual ~RHistImplPrecisionAgnosticBase() {}
0086
0087
0088 static constexpr int GetNDim() { return DIMENSIONS; }
0089
0090
0091 virtual int GetNBins() const noexcept = 0;
0092
0093
0094 virtual int GetNBinsNoOver() const noexcept = 0;
0095
0096
0097 virtual int GetNOverflowBins() const noexcept = 0;
0098
0099
0100 const std::string &GetTitle() const { return fTitle; }
0101
0102
0103 virtual int GetBinIndex(const CoordArray_t &x) const = 0;
0104
0105
0106 virtual int GetBinIndexAndGrow(const CoordArray_t &x) const = 0;
0107
0108
0109 virtual int GetBinIndexFromLocalBins(const BinArray_t &x) const = 0;
0110
0111 virtual BinArray_t GetLocalBins(int binidx) const = 0;
0112
0113
0114 virtual CoordArray_t GetBinCenter(int binidx) const = 0;
0115
0116 virtual CoordArray_t GetBinFrom(int binidx) const = 0;
0117
0118 virtual CoordArray_t GetBinTo(int binidx) const = 0;
0119
0120
0121 virtual double GetBinUncertainty(int binidx) const = 0;
0122
0123
0124
0125 virtual bool HasBinUncertainty() const = 0;
0126
0127
0128 virtual double GetBinContentAsDouble(int binidx) const = 0;
0129
0130
0131
0132
0133 virtual const RAxisBase &GetAxis(int iAxis) const = 0;
0134
0135
0136
0137 virtual AxisIterRange_t GetRange() const = 0;
0138
0139 private:
0140 std::string fTitle;
0141 };
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151 template <class DATA>
0152 class RHistImplBase: public RHistImplPrecisionAgnosticBase<DATA::GetNDim()> {
0153 public:
0154
0155 using Stat_t = DATA;
0156
0157 using CoordArray_t = Hist::CoordArray_t<DATA::GetNDim()>;
0158
0159 using BinArray_t = std::array<int, DATA::GetNDim()>;
0160
0161 using Weight_t = typename DATA::Weight_t;
0162
0163
0164 using FillFunc_t = void (RHistImplBase::*)(const CoordArray_t &x, Weight_t w);
0165
0166 private:
0167
0168 Stat_t fStatistics;
0169
0170 public:
0171 RHistImplBase() = default;
0172 RHistImplBase(size_t numBins, size_t numOverflowBins): fStatistics(numBins, numOverflowBins) {}
0173 RHistImplBase(std::string_view title, size_t numBins, size_t numOverflowBins)
0174 : RHistImplPrecisionAgnosticBase<DATA::GetNDim()>(title), fStatistics(numBins, numOverflowBins)
0175 {}
0176 RHistImplBase(const RHistImplBase &) = default;
0177 RHistImplBase(RHistImplBase &&) = default;
0178
0179 virtual std::unique_ptr<RHistImplBase> Clone() const = 0;
0180
0181
0182
0183
0184 virtual void FillN(const std::span<const CoordArray_t> xN, const std::span<const Weight_t> weightN) = 0;
0185
0186
0187 virtual void FillN(const std::span<const CoordArray_t> xN) = 0;
0188
0189
0190 virtual FillFunc_t GetFillFunc() const = 0;
0191
0192
0193 virtual Weight_t GetBinContent(const CoordArray_t &x) const = 0;
0194
0195 using RHistImplPrecisionAgnosticBase<DATA::GetNDim()>::GetBinUncertainty;
0196
0197
0198 virtual double GetBinUncertainty(const CoordArray_t &x) const = 0;
0199
0200
0201
0202 int GetNBins() const noexcept final { return fStatistics.size(); }
0203
0204
0205
0206 int GetNBinsNoOver() const noexcept final { return fStatistics.sizeNoOver(); }
0207
0208
0209
0210 int GetNOverflowBins() const noexcept final { return fStatistics.sizeUnderOver(); }
0211
0212
0213 Weight_t GetBinContent(int binidx) const
0214 {
0215 assert(binidx != 0);
0216 return fStatistics[binidx];
0217 }
0218
0219
0220 Weight_t &GetBinContent(int binidx)
0221 {
0222 assert(binidx != 0);
0223 return fStatistics[binidx];
0224 }
0225
0226
0227 const Stat_t &GetStat() const noexcept { return fStatistics; }
0228
0229
0230 Stat_t &GetStat() noexcept { return fStatistics; }
0231
0232
0233
0234 double GetBinContentAsDouble(int binidx) const final { return (double)GetBinContent(binidx); }
0235
0236
0237 void AddBinContent(int binidx, Weight_t w)
0238 {
0239 assert(binidx != 0);
0240 fStatistics[binidx] += w;
0241 }
0242 };
0243 }
0244
0245 namespace Internal {
0246
0247
0248
0249
0250
0251
0252 enum class EBinCoord {
0253 kBinFrom,
0254 kBinCenter,
0255 kBinTo
0256 };
0257
0258
0259 enum class EFindStatus {
0260 kCanGrow,
0261 kValid
0262 };
0263
0264
0265
0266
0267
0268
0269
0270
0271 template <int IDX, class AXISTUPLE>
0272 struct RGetNBinsNoOverCount;
0273
0274 template <class AXES>
0275 struct RGetNBinsNoOverCount<0, AXES> {
0276 int operator()(const AXES &axes) const { return std::get<0>(axes).GetNBinsNoOver(); }
0277 };
0278
0279 template <int I, class AXES>
0280 struct RGetNBinsNoOverCount {
0281 int operator()(const AXES &axes) const { return std::get<I>(axes).GetNBinsNoOver() * RGetNBinsNoOverCount<I - 1, AXES>()(axes); }
0282 };
0283
0284
0285 template <class... AXISCONFIG>
0286 int GetNBinsNoOverFromAxes(AXISCONFIG... axisArgs)
0287 {
0288 using axesTuple = std::tuple<AXISCONFIG...>;
0289 return RGetNBinsNoOverCount<sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...});
0290 }
0291
0292
0293
0294
0295 template <int IDX, class AXISTUPLE>
0296 struct RGetNBinsCount;
0297
0298 template <class AXES>
0299 struct RGetNBinsCount<0, AXES> {
0300 int operator()(const AXES &axes) const { return std::get<0>(axes).GetNBins(); }
0301 };
0302
0303 template <int I, class AXES>
0304 struct RGetNBinsCount {
0305 int operator()(const AXES &axes) const { return std::get<I>(axes).GetNBins() * RGetNBinsCount<I - 1, AXES>()(axes); }
0306 };
0307
0308
0309 template <class... AXISCONFIG>
0310 int GetNBinsFromAxes(AXISCONFIG... axisArgs)
0311 {
0312 using axesTuple = std::tuple<AXISCONFIG...>;
0313 return RGetNBinsCount<sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...});
0314 }
0315
0316
0317 template <class... AXISCONFIG>
0318 int GetNOverflowBinsFromAxes(AXISCONFIG... axisArgs)
0319 {
0320 using axesTuple = std::tuple<AXISCONFIG...>;
0321 return RGetNBinsCount<sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...}) - RGetNBinsNoOverCount<sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...});
0322 }
0323
0324
0325
0326
0327 template <int I, class AXES>
0328 struct RFillIterRange;
0329
0330 template <class AXES>
0331 struct RFillIterRange<-1, AXES> {
0332 void operator()(Hist::AxisIterRange_t<std::tuple_size<AXES>::value> & , const AXES & ) const
0333 {}
0334 };
0335
0336 template <int I, class AXES>
0337 struct RFillIterRange {
0338 void operator()(Hist::AxisIterRange_t<std::tuple_size<AXES>::value> &range, const AXES &axes) const
0339 {
0340 range[0][I] = std::get<I>(axes).begin();
0341 range[1][I] = std::get<I>(axes).end();
0342 RFillIterRange<I - 1, AXES>()(range, axes);
0343 }
0344 };
0345
0346
0347
0348
0349 template <int I, int NDIMS, typename BINS, class AXES>
0350 struct RGetNRegularBinsBefore;
0351
0352 template <int NDIMS, typename BINS, class AXES>
0353 struct RGetNRegularBinsBefore<-1, NDIMS, BINS, AXES> {
0354 void operator()(BINS &, const AXES &) const
0355 {}
0356 };
0357
0358 template <int I, int NDIMS, typename BINS, class AXES>
0359 struct RGetNRegularBinsBefore {
0360 void operator()(BINS &binSizes, const AXES &axes) const
0361 {
0362 constexpr const int thisAxis = NDIMS - I - 1;
0363 binSizes[thisAxis] = binSizes[thisAxis-1] * std::get<thisAxis-1>(axes).GetNBinsNoOver();
0364 RGetNRegularBinsBefore<I - 1, NDIMS, BINS, AXES>()(binSizes, axes);
0365 }
0366 };
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384 template <int I, int NDIMS, typename BINS, class AXES>
0385 struct RComputeGlobalBin;
0386
0387 template <int NDIMS, typename BINS, class AXES>
0388 struct RComputeGlobalBin<-1, NDIMS, BINS, AXES> {
0389 int operator()(int total_regular_bins_before, const AXES &, const BINS &, const BINS &, const BINS &) const
0390 {
0391 return total_regular_bins_before;
0392 }
0393 };
0394
0395 template <int I, int NDIMS, typename BINS, class AXES>
0396 struct RComputeGlobalBin {
0397 int operator()(int total_regular_bins_before, const AXES &axes, const BINS &virtualBins, const BINS &binSizes, const BINS &localBins) const
0398 {
0399
0400
0401 const int num_underflow_bins = static_cast<int>(!std::get<I>(axes).CanGrow());
0402 const int num_regular_bins_before =
0403 std::max(virtualBins[I] - num_underflow_bins, 0);
0404 total_regular_bins_before += num_regular_bins_before * binSizes[I];
0405
0406
0407
0408
0409
0410
0411 if (localBins[I] < 1)
0412 return total_regular_bins_before;
0413
0414 return RComputeGlobalBin<I - 1, NDIMS, BINS, AXES>()(total_regular_bins_before, axes, virtualBins, binSizes, localBins);
0415 }
0416 };
0417
0418
0419
0420
0421 template <int I, int NDIMS, class AXES>
0422 struct RComputeLocalBinsInitialisation;
0423
0424 template <int NDIMS, class AXES>
0425 struct RComputeLocalBinsInitialisation<0, NDIMS, AXES> {
0426 void operator()(std::array<int, NDIMS-1> , std::array<int, NDIMS-1> , const AXES & ) const
0427 {}
0428 };
0429
0430 template <int I, int NDIMS, class AXES>
0431 struct RComputeLocalBinsInitialisation {
0432 void operator()(std::array<int, NDIMS-1>& bins_per_hyperplane, std::array<int, NDIMS-1>& regular_bins_per_hyperplane, const AXES &axes) const
0433 {
0434 constexpr const int thisAxis = NDIMS - I - 1;
0435 bins_per_hyperplane[thisAxis] = Internal::RGetNBinsCount<thisAxis, AXES>()(axes);
0436 regular_bins_per_hyperplane[thisAxis] = Internal::RGetNBinsNoOverCount<thisAxis, AXES>()(axes);
0437 RComputeLocalBinsInitialisation<I - 1, NDIMS, AXES>()(bins_per_hyperplane, regular_bins_per_hyperplane, axes);
0438 }
0439 };
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450 template <int I, int NDIMS, class AXES>
0451 struct RComputeLocalBins;
0452
0453 template <int NDIMS, class AXES>
0454 struct RComputeLocalBins<0, NDIMS, AXES> {
0455 void operator()(const AXES &, int &,
0456 int &, std::array<int, NDIMS-1> ,
0457 std::array<int, NDIMS-1> , int ,
0458 int ) const
0459 {}
0460 };
0461
0462 template <int I, int NDIMS, class AXES>
0463 struct RComputeLocalBins {
0464 void operator()(const AXES &axes, int &unprocessed_previous_overflow_bin,
0465 int &num_regular_bins_before, std::array<int, NDIMS-1> bins_per_hyperplane,
0466 std::array<int, NDIMS-1> regular_bins_per_hyperplane, int curr_bins_per_hyperplane,
0467 int curr_regular_bins_per_hyperplane) const
0468 {
0469
0470
0471 const int num_underflow_hyperplanes =
0472 static_cast<int>(!std::get<I>(axes).CanGrow());
0473 const int bins_in_underflow_hyperplane =
0474 num_underflow_hyperplanes * bins_per_hyperplane[I-1];
0475
0476
0477
0478
0479 const int overflow_bins_per_regular_hyperplane =
0480 bins_per_hyperplane[I-1] - regular_bins_per_hyperplane[I-1];
0481
0482
0483
0484
0485 if (overflow_bins_per_regular_hyperplane != 0) {
0486
0487
0488 const int overflow_bins_in_regular_hyperplanes =
0489 std::min(
0490 std::max(
0491 unprocessed_previous_overflow_bin
0492 - bins_in_underflow_hyperplane,
0493 0
0494 ),
0495 overflow_bins_per_regular_hyperplane
0496 * std::get<I>(axes).GetNBinsNoOver()
0497 );
0498
0499
0500
0501 const int num_regular_hyperplanes_before =
0502 overflow_bins_in_regular_hyperplanes
0503 / overflow_bins_per_regular_hyperplane;
0504 num_regular_bins_before +=
0505 num_regular_hyperplanes_before
0506 * regular_bins_per_hyperplane[I-1];
0507
0508
0509
0510
0511 unprocessed_previous_overflow_bin =
0512 overflow_bins_in_regular_hyperplanes
0513 % overflow_bins_per_regular_hyperplane;
0514 } else {
0515
0516
0517
0518
0519 if (unprocessed_previous_overflow_bin >= bins_in_underflow_hyperplane) {
0520 num_regular_bins_before +=
0521 std::get<I>(axes).GetNBinsNoOver()
0522 * regular_bins_per_hyperplane[I-1];
0523 }
0524
0525
0526
0527
0528
0529 unprocessed_previous_overflow_bin = 0;
0530 }
0531
0532
0533
0534 if (unprocessed_previous_overflow_bin == 0)
0535 return;
0536
0537 return Internal::RComputeLocalBins<I - 1, NDIMS, AXES>()
0538 (axes, unprocessed_previous_overflow_bin, num_regular_bins_before, bins_per_hyperplane,
0539 regular_bins_per_hyperplane, curr_bins_per_hyperplane, curr_regular_bins_per_hyperplane);
0540 }
0541 };
0542
0543
0544
0545
0546
0547
0548
0549 template <int I, int NDIMS, typename BINS, class AXES, class BINTYPE>
0550 struct RComputeLocalBinsRaw;
0551
0552 template <int NDIMS, typename BINS, class AXES, class BINTYPE>
0553 struct RComputeLocalBinsRaw<-1, NDIMS, BINS, AXES, BINTYPE> {
0554 void operator()(BINS & , const AXES & , int , BINTYPE ) const
0555 {}
0556 };
0557
0558 template <int I, int NDIMS, typename BINS, class AXES, class BINTYPE>
0559 struct RComputeLocalBinsRaw {
0560 void operator()(BINS &virtualBins, const AXES &axes, int zeroBasedGlobalBin, BINTYPE GetNBinType) const
0561 {
0562 constexpr const int thisAxis = NDIMS - I - 1;
0563 virtualBins[thisAxis] = zeroBasedGlobalBin % (std::get<thisAxis>(axes).*GetNBinType)();
0564 RComputeLocalBinsRaw<I - 1, NDIMS, BINS, AXES, BINTYPE>()(virtualBins, axes, zeroBasedGlobalBin / (std::get<thisAxis>(axes).*GetNBinType)(), GetNBinType);
0565 }
0566 };
0567
0568
0569
0570
0571
0572
0573
0574 template <int I, int NDIMS, typename BINS, class AXES, class BINTYPE>
0575 struct RComputeGlobalBinRaw;
0576
0577 template <int NDIMS, typename BINS, class AXES, class BINTYPE>
0578 struct RComputeGlobalBinRaw<-1, NDIMS, BINS, AXES, BINTYPE> {
0579 int operator()(int globalVirtualBin, const AXES & , const BINS & , int , BINTYPE ) const
0580 {
0581 return globalVirtualBin;
0582 }
0583 };
0584
0585 template <int I, int NDIMS, typename BINS, class AXES, class BINTYPE>
0586 struct RComputeGlobalBinRaw {
0587 int operator()(int globalVirtualBin, const AXES &axes, const BINS &zeroBasedLocalBins, int binSize, BINTYPE GetNBinType) const
0588 {
0589 constexpr const int thisAxis = NDIMS - I - 1;
0590 globalVirtualBin += zeroBasedLocalBins[thisAxis] * binSize;
0591 binSize *= (std::get<thisAxis>(axes).*GetNBinType)();
0592 return Internal::RComputeGlobalBinRaw<I - 1, NDIMS, BINS, AXES, BINTYPE>()(globalVirtualBin, axes, zeroBasedLocalBins, binSize, GetNBinType);
0593 }
0594 };
0595
0596
0597
0598
0599
0600
0601
0602
0603 template <int I, int NDIMS, typename BINS, class AXES>
0604 struct RVirtualBinsToLocalBins;
0605
0606 template <int NDIMS, typename BINS, class AXES>
0607 struct RVirtualBinsToLocalBins<-1, NDIMS, BINS, AXES> {
0608 void operator()(BINS & , const AXES & , const BINS & ) const
0609 {}
0610 };
0611
0612 template <int I, int NDIMS, typename BINS, class AXES>
0613 struct RVirtualBinsToLocalBins {
0614 void operator()(BINS &localBins, const AXES &axes, const BINS &virtualBins) const
0615 {
0616 constexpr const int thisAxis = NDIMS - I - 1;
0617 if ((!std::get<thisAxis>(axes).CanGrow()) && (virtualBins[thisAxis] == 0)) {
0618 localBins[thisAxis] = RAxisBase::kUnderflowBin;
0619 } else if ((!std::get<thisAxis>(axes).CanGrow()) && (virtualBins[thisAxis] == (std::get<thisAxis>(axes).GetNBins() - 1))) {
0620 localBins[thisAxis] = RAxisBase::kOverflowBin;
0621 } else {
0622 const int regular_bin_offset = -static_cast<int>(std::get<thisAxis>(axes).CanGrow());
0623 localBins[thisAxis] = virtualBins[thisAxis] - regular_bin_offset;
0624 }
0625 RVirtualBinsToLocalBins<I - 1, NDIMS, BINS, AXES>()(localBins, axes, virtualBins);
0626 }
0627 };
0628
0629
0630
0631
0632
0633
0634
0635
0636
0637 template <int I, int NDIMS, typename BINS, class AXES>
0638 struct RLocalBinsToVirtualBins;
0639
0640 template <int NDIMS, typename BINS, class AXES>
0641 struct RLocalBinsToVirtualBins<-1, NDIMS, BINS, AXES> {
0642 void operator()(BINS & , const AXES & , const BINS & ) const
0643 {}
0644 };
0645
0646 template <int I, int NDIMS, typename BINS, class AXES>
0647 struct RLocalBinsToVirtualBins {
0648 void operator()(BINS &virtualBins, const AXES &axes, const BINS &localBins) const
0649 {
0650 constexpr const int thisAxis = NDIMS - I - 1;
0651 switch (localBins[thisAxis]) {
0652 case RAxisBase::kUnderflowBin:
0653 virtualBins[thisAxis] = 0; break;
0654 case RAxisBase::kOverflowBin:
0655 virtualBins[thisAxis] = std::get<thisAxis>(axes).GetNBins() - 1; break;
0656 default:
0657 virtualBins[thisAxis] = localBins[thisAxis] - static_cast<int>(std::get<thisAxis>(axes).CanGrow());
0658 }
0659 RLocalBinsToVirtualBins<I - 1, NDIMS, BINS, AXES>()(virtualBins, axes, localBins);
0660 }
0661 };
0662
0663
0664 template <int I, int NDIMS, typename BINS, typename COORD, class AXES>
0665 struct RFindLocalBins;
0666
0667 template <int NDIMS, typename BINS, typename COORD, class AXES>
0668 struct RFindLocalBins<-1, NDIMS, BINS, COORD, AXES> {
0669 void operator()(BINS & , const AXES & , const COORD & ) const
0670 {}
0671 };
0672
0673 template <int I, int NDIMS, typename BINS, typename COORD, class AXES>
0674 struct RFindLocalBins {
0675 void operator()(BINS &localBins, const AXES &axes, const COORD &coords) const
0676 {
0677 constexpr const int thisAxis = NDIMS - I - 1;
0678 localBins[thisAxis] = std::get<thisAxis>(axes).FindBin(coords[thisAxis]);
0679 RFindLocalBins<I - 1, NDIMS, BINS, COORD, AXES>()(localBins, axes, coords);
0680 }
0681 };
0682
0683
0684
0685 template <int I, int NDIMS, typename BINS, typename COORD, class AXES>
0686 struct RLocalBinsToCoords;
0687
0688 template <int NDIMS, typename BINS, typename COORD, class AXES>
0689 struct RLocalBinsToCoords<-1, NDIMS, BINS, COORD, AXES> {
0690 void operator()(COORD & , const AXES & , const BINS & , EBinCoord ) const
0691 {}
0692 };
0693
0694 template <int I, int NDIMS, typename BINS, typename COORD, class AXES>
0695 struct RLocalBinsToCoords {
0696 void operator()(COORD &coords, const AXES &axes, const BINS &localBins, EBinCoord kind) const
0697 {
0698 constexpr const int thisAxis = NDIMS - I - 1;
0699 int axisbin = localBins[thisAxis];
0700 switch (kind) {
0701 case EBinCoord::kBinFrom: coords[thisAxis] = std::get<thisAxis>(axes).GetBinFrom(axisbin); break;
0702 case EBinCoord::kBinCenter: coords[thisAxis] = std::get<thisAxis>(axes).GetBinCenter(axisbin); break;
0703 case EBinCoord::kBinTo: coords[thisAxis] = std::get<thisAxis>(axes).GetBinTo(axisbin); break;
0704 }
0705 RLocalBinsToCoords<I - 1, NDIMS, BINS, COORD, AXES>()(coords, axes, localBins, kind);
0706 }
0707 };
0708
0709 template <class... AXISCONFIG>
0710 static std::array<const RAxisBase *, sizeof...(AXISCONFIG)> GetAxisView(const AXISCONFIG &... axes) noexcept
0711 {
0712 std::array<const RAxisBase *, sizeof...(AXISCONFIG)> axisViews{{&axes...}};
0713 return axisViews;
0714 }
0715
0716
0717 }
0718
0719 namespace Detail {
0720
0721 template <class DATA, class... AXISCONFIG>
0722 class RHistImpl final: public RHistImplBase<DATA> {
0723 static_assert(sizeof...(AXISCONFIG) == DATA::GetNDim(), "Number of axes must equal histogram dimension");
0724
0725 friend typename DATA::Hist_t;
0726
0727 public:
0728 using ImplBase_t = RHistImplBase<DATA>;
0729 using CoordArray_t = typename ImplBase_t::CoordArray_t;
0730 using BinArray_t = typename ImplBase_t::BinArray_t;
0731 using Weight_t = typename ImplBase_t::Weight_t;
0732 using typename ImplBase_t::FillFunc_t;
0733 template <int NDIMS = DATA::GetNDim()>
0734 using AxisIterRange_t = typename Hist::AxisIterRange_t<NDIMS>;
0735
0736 private:
0737 std::tuple<AXISCONFIG...> fAxes;
0738
0739 public:
0740 RHistImpl(TRootIOCtor *);
0741 RHistImpl(AXISCONFIG... axisArgs);
0742 RHistImpl(std::string_view title, AXISCONFIG... axisArgs);
0743
0744 std::unique_ptr<ImplBase_t> Clone() const override {
0745 return std::unique_ptr<ImplBase_t>(new RHistImpl(*this));
0746 }
0747
0748
0749
0750 FillFunc_t GetFillFunc() const final {
0751 return (FillFunc_t)&RHistImpl::Fill;
0752 }
0753
0754
0755 const std::tuple<AXISCONFIG...> &GetAxes() const { return fAxes; }
0756
0757
0758 const RAxisBase &GetAxis(int iAxis) const final { return *std::apply(Internal::GetAxisView<AXISCONFIG...>, fAxes)[iAxis]; }
0759
0760
0761
0762
0763
0764
0765
0766 template <int NDIMS, typename BINTYPE>
0767 int ComputeGlobalBinRaw(const BinArray_t& zeroBasedLocalBins, BINTYPE GetNBinType) const {
0768 int result = 0;
0769 int binSize = 1;
0770 return Internal::RComputeGlobalBinRaw<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes), BINTYPE>()(result, fAxes, zeroBasedLocalBins, binSize, GetNBinType);
0771 }
0772
0773
0774
0775
0776
0777
0778
0779 template <int NDIMS, typename BINTYPE>
0780 BinArray_t ComputeLocalBinsRaw(int zeroBasedGlobalBin, BINTYPE GetNBinType) const {
0781 BinArray_t result;
0782 Internal::RComputeLocalBinsRaw<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes), BINTYPE>()(result, fAxes, zeroBasedGlobalBin, GetNBinType);
0783 return result;
0784 }
0785
0786
0787
0788
0789
0790 template <int NDIMS>
0791 BinArray_t LocalBinsToVirtualBins(const BinArray_t& localBins) const {
0792 BinArray_t virtualBins;
0793 Internal::RLocalBinsToVirtualBins<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes)>()(virtualBins, fAxes, localBins);
0794 return virtualBins;
0795 }
0796
0797
0798
0799
0800
0801 template <int NDIMS>
0802 BinArray_t VirtualBinsToLocalBins(const BinArray_t& virtualBins) const {
0803 BinArray_t localBins = {};
0804 Internal::RVirtualBinsToLocalBins<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes)>()(localBins, fAxes, virtualBins);
0805 return localBins;
0806 }
0807
0808
0809
0810 template <int NDIMS>
0811 int ComputeGlobalBin(BinArray_t& local_bins) const {
0812
0813 if (std::all_of(local_bins.cbegin(), local_bins.cend(),
0814 [](int bin) { return bin >= 1; })) {
0815 for (int bin = 0; bin < NDIMS; bin++)
0816 local_bins[bin] -= 1;
0817 return ComputeGlobalBinRaw<NDIMS>(local_bins, &ROOT::Experimental::RAxisBase::GetNBinsNoOver) + 1;
0818 }
0819
0820
0821
0822
0823 BinArray_t virtual_bins = LocalBinsToVirtualBins<NDIMS>(local_bins);
0824
0825
0826
0827 const int global_virtual_bin = ComputeGlobalBinRaw<NDIMS>(virtual_bins, &ROOT::Experimental::RAxisBase::GetNBins);
0828
0829
0830 const int neg_1based_virtual_bin = -global_virtual_bin - 1;
0831
0832
0833
0834
0835
0836
0837
0838
0839
0840
0841 int total_regular_bins_before = 0;
0842
0843
0844
0845
0846
0847
0848
0849
0850 BinArray_t bin_sizes;
0851 bin_sizes[0] = 1;
0852 Internal::RGetNRegularBinsBefore<NDIMS - 2, NDIMS, BinArray_t, decltype(fAxes)>()(bin_sizes, fAxes);
0853
0854
0855 total_regular_bins_before = Internal::RComputeGlobalBin<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes)>()
0856 (total_regular_bins_before, fAxes, virtual_bins, bin_sizes, local_bins);
0857
0858
0859
0860
0861 return neg_1based_virtual_bin + total_regular_bins_before;
0862 }
0863
0864
0865
0866 template <int NDIMS>
0867 BinArray_t ComputeLocalBins(int global_bin) const {
0868
0869 if (global_bin >= 1) {
0870 BinArray_t computed_bins = ComputeLocalBinsRaw<NDIMS>(global_bin - 1, &ROOT::Experimental::RAxisBase::GetNBinsNoOver);
0871 for (int bin = 0; bin < NDIMS; ++bin)
0872 computed_bins[bin] += 1;
0873 return computed_bins;
0874 }
0875
0876
0877
0878
0879
0880 const int corrected_virtual_overflow_bin = -global_bin - 1;
0881
0882
0883
0884
0885
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896
0897
0898
0899
0900
0901
0902
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919
0920
0921
0922
0923
0924
0925
0926
0927
0928
0929
0930
0931
0932
0933
0934 std::array<int, NDIMS - 1> bins_per_hyperplane{};
0935 std::array<int, NDIMS - 1> regular_bins_per_hyperplane{};
0936 Internal::RComputeLocalBinsInitialisation<NDIMS - 1, NDIMS, decltype(fAxes)>()(bins_per_hyperplane, regular_bins_per_hyperplane, fAxes);
0937
0938 int curr_bins_per_hyperplane = Internal::RGetNBinsCount<NDIMS - 1, decltype(fAxes)>()(fAxes);
0939 int curr_regular_bins_per_hyperplane = Internal::RGetNBinsNoOverCount<NDIMS - 1, decltype(fAxes)>()(fAxes);
0940
0941
0942 int unprocessed_previous_overflow_bin = corrected_virtual_overflow_bin;
0943 int num_regular_bins_before = 0;
0944 Internal::RComputeLocalBins<NDIMS - 1, NDIMS, decltype(fAxes)>()
0945 (fAxes, unprocessed_previous_overflow_bin, num_regular_bins_before, bins_per_hyperplane,
0946 regular_bins_per_hyperplane, curr_bins_per_hyperplane, curr_regular_bins_per_hyperplane);
0947
0948
0949
0950
0951
0952
0953
0954
0955
0956
0957
0958 num_regular_bins_before +=
0959 unprocessed_previous_overflow_bin * std::get<0>(fAxes).GetNBinsNoOver();
0960
0961
0962
0963
0964
0965 const int global_virtual_bin =
0966 corrected_virtual_overflow_bin + num_regular_bins_before;
0967
0968
0969 const BinArray_t virtual_bins = ComputeLocalBinsRaw<NDIMS>(global_virtual_bin, &ROOT::Experimental::RAxisBase::GetNBins);
0970
0971
0972 return VirtualBinsToLocalBins<NDIMS>(virtual_bins);
0973 }
0974
0975
0976
0977
0978 int GetBinIndex(const CoordArray_t &x) const final
0979 {
0980 BinArray_t localBins = {};
0981 Internal::RFindLocalBins<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(localBins, fAxes, x);
0982 int result = ComputeGlobalBin<DATA::GetNDim()>(localBins);
0983 return result;
0984 }
0985
0986
0987
0988
0989
0990
0991 int GetBinIndexAndGrow(const CoordArray_t &x) const final
0992 {
0993 Internal::EFindStatus status = Internal::EFindStatus::kCanGrow;
0994 int ret = 0;
0995 BinArray_t localBins = {};
0996 while (status == Internal::EFindStatus::kCanGrow) {
0997 Internal::RFindLocalBins<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(localBins, fAxes, x);
0998 ret = ComputeGlobalBin<DATA::GetNDim()>(localBins);
0999 status = Internal::EFindStatus::kValid;
1000 }
1001 return ret;
1002 }
1003
1004
1005
1006 int GetBinIndexFromLocalBins(const BinArray_t &x) const final
1007 {
1008 BinArray_t localBins = x;
1009 int result = ComputeGlobalBin<DATA::GetNDim()>(localBins);
1010 return result;
1011 }
1012
1013
1014
1015 BinArray_t GetLocalBins(int binidx) const final
1016 {
1017 BinArray_t localBins = ComputeLocalBins<DATA::GetNDim()>(binidx);
1018 return localBins;
1019 }
1020
1021
1022 CoordArray_t GetBinCenter(int binidx) const final
1023 {
1024 BinArray_t localBins = ComputeLocalBins<DATA::GetNDim()>(binidx);
1025 CoordArray_t coords;
1026 Internal::RLocalBinsToCoords<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(coords, fAxes, localBins, Internal::EBinCoord::kBinCenter);
1027 return coords;
1028 }
1029
1030
1031 CoordArray_t GetBinFrom(int binidx) const final
1032 {
1033 BinArray_t localBins = ComputeLocalBins<DATA::GetNDim()>(binidx);
1034 CoordArray_t coords;
1035 Internal::RLocalBinsToCoords<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(coords, fAxes, localBins, Internal::EBinCoord::kBinFrom);
1036 return coords;
1037 }
1038
1039
1040 CoordArray_t GetBinTo(int binidx) const final
1041 {
1042 BinArray_t localBins = ComputeLocalBins<DATA::GetNDim()>(binidx);
1043 CoordArray_t coords;
1044 Internal::RLocalBinsToCoords<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(coords, fAxes, localBins, Internal::EBinCoord::kBinTo);
1045 return coords;
1046 }
1047
1048
1049
1050
1051
1052 void FillN(const std::span<const CoordArray_t> xN, const std::span<const Weight_t> weightN) final
1053 {
1054 #ifndef NDEBUG
1055 if (xN.size() != weightN.size()) {
1056 R__LOG_ERROR(HistLog()) << "Not the same number of points and weights!";
1057 return;
1058 }
1059 #endif
1060
1061 for (size_t i = 0; i < xN.size(); ++i) {
1062 Fill(xN[i], weightN[i]);
1063 }
1064 }
1065
1066
1067
1068
1069 void FillN(const std::span<const CoordArray_t> xN) final
1070 {
1071 for (auto &&x: xN) {
1072 Fill(x);
1073 }
1074 }
1075
1076
1077 void Fill(const CoordArray_t &x, Weight_t w = 1.)
1078 {
1079 int bin = GetBinIndexAndGrow(x);
1080 this->GetStat().Fill(x, bin, w);
1081 }
1082
1083
1084 Weight_t GetBinContent(const CoordArray_t &x) const final
1085 {
1086 int bin = GetBinIndex(x);
1087 return ImplBase_t::GetBinContent(bin);
1088 }
1089
1090
1091 double GetBinUncertainty(int binidx) const final { return this->GetStat().GetBinUncertainty(binidx); }
1092
1093
1094 double GetBinUncertainty(const CoordArray_t &x) const final
1095 {
1096 const int bin = GetBinIndex(x);
1097 return this->GetBinUncertainty(bin);
1098 }
1099
1100
1101
1102 bool HasBinUncertainty() const final { return this->GetStat().HasBinUncertainty(); }
1103
1104
1105 AxisIterRange_t<DATA::GetNDim()>
1106 GetRange() const final
1107 {
1108 std::array<std::array<RAxisBase::const_iterator, DATA::GetNDim()>, 2> ret;
1109 Internal::RFillIterRange<DATA::GetNDim() - 1, decltype(fAxes)>()(ret, fAxes);
1110 return ret;
1111 }
1112
1113
1114
1115
1116
1117
1118 void GrowAxis(int , double )
1119 {
1120
1121 }
1122
1123
1124
1125 using const_iterator = RHistBinIter<const ImplBase_t>;
1126 using iterator = RHistBinIter<ImplBase_t>;
1127 iterator begin() noexcept { return iterator(*this); }
1128 const_iterator begin() const noexcept { return const_iterator(*this); }
1129 iterator end() noexcept { return iterator(*this, this->GetNBinsNoOver()); }
1130 const_iterator end() const noexcept { return const_iterator(*this, this->GetNBinsNoOver()); }
1131
1132 };
1133
1134 template <class DATA, class... AXISCONFIG>
1135 RHistImpl<DATA, AXISCONFIG...>::RHistImpl(TRootIOCtor *)
1136 {}
1137
1138 template <class DATA, class... AXISCONFIG>
1139 RHistImpl<DATA, AXISCONFIG...>::RHistImpl(AXISCONFIG... axisArgs)
1140 : ImplBase_t(Internal::GetNBinsNoOverFromAxes(axisArgs...), Internal::GetNOverflowBinsFromAxes(axisArgs...)), fAxes{axisArgs...}
1141 {}
1142
1143 template <class DATA, class... AXISCONFIG>
1144 RHistImpl<DATA, AXISCONFIG...>::RHistImpl(std::string_view title, AXISCONFIG... axisArgs)
1145 : ImplBase_t(title, Internal::GetNBinsNoOverFromAxes(axisArgs...), Internal::GetNOverflowBinsFromAxes(axisArgs...)), fAxes{axisArgs...}
1146 {}
1147
1148 #if 0
1149
1150
1151 template <class DATA>
1152 class RHistImplRuntime: public RHistImplBase<DATA> {
1153 public:
1154 RHistImplRuntime(std::array<RAxisConfig, DATA::GetNDim()>&& axisCfg);
1155 };
1156 #endif
1157
1158 }
1159
1160 }
1161 }
1162
1163 #endif