11 #ifndef ROOT_TDFOPERATIONS 12 #define ROOT_TDFOPERATIONS 26 #include <type_traits> 40 class ForeachSlotHelper {
44 using BranchTypes_t = RemoveFirstParameter_t<typename CallableTraits<F>::arg_types>;
45 ForeachSlotHelper(
F &&f) : fCallable(f) {}
46 ForeachSlotHelper(ForeachSlotHelper &&) =
default;
47 ForeachSlotHelper(
const ForeachSlotHelper &) =
delete;
51 template <
typename... Args>
52 void Exec(
unsigned int slot, Args &&... args)
56 fCallable(slot, std::forward<Args>(args)...);
63 const std::shared_ptr<ULong64_t> fResultCount;
64 std::vector<ULong64_t> fCounts;
68 CountHelper(
const std::shared_ptr<ULong64_t> &resultCount,
const unsigned int nSlots);
69 CountHelper(CountHelper &&) =
default;
70 CountHelper(
const CountHelper &) =
delete;
72 void Exec(
unsigned int slot);
74 ULong64_t &PartialUpdate(
unsigned int slot);
79 static constexpr
unsigned int fgTotalBufSize = 2097152;
80 using BufEl_t = double;
81 using Buf_t = std::vector<BufEl_t>;
83 std::vector<Buf_t> fBuffers;
84 std::vector<Buf_t> fWBuffers;
85 const std::shared_ptr<Hist_t> fResultHist;
87 unsigned int fBufSize;
89 std::vector<std::unique_ptr<Hist_t>> fPartialHists;
93 void UpdateMinMax(
unsigned int slot,
double v);
96 FillHelper(
const std::shared_ptr<Hist_t> &
h,
const unsigned int nSlots);
97 FillHelper(FillHelper &&) =
default;
98 FillHelper(
const FillHelper &) =
delete;
100 void Exec(
unsigned int slot,
double v);
101 void Exec(
unsigned int slot,
double v,
double w);
103 template <typename T, typename std::enable_if<IsContainer<T>::value,
int>
::type = 0>
104 void Exec(
unsigned int slot,
const T &vs)
106 auto &thisBuf = fBuffers[slot];
108 UpdateMinMax(slot,
v);
109 thisBuf.emplace_back(
v);
113 template <
typename T,
typename W,
115 void Exec(
unsigned int slot,
const T &vs,
const W &
ws)
117 auto &thisBuf = fBuffers[slot];
119 UpdateMinMax(slot,
v);
120 thisBuf.emplace_back(
v);
123 auto &thisWBuf = fWBuffers[slot];
125 thisWBuf.emplace_back(w);
129 Hist_t &PartialUpdate(
unsigned int);
134 extern template void FillHelper::Exec(
unsigned int,
const std::vector<float> &);
135 extern template void FillHelper::Exec(
unsigned int,
const std::vector<double> &);
136 extern template void FillHelper::Exec(
unsigned int,
const std::vector<char> &);
137 extern template void FillHelper::Exec(
unsigned int,
const std::vector<int> &);
138 extern template void FillHelper::Exec(
unsigned int,
const std::vector<unsigned int> &);
139 extern template void FillHelper::Exec(
unsigned int,
const std::vector<float> &,
const std::vector<float> &);
140 extern template void FillHelper::Exec(
unsigned int,
const std::vector<double> &,
const std::vector<double> &);
141 extern template void FillHelper::Exec(
unsigned int,
const std::vector<char> &,
const std::vector<char> &);
142 extern template void FillHelper::Exec(
unsigned int,
const std::vector<int> &,
const std::vector<int> &);
144 FillHelper::Exec(
unsigned int,
const std::vector<unsigned int> &,
const std::vector<unsigned int> &);
146 template <
typename HIST = Hist_t>
148 std::unique_ptr<TThreadedObject<HIST>> fTo;
151 FillTOHelper(FillTOHelper &&) =
default;
152 FillTOHelper(
const FillTOHelper &) =
delete;
154 FillTOHelper(
const std::shared_ptr<HIST> &
h,
const unsigned int nSlots) : fTo(new TThreadedObject<HIST>(*h))
156 fTo->SetAtSlot(0, h);
158 for (
unsigned int i = 0; i < nSlots; ++i) {
165 void Exec(
unsigned int slot,
double x0)
167 fTo->GetAtSlotRaw(slot)->Fill(x0);
170 void Exec(
unsigned int slot,
double x0,
double x1)
172 fTo->GetAtSlotRaw(slot)->Fill(x0, x1);
175 void Exec(
unsigned int slot,
double x0,
double x1,
double x2)
177 fTo->GetAtSlotRaw(slot)->Fill(x0, x1, x2);
180 void Exec(
unsigned int slot,
double x0,
double x1,
double x2,
double x3)
182 fTo->GetAtSlotRaw(slot)->Fill(x0, x1, x2, x3);
185 template <typename X0, typename std::enable_if<IsContainer<X0>::value,
int>::type = 0>
186 void Exec(
unsigned int slot,
const X0 &x0s)
188 auto thisSlotH = fTo->GetAtSlotRaw(slot);
189 for (
auto &x0 : x0s) {
194 template <
typename X0,
typename X1,
196 void Exec(
unsigned int slot,
const X0 &x0s,
const X1 &x1s)
198 auto thisSlotH = fTo->GetAtSlotRaw(slot);
199 if (x0s.size() != x1s.size()) {
200 throw std::runtime_error(
"Cannot fill histogram with values in containers of different sizes.");
202 auto x0sIt = std::begin(x0s);
203 const auto x0sEnd = std::end(x0s);
204 auto x1sIt = std::begin(x1s);
205 for (; x0sIt != x0sEnd; x0sIt++, x1sIt++) {
206 thisSlotH->Fill(*x0sIt, *x1sIt);
210 template <
typename X0,
typename X1,
typename X2,
213 void Exec(
unsigned int slot,
const X0 &x0s,
const X1 &x1s,
const X2 &x2s)
215 auto thisSlotH = fTo->GetAtSlotRaw(slot);
216 if (!(x0s.size() == x1s.size() && x1s.size() == x2s.size())) {
217 throw std::runtime_error(
"Cannot fill histogram with values in containers of different sizes.");
219 auto x0sIt = std::begin(x0s);
220 const auto x0sEnd = std::end(x0s);
221 auto x1sIt = std::begin(x1s);
222 auto x2sIt = std::begin(x2s);
223 for (; x0sIt != x0sEnd; x0sIt++, x1sIt++, x2sIt++) {
224 thisSlotH->Fill(*x0sIt, *x1sIt, *x2sIt);
227 template <
typename X0,
typename X1,
typename X2,
typename X3,
228 typename std::enable_if<IsContainer<X0>::value && IsContainer<X1>::value && IsContainer<X2>::value &&
231 void Exec(
unsigned int slot,
const X0 &x0s,
const X1 &x1s,
const X2 &x2s,
const X3 &x3s)
233 auto thisSlotH = fTo->GetAtSlotRaw(slot);
234 if (!(x0s.size() == x1s.size() && x1s.size() == x2s.size() && x1s.size() == x3s.size())) {
235 throw std::runtime_error(
"Cannot fill histogram with values in containers of different sizes.");
237 auto x0sIt = std::begin(x0s);
238 const auto x0sEnd = std::end(x0s);
239 auto x1sIt = std::begin(x1s);
240 auto x2sIt = std::begin(x2s);
241 auto x3sIt = std::begin(x3s);
242 for (; x0sIt != x0sEnd; x0sIt++, x1sIt++, x2sIt++, x3sIt++) {
243 thisSlotH->Fill(*x0sIt, *x1sIt, *x2sIt, *x3sIt);
246 void Finalize() { fTo->Merge(); }
248 HIST &PartialUpdate(
unsigned int slot) {
return *fTo->GetAtSlotRaw(slot); }
259 template <
typename RealT_t,
typename T,
typename COLL>
261 std::vector<std::shared_ptr<COLL>> fColls;
265 TakeHelper(
const std::shared_ptr<COLL> &resultColl,
const unsigned int nSlots)
267 fColls.emplace_back(resultColl);
268 for (
unsigned int i = 1; i < nSlots; ++i)
269 fColls.emplace_back(std::make_shared<COLL>());
271 TakeHelper(TakeHelper &&) =
default;
272 TakeHelper(
const TakeHelper &) =
delete;
276 void Exec(
unsigned int slot,
T &
v) { fColls[slot]->emplace_back(v); }
280 auto rColl = fColls[0];
281 for (
unsigned int i = 1; i < fColls.size(); ++i) {
282 auto &coll = fColls[i];
284 rColl->emplace_back(v);
289 COLL &PartialUpdate(
unsigned int slot) {
return *fColls[slot].get(); }
294 template <
typename RealT_t,
typename T>
295 class TakeHelper<RealT_t,
T,
std::vector<T>> {
296 std::vector<std::shared_ptr<std::vector<T>>> fColls;
300 TakeHelper(
const std::shared_ptr<std::vector<T>> &resultColl,
const unsigned int nSlots)
302 fColls.emplace_back(resultColl);
303 for (
unsigned int i = 1; i < nSlots; ++i) {
304 auto v = std::make_shared<std::vector<T>>();
306 fColls.emplace_back(v);
309 TakeHelper(TakeHelper &&) =
default;
310 TakeHelper(
const TakeHelper &) =
delete;
314 void Exec(
unsigned int slot,
T &v) { fColls[slot]->emplace_back(v); }
320 for (
auto &coll : fColls)
321 totSize += coll->size();
322 auto rColl = fColls[0];
323 rColl->reserve(totSize);
324 for (
unsigned int i = 1; i < fColls.size(); ++i) {
325 auto &coll = fColls[i];
326 rColl->insert(rColl->end(), coll->begin(), coll->end());
330 std::vector<T> &PartialUpdate(
unsigned int slot) {
return *fColls[slot]; }
335 template <
typename RealT_t,
typename COLL>
336 class TakeHelper<RealT_t,
TArrayBranch<RealT_t>, COLL> {
337 std::vector<std::shared_ptr<COLL>> fColls;
341 TakeHelper(
const std::shared_ptr<COLL> &resultColl,
const unsigned int nSlots)
343 fColls.emplace_back(resultColl);
344 for (
unsigned int i = 1; i < nSlots; ++i)
345 fColls.emplace_back(std::make_shared<COLL>());
347 TakeHelper(TakeHelper &&) =
default;
348 TakeHelper(
const TakeHelper &) =
delete;
356 auto rColl = fColls[0];
357 for (
unsigned int i = 1; i < fColls.size(); ++i) {
358 auto &coll = fColls[i];
359 for (
auto &v : *coll) {
360 rColl->emplace_back(v);
368 template <
typename RealT_t>
369 class TakeHelper<RealT_t,
TArrayBranch<RealT_t>,
std::vector<RealT_t>> {
370 std::vector<std::shared_ptr<std::vector<std::vector<RealT_t>>>> fColls;
374 TakeHelper(
const std::shared_ptr<std::vector<std::vector<RealT_t>>> &resultColl,
const unsigned int nSlots)
376 fColls.emplace_back(resultColl);
377 for (
unsigned int i = 1; i < nSlots; ++i) {
378 auto v = std::make_shared<std::vector<RealT_t>>();
380 fColls.emplace_back(v);
383 TakeHelper(TakeHelper &&) =
default;
384 TakeHelper(
const TakeHelper &) =
delete;
394 for (
auto &coll : fColls)
395 totSize += coll->size();
396 auto rColl = fColls[0];
397 rColl->reserve(totSize);
398 for (
unsigned int i = 1; i < fColls.size(); ++i) {
399 auto &coll = fColls[i];
400 rColl->insert(rColl->end(), coll->begin(), coll->end());
405 template <
typename F,
typename T>
408 const std::shared_ptr<T> fReduceRes;
409 std::vector<T> fReduceObjs;
413 ReduceHelper(
F &&f,
const std::shared_ptr<T> &reduceRes,
const unsigned int nSlots)
414 : fReduceFun(
std::move(f)), fReduceRes(reduceRes), fReduceObjs(nSlots, *reduceRes)
417 ReduceHelper(ReduceHelper &&) =
default;
418 ReduceHelper(
const ReduceHelper &) =
delete;
422 void Exec(
unsigned int slot,
const T &value) { fReduceObjs[slot] = fReduceFun(fReduceObjs[slot], value); }
426 for (
auto &t : fReduceObjs)
427 *fReduceRes = fReduceFun(*fReduceRes, t);
430 T &PartialUpdate(
unsigned int slot) {
return fReduceObjs[slot]; }
433 template <
typename ResultType>
435 const std::shared_ptr<ResultType> fResultMin;
436 std::vector<ResultType> fMins;
439 MinHelper(MinHelper &&) =
default;
440 MinHelper(
const std::shared_ptr<ResultType> &minVPtr,
const unsigned int nSlots)
441 : fResultMin(minVPtr), fMins(nSlots,
std::numeric_limits<ResultType>::max())
445 void Exec(
unsigned int slot, ResultType v) { fMins[slot] = std::min(v, fMins[slot]); }
449 template <typename T, typename std::enable_if<IsContainer<T>::value,
int>::type = 0>
450 void Exec(
unsigned int slot,
const T &vs)
453 fMins[slot] = std::min(v, fMins[slot]);
458 *fResultMin = std::numeric_limits<ResultType>::max();
459 for (
auto &
m : fMins)
460 *fResultMin = std::min(
m, *fResultMin);
463 ResultType &PartialUpdate(
unsigned int slot) {
return fMins[slot]; }
473 template <
typename ResultType>
475 const std::shared_ptr<ResultType> fResultMax;
476 std::vector<ResultType> fMaxs;
479 MaxHelper(MaxHelper &&) =
default;
480 MaxHelper(
const MaxHelper &) =
delete;
481 MaxHelper(
const std::shared_ptr<ResultType> &maxVPtr,
const unsigned int nSlots)
482 : fResultMax(maxVPtr), fMaxs(nSlots,
std::numeric_limits<ResultType>::lowest())
487 void Exec(
unsigned int slot, ResultType v) { fMaxs[slot] = std::max(v, fMaxs[slot]); }
489 template <typename T, typename std::enable_if<IsContainer<T>::value,
int>::type = 0>
490 void Exec(
unsigned int slot,
const T &vs)
493 fMaxs[slot] = std::max((ResultType)v, fMaxs[slot]);
498 *fResultMax = std::numeric_limits<ResultType>::lowest();
499 for (
auto &
m : fMaxs) {
500 *fResultMax = std::max(
m, *fResultMax);
504 ResultType &PartialUpdate(
unsigned int slot) {
return fMaxs[slot]; }
514 template <
typename ResultType>
516 const std::shared_ptr<ResultType> fResultSum;
517 std::vector<ResultType> fSums;
520 SumHelper(SumHelper &&) =
default;
521 SumHelper(
const SumHelper &) =
delete;
522 SumHelper(
const std::shared_ptr<ResultType> &sumVPtr,
const unsigned int nSlots)
523 : fResultSum(sumVPtr), fSums(nSlots, *sumVPtr - *sumVPtr)
528 void Exec(
unsigned int slot, ResultType v) { fSums[slot] +=
v; }
530 template <typename T, typename std::enable_if<IsContainer<T>::value,
int>::type = 0>
531 void Exec(
unsigned int slot,
const T &vs)
534 fSums[slot] +=
static_cast<ResultType
>(
v);
539 for (
auto &
m : fSums)
543 ResultType &PartialUpdate(
unsigned int slot) {
return fSums[slot]; }
547 const std::shared_ptr<double> fResultMean;
548 std::vector<ULong64_t> fCounts;
549 std::vector<double> fSums;
550 std::vector<double> fPartialMeans;
553 MeanHelper(
const std::shared_ptr<double> &meanVPtr,
const unsigned int nSlots);
554 MeanHelper(MeanHelper &&) =
default;
555 MeanHelper(
const MeanHelper &) =
delete;
557 void Exec(
unsigned int slot,
double v);
559 template <typename T, typename std::enable_if<IsContainer<T>::value,
int>::type = 0>
560 void Exec(
unsigned int slot,
const T &vs)
562 for (
auto &&v : vs) {
570 double &PartialUpdate(
unsigned int slot);
573 extern template void MeanHelper::Exec(
unsigned int,
const std::vector<float> &);
574 extern template void MeanHelper::Exec(
unsigned int,
const std::vector<double> &);
575 extern template void MeanHelper::Exec(
unsigned int,
const std::vector<char> &);
576 extern template void MeanHelper::Exec(
unsigned int,
const std::vector<int> &);
577 extern template void MeanHelper::Exec(
unsigned int,
const std::vector<unsigned int> &);
579 template <
typename T>
580 struct AddRefIfNotArrayBranch {
584 template <
typename T>
585 struct AddRefIfNotArrayBranch<TArrayBranch<T>> {
589 template <
typename T>
593 template <
typename T>
594 void SetBranchesHelper(TTree * , TTree &outputTree,
const std::string & ,
595 const std::string &
name,
T *address)
597 outputTree.Branch(name.c_str(), address);
603 template <
typename T>
604 void SetBranchesHelper(TTree *inputTree, TTree &outputTree,
const std::string &validName,
const std::string &name,
607 auto *
const inputBranch = inputTree->GetBranch(validName.c_str());
608 auto *
const leaf =
static_cast<TLeaf *
>(inputBranch->GetListOfLeaves()->UncheckedAt(0));
609 const auto bname = leaf->
GetName();
610 const auto counterStr =
611 leaf->GetLeafCount() ? std::string(leaf->GetLeafCount()->GetName()) : std::to_string(leaf->GetLenStatic());
612 const auto btype = leaf->GetTypeName();
614 const auto leaflist = std::string(bname) +
"[" + counterStr +
"]/" + rootbtype;
615 auto *
const outputBranch = outputTree.Branch(name.c_str(), ab->
GetData(), leaflist.c_str());
616 outputBranch->SetTitle(inputBranch->GetTitle());
620 template <
typename... BranchTypes>
621 class SnapshotHelper {
622 std::unique_ptr<TFile> fOutputFile;
623 std::unique_ptr<TTree> fOutputTree;
624 bool fIsFirstEvent{
true};
625 const ColumnNames_t fValidBranchNames;
626 const ColumnNames_t fBranchNames;
627 TTree *fInputTree =
nullptr;
631 const ColumnNames_t &vbnames,
const ColumnNames_t &bnames,
const TSnapshotOptions &options)
632 : fOutputFile(TFile::Open(
std::string(filename).c_str(), options.fMode.c_str(),
"",
633 ROOT::CompressionSettings(options.fCompressionAlgorithm, options.fCompressionLevel))),
634 fValidBranchNames(vbnames), fBranchNames(bnames)
636 if (!dirname.empty()) {
637 std::string dirnameStr(dirname);
638 fOutputFile->mkdir(dirnameStr.c_str());
639 fOutputFile->cd(dirnameStr.c_str());
641 std::string treenameStr(treename);
643 new TTree(treenameStr.c_str(), treenameStr.c_str(), options.
fSplitLevel, fOutputFile.get()));
646 fOutputTree->SetAutoFlush(options.
fAutoFlush);
649 SnapshotHelper(
const SnapshotHelper &) =
delete;
650 SnapshotHelper(SnapshotHelper &&) =
default;
659 fInputTree->AddClone(fOutputTree.get());
662 void Exec(
unsigned int , AddRefIfNotArrayBranch_t<BranchTypes>... values)
665 using ind_t = GenStaticSeq_t<
sizeof...(BranchTypes)>;
666 SetBranches(values..., ind_t());
672 void SetBranches(AddRefIfNotArrayBranch_t<BranchTypes>... values, StaticSeq<S...> )
676 (SetBranchesHelper(fInputTree, *fOutputTree, fValidBranchNames[
S], fBranchNames[S], &values), 0)..., 0};
678 fIsFirstEvent =
false;
681 void Finalize() { fOutputTree->Write(); }
685 template <
typename... BranchTypes>
686 class SnapshotHelperMT {
687 const unsigned int fNSlots;
688 std::unique_ptr<ROOT::Experimental::TBufferMerger> fMerger;
689 std::vector<std::shared_ptr<ROOT::Experimental::TBufferMergerFile>> fOutputFiles;
690 std::vector<TTree *> fOutputTrees;
691 std::vector<int> fIsFirstEvent;
692 const std::string fDirName;
693 const std::string fTreeName;
695 const ColumnNames_t fValidBranchNames;
696 const ColumnNames_t fBranchNames;
697 std::vector<TTree *> fInputTrees;
700 using BranchTypes_t =
TypeList<BranchTypes...>;
702 std::string_view treename,
const ColumnNames_t &vbnames,
const ColumnNames_t &bnames,
704 : fNSlots(nSlots), fMerger(new
ROOT::Experimental::TBufferMerger(
705 std::string(filename).c_str(), options.fMode.c_str(),
706 ROOT::CompressionSettings(options.fCompressionAlgorithm, options.fCompressionLevel))),
707 fOutputFiles(fNSlots), fOutputTrees(fNSlots, nullptr), fIsFirstEvent(fNSlots, 1), fDirName(dirname),
708 fTreeName(treename), fOptions(options), fValidBranchNames(vbnames), fBranchNames(bnames), fInputTrees(fNSlots)
711 SnapshotHelperMT(
const SnapshotHelperMT &) =
delete;
712 SnapshotHelperMT(SnapshotHelperMT &&) =
default;
717 if (!fOutputTrees[slot]) {
719 fOutputFiles[slot] = fMerger->
GetFile();
722 fOutputFiles[slot]->Write();
724 TDirectory *treeDirectory = fOutputFiles[slot].get();
725 if (!fDirName.empty()) {
726 treeDirectory = fOutputFiles[slot]->mkdir(fDirName.c_str());
730 fOutputTrees[slot] =
new TTree(fTreeName.c_str(), fTreeName.c_str(), fOptions.
fSplitLevel, treeDirectory);
733 fOutputTrees[slot]->SetAutoFlush(fOptions.
fAutoFlush);
736 fInputTrees[slot] = r->
GetTree();
739 fInputTrees[slot]->AddClone(fOutputTrees[slot]);
741 fIsFirstEvent[slot] = 1;
744 void Exec(
unsigned int slot, AddRefIfNotArrayBranch_t<BranchTypes>... values)
746 if (fIsFirstEvent[slot]) {
747 using ind_t = GenStaticSeq_t<
sizeof...(BranchTypes)>;
748 SetBranches(slot, values..., ind_t());
749 fIsFirstEvent[slot] = 0;
751 fOutputTrees[slot]->Fill();
752 auto entries = fOutputTrees[slot]->GetEntries();
753 auto autoFlush = fOutputTrees[slot]->GetAutoFlush();
754 if ((autoFlush > 0) && (entries % autoFlush == 0))
755 fOutputFiles[slot]->Write();
759 void SetBranches(
unsigned int slot, AddRefIfNotArrayBranch_t<BranchTypes>... values, StaticSeq<S...> )
763 (SetBranchesHelper(fInputTrees[slot], *fOutputTrees[slot], fValidBranchNames[
S], fBranchNames[S], &values),
771 for (
auto &
file : fOutputFiles) {
virtual const char * GetName() const
Returns name of object.
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
A collection of options to steer the creation of the dataset on file.
char TypeName2ROOTTypeName(const std::string &b)
Convert type name (e.g.
TTreeReader is a simple, robust and fast interface to read values from a TTree, TChain or TNtuple...
basic_string_view< char > string_view
Namespace for new ROOT classes and functions.
static const double x2[5]
When using TDataFrame to read data from a ROOT file, users can specify that the type of a branch is T...
RooArgSet S(const RooAbsArg &v1)
Lightweight storage for a collection of types.
static const double x1[5]
Describe directory structure in memory.
unsigned long long ULong64_t
ROOT type_traits extensions.
typedef void((*Func_t)())
std::shared_ptr< TBufferMergerFile > GetFile()
Returns a TBufferMergerFile to which data can be written.
THist< 1, double, THistStatContent, THistStatUncertainty > TH1D
Check for container traits.
static const double x3[11]