Logo ROOT   6.10/09
Reference Guide
TDFActionHelpers.hxx
Go to the documentation of this file.
1 // Author: Enrico Guiraud, Danilo Piparo CERN 12/2016
2 
3 /*************************************************************************
4  * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers. *
5  * All rights reserved. *
6  * *
7  * For the licensing terms see $ROOTSYS/LICENSE. *
8  * For the list of contributors see $ROOTSYS/README/CREDITS. *
9  *************************************************************************/
10 
11 #ifndef ROOT_TDFOPERATIONS
12 #define ROOT_TDFOPERATIONS
13 
14 #include "ROOT/TDFUtils.hxx"
15 #include "ROOT/TThreadedObject.hxx"
16 #include "TH1.h"
17 
18 #include <algorithm>
19 #include <memory>
20 #include <stdexcept>
21 #include <type_traits>
22 #include <vector>
23 
24 /// \cond HIDDEN_SYMBOLS
25 
26 namespace ROOT {
27 namespace Internal {
28 namespace TDF {
29 
30 using Count_t = unsigned long;
31 using Hist_t = ::TH1F;
32 
33 template <typename F>
34 class ForeachSlotHelper {
35  F fCallable;
36 
37 public:
38  using BranchTypes_t = typename TRemoveFirst<typename TFunctionTraits<F>::Args_t>::Types_t;
39  ForeachSlotHelper(F &&f) : fCallable(f) {}
40 
41  void Init(TTreeReader*, unsigned int) {}
42 
43  template <typename... Args>
44  void Exec(unsigned int slot, Args &&... args)
45  {
46  // check that the decayed types of Args are the same as the branch types
47  static_assert(std::is_same<TTypeList<typename std::decay<Args>::type...>, BranchTypes_t>::value, "");
48  fCallable(slot, std::forward<Args>(args)...);
49  }
50 
51  void Finalize() { /* noop */}
52 };
53 
54 class CountHelper {
55  std::shared_ptr<unsigned int> fResultCount;
56  std::vector<Count_t> fCounts;
57 
58 public:
59  using BranchTypes_t = TTypeList<>;
60  CountHelper(const std::shared_ptr<unsigned int> &resultCount, unsigned int nSlots);
61  void Init(TTreeReader*, unsigned int) {}
62  void Exec(unsigned int slot);
63  void Finalize();
64 };
65 
66 class FillHelper {
67  // this sets a total initial size of 16 MB for the buffers (can increase)
68  static constexpr unsigned int fgTotalBufSize = 2097152;
69  using BufEl_t = double;
70  using Buf_t = std::vector<BufEl_t>;
71 
72  std::vector<Buf_t> fBuffers;
73  std::vector<Buf_t> fWBuffers;
74  std::shared_ptr<Hist_t> fResultHist;
75  unsigned int fNSlots;
76  unsigned int fBufSize;
77  Buf_t fMin;
78  Buf_t fMax;
79 
80  void UpdateMinMax(unsigned int slot, double v);
81 
82 public:
83  FillHelper(const std::shared_ptr<Hist_t> &h, unsigned int nSlots);
84  void Init(TTreeReader*, unsigned int) {}
85  void Exec(unsigned int slot, double v);
86  void Exec(unsigned int slot, double v, double w);
87 
88  template <typename T, typename std::enable_if<TIsContainer<T>::fgValue, int>::type = 0>
89  void Exec(unsigned int slot, const T &vs)
90  {
91  auto &thisBuf = fBuffers[slot];
92  for (auto &v : vs) {
93  UpdateMinMax(slot, v);
94  thisBuf.emplace_back(v); // TODO: Can be optimised in case T == BufEl_t
95  }
96  }
97 
98  template <typename T, typename W,
99  typename std::enable_if<TIsContainer<T>::fgValue && TIsContainer<W>::fgValue, int>::type = 0>
100  void Exec(unsigned int slot, const T &vs, const W &ws)
101  {
102  auto &thisBuf = fBuffers[slot];
103  for (auto &v : vs) {
104  UpdateMinMax(slot, v);
105  thisBuf.emplace_back(v); // TODO: Can be optimised in case T == BufEl_t
106  }
107 
108  auto &thisWBuf = fWBuffers[slot];
109  for (auto &w : ws) {
110  thisWBuf.emplace_back(w); // TODO: Can be optimised in case T == BufEl_t
111  }
112  }
113 
114  void Finalize();
115 };
116 
117 extern template void FillHelper::Exec(unsigned int, const std::vector<float> &);
118 extern template void FillHelper::Exec(unsigned int, const std::vector<double> &);
119 extern template void FillHelper::Exec(unsigned int, const std::vector<char> &);
120 extern template void FillHelper::Exec(unsigned int, const std::vector<int> &);
121 extern template void FillHelper::Exec(unsigned int, const std::vector<unsigned int> &);
122 extern template void FillHelper::Exec(unsigned int, const std::vector<float> &, const std::vector<float> &);
123 extern template void FillHelper::Exec(unsigned int, const std::vector<double> &, const std::vector<double> &);
124 extern template void FillHelper::Exec(unsigned int, const std::vector<char> &, const std::vector<char> &);
125 extern template void FillHelper::Exec(unsigned int, const std::vector<int> &, const std::vector<int> &);
126 extern template void FillHelper::Exec(unsigned int, const std::vector<unsigned int> &,
127  const std::vector<unsigned int> &);
128 
129 template <typename HIST = Hist_t>
130 class FillTOHelper {
131  std::unique_ptr<TThreadedObject<HIST>> fTo;
132 
133 public:
134  FillTOHelper(FillTOHelper &&) = default;
135 
136  FillTOHelper(const std::shared_ptr<HIST> &h, unsigned int nSlots) : fTo(new TThreadedObject<HIST>(*h))
137  {
138  fTo->SetAtSlot(0, h);
139  // Initialise all other slots
140  for (unsigned int i = 0; i < nSlots; ++i) {
141  fTo->GetAtSlot(i);
142  }
143  }
144 
145  void Init(TTreeReader*, unsigned int) {}
146 
147  void Exec(unsigned int slot, double x0) // 1D histos
148  {
149  fTo->GetAtSlotUnchecked(slot)->Fill(x0);
150  }
151 
152  void Exec(unsigned int slot, double x0, double x1) // 1D weighted and 2D histos
153  {
154  fTo->GetAtSlotUnchecked(slot)->Fill(x0, x1);
155  }
156 
157  void Exec(unsigned int slot, double x0, double x1, double x2) // 2D weighted and 3D histos
158  {
159  fTo->GetAtSlotUnchecked(slot)->Fill(x0, x1, x2);
160  }
161 
162  void Exec(unsigned int slot, double x0, double x1, double x2, double x3) // 3D weighted histos
163  {
164  fTo->GetAtSlotUnchecked(slot)->Fill(x0, x1, x2, x3);
165  }
166 
167  template <typename X0, typename std::enable_if<TIsContainer<X0>::fgValue, int>::type = 0>
168  void Exec(unsigned int slot, const X0 &x0s)
169  {
170  auto thisSlotH = fTo->GetAtSlotUnchecked(slot);
171  for (auto &x0 : x0s) {
172  thisSlotH->Fill(x0); // TODO: Can be optimised in case T == vector<double>
173  }
174  }
175 
176  template <typename X0, typename X1,
177  typename std::enable_if<TIsContainer<X0>::fgValue && TIsContainer<X1>::fgValue, int>::type = 0>
178  void Exec(unsigned int slot, const X0 &x0s, const X1 &x1s)
179  {
180  auto thisSlotH = fTo->GetAtSlotUnchecked(slot);
181  if (x0s.size() != x1s.size()) {
182  throw std::runtime_error("Cannot fill histogram with values in containers of different sizes.");
183  }
184  auto x0sIt = std::begin(x0s);
185  const auto x0sEnd = std::end(x0s);
186  auto x1sIt = std::begin(x1s);
187  for (; x0sIt != x0sEnd; x0sIt++, x1sIt++) {
188  thisSlotH->Fill(*x0sIt, *x1sIt); // TODO: Can be optimised in case T == vector<double>
189  }
190  }
191 
192  template <typename X0, typename X1, typename X2,
193  typename std::enable_if<
194  TIsContainer<X0>::fgValue && TIsContainer<X1>::fgValue && TIsContainer<X2>::fgValue, int>::type = 0>
195  void Exec(unsigned int slot, const X0 &x0s, const X1 &x1s, const X2 &x2s)
196  {
197  auto thisSlotH = fTo->GetAtSlotUnchecked(slot);
198  if (!(x0s.size() == x1s.size() && x1s.size() == x2s.size())) {
199  throw std::runtime_error("Cannot fill histogram with values in containers of different sizes.");
200  }
201  auto x0sIt = std::begin(x0s);
202  const auto x0sEnd = std::end(x0s);
203  auto x1sIt = std::begin(x1s);
204  auto x2sIt = std::begin(x2s);
205  for (; x0sIt != x0sEnd; x0sIt++, x1sIt++, x2sIt++) {
206  thisSlotH->Fill(*x0sIt, *x1sIt, *x2sIt); // TODO: Can be optimised in case T == vector<double>
207  }
208  }
209  template <typename X0, typename X1, typename X2, typename X3,
210  typename std::enable_if<TIsContainer<X0>::fgValue && TIsContainer<X1>::fgValue &&
211  TIsContainer<X2>::fgValue && TIsContainer<X3>::fgValue,
212  int>::type = 0>
213  void Exec(unsigned int slot, const X0 &x0s, const X1 &x1s, const X2 &x2s, const X3 &x3s)
214  {
215  auto thisSlotH = fTo->GetAtSlotUnchecked(slot);
216  if (!(x0s.size() == x1s.size() && x1s.size() == x2s.size() && x1s.size() == x3s.size())) {
217  throw std::runtime_error("Cannot fill histogram with values in containers of different sizes.");
218  }
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  auto x3sIt = std::begin(x3s);
224  for (; x0sIt != x0sEnd; x0sIt++, x1sIt++, x2sIt++, x3sIt++) {
225  thisSlotH->Fill(*x0sIt, *x1sIt, *x2sIt, *x3sIt); // TODO: Can be optimised in case T == vector<double>
226  }
227  }
228  void Finalize() { fTo->Merge(); }
229 };
230 
231 // note: changes to this class should probably be replicated in its partial
232 // specialization below
233 template <typename T, typename COLL>
234 class TakeHelper {
235  std::vector<std::shared_ptr<COLL>> fColls;
236 
237 public:
238  using BranchTypes_t = TTypeList<T>;
239  TakeHelper(const std::shared_ptr<COLL> &resultColl, unsigned int nSlots)
240  {
241  fColls.emplace_back(resultColl);
242  for (unsigned int i = 1; i < nSlots; ++i) fColls.emplace_back(std::make_shared<COLL>());
243  }
244 
245  void Init(TTreeReader*, unsigned int) {}
246 
247  void Exec(unsigned int slot, T v)
248  {
249  fColls[slot]->emplace_back(v);
250  }
251 
252  void Finalize()
253  {
254  auto rColl = fColls[0];
255  for (unsigned int i = 1; i < fColls.size(); ++i) {
256  auto &coll = fColls[i];
257  for (T &v : *coll) {
258  rColl->emplace_back(v);
259  }
260  }
261  }
262 };
263 
264 // note: changes to this class should probably be replicated in its unspecialized
265 // declaration above
266 template <typename T>
267 class TakeHelper<T, std::vector<T>> {
268  std::vector<std::shared_ptr<std::vector<T>>> fColls;
269 
270 public:
271  using BranchTypes_t = TTypeList<T>;
272  TakeHelper(const std::shared_ptr<std::vector<T>> &resultColl, unsigned int nSlots)
273  {
274  fColls.emplace_back(resultColl);
275  for (unsigned int i = 1; i < nSlots; ++i) {
276  auto v = std::make_shared<std::vector<T>>();
277  v->reserve(1024);
278  fColls.emplace_back(v);
279  }
280  }
281 
282  void Init(TTreeReader*, unsigned int) {}
283 
284  void Exec(unsigned int slot, T v)
285  {
286  fColls[slot]->emplace_back(v);
287  }
288 
289  void Finalize()
290  {
291  ULong64_t totSize = 0;
292  for (auto &coll : fColls) totSize += coll->size();
293  auto rColl = fColls[0];
294  rColl->reserve(totSize);
295  for (unsigned int i = 1; i < fColls.size(); ++i) {
296  auto &coll = fColls[i];
297  rColl->insert(rColl->end(), coll->begin(), coll->end());
298  }
299  }
300 };
301 
302 template <typename F, typename T>
303 class ReduceHelper {
304  F fReduceFun;
305  std::shared_ptr<T> fReduceRes;
306  std::vector<T> fReduceObjs;
307 
308 public:
309  using BranchTypes_t = TTypeList<T>;
310  ReduceHelper(F &&f, const std::shared_ptr<T> &reduceRes, unsigned int nSlots)
311  : fReduceFun(std::move(f)), fReduceRes(reduceRes), fReduceObjs(nSlots, *reduceRes)
312  {
313  }
314 
315  void Init(TTreeReader*, unsigned int) {}
316 
317  void Exec(unsigned int slot, const T &value) { fReduceObjs[slot] = fReduceFun(fReduceObjs[slot], value); }
318 
319  void Finalize()
320  {
321  for (auto &t : fReduceObjs) *fReduceRes = fReduceFun(*fReduceRes, t);
322  }
323 };
324 
325 class MinHelper {
326  std::shared_ptr<double> fResultMin;
327  std::vector<double> fMins;
328 
329 public:
330  MinHelper(const std::shared_ptr<double> &minVPtr, unsigned int nSlots);
331 
332  void Init(TTreeReader*, unsigned int) {}
333 
334  void Exec(unsigned int slot, double v);
335 
336  template <typename T, typename std::enable_if<TIsContainer<T>::fgValue, int>::type = 0>
337  void Exec(unsigned int slot, const T &vs)
338  {
339  for (auto &&v : vs) fMins[slot] = std::min((double)v, fMins[slot]);
340  }
341 
342  void Finalize();
343 };
344 
345 extern template void MinHelper::Exec(unsigned int, const std::vector<float> &);
346 extern template void MinHelper::Exec(unsigned int, const std::vector<double> &);
347 extern template void MinHelper::Exec(unsigned int, const std::vector<char> &);
348 extern template void MinHelper::Exec(unsigned int, const std::vector<int> &);
349 extern template void MinHelper::Exec(unsigned int, const std::vector<unsigned int> &);
350 
351 class MaxHelper {
352  std::shared_ptr<double> fResultMax;
353  std::vector<double> fMaxs;
354 
355 public:
356  MaxHelper(const std::shared_ptr<double> &maxVPtr, unsigned int nSlots);
357  void Init(TTreeReader*, unsigned int) {}
358  void Exec(unsigned int slot, double v);
359 
360  template <typename T, typename std::enable_if<TIsContainer<T>::fgValue, int>::type = 0>
361  void Exec(unsigned int slot, const T &vs)
362  {
363  for (auto &&v : vs) fMaxs[slot] = std::max((double)v, fMaxs[slot]);
364  }
365 
366  void Finalize();
367 };
368 
369 extern template void MaxHelper::Exec(unsigned int, const std::vector<float> &);
370 extern template void MaxHelper::Exec(unsigned int, const std::vector<double> &);
371 extern template void MaxHelper::Exec(unsigned int, const std::vector<char> &);
372 extern template void MaxHelper::Exec(unsigned int, const std::vector<int> &);
373 extern template void MaxHelper::Exec(unsigned int, const std::vector<unsigned int> &);
374 
375 class MeanHelper {
376  std::shared_ptr<double> fResultMean;
377  std::vector<Count_t> fCounts;
378  std::vector<double> fSums;
379 
380 public:
381  MeanHelper(const std::shared_ptr<double> &meanVPtr, unsigned int nSlots);
382  void Init(TTreeReader*, unsigned int) {}
383  void Exec(unsigned int slot, double v);
384 
385  template <typename T, typename std::enable_if<TIsContainer<T>::fgValue, int>::type = 0>
386  void Exec(unsigned int slot, const T &vs)
387  {
388  for (auto &&v : vs) {
389  fSums[slot] += v;
390  fCounts[slot]++;
391  }
392  }
393 
394  void Finalize();
395 };
396 
397 extern template void MeanHelper::Exec(unsigned int, const std::vector<float> &);
398 extern template void MeanHelper::Exec(unsigned int, const std::vector<double> &);
399 extern template void MeanHelper::Exec(unsigned int, const std::vector<char> &);
400 extern template void MeanHelper::Exec(unsigned int, const std::vector<int> &);
401 extern template void MeanHelper::Exec(unsigned int, const std::vector<unsigned int> &);
402 
403 template <typename F1, typename F2>
404 class SnapshotHelper {
405  F1 fInitFunc;
406  F2 fExecFunc;
407 
408 public:
409  using BranchTypes_t = typename TRemoveFirst<typename TFunctionTraits<F2>::Args_t>::Types_t;
410  SnapshotHelper(F1 &&f1, F2 &&f2) : fInitFunc(f1), fExecFunc(f2) {}
411 
412  void Init(TTreeReader *r, unsigned int slot) { fInitFunc(r, slot); }
413 
414  template <typename... Args>
415  void Exec(unsigned int slot, Args &&... args)
416  {
417  // check that the decayed types of Args are the same as the branch types
418  static_assert(std::is_same<TTypeList<typename std::decay<Args>::type...>, BranchTypes_t>::value, "");
419  fExecFunc(slot, std::forward<Args>(args)...);
420  }
421 
422  void Finalize() { /* noop */}
423 };
424 
425 } // end of NS TDF
426 } // end of NS Internal
427 } // end of NS ROOT
428 
429 /// \endcond
430 
431 #endif
TTreeReader is a simple, robust and fast interface to read values from a TTree, TChain or TNtuple...
Definition: TTreeReader.h:43
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
double T(double x)
Definition: ChebyshevPol.h:34
THist< 1, float, THistStatContent, THistStatUncertainty > TH1F
Definition: THist.hxx:311
TH1 * h
Definition: legend2.C:5
STL namespace.
static const double x2[5]
#define F1(x, y, z)
Definition: TMD5.cxx:267
#define F(x, y, z)
TRandom2 r(17)
SVector< double, 2 > v
Definition: Dict.h:5
#define F2(x, y, z)
Definition: TMD5.cxx:268
static const double x1[5]
double f(double x)
int type
Definition: TGX11.cxx:120
unsigned long long ULong64_t
Definition: RtypesCore.h:70
double f2(const double *x)
TF1 * f1
Definition: legend1.C:11
static const double x3[11]