Logo ROOT   6.10/02
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  auto tree = df->GetTree();
244  auto branches = tree ? tree->GetListOfBranches() : nullptr;
245  auto tmpBranches = fProxiedPtr->GetTmpBranches();
246  auto tmpBookedBranches = df->GetBookedBranches();
247  const std::string expressionInt(expression);
248  const std::string nameInt(name);
249  auto retVal = TDFInternal::JitTransformation(this, "Define", GetNodeTypeName(), nameInt, expressionInt, branches,tmpBranches, tmpBookedBranches, tree);
250  return *(TInterface<TCustomColumnBase> *)retVal;
251  }
252 
253  ////////////////////////////////////////////////////////////////////////////
254  /// \brief Create a snapshot of the dataset on disk in the form of a TTree
255  /// \tparam BranchTypes variadic list of branch/column types
256  /// \param[in] treename The name of the output TTree
257  /// \param[in] filename The name of the output TFile
258  /// \param[in] bnames The list of names of the branches to be written
259  ///
260  /// This function returns a `TDataFrame` built with the output tree as a source.
261  template <typename... BranchTypes>
262  TInterface<TLoopManager> Snapshot(std::string_view treename, std::string_view filename,
263  const ColumnNames_t &bnames)
264  {
265  using TypeInd_t = typename TDFInternal::TGenStaticSeq<sizeof...(BranchTypes)>::Type_t;
266  return SnapshotImpl<BranchTypes...>(treename, filename, bnames, TypeInd_t());
267  }
268 
269  ////////////////////////////////////////////////////////////////////////////
270  /// \brief Create a snapshot of the dataset on disk in the form of a TTree
271  /// \param[in] treename The name of the output TTree
272  /// \param[in] filename The name of the output TFile
273  /// \param[in] bnames The list of names of the branches to be written
274  ///
275  /// This function returns a `TDataFrame` built with the output tree as a source.
276  /// The types of the branches are automatically inferred and do not need to be specified.
277  TInterface<TLoopManager> Snapshot(std::string_view treename, std::string_view filename,
278  const ColumnNames_t &bnames)
279  {
280  auto df = GetDataFrameChecked();
281  auto tree = df->GetTree();
282  std::stringstream snapCall;
283  // build a string equivalent to
284  // "reinterpret_cast</nodetype/*>(this)->Snapshot<Ts...>(treename,filename,*reinterpret_cast<ColumnNames_t*>(&bnames))"
285  snapCall << "if (gROOTMutex) gROOTMutex->UnLock(); ((" << GetNodeTypeName() << "*)" << this << ")->Snapshot<";
286  bool first = true;
287  for (auto &b : bnames) {
288  if (!first) snapCall << ", ";
289  snapCall << TDFInternal::ColumnName2ColumnTypeName(b, tree, df->GetBookedBranch(b));
290  first = false;
291  };
292  const std::string treeNameInt(treename);
293  const std::string filenameInt(filename);
294  snapCall << ">(\"" << treeNameInt << "\", \"" << filenameInt << "\", "
295  << "*reinterpret_cast<std::vector<std::string>*>(" // vector<string> should be ColumnNames_t
296  << &bnames << "));";
297  // jit snapCall, return result
298  TInterpreter::EErrorCode errorCode;
299  auto newTDFPtr = gInterpreter->ProcessLine(snapCall.str().c_str(), &errorCode);
300  if (TInterpreter::EErrorCode::kNoError != errorCode) {
301  std::string msg = "Cannot jit Snapshot call. Interpreter error code is " + std::to_string(errorCode) + ".";
302  throw std::runtime_error(msg);
303  }
304  return *reinterpret_cast<TInterface<TLoopManager> *>(newTDFPtr);
305  }
306 
307  ////////////////////////////////////////////////////////////////////////////
308  /// \brief Create a snapshot of the dataset on disk in the form of a TTree
309  /// \param[in] treename The name of the output TTree
310  /// \param[in] filename The name of the output TFile
311  /// \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.
312  ///
313  /// This function returns a `TDataFrame` built with the output tree as a source.
314  /// The types of the branches are automatically inferred and do not need to be specified.
315  TInterface<TLoopManager> Snapshot(std::string_view treename, std::string_view filename,
316  std::string_view columnNameRegexp = "")
317  {
318  const auto theRegexSize = columnNameRegexp.size();
319  std::string theRegex(columnNameRegexp);
320 
321  const auto isEmptyRegex = 0 == theRegexSize;
322  // This is to avoid cases where branches called b1, b2, b3 are all matched by expression "b"
323  if (theRegexSize > 0 && theRegex[0] != '^') theRegex = "^" + theRegex;
324  if (theRegexSize > 0 && theRegex[theRegexSize-1] != '$') theRegex = theRegex + "$";
325 
326  ColumnNames_t selectedColumns;
327  selectedColumns.reserve(32);
328 
329  const auto tmpBranches = fProxiedPtr->GetTmpBranches();
330  // Since we support gcc48 and it does not provide in its stl std::regex,
331  // we need to use TRegexp
332  TRegexp regexp(theRegex);
333  int dummy;
334  for (auto &&branchName : tmpBranches) {
335  if (isEmptyRegex || -1 != regexp.Index(branchName.c_str(), &dummy)) {
336  selectedColumns.emplace_back(branchName);
337  }
338  }
339 
340  auto df = GetDataFrameChecked();
341  auto tree = df->GetTree();
342  if (tree) {
343  const auto branches = tree->GetListOfBranches();
344  for (auto branch : *branches) {
345  auto branchName = branch->GetName();
346  if (isEmptyRegex || -1 != regexp.Index(branchName, &dummy)) {
347  selectedColumns.emplace_back(branchName);
348  }
349  }
350  }
351 
352  return Snapshot(treename, filename, selectedColumns);
353  }
354 
355  ////////////////////////////////////////////////////////////////////////////
356  /// \brief Creates a node that filters entries based on range
357  /// \param[in] start How many entries to discard before resuming processing.
358  /// \param[in] stop Total number of entries that will be processed before stopping. 0 means "never stop".
359  /// \param[in] stride Process one entry every `stride` entries. Must be strictly greater than 0.
360  ///
361  /// Ranges are only available if EnableImplicitMT has _not_ been called. Multi-thread ranges are not supported.
362  TInterface<TRangeBase> Range(unsigned int start, unsigned int stop, unsigned int stride = 1)
363  {
364  // check invariants
365  if (stride == 0 || (stop != 0 && stop < start))
366  throw std::runtime_error("Range: stride must be strictly greater than 0 and stop must be greater than start.");
368  throw std::runtime_error("Range was called with ImplicitMT enabled. Multi-thread ranges are not supported.");
369 
370  auto df = GetDataFrameChecked();
372  auto RangePtr = std::make_shared<Range_t>(start, stop, stride, *fProxiedPtr);
373  fProxiedPtr->IncrChildrenCount();
374  df->Book(RangePtr);
375  TInterface<TRangeBase> tdf_r(RangePtr, fImplWeakPtr);
376  return tdf_r;
377  }
378 
379  ////////////////////////////////////////////////////////////////////////////
380  /// \brief Creates a node that filters entries based on range
381  /// \param[in] stop Total number of entries that will be processed before stopping. 0 means "never stop".
382  ///
383  /// See the other Range overload for a detailed description.
384  TInterface<TRangeBase> Range(unsigned int stop) { return Range(0, stop, 1); }
385 
386  ////////////////////////////////////////////////////////////////////////////
387  /// \brief Execute a user-defined function on each entry (*instant action*)
388  /// \param[in] f Function, lambda expression, functor class or any other callable object performing user defined
389  /// calculations.
390  /// \param[in] bl Names of the branches in input to the user function.
391  ///
392  /// The callable `f` is invoked once per entry. This is an *instant action*:
393  /// upon invocation, an event loop as well as execution of all scheduled actions
394  /// is triggered.
395  /// Users are responsible for the thread-safety of this callable when executing
396  /// with implicit multi-threading enabled (i.e. ROOT::EnableImplicitMT).
397  template <typename F>
398  void Foreach(F f, const ColumnNames_t &bl = {})
399  {
400  using Args_t = typename TDFInternal::TFunctionTraits<decltype(f)>::ArgsNoDecay_t;
401  using Ret_t = typename TDFInternal::TFunctionTraits<decltype(f)>::Ret_t;
402  ForeachSlot(TDFInternal::AddSlotParameter<Ret_t>(f, Args_t()), bl);
403  }
404 
405  ////////////////////////////////////////////////////////////////////////////
406  /// \brief Execute a user-defined function requiring a processing slot index on each entry (*instant action*)
407  /// \param[in] f Function, lambda expression, functor class or any other callable object performing user defined
408  /// calculations.
409  /// \param[in] bl Names of the branches in input to the user function.
410  ///
411  /// Same as `Foreach`, but the user-defined function takes an extra
412  /// `unsigned int` as its first parameter, the *processing slot index*.
413  /// This *slot index* will be assigned a different value, `0` to `poolSize - 1`,
414  /// for each thread of execution.
415  /// This is meant as a helper in writing thread-safe `Foreach`
416  /// actions when using `TDataFrame` after `ROOT::EnableImplicitMT()`.
417  /// The user-defined processing callable is able to follow different
418  /// *streams of processing* indexed by the first parameter.
419  /// `ForeachSlot` works just as well with single-thread execution: in that
420  /// case `slot` will always be `0`.
421  template <typename F>
422  void ForeachSlot(F f, const ColumnNames_t &bl = {})
423  {
424  auto df = GetDataFrameChecked();
425  const ColumnNames_t &defBl = df->GetDefaultBranches();
426  auto nArgs = TDFInternal::TFunctionTraits<F>::Args_t::fgSize;
427  const ColumnNames_t &actualBl = TDFInternal::PickBranchNames(nArgs - 1, bl, defBl);
428  using Op_t = TDFInternal::ForeachSlotHelper<F>;
430  df->Book(std::make_shared<DFA_t>(Op_t(std::move(f)), actualBl, *fProxiedPtr));
431  fProxiedPtr->IncrChildrenCount();
432  df->Run();
433  }
434 
435  ////////////////////////////////////////////////////////////////////////////
436  /// \brief Execute a user-defined reduce operation on the values of a branch
437  /// \tparam F The type of the reduce callable. Automatically deduced.
438  /// \tparam T The type of the branch to apply the reduction to. Automatically deduced.
439  /// \param[in] f A callable with signature `T(T,T)`
440  /// \param[in] branchName The branch to be reduced. If omitted, the default branch is used instead.
441  ///
442  /// A reduction takes two values of a branch and merges them into one (e.g.
443  /// by summing them, taking the maximum, etc). This action performs the
444  /// specified reduction operation on all branch values, returning
445  /// a single value of the same type. The callable f must satisfy the general
446  /// requirements of a *processing function* besides having signature `T(T,T)`
447  /// where `T` is the type of branch.
448  ///
449  /// This action is *lazy*: upon invocation of this method the calculation is
450  /// booked but not executed. See TResultProxy documentation.
451  template <typename F, typename T = typename TDFInternal::TFunctionTraits<F>::Ret_t>
452  TResultProxy<T> Reduce(F f, std::string_view branchName = {})
453  {
454  static_assert(std::is_default_constructible<T>::value,
455  "reduce object cannot be default-constructed. Please provide an initialisation value (initValue)");
456  return Reduce(std::move(f), branchName, T());
457  }
458 
459  ////////////////////////////////////////////////////////////////////////////
460  /// \brief Execute a user-defined reduce operation on the values of a branch
461  /// \tparam F The type of the reduce callable. Automatically deduced.
462  /// \tparam T The type of the branch to apply the reduction to. Automatically deduced.
463  /// \param[in] f A callable with signature `T(T,T)`
464  /// \param[in] branchName The branch to be reduced. If omitted, the default branch is used instead.
465  /// \param[in] initValue The reduced object is initialised to this value rather than being default-constructed
466  ///
467  /// See the description of the other Reduce overload for more information.
468  template <typename F, typename T = typename TDFInternal::TFunctionTraits<F>::Ret_t>
469  TResultProxy<T> Reduce(F f, std::string_view branchName, const T &initValue)
470  {
471  using Args_t = typename TDFInternal::TFunctionTraits<F>::Args_t;
472  TDFInternal::CheckReduce(f, Args_t());
473  auto df = GetDataFrameChecked();
474  unsigned int nSlots = df->GetNSlots();
475  auto bl = GetBranchNames<T>({branchName}, "reduce branch values");
476  auto redObjPtr = std::make_shared<T>(initValue);
477  using Op_t = TDFInternal::ReduceHelper<F, T>;
478  using DFA_t = typename TDFInternal::TAction<Op_t, Proxied>;
479  df->Book(std::make_shared<DFA_t>(Op_t(std::move(f), redObjPtr, nSlots), bl, *fProxiedPtr));
480  fProxiedPtr->IncrChildrenCount();
481  return MakeResultProxy(redObjPtr, df);
482  }
483 
484  ////////////////////////////////////////////////////////////////////////////
485  /// \brief Return the number of entries processed (*lazy action*)
486  ///
487  /// This action is *lazy*: upon invocation of this method the calculation is
488  /// booked but not executed. See TResultProxy documentation.
490  {
491  auto df = GetDataFrameChecked();
492  unsigned int nSlots = df->GetNSlots();
493  auto cSPtr = std::make_shared<unsigned int>(0);
494  using Op_t = TDFInternal::CountHelper;
496  df->Book(std::make_shared<DFA_t>(Op_t(cSPtr, nSlots), ColumnNames_t({}), *fProxiedPtr));
497  fProxiedPtr->IncrChildrenCount();
498  return MakeResultProxy(cSPtr, df);
499  }
500 
501  ////////////////////////////////////////////////////////////////////////////
502  /// \brief Return a collection of values of a branch (*lazy action*)
503  /// \tparam T The type of the branch.
504  /// \tparam COLL The type of collection used to store the values.
505  /// \param[in] branchName The name of the branch of which the values are to be collected
506  ///
507  /// This action is *lazy*: upon invocation of this method the calculation is
508  /// booked but not executed. See TResultProxy documentation.
509  template <typename T, typename COLL = std::vector<T>>
510  TResultProxy<COLL> Take(std::string_view branchName = "")
511  {
512  auto df = GetDataFrameChecked();
513  unsigned int nSlots = df->GetNSlots();
514  auto bl = GetBranchNames<T>({branchName}, "get the values of the branch");
515  auto valuesPtr = std::make_shared<COLL>();
516  using Op_t = TDFInternal::TakeHelper<T, COLL>;
518  df->Book(std::make_shared<DFA_t>(Op_t(valuesPtr, nSlots), bl, *fProxiedPtr));
519  fProxiedPtr->IncrChildrenCount();
520  return MakeResultProxy(valuesPtr, df);
521  }
522 
523  ////////////////////////////////////////////////////////////////////////////
524  /// \brief Fill and return a one-dimensional histogram with the values of a branch (*lazy action*)
525  /// \tparam V The type of the branch used to fill the histogram.
526  /// \param[in] model The returned histogram will be constructed using this as a model.
527  /// \param[in] vName The name of the branch that will fill the histogram.
528  ///
529  /// The default branches, if available, will be used instead of branches whose names are left empty.
530  /// Branches can be of a container type (e.g. std::vector<double>), in which case the histogram
531  /// is filled with each one of the elements of the container. In case multiple branches of container type
532  /// are provided (e.g. values and weights) they must have the same length for each one of the events (but
533  /// possibly different lengths between events).
534  /// This action is *lazy*: upon invocation of this method the calculation is
535  /// booked but not executed. See TResultProxy documentation.
536  /// The user gives up ownership of the model histogram.
537  template <typename V = TDFDetail::TInferType>
538  TResultProxy<::TH1F> Histo1D(::TH1F &&model = ::TH1F{"", "", 128u, 0., 0.}, std::string_view vName = "")
539  {
540  auto bl = GetBranchNames<V>({vName}, "fill the histogram");
541  auto h = std::make_shared<::TH1F>(std::move(model));
542  if (h->GetXaxis()->GetXmax() == h->GetXaxis()->GetXmin())
543  TDFInternal::HistoUtils<::TH1F>::SetCanExtendAllAxes(*h);
544  return CreateAction<TDFInternal::ActionTypes::Histo1D, V>(bl, h);
545  }
546 
547  template <typename V = TDFDetail::TInferType>
548  TResultProxy<::TH1F> Histo1D(std::string_view vName)
549  {
550  return Histo1D<V>(::TH1F{"", "", 128u, 0., 0.}, vName);
551  }
552 
553  ////////////////////////////////////////////////////////////////////////////
554  /// \brief Fill and return a one-dimensional histogram with the values of a branch (*lazy action*)
555  /// \tparam V The type of the branch used to fill the histogram.
556  /// \param[in] model The returned histogram will be constructed using this as a model.
557  /// \param[in] vName The name of the branch that will fill the histogram.
558  /// \param[in] wName The name of the branch that will provide the weights.
559  ///
560  /// The default branches, if available, will be used instead of branches whose names are left empty.
561  /// Branches can be of a container type (e.g. std::vector<double>), in which case the histogram
562  /// is filled with each one of the elements of the container. In case multiple branches of container type
563  /// are provided (e.g. values and weights) they must have the same length for each one of the events (but
564  /// possibly different lengths between events).
565  /// This action is *lazy*: upon invocation of this method the calculation is
566  /// booked but not executed. See TResultProxy documentation.
567  /// The user gives up ownership of the model histogram.
568  template <typename V = TDFDetail::TInferType, typename W = TDFDetail::TInferType>
569  TResultProxy<::TH1F> Histo1D(::TH1F &&model, std::string_view vName, std::string_view wName)
570  {
571  auto bl = GetBranchNames<V, W>({vName, wName}, "fill the histogram");
572  auto h = std::make_shared<::TH1F>(std::move(model));
573  return CreateAction<TDFInternal::ActionTypes::Histo1D, V, W>(bl, h);
574  }
575 
576  template <typename V = TDFDetail::TInferType, typename W = TDFDetail::TInferType>
577  TResultProxy<::TH1F> Histo1D(std::string_view vName, std::string_view wName)
578  {
579  return Histo1D<V, W>(::TH1F{"", "", 128u, 0., 0.}, vName, wName);
580  }
581 
582  template <typename V, typename W>
583  TResultProxy<::TH1F> Histo1D(::TH1F &&model = ::TH1F{"", "", 128u, 0., 0.})
584  {
585  return Histo1D<V, W>(std::move(model), "", "");
586  }
587 
588  ////////////////////////////////////////////////////////////////////////////
589  /// \brief Fill and return a two-dimensional histogram (*lazy action*)
590  /// \tparam V1 The type of the branch used to fill the x axis of the histogram.
591  /// \tparam V2 The type of the branch used to fill the y axis of the histogram.
592  /// \param[in] model The returned histogram will be constructed using this as a model.
593  /// \param[in] v1Name The name of the branch that will fill the x axis.
594  /// \param[in] v2Name The name of the branch that will fill the y axis.
595  ///
596  /// This action is *lazy*: upon invocation of this method the calculation is
597  /// booked but not executed. See TResultProxy documentation.
598  /// The user gives up ownership of the model histogram.
599  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType>
600  TResultProxy<::TH2F> Histo2D(::TH2F &&model, std::string_view v1Name = "", std::string_view v2Name = "")
601  {
602  auto h = std::make_shared<::TH2F>(std::move(model));
603  if (!TDFInternal::HistoUtils<::TH2F>::HasAxisLimits(*h)) {
604  throw std::runtime_error("2D histograms with no axes limits are not supported yet.");
605  }
606  auto bl = GetBranchNames<V1, V2>({v1Name, v2Name}, "fill the histogram");
607  return CreateAction<TDFInternal::ActionTypes::Histo2D, V1, V2>(bl, h);
608  }
609 
610  ////////////////////////////////////////////////////////////////////////////
611  /// \brief Fill and return a two-dimensional histogram (*lazy action*)
612  /// \tparam V1 The type of the branch used to fill the x axis of the histogram.
613  /// \tparam V2 The type of the branch used to fill the y axis of the histogram.
614  /// \tparam W The type of the branch used for the weights of the histogram.
615  /// \param[in] model The returned histogram will be constructed using this as a model.
616  /// \param[in] v1Name The name of the branch that will fill the x axis.
617  /// \param[in] v2Name The name of the branch that will fill the y axis.
618  /// \param[in] wName The name of the branch that will provide the weights.
619  ///
620  /// This action is *lazy*: upon invocation of this method the calculation is
621  /// booked but not executed. See TResultProxy documentation.
622  /// The user gives up ownership of the model histogram.
623  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType,
624  typename W = TDFDetail::TInferType>
625  TResultProxy<::TH2F> Histo2D(::TH2F &&model, std::string_view v1Name, std::string_view v2Name,
626  std::string_view wName)
627  {
628  auto h = std::make_shared<::TH2F>(std::move(model));
629  if (!TDFInternal::HistoUtils<::TH2F>::HasAxisLimits(*h)) {
630  throw std::runtime_error("2D histograms with no axes limits are not supported yet.");
631  }
632  auto bl = GetBranchNames<V1, V2, W>({v1Name, v2Name, wName}, "fill the histogram");
633  return CreateAction<TDFInternal::ActionTypes::Histo2D, V1, V2, W>(bl, h);
634  }
635 
636  template <typename V1, typename V2, typename W>
638  {
639  return Histo2D<V1, V2, W>(std::move(model), "", "", "");
640  }
641 
642  ////////////////////////////////////////////////////////////////////////////
643  /// \brief Fill and return a three-dimensional histogram (*lazy action*)
644  /// \tparam V1 The type of the branch used to fill the x axis of the histogram.
645  /// \tparam V2 The type of the branch used to fill the y axis of the histogram.
646  /// \tparam V3 The type of the branch used to fill the z axis of the histogram.
647  /// \param[in] model The returned histogram will be constructed using this as a model.
648  /// \param[in] v1Name The name of the branch that will fill the x axis.
649  /// \param[in] v2Name The name of the branch that will fill the y axis.
650  /// \param[in] v3Name The name of the branch that will fill the z axis.
651  ///
652  /// This action is *lazy*: upon invocation of this method the calculation is
653  /// booked but not executed. See TResultProxy documentation.
654  /// The user gives up ownership of the model histogram.
655  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType,
656  typename V3 = TDFDetail::TInferType>
657  TResultProxy<::TH3F> Histo3D(::TH3F &&model, std::string_view v1Name = "", std::string_view v2Name = "",
658  std::string_view v3Name = "")
659  {
660  auto h = std::make_shared<::TH3F>(std::move(model));
661  if (!TDFInternal::HistoUtils<::TH3F>::HasAxisLimits(*h)) {
662  throw std::runtime_error("3D histograms with no axes limits are not supported yet.");
663  }
664  auto bl = GetBranchNames<V1, V2, V3>({v1Name, v2Name, v3Name}, "fill the histogram");
665  return CreateAction<TDFInternal::ActionTypes::Histo3D, V1, V2, V3>(bl, h);
666  }
667 
668  ////////////////////////////////////////////////////////////////////////////
669  /// \brief Fill and return a three-dimensional histogram (*lazy action*)
670  /// \tparam V1 The type of the branch used to fill the x axis of the histogram.
671  /// \tparam V2 The type of the branch used to fill the y axis of the histogram.
672  /// \tparam V3 The type of the branch used to fill the z axis of the histogram.
673  /// \tparam W The type of the branch used for the weights of the histogram.
674  /// \param[in] model The returned histogram will be constructed using this as a model.
675  /// \param[in] v1Name The name of the branch that will fill the x axis.
676  /// \param[in] v2Name The name of the branch that will fill the y axis.
677  /// \param[in] v3Name The name of the branch that will fill the z axis.
678  /// \param[in] wName The name of the branch that will provide the weights.
679  ///
680  /// This action is *lazy*: upon invocation of this method the calculation is
681  /// booked but not executed. See TResultProxy documentation.
682  /// The user gives up ownership of the model histogram.
683  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType,
684  typename V3 = TDFDetail::TInferType, typename W = TDFDetail::TInferType>
685  TResultProxy<::TH3F> Histo3D(::TH3F &&model, std::string_view v1Name, std::string_view v2Name,
686  std::string_view v3Name, std::string_view wName)
687  {
688  auto h = std::make_shared<::TH3F>(std::move(model));
689  if (!TDFInternal::HistoUtils<::TH3F>::HasAxisLimits(*h)) {
690  throw std::runtime_error("3D histograms with no axes limits are not supported yet.");
691  }
692  auto bl = GetBranchNames<V1, V2, V3, W>({v1Name, v2Name, v3Name, wName}, "fill the histogram");
693  return CreateAction<TDFInternal::ActionTypes::Histo3D, V1, V2, V3, W>(bl, h);
694  }
695 
696  template <typename V1, typename V2, typename V3, typename W>
698  {
699  return Histo3D<V1, V2, V3, W>(std::move(model), "", "", "", "");
700  }
701 
702  ////////////////////////////////////////////////////////////////////////////
703  /// \brief Fill and return a one-dimensional profile (*lazy action*)
704  /// \tparam V1 The type of the branch the values of which are used to fill the profile.
705  /// \tparam V2 The type of the branch the values of which are used to fill the profile.
706  /// \param[in] model The model to be considered to build the new return value.
707  /// \param[in] v1Name The name of the branch that will fill the x axis.
708  /// \param[in] v2Name The name of the branch that will fill the y axis.
709  ///
710  /// This action is *lazy*: upon invocation of this method the calculation is
711  /// booked but not executed. See TResultProxy documentation.
712  /// The user gives up ownership of the model profile object.
713  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType>
714  TResultProxy<::TProfile> Profile1D(::TProfile &&model, std::string_view v1Name = "",
715  std::string_view v2Name = "")
716  {
717  auto h = std::make_shared<::TProfile>(std::move(model));
718  if (!TDFInternal::HistoUtils<::TProfile>::HasAxisLimits(*h)) {
719  throw std::runtime_error("Profiles with no axes limits are not supported yet.");
720  }
721  auto bl = GetBranchNames<V1, V2>({v1Name, v2Name}, "fill the 1D Profile");
722  return CreateAction<TDFInternal::ActionTypes::Profile1D, V1, V2>(bl, h);
723  }
724 
725  ////////////////////////////////////////////////////////////////////////////
726  /// \brief Fill and return a one-dimensional profile (*lazy action*)
727  /// \tparam V1 The type of the branch the values of which are used to fill the profile.
728  /// \tparam V2 The type of the branch the values of which are used to fill the profile.
729  /// \tparam W The type of the branch the weights of which are used to fill the profile.
730  /// \param[in] model The model to be considered to build the new return value.
731  /// \param[in] v1Name The name of the branch that will fill the x axis.
732  /// \param[in] v2Name The name of the branch that will fill the y axis.
733  /// \param[in] wName The name of the branch that will provide the weights.
734  ///
735  /// This action is *lazy*: upon invocation of this method the calculation is
736  /// booked but not executed. See TResultProxy documentation.
737  /// The user gives up ownership of the model profile object.
738  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType,
739  typename W = TDFDetail::TInferType>
740  TResultProxy<::TProfile> Profile1D(::TProfile &&model, std::string_view v1Name, std::string_view v2Name,
741  std::string_view wName)
742  {
743  auto h = std::make_shared<::TProfile>(std::move(model));
744  if (!TDFInternal::HistoUtils<::TProfile>::HasAxisLimits(*h)) {
745  throw std::runtime_error("Profile histograms with no axes limits are not supported yet.");
746  }
747  auto bl = GetBranchNames<V1, V2, W>({v1Name, v2Name, wName}, "fill the 1D profile");
748  return CreateAction<TDFInternal::ActionTypes::Profile1D, V1, V2, W>(bl, h);
749  }
750 
751  template <typename V1, typename V2, typename W>
753  {
754  return Profile1D<V1, V2, W>(std::move(model), "", "", "");
755  }
756 
757  ////////////////////////////////////////////////////////////////////////////
758  /// \brief Fill and return a two-dimensional profile (*lazy action*)
759  /// \tparam V1 The type of the branch used to fill the x axis of the histogram.
760  /// \tparam V2 The type of the branch used to fill the y axis of the histogram.
761  /// \tparam V2 The type of the branch used to fill the z axis of the histogram.
762  /// \param[in] model The returned profile will be constructed using this as a model.
763  /// \param[in] v1Name The name of the branch that will fill the x axis.
764  /// \param[in] v2Name The name of the branch that will fill the y axis.
765  /// \param[in] v3Name The name of the branch that will fill the z axis.
766  ///
767  /// This action is *lazy*: upon invocation of this method the calculation is
768  /// booked but not executed. See TResultProxy documentation.
769  /// The user gives up ownership of the model profile.
770  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType,
771  typename V3 = TDFDetail::TInferType>
772  TResultProxy<::TProfile2D> Profile2D(::TProfile2D &&model, std::string_view v1Name = "",
773  std::string_view v2Name = "", std::string_view v3Name = "")
774  {
775  auto h = std::make_shared<::TProfile2D>(std::move(model));
776  if (!TDFInternal::HistoUtils<::TProfile2D>::HasAxisLimits(*h)) {
777  throw std::runtime_error("2D profiles with no axes limits are not supported yet.");
778  }
779  auto bl = GetBranchNames<V1, V2, V3>({v1Name, v2Name, v3Name}, "fill the 2D profile");
780  return CreateAction<TDFInternal::ActionTypes::Profile2D, V1, V2, V3>(bl, h);
781  }
782 
783  ////////////////////////////////////////////////////////////////////////////
784  /// \brief Fill and return a two-dimensional profile (*lazy action*)
785  /// \tparam V1 The type of the branch used to fill the x axis of the histogram.
786  /// \tparam V2 The type of the branch used to fill the y axis of the histogram.
787  /// \tparam V3 The type of the branch used to fill the z axis of the histogram.
788  /// \tparam W The type of the branch used for the weights of the histogram.
789  /// \param[in] model The returned histogram will be constructed using this as a model.
790  /// \param[in] v1Name The name of the branch that will fill the x axis.
791  /// \param[in] v2Name The name of the branch that will fill the y axis.
792  /// \param[in] v3Name The name of the branch that will fill the z axis.
793  /// \param[in] wName The name of the branch that will provide the weights.
794  ///
795  /// This action is *lazy*: upon invocation of this method the calculation is
796  /// booked but not executed. See TResultProxy documentation.
797  /// The user gives up ownership of the model profile.
798  template <typename V1 = TDFDetail::TInferType, typename V2 = TDFDetail::TInferType,
799  typename V3 = TDFDetail::TInferType, typename W = TDFDetail::TInferType>
800  TResultProxy<::TProfile2D> Profile2D(::TProfile2D &&model, std::string_view v1Name, std::string_view v2Name,
801  std::string_view v3Name, std::string_view wName)
802  {
803  auto h = std::make_shared<::TProfile2D>(std::move(model));
804  if (!TDFInternal::HistoUtils<::TProfile2D>::HasAxisLimits(*h)) {
805  throw std::runtime_error("2D profiles with no axes limits are not supported yet.");
806  }
807  auto bl = GetBranchNames<V1, V2, V3, W>({v1Name, v2Name, v3Name, wName}, "fill the histogram");
808  return CreateAction<TDFInternal::ActionTypes::Profile2D, V1, V2, V3, W>(bl, h);
809  }
810 
811  template <typename V1, typename V2, typename V3, typename W>
813  {
814  return Profile2D<V1, V2, V3, W>(std::move(model), "", "", "", "");
815  }
816 
817  ////////////////////////////////////////////////////////////////////////////
818  /// \brief Fill and return any entity with a Fill method (*lazy action*)
819  /// \tparam BranchTypes The types of the branches the values of which are used to fill the object.
820  /// \param[in] model The model to be considered to build the new return value.
821  /// \param[in] bl The name of the branches read to fill the object.
822  ///
823  /// The returned object is independent of the input one.
824  /// This action is *lazy*: upon invocation of this method the calculation is
825  /// booked but not executed. See TResultProxy documentation.
826  /// The user gives up ownership of the model object.
827  /// It is compulsory to express the branches to be considered.
828  template <typename FirstBranch, typename... OtherBranches, typename T> // need FirstBranch to disambiguate overloads
830  {
831  auto h = std::make_shared<T>(std::move(model));
832  if (!TDFInternal::HistoUtils<T>::HasAxisLimits(*h)) {
833  throw std::runtime_error("The absence of axes limits is not supported yet.");
834  }
835  return CreateAction<TDFInternal::ActionTypes::Fill, FirstBranch, OtherBranches...>(bl, h);
836  }
837 
838  template <typename T>
840  {
841  auto h = std::make_shared<T>(std::move(model));
842  if (!TDFInternal::HistoUtils<T>::HasAxisLimits(*h)) {
843  throw std::runtime_error("The absence of axes limits is not supported yet.");
844  }
845  return CreateAction<TDFInternal::ActionTypes::Fill, TDFDetail::TInferType>(bl, h);
846  }
847 
848  ////////////////////////////////////////////////////////////////////////////
849  /// \brief Return the minimum of processed branch values (*lazy action*)
850  /// \tparam T The type of the branch.
851  /// \param[in] branchName The name of the branch to be treated.
852  ///
853  /// If no branch type is specified, the implementation will try to guess one.
854  ///
855  /// This action is *lazy*: upon invocation of this method the calculation is
856  /// booked but not executed. See TResultProxy documentation.
857  template <typename T = TDFDetail::TInferType>
858  TResultProxy<double> Min(std::string_view branchName = "")
859  {
860  auto bl = GetBranchNames<T>({branchName}, "calculate the minimum");
861  auto minV = std::make_shared<double>(std::numeric_limits<double>::max());
862  return CreateAction<TDFInternal::ActionTypes::Min, T>(bl, minV);
863  }
864 
865  ////////////////////////////////////////////////////////////////////////////
866  /// \brief Return the maximum of processed branch values (*lazy action*)
867  /// \tparam T The type of the branch.
868  /// \param[in] branchName The name of the branch to be treated.
869  ///
870  /// If no branch type is specified, the implementation will try to guess one.
871  ///
872  /// This action is *lazy*: upon invocation of this method the calculation is
873  /// booked but not executed. See TResultProxy documentation.
874  template <typename T = TDFDetail::TInferType>
875  TResultProxy<double> Max(std::string_view branchName = "")
876  {
877  auto bl = GetBranchNames<T>({branchName}, "calculate the maximum");
878  auto maxV = std::make_shared<double>(std::numeric_limits<double>::min());
879  return CreateAction<TDFInternal::ActionTypes::Max, T>(bl, maxV);
880  }
881 
882  ////////////////////////////////////////////////////////////////////////////
883  /// \brief Return the mean of processed branch values (*lazy action*)
884  /// \tparam T The type of the branch.
885  /// \param[in] branchName The name of the branch to be treated.
886  ///
887  /// If no branch type is specified, the implementation will try to guess one.
888  ///
889  /// This action is *lazy*: upon invocation of this method the calculation is
890  /// booked but not executed. See TResultProxy documentation.
891  template <typename T = TDFDetail::TInferType>
892  TResultProxy<double> Mean(std::string_view branchName = "")
893  {
894  auto bl = GetBranchNames<T>({branchName}, "calculate the mean");
895  auto meanV = std::make_shared<double>(0);
896  return CreateAction<TDFInternal::ActionTypes::Mean, T>(bl, meanV);
897  }
898 
899  ////////////////////////////////////////////////////////////////////////////
900  /// \brief Print filtering statistics on screen
901  ///
902  /// Calling `Report` on the main `TDataFrame` object prints stats for
903  /// all named filters in the call graph. Calling this method on a
904  /// stored chain state (i.e. a graph node different from the first) prints
905  /// the stats for all named filters in the chain section between the original
906  /// `TDataFrame` and that node (included). Stats are printed in the same
907  /// order as the named filters have been added to the graph.
908  void Report()
909  {
910  auto df = GetDataFrameChecked();
911  if (!df->HasRunAtLeastOnce()) df->Run();
912  fProxiedPtr->Report();
913  }
914 
915 private:
916  inline const char *GetNodeTypeName() { return ""; };
917 
918  /// Returns the default branches if needed, takes care of the error handling.
919  template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void>
920  ColumnNames_t GetBranchNames(const std::vector<std::string_view>& bl, std::string_view actionNameForErr)
921  {
922  constexpr auto isT2Void = std::is_same<T2, void>::value;
923  constexpr auto isT3Void = std::is_same<T3, void>::value;
924  constexpr auto isT4Void = std::is_same<T4, void>::value;
925 
926  unsigned int neededBranches = 1 + !isT2Void + !isT3Void + !isT4Void;
927 
928  unsigned int providedBranches = 0;
929  std::for_each(bl.begin(), bl.end(), [&providedBranches](std::string_view s) {
930  if (!s.empty()) providedBranches++;
931  });
932 
933  if (neededBranches == providedBranches) {
934  ColumnNames_t bl2(bl.begin(), bl.end());
935  return bl2;
936  }
937 
938  return GetDefaultBranchNames(neededBranches, actionNameForErr);
939  }
940 
941  /// \cond HIDDEN_SYMBOLS
942 
943  /****** BuildAndBook overloads *******/
944  // BuildAndBook builds a TAction with the right operation and book it with the TLoopManager
945 
946  // Generic filling (covers Histo2D, Histo3D, Profile1D and Profile2D actions, with and without weights)
947  template <typename... BranchTypes, typename ActionType, typename ActionResultType>
948  void BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h, unsigned int nSlots,
949  ActionType *)
950  {
951  using Op_t = TDFInternal::FillTOHelper<ActionResultType>;
952  using DFA_t = TDFInternal::TAction<Op_t, Proxied, TDFInternal::TTypeList<BranchTypes...>>;
953  auto df = GetDataFrameChecked();
954  df->Book(std::make_shared<DFA_t>(Op_t(h, nSlots), bl, *fProxiedPtr));
955  }
956 
957  // Histo1D filling (must handle the special case of distinguishing FillTOHelper and FillHelper
958  template <typename... BranchTypes>
959  void BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr<::TH1F> &h, unsigned int nSlots,
960  TDFInternal::ActionTypes::Histo1D *)
961  {
962  auto df = GetDataFrameChecked();
963  auto hasAxisLimits = TDFInternal::HistoUtils<::TH1F>::HasAxisLimits(*h);
964 
965  if (hasAxisLimits) {
966  using Op_t = TDFInternal::FillTOHelper<::TH1F>;
967  using DFA_t = TDFInternal::TAction<Op_t, Proxied, TDFInternal::TTypeList<BranchTypes...>>;
968  df->Book(std::make_shared<DFA_t>(Op_t(h, nSlots), bl, *fProxiedPtr));
969  } else {
970  using Op_t = TDFInternal::FillHelper;
971  using DFA_t = TDFInternal::TAction<Op_t, Proxied, TDFInternal::TTypeList<BranchTypes...>>;
972  df->Book(std::make_shared<DFA_t>(Op_t(h, nSlots), bl, *fProxiedPtr));
973  }
974  }
975 
976  // Min action
977  template <typename BranchType>
978  void BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr<double> &minV, unsigned int nSlots,
980  {
981  using Op_t = TDFInternal::MinHelper;
983  auto df = GetDataFrameChecked();
984  df->Book(std::make_shared<DFA_t>(Op_t(minV, nSlots), bl, *fProxiedPtr));
985  }
986 
987  // Max action
988  template <typename BranchType>
989  void BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr<double> &maxV, unsigned int nSlots,
991  {
992  using Op_t = TDFInternal::MaxHelper;
994  auto df = GetDataFrameChecked();
995  df->Book(std::make_shared<DFA_t>(Op_t(maxV, nSlots), bl, *fProxiedPtr));
996  }
997 
998  // Mean action
999  template <typename BranchType>
1000  void BuildAndBook(const ColumnNames_t &bl, const std::shared_ptr<double> &meanV, unsigned int nSlots,
1002  {
1003  using Op_t = TDFInternal::MeanHelper;
1005  auto df = GetDataFrameChecked();
1006  df->Book(std::make_shared<DFA_t>(Op_t(meanV, nSlots), bl, *fProxiedPtr));
1007  }
1008  /****** end BuildAndBook ******/
1009  /// \endcond
1010 
1011  // Type was specified by the user, no need to infer it
1012  template <typename ActionType, typename... BranchTypes, typename ActionResultType,
1013  typename std::enable_if<!TDFInternal::TNeedJitting<BranchTypes...>::value, int>::type = 0>
1014  TResultProxy<ActionResultType> CreateAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &r)
1015  {
1016  auto df = GetDataFrameChecked();
1017  unsigned int nSlots = df->GetNSlots();
1018  BuildAndBook<BranchTypes...>(bl, r, nSlots, (ActionType *)nullptr);
1019  fProxiedPtr->IncrChildrenCount();
1020  return MakeResultProxy(r, df);
1021  }
1022 
1023  // User did not specify type, do type inference
1024  template <typename ActionType, typename... BranchTypes, typename ActionResultType,
1025  typename std::enable_if<TDFInternal::TNeedJitting<BranchTypes...>::value, int>::type = 0>
1026  TResultProxy<ActionResultType> CreateAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &r)
1027  {
1028  auto df = GetDataFrameChecked();
1029  unsigned int nSlots = df->GetNSlots();
1030  const auto &tmpBranches = df->GetBookedBranches();
1031  auto tree = df->GetTree();
1032  TDFInternal::JitBuildAndBook(bl, GetNodeTypeName(), this, typeid(std::shared_ptr<ActionResultType>),
1033  typeid(ActionType), &r, tree, nSlots, tmpBranches);
1034  fProxiedPtr->IncrChildrenCount();
1035  return MakeResultProxy(r, df);
1036  }
1037 
1038 protected:
1039  /// Get the TLoopManager if reachable. If not, throw.
1040  std::shared_ptr<TLoopManager> GetDataFrameChecked()
1041  {
1042  auto df = fImplWeakPtr.lock();
1043  if (!df) {
1044  throw std::runtime_error("The main TDataFrame is not reachable: did it go out of scope?");
1045  }
1046  return df;
1047  }
1048 
1049  const ColumnNames_t GetDefaultBranchNames(unsigned int nExpectedBranches, std::string_view actionNameForErr)
1050  {
1051  auto df = GetDataFrameChecked();
1052  const ColumnNames_t &defaultBranches = df->GetDefaultBranches();
1053  const auto dBSize = defaultBranches.size();
1054  if (nExpectedBranches > dBSize) {
1055  std::string msg("Trying to deduce the branches from the default list in order to ");
1056  msg += actionNameForErr;
1057  msg += ". A set of branches of size ";
1058  msg += std::to_string(dBSize);
1059  msg += " was found. ";
1060  msg += std::to_string(nExpectedBranches);
1061  msg += 1 != nExpectedBranches ? " are" : " is";
1062  msg += " needed. Please specify the branches explicitly.";
1063  throw std::runtime_error(msg);
1064  }
1065  auto bnBegin = defaultBranches.begin();
1066  return ColumnNames_t(bnBegin, bnBegin + nExpectedBranches);
1067  }
1068 
1069  ////////////////////////////////////////////////////////////////////////////
1070  /// \brief Implementation of snapshot
1071  /// \param[in] treename The name of the TTree
1072  /// \param[in] filename The name of the TFile
1073  /// \param[in] bnames The list of names of the branches to be written
1074  /// The implementation exploits Foreach. The association of the addresses to
1075  /// the branches takes place at the first event. This is possible because
1076  /// since there are no copies, the address of the value passed by reference
1077  /// is the address pointing to the storage of the read/created object in/by
1078  /// the TTreeReaderValue/TemporaryBranch
1079  template <typename... Args, int... S>
1080  TInterface<TLoopManager> SnapshotImpl(std::string_view treename, std::string_view filename,
1081  const ColumnNames_t &bnames, TDFInternal::TStaticSeq<S...> /*dummy*/)
1082  {
1083  std::string treenameInt;
1084  std::string dirnameInt;
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::unique_ptr<TFile> ofile(TFile::Open(filenameInt.c_str(), "RECREATE"));
1114  std::tie(dirnameInt, treenameInt) = getDirTreeName(treename);
1115  if (!dirnameInt.empty()) {
1116  ofile->mkdir(dirnameInt.c_str());
1117  ofile->cd(dirnameInt.c_str());
1118  }
1119  TTree t(treenameInt.c_str(), treenameInt.c_str());
1120 
1121  bool FirstEvent = true;
1122  // TODO move fillTree and initLambda to SnapshotHelper's body
1123  auto fillTree = [&t, &bnames, &FirstEvent](unsigned int /* unused */, Args &... args) {
1124  if (FirstEvent) {
1125  // hack to call TTree::Branch on all variadic template arguments
1126  std::initializer_list<int> expander = {(t.Branch(bnames[S].c_str(), &args), 0)..., 0};
1127  (void)expander; // avoid unused variable warnings for older compilers such as gcc 4.9
1128  FirstEvent = false;
1129  }
1130  t.Fill();
1131  };
1132 
1133  auto initLambda = [&t] (TTreeReader *r, unsigned int /* unused */) {
1134  if(r) {
1135  // not an empty-source TDF
1136  auto tree = r->GetTree();
1137  tree->AddClone(&t);
1138  }
1139  };
1140 
1141  using Op_t = TDFInternal::SnapshotHelper<decltype(initLambda), decltype(fillTree)>;
1143  df->Book(std::make_shared<DFA_t>(Op_t(std::move(initLambda), std::move(fillTree)), bnames, *fProxiedPtr));
1144  fProxiedPtr->IncrChildrenCount();
1145  df->Run();
1146  t.Write();
1147  } else {
1148  unsigned int nSlots = df->GetNSlots();
1149  TBufferMerger merger(filenameInt.c_str(), "RECREATE");
1150  std::vector<std::shared_ptr<TBufferMergerFile>> files(nSlots);
1151  std::vector<TTree *> trees(nSlots, nullptr); // ROOT owns/manages these TTrees
1152  std::vector<int> isFirstEvent(nSlots, 1); // vector<bool> is evil
1153 
1154  auto fillTree = [&](unsigned int slot, Args &... args) {
1155  if (isFirstEvent[slot]) {
1156  // hack to call TTree::Branch on all variadic template arguments
1157  std::initializer_list<int> expander = {(trees[slot]->Branch(bnames[S].c_str(), &args), 0)..., 0};
1158  (void)expander; // avoid unused variable warnings for older compilers such as gcc 4.9
1159  isFirstEvent[slot] = 0;
1160  }
1161  trees[slot]->Fill();
1162  auto entries = trees[slot]->GetEntries();
1163  auto autoflush = trees[slot]->GetAutoFlush();
1164  if ((autoflush > 0) && (entries % autoflush == 0)) files[slot]->Write();
1165  };
1166 
1167  // called at the beginning of each task
1168  auto initLambda = [&trees, &merger, &files, &treenameInt, &dirnameInt, &treename, &isFirstEvent, &getDirTreeName] (TTreeReader *r, unsigned int slot) {
1170  if(!trees[slot]) {
1171  // first time this thread executes something, let's create a TBufferMerger output directory
1172  files[slot] = merger.GetFile();
1173  } else {
1174  files[slot]->Write();
1175  }
1176  std::tie(dirnameInt, treenameInt) = getDirTreeName(treename);
1177  if (!dirnameInt.empty()) {
1178  files[slot]->mkdir(dirnameInt.c_str());
1179  files[slot]->cd(dirnameInt.c_str());
1180  }
1181  trees[slot] = new TTree(treenameInt.c_str(), treenameInt.c_str());
1182  trees[slot]->ResetBit(kMustCleanup);
1183  if(r) {
1184  // not an empty-source TDF
1185  auto tree = r->GetTree();
1186  tree->AddClone(trees[slot]);
1187  }
1188  isFirstEvent[slot] = 1;
1189  };
1190 
1191  using Op_t = TDFInternal::SnapshotHelper<decltype(initLambda), decltype(fillTree)>;
1193  df->Book(std::make_shared<DFA_t>(Op_t(std::move(initLambda), std::move(fillTree)), bnames, *fProxiedPtr));
1194  fProxiedPtr->IncrChildrenCount();
1195  df->Run();
1196  for (auto &&file : files) {
1197  if (file) file->Write();
1198  }
1199  }
1200 
1202  std::string fullTreeNameInt(treename);
1203  // Now we mimic a constructor for the TDataFrame. We cannot invoke it here
1204  // since this would introduce a cyclic headers dependency.
1205  TInterface<TLoopManager> snapshotTDF(std::make_shared<TLoopManager>(nullptr, bnames));
1206  auto chain = new TChain(fullTreeNameInt.c_str());
1207  chain->Add(filenameInt.c_str());
1208  snapshotTDF.fProxiedPtr->SetTree(std::shared_ptr<TTree>(static_cast<TTree *>(chain)));
1209 
1210  return snapshotTDF;
1211  }
1212 
1213  TInterface(const std::shared_ptr<Proxied> &proxied, const std::weak_ptr<TLoopManager> &impl)
1214  : fProxiedPtr(proxied), fImplWeakPtr(impl)
1215  {
1216  }
1217 
1218  /// Only enabled when building a TInterface<TLoopManager>
1219  template <typename T = Proxied, typename std::enable_if<std::is_same<T, TLoopManager>::value, int>::type = 0>
1220  TInterface(const std::shared_ptr<Proxied> &proxied) : fProxiedPtr(proxied), fImplWeakPtr(proxied->GetSharedPtr())
1221  {
1222  }
1223 
1224  std::shared_ptr<Proxied> fProxiedPtr;
1225  std::weak_ptr<TLoopManager> fImplWeakPtr;
1226 };
1227 
1228 template <>
1230 {
1231  return "ROOT::Experimental::TDF::TInterface<ROOT::Detail::TDF::TFilterBase>";
1232 }
1233 
1234 template <>
1236 {
1237  return "ROOT::Experimental::TDF::TInterface<ROOT::Detail::TDF::TCustomColumnBase>";
1238 }
1239 
1240 template <>
1242 {
1243  return "ROOT::Experimental::TDF::TInterface<ROOT::Detail::TDF::TLoopManager>";
1244 }
1245 
1246 template <>
1248 {
1249  return "ROOT::Experimental::TDF::TInterface<ROOT::Detail::TDF::TRangeBase>";
1250 }
1251 
1252 } // end NS TDF
1253 } // end NS Experimental
1254 } // end NS ROOT
1255 
1256 #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:42
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
TTree * GetTree() const
Definition: TTreeReader.h:151
TH1 * h
Definition: legend2.C:5
TInterface< TCustomColumnBase > Define(std::string_view name, std::string_view expression)
Creates a temporary branch.
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
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.
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.}, std::string_view vName="")
Fill and return a one-dimensional histogram with the values of a branch (lazy action) ...
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
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)
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:240
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
TResultProxy<::TH1F > Histo1D(::TH1F &&model=::TH1F{"","", 128u, 0., 0.})
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
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)
char name[80]
Definition: TGX11.cxx:109
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)