Logo ROOT   6.10/09
Reference Guide
TDFInterface.hxx
Go to the documentation of this file.
1 // Author: Enrico Guiraud, Danilo Piparo CERN 03/2017
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_TDF_TINTERFACE
12 #define ROOT_TDF_TINTERFACE
13 
14 #include "ROOT/TBufferMerger.hxx"
15 #include "ROOT/TResultProxy.hxx"
16 #include "ROOT/TDFNodes.hxx"
18 #include "ROOT/TDFUtils.hxx"
19 #include "TChain.h"
20 #include "TFile.h"
21 #include "TH1.h" // For Histo actions
22 #include "TH2.h" // For Histo actions
23 #include "TH3.h" // For Histo actions
24 #include "TInterpreter.h"
25 #include "TProfile.h" // For Histo actions
26 #include "TProfile2D.h" // For Histo actions
27 #include "TRegexp.h"
28 #include "TROOT.h" // IsImplicitMTEnabled
29 #include "TTreeReader.h"
30 
31 #include <initializer_list>
32 #include <memory>
33 #include <string>
34 #include <sstream>
35 #include <typeinfo>
36 #include <type_traits> // is_same, enable_if
37 
38 namespace ROOT {
39 
40 namespace Internal {
41 namespace TDF {
42 using namespace ROOT::Experimental::TDF;
43 using namespace ROOT::Detail::TDF;
44 
45 using TmpBranchBasePtr_t = std::shared_ptr<TCustomColumnBase>;
46 
47 template <typename TDFNode, typename ActionType, typename... BranchTypes, typename ActionResultType>
48 void CallBuildAndBook(TDFNode *node, const ColumnNames_t &bl, unsigned int nSlots,
49  const std::shared_ptr<ActionResultType> &r)
50 {
51  node->template BuildAndBook<BranchTypes...>(bl, r, nSlots, (ActionType *)nullptr);
52 }
53 
54 std::vector<std::string> GetUsedBranchesNames(const std::string, TObjArray *, const std::vector<std::string> &);
55 
56 Long_t JitTransformation(void *thisPtr, const std::string &methodName, const std::string &nodeTypeName,
57  const std::string &name, const std::string &expression, TObjArray *branches,
58  const std::vector<std::string> &tmpBranches,
59  const std::map<std::string, TmpBranchBasePtr_t> &tmpBookedBranches, TTree *tree);
60 
61 void JitBuildAndBook(const ColumnNames_t &bl, const std::string &nodeTypename, void *thisPtr, const std::type_info &art,
62  const std::type_info &at, const void *r, TTree *tree, unsigned int nSlots,
63  const std::map<std::string, TmpBranchBasePtr_t> &tmpBranches);
64 
65 } // namespace TDF
66 } // namespace Internal
67 
68 namespace Experimental {
69 
70 // forward declarations
71 class TDataFrame;
72 
73 } // namespace Experimental
74 } // namespace ROOT
75 
76 namespace cling {
77 std::string printValue(ROOT::Experimental::TDataFrame *tdf); // For a nice printing at the promp
78 }
79 
80 namespace ROOT {
81 namespace Experimental {
82 namespace TDF {
83 namespace TDFDetail = ROOT::Detail::TDF;
85 
86 /**
87 * \class ROOT::Experimental::TDF::TInterface
88 * \ingroup dataframe
89 * \brief The public interface to the TDataFrame federation of classes
90 * \tparam T One of the "node" base types (e.g. TLoopManager, TFilterBase). The user never specifies this type manually.
91 */
92 template <typename Proxied>
93 class TInterface {
94  using ColumnNames_t = TDFDetail::ColumnNames_t;
99  friend std::string cling::printValue(ROOT::Experimental::TDataFrame *tdf); // For a nice printing at the prompt
100  template <typename T>
101  friend class TInterface;
102  template <typename TDFNode, typename ActionType, typename... BranchTypes, typename ActionResultType>
103  friend void TDFInternal::CallBuildAndBook(TDFNode *, const TDFDetail::ColumnNames_t &, unsigned int nSlots,
104  const std::shared_ptr<ActionResultType> &);
105 
106 public:
107  ////////////////////////////////////////////////////////////////////////////
108  /// \brief Append a filter to the call graph.
109  /// \param[in] f Function, lambda expression, functor class or any other callable object. It must return a `bool`
110  /// signalling whether the event has passed the selection (true) or not (false).
111  /// \param[in] bn Names of the branches in input to the filter function.
112  /// \param[in] name Optional name of this filter. See `Report`.
113  ///
114  /// Append a filter node at the point of the call graph corresponding to the
115  /// object this method is called on.
116  /// The callable `f` should not have side-effects (e.g. modification of an
117  /// external or static variable) to ensure correct results when implicit
118  /// multi-threading is active.
119  ///
120  /// TDataFrame only evaluates filters when necessary: if multiple filters
121  /// are chained one after another, they are executed in order and the first
122  /// one returning false causes the event to be discarded.
123  /// Even if multiple actions or transformations depend on the same filter,
124  /// it is executed once per entry. If its result is requested more than
125  /// once, the cached result is served.
126  template <typename F, typename std::enable_if<!std::is_convertible<F, std::string>::value, int>::type = 0>
127  TInterface<TFilterBase> Filter(F f, const ColumnNames_t &bn = {}, std::string_view name = "")
128  {
129  TDFInternal::CheckFilter(f);
130  auto df = GetDataFrameChecked();
131  const ColumnNames_t &defBl = df->GetDefaultBranches();
132  auto nArgs = TDFInternal::TFunctionTraits<F>::Args_t::fgSize;
133  const ColumnNames_t &actualBl = TDFInternal::PickBranchNames(nArgs, bn, defBl);
134  using DFF_t = TDFDetail::TFilter<F, Proxied>;
135  auto FilterPtr = std::make_shared<DFF_t>(std::move(f), actualBl, *fProxiedPtr, name);
136  fProxiedPtr->IncrChildrenCount();
137  df->Book(FilterPtr);
138  TInterface<TFilterBase> tdf_f(FilterPtr, fImplWeakPtr);
139  return tdf_f;
140  }
141 
142  ////////////////////////////////////////////////////////////////////////////
143  /// \brief Append a filter to the call graph.
144  /// \param[in] f Function, lambda expression, functor class or any other callable object. It must return a `bool`
145  /// signalling whether the event has passed the selection (true) or not (false).
146  /// \param[in] name Optional name of this filter. See `Report`.
147  ///
148  /// Refer to the first overload of this method for the full documentation.
149  template <typename F, typename std::enable_if<!std::is_convertible<F, std::string>::value, int>::type = 0>
150  TInterface<TFilterBase> Filter(F f, std::string_view name)
151  {
152  // The sfinae is there in order to pick up the overloaded method which accepts two strings
153  // rather than this template method.
154  return Filter(f, {}, name);
155  }
156 
157  ////////////////////////////////////////////////////////////////////////////
158  /// \brief Append a filter to the call graph.
159  /// \param[in] f Function, lambda expression, functor class or any other callable object. It must return a `bool`
160  /// signalling whether the event has passed the selection (true) or not (false).
161  /// \param[in] bn Names of the branches in input to the filter function.
162  ///
163  /// Refer to the first overload of this method for the full documentation.
164  template <typename F>
165  TInterface<TFilterBase> Filter(F f, const std::initializer_list<std::string> &bn)
166  {
167  return Filter(f, ColumnNames_t{bn});
168  }
169 
170  ////////////////////////////////////////////////////////////////////////////
171  /// \brief Append a filter to the call graph.
172  /// \param[in] expression The filter expression in C++
173  /// \param[in] name Optional name of this filter. See `Report`.
174  ///
175  /// The expression is just in time compiled and used to filter entries. The
176  /// variable names to be used inside are the names of the branches. Only
177  /// valid C++ is accepted.
178  /// Refer to the first overload of this method for the full documentation.
179  TInterface<TFilterBase> Filter(std::string_view expression, std::string_view name = "")
180  {
181  auto df = GetDataFrameChecked();
182  auto tree = df->GetTree();
183  auto branches = tree ? tree->GetListOfBranches() : nullptr;
184  auto tmpBranches = fProxiedPtr->GetTmpBranches();
185  auto tmpBookedBranches = df->GetBookedBranches();
186  const std::string expressionInt(expression);
187  const std::string nameInt(name);
188  auto retVal = TDFInternal::JitTransformation(this, "Filter", GetNodeTypeName(), nameInt, expressionInt, branches,
189  tmpBranches, tmpBookedBranches, tree);
190  return *(TInterface<TFilterBase> *)retVal;
191  }
192 
193  ////////////////////////////////////////////////////////////////////////////
194  /// \brief Creates a temporary branch
195  /// \param[in] name The name of the temporary branch.
196  /// \param[in] expression Function, lambda expression, functor class or any other callable object producing the
197  /// temporary value. Returns the value that will be assigned to the temporary branch.
198  /// \param[in] bl Names of the branches in input to the producer function.
199  ///
200  /// Create a temporary branch that will be visible from all subsequent nodes
201  /// of the functional chain. The `expression` is only evaluated for entries that pass
202  /// all the preceding filters.
203  /// A new variable is created called `name`, accessible as if it was contained
204  /// in the dataset from subsequent transformations/actions.
205  ///
206  /// Use cases include:
207  ///
208  /// * caching the results of complex calculations for easy and efficient multiple access
209  /// * extraction of quantities of interest from complex objects
210  /// * branch aliasing, i.e. changing the name of a branch
211  ///
212  /// An exception is thrown if the name of the new branch is already in use
213  /// for another branch in the TTree.
214  template <typename F, typename std::enable_if<!std::is_convertible<F, std::string>::value, int>::type = 0>
215  TInterface<TCustomColumnBase> Define(std::string_view name, F expression, const ColumnNames_t &bl = {})
216  {
217  auto df = GetDataFrameChecked();
218  TDFInternal::CheckTmpBranch(name, df->GetTree());
219  const ColumnNames_t &defBl = df->GetDefaultBranches();
220  auto nArgs = TDFInternal::TFunctionTraits<F>::Args_t::fgSize;
221  const ColumnNames_t &actualBl = TDFInternal::PickBranchNames(nArgs, bl, defBl);
223  const std::string nameInt(name);
224  auto BranchPtr = std::make_shared<DFB_t>(nameInt, std::move(expression), actualBl, *fProxiedPtr);
225  fProxiedPtr->IncrChildrenCount();
226  df->Book(BranchPtr);
227  TInterface<TCustomColumnBase> tdf_b(BranchPtr, fImplWeakPtr);
228  return tdf_b;
229  }
230 
231  ////////////////////////////////////////////////////////////////////////////
232  /// \brief Creates a temporary branch
233  /// \param[in] name The name of the temporary branch.
234  /// \param[in] expression An expression in C++ which represents the temporary value
235  ///
236  /// The expression is just in time compiled and used to produce new values. The
237  /// variable names to be used inside are the names of the branches. Only
238  /// valid C++ is accepted.
239  /// Refer to the first overload of this method for the full documentation.
240  TInterface<TCustomColumnBase> Define(std::string_view name, std::string_view expression)
241  {
242  auto df = GetDataFrameChecked();
243  // this check must be done before jitting lest we throw exceptions in jitted code
244  TDFInternal::CheckTmpBranch(name, df->GetTree());
245  auto tree = df->GetTree();
246  auto branches = tree ? tree->GetListOfBranches() : nullptr;
247  auto tmpBranches = fProxiedPtr->GetTmpBranches();
248  auto tmpBookedBranches = df->GetBookedBranches();
249  const std::string expressionInt(expression);
250  const std::string nameInt(name);
251  auto retVal = TDFInternal::JitTransformation(this, "Define", GetNodeTypeName(), nameInt, expressionInt, branches,tmpBranches, tmpBookedBranches, tree);
252  return *(TInterface<TCustomColumnBase> *)retVal;
253  }
254 
255  ////////////////////////////////////////////////////////////////////////////
256  /// \brief Create a snapshot of the dataset on disk in the form of a TTree
257  /// \tparam BranchTypes variadic list of branch/column types
258  /// \param[in] treename The name of the output TTree
259  /// \param[in] filename The name of the output TFile
260  /// \param[in] bnames The list of names of the branches to be written
261  ///
262  /// This function returns a `TDataFrame` built with the output tree as a source.
263  template <typename... BranchTypes>
264  TInterface<TLoopManager> Snapshot(std::string_view treename, std::string_view filename,
265  const ColumnNames_t &bnames)
266  {
267  using TypeInd_t = typename TDFInternal::TGenStaticSeq<sizeof...(BranchTypes)>::Type_t;
268  return SnapshotImpl<BranchTypes...>(treename, filename, bnames, TypeInd_t());
269  }
270 
271  ////////////////////////////////////////////////////////////////////////////
272  /// \brief Create a snapshot of the dataset on disk in the form of a TTree
273  /// \param[in] treename The name of the output TTree
274  /// \param[in] filename The name of the output TFile
275  /// \param[in] bnames The list of names of the branches to be written
276  ///
277  /// This function returns a `TDataFrame` built with the output tree as a source.
278  /// The types of the branches are automatically inferred and do not need to be specified.
279  TInterface<TLoopManager> Snapshot(std::string_view treename, std::string_view filename,
280  const ColumnNames_t &bnames)
281  {
282  auto df = GetDataFrameChecked();
283  auto tree = df->GetTree();
284  std::stringstream snapCall;
285  // build a string equivalent to
286  // "reinterpret_cast</nodetype/*>(this)->Snapshot<Ts...>(treename,filename,*reinterpret_cast<ColumnNames_t*>(&bnames))"
287  snapCall << "if (gROOTMutex) gROOTMutex->UnLock(); ((" << GetNodeTypeName() << "*)" << this << ")->Snapshot<";
288  bool first = true;
289  for (auto &b : bnames) {
290  if (!first) snapCall << ", ";
291  snapCall << TDFInternal::ColumnName2ColumnTypeName(b, tree, df->GetBookedBranch(b));
292  first = false;
293  };
294  const std::string treeNameInt(treename);
295  const std::string filenameInt(filename);
296  snapCall << ">(\"" << treeNameInt << "\", \"" << filenameInt << "\", "
297  << "*reinterpret_cast<std::vector<std::string>*>(" // vector<string> should be ColumnNames_t
298  << &bnames << "));";
299  // jit snapCall, return result
300  TInterpreter::EErrorCode errorCode;
301  auto newTDFPtr = gInterpreter->Calc(snapCall.str().c_str(), &errorCode);
302  if (TInterpreter::EErrorCode::kNoError != errorCode) {
303  std::string msg = "Cannot jit Snapshot call. Interpreter error code is " + std::to_string(errorCode) + ".";
304  throw std::runtime_error(msg);
305  }
306  return *reinterpret_cast<TInterface<TLoopManager> *>(newTDFPtr);
307  }
308 
309  ////////////////////////////////////////////////////////////////////////////
310  /// \brief Create a snapshot of the dataset on disk in the form of a TTree
311  /// \param[in] treename The name of the output TTree
312  /// \param[in] filename The name of the output TFile
313  /// \param[in] columnNameRegexp The regular expression to match the column names to be selected. The presence of a '^' and a '$' at the end of the string is implicitly assumed if they are not specified. See the documentation of TRegexp for more details. An empty string signals the selection of all columns.
314  ///
315  /// This function returns a `TDataFrame` built with the output tree as a source.
316  /// The types of the branches are automatically inferred and do not need to be specified.
317  TInterface<TLoopManager> Snapshot(std::string_view treename, std::string_view filename,
318  std::string_view columnNameRegexp = "")
319  {
320  const auto theRegexSize = columnNameRegexp.size();
321  std::string theRegex(columnNameRegexp);
322 
323  const auto isEmptyRegex = 0 == theRegexSize;
324  // This is to avoid cases where branches called b1, b2, b3 are all matched by expression "b"
325  if (theRegexSize > 0 && theRegex[0] != '^') theRegex = "^" + theRegex;
326  if (theRegexSize > 0 && theRegex[theRegexSize-1] != '$') theRegex = theRegex + "$";
327 
328  ColumnNames_t selectedColumns;
329  selectedColumns.reserve(32);
330 
331  const auto tmpBranches = fProxiedPtr->GetTmpBranches();
332  // Since we support gcc48 and it does not provide in its stl std::regex,
333  // we need to use TRegexp
334  TRegexp regexp(theRegex);
335  int dummy;
336  for (auto &&branchName : tmpBranches) {
337  if (isEmptyRegex || -1 != regexp.Index(branchName.c_str(), &dummy)) {
338  selectedColumns.emplace_back(branchName);
339  }
340  }
341 
342  auto df = GetDataFrameChecked();
343  auto tree = df->GetTree();
344  if (tree) {
345  const auto branches = tree->GetListOfBranches();
346  for (auto branch : *branches) {
347  auto branchName = branch->GetName();
348  if (isEmptyRegex || -1 != regexp.Index(branchName, &dummy)) {
349  selectedColumns.emplace_back(branchName);
350  }
351  }
352  }
353 
354  return Snapshot(treename, filename, selectedColumns);
355  }
356 
357  ////////////////////////////////////////////////////////////////////////////
358  /// \brief Creates a node that filters entries based on range
359  /// \param[in] start How many entries to discard before resuming processing.
360  /// \param[in] stop Total number of entries that will be processed before stopping. 0 means "never stop".
361  /// \param[in] stride Process one entry every `stride` entries. Must be strictly greater than 0.
362  ///
363  /// Ranges are only available if EnableImplicitMT has _not_ been called. Multi-thread ranges are not supported.
364  TInterface<TRangeBase> Range(unsigned int start, unsigned int stop, unsigned int stride = 1)
365  {
366  // check invariants
367  if (stride == 0 || (stop != 0 && stop < start))
368  throw std::runtime_error("Range: stride must be strictly greater than 0 and stop must be greater than start.");
370  throw std::runtime_error("Range was called with ImplicitMT enabled. Multi-thread ranges are not supported.");
371 
372  auto df = GetDataFrameChecked();
374  auto RangePtr = std::make_shared<Range_t>(start, stop, stride, *fProxiedPtr);
375  fProxiedPtr->IncrChildrenCount();
376  df->Book(RangePtr);
377  TInterface<TRangeBase> tdf_r(RangePtr, fImplWeakPtr);
378  return tdf_r;
379  }
380 
381  ////////////////////////////////////////////////////////////////////////////
382  /// \brief Creates a node that filters entries based on range
383  /// \param[in] stop Total number of entries that will be processed before stopping. 0 means "never stop".
384  ///
385  /// See the other Range overload for a detailed description.
386  TInterface<TRangeBase> Range(unsigned int stop) { return Range(0, stop, 1); }
387 
388  ////////////////////////////////////////////////////////////////////////////
389  /// \brief Execute a user-defined function on each entry (*instant action*)
390  /// \param[in] f Function, lambda expression, functor class or any other callable object performing user defined
391  /// calculations.
392  /// \param[in] bl Names of the branches in input to the user function.
393  ///
394  /// The callable `f` is invoked once per entry. This is an *instant action*:
395  /// upon invocation, an event loop as well as execution of all scheduled actions
396  /// is triggered.
397  /// Users are responsible for the thread-safety of this callable when executing
398  /// with implicit multi-threading enabled (i.e. ROOT::EnableImplicitMT).
399  template <typename F>
400  void Foreach(F f, const ColumnNames_t &bl = {})
401  {
402  using Args_t = typename TDFInternal::TFunctionTraits<decltype(f)>::ArgsNoDecay_t;
403  using Ret_t = typename TDFInternal::TFunctionTraits<decltype(f)>::Ret_t;
404  ForeachSlot(TDFInternal::AddSlotParameter<Ret_t>(f, Args_t()), bl);
405  }
406 
407  ////////////////////////////////////////////////////////////////////////////
408  /// \brief Execute a user-defined function requiring a processing slot index on each entry (*instant action*)
409  /// \param[in] f Function, lambda expression, functor class or any other callable object performing user defined
410  /// calculations.
411  /// \param[in] bl Names of the branches in input to the user function.
412  ///
413  /// Same as `Foreach`, but the user-defined function takes an extra
414  /// `unsigned int` as its first parameter, the *processing slot index*.
415  /// This *slot index* will be assigned a different value, `0` to `poolSize - 1`,
416  /// for each thread of execution.
417  /// This is meant as a helper in writing thread-safe `Foreach`
418  /// actions when using `TDataFrame` after `ROOT::EnableImplicitMT()`.
419  /// The user-defined processing callable is able to follow different
420  /// *streams of processing* indexed by the first parameter.
421  /// `ForeachSlot` works just as well with single-thread execution: in that
422  /// case `slot` will always be `0`.
423  template <typename F>
424  void ForeachSlot(F f, const ColumnNames_t &bl = {})
425  {
426  auto df = GetDataFrameChecked();
427  const ColumnNames_t &defBl = df->GetDefaultBranches();
428  auto nArgs = TDFInternal::TFunctionTraits<F>::Args_t::fgSize;
429  const ColumnNames_t &actualBl = TDFInternal::PickBranchNames(nArgs - 1, bl, defBl);
430  using Op_t = TDFInternal::ForeachSlotHelper<F>;
432  df->Book(std::make_shared<DFA_t>(Op_t(std::move(f)), actualBl, *fProxiedPtr));
433  fProxiedPtr->IncrChildrenCount();
434  df->Run();
435  }
436 
437  ////////////////////////////////////////////////////////////////////////////
438  /// \brief Execute a user-defined reduce operation on the values of a branch
439  /// \tparam F The type of the reduce callable. Automatically deduced.
440  /// \tparam T The type of the branch to apply the reduction to. Automatically deduced.
441  /// \param[in] f A callable with signature `T(T,T)`
442  /// \param[in] branchName The branch to be reduced. If omitted, the default branch is used instead.
443  ///
444  /// A reduction takes two values of a branch and merges them into one (e.g.
445  /// by summing them, taking the maximum, etc). This action performs the
446  /// specified reduction operation on all branch values, returning
447  /// a single value of the same type. The callable f must satisfy the general
448  /// requirements of a *processing function* besides having signature `T(T,T)`
449  /// where `T` is the type of branch.
450  ///
451  /// This action is *lazy*: upon invocation of this method the calculation is
452  /// booked but not executed. See TResultProxy documentation.
453  template <typename F, typename T = typename TDFInternal::TFunctionTraits<F>::Ret_t>
454  TResultProxy<T> Reduce(F f, std::string_view branchName = {})
455  {
456  static_assert(std::is_default_constructible<T>::value,
457  "reduce object cannot be default-constructed. Please provide an initialisation value (initValue)");
458  return Reduce(std::move(f), branchName, T());
459  }
460 
461  ////////////////////////////////////////////////////////////////////////////
462  /// \brief Execute a user-defined reduce operation on the values of a branch
463  /// \tparam F The type of the reduce callable. Automatically deduced.
464  /// \tparam T The type of the branch to apply the reduction to. Automatically deduced.
465  /// \param[in] f A callable with signature `T(T,T)`
466  /// \param[in] branchName The branch to be reduced. If omitted, the default branch is used instead.
467  /// \param[in] initValue The reduced object is initialised to this value rather than being default-constructed
468  ///
469  /// See the description of the other Reduce overload for more information.
470  template <typename F, typename T = typename TDFInternal::TFunctionTraits<F>::Ret_t>
471  TResultProxy<T> Reduce(F f, std::string_view branchName, const T &initValue)
472  {
473  using Args_t = typename TDFInternal::TFunctionTraits<F>::Args_t;
474  TDFInternal::CheckReduce(f, Args_t());
475  auto df = GetDataFrameChecked();
476  unsigned int nSlots = df->GetNSlots();
477  auto bl = GetBranchNames<T>({branchName}, "reduce branch values");
478  auto redObjPtr = std::make_shared<T>(initValue);
479  using Op_t = TDFInternal::ReduceHelper<F, T>;
480  using DFA_t = typename TDFInternal::TAction<Op_t, Proxied>;
481  df->Book(std::make_shared<DFA_t>(Op_t(std::move(f), redObjPtr, nSlots), bl, *fProxiedPtr));
482  fProxiedPtr->IncrChildrenCount();
483  return MakeResultProxy(redObjPtr, df);
484  }
485 
486  ////////////////////////////////////////////////////////////////////////////
487  /// \brief Return the number of entries processed (*lazy action*)
488  ///
489  /// This action is *lazy*: upon invocation of this method the calculation is
490  /// booked but not executed. See TResultProxy documentation.
492  {
493  auto df = GetDataFrameChecked();
494  unsigned int nSlots = df->GetNSlots();
495  auto cSPtr = std::make_shared<unsigned int>(0);
496  using Op_t = TDFInternal::CountHelper;
498  df->Book(std::make_shared<DFA_t>(Op_t(cSPtr, nSlots), ColumnNames_t({}), *fProxiedPtr));
499  fProxiedPtr->IncrChildrenCount();
500  return MakeResultProxy(cSPtr, df);
501  }
502 
503  ////////////////////////////////////////////////////////////////////////////
504  /// \brief Return a collection of values of a branch (*lazy action*)
505  /// \tparam T The type of the branch.
506  /// \tparam COLL The type of collection used to store the values.
507  /// \param[in] branchName The name of the branch of which the values are to be collected
508  ///
509  /// This action is *lazy*: upon invocation of this method the calculation is
510  /// booked but not executed. See TResultProxy documentation.
511  template <typename T, typename COLL = std::vector<T>>
512  TResultProxy<COLL> Take(std::string_view branchName = "")
513  {
514  auto df = GetDataFrameChecked();
515  unsigned int nSlots = df->GetNSlots();
516  auto bl = GetBranchNames<T>({branchName}, "get the values of the branch");
517  auto valuesPtr = std::make_shared<COLL>();
518  using Op_t = TDFInternal::TakeHelper<T, COLL>;
520  df->Book(std::make_shared<DFA_t>(Op_t(valuesPtr, nSlots), bl, *fProxiedPtr));
521  fProxiedPtr->IncrChildrenCount();
522  return MakeResultProxy(valuesPtr, df);
523  }
524 
525  ////////////////////////////////////////////////////////////////////////////
526  /// \brief Fill and return a one-dimensional histogram with the values of a branch (*lazy action*)
527  /// \tparam V The type of the branch used to fill the histogram.
528  /// \param[in] model The returned histogram will be constructed using this as a model.
529  /// \param[in] vName The name of the branch that will fill the histogram.
530  ///
531  /// The default branches, if available, will be used instead of branches whose names are left empty.
532  /// Branches can be of a container type (e.g. std::vector<double>), in which case the histogram
533  /// is filled with each one of the elements of the container. In case multiple branches of container type
534  /// are provided (e.g. values and weights) they must have the same length for each one of the events (but
535  /// possibly different lengths between events).
536  /// This action is *lazy*: upon invocation of this method the calculation is
537  /// booked but not executed. See TResultProxy documentation.
538  /// The user gives up ownership of the model histogram.
539  template <typename V = TDFDetail::TInferType>
540  TResultProxy<::TH1F> Histo1D(::TH1F &&model = ::TH1F{"", "", 128u, 0., 0.}, std::string_view vName = "")
541  {
542  auto bl = GetBranchNames<V>({vName}, "fill the histogram");
543  auto h = std::make_shared<::TH1F>(std::move(model));
544  if (h->GetXaxis()->GetXmax() == h->GetXaxis()->GetXmin())
545  TDFInternal::HistoUtils<::TH1F>::SetCanExtendAllAxes(*h);
546  return CreateAction<TDFInternal::ActionTypes::Histo1D, V>(bl, h);
547  }
548 
549  template <typename V = TDFDetail::TInferType>
550  TResultProxy<::TH1F> Histo1D(std::string_view vName)
551  {
552  return Histo1D<V>(::TH1F{"", "", 128u, 0., 0.}, vName);
553  }
554 
555  ////////////////////////////////////////////////////////////////////////////
556  /// \brief Fill and return a one-dimensional histogram with the values of a branch (*lazy action*)
557  /// \tparam V The type of the branch used to fill the histogram.
558  /// \param[in] model The returned histogram will be constructed using this as a model.
559  /// \param[in] vName The name of the branch that will fill the histogram.
560  /// \param[in] wName The name of the branch that will provide the weights.
561  ///
562  /// The default branches, if available, will be used instead of branches whose names are left empty.
563  /// Branches can be of a container type (e.g. std::vector<double>), in which case the histogram
564  /// is filled with each one of the elements of the container. In case multiple branches of container type
565  /// are provided (e.g. values and weights) they must have the same length for each one of the events (but
566  /// possibly different lengths between events).
567  /// This action is *lazy*: upon invocation of this method the calculation is
568  /// booked but not executed. See TResultProxy documentation.
569  /// The user gives up ownership of the model histogram.
570  template <typename V = TDFDetail::TInferType, typename W = TDFDetail::TInferType>
571  TResultProxy<::TH1F> Histo1D(::TH1F &&model, std::string_view vName, std::string_view wName)
572  {
573  auto bl = GetBranchNames<V, W>({vName, wName}, "fill the histogram");
574  auto h = std::make_shared<::TH1F>(std::move(model));
575  return CreateAction<TDFInternal::ActionTypes::Histo1D, V, W>(bl, h);
576  }
577 
578  template <typename V = TDFDetail::TInferType, typename W = TDFDetail::TInferType>
579  TResultProxy<::TH1F> Histo1D(std::string_view vName, std::string_view wName)
580  {
581  return Histo1D<V, W>(::TH1F{"", "", 128u, 0., 0.}, vName, wName);
582  }
583 
584  template <typename V, typename W>
585  TResultProxy<::TH1F> Histo1D(::TH1F &&model = ::TH1F{"", "", 128u, 0., 0.})
586  {
587  return Histo1D<V, W>(std::move(model), "", "");
588  }
589 
590  ////////////////////////////////////////////////////////////////////////////
591  /// \brief Fill and return a two-dimensional histogram (*lazy action*)
592  /// \tparam V1 The type of the branch used to fill the x axis of the histogram.
593  /// \tparam V2 The type of the branch used to fill the y axis of the histogram.
594  /// \param[in] model The returned histogram will be constructed using this as a model.
595  /// \param[in] v1Name The name of the branch that will fill the x axis.
596  /// \param[in] v2Name The name of the branch that will fill the y axis.
597  ///
598  /// This action is *lazy*: upon invocation of this method the calculation is
599  /// booked but not executed. See TResultProxy documentation.
600  /// The user gives up ownership of the model histogram.
601  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType>
602  TResultProxy<::TH2F> Histo2D(::TH2F &&model, std::string_view v1Name = "", std::string_view v2Name = "")
603  {
604  auto h = std::make_shared<::TH2F>(std::move(model));
605  if (!TDFInternal::HistoUtils<::TH2F>::HasAxisLimits(*h)) {
606  throw std::runtime_error("2D histograms with no axes limits are not supported yet.");
607  }
608  auto bl = GetBranchNames<V1, V2>({v1Name, v2Name}, "fill the histogram");
609  return CreateAction<TDFInternal::ActionTypes::Histo2D, V1, V2>(bl, h);
610  }
611 
612  ////////////////////////////////////////////////////////////////////////////
613  /// \brief Fill and return a two-dimensional histogram (*lazy action*)
614  /// \tparam V1 The type of the branch used to fill the x axis of the histogram.
615  /// \tparam V2 The type of the branch used to fill the y axis of the histogram.
616  /// \tparam W The type of the branch used for the weights of the histogram.
617  /// \param[in] model The returned histogram will be constructed using this as a model.
618  /// \param[in] v1Name The name of the branch that will fill the x axis.
619  /// \param[in] v2Name The name of the branch that will fill the y axis.
620  /// \param[in] wName The name of the branch that will provide the weights.
621  ///
622  /// This action is *lazy*: upon invocation of this method the calculation is
623  /// booked but not executed. See TResultProxy documentation.
624  /// The user gives up ownership of the model histogram.
625  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType,
626  typename W = TDFDetail::TInferType>
627  TResultProxy<::TH2F> Histo2D(::TH2F &&model, std::string_view v1Name, std::string_view v2Name,
628  std::string_view wName)
629  {
630  auto h = std::make_shared<::TH2F>(std::move(model));
631  if (!TDFInternal::HistoUtils<::TH2F>::HasAxisLimits(*h)) {
632  throw std::runtime_error("2D histograms with no axes limits are not supported yet.");
633  }
634  auto bl = GetBranchNames<V1, V2, W>({v1Name, v2Name, wName}, "fill the histogram");
635  return CreateAction<TDFInternal::ActionTypes::Histo2D, V1, V2, W>(bl, h);
636  }
637 
638  template <typename V1, typename V2, typename W>
640  {
641  return Histo2D<V1, V2, W>(std::move(model), "", "", "");
642  }
643 
644  ////////////////////////////////////////////////////////////////////////////
645  /// \brief Fill and return a three-dimensional histogram (*lazy action*)
646  /// \tparam V1 The type of the branch used to fill the x axis of the histogram.
647  /// \tparam V2 The type of the branch used to fill the y axis of the histogram.
648  /// \tparam V3 The type of the branch used to fill the z axis of the histogram.
649  /// \param[in] model The returned histogram will be constructed using this as a model.
650  /// \param[in] v1Name The name of the branch that will fill the x axis.
651  /// \param[in] v2Name The name of the branch that will fill the y axis.
652  /// \param[in] v3Name The name of the branch that will fill the z axis.
653  ///
654  /// This action is *lazy*: upon invocation of this method the calculation is
655  /// booked but not executed. See TResultProxy documentation.
656  /// The user gives up ownership of the model histogram.
657  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType,
658  typename V3 = TDFDetail::TInferType>
659  TResultProxy<::TH3F> Histo3D(::TH3F &&model, std::string_view v1Name = "", std::string_view v2Name = "",
660  std::string_view v3Name = "")
661  {
662  auto h = std::make_shared<::TH3F>(std::move(model));
663  if (!TDFInternal::HistoUtils<::TH3F>::HasAxisLimits(*h)) {
664  throw std::runtime_error("3D histograms with no axes limits are not supported yet.");
665  }
666  auto bl = GetBranchNames<V1, V2, V3>({v1Name, v2Name, v3Name}, "fill the histogram");
667  return CreateAction<TDFInternal::ActionTypes::Histo3D, V1, V2, V3>(bl, h);
668  }
669 
670  ////////////////////////////////////////////////////////////////////////////
671  /// \brief Fill and return a three-dimensional histogram (*lazy action*)
672  /// \tparam V1 The type of the branch used to fill the x axis of the histogram.
673  /// \tparam V2 The type of the branch used to fill the y axis of the histogram.
674  /// \tparam V3 The type of the branch used to fill the z axis of the histogram.
675  /// \tparam W The type of the branch used for the weights of the histogram.
676  /// \param[in] model The returned histogram will be constructed using this as a model.
677  /// \param[in] v1Name The name of the branch that will fill the x axis.
678  /// \param[in] v2Name The name of the branch that will fill the y axis.
679  /// \param[in] v3Name The name of the branch that will fill the z axis.
680  /// \param[in] wName The name of the branch that will provide the weights.
681  ///
682  /// This action is *lazy*: upon invocation of this method the calculation is
683  /// booked but not executed. See TResultProxy documentation.
684  /// The user gives up ownership of the model histogram.
685  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType,
686  typename V3 = TDFDetail::TInferType, typename W = TDFDetail::TInferType>
687  TResultProxy<::TH3F> Histo3D(::TH3F &&model, std::string_view v1Name, std::string_view v2Name,
688  std::string_view v3Name, std::string_view wName)
689  {
690  auto h = std::make_shared<::TH3F>(std::move(model));
691  if (!TDFInternal::HistoUtils<::TH3F>::HasAxisLimits(*h)) {
692  throw std::runtime_error("3D histograms with no axes limits are not supported yet.");
693  }
694  auto bl = GetBranchNames<V1, V2, V3, W>({v1Name, v2Name, v3Name, wName}, "fill the histogram");
695  return CreateAction<TDFInternal::ActionTypes::Histo3D, V1, V2, V3, W>(bl, h);
696  }
697 
698  template <typename V1, typename V2, typename V3, typename W>
700  {
701  return Histo3D<V1, V2, V3, W>(std::move(model), "", "", "", "");
702  }
703 
704  ////////////////////////////////////////////////////////////////////////////
705  /// \brief Fill and return a one-dimensional profile (*lazy action*)
706  /// \tparam V1 The type of the branch the values of which are used to fill the profile.
707  /// \tparam V2 The type of the branch the values of which are used to fill the profile.
708  /// \param[in] model The model to be considered to build the new return value.
709  /// \param[in] v1Name The name of the branch that will fill the x axis.
710  /// \param[in] v2Name The name of the branch that will fill the y axis.
711  ///
712  /// This action is *lazy*: upon invocation of this method the calculation is
713  /// booked but not executed. See TResultProxy documentation.
714  /// The user gives up ownership of the model profile object.
715  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType>
716  TResultProxy<::TProfile> Profile1D(::TProfile &&model, std::string_view v1Name = "",
717  std::string_view v2Name = "")
718  {
719  auto h = std::make_shared<::TProfile>(std::move(model));
720  if (!TDFInternal::HistoUtils<::TProfile>::HasAxisLimits(*h)) {
721  throw std::runtime_error("Profiles with no axes limits are not supported yet.");
722  }
723  auto bl = GetBranchNames<V1, V2>({v1Name, v2Name}, "fill the 1D Profile");
724  return CreateAction<TDFInternal::ActionTypes::Profile1D, V1, V2>(bl, h);
725  }
726 
727  ////////////////////////////////////////////////////////////////////////////
728  /// \brief Fill and return a one-dimensional profile (*lazy action*)
729  /// \tparam V1 The type of the branch the values of which are used to fill the profile.
730  /// \tparam V2 The type of the branch the values of which are used to fill the profile.
731  /// \tparam W The type of the branch the weights of which are used to fill the profile.
732  /// \param[in] model The model to be considered to build the new return value.
733  /// \param[in] v1Name The name of the branch that will fill the x axis.
734  /// \param[in] v2Name The name of the branch that will fill the y axis.
735  /// \param[in] wName The name of the branch that will provide the weights.
736  ///
737  /// This action is *lazy*: upon invocation of this method the calculation is
738  /// booked but not executed. See TResultProxy documentation.
739  /// The user gives up ownership of the model profile object.
740  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType,
741  typename W = TDFDetail::TInferType>
742  TResultProxy<::TProfile> Profile1D(::TProfile &&model, std::string_view v1Name, std::string_view v2Name,
743  std::string_view wName)
744  {
745  auto h = std::make_shared<::TProfile>(std::move(model));
746  if (!TDFInternal::HistoUtils<::TProfile>::HasAxisLimits(*h)) {
747  throw std::runtime_error("Profile histograms with no axes limits are not supported yet.");
748  }
749  auto bl = GetBranchNames<V1, V2, W>({v1Name, v2Name, wName}, "fill the 1D profile");
750  return CreateAction<TDFInternal::ActionTypes::Profile1D, V1, V2, W>(bl, h);
751  }
752 
753  template <typename V1, typename V2, typename W>
755  {
756  return Profile1D<V1, V2, W>(std::move(model), "", "", "");
757  }
758 
759  ////////////////////////////////////////////////////////////////////////////
760  /// \brief Fill and return a two-dimensional profile (*lazy action*)
761  /// \tparam V1 The type of the branch used to fill the x axis of the histogram.
762  /// \tparam V2 The type of the branch used to fill the y axis of the histogram.
763  /// \tparam V2 The type of the branch used to fill the z axis of the histogram.
764  /// \param[in] model The returned profile will be constructed using this as a model.
765  /// \param[in] v1Name The name of the branch that will fill the x axis.
766  /// \param[in] v2Name The name of the branch that will fill the y axis.
767  /// \param[in] v3Name The name of the branch that will fill the z axis.
768  ///
769  /// This action is *lazy*: upon invocation of this method the calculation is
770  /// booked but not executed. See TResultProxy documentation.
771  /// The user gives up ownership of the model profile.
772  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType,
773  typename V3 = TDFDetail::TInferType>
774  TResultProxy<::TProfile2D> Profile2D(::TProfile2D &&model, std::string_view v1Name = "",
775  std::string_view v2Name = "", std::string_view v3Name = "")
776  {
777  auto h = std::make_shared<::TProfile2D>(std::move(model));
778  if (!TDFInternal::HistoUtils<::TProfile2D>::HasAxisLimits(*h)) {
779  throw std::runtime_error("2D profiles with no axes limits are not supported yet.");
780  }
781  auto bl = GetBranchNames<V1, V2, V3>({v1Name, v2Name, v3Name}, "fill the 2D profile");
782  return CreateAction<TDFInternal::ActionTypes::Profile2D, V1, V2, V3>(bl, h);
783  }
784 
785  ////////////////////////////////////////////////////////////////////////////
786  /// \brief Fill and return a two-dimensional profile (*lazy action*)
787  /// \tparam V1 The type of the branch used to fill the x axis of the histogram.
788  /// \tparam V2 The type of the branch used to fill the y axis of the histogram.
789  /// \tparam V3 The type of the branch used to fill the z axis of the histogram.
790  /// \tparam W The type of the branch used for the weights of the histogram.
791  /// \param[in] model The returned histogram will be constructed using this as a model.
792  /// \param[in] v1Name The name of the branch that will fill the x axis.
793  /// \param[in] v2Name The name of the branch that will fill the y axis.
794  /// \param[in] v3Name The name of the branch that will fill the z axis.
795  /// \param[in] wName The name of the branch that will provide the weights.
796  ///
797  /// This action is *lazy*: upon invocation of this method the calculation is
798  /// booked but not executed. See TResultProxy documentation.
799  /// The user gives up ownership of the model profile.
800  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType,
801  typename V3 = TDFDetail::TInferType, typename W = TDFDetail::TInferType>
802  TResultProxy<::TProfile2D> Profile2D(::TProfile2D &&model, std::string_view v1Name, std::string_view v2Name,
803  std::string_view v3Name, std::string_view wName)
804  {
805  auto h = std::make_shared<::TProfile2D>(std::move(model));
806  if (!TDFInternal::HistoUtils<::TProfile2D>::HasAxisLimits(*h)) {
807  throw std::runtime_error("2D profiles with no axes limits are not supported yet.");
808  }
809  auto bl = GetBranchNames<V1, V2, V3, W>({v1Name, v2Name, v3Name, wName}, "fill the histogram");
810  return CreateAction<TDFInternal::ActionTypes::Profile2D, V1, V2, V3, W>(bl, h);
811  }
812 
813  template <typename V1, typename V2, typename V3, typename W>
815  {
816  return Profile2D<V1, V2, V3, W>(std::move(model), "", "", "", "");
817  }
818 
819  ////////////////////////////////////////////////////////////////////////////
820  /// \brief Fill and return any entity with a Fill method (*lazy action*)
821  /// \tparam BranchTypes The types of the branches the values of which are used to fill the object.
822  /// \param[in] model The model to be considered to build the new return value.
823  /// \param[in] bl The name of the branches read to fill the object.
824  ///
825  /// The returned object is independent of the input one.
826  /// This action is *lazy*: upon invocation of this method the calculation is
827  /// booked but not executed. See TResultProxy documentation.
828  /// The user gives up ownership of the model object.
829  /// It is compulsory to express the branches to be considered.
830  template <typename FirstBranch, typename... OtherBranches, typename T> // need FirstBranch to disambiguate overloads
832  {
833  auto h = std::make_shared<T>(std::move(model));
834  if (!TDFInternal::HistoUtils<T>::HasAxisLimits(*h)) {
835  throw std::runtime_error("The absence of axes limits is not supported yet.");
836  }
837  return CreateAction<TDFInternal::ActionTypes::Fill, FirstBranch, OtherBranches...>(bl, h);
838  }
839 
840  template <typename T>
842  {
843  auto h = std::make_shared<T>(std::move(model));
844  if (!TDFInternal::HistoUtils<T>::HasAxisLimits(*h)) {
845  throw std::runtime_error("The absence of axes limits is not supported yet.");
846  }
847  return CreateAction<TDFInternal::ActionTypes::Fill, TDFDetail::TInferType>(bl, h);
848  }
849 
850  ////////////////////////////////////////////////////////////////////////////
851  /// \brief Return the minimum of processed branch values (*lazy action*)
852  /// \tparam T The type of the branch.
853  /// \param[in] branchName The name of the branch to be treated.
854  ///
855  /// If no branch type is specified, the implementation will try to guess one.
856  ///
857  /// This action is *lazy*: upon invocation of this method the calculation is
858  /// booked but not executed. See TResultProxy documentation.
859  template <typename T = TDFDetail::TInferType>
860  TResultProxy<double> Min(std::string_view branchName = "")
861  {
862  auto bl = GetBranchNames<T>({branchName}, "calculate the minimum");
863  auto minV = std::make_shared<double>(std::numeric_limits<double>::max());
864  return CreateAction<TDFInternal::ActionTypes::Min, T>(bl, minV);
865  }
866 
867  ////////////////////////////////////////////////////////////////////////////
868  /// \brief Return the maximum of processed branch values (*lazy action*)
869  /// \tparam T The type of the branch.
870  /// \param[in] branchName The name of the branch to be treated.
871  ///
872  /// If no branch type is specified, the implementation will try to guess one.
873  ///
874  /// This action is *lazy*: upon invocation of this method the calculation is
875  /// booked but not executed. See TResultProxy documentation.
876  template <typename T = TDFDetail::TInferType>
877  TResultProxy<double> Max(std::string_view branchName = "")
878  {
879  auto bl = GetBranchNames<T>({branchName}, "calculate the maximum");
880  auto maxV = std::make_shared<double>(std::numeric_limits<double>::lowest());
881  return CreateAction<TDFInternal::ActionTypes::Max, T>(bl, maxV);
882  }
883 
884  ////////////////////////////////////////////////////////////////////////////
885  /// \brief Return the mean of processed branch values (*lazy action*)
886  /// \tparam T The type of the branch.
887  /// \param[in] branchName The name of the branch to be treated.
888  ///
889  /// If no branch type is specified, the implementation will try to guess one.
890  ///
891  /// This action is *lazy*: upon invocation of this method the calculation is
892  /// booked but not executed. See TResultProxy documentation.
893  template <typename T = TDFDetail::TInferType>
894  TResultProxy<double> Mean(std::string_view branchName = "")
895  {
896  auto bl = GetBranchNames<T>({branchName}, "calculate the mean");
897  auto meanV = std::make_shared<double>(0);
898  return CreateAction<TDFInternal::ActionTypes::Mean, T>(bl, meanV);
899  }
900 
901  ////////////////////////////////////////////////////////////////////////////
902  /// \brief Print filtering statistics on screen
903  ///
904  /// Calling `Report` on the main `TDataFrame` object prints stats for
905  /// all named filters in the call graph. Calling this method on a
906  /// stored chain state (i.e. a graph node different from the first) prints
907  /// the stats for all named filters in the chain section between the original
908  /// `TDataFrame` and that node (included). Stats are printed in the same
909  /// order as the named filters have been added to the graph.
910  void Report()
911  {
912  auto df = GetDataFrameChecked();
913  if (!df->HasRunAtLeastOnce()) df->Run();
914  fProxiedPtr->Report();
915  }
916 
917 private:
918  inline const char *GetNodeTypeName() { return ""; };
919 
920  /// Returns the default branches if needed, takes care of the error handling.
921  template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void>
922  ColumnNames_t GetBranchNames(const std::vector<std::string_view>& bl, std::string_view actionNameForErr)
923  {
924  constexpr auto isT2Void = std::is_same<T2, void>::value;
925  constexpr auto isT3Void = std::is_same<T3, void>::value;
926  constexpr auto isT4Void = std::is_same<T4, void>::value;
927 
928  unsigned int neededBranches = 1 + !isT2Void + !isT3Void + !isT4Void;
929 
930  unsigned int providedBranches = 0;
931  std::for_each(bl.begin(), bl.end(), [&providedBranches](std::string_view s) {
932  if (!s.empty()) providedBranches++;
933  });
934 
935  if (neededBranches == providedBranches) {
936  ColumnNames_t bl2(bl.begin(), bl.end());
937  return bl2;
938  }
939 
940  return GetDefaultBranchNames(neededBranches, actionNameForErr);
941  }
942 
943  /// \cond HIDDEN_SYMBOLS
944 
945  /****** BuildAndBook overloads *******/
946  // BuildAndBook builds a TAction with the right operation and book it with the TLoopManager
947 
948  // Generic filling (covers Histo2D, Histo3D, Profile1D and Profile2D actions, with and without weights)
949  template <typename... BranchTypes, typename ActionType, typename ActionResultType>
950  void BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h, unsigned int nSlots,
951  ActionType *)
952  {
953  using Op_t = TDFInternal::FillTOHelper<ActionResultType>;
954  using DFA_t = TDFInternal::TAction<Op_t, Proxied, TDFInternal::TTypeList<BranchTypes...>>;
955  auto df = GetDataFrameChecked();
956  df->Book(std::make_shared<DFA_t>(Op_t(h, nSlots), bl, *fProxiedPtr));
957  }
958 
959  // Histo1D filling (must handle the special case of distinguishing FillTOHelper and FillHelper
960  template <typename... BranchTypes>
961  void BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr<::TH1F> &h, unsigned int nSlots,
962  TDFInternal::ActionTypes::Histo1D *)
963  {
964  auto df = GetDataFrameChecked();
965  auto hasAxisLimits = TDFInternal::HistoUtils<::TH1F>::HasAxisLimits(*h);
966 
967  if (hasAxisLimits) {
968  using Op_t = TDFInternal::FillTOHelper<::TH1F>;
969  using DFA_t = TDFInternal::TAction<Op_t, Proxied, TDFInternal::TTypeList<BranchTypes...>>;
970  df->Book(std::make_shared<DFA_t>(Op_t(h, nSlots), bl, *fProxiedPtr));
971  } else {
972  using Op_t = TDFInternal::FillHelper;
973  using DFA_t = TDFInternal::TAction<Op_t, Proxied, TDFInternal::TTypeList<BranchTypes...>>;
974  df->Book(std::make_shared<DFA_t>(Op_t(h, nSlots), bl, *fProxiedPtr));
975  }
976  }
977 
978  // Min action
979  template <typename BranchType>
980  void BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr<double> &minV, unsigned int nSlots,
982  {
983  using Op_t = TDFInternal::MinHelper;
985  auto df = GetDataFrameChecked();
986  df->Book(std::make_shared<DFA_t>(Op_t(minV, nSlots), bl, *fProxiedPtr));
987  }
988 
989  // Max action
990  template <typename BranchType>
991  void BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr<double> &maxV, unsigned int nSlots,
993  {
994  using Op_t = TDFInternal::MaxHelper;
996  auto df = GetDataFrameChecked();
997  df->Book(std::make_shared<DFA_t>(Op_t(maxV, nSlots), bl, *fProxiedPtr));
998  }
999 
1000  // Mean action
1001  template <typename BranchType>
1002  void BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr<double> &meanV, unsigned int nSlots,
1004  {
1005  using Op_t = TDFInternal::MeanHelper;
1007  auto df = GetDataFrameChecked();
1008  df->Book(std::make_shared<DFA_t>(Op_t(meanV, nSlots), bl, *fProxiedPtr));
1009  }
1010  /****** end BuildAndBook ******/
1011  /// \endcond
1012 
1013  // Type was specified by the user, no need to infer it
1014  template <typename ActionType, typename... BranchTypes, typename ActionResultType,
1015  typename std::enable_if<!TDFInternal::TNeedJitting<BranchTypes...>::value, int>::type = 0>
1016  TResultProxy<ActionResultType> CreateAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &r)
1017  {
1018  auto df = GetDataFrameChecked();
1019  unsigned int nSlots = df->GetNSlots();
1020  BuildAndBook<BranchTypes...>(bl, r, nSlots, (ActionType *)nullptr);
1021  fProxiedPtr->IncrChildrenCount();
1022  return MakeResultProxy(r, df);
1023  }
1024 
1025  // User did not specify type, do type inference
1026  template <typename ActionType, typename... BranchTypes, typename ActionResultType,
1027  typename std::enable_if<TDFInternal::TNeedJitting<BranchTypes...>::value, int>::type = 0>
1028  TResultProxy<ActionResultType> CreateAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &r)
1029  {
1030  auto df = GetDataFrameChecked();
1031  unsigned int nSlots = df->GetNSlots();
1032  const auto &tmpBranches = df->GetBookedBranches();
1033  auto tree = df->GetTree();
1034  TDFInternal::JitBuildAndBook(bl, GetNodeTypeName(), this, typeid(std::shared_ptr<ActionResultType>),
1035  typeid(ActionType), &r, tree, nSlots, tmpBranches);
1036  fProxiedPtr->IncrChildrenCount();
1037  return MakeResultProxy(r, df);
1038  }
1039 
1040 protected:
1041  /// Get the TLoopManager if reachable. If not, throw.
1042  std::shared_ptr<TLoopManager> GetDataFrameChecked()
1043  {
1044  auto df = fImplWeakPtr.lock();
1045  if (!df) {
1046  throw std::runtime_error("The main TDataFrame is not reachable: did it go out of scope?");
1047  }
1048  return df;
1049  }
1050 
1051  const ColumnNames_t GetDefaultBranchNames(unsigned int nExpectedBranches, std::string_view actionNameForErr)
1052  {
1053  auto df = GetDataFrameChecked();
1054  const ColumnNames_t &defaultBranches = df->GetDefaultBranches();
1055  const auto dBSize = defaultBranches.size();
1056  if (nExpectedBranches > dBSize) {
1057  std::string msg("Trying to deduce the branches from the default list in order to ");
1058  msg += actionNameForErr;
1059  msg += ". A set of branches of size ";
1060  msg += std::to_string(dBSize);
1061  msg += " was found. ";
1062  msg += std::to_string(nExpectedBranches);
1063  msg += 1 != nExpectedBranches ? " are" : " is";
1064  msg += " needed. Please specify the branches explicitly.";
1065  throw std::runtime_error(msg);
1066  }
1067  auto bnBegin = defaultBranches.begin();
1068  return ColumnNames_t(bnBegin, bnBegin + nExpectedBranches);
1069  }
1070 
1071  ////////////////////////////////////////////////////////////////////////////
1072  /// \brief Implementation of snapshot
1073  /// \param[in] treename The name of the TTree
1074  /// \param[in] filename The name of the TFile
1075  /// \param[in] bnames The list of names of the branches to be written
1076  /// The implementation exploits Foreach. The association of the addresses to
1077  /// the branches takes place at the first event. This is possible because
1078  /// since there are no copies, the address of the value passed by reference
1079  /// is the address pointing to the storage of the read/created object in/by
1080  /// the TTreeReaderValue/TemporaryBranch
1081  template <typename... Args, int... S>
1082  TInterface<TLoopManager> SnapshotImpl(std::string_view treename, std::string_view filename,
1083  const ColumnNames_t &bnames, TDFInternal::TStaticSeq<S...> /*dummy*/)
1084  {
1085  const std::string filenameInt(filename);
1086  const auto templateParamsN = sizeof...(S);
1087  const auto bNamesN = bnames.size();
1088  if (templateParamsN != bNamesN) {
1089  std::string err_msg = "The number of template parameters specified for the snapshot is ";
1090  err_msg += std::to_string(templateParamsN);
1091  err_msg += " while ";
1092  err_msg += std::to_string(bNamesN);
1093  err_msg += " branches have been specified.";
1094  throw std::runtime_error(err_msg.c_str());
1095  }
1096 
1097  // splits name into directory and treename if needed
1098  auto getDirTreeName = [](std::string_view treePath) {
1099  auto lastSlash = treePath.rfind('/');
1100  std::string_view treeDir, treeName;
1101  if (std::string_view::npos != lastSlash) {
1102  treeDir = treePath.substr(0,lastSlash);
1103  treeName = treePath.substr(lastSlash+1,treePath.size());
1104  } else {
1105  treeName = treePath;
1106  }
1107  // need to convert to string for TTree and TDirectory ctors anyway
1108  return std::make_pair(std::string(treeDir), std::string(treeName));
1109  };
1110 
1111  auto df = GetDataFrameChecked();
1112  if (!ROOT::IsImplicitMTEnabled()) {
1113  std::string treenameInt;
1114  std::string dirnameInt;
1115  std::unique_ptr<TFile> ofile(TFile::Open(filenameInt.c_str(), "RECREATE"));
1116  std::tie(dirnameInt, treenameInt) = getDirTreeName(treename);
1117  if (!dirnameInt.empty()) {
1118  ofile->mkdir(dirnameInt.c_str());
1119  ofile->cd(dirnameInt.c_str());
1120  }
1121  TTree t(treenameInt.c_str(), treenameInt.c_str());
1122 
1123  bool FirstEvent = true;
1124  // TODO move fillTree and initLambda to SnapshotHelper's body
1125  auto fillTree = [&t, &bnames, &FirstEvent](unsigned int /* unused */, Args &... args) {
1126  if (FirstEvent) {
1127  // hack to call TTree::Branch on all variadic template arguments
1128  std::initializer_list<int> expander = {(t.Branch(bnames[S].c_str(), &args), 0)..., 0};
1129  (void)expander; // avoid unused variable warnings for older compilers such as gcc 4.9
1130  FirstEvent = false;
1131  }
1132  t.Fill();
1133  };
1134 
1135  auto initLambda = [&t] (TTreeReader *r, unsigned int /* unused */) {
1136  if(r) {
1137  // not an empty-source TDF
1138  auto tree = r->GetTree();
1139  tree->AddClone(&t);
1140  }
1141  };
1142 
1143  using Op_t = TDFInternal::SnapshotHelper<decltype(initLambda), decltype(fillTree)>;
1145  df->Book(std::make_shared<DFA_t>(Op_t(std::move(initLambda), std::move(fillTree)), bnames, *fProxiedPtr));
1146  fProxiedPtr->IncrChildrenCount();
1147  df->Run();
1148  t.Write();
1149  } else {
1150  unsigned int nSlots = df->GetNSlots();
1151  TBufferMerger merger(filenameInt.c_str(), "RECREATE");
1152  std::vector<std::shared_ptr<TBufferMergerFile>> files(nSlots);
1153  std::vector<TTree *> trees(nSlots, nullptr); // ROOT owns/manages these TTrees
1154  std::vector<int> isFirstEvent(nSlots, 1); // vector<bool> is evil
1155 
1156  auto fillTree = [&](unsigned int slot, Args &... args) {
1157  if (isFirstEvent[slot]) {
1158  // hack to call TTree::Branch on all variadic template arguments
1159  std::initializer_list<int> expander = {(trees[slot]->Branch(bnames[S].c_str(), &args), 0)..., 0};
1160  (void)expander; // avoid unused variable warnings for older compilers such as gcc 4.9
1161  isFirstEvent[slot] = 0;
1162  }
1163  trees[slot]->Fill();
1164  auto entries = trees[slot]->GetEntries();
1165  auto autoflush = trees[slot]->GetAutoFlush();
1166  if ((autoflush > 0) && (entries % autoflush == 0)) files[slot]->Write();
1167  };
1168 
1169  // called at the beginning of each task
1170  auto initLambda = [&trees, &merger, &files, &treename, &isFirstEvent, &getDirTreeName](TTreeReader *r,
1171  unsigned int slot) {
1172  std::string treenameInt;
1173  std::string dirnameInt;
1175  if(!trees[slot]) {
1176  // first time this thread executes something, let's create a TBufferMerger output directory
1177  files[slot] = merger.GetFile();
1178  } else {
1179  files[slot]->Write();
1180  }
1181  std::tie(dirnameInt, treenameInt) = getDirTreeName(treename);
1182  ::TDirectory *subdir = files[slot].get();
1183  if (!dirnameInt.empty()) subdir = files[slot]->mkdir(dirnameInt.c_str());
1184  subdir->cd();
1185  trees[slot] = new TTree(treenameInt.c_str(), treenameInt.c_str());
1186  trees[slot]->ResetBit(kMustCleanup);
1187  trees[slot]->SetImplicitMT(false);
1188  if(r) {
1189  // not an empty-source TDF
1190  auto tree = r->GetTree();
1191  tree->AddClone(trees[slot]);
1192  }
1193  isFirstEvent[slot] = 1;
1194  };
1195 
1196  using Op_t = TDFInternal::SnapshotHelper<decltype(initLambda), decltype(fillTree)>;
1198  df->Book(std::make_shared<DFA_t>(Op_t(std::move(initLambda), std::move(fillTree)), bnames, *fProxiedPtr));
1199  fProxiedPtr->IncrChildrenCount();
1200  df->Run();
1201  for (auto &&file : files) {
1202  if (file) file->Write();
1203  }
1204  }
1205 
1207  std::string fullTreeNameInt(treename);
1208  // Now we mimic a constructor for the TDataFrame. We cannot invoke it here
1209  // since this would introduce a cyclic headers dependency.
1210  TInterface<TLoopManager> snapshotTDF(std::make_shared<TLoopManager>(nullptr, bnames));
1211  auto chain = new TChain(fullTreeNameInt.c_str());
1212  chain->Add(filenameInt.c_str());
1213  snapshotTDF.fProxiedPtr->SetTree(std::shared_ptr<TTree>(static_cast<TTree *>(chain)));
1214 
1215  return snapshotTDF;
1216  }
1217 
1218  TInterface(const std::shared_ptr<Proxied> &proxied, const std::weak_ptr<TLoopManager> &impl)
1219  : fProxiedPtr(proxied), fImplWeakPtr(impl)
1220  {
1221  }
1222 
1223  /// Only enabled when building a TInterface<TLoopManager>
1224  template <typename T = Proxied, typename std::enable_if<std::is_same<T, TLoopManager>::value, int>::type = 0>
1225  TInterface(const std::shared_ptr<Proxied> &proxied) : fProxiedPtr(proxied), fImplWeakPtr(proxied->GetSharedPtr())
1226  {
1227  }
1228 
1229  std::shared_ptr<Proxied> fProxiedPtr;
1230  std::weak_ptr<TLoopManager> fImplWeakPtr;
1231 };
1232 
1233 template <>
1235 {
1236  return "ROOT::Experimental::TDF::TInterface<ROOT::Detail::TDF::TFilterBase>";
1237 }
1238 
1239 template <>
1241 {
1242  return "ROOT::Experimental::TDF::TInterface<ROOT::Detail::TDF::TCustomColumnBase>";
1243 }
1244 
1245 template <>
1247 {
1248  return "ROOT::Experimental::TDF::TInterface<ROOT::Detail::TDF::TLoopManager>";
1249 }
1250 
1251 template <>
1253 {
1254  return "ROOT::Experimental::TDF::TInterface<ROOT::Detail::TDF::TRangeBase>";
1255 }
1256 
1257 } // end NS TDF
1258 } // end NS Experimental
1259 } // end NS ROOT
1260 
1261 #endif // ROOT_TDF_INTERFACE
TResultProxy<::TProfile2D > Profile2D(::TProfile2D &&model, std::string_view v1Name, std::string_view v2Name, std::string_view v3Name, std::string_view wName)
Fill and return a two-dimensional profile (lazy action)
TResultProxy<::TH3F > Histo3D(::TH3F &&model, std::string_view v1Name="", std::string_view v2Name="", std::string_view v3Name="")
Fill and return a three-dimensional histogram (lazy action)
An array of TObjects.
Definition: TObjArray.h:37
TResultProxy<::TProfile2D > Profile2D(::TProfile2D &&model)
TResultProxy<::TH3F > Histo3D(::TH3F &&model)
TResultProxy<::TH3F > Histo3D(::TH3F &&model, std::string_view v1Name, std::string_view v2Name, std::string_view v3Name, std::string_view wName)
Fill and return a three-dimensional histogram (lazy action)
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
TInterface< TLoopManager > Snapshot(std::string_view treename, std::string_view filename, std::string_view columnNameRegexp="")
Create a snapshot of the dataset on disk in the form of a TTree.
std::pair< Double_t, Double_t > Range_t
Definition: TGLUtil.h:1193
double T(double x)
Definition: ChebyshevPol.h:34
TH1 * h
Definition: legend2.C:5
TInterface< TCustomColumnBase > Define(std::string_view name, std::string_view expression)
Creates a temporary branch.
TInterface< TCustomColumnBase > Define(std::string_view name, F expression, const ColumnNames_t &bl={})
Creates a temporary branch.
TInterface< TLoopManager > Snapshot(std::string_view treename, std::string_view filename, const ColumnNames_t &bnames)
Create a snapshot of the dataset on disk in the form of a TTree.
Regular expression class.
Definition: TRegexp.h:31
void Foreach(F f, const ColumnNames_t &bl={})
Execute a user-defined function on each entry (instant action)
const ColumnNames_t & PickBranchNames(unsigned int nArgs, const ColumnNames_t &bl, const ColumnNames_t &defBl)
Returns local BranchNames or default BranchNames according to which one should be used...
Definition: TDFUtils.cxx:147
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:168
#define gInterpreter
Definition: TInterpreter.h:499
void CallBuildAndBook(TDFNode *node, const ColumnNames_t &bl, unsigned int nSlots, const std::shared_ptr< ActionResultType > &r)
Profile Histogram.
Definition: TProfile.h:32
TInterface< TFilterBase > Filter(F f, const std::initializer_list< std::string > &bn)
Append a filter to the call graph.
const ColumnNames_t GetDefaultBranchNames(unsigned int nExpectedBranches, std::string_view actionNameForErr)
TResultProxy<::TH2F > Histo2D(::TH2F &&model)
TResultProxy<::TProfile > Profile1D(::TProfile &&model)
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=1, Int_t netopt=0)
Create / open a file.
Definition: TFile.cxx:3909
TInterface< TFilterBase > Filter(F f, const ColumnNames_t &bn={}, std::string_view name="")
Append a filter to the call graph.
TTree * GetTree() const
Definition: TTreeReader.h:152
TResultProxy<::TH2F > Histo2D(::TH2F &&model, std::string_view v1Name="", std::string_view v2Name="")
Fill and return a two-dimensional histogram (lazy action)
TInterface< TRangeBase > Range(unsigned int start, unsigned int stop, unsigned int stride=1)
Creates a node that filters entries based on range.
TInterface< TLoopManager > Snapshot(std::string_view treename, std::string_view filename, const ColumnNames_t &bnames)
Create a snapshot of the dataset on disk in the form of a TTree.
TResultProxy<::TH1F > Histo1D(::TH1F &&model=::TH1F{"", "", 128u, 0., 0.})
TResultProxy<::TProfile > Profile1D(::TProfile &&model, std::string_view v1Name="", std::string_view v2Name="")
Fill and return a one-dimensional profile (lazy action)
TResultProxy<::TProfile2D > Profile2D(::TProfile2D &&model, std::string_view v1Name="", std::string_view v2Name="", std::string_view v3Name="")
Fill and return a two-dimensional profile (lazy action)
TResultProxy<::TH1F > Histo1D(::TH1F &&model, std::string_view vName, std::string_view wName)
Fill and return a one-dimensional histogram with the values of a branch (lazy action) ...
TResultProxy< T > Reduce(F f, std::string_view branchName={})
Execute a user-defined reduce operation on the values of a branch.
RooArgSet S(const RooAbsArg &v1)
Smart pointer for the return type of actions.
#define F(x, y, z)
std::string printValue(const TDatime *val)
Print a TDatime at the prompt.
Definition: TDatime.cxx:514
TResultProxy<::TH2F > Histo2D(::TH2F &&model, std::string_view v1Name, std::string_view v2Name, std::string_view wName)
Fill and return a two-dimensional histogram (lazy action)
TRandom2 r(17)
TResultProxy<::TH1F > Histo1D(std::string_view vName)
TInterface< TFilterBase > Filter(F f, std::string_view name)
Append a filter to the call graph.
TInterface(const std::shared_ptr< Proxied > &proxied, const std::weak_ptr< TLoopManager > &impl)
Double_t Mean(Long64_t n, const T *a, const Double_t *w=0)
Definition: TMath.h:973
TResultProxy<::TH1F > Histo1D(::TH1F &&model=::TH1F{"", "", 128u, 0., 0.}, std::string_view vName="")
Fill and return a one-dimensional histogram with the values of a branch (lazy action) ...
void fillTree(TTree &t2)
Definition: testRooFit.cxx:49
std::shared_ptr< TLoopManager > GetDataFrameChecked()
Get the TLoopManager if reachable. If not, throw.
TBufferMerger is a class to facilitate writing data in parallel from multiple threads, while writing to a single output file.
Histogram class for histograms with DIMENSIONS dimensions, where each bin count is stored by a value ...
Definition: THist.hxx:33
std::string ColumnName2ColumnTypeName(const std::string &colName, TTree *tree, TCustomColumnBase *tmpBranch)
Return a string containing the type of the given branch.
Definition: TDFUtils.cxx:30
void ForeachSlot(F f, const ColumnNames_t &bl={})
Execute a user-defined function requiring a processing slot index on each entry (instant action) ...
TInterface< TRangeBase > Range(unsigned int stop)
Creates a node that filters entries based on range.
TResultProxy< T > Fill(T &&model, const ColumnNames_t &bl)
Long_t JitTransformation(void *thisPtr, const std::string &methodName, const std::string &nodeTypeName, const std::string &name, const std::string &expression, TObjArray *branches, const std::vector< std::string > &tmpBranches, const std::map< std::string, TmpBranchBasePtr_t > &tmpBookedBranches, TTree *tree)
TResultProxy< ActionResultType > CreateAction(const ColumnNames_t &bl, const std::shared_ptr< ActionResultType > &r)
long Long_t
Definition: RtypesCore.h:50
TResultProxy< T > MakeResultProxy(const std::shared_ptr< T > &r, const std::shared_ptr< TLoopManager > &df)
double f(double x)
TInterface< TFilterBase > Filter(std::string_view expression, std::string_view name="")
Append a filter to the call graph.
TResultProxy< double > Min(std::string_view branchName="")
Return the minimum of processed branch values (lazy action)
Ssiz_t Index(const TString &str, Ssiz_t *len, Ssiz_t start=0) const
Find the first occurrence of the regexp in string and return the position, or -1 if there is no match...
Definition: TRegexp.cxx:209
int type
Definition: TGX11.cxx:120
Print a TSeq at the prompt:
Definition: TDatime.h:115
void Run(unsigned int slot, Long64_t entry) final
Definition: TDFNodes.hxx:251
TResultProxy< double > Max(std::string_view branchName="")
Return the maximum of processed branch values (lazy action)
void Report()
Print filtering statistics on screen.
static RooMathCoreReg dummy
std::shared_ptr< Proxied > fProxiedPtr
Profile2D histograms are used to display the mean value of Z and its RMS for each cell in X...
Definition: TProfile2D.h:27
typedef void((*Func_t)())
TResultProxy< T > Fill(T &&model, const ColumnNames_t &bl)
Fill and return any entity with a Fill method (lazy action)
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition: TROOT.cxx:552
TResultProxy<::TH1F > Histo1D(std::string_view vName, std::string_view wName)
Definition: file.py:1
Key/value store of objects.
Definition: TDirectory.hxx:68
ROOT&#39;s TDataFrame offers a high level interface for analyses of data stored in TTrees.
Definition: TDataFrame.hxx:36
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:200
A chain is a collection of files containing TTree objects.
Definition: TChain.h:33
void CheckTmpBranch(std::string_view branchName, TTree *treePtr)
Definition: TDFUtils.cxx:134
you should not use this method at all Int_t Int_t Double_t Double_t Double_t Int_t Double_t Double_t Double_t Double_t b
Definition: TRolke.cxx:630
Definition: tree.py:1
ColumnNames_t GetBranchNames(const std::vector< std::string_view > &bl, std::string_view actionNameForErr)
Returns the default branches if needed, takes care of the error handling.
void JitBuildAndBook(const ColumnNames_t &bl, const std::string &nodeTypename, void *thisPtr, const std::type_info &art, const std::type_info &at, const void *r, TTree *tree, unsigned int nSlots, const std::map< std::string, TmpBranchBasePtr_t > &tmpBranches)
TResultProxy< T > Reduce(F f, std::string_view branchName, const T &initValue)
Execute a user-defined reduce operation on the values of a branch.
std::shared_ptr< TCustomColumnBase > TmpBranchBasePtr_t
Definition: first.py:1
std::vector< std::string > GetUsedBranchesNames(const std::string, TObjArray *, const std::vector< std::string > &)
TResultProxy< double > Mean(std::string_view branchName="")
Return the mean of processed branch values (lazy action)
std::weak_ptr< TLoopManager > fImplWeakPtr
static void Fill(TTree *tree, int init, int count)
The public interface to the TDataFrame federation of classes.
TInterface< TLoopManager > SnapshotImpl(std::string_view treename, std::string_view filename, const ColumnNames_t &bnames, TDFInternal::TStaticSeq< S... >)
Implementation of snapshot.
virtual Int_t Add(TChain *chain)
Add all files referenced by the passed chain to this chain.
Definition: TChain.cxx:220
TResultProxy<::TProfile > Profile1D(::TProfile &&model, std::string_view v1Name, std::string_view v2Name, std::string_view wName)
Fill and return a one-dimensional profile (lazy action)
TInterface(const std::shared_ptr< Proxied > &proxied)
Only enabled when building a TInterface<TLoopManager>
TResultProxy< COLL > Take(std::string_view branchName="")
Return a collection of values of a branch (lazy action)
TResultProxy< unsigned int > Count()
Return the number of entries processed (lazy action)