Warning, file /include/root/ROOT/RDF/ActionHelpers.hxx was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #ifndef ROOT_RDFOPERATIONS
0020 #define ROOT_RDFOPERATIONS
0021
0022 #include "ROOT/RVec.hxx"
0023 #include "ROOT/RDF/Utils.hxx"
0024 #include "ROOT/TypeTraits.hxx"
0025 #include "ROOT/RDF/RDisplay.hxx"
0026 #include "RtypesCore.h"
0027 #include "TH1.h"
0028 #include "TH3.h"
0029 #include "TGraph.h"
0030 #include "TGraphAsymmErrors.h"
0031 #include "TObject.h"
0032 #include "ROOT/RDF/RActionImpl.hxx"
0033 #include "ROOT/RDF/RMergeableValue.hxx"
0034
0035 #include <algorithm>
0036 #include <array>
0037 #include <limits>
0038 #include <memory>
0039 #include <mutex>
0040 #include <stdexcept>
0041 #include <string>
0042 #include <string_view>
0043 #include <type_traits>
0044 #include <utility> // std::index_sequence
0045 #include <vector>
0046 #include <numeric> // std::accumulate in MeanHelper
0047
0048 class TCollection;
0049 class TStatistic;
0050 class TTreeReader;
0051 namespace ROOT::RDF {
0052 class RCutFlowReport;
0053 }
0054
0055
0056
0057 namespace ROOT {
0058 namespace Internal {
0059 namespace RDF {
0060 using namespace ROOT::TypeTraits;
0061 using namespace ROOT::VecOps;
0062 using namespace ROOT::RDF;
0063 using namespace ROOT::Detail::RDF;
0064
0065 using Hist_t = ::TH1D;
0066
0067
0068
0069
0070
0071 template <typename T>
0072 using Results = std::conditional_t<std::is_same<T, bool>::value, std::deque<T>, std::vector<T>>;
0073
0074 template <typename F>
0075 class R__CLING_PTRCHECK(off) ForeachSlotHelper : public RActionImpl<ForeachSlotHelper<F>> {
0076 F fCallable;
0077
0078 public:
0079 using ColumnTypes_t = RemoveFirstParameter_t<typename CallableTraits<F>::arg_types>;
0080 ForeachSlotHelper(F &&f) : fCallable(f) {}
0081 ForeachSlotHelper(ForeachSlotHelper &&) = default;
0082 ForeachSlotHelper(const ForeachSlotHelper &) = delete;
0083
0084 void InitTask(TTreeReader *, unsigned int) {}
0085
0086 template <typename... Args>
0087 void Exec(unsigned int slot, Args &&... args)
0088 {
0089
0090 static_assert(std::is_same<TypeList<std::decay_t<Args>...>, ColumnTypes_t>::value, "");
0091 fCallable(slot, std::forward<Args>(args)...);
0092 }
0093
0094 void Initialize() { }
0095
0096 void Finalize() { }
0097
0098 std::string GetActionName() { return "ForeachSlot"; }
0099 };
0100
0101 class R__CLING_PTRCHECK(off) CountHelper : public RActionImpl<CountHelper> {
0102 std::shared_ptr<ULong64_t> fResultCount;
0103 Results<ULong64_t> fCounts;
0104
0105 public:
0106 using ColumnTypes_t = TypeList<>;
0107 CountHelper(const std::shared_ptr<ULong64_t> &resultCount, const unsigned int nSlots);
0108 CountHelper(CountHelper &&) = default;
0109 CountHelper(const CountHelper &) = delete;
0110 void InitTask(TTreeReader *, unsigned int) {}
0111 void Exec(unsigned int slot);
0112 void Initialize() { }
0113 void Finalize();
0114
0115
0116 std::unique_ptr<RMergeableValueBase> GetMergeableValue() const final
0117 {
0118 return std::make_unique<RMergeableCount>(*fResultCount);
0119 }
0120
0121 ULong64_t &PartialUpdate(unsigned int slot);
0122
0123 std::string GetActionName() { return "Count"; }
0124
0125 CountHelper MakeNew(void *newResult, std::string_view = "nominal")
0126 {
0127 auto &result = *static_cast<std::shared_ptr<ULong64_t> *>(newResult);
0128 return CountHelper(result, fCounts.size());
0129 }
0130 };
0131
0132 template <typename RNode_t>
0133 class R__CLING_PTRCHECK(off) ReportHelper : public RActionImpl<ReportHelper<RNode_t>> {
0134 std::shared_ptr<RCutFlowReport> fReport;
0135
0136
0137 RNode_t *fNode;
0138 bool fReturnEmptyReport;
0139
0140 public:
0141 using ColumnTypes_t = TypeList<>;
0142 ReportHelper(const std::shared_ptr<RCutFlowReport> &report, RNode_t *node, bool emptyRep)
0143 : fReport(report), fNode(node), fReturnEmptyReport(emptyRep){};
0144 ReportHelper(ReportHelper &&) = default;
0145 ReportHelper(const ReportHelper &) = delete;
0146 void InitTask(TTreeReader *, unsigned int) {}
0147 void Exec(unsigned int ) {}
0148 void Initialize() { }
0149 void Finalize()
0150 {
0151 if (!fReturnEmptyReport)
0152 fNode->Report(*fReport);
0153 }
0154
0155 std::string GetActionName() { return "Report"; }
0156
0157 ReportHelper MakeNew(void *newResult, std::string_view variation = "nominal")
0158 {
0159 auto &&result = *static_cast<std::shared_ptr<RCutFlowReport> *>(newResult);
0160 return ReportHelper{result,
0161 std::static_pointer_cast<RNode_t>(fNode->GetVariedFilter(std::string(variation))).get(),
0162 fReturnEmptyReport};
0163 }
0164 };
0165
0166
0167
0168
0169
0170
0171
0172
0173 class R__CLING_PTRCHECK(off) BufferedFillHelper : public RActionImpl<BufferedFillHelper> {
0174
0175 static constexpr unsigned int fgTotalBufSize = 2097152;
0176 using BufEl_t = double;
0177 using Buf_t = std::vector<BufEl_t>;
0178
0179 std::vector<Buf_t> fBuffers;
0180 std::vector<Buf_t> fWBuffers;
0181 std::shared_ptr<Hist_t> fResultHist;
0182 unsigned int fNSlots;
0183 unsigned int fBufSize;
0184
0185 Results<std::unique_ptr<Hist_t>> fPartialHists;
0186 Buf_t fMin;
0187 Buf_t fMax;
0188
0189 void UpdateMinMax(unsigned int slot, double v);
0190
0191 public:
0192 BufferedFillHelper(const std::shared_ptr<Hist_t> &h, const unsigned int nSlots);
0193 BufferedFillHelper(BufferedFillHelper &&) = default;
0194 BufferedFillHelper(const BufferedFillHelper &) = delete;
0195 void InitTask(TTreeReader *, unsigned int) {}
0196 void Exec(unsigned int slot, double v);
0197 void Exec(unsigned int slot, double v, double w);
0198
0199 template <typename T, std::enable_if_t<IsDataContainer<T>::value, int> = 0>
0200 void Exec(unsigned int slot, const T &vs)
0201 {
0202 auto &thisBuf = fBuffers[slot];
0203
0204 for (auto v = vs.begin(); v != vs.end(); ++v) {
0205 UpdateMinMax(slot, *v);
0206 thisBuf.emplace_back(*v);
0207 }
0208 }
0209
0210 template <typename T, typename W, std::enable_if_t<IsDataContainer<T>::value && IsDataContainer<W>::value, int> = 0>
0211 void Exec(unsigned int slot, const T &vs, const W &ws)
0212 {
0213 auto &thisBuf = fBuffers[slot];
0214
0215 for (auto &v : vs) {
0216 UpdateMinMax(slot, v);
0217 thisBuf.emplace_back(v);
0218 }
0219
0220 auto &thisWBuf = fWBuffers[slot];
0221 for (auto &w : ws) {
0222 thisWBuf.emplace_back(w);
0223 }
0224 }
0225
0226 template <typename T, typename W, std::enable_if_t<IsDataContainer<T>::value && !IsDataContainer<W>::value, int> = 0>
0227 void Exec(unsigned int slot, const T &vs, const W w)
0228 {
0229 auto &thisBuf = fBuffers[slot];
0230 for (auto &v : vs) {
0231 UpdateMinMax(slot, v);
0232 thisBuf.emplace_back(v);
0233 }
0234
0235 auto &thisWBuf = fWBuffers[slot];
0236 thisWBuf.insert(thisWBuf.end(), vs.size(), w);
0237 }
0238
0239 template <typename T, typename W, std::enable_if_t<IsDataContainer<W>::value && !IsDataContainer<T>::value, int> = 0>
0240 void Exec(unsigned int slot, const T v, const W &ws)
0241 {
0242 UpdateMinMax(slot, v);
0243 auto &thisBuf = fBuffers[slot];
0244 thisBuf.insert(thisBuf.end(), ws.size(), v);
0245
0246 auto &thisWBuf = fWBuffers[slot];
0247 thisWBuf.insert(thisWBuf.end(), ws.begin(), ws.end());
0248 }
0249
0250 Hist_t &PartialUpdate(unsigned int);
0251
0252 void Initialize() { }
0253
0254 void Finalize();
0255
0256
0257 std::unique_ptr<RMergeableValueBase> GetMergeableValue() const final
0258 {
0259 return std::make_unique<RMergeableFill<Hist_t>>(*fResultHist);
0260 }
0261
0262 std::string GetActionName()
0263 {
0264 return std::string(fResultHist->IsA()->GetName()) + "\\n" + std::string(fResultHist->GetName());
0265 }
0266
0267 BufferedFillHelper MakeNew(void *newResult, std::string_view = "nominal")
0268 {
0269 auto &result = *static_cast<std::shared_ptr<Hist_t> *>(newResult);
0270 result->Reset();
0271 result->SetDirectory(nullptr);
0272 return BufferedFillHelper(result, fNSlots);
0273 }
0274 };
0275
0276
0277 template <typename T>
0278 class ScalarConstIterator {
0279 const T *obj_;
0280
0281 public:
0282 using iterator_category = std::forward_iterator_tag;
0283 using difference_type = std::ptrdiff_t;
0284 using value_type = T;
0285 using pointer = T *;
0286 using reference = T &;
0287 ScalarConstIterator(const T *obj) : obj_(obj) {}
0288 const T &operator*() const { return *obj_; }
0289 ScalarConstIterator<T> &operator++() { return *this; }
0290 };
0291
0292
0293 template <typename T>
0294 auto MakeBegin(const T &val)
0295 {
0296 if constexpr (IsDataContainer<T>::value) {
0297 return std::begin(val);
0298 } else {
0299 return ScalarConstIterator<T>(&val);
0300 }
0301 }
0302
0303
0304 template <typename T>
0305 std::size_t GetSize(const T &val)
0306 {
0307 if constexpr (IsDataContainer<T>::value) {
0308 return std::size(val);
0309 } else {
0310 return 1;
0311 }
0312 }
0313
0314
0315 template <typename H, typename = decltype(std::declval<H>().Reset())>
0316 void ResetIfPossible(H *h)
0317 {
0318 h->Reset();
0319 }
0320
0321 void ResetIfPossible(TStatistic *h);
0322 void ResetIfPossible(...);
0323
0324 void UnsetDirectoryIfPossible(TH1 *h);
0325 void UnsetDirectoryIfPossible(...);
0326
0327
0328
0329 template <typename HIST = Hist_t>
0330 class R__CLING_PTRCHECK(off) FillHelper : public RActionImpl<FillHelper<HIST>> {
0331 std::vector<HIST *> fObjects;
0332
0333
0334 template <typename H, typename = std::enable_if_t<std::is_base_of<TObject, H>::value, int>>
0335 auto Merge(std::vector<H *> &objs, int )
0336 -> decltype(objs[0]->Merge((TCollection *)nullptr), void())
0337 {
0338 TList l;
0339 for (auto it = ++objs.begin(); it != objs.end(); ++it)
0340 l.Add(*it);
0341 objs[0]->Merge(&l);
0342 }
0343
0344
0345 template <typename H>
0346 auto Merge(std::vector<H *> &objs, double )
0347 -> decltype(objs[0]->Merge(std::vector<HIST *>{}), void())
0348 {
0349 objs[0]->Merge({++objs.begin(), objs.end()});
0350 }
0351
0352
0353 template <typename T>
0354 void Merge(T, ...)
0355 {
0356 static_assert(sizeof(T) < 0,
0357 "The type passed to Fill does not provide a Merge(TCollection*) or Merge(const std::vector&) method.");
0358 }
0359
0360 template <std::size_t ColIdx, typename End_t, typename... Its>
0361 void ExecLoop(unsigned int slot, End_t end, Its... its)
0362 {
0363 for (auto *thisSlotH = fObjects[slot]; GetNthElement<ColIdx>(its...) != end; (std::advance(its, 1), ...)) {
0364 thisSlotH->Fill(*its...);
0365 }
0366 }
0367
0368 public:
0369 FillHelper(FillHelper &&) = default;
0370 FillHelper(const FillHelper &) = delete;
0371
0372 FillHelper(const std::shared_ptr<HIST> &h, const unsigned int nSlots) : fObjects(nSlots, nullptr)
0373 {
0374 fObjects[0] = h.get();
0375
0376 for (unsigned int i = 1; i < nSlots; ++i) {
0377 fObjects[i] = new HIST(*fObjects[0]);
0378 UnsetDirectoryIfPossible(fObjects[i]);
0379 }
0380 }
0381
0382 void InitTask(TTreeReader *, unsigned int) {}
0383
0384
0385 template <typename... ValTypes, std::enable_if_t<!Disjunction<IsDataContainer<ValTypes>...>::value, int> = 0>
0386 auto Exec(unsigned int slot, const ValTypes &...x) -> decltype(fObjects[slot]->Fill(x...), void())
0387 {
0388 fObjects[slot]->Fill(x...);
0389 }
0390
0391
0392 template <typename... Xs, std::enable_if_t<Disjunction<IsDataContainer<Xs>...>::value, int> = 0>
0393 auto Exec(unsigned int slot, const Xs &...xs) -> decltype(fObjects[slot]->Fill(*MakeBegin(xs)...), void())
0394 {
0395
0396 constexpr std::array<bool, sizeof...(Xs)> isContainer{IsDataContainer<Xs>::value...};
0397
0398
0399 constexpr std::size_t colidx = FindIdxTrue(isContainer);
0400
0401 static_assert(colidx < sizeof...(Xs), "Error: index of collection-type argument not found.");
0402
0403
0404 auto const xrefend = std::end(GetNthElement<colidx>(xs...));
0405
0406
0407 std::array<std::size_t, sizeof...(xs)> sizes = {{GetSize(xs)...}};
0408
0409 for (std::size_t i = 0; i < sizeof...(xs); ++i) {
0410 if (isContainer[i] && sizes[i] != sizes[colidx]) {
0411 throw std::runtime_error("Cannot fill histogram with values in containers of different sizes.");
0412 }
0413 }
0414
0415 ExecLoop<colidx>(slot, xrefend, MakeBegin(xs)...);
0416 }
0417
0418 template <typename T = HIST>
0419 void Exec(...)
0420 {
0421 static_assert(sizeof(T) < 0,
0422 "When filling an object with RDataFrame (e.g. via a Fill action) the number or types of the "
0423 "columns passed did not match the signature of the object's `Fill` method.");
0424 }
0425
0426 void Initialize() { }
0427
0428 void Finalize()
0429 {
0430 if (fObjects.size() == 1)
0431 return;
0432
0433 Merge(fObjects, 0);
0434
0435
0436 for (auto it = ++fObjects.begin(); it != fObjects.end(); ++it)
0437 delete *it;
0438 }
0439
0440 HIST &PartialUpdate(unsigned int slot) { return *fObjects[slot]; }
0441
0442
0443 std::unique_ptr<RMergeableValueBase> GetMergeableValue() const final
0444 {
0445 return std::make_unique<RMergeableFill<HIST>>(*fObjects[0]);
0446 }
0447
0448
0449 template <typename T = HIST, std::enable_if_t<std::is_base_of<TObject, T>::value, int> = 0>
0450 std::string GetActionName()
0451 {
0452 return std::string(fObjects[0]->IsA()->GetName()) + "\\n" + std::string(fObjects[0]->GetName());
0453 }
0454
0455
0456 template <typename T = HIST, std::enable_if_t<!std::is_base_of<TObject, T>::value, int> = 0>
0457 std::string GetActionName()
0458 {
0459 return "Fill custom object";
0460 }
0461
0462 template <typename H = HIST>
0463 FillHelper MakeNew(void *newResult, std::string_view = "nominal")
0464 {
0465 auto &result = *static_cast<std::shared_ptr<H> *>(newResult);
0466 ResetIfPossible(result.get());
0467 UnsetDirectoryIfPossible(result.get());
0468 return FillHelper(result, fObjects.size());
0469 }
0470 };
0471
0472 class R__CLING_PTRCHECK(off) FillTGraphHelper : public ROOT::Detail::RDF::RActionImpl<FillTGraphHelper> {
0473 public:
0474 using Result_t = ::TGraph;
0475
0476 private:
0477 std::vector<::TGraph *> fGraphs;
0478
0479 public:
0480 FillTGraphHelper(FillTGraphHelper &&) = default;
0481 FillTGraphHelper(const FillTGraphHelper &) = delete;
0482
0483 FillTGraphHelper(const std::shared_ptr<::TGraph> &g, const unsigned int nSlots) : fGraphs(nSlots, nullptr)
0484 {
0485 fGraphs[0] = g.get();
0486
0487 for (unsigned int i = 1; i < nSlots; ++i) {
0488 fGraphs[i] = new TGraph(*fGraphs[0]);
0489 }
0490 }
0491
0492 void Initialize() {}
0493 void InitTask(TTreeReader *, unsigned int) {}
0494
0495
0496 template <typename X0, typename X1,
0497 std::enable_if_t<IsDataContainer<X0>::value && IsDataContainer<X1>::value, int> = 0>
0498 void Exec(unsigned int slot, const X0 &x0s, const X1 &x1s)
0499 {
0500 if (x0s.size() != x1s.size()) {
0501 throw std::runtime_error("Cannot fill Graph with values in containers of different sizes.");
0502 }
0503 auto *thisSlotG = fGraphs[slot];
0504 auto x0sIt = std::begin(x0s);
0505 const auto x0sEnd = std::end(x0s);
0506 auto x1sIt = std::begin(x1s);
0507 for (; x0sIt != x0sEnd; x0sIt++, x1sIt++) {
0508 thisSlotG->SetPoint(thisSlotG->GetN(), *x0sIt, *x1sIt);
0509 }
0510 }
0511
0512
0513 template <typename X0, typename X1,
0514 std::enable_if_t<!IsDataContainer<X0>::value && !IsDataContainer<X1>::value, int> = 0>
0515 void Exec(unsigned int slot, X0 x0, X1 x1)
0516 {
0517 auto thisSlotG = fGraphs[slot];
0518 thisSlotG->SetPoint(thisSlotG->GetN(), x0, x1);
0519 }
0520
0521
0522
0523 template <typename X0, typename X1, typename... ExtraArgsToLowerPriority>
0524 void Exec(unsigned int, X0, X1, ExtraArgsToLowerPriority...)
0525 {
0526 throw std::runtime_error("Graph was applied to a mix of scalar values and collections. This is not supported.");
0527 }
0528
0529 void Finalize()
0530 {
0531 const auto nSlots = fGraphs.size();
0532 auto resGraph = fGraphs[0];
0533 TList l;
0534 l.SetOwner();
0535 for (unsigned int slot = 1; slot < nSlots; ++slot) {
0536 l.Add(fGraphs[slot]);
0537 }
0538 resGraph->Merge(&l);
0539 }
0540
0541
0542 std::unique_ptr<RMergeableValueBase> GetMergeableValue() const final
0543 {
0544 return std::make_unique<RMergeableFill<Result_t>>(*fGraphs[0]);
0545 }
0546
0547 std::string GetActionName() { return "Graph"; }
0548
0549 Result_t &PartialUpdate(unsigned int slot) { return *fGraphs[slot]; }
0550
0551 FillTGraphHelper MakeNew(void *newResult, std::string_view = "nominal")
0552 {
0553 auto &result = *static_cast<std::shared_ptr<TGraph> *>(newResult);
0554 result->Set(0);
0555 return FillTGraphHelper(result, fGraphs.size());
0556 }
0557 };
0558
0559 class R__CLING_PTRCHECK(off) FillTGraphAsymmErrorsHelper
0560 : public ROOT::Detail::RDF::RActionImpl<FillTGraphAsymmErrorsHelper> {
0561 public:
0562 using Result_t = ::TGraphAsymmErrors;
0563
0564 private:
0565 std::vector<::TGraphAsymmErrors *> fGraphAsymmErrors;
0566
0567 public:
0568 FillTGraphAsymmErrorsHelper(FillTGraphAsymmErrorsHelper &&) = default;
0569 FillTGraphAsymmErrorsHelper(const FillTGraphAsymmErrorsHelper &) = delete;
0570
0571 FillTGraphAsymmErrorsHelper(const std::shared_ptr<::TGraphAsymmErrors> &g, const unsigned int nSlots)
0572 : fGraphAsymmErrors(nSlots, nullptr)
0573 {
0574 fGraphAsymmErrors[0] = g.get();
0575
0576 for (unsigned int i = 1; i < nSlots; ++i) {
0577 fGraphAsymmErrors[i] = new TGraphAsymmErrors(*fGraphAsymmErrors[0]);
0578 }
0579 }
0580
0581 void Initialize() {}
0582 void InitTask(TTreeReader *, unsigned int) {}
0583
0584
0585 template <
0586 typename X, typename Y, typename EXL, typename EXH, typename EYL, typename EYH,
0587 std::enable_if_t<IsDataContainer<X>::value && IsDataContainer<Y>::value && IsDataContainer<EXL>::value &&
0588 IsDataContainer<EXH>::value && IsDataContainer<EYL>::value && IsDataContainer<EYH>::value,
0589 int> = 0>
0590 void
0591 Exec(unsigned int slot, const X &xs, const Y &ys, const EXL &exls, const EXH &exhs, const EYL &eyls, const EYH &eyhs)
0592 {
0593 if ((xs.size() != ys.size()) || (xs.size() != exls.size()) || (xs.size() != exhs.size()) ||
0594 (xs.size() != eyls.size()) || (xs.size() != eyhs.size())) {
0595 throw std::runtime_error("Cannot fill GraphAsymmErrors with values in containers of different sizes.");
0596 }
0597 auto *thisSlotG = fGraphAsymmErrors[slot];
0598 auto xsIt = std::begin(xs);
0599 auto ysIt = std::begin(ys);
0600 auto exlsIt = std::begin(exls);
0601 auto exhsIt = std::begin(exhs);
0602 auto eylsIt = std::begin(eyls);
0603 auto eyhsIt = std::begin(eyhs);
0604 while (xsIt != std::end(xs)) {
0605 const auto n = thisSlotG->GetN();
0606 thisSlotG->SetPoint(n, *xsIt++, *ysIt++);
0607 thisSlotG->SetPointError(n, *exlsIt++, *exhsIt++, *eylsIt++, *eyhsIt++);
0608 }
0609 }
0610
0611
0612 template <
0613 typename X, typename Y, typename EXL, typename EXH, typename EYL, typename EYH,
0614 std::enable_if_t<!IsDataContainer<X>::value && !IsDataContainer<Y>::value && !IsDataContainer<EXL>::value &&
0615 !IsDataContainer<EXH>::value && !IsDataContainer<EYL>::value && !IsDataContainer<EYH>::value,
0616 int> = 0>
0617 void Exec(unsigned int slot, X x, Y y, EXL exl, EXH exh, EYL eyl, EYH eyh)
0618 {
0619 auto thisSlotG = fGraphAsymmErrors[slot];
0620 const auto n = thisSlotG->GetN();
0621 thisSlotG->SetPoint(n, x, y);
0622 thisSlotG->SetPointError(n, exl, exh, eyl, eyh);
0623 }
0624
0625
0626
0627 template <typename X, typename Y, typename EXL, typename EXH, typename EYL, typename EYH,
0628 typename... ExtraArgsToLowerPriority>
0629 void Exec(unsigned int, X, Y, EXL, EXH, EYL, EYH, ExtraArgsToLowerPriority...)
0630 {
0631 throw std::runtime_error(
0632 "GraphAsymmErrors was applied to a mix of scalar values and collections. This is not supported.");
0633 }
0634
0635 void Finalize()
0636 {
0637 const auto nSlots = fGraphAsymmErrors.size();
0638 auto resGraphAsymmErrors = fGraphAsymmErrors[0];
0639 TList l;
0640 l.SetOwner();
0641 for (unsigned int slot = 1; slot < nSlots; ++slot) {
0642 l.Add(fGraphAsymmErrors[slot]);
0643 }
0644 resGraphAsymmErrors->Merge(&l);
0645 }
0646
0647
0648 std::unique_ptr<RMergeableValueBase> GetMergeableValue() const final
0649 {
0650 return std::make_unique<RMergeableFill<Result_t>>(*fGraphAsymmErrors[0]);
0651 }
0652
0653 std::string GetActionName() { return "GraphAsymmErrors"; }
0654
0655 Result_t &PartialUpdate(unsigned int slot) { return *fGraphAsymmErrors[slot]; }
0656
0657 FillTGraphAsymmErrorsHelper MakeNew(void *newResult, std::string_view = "nominal")
0658 {
0659 auto &result = *static_cast<std::shared_ptr<TGraphAsymmErrors> *>(newResult);
0660 result->Set(0);
0661 return FillTGraphAsymmErrorsHelper(result, fGraphAsymmErrors.size());
0662 }
0663 };
0664
0665
0666 template <typename HIST>
0667 class R__CLING_PTRCHECK(off) ThreadSafeFillHelper : public RActionImpl<ThreadSafeFillHelper<HIST>> {
0668 std::vector<std::shared_ptr<HIST>> fObjects;
0669 std::vector<std::unique_ptr<std::mutex>> fMutexPtrs;
0670
0671
0672 template <typename T, typename... Args>
0673 auto TryCallFillThreadSafe(T &object, std::mutex &, int , Args... args)
0674 -> decltype(ROOT::Internal::FillThreadSafe(object, args...), void())
0675 {
0676 ROOT::Internal::FillThreadSafe(object, args...);
0677 }
0678
0679 template <typename T, typename... Args>
0680 auto TryCallFillThreadSafe(T &object, std::mutex &mutex, char , Args... args)
0681 {
0682 std::scoped_lock lock{mutex};
0683 object.Fill(args...);
0684 }
0685
0686 template <std::size_t ColIdx, typename End_t, typename... Its>
0687 void ExecLoop(unsigned int slot, End_t end, Its... its)
0688 {
0689 const auto localSlot = slot % fObjects.size();
0690 for (; GetNthElement<ColIdx>(its...) != end; (std::advance(its, 1), ...)) {
0691 TryCallFillThreadSafe(*fObjects[localSlot], *fMutexPtrs[localSlot], 0, *its...);
0692 }
0693 }
0694
0695 public:
0696 ThreadSafeFillHelper(ThreadSafeFillHelper &&) = default;
0697 ThreadSafeFillHelper(const ThreadSafeFillHelper &) = delete;
0698
0699 ThreadSafeFillHelper(const std::shared_ptr<HIST> &h, const unsigned int nSlots)
0700 {
0701 fObjects.resize(nSlots);
0702 fObjects.front() = h;
0703
0704 std::generate(fObjects.begin() + 1, fObjects.end(), [h]() {
0705 auto hist = std::make_shared<HIST>(*h);
0706 UnsetDirectoryIfPossible(hist.get());
0707 return hist;
0708 });
0709 fMutexPtrs.resize(nSlots);
0710 std::generate(fMutexPtrs.begin(), fMutexPtrs.end(), []() { return std::make_unique<std::mutex>(); });
0711 }
0712
0713 void InitTask(TTreeReader *, unsigned int) {}
0714
0715
0716 template <typename... ValTypes, std::enable_if_t<!Disjunction<IsDataContainer<ValTypes>...>::value, int> = 0>
0717 void Exec(unsigned int slot, const ValTypes &...x)
0718 {
0719 const auto localSlot = slot % fObjects.size();
0720 TryCallFillThreadSafe(*fObjects[localSlot], *fMutexPtrs[localSlot], 0, x...);
0721 }
0722
0723
0724 template <typename... Xs, std::enable_if_t<Disjunction<IsDataContainer<Xs>...>::value, int> = 0>
0725 void Exec(unsigned int slot, const Xs &...xs)
0726 {
0727
0728 constexpr std::array<bool, sizeof...(Xs)> isContainer{IsDataContainer<Xs>::value...};
0729
0730
0731 constexpr std::size_t colidx = FindIdxTrue(isContainer);
0732
0733 static_assert(colidx < sizeof...(Xs), "Error: index of collection-type argument not found.");
0734
0735
0736 auto const xrefend = std::end(GetNthElement<colidx>(xs...));
0737
0738
0739 std::array<std::size_t, sizeof...(xs)> sizes = {{GetSize(xs)...}};
0740
0741 for (std::size_t i = 0; i < sizeof...(xs); ++i) {
0742 if (isContainer[i] && sizes[i] != sizes[colidx]) {
0743 throw std::runtime_error("Cannot fill histogram with values in containers of different sizes.");
0744 }
0745 }
0746
0747 ExecLoop<colidx>(slot, xrefend, MakeBegin(xs)...);
0748 }
0749
0750 template <typename T = HIST>
0751 void Exec(...)
0752 {
0753 static_assert(sizeof(T) < 0,
0754 "When filling an object with RDataFrame (e.g. via a Fill action) the number or types of the "
0755 "columns passed did not match the signature of the object's `FillThreadSafe` method.");
0756 }
0757
0758 void Initialize() { }
0759
0760 void Finalize()
0761 {
0762 if (fObjects.size() > 1) {
0763 TList list;
0764 for (auto it = fObjects.cbegin() + 1; it != fObjects.end(); ++it) {
0765 list.Add(it->get());
0766 }
0767 fObjects[0]->Merge(&list);
0768 }
0769
0770 fObjects.resize(1);
0771 fMutexPtrs.clear();
0772 }
0773
0774
0775 std::unique_ptr<RMergeableValueBase> GetMergeableValue() const final
0776 {
0777 return std::make_unique<RMergeableFill<HIST>>(*fObjects[0]);
0778 }
0779
0780
0781 template <typename T = HIST, std::enable_if_t<std::is_base_of<TObject, T>::value, int> = 0>
0782 std::string GetActionName()
0783 {
0784 return std::string(fObjects[0]->IsA()->GetName()) + "\\n" + std::string(fObjects[0]->GetName());
0785 }
0786
0787 template <typename H = HIST>
0788 ThreadSafeFillHelper MakeNew(void *newResult, std::string_view = "nominal")
0789 {
0790 auto &result = *static_cast<std::shared_ptr<H> *>(newResult);
0791 ResetIfPossible(result.get());
0792 UnsetDirectoryIfPossible(result.get());
0793 return ThreadSafeFillHelper(result, fObjects.size());
0794 }
0795 };
0796
0797
0798
0799
0800
0801
0802
0803 template <typename V, typename COLL>
0804 void FillColl(V&& v, COLL& c) {
0805 c.emplace_back(v);
0806 }
0807
0808
0809 template <typename COLL>
0810 void FillColl(bool v, COLL& c) {
0811 c.push_back(v);
0812 }
0813
0814
0815
0816 template <typename RealT_t, typename T, typename COLL>
0817 class R__CLING_PTRCHECK(off) TakeHelper : public RActionImpl<TakeHelper<RealT_t, T, COLL>> {
0818 Results<std::shared_ptr<COLL>> fColls;
0819
0820 public:
0821 using ColumnTypes_t = TypeList<T>;
0822 TakeHelper(const std::shared_ptr<COLL> &resultColl, const unsigned int nSlots)
0823 {
0824 fColls.emplace_back(resultColl);
0825 for (unsigned int i = 1; i < nSlots; ++i)
0826 fColls.emplace_back(std::make_shared<COLL>());
0827 }
0828 TakeHelper(TakeHelper &&);
0829 TakeHelper(const TakeHelper &) = delete;
0830
0831 void InitTask(TTreeReader *, unsigned int) {}
0832
0833 void Exec(unsigned int slot, T &v) { FillColl(v, *fColls[slot]); }
0834
0835 void Initialize() { }
0836
0837 void Finalize()
0838 {
0839 auto rColl = fColls[0];
0840 for (unsigned int i = 1; i < fColls.size(); ++i) {
0841 const auto &coll = fColls[i];
0842 const auto end = coll->end();
0843
0844
0845 for (auto j = coll->begin(); j != end; j++) {
0846 FillColl(*j, *rColl);
0847 }
0848 }
0849 }
0850
0851 COLL &PartialUpdate(unsigned int slot) { return *fColls[slot].get(); }
0852
0853 std::string GetActionName() { return "Take"; }
0854
0855 TakeHelper MakeNew(void *newResult, std::string_view = "nominal")
0856 {
0857 auto &result = *static_cast<std::shared_ptr<COLL> *>(newResult);
0858 result->clear();
0859 return TakeHelper(result, fColls.size());
0860 }
0861 };
0862
0863
0864
0865 template <typename RealT_t, typename T>
0866 class R__CLING_PTRCHECK(off) TakeHelper<RealT_t, T, std::vector<T>>
0867 : public RActionImpl<TakeHelper<RealT_t, T, std::vector<T>>> {
0868 Results<std::shared_ptr<std::vector<T>>> fColls;
0869
0870 public:
0871 using ColumnTypes_t = TypeList<T>;
0872 TakeHelper(const std::shared_ptr<std::vector<T>> &resultColl, const unsigned int nSlots)
0873 {
0874 fColls.emplace_back(resultColl);
0875 for (unsigned int i = 1; i < nSlots; ++i) {
0876 auto v = std::make_shared<std::vector<T>>();
0877 v->reserve(1024);
0878 fColls.emplace_back(v);
0879 }
0880 }
0881 TakeHelper(TakeHelper &&);
0882 TakeHelper(const TakeHelper &) = delete;
0883
0884 void InitTask(TTreeReader *, unsigned int) {}
0885
0886 void Exec(unsigned int slot, T &v) { FillColl(v, *fColls[slot]); }
0887
0888 void Initialize() { }
0889
0890
0891 void Finalize()
0892 {
0893 ULong64_t totSize = 0;
0894 for (auto &coll : fColls)
0895 totSize += coll->size();
0896 auto rColl = fColls[0];
0897 rColl->reserve(totSize);
0898 for (unsigned int i = 1; i < fColls.size(); ++i) {
0899 auto &coll = fColls[i];
0900 rColl->insert(rColl->end(), coll->begin(), coll->end());
0901 }
0902 }
0903
0904 std::vector<T> &PartialUpdate(unsigned int slot) { return *fColls[slot]; }
0905
0906 std::string GetActionName() { return "Take"; }
0907
0908 TakeHelper MakeNew(void *newResult, std::string_view = "nominal")
0909 {
0910 auto &result = *static_cast<std::shared_ptr<std::vector<T>> *>(newResult);
0911 result->clear();
0912 return TakeHelper(result, fColls.size());
0913 }
0914 };
0915
0916
0917
0918 template <typename RealT_t, typename COLL>
0919 class R__CLING_PTRCHECK(off) TakeHelper<RealT_t, RVec<RealT_t>, COLL>
0920 : public RActionImpl<TakeHelper<RealT_t, RVec<RealT_t>, COLL>> {
0921 Results<std::shared_ptr<COLL>> fColls;
0922
0923 public:
0924 using ColumnTypes_t = TypeList<RVec<RealT_t>>;
0925 TakeHelper(const std::shared_ptr<COLL> &resultColl, const unsigned int nSlots)
0926 {
0927 fColls.emplace_back(resultColl);
0928 for (unsigned int i = 1; i < nSlots; ++i)
0929 fColls.emplace_back(std::make_shared<COLL>());
0930 }
0931 TakeHelper(TakeHelper &&);
0932 TakeHelper(const TakeHelper &) = delete;
0933
0934 void InitTask(TTreeReader *, unsigned int) {}
0935
0936 void Exec(unsigned int slot, RVec<RealT_t> av) { fColls[slot]->emplace_back(av.begin(), av.end()); }
0937
0938 void Initialize() { }
0939
0940 void Finalize()
0941 {
0942 auto rColl = fColls[0];
0943 for (unsigned int i = 1; i < fColls.size(); ++i) {
0944 auto &coll = fColls[i];
0945 for (auto &v : *coll) {
0946 rColl->emplace_back(v);
0947 }
0948 }
0949 }
0950
0951 std::string GetActionName() { return "Take"; }
0952
0953 TakeHelper MakeNew(void *newResult, std::string_view = "nominal")
0954 {
0955 auto &result = *static_cast<std::shared_ptr<COLL> *>(newResult);
0956 result->clear();
0957 return TakeHelper(result, fColls.size());
0958 }
0959 };
0960
0961
0962
0963 template <typename RealT_t>
0964 class R__CLING_PTRCHECK(off) TakeHelper<RealT_t, RVec<RealT_t>, std::vector<RealT_t>>
0965 : public RActionImpl<TakeHelper<RealT_t, RVec<RealT_t>, std::vector<RealT_t>>> {
0966
0967 Results<std::shared_ptr<std::vector<std::vector<RealT_t>>>> fColls;
0968
0969 public:
0970 using ColumnTypes_t = TypeList<RVec<RealT_t>>;
0971 TakeHelper(const std::shared_ptr<std::vector<std::vector<RealT_t>>> &resultColl, const unsigned int nSlots)
0972 {
0973 fColls.emplace_back(resultColl);
0974 for (unsigned int i = 1; i < nSlots; ++i) {
0975 auto v = std::make_shared<std::vector<RealT_t>>();
0976 v->reserve(1024);
0977 fColls.emplace_back(v);
0978 }
0979 }
0980 TakeHelper(TakeHelper &&);
0981 TakeHelper(const TakeHelper &) = delete;
0982
0983 void InitTask(TTreeReader *, unsigned int) {}
0984
0985 void Exec(unsigned int slot, RVec<RealT_t> av) { fColls[slot]->emplace_back(av.begin(), av.end()); }
0986
0987 void Initialize() { }
0988
0989
0990 void Finalize()
0991 {
0992 ULong64_t totSize = 0;
0993 for (auto &coll : fColls)
0994 totSize += coll->size();
0995 auto rColl = fColls[0];
0996 rColl->reserve(totSize);
0997 for (unsigned int i = 1; i < fColls.size(); ++i) {
0998 auto &coll = fColls[i];
0999 rColl->insert(rColl->end(), coll->begin(), coll->end());
1000 }
1001 }
1002
1003 std::string GetActionName() { return "Take"; }
1004
1005 TakeHelper MakeNew(void *newResult, std::string_view = "nominal")
1006 {
1007 auto &result = *static_cast<typename decltype(fColls)::value_type *>(newResult);
1008 result->clear();
1009 return TakeHelper(result, fColls.size());
1010 }
1011 };
1012
1013
1014
1015
1016 template <typename RealT_t, typename T, typename COLL>
1017 TakeHelper<RealT_t, T, COLL>::TakeHelper(TakeHelper<RealT_t, T, COLL> &&) = default;
1018 template <typename RealT_t, typename T>
1019 TakeHelper<RealT_t, T, std::vector<T>>::TakeHelper(TakeHelper<RealT_t, T, std::vector<T>> &&) = default;
1020 template <typename RealT_t, typename COLL>
1021 TakeHelper<RealT_t, RVec<RealT_t>, COLL>::TakeHelper(TakeHelper<RealT_t, RVec<RealT_t>, COLL> &&) = default;
1022 template <typename RealT_t>
1023 TakeHelper<RealT_t, RVec<RealT_t>, std::vector<RealT_t>>::TakeHelper(TakeHelper<RealT_t, RVec<RealT_t>, std::vector<RealT_t>> &&) = default;
1024
1025
1026 #if __GNUC__ > 5
1027 extern template class TakeHelper<bool, bool, std::vector<bool>>;
1028 extern template class TakeHelper<unsigned int, unsigned int, std::vector<unsigned int>>;
1029 extern template class TakeHelper<unsigned long, unsigned long, std::vector<unsigned long>>;
1030 extern template class TakeHelper<unsigned long long, unsigned long long, std::vector<unsigned long long>>;
1031 extern template class TakeHelper<int, int, std::vector<int>>;
1032 extern template class TakeHelper<long, long, std::vector<long>>;
1033 extern template class TakeHelper<long long, long long, std::vector<long long>>;
1034 extern template class TakeHelper<float, float, std::vector<float>>;
1035 extern template class TakeHelper<double, double, std::vector<double>>;
1036 #endif
1037
1038 template <typename ResultType>
1039 class R__CLING_PTRCHECK(off) MinHelper : public RActionImpl<MinHelper<ResultType>> {
1040 std::shared_ptr<ResultType> fResultMin;
1041 Results<ResultType> fMins;
1042
1043 public:
1044 MinHelper(MinHelper &&) = default;
1045 MinHelper(const std::shared_ptr<ResultType> &minVPtr, const unsigned int nSlots)
1046 : fResultMin(minVPtr), fMins(nSlots, std::numeric_limits<ResultType>::max())
1047 {
1048 }
1049
1050 void Exec(unsigned int slot, ResultType v) { fMins[slot] = std::min(v, fMins[slot]); }
1051
1052 void InitTask(TTreeReader *, unsigned int) {}
1053
1054 template <typename T, std::enable_if_t<IsDataContainer<T>::value, int> = 0>
1055 void Exec(unsigned int slot, const T &vs)
1056 {
1057 for (auto &&v : vs)
1058 fMins[slot] = std::min(static_cast<ResultType>(v), fMins[slot]);
1059 }
1060
1061 void Initialize() { }
1062
1063 void Finalize()
1064 {
1065 *fResultMin = std::numeric_limits<ResultType>::max();
1066 for (auto &m : fMins)
1067 *fResultMin = std::min(m, *fResultMin);
1068 }
1069
1070
1071 std::unique_ptr<RMergeableValueBase> GetMergeableValue() const final
1072 {
1073 return std::make_unique<RMergeableMin<ResultType>>(*fResultMin);
1074 }
1075
1076 ResultType &PartialUpdate(unsigned int slot) { return fMins[slot]; }
1077
1078 std::string GetActionName() { return "Min"; }
1079
1080 MinHelper MakeNew(void *newResult, std::string_view = "nominal")
1081 {
1082 auto &result = *static_cast<std::shared_ptr<ResultType> *>(newResult);
1083 return MinHelper(result, fMins.size());
1084 }
1085 };
1086
1087 template <typename ResultType>
1088 class R__CLING_PTRCHECK(off) MaxHelper : public RActionImpl<MaxHelper<ResultType>> {
1089 std::shared_ptr<ResultType> fResultMax;
1090 Results<ResultType> fMaxs;
1091
1092 public:
1093 MaxHelper(MaxHelper &&) = default;
1094 MaxHelper(const MaxHelper &) = delete;
1095 MaxHelper(const std::shared_ptr<ResultType> &maxVPtr, const unsigned int nSlots)
1096 : fResultMax(maxVPtr), fMaxs(nSlots, std::numeric_limits<ResultType>::lowest())
1097 {
1098 }
1099
1100 void InitTask(TTreeReader *, unsigned int) {}
1101 void Exec(unsigned int slot, ResultType v) { fMaxs[slot] = std::max(v, fMaxs[slot]); }
1102
1103 template <typename T, std::enable_if_t<IsDataContainer<T>::value, int> = 0>
1104 void Exec(unsigned int slot, const T &vs)
1105 {
1106 for (auto &&v : vs)
1107 fMaxs[slot] = std::max(static_cast<ResultType>(v), fMaxs[slot]);
1108 }
1109
1110 void Initialize() { }
1111
1112 void Finalize()
1113 {
1114 *fResultMax = std::numeric_limits<ResultType>::lowest();
1115 for (auto &m : fMaxs) {
1116 *fResultMax = std::max(m, *fResultMax);
1117 }
1118 }
1119
1120
1121 std::unique_ptr<RMergeableValueBase> GetMergeableValue() const final
1122 {
1123 return std::make_unique<RMergeableMax<ResultType>>(*fResultMax);
1124 }
1125
1126 ResultType &PartialUpdate(unsigned int slot) { return fMaxs[slot]; }
1127
1128 std::string GetActionName() { return "Max"; }
1129
1130 MaxHelper MakeNew(void *newResult, std::string_view = "nominal")
1131 {
1132 auto &result = *static_cast<std::shared_ptr<ResultType> *>(newResult);
1133 return MaxHelper(result, fMaxs.size());
1134 }
1135 };
1136
1137 template <typename ResultType>
1138 class R__CLING_PTRCHECK(off) SumHelper : public RActionImpl<SumHelper<ResultType>> {
1139 std::shared_ptr<ResultType> fResultSum;
1140 Results<ResultType> fSums;
1141 Results<ResultType> fCompensations;
1142
1143
1144
1145
1146 template <typename T = ResultType>
1147 auto NeutralElement(const T &v, int ) -> decltype(v - v)
1148 {
1149 return v - v;
1150 }
1151
1152 template <typename T = ResultType, typename Dummy = int>
1153 ResultType NeutralElement(const T &, Dummy)
1154 {
1155 return ResultType{};
1156 }
1157
1158 public:
1159 SumHelper(SumHelper &&) = default;
1160 SumHelper(const SumHelper &) = delete;
1161 SumHelper(const std::shared_ptr<ResultType> &sumVPtr, const unsigned int nSlots)
1162 : fResultSum(sumVPtr), fSums(nSlots, NeutralElement(*sumVPtr, -1)),
1163 fCompensations(nSlots, NeutralElement(*sumVPtr, -1))
1164 {
1165 }
1166 void InitTask(TTreeReader *, unsigned int) {}
1167
1168 void Exec(unsigned int slot, ResultType x)
1169 {
1170
1171 ResultType y = x - fCompensations[slot];
1172 ResultType t = fSums[slot] + y;
1173 fCompensations[slot] = (t - fSums[slot]) - y;
1174 fSums[slot] = t;
1175 }
1176
1177 template <typename T, std::enable_if_t<IsDataContainer<T>::value, int> = 0>
1178 void Exec(unsigned int slot, const T &vs)
1179 {
1180 for (auto &&v : vs) {
1181 Exec(slot, v);
1182 }
1183 }
1184
1185 void Initialize() { }
1186
1187 void Finalize()
1188 {
1189 ResultType sum(NeutralElement(ResultType{}, -1));
1190 ResultType compensation(NeutralElement(ResultType{}, -1));
1191 ResultType y(NeutralElement(ResultType{}, -1));
1192 ResultType t(NeutralElement(ResultType{}, -1));
1193 for (auto &m : fSums) {
1194
1195 y = m - compensation;
1196 t = sum + y;
1197 compensation = (t - sum) - y;
1198 sum = t;
1199 }
1200 *fResultSum += sum;
1201 }
1202
1203
1204 std::unique_ptr<RMergeableValueBase> GetMergeableValue() const final
1205 {
1206 return std::make_unique<RMergeableSum<ResultType>>(*fResultSum);
1207 }
1208
1209 ResultType &PartialUpdate(unsigned int slot) { return fSums[slot]; }
1210
1211 std::string GetActionName() { return "Sum"; }
1212
1213 SumHelper MakeNew(void *newResult, std::string_view = "nominal")
1214 {
1215 auto &result = *static_cast<std::shared_ptr<ResultType> *>(newResult);
1216 *result = NeutralElement(*result, -1);
1217 return SumHelper(result, fSums.size());
1218 }
1219 };
1220
1221 class R__CLING_PTRCHECK(off) MeanHelper : public RActionImpl<MeanHelper> {
1222 std::shared_ptr<double> fResultMean;
1223 std::vector<ULong64_t> fCounts;
1224 std::vector<double> fSums;
1225 std::vector<double> fPartialMeans;
1226 std::vector<double> fCompensations;
1227
1228 public:
1229 MeanHelper(const std::shared_ptr<double> &meanVPtr, const unsigned int nSlots);
1230 MeanHelper(MeanHelper &&) = default;
1231 MeanHelper(const MeanHelper &) = delete;
1232 void InitTask(TTreeReader *, unsigned int) {}
1233 void Exec(unsigned int slot, double v);
1234
1235 template <typename T, std::enable_if_t<IsDataContainer<T>::value, int> = 0>
1236 void Exec(unsigned int slot, const T &vs)
1237 {
1238 for (auto &&v : vs) {
1239
1240 fCounts[slot]++;
1241
1242 double y = v - fCompensations[slot];
1243 double t = fSums[slot] + y;
1244 fCompensations[slot] = (t - fSums[slot]) - y;
1245 fSums[slot] = t;
1246 }
1247 }
1248
1249 void Initialize() { }
1250
1251 void Finalize();
1252
1253
1254 std::unique_ptr<RMergeableValueBase> GetMergeableValue() const final
1255 {
1256 const ULong64_t counts = std::accumulate(fCounts.begin(), fCounts.end(), 0ull);
1257 return std::make_unique<RMergeableMean>(*fResultMean, counts);
1258 }
1259
1260 double &PartialUpdate(unsigned int slot);
1261
1262 std::string GetActionName() { return "Mean"; }
1263
1264 MeanHelper MakeNew(void *newResult, std::string_view = "nominal")
1265 {
1266 auto &result = *static_cast<std::shared_ptr<double> *>(newResult);
1267 return MeanHelper(result, fSums.size());
1268 }
1269 };
1270
1271 class R__CLING_PTRCHECK(off) StdDevHelper : public RActionImpl<StdDevHelper> {
1272
1273 unsigned int fNSlots;
1274 std::shared_ptr<double> fResultStdDev;
1275
1276 std::vector<ULong64_t> fCounts;
1277
1278 std::vector<double> fMeans;
1279
1280 std::vector<double> fDistancesfromMean;
1281
1282 public:
1283 StdDevHelper(const std::shared_ptr<double> &meanVPtr, const unsigned int nSlots);
1284 StdDevHelper(StdDevHelper &&) = default;
1285 StdDevHelper(const StdDevHelper &) = delete;
1286 void InitTask(TTreeReader *, unsigned int) {}
1287 void Exec(unsigned int slot, double v);
1288
1289 template <typename T, std::enable_if_t<IsDataContainer<T>::value, int> = 0>
1290 void Exec(unsigned int slot, const T &vs)
1291 {
1292 for (auto &&v : vs) {
1293 Exec(slot, v);
1294 }
1295 }
1296
1297 void Initialize() { }
1298
1299 void Finalize();
1300
1301
1302 std::unique_ptr<RMergeableValueBase> GetMergeableValue() const final
1303 {
1304 const ULong64_t counts = std::accumulate(fCounts.begin(), fCounts.end(), 0ull);
1305 const Double_t mean =
1306 std::inner_product(fMeans.begin(), fMeans.end(), fCounts.begin(), 0.) / static_cast<Double_t>(counts);
1307 return std::make_unique<RMergeableStdDev>(*fResultStdDev, counts, mean);
1308 }
1309
1310 std::string GetActionName() { return "StdDev"; }
1311
1312 StdDevHelper MakeNew(void *newResult, std::string_view = "nominal")
1313 {
1314 auto &result = *static_cast<std::shared_ptr<double> *>(newResult);
1315 return StdDevHelper(result, fCounts.size());
1316 }
1317 };
1318
1319 template <typename PrevNodeType>
1320 class R__CLING_PTRCHECK(off) DisplayHelper : public RActionImpl<DisplayHelper<PrevNodeType>> {
1321 private:
1322 using Display_t = ROOT::RDF::RDisplay;
1323 std::shared_ptr<Display_t> fDisplayerHelper;
1324 std::shared_ptr<PrevNodeType> fPrevNode;
1325 size_t fEntriesToProcess;
1326
1327 public:
1328 DisplayHelper(size_t nRows, const std::shared_ptr<Display_t> &d, const std::shared_ptr<PrevNodeType> &prevNode)
1329 : fDisplayerHelper(d), fPrevNode(prevNode), fEntriesToProcess(nRows)
1330 {
1331 }
1332 DisplayHelper(DisplayHelper &&) = default;
1333 DisplayHelper(const DisplayHelper &) = delete;
1334 void InitTask(TTreeReader *, unsigned int) {}
1335
1336 template <typename... Columns>
1337 void Exec(unsigned int, Columns &... columns)
1338 {
1339 if (fEntriesToProcess == 0)
1340 return;
1341
1342 fDisplayerHelper->AddRow(columns...);
1343 --fEntriesToProcess;
1344
1345 if (fEntriesToProcess == 0) {
1346
1347
1348
1349
1350 fPrevNode->StopProcessing();
1351 }
1352 }
1353
1354 void Initialize() {}
1355
1356 void Finalize() {}
1357
1358 std::string GetActionName() { return "Display"; }
1359 };
1360
1361 template <typename Acc, typename Merge, typename R, typename T, typename U,
1362 bool MustCopyAssign = std::is_same<R, U>::value>
1363 class R__CLING_PTRCHECK(off) AggregateHelper
1364 : public RActionImpl<AggregateHelper<Acc, Merge, R, T, U, MustCopyAssign>> {
1365 Acc fAggregate;
1366 Merge fMerge;
1367 std::shared_ptr<U> fResult;
1368 Results<U> fAggregators;
1369
1370 public:
1371 using ColumnTypes_t = TypeList<T>;
1372
1373 AggregateHelper(Acc &&f, Merge &&m, const std::shared_ptr<U> &result, const unsigned int nSlots)
1374 : fAggregate(std::move(f)), fMerge(std::move(m)), fResult(result), fAggregators(nSlots, *result)
1375 {
1376 }
1377
1378 AggregateHelper(Acc &f, Merge &m, const std::shared_ptr<U> &result, const unsigned int nSlots)
1379 : fAggregate(f), fMerge(m), fResult(result), fAggregators(nSlots, *result)
1380 {
1381 }
1382
1383 AggregateHelper(AggregateHelper &&) = default;
1384 AggregateHelper(const AggregateHelper &) = delete;
1385
1386 void InitTask(TTreeReader *, unsigned int) {}
1387
1388 template <bool MustCopyAssign_ = MustCopyAssign, std::enable_if_t<MustCopyAssign_, int> = 0>
1389 void Exec(unsigned int slot, const T &value)
1390 {
1391 fAggregators[slot] = fAggregate(fAggregators[slot], value);
1392 }
1393
1394 template <bool MustCopyAssign_ = MustCopyAssign, std::enable_if_t<!MustCopyAssign_, int> = 0>
1395 void Exec(unsigned int slot, const T &value)
1396 {
1397 fAggregate(fAggregators[slot], value);
1398 }
1399
1400 void Initialize() { }
1401
1402 template <typename MergeRet = typename CallableTraits<Merge>::ret_type,
1403 bool MergeAll = std::is_same<void, MergeRet>::value>
1404 std::enable_if_t<MergeAll, void> Finalize()
1405 {
1406 fMerge(fAggregators);
1407 *fResult = fAggregators[0];
1408 }
1409
1410 template <typename MergeRet = typename CallableTraits<Merge>::ret_type,
1411 bool MergeTwoByTwo = std::is_same<U, MergeRet>::value>
1412 std::enable_if_t<MergeTwoByTwo, void> Finalize(...)
1413 {
1414 for (const auto &acc : fAggregators)
1415 *fResult = fMerge(*fResult, acc);
1416 }
1417
1418 U &PartialUpdate(unsigned int slot) { return fAggregators[slot]; }
1419
1420 std::string GetActionName() { return "Aggregate"; }
1421
1422 AggregateHelper MakeNew(void *newResult, std::string_view = "nominal")
1423 {
1424 auto &result = *static_cast<std::shared_ptr<U> *>(newResult);
1425 return AggregateHelper(fAggregate, fMerge, result, fAggregators.size());
1426 }
1427 };
1428
1429 }
1430 }
1431 }
1432
1433
1434
1435 #endif