11 #ifndef ROOT_RDFOPERATIONS
12 #define ROOT_RDFOPERATIONS
43 #include <type_traits>
52 template <
typename Helper>
56 template <
typename T = Helper>
57 auto CallFinalizeTask(
unsigned int slot) -> decltype(&T::FinalizeTask,
void())
59 static_cast<Helper *
>(
this)->FinalizeTask(slot);
62 template <
typename... Args>
63 void CallFinalizeTask(
unsigned int, Args...) {}
72 using namespace ROOT::TypeTraits;
73 using namespace ROOT::VecOps;
74 using namespace ROOT::RDF;
75 using namespace ROOT::Detail::RDF;
77 using Hist_t = ::TH1D;
84 using Results =
typename std::conditional<std::is_same<T, bool>::value, std::deque<T>, std::vector<T>>::type;
87 class ForeachSlotHelper :
public RActionImpl<ForeachSlotHelper<F>> {
91 using ColumnTypes_t = RemoveFirstParameter_t<typename CallableTraits<F>::arg_types>;
92 ForeachSlotHelper(F &&f) : fCallable(f) {}
93 ForeachSlotHelper(ForeachSlotHelper &&) =
default;
94 ForeachSlotHelper(
const ForeachSlotHelper &) =
delete;
96 void InitTask(TTreeReader *,
unsigned int) {}
98 template <
typename... Args>
99 void Exec(
unsigned int slot, Args &&... args)
102 static_assert(std::is_same<TypeList<
typename std::decay<Args>::type...>, ColumnTypes_t>::value,
"");
103 fCallable(slot, std::forward<Args>(args)...);
106 void Initialize() { }
110 std::string GetActionName() {
return "ForeachSlot"; }
113 class CountHelper :
public RActionImpl<CountHelper> {
114 const std::shared_ptr<ULong64_t> fResultCount;
115 Results<ULong64_t> fCounts;
118 using ColumnTypes_t = TypeList<>;
119 CountHelper(
const std::shared_ptr<ULong64_t> &resultCount,
const unsigned int nSlots);
120 CountHelper(CountHelper &&) =
default;
121 CountHelper(
const CountHelper &) =
delete;
122 void InitTask(TTreeReader *,
unsigned int) {}
123 void Exec(
unsigned int slot);
124 void Initialize() { }
126 ULong64_t &PartialUpdate(
unsigned int slot);
128 std::string GetActionName() {
return "Count"; }
131 template <
typename ProxiedVal_t>
132 class ReportHelper :
public RActionImpl<ReportHelper<ProxiedVal_t>> {
133 const std::shared_ptr<RCutFlowReport> fReport;
138 std::weak_ptr<ProxiedVal_t> fProxiedWPtr;
139 bool fReturnEmptyReport;
142 using ColumnTypes_t = TypeList<>;
143 ReportHelper(
const std::shared_ptr<RCutFlowReport> &report,
const std::shared_ptr<ProxiedVal_t> &pp,
bool emptyRep)
144 : fReport(report), fProxiedWPtr(pp), fReturnEmptyReport(emptyRep){};
145 ReportHelper(ReportHelper &&) =
default;
146 ReportHelper(
const ReportHelper &) =
delete;
147 void InitTask(TTreeReader *,
unsigned int) {}
148 void Exec(
unsigned int ) {}
149 void Initialize() { }
153 if (!fReturnEmptyReport && !fProxiedWPtr.expired())
154 fProxiedWPtr.lock()->Report(*fReport);
157 std::string GetActionName() {
return "Report"; }
160 class FillHelper :
public RActionImpl<FillHelper> {
162 static constexpr
unsigned int fgTotalBufSize = 2097152;
163 using BufEl_t = double;
164 using Buf_t = std::vector<BufEl_t>;
166 std::vector<Buf_t> fBuffers;
167 std::vector<Buf_t> fWBuffers;
168 const std::shared_ptr<Hist_t> fResultHist;
169 unsigned int fNSlots;
170 unsigned int fBufSize;
172 Results<std::unique_ptr<Hist_t>> fPartialHists;
176 void UpdateMinMax(
unsigned int slot,
double v);
179 FillHelper(
const std::shared_ptr<Hist_t> &h,
const unsigned int nSlots);
180 FillHelper(FillHelper &&) =
default;
181 FillHelper(
const FillHelper &) =
delete;
182 void InitTask(TTreeReader *,
unsigned int) {}
183 void Exec(
unsigned int slot,
double v);
184 void Exec(
unsigned int slot,
double v,
double w);
186 template <typename T, typename std::enable_if<IsContainer<T>::value,
int>::type = 0>
187 void Exec(
unsigned int slot,
const T &vs)
189 auto &thisBuf = fBuffers[slot];
191 UpdateMinMax(slot, v);
192 thisBuf.emplace_back(v);
196 template <
typename T,
typename W,
197 typename std::enable_if<IsContainer<T>::value && IsContainer<W>::value,
int>::type = 0>
198 void Exec(
unsigned int slot,
const T &vs,
const W &ws)
200 auto &thisBuf = fBuffers[slot];
203 UpdateMinMax(slot, v);
204 thisBuf.emplace_back(v);
207 auto &thisWBuf = fWBuffers[slot];
209 thisWBuf.emplace_back(w);
213 template <
typename T,
typename W,
214 typename std::enable_if<IsContainer<T>::value && !IsContainer<W>::value,
int>::type = 0>
215 void Exec(
unsigned int slot,
const T &vs,
const W w)
217 auto &thisBuf = fBuffers[slot];
219 UpdateMinMax(slot, v);
220 thisBuf.emplace_back(v);
223 auto &thisWBuf = fWBuffers[slot];
224 thisWBuf.insert(thisWBuf.end(), vs.size(), w);
228 template <
typename T,
typename W,
229 typename std::enable_if<IsContainer<W>::value && !IsContainer<T>::value,
int>::type = 0>
230 void Exec(
unsigned int,
const T &,
const W &)
232 throw std::runtime_error(
233 "Cannot fill object if the type of the first column is a scalar and the one of the second a container.");
236 Hist_t &PartialUpdate(
unsigned int);
238 void Initialize() { }
242 std::string GetActionName() {
return "Fill"; }
245 extern template void FillHelper::Exec(
unsigned int,
const std::vector<float> &);
246 extern template void FillHelper::Exec(
unsigned int,
const std::vector<double> &);
247 extern template void FillHelper::Exec(
unsigned int,
const std::vector<char> &);
248 extern template void FillHelper::Exec(
unsigned int,
const std::vector<int> &);
249 extern template void FillHelper::Exec(
unsigned int,
const std::vector<unsigned int> &);
250 extern template void FillHelper::Exec(
unsigned int,
const std::vector<float> &,
const std::vector<float> &);
251 extern template void FillHelper::Exec(
unsigned int,
const std::vector<double> &,
const std::vector<double> &);
252 extern template void FillHelper::Exec(
unsigned int,
const std::vector<char> &,
const std::vector<char> &);
253 extern template void FillHelper::Exec(
unsigned int,
const std::vector<int> &,
const std::vector<int> &);
255 FillHelper::Exec(
unsigned int,
const std::vector<unsigned int> &,
const std::vector<unsigned int> &);
257 template <
typename HIST = Hist_t>
258 class FillParHelper :
public RActionImpl<FillParHelper<HIST>> {
259 std::vector<HIST *> fObjects;
262 FillParHelper(FillParHelper &&) =
default;
263 FillParHelper(
const FillParHelper &) =
delete;
265 FillParHelper(
const std::shared_ptr<HIST> &h,
const unsigned int nSlots) : fObjects(nSlots, nullptr)
267 fObjects[0] = h.get();
269 for (
unsigned int i = 1; i < nSlots; ++i) {
270 fObjects[i] =
new HIST(*fObjects[0]);
271 if (
auto objAsHist = dynamic_cast<TH1*>(fObjects[i])) {
272 objAsHist->SetDirectory(
nullptr);
277 void InitTask(TTreeReader *,
unsigned int) {}
279 void Exec(
unsigned int slot,
double x0)
281 fObjects[slot]->Fill(x0);
284 void Exec(
unsigned int slot,
double x0,
double x1)
286 fObjects[slot]->Fill(x0, x1);
289 void Exec(
unsigned int slot,
double x0,
double x1,
double x2)
291 fObjects[slot]->Fill(x0, x1, x2);
294 void Exec(
unsigned int slot,
double x0,
double x1,
double x2,
double x3)
296 fObjects[slot]->Fill(x0, x1, x2, x3);
299 template <typename X0, typename std::enable_if<IsContainer<X0>::value,
int>::type = 0>
300 void Exec(
unsigned int slot,
const X0 &x0s)
302 auto thisSlotH = fObjects[slot];
303 for (
auto &x0 : x0s) {
309 template <
typename X0,
typename X1,
310 typename std::enable_if<IsContainer<X1>::value && !IsContainer<X0>::value,
int>::type = 0>
311 void Exec(
unsigned int ,
const X0 &,
const X1 &)
313 throw std::runtime_error(
314 "Cannot fill object if the type of the first column is a scalar and the one of the second a container.");
317 template <
typename X0,
typename X1,
318 typename std::enable_if<IsContainer<X0>::value && IsContainer<X1>::value,
int>::type = 0>
319 void Exec(
unsigned int slot,
const X0 &x0s,
const X1 &x1s)
321 auto thisSlotH = fObjects[slot];
322 if (x0s.size() != x1s.size()) {
323 throw std::runtime_error(
"Cannot fill histogram with values in containers of different sizes.");
325 auto x0sIt = std::begin(x0s);
326 const auto x0sEnd = std::end(x0s);
327 auto x1sIt = std::begin(x1s);
328 for (; x0sIt != x0sEnd; x0sIt++, x1sIt++) {
329 thisSlotH->Fill(*x0sIt, *x1sIt);
333 template <
typename X0,
typename W,
334 typename std::enable_if<IsContainer<X0>::value && !IsContainer<W>::value,
int>::type = 0>
335 void Exec(
unsigned int slot,
const X0 &x0s,
const W w)
337 auto thisSlotH = fObjects[slot];
338 for (
auto &&x : x0s) {
339 thisSlotH->Fill(x, w);
343 template <
typename X0,
typename X1,
typename X2,
344 typename std::enable_if<IsContainer<X0>::value && IsContainer<X1>::value && IsContainer<X2>::value,
346 void Exec(
unsigned int slot,
const X0 &x0s,
const X1 &x1s,
const X2 &x2s)
348 auto thisSlotH = fObjects[slot];
349 if (!(x0s.size() == x1s.size() && x1s.size() == x2s.size())) {
350 throw std::runtime_error(
"Cannot fill histogram with values in containers of different sizes.");
352 auto x0sIt = std::begin(x0s);
353 const auto x0sEnd = std::end(x0s);
354 auto x1sIt = std::begin(x1s);
355 auto x2sIt = std::begin(x2s);
356 for (; x0sIt != x0sEnd; x0sIt++, x1sIt++, x2sIt++) {
357 thisSlotH->Fill(*x0sIt, *x1sIt, *x2sIt);
361 template <
typename X0,
typename X1,
typename W,
362 typename std::enable_if<IsContainer<X0>::value && IsContainer<X1>::value && !IsContainer<W>::value,
364 void Exec(
unsigned int slot,
const X0 &x0s,
const X1 &x1s,
const W w)
366 auto thisSlotH = fObjects[slot];
367 if (x0s.size() != x1s.size()) {
368 throw std::runtime_error(
"Cannot fill histogram with values in containers of different sizes.");
370 auto x0sIt = std::begin(x0s);
371 const auto x0sEnd = std::end(x0s);
372 auto x1sIt = std::begin(x1s);
373 for (; x0sIt != x0sEnd; x0sIt++, x1sIt++) {
374 thisSlotH->Fill(*x0sIt, *x1sIt, w);
378 template <
typename X0,
typename X1,
typename X2,
typename X3,
379 typename std::enable_if<IsContainer<X0>::value && IsContainer<X1>::value && IsContainer<X2>::value &&
380 IsContainer<X3>::value,
382 void Exec(
unsigned int slot,
const X0 &x0s,
const X1 &x1s,
const X2 &x2s,
const X3 &x3s)
384 auto thisSlotH = fObjects[slot];
385 if (!(x0s.size() == x1s.size() && x1s.size() == x2s.size() && x1s.size() == x3s.size())) {
386 throw std::runtime_error(
"Cannot fill histogram with values in containers of different sizes.");
388 auto x0sIt = std::begin(x0s);
389 const auto x0sEnd = std::end(x0s);
390 auto x1sIt = std::begin(x1s);
391 auto x2sIt = std::begin(x2s);
392 auto x3sIt = std::begin(x3s);
393 for (; x0sIt != x0sEnd; x0sIt++, x1sIt++, x2sIt++, x3sIt++) {
394 thisSlotH->Fill(*x0sIt, *x1sIt, *x2sIt, *x3sIt);
398 template <
typename X0,
typename X1,
typename X2,
typename W,
399 typename std::enable_if<IsContainer<X0>::value && IsContainer<X1>::value && IsContainer<X2>::value &&
400 !IsContainer<W>::value,
402 void Exec(
unsigned int slot,
const X0 &x0s,
const X1 &x1s,
const X2 &x2s,
const W w)
404 auto thisSlotH = fObjects[slot];
405 if (!(x0s.size() == x1s.size() && x1s.size() == x2s.size())) {
406 throw std::runtime_error(
"Cannot fill histogram with values in containers of different sizes.");
408 auto x0sIt = std::begin(x0s);
409 const auto x0sEnd = std::end(x0s);
410 auto x1sIt = std::begin(x1s);
411 auto x2sIt = std::begin(x2s);
412 for (; x0sIt != x0sEnd; x0sIt++, x1sIt++, x2sIt++) {
413 thisSlotH->Fill(*x0sIt, *x1sIt, *x2sIt, w);
417 void Initialize() { }
421 auto resObj = fObjects[0];
422 const auto nSlots = fObjects.size();
425 for (
unsigned int slot = 1; slot < nSlots; ++slot) {
426 l.Add(fObjects[slot]);
432 HIST &PartialUpdate(
unsigned int slot) {
return *fObjects[slot]; }
434 std::string GetActionName() {
return "FillPar"; }
437 class FillTGraphHelper :
public ROOT::Detail::RDF::RActionImpl<FillTGraphHelper> {
439 using Result_t = ::TGraph;
442 std::vector<::TGraph *> fGraphs;
445 FillTGraphHelper(FillTGraphHelper &&) =
default;
446 FillTGraphHelper(
const FillTGraphHelper &) =
delete;
450 FillTGraphHelper(
const std::shared_ptr<::TGraph> &g,
const unsigned int nSlots) : fGraphs(nSlots, nullptr)
452 fGraphs[0] = g.get();
454 for (
unsigned int i = 1; i < nSlots; ++i) {
455 fGraphs[i] =
new TGraph(*fGraphs[0]);
460 void InitTask(TTreeReader *,
unsigned int) {}
462 template <
typename X0,
typename X1,
463 typename std::enable_if<
464 ROOT::TypeTraits::IsContainer<X0>::value && ROOT::TypeTraits::IsContainer<X1>::value,
int>::type = 0>
465 void Exec(
unsigned int slot,
const X0 &x0s,
const X1 &x1s)
467 if (x0s.size() != x1s.size()) {
468 throw std::runtime_error(
"Cannot fill Graph with values in containers of different sizes.");
470 auto thisSlotG = fGraphs[slot];
471 auto x0sIt = std::begin(x0s);
472 const auto x0sEnd = std::end(x0s);
473 auto x1sIt = std::begin(x1s);
474 for (; x0sIt != x0sEnd; x0sIt++, x1sIt++) {
475 thisSlotG->SetPoint(thisSlotG->GetN(), *x0sIt, *x1sIt);
479 template <
typename X0,
typename X1>
480 void Exec(
unsigned int slot, X0 x0, X1 x1)
482 auto thisSlotG = fGraphs[slot];
483 thisSlotG->SetPoint(thisSlotG->GetN(), x0, x1);
488 const auto nSlots = fGraphs.size();
489 auto resGraph = fGraphs[0];
492 for (
unsigned int slot = 1; slot < nSlots; ++slot) {
493 l.Add(fGraphs[slot]);
498 std::string GetActionName() {
return "Graph"; }
500 Result_t &PartialUpdate(
unsigned int slot) {
return *fGraphs[slot]; }
509 template <
typename V,
typename COLL>
510 void FillColl(V&& v, COLL& c) {
515 template <
typename COLL>
516 void FillColl(
bool v, COLL& c) {
522 template <
typename RealT_t,
typename T,
typename COLL>
523 class TakeHelper :
public RActionImpl<TakeHelper<RealT_t, T, COLL>> {
524 Results<std::shared_ptr<COLL>> fColls;
527 using ColumnTypes_t = TypeList<T>;
528 TakeHelper(
const std::shared_ptr<COLL> &resultColl,
const unsigned int nSlots)
530 fColls.emplace_back(resultColl);
531 for (
unsigned int i = 1; i < nSlots; ++i)
532 fColls.emplace_back(std::make_shared<COLL>());
534 TakeHelper(TakeHelper &&);
535 TakeHelper(
const TakeHelper &) =
delete;
537 void InitTask(TTreeReader *,
unsigned int) {}
539 void Exec(
unsigned int slot, T &v) { FillColl(v, *fColls[slot]); }
541 void Initialize() { }
545 auto rColl = fColls[0];
546 for (
unsigned int i = 1; i < fColls.size(); ++i) {
547 const auto &coll = fColls[i];
548 const auto end = coll->end();
551 for (
auto j = coll->begin(); j != end; j++) {
552 FillColl(*j, *rColl);
557 COLL &PartialUpdate(
unsigned int slot) {
return *fColls[slot].get(); }
559 std::string GetActionName() {
return "Take"; }
564 template <
typename RealT_t,
typename T>
565 class TakeHelper<RealT_t, T, std::vector<T>> :
public RActionImpl<TakeHelper<RealT_t, T, std::vector<T>>> {
566 Results<std::shared_ptr<std::vector<T>>> fColls;
569 using ColumnTypes_t = TypeList<T>;
570 TakeHelper(
const std::shared_ptr<std::vector<T>> &resultColl,
const unsigned int nSlots)
572 fColls.emplace_back(resultColl);
573 for (
unsigned int i = 1; i < nSlots; ++i) {
574 auto v = std::make_shared<std::vector<T>>();
576 fColls.emplace_back(v);
579 TakeHelper(TakeHelper &&);
580 TakeHelper(
const TakeHelper &) =
delete;
582 void InitTask(TTreeReader *,
unsigned int) {}
584 void Exec(
unsigned int slot, T &v) { FillColl(v, *fColls[slot]); }
586 void Initialize() { }
591 ULong64_t totSize = 0;
592 for (
auto &coll : fColls)
593 totSize += coll->size();
594 auto rColl = fColls[0];
595 rColl->reserve(totSize);
596 for (
unsigned int i = 1; i < fColls.size(); ++i) {
597 auto &coll = fColls[i];
598 rColl->insert(rColl->end(), coll->begin(), coll->end());
602 std::vector<T> &PartialUpdate(
unsigned int slot) {
return *fColls[slot]; }
604 std::string GetActionName() {
return "Take"; }
609 template <
typename RealT_t,
typename COLL>
610 class TakeHelper<RealT_t, RVec<RealT_t>, COLL> :
public RActionImpl<TakeHelper<RealT_t, RVec<RealT_t>, COLL>> {
611 Results<std::shared_ptr<COLL>> fColls;
614 using ColumnTypes_t = TypeList<RVec<RealT_t>>;
615 TakeHelper(
const std::shared_ptr<COLL> &resultColl,
const unsigned int nSlots)
617 fColls.emplace_back(resultColl);
618 for (
unsigned int i = 1; i < nSlots; ++i)
619 fColls.emplace_back(std::make_shared<COLL>());
621 TakeHelper(TakeHelper &&);
622 TakeHelper(
const TakeHelper &) =
delete;
624 void InitTask(TTreeReader *,
unsigned int) {}
626 void Exec(
unsigned int slot, RVec<RealT_t> av) { fColls[slot]->emplace_back(av.begin(), av.end()); }
628 void Initialize() { }
632 auto rColl = fColls[0];
633 for (
unsigned int i = 1; i < fColls.size(); ++i) {
634 auto &coll = fColls[i];
635 for (
auto &v : *coll) {
636 rColl->emplace_back(v);
641 std::string GetActionName() {
return "Take"; }
646 template <
typename RealT_t>
647 class TakeHelper<RealT_t, RVec<RealT_t>, std::vector<RealT_t>>
648 :
public RActionImpl<TakeHelper<RealT_t, RVec<RealT_t>, std::vector<RealT_t>>> {
650 Results<std::shared_ptr<std::vector<std::vector<RealT_t>>>> fColls;
653 using ColumnTypes_t = TypeList<RVec<RealT_t>>;
654 TakeHelper(
const std::shared_ptr<std::vector<std::vector<RealT_t>>> &resultColl,
const unsigned int nSlots)
656 fColls.emplace_back(resultColl);
657 for (
unsigned int i = 1; i < nSlots; ++i) {
658 auto v = std::make_shared<std::vector<RealT_t>>();
660 fColls.emplace_back(v);
663 TakeHelper(TakeHelper &&);
664 TakeHelper(
const TakeHelper &) =
delete;
666 void InitTask(TTreeReader *,
unsigned int) {}
668 void Exec(
unsigned int slot, RVec<RealT_t> av) { fColls[slot]->emplace_back(av.begin(), av.end()); }
670 void Initialize() { }
675 ULong64_t totSize = 0;
676 for (
auto &coll : fColls)
677 totSize += coll->size();
678 auto rColl = fColls[0];
679 rColl->reserve(totSize);
680 for (
unsigned int i = 1; i < fColls.size(); ++i) {
681 auto &coll = fColls[i];
682 rColl->insert(rColl->end(), coll->begin(), coll->end());
686 std::string GetActionName() {
return "Take"; }
692 template <
typename RealT_t,
typename T,
typename COLL>
693 TakeHelper<RealT_t, T, COLL>::TakeHelper(TakeHelper<RealT_t, T, COLL> &&) =
default;
694 template <
typename RealT_t,
typename T>
695 TakeHelper<RealT_t, T, std::vector<T>>::TakeHelper(TakeHelper<RealT_t, T, std::vector<T>> &&) =
default;
696 template <
typename RealT_t,
typename COLL>
697 TakeHelper<RealT_t, RVec<RealT_t>, COLL>::TakeHelper(TakeHelper<RealT_t, RVec<RealT_t>, COLL> &&) =
default;
698 template <
typename RealT_t>
699 TakeHelper<RealT_t, RVec<RealT_t>, std::vector<RealT_t>>::TakeHelper(TakeHelper<RealT_t, RVec<RealT_t>, std::vector<RealT_t>> &&) =
default;
703 extern template class TakeHelper<bool, bool, std::vector<bool>>;
704 extern template class TakeHelper<unsigned int, unsigned int, std::vector<unsigned int>>;
705 extern template class TakeHelper<unsigned long, unsigned long, std::vector<unsigned long>>;
706 extern template class TakeHelper<unsigned long long, unsigned long long, std::vector<unsigned long long>>;
707 extern template class TakeHelper<int, int, std::vector<int>>;
708 extern template class TakeHelper<long, long, std::vector<long>>;
709 extern template class TakeHelper<long long, long long, std::vector<long long>>;
710 extern template class TakeHelper<float, float, std::vector<float>>;
711 extern template class TakeHelper<double, double, std::vector<double>>;
715 template <
typename ResultType>
716 class MinHelper :
public RActionImpl<MinHelper<ResultType>> {
717 const std::shared_ptr<ResultType> fResultMin;
718 Results<ResultType> fMins;
721 MinHelper(MinHelper &&) =
default;
722 MinHelper(
const std::shared_ptr<ResultType> &minVPtr,
const unsigned int nSlots)
723 : fResultMin(minVPtr), fMins(nSlots, std::numeric_limits<ResultType>::max())
727 void Exec(
unsigned int slot, ResultType v) { fMins[slot] = std::min(v, fMins[slot]); }
729 void InitTask(TTreeReader *,
unsigned int) {}
731 template <typename T, typename std::enable_if<IsContainer<T>::value,
int>::type = 0>
732 void Exec(
unsigned int slot,
const T &vs)
735 fMins[slot] = std::min(v, fMins[slot]);
738 void Initialize() { }
742 *fResultMin = std::numeric_limits<ResultType>::max();
743 for (
auto &m : fMins)
744 *fResultMin = std::min(m, *fResultMin);
747 ResultType &PartialUpdate(
unsigned int slot) {
return fMins[slot]; }
749 std::string GetActionName() {
return "Min"; }
759 template <
typename ResultType>
760 class MaxHelper :
public RActionImpl<MaxHelper<ResultType>> {
761 const std::shared_ptr<ResultType> fResultMax;
762 Results<ResultType> fMaxs;
765 MaxHelper(MaxHelper &&) =
default;
766 MaxHelper(
const MaxHelper &) =
delete;
767 MaxHelper(
const std::shared_ptr<ResultType> &maxVPtr,
const unsigned int nSlots)
768 : fResultMax(maxVPtr), fMaxs(nSlots, std::numeric_limits<ResultType>::lowest())
772 void InitTask(TTreeReader *,
unsigned int) {}
773 void Exec(
unsigned int slot, ResultType v) { fMaxs[slot] = std::max(v, fMaxs[slot]); }
775 template <typename T, typename std::enable_if<IsContainer<T>::value,
int>::type = 0>
776 void Exec(
unsigned int slot,
const T &vs)
779 fMaxs[slot] = std::max((ResultType)v, fMaxs[slot]);
782 void Initialize() { }
786 *fResultMax = std::numeric_limits<ResultType>::lowest();
787 for (
auto &m : fMaxs) {
788 *fResultMax = std::max(m, *fResultMax);
792 ResultType &PartialUpdate(
unsigned int slot) {
return fMaxs[slot]; }
794 std::string GetActionName() {
return "Max"; }
804 template <
typename ResultType>
805 class SumHelper :
public RActionImpl<SumHelper<ResultType>> {
806 const std::shared_ptr<ResultType> fResultSum;
807 Results<ResultType> fSums;
812 template <
typename T = ResultType>
813 auto NeutralElement(
const T &v,
int ) -> decltype(v - v)
818 template <
typename T = ResultType,
typename Dummy =
int>
819 ResultType NeutralElement(
const T &, Dummy)
825 SumHelper(SumHelper &&) =
default;
826 SumHelper(
const SumHelper &) =
delete;
827 SumHelper(
const std::shared_ptr<ResultType> &sumVPtr,
const unsigned int nSlots)
828 : fResultSum(sumVPtr), fSums(nSlots, NeutralElement(*sumVPtr, -1))
832 void InitTask(TTreeReader *,
unsigned int) {}
833 void Exec(
unsigned int slot, ResultType v) { fSums[slot] += v; }
835 template <typename T, typename std::enable_if<IsContainer<T>::value,
int>::type = 0>
836 void Exec(
unsigned int slot,
const T &vs)
839 fSums[slot] +=
static_cast<ResultType
>(v);
842 void Initialize() { }
846 for (
auto &m : fSums)
850 ResultType &PartialUpdate(
unsigned int slot) {
return fSums[slot]; }
852 std::string GetActionName() {
return "Sum"; }
855 class MeanHelper :
public RActionImpl<MeanHelper> {
856 const std::shared_ptr<double> fResultMean;
857 std::vector<ULong64_t> fCounts;
858 std::vector<double> fSums;
859 std::vector<double> fPartialMeans;
862 MeanHelper(
const std::shared_ptr<double> &meanVPtr,
const unsigned int nSlots);
863 MeanHelper(MeanHelper &&) =
default;
864 MeanHelper(
const MeanHelper &) =
delete;
865 void InitTask(TTreeReader *,
unsigned int) {}
866 void Exec(
unsigned int slot,
double v);
868 template <typename T, typename std::enable_if<IsContainer<T>::value,
int>::type = 0>
869 void Exec(
unsigned int slot,
const T &vs)
871 for (
auto &&v : vs) {
877 void Initialize() { }
881 double &PartialUpdate(
unsigned int slot);
883 std::string GetActionName() {
return "Mean"; }
886 extern template void MeanHelper::Exec(
unsigned int,
const std::vector<float> &);
887 extern template void MeanHelper::Exec(
unsigned int,
const std::vector<double> &);
888 extern template void MeanHelper::Exec(
unsigned int,
const std::vector<char> &);
889 extern template void MeanHelper::Exec(
unsigned int,
const std::vector<int> &);
890 extern template void MeanHelper::Exec(
unsigned int,
const std::vector<unsigned int> &);
892 class StdDevHelper :
public RActionImpl<StdDevHelper> {
894 const unsigned int fNSlots;
895 const std::shared_ptr<double> fResultStdDev;
897 std::vector<ULong64_t> fCounts;
899 std::vector<double> fMeans;
901 std::vector<double> fDistancesfromMean;
904 StdDevHelper(
const std::shared_ptr<double> &meanVPtr,
const unsigned int nSlots);
905 StdDevHelper(StdDevHelper &&) =
default;
906 StdDevHelper(
const StdDevHelper &) =
delete;
907 void InitTask(TTreeReader *,
unsigned int) {}
908 void Exec(
unsigned int slot,
double v);
910 template <typename T, typename std::enable_if<IsContainer<T>::value,
int>::type = 0>
911 void Exec(
unsigned int slot,
const T &vs)
913 for (
auto &&v : vs) {
918 void Initialize() { }
922 std::string GetActionName() {
return "StdDev"; }
925 extern template void StdDevHelper::Exec(
unsigned int,
const std::vector<float> &);
926 extern template void StdDevHelper::Exec(
unsigned int,
const std::vector<double> &);
927 extern template void StdDevHelper::Exec(
unsigned int,
const std::vector<char> &);
928 extern template void StdDevHelper::Exec(
unsigned int,
const std::vector<int> &);
929 extern template void StdDevHelper::Exec(
unsigned int,
const std::vector<unsigned int> &);
931 template <
typename PrevNodeType>
932 class DisplayHelper :
public RActionImpl<DisplayHelper<PrevNodeType>> {
934 using Display_t = ROOT::RDF::RDisplay;
935 const std::shared_ptr<Display_t> fDisplayerHelper;
936 const std::shared_ptr<PrevNodeType> fPrevNode;
939 DisplayHelper(
const std::shared_ptr<Display_t> &d,
const std::shared_ptr<PrevNodeType> &prevNode)
940 : fDisplayerHelper(d), fPrevNode(prevNode)
943 DisplayHelper(DisplayHelper &&) =
default;
944 DisplayHelper(
const DisplayHelper &) =
delete;
945 void InitTask(TTreeReader *,
unsigned int) {}
947 template <
typename... Columns>
948 void Exec(
unsigned int, Columns... columns)
950 fDisplayerHelper->AddRow(columns...);
951 if (!fDisplayerHelper->HasNext()) {
952 fPrevNode->StopProcessing();
960 std::string GetActionName() {
return "Display"; }
970 std::size_t fSize = 0;
971 bool *fBools =
nullptr;
973 bool *CopyVector(
const RVec<bool> &v)
975 auto b =
new bool[fSize];
976 std::copy(v.begin(), v.end(), b);
980 bool *CopyArray(
bool *o, std::size_t size)
982 auto b =
new bool[size];
983 for (
auto i = 0u; i < size; ++i)
990 BoolArray() =
default;
991 template <
typename T>
992 BoolArray(
const T &) {
throw std::runtime_error(
"This constructor should never be called"); }
993 BoolArray(
const RVec<bool> &v) : fSize(v.size()), fBools(CopyVector(v)) {}
994 BoolArray(
const BoolArray &b)
996 CopyArray(b.fBools, b.fSize);
998 BoolArray &operator=(
const BoolArray &b)
1001 CopyArray(b.fBools, b.fSize);
1004 BoolArray(BoolArray &&b)
1011 BoolArray &operator=(BoolArray &&b)
1020 ~BoolArray() {
delete[] fBools; }
1021 std::size_t Size()
const {
return fSize; }
1022 bool *Data() {
return fBools; }
1024 using BoolArrayMap = std::map<std::string, BoolArray>;
1026 inline bool *UpdateBoolArrayIfBool(BoolArrayMap &boolArrays, RVec<bool> &v,
const std::string &outName)
1029 boolArrays[outName] = BoolArray(v);
1030 return boolArrays[outName].Data();
1033 template <
typename T>
1034 T *UpdateBoolArrayIfBool(BoolArrayMap &, RVec<T> &v,
const std::string &)
1041 inline void *GetData(ROOT::VecOps::RVec<bool> & )
1046 template <
typename T>
1047 void *GetData(ROOT::VecOps::RVec<T> &v)
1052 template <
typename T>
1059 template <
typename T>
1060 void SetBranchesHelper(BoolArrayMap &, TTree * , TTree &outputTree,
const std::string & ,
1061 const std::string &name, TBranch *& branch,
void *& branchAddress, T *address)
1063 outputTree.Branch(name.c_str(), address);
1065 branchAddress =
nullptr;
1075 template <
typename T>
1076 void SetBranchesHelper(BoolArrayMap &boolArrays, TTree *inputTree, TTree &outputTree,
const std::string &inName,
1077 const std::string &outName, TBranch *&branch,
void *&branchAddress, RVec<T> *ab)
1079 auto *
const inputBranch = inputTree ? inputTree->GetBranch(inName.c_str()) :
nullptr;
1080 const auto mustWriteStdVec =
1081 !inputBranch || ROOT::ESTLType::kSTLvector == TClassEdit::IsSTLCont(inputBranch->GetClassName());
1083 if (mustWriteStdVec) {
1087 outputTree.Branch(outName.c_str(), &ab->AsVector());
1092 auto *
const leaf =
static_cast<TLeaf *
>(inputBranch->GetListOfLeaves()->UncheckedAt(0));
1093 const auto bname = leaf->GetName();
1094 const auto counterStr =
1095 leaf->GetLeafCount() ? std::string(leaf->GetLeafCount()->GetName()) : std::to_string(leaf->GetLenStatic());
1096 const auto btype = leaf->GetTypeName();
1097 const auto rootbtype = TypeName2ROOTTypeName(btype);
1098 const auto leaflist = std::string(bname) +
"[" + counterStr +
"]/" + rootbtype;
1102 auto dataPtr = UpdateBoolArrayIfBool(boolArrays, *ab, outName);
1104 auto *
const outputBranch = outputTree.Branch(outName.c_str(), dataPtr, leaflist.c_str());
1105 outputBranch->SetTitle(inputBranch->GetTitle());
1108 if (!std::is_same<bool, T>::value) {
1109 branch = outputBranch;
1110 branchAddress = GetData(*ab);
1115 template <
typename T>
1116 void UpdateBoolArray(BoolArrayMap &, T&,
const std::string &, TTree &) {}
1119 inline void UpdateBoolArray(BoolArrayMap &boolArrays, RVec<bool> &v,
const std::string &outName, TTree &t)
1121 if (v.size() > boolArrays[outName].Size()) {
1122 boolArrays[outName] = BoolArray(v);
1123 t.SetBranchAddress(outName.c_str(), boolArrays[outName].Data());
1126 std::copy(v.begin(), v.end(), boolArrays[outName].Data());
1131 template <
typename... BranchTypes>
1132 class SnapshotHelper :
public RActionImpl<SnapshotHelper<BranchTypes...>> {
1133 const std::string fFileName;
1134 const std::string fDirName;
1135 const std::string fTreeName;
1136 const RSnapshotOptions fOptions;
1137 std::unique_ptr<TFile> fOutputFile;
1138 std::unique_ptr<TTree> fOutputTree;
1139 bool fIsFirstEvent{
true};
1140 const ColumnNames_t fInputBranchNames;
1141 const ColumnNames_t fOutputBranchNames;
1142 TTree *fInputTree =
nullptr;
1143 BoolArrayMap fBoolArrays;
1144 std::vector<TBranch *> fBranches;
1145 std::vector<void *> fBranchAddresses;
1148 using ColumnTypes_t = TypeList<BranchTypes...>;
1149 SnapshotHelper(std::string_view filename, std::string_view dirname, std::string_view treename,
1150 const ColumnNames_t &vbnames,
const ColumnNames_t &bnames,
const RSnapshotOptions &options)
1151 : fFileName(filename), fDirName(dirname), fTreeName(treename), fOptions(options), fInputBranchNames(vbnames),
1152 fOutputBranchNames(ReplaceDotWithUnderscore(bnames)), fBranches(vbnames.size(), nullptr),
1153 fBranchAddresses(vbnames.size(), nullptr)
1157 SnapshotHelper(
const SnapshotHelper &) =
delete;
1158 SnapshotHelper(SnapshotHelper &&) =
default;
1160 void InitTask(TTreeReader *r,
unsigned int )
1164 fInputTree = r->GetTree();
1167 fInputTree->AddClone(fOutputTree.get());
1170 void Exec(
unsigned int , BranchTypes &... values)
1172 using ind_t = std::index_sequence_for<BranchTypes...>;
1173 if (! fIsFirstEvent) {
1174 UpdateCArraysPtrs(values..., ind_t{});
1176 SetBranches(values..., ind_t{});
1177 fIsFirstEvent =
false;
1179 UpdateBoolArrays(values..., ind_t{});
1180 fOutputTree->Fill();
1183 template <std::size_t... S>
1184 void UpdateCArraysPtrs(BranchTypes &... values, std::index_sequence<S...> )
1192 int expander[] = {(fBranches[S] && fBranchAddresses[S] != GetData(values)
1193 ? fBranches[S]->SetAddress(GetData(values)),
1194 fBranchAddresses[S] = GetData(values), 0 : 0, 0)...,
1199 template <std::size_t... S>
1200 void SetBranches(BranchTypes &... values, std::index_sequence<S...> )
1203 int expander[] = {(SetBranchesHelper(fBoolArrays, fInputTree, *fOutputTree, fInputBranchNames[S],
1204 fOutputBranchNames[S], fBranches[S], fBranchAddresses[S], &values),
1210 template <std::size_t... S>
1211 void UpdateBoolArrays(BranchTypes &...values, std::index_sequence<S...> )
1213 int expander[] = {(UpdateBoolArray(fBoolArrays, values, fOutputBranchNames[S], *fOutputTree), 0)..., 0};
1220 TFile::Open(fFileName.c_str(), fOptions.fMode.c_str(),
"",
1221 ROOT::CompressionSettings(fOptions.fCompressionAlgorithm, fOptions.fCompressionLevel)));
1223 if (!fDirName.empty()) {
1224 fOutputFile->mkdir(fDirName.c_str());
1225 fOutputFile->cd(fDirName.c_str());
1229 std::make_unique<TTree>(fTreeName.c_str(), fTreeName.c_str(), fOptions.fSplitLevel, fOutputFile.get());
1231 if (fOptions.fAutoFlush)
1232 fOutputTree->SetAutoFlush(fOptions.fAutoFlush);
1237 if (fOutputFile && fOutputTree) {
1238 ::TDirectory::TContext ctxt(fOutputFile->GetDirectory(fDirName.c_str()));
1239 fOutputTree->Write();
1241 fOutputTree.reset();
1242 fOutputFile->Close();
1244 Warning(
"Snapshot",
"A lazy Snapshot action was booked but never triggered.");
1248 std::string GetActionName() {
return "Snapshot"; }
1252 template <
typename... BranchTypes>
1253 class SnapshotHelperMT :
public RActionImpl<SnapshotHelperMT<BranchTypes...>> {
1254 const unsigned int fNSlots;
1255 std::unique_ptr<ROOT::Experimental::TBufferMerger> fMerger;
1256 std::vector<std::shared_ptr<ROOT::Experimental::TBufferMergerFile>> fOutputFiles;
1257 std::vector<std::unique_ptr<TTree>> fOutputTrees;
1258 std::vector<int> fIsFirstEvent;
1259 const std::string fFileName;
1260 const std::string fDirName;
1261 const std::string fTreeName;
1262 const RSnapshotOptions fOptions;
1263 const ColumnNames_t fInputBranchNames;
1264 const ColumnNames_t fOutputBranchNames;
1265 std::vector<TTree *> fInputTrees;
1266 std::vector<BoolArrayMap> fBoolArrays;
1268 std::vector<std::vector<TBranch *>> fBranches;
1270 std::vector<std::vector<void *>> fBranchAddresses;
1273 using ColumnTypes_t = TypeList<BranchTypes...>;
1274 SnapshotHelperMT(
const unsigned int nSlots, std::string_view filename, std::string_view dirname,
1275 std::string_view treename,
const ColumnNames_t &vbnames,
const ColumnNames_t &bnames,
1276 const RSnapshotOptions &options)
1277 : fNSlots(nSlots), fOutputFiles(fNSlots), fOutputTrees(fNSlots), fIsFirstEvent(fNSlots, 1), fFileName(filename),
1278 fDirName(dirname), fTreeName(treename), fOptions(options), fInputBranchNames(vbnames),
1279 fOutputBranchNames(ReplaceDotWithUnderscore(bnames)), fInputTrees(fNSlots), fBoolArrays(fNSlots),
1280 fBranches(fNSlots, std::vector<TBranch *>(vbnames.size(), nullptr)),
1281 fBranchAddresses(fNSlots, std::vector<void *>(vbnames.size(), nullptr))
1283 TString checkupdate = fOptions.fMode;
1284 checkupdate.ToLower();
1285 if (checkupdate ==
"update") {
1286 throw std::invalid_argument(
"Snapshot: fMode == \"update\" not supported when implicit MT is enabled");
1289 SnapshotHelperMT(
const SnapshotHelperMT &) =
delete;
1290 SnapshotHelperMT(SnapshotHelperMT &&) =
default;
1292 void InitTask(TTreeReader *r,
unsigned int slot)
1294 ::TDirectory::TContext c;
1295 if (!fOutputFiles[slot]) {
1297 fOutputFiles[slot] = fMerger->GetFile();
1299 TDirectory *treeDirectory = fOutputFiles[slot].get();
1300 if (!fDirName.empty()) {
1302 treeDirectory = fOutputFiles[slot]->mkdir(fDirName.c_str(),
"",
true);
1306 fOutputTrees[slot] =
1307 std::make_unique<TTree>(fTreeName.c_str(), fTreeName.c_str(), fOptions.fSplitLevel, treeDirectory);
1308 fOutputTrees[slot]->SetBit(TTree::kEntriesReshuffled);
1310 fOutputTrees[slot]->SetImplicitMT(
false);
1311 if (fOptions.fAutoFlush)
1312 fOutputTrees[slot]->SetAutoFlush(fOptions.fAutoFlush);
1315 fInputTrees[slot] = r->GetTree();
1320 const auto friendsListPtr = fInputTrees[slot]->GetListOfFriends();
1321 if (friendsListPtr && friendsListPtr->GetEntries() > 0)
1322 fInputTrees[slot]->AddClone(fOutputTrees[slot].
get());
1324 fIsFirstEvent[slot] = 1;
1327 void FinalizeTask(
unsigned int slot)
1329 if (fOutputTrees[slot]->GetEntries() > 0)
1330 fOutputFiles[slot]->Write();
1332 fOutputTrees[slot].reset(
nullptr);
1335 void Exec(
unsigned int slot, BranchTypes &... values)
1337 using ind_t = std::index_sequence_for<BranchTypes...>;
1338 if (!fIsFirstEvent[slot]) {
1339 UpdateCArraysPtrs(slot, values..., ind_t{});
1341 SetBranches(slot, values..., ind_t{});
1342 fIsFirstEvent[slot] = 0;
1344 UpdateBoolArrays(slot, values..., ind_t{});
1345 fOutputTrees[slot]->Fill();
1346 auto entries = fOutputTrees[slot]->GetEntries();
1347 auto autoFlush = fOutputTrees[slot]->GetAutoFlush();
1348 if ((autoFlush > 0) && (entries % autoFlush == 0))
1349 fOutputFiles[slot]->Write();
1352 template <std::size_t... S>
1353 void UpdateCArraysPtrs(
unsigned int slot, BranchTypes &... values, std::index_sequence<S...> )
1362 int expander[] = {(fBranches[slot][S] && fBranchAddresses[slot][S] != GetData(values)
1363 ? fBranches[slot][S]->SetAddress(GetData(values)),
1364 fBranchAddresses[slot][S] = GetData(values), 0 : 0, 0)...,
1369 template <std::size_t... S>
1370 void SetBranches(
unsigned int slot, BranchTypes &... values, std::index_sequence<S...> )
1374 (SetBranchesHelper(fBoolArrays[slot], fInputTrees[slot], *fOutputTrees[slot], fInputBranchNames[S],
1375 fOutputBranchNames[S], fBranches[slot][S], fBranchAddresses[slot][S], &values),
1382 template <std::size_t... S>
1383 void UpdateBoolArrays(
unsigned int slot, BranchTypes &... values, std::index_sequence<S...> )
1387 (UpdateBoolArray(fBoolArrays[slot], values, fOutputBranchNames[S], *fOutputTrees[slot]), 0)..., 0};
1393 const auto cs = ROOT::CompressionSettings(fOptions.fCompressionAlgorithm, fOptions.fCompressionLevel);
1394 fMerger = std::make_unique<ROOT::Experimental::TBufferMerger>(fFileName.c_str(), fOptions.fMode.c_str(), cs);
1399 auto fileWritten =
false;
1400 for (
auto &file : fOutputFiles) {
1409 Warning(
"Snapshot",
"A lazy Snapshot action was booked but never triggered.");
1413 fOutputFiles.clear();
1417 std::string GetActionName() {
return "Snapshot"; }
1420 template <
typename Acc,
typename Merge,
typename R,
typename T,
typename U,
1421 bool MustCopyAssign = std::is_same<R, U>::value>
1422 class AggregateHelper :
public RActionImpl<AggregateHelper<Acc, Merge, R, T, U, MustCopyAssign>> {
1425 const std::shared_ptr<U> fResult;
1426 Results<U> fAggregators;
1429 using ColumnTypes_t = TypeList<T>;
1430 AggregateHelper(Acc &&f, Merge &&m,
const std::shared_ptr<U> &result,
const unsigned int nSlots)
1431 : fAggregate(std::move(f)), fMerge(std::move(m)), fResult(result), fAggregators(nSlots, *result)
1434 AggregateHelper(AggregateHelper &&) =
default;
1435 AggregateHelper(
const AggregateHelper &) =
delete;
1437 void InitTask(TTreeReader *,
unsigned int) {}
1439 template <bool MustCopyAssign_ = MustCopyAssign, typename std::enable_if<MustCopyAssign_, int>::type = 0>
1440 void Exec(
unsigned int slot,
const T &value)
1442 fAggregators[slot] = fAggregate(fAggregators[slot], value);
1445 template <bool MustCopyAssign_ = MustCopyAssign, typename std::enable_if<!MustCopyAssign_, int>::type = 0>
1446 void Exec(
unsigned int slot,
const T &value)
1448 fAggregate(fAggregators[slot], value);
1451 void Initialize() { }
1453 template <typename MergeRet = typename CallableTraits<Merge>::ret_type,
1454 bool MergeAll = std::is_same<void, MergeRet>::value>
1455 typename std::enable_if<MergeAll, void>::type Finalize()
1457 fMerge(fAggregators);
1458 *fResult = fAggregators[0];
1461 template <typename MergeRet = typename CallableTraits<Merge>::ret_type,
1462 bool MergeTwoByTwo = std::is_same<U, MergeRet>::value>
1463 typename std::enable_if<MergeTwoByTwo, void>::type Finalize(...)
1465 for (
const auto &acc : fAggregators)
1466 *fResult = fMerge(*fResult, acc);
1469 U &PartialUpdate(
unsigned int slot) {
return fAggregators[slot]; }
1471 std::string GetActionName() {
return "Aggregate"; }