Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
InterfaceUtils.hxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, Danilo Piparo CERN 02/2018
2
3/*************************************************************************
4 * Copyright (C) 1995-2018, 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_RDF_TINTERFACE_UTILS
12#define ROOT_RDF_TINTERFACE_UTILS
13
14#include <ROOT/RDF/RAction.hxx>
16#include <ROOT/RDF/ActionHelpers.hxx> // for BuildAction
21#include <ROOT/RDF/RDefine.hxx>
23#include <ROOT/RDF/RFilter.hxx>
24#include <ROOT/RDF/Utils.hxx>
30#include <string_view>
32#include <ROOT/TypeTraits.hxx>
33#include <RConfigure.h> // for R__HAS_ROOT7
34#include <TError.h> // gErrorIgnoreLevel
35#include <TH1.h>
36#include <TROOT.h> // IsImplicitMTEnabled
37
38#include <deque>
39#include <functional>
40#include <list>
41#include <memory>
42#include <string>
43#include <type_traits>
44#include <typeinfo>
45#include <vector>
46
47class TTree;
48namespace ROOT {
49namespace Detail {
50namespace RDF {
51class RNodeBase;
52}
53}
54namespace RDF {
55template <typename Proxied>
56class RInterface;
58} // namespace RDF
59
60} // namespace ROOT
61
62/// \cond HIDDEN_SYMBOLS
63
64namespace ROOT {
65namespace Internal {
66namespace RDF {
67using namespace ROOT::Detail::RDF;
68using namespace ROOT::RDF;
69namespace TTraits = ROOT::TypeTraits;
70
71std::string DemangleTypeIdName(const std::type_info &typeInfo);
72
73ColumnNames_t
74ConvertRegexToColumns(const ColumnNames_t &colNames, std::string_view columnNameRegexp, std::string_view callerName);
75
76/// An helper object that sets and resets gErrorIgnoreLevel via RAII.
77class RIgnoreErrorLevelRAII {
78private:
79 int fCurIgnoreErrorLevel = gErrorIgnoreLevel;
80
81public:
82 RIgnoreErrorLevelRAII(int errorIgnoreLevel) { gErrorIgnoreLevel = errorIgnoreLevel; }
83 ~RIgnoreErrorLevelRAII() { gErrorIgnoreLevel = fCurIgnoreErrorLevel; }
84};
85
86/****** BuildAction overloads *******/
87
88// clang-format off
89/// This namespace defines types to be used for tag dispatching in RInterface.
90namespace ActionTags {
91struct Histo1D{};
92struct Histo2D{};
93struct Histo3D{};
94struct HistoND{};
95struct HistoNSparseD{};
96struct Hist{};
97struct HistWithWeight{};
98struct Graph{};
99struct GraphAsymmErrors{};
100struct Profile1D{};
101struct Profile2D{};
102struct Min{};
103struct Max{};
104struct Sum{};
105struct Mean{};
106struct Fill{};
107struct StdDev{};
108struct Median{};
109struct Display{};
110struct Snapshot{};
111struct Book{};
112}
113// clang-format on
114
115template <typename T, bool ISV6HISTO = std::is_base_of<TH1, std::decay_t<T>>::value>
116struct HistoUtils {
117 static bool HasAxisLimits(T &h)
118 {
119 auto xaxis = h.GetXaxis();
120 return !(xaxis->GetXmin() == 0. && xaxis->GetXmax() == 0.);
121 }
122};
123
124template <typename T>
125struct HistoUtils<T, false> {
126 static bool HasAxisLimits(T &) { return true; }
127};
128
129// Generic filling (covers Histo2D, HistoND, HistoNSparseD, Profile1D and Profile2D actions, with and without weights)
130template <typename... ColTypes, typename ActionTag, typename ActionResultType, typename PrevNodeType>
131std::unique_ptr<RActionBase>
132BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h, const unsigned int nSlots,
133 std::shared_ptr<PrevNodeType> prevNode, ActionTag, const RColumnRegister &colRegister)
134{
135 using Helper_t = FillHelper<ActionResultType>;
136 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
137 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
138}
139
140// Histo1D filling (must handle the special case of distinguishing FillHelper and BufferedFillHelper
141template <typename... ColTypes, typename PrevNodeType>
142std::unique_ptr<RActionBase>
143BuildAction(const ColumnNames_t &bl, const std::shared_ptr<::TH1D> &h, const unsigned int nSlots,
144 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Histo1D, const RColumnRegister &colRegister)
145{
146 auto hasAxisLimits = HistoUtils<::TH1D>::HasAxisLimits(*h);
147
148 if (hasAxisLimits || !IsImplicitMTEnabled()) {
149 using Helper_t = FillHelper<::TH1D>;
150 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
151 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
152 } else {
153 using Helper_t = BufferedFillHelper;
154 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
155 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
156 }
157}
158
159// Action for Histo3D, where thread safe filling might be supported to save memory
160template <typename... ColTypes, typename ActionResultType, typename PrevNodeType>
161std::unique_ptr<RActionBase>
162BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h, const unsigned int nSlots,
163 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Histo3D, const RColumnRegister &colRegister)
164{
165 if (RDFInternal::NThreadPerTH3() <= 1 || nSlots == 1) {
166 using Helper_t = FillHelper<ActionResultType>;
167 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
168 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
169 } else {
170 using Helper_t = ThreadSafeFillHelper<ActionResultType>;
171 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
172 if constexpr (sizeof...(ColTypes) > 3) {
173 h->Sumw2();
174 }
175 const auto histoSlots = std::max(nSlots / RDFInternal::NThreadPerTH3(), 1u);
176 return std::make_unique<Action_t>(Helper_t(h, histoSlots), bl, std::move(prevNode), colRegister);
177 }
178}
179
180#ifdef R__HAS_ROOT7
181// Action for RHist using RHistConcurrentFiller without weights
182template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
183std::unique_ptr<RActionBase>
184BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHist<BinContentType>> &h,
185 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode, ActionTags::Hist,
186 const RColumnRegister &colRegister)
187{
188 using Helper_t = RHistFillHelper<BinContentType>;
189 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
190 return std::make_unique<Action_t>(Helper_t(h, nSlots), columnList, std::move(prevNode), colRegister);
191}
192
193// Action for RHist using RHistConcurrentFiller with weights
194template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
195std::unique_ptr<RActionBase>
196BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHist<BinContentType>> &h,
197 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode, ActionTags::HistWithWeight,
198 const RColumnRegister &colRegister)
199{
200 using Helper_t = RHistFillHelper<BinContentType, true>;
201 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
202 return std::make_unique<Action_t>(Helper_t(h, nSlots), columnList, std::move(prevNode), colRegister);
203}
204
205// Action for RHistEngine using FillAtomic without weights
206template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
207std::unique_ptr<RActionBase>
208BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHistEngine<BinContentType>> &h,
209 const unsigned int, std::shared_ptr<PrevNodeType> prevNode, ActionTags::Hist,
210 const RColumnRegister &colRegister)
211{
212 using Helper_t = RHistEngineFillHelper<BinContentType>;
213 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
214 return std::make_unique<Action_t>(Helper_t(h), columnList, std::move(prevNode), colRegister);
215}
216
217// Action for RHistEngine using FillAtomic with weights
218template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
219std::unique_ptr<RActionBase>
220BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHistEngine<BinContentType>> &h,
221 const unsigned int, std::shared_ptr<PrevNodeType> prevNode, ActionTags::HistWithWeight,
222 const RColumnRegister &colRegister)
223{
224 using Helper_t = RHistEngineFillHelper<BinContentType, true>;
225 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
226 return std::make_unique<Action_t>(Helper_t(h), columnList, std::move(prevNode), colRegister);
227}
228#endif
229
230template <typename... ColTypes, typename PrevNodeType>
231std::unique_ptr<RActionBase>
232BuildAction(const ColumnNames_t &bl, const std::shared_ptr<TGraph> &g, const unsigned int nSlots,
233 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Graph, const RColumnRegister &colRegister)
234{
235 using Helper_t = FillTGraphHelper;
236 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
237 return std::make_unique<Action_t>(Helper_t(g, nSlots), bl, std::move(prevNode), colRegister);
238}
239
240template <typename... ColTypes, typename PrevNodeType>
241std::unique_ptr<RActionBase>
242BuildAction(const ColumnNames_t &bl, const std::shared_ptr<TGraphAsymmErrors> &g, const unsigned int nSlots,
243 std::shared_ptr<PrevNodeType> prevNode, ActionTags::GraphAsymmErrors, const RColumnRegister &colRegister)
244{
245 using Helper_t = FillTGraphAsymmErrorsHelper;
246 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
247 return std::make_unique<Action_t>(Helper_t(g, nSlots), bl, std::move(prevNode), colRegister);
248}
249
250// Min action
251template <typename ColType, typename PrevNodeType, typename ActionResultType>
252std::unique_ptr<RActionBase>
253BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &minV, const unsigned int nSlots,
254 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Min, const RColumnRegister &colRegister)
255{
256 using Helper_t = MinHelper<ActionResultType>;
257 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
258 return std::make_unique<Action_t>(Helper_t(minV, nSlots), bl, std::move(prevNode), colRegister);
259}
260
261// Max action
262template <typename ColType, typename PrevNodeType, typename ActionResultType>
263std::unique_ptr<RActionBase>
264BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &maxV, const unsigned int nSlots,
265 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Max, const RColumnRegister &colRegister)
266{
267 using Helper_t = MaxHelper<ActionResultType>;
268 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
269 return std::make_unique<Action_t>(Helper_t(maxV, nSlots), bl, std::move(prevNode), colRegister);
270}
271
272// Sum action
273template <typename ColType, typename PrevNodeType, typename ActionResultType>
274std::unique_ptr<RActionBase>
275BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &sumV, const unsigned int nSlots,
276 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Sum, const RColumnRegister &colRegister)
277{
278 using Helper_t = SumHelper<ActionResultType>;
279 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
280 return std::make_unique<Action_t>(Helper_t(sumV, nSlots), bl, std::move(prevNode), colRegister);
281}
282
283// Mean action
284template <typename ColType, typename PrevNodeType>
285std::unique_ptr<RActionBase>
286BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &meanV, const unsigned int nSlots,
287 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Mean, const RColumnRegister &colRegister)
288{
289 using Helper_t = MeanHelper;
290 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
291 return std::make_unique<Action_t>(Helper_t(meanV, nSlots), bl, std::move(prevNode), colRegister);
292}
293
294// Standard Deviation action
295template <typename ColType, typename PrevNodeType>
296std::unique_ptr<RActionBase>
297BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &stdDeviationV, const unsigned int nSlots,
298 std::shared_ptr<PrevNodeType> prevNode, ActionTags::StdDev, const RColumnRegister &colRegister)
299{
300 using Helper_t = StdDevHelper;
301 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
302 return std::make_unique<Action_t>(Helper_t(stdDeviationV, nSlots), bl, prevNode, colRegister);
303}
304
305// Median action
306template <typename ColType, typename PrevNodeType>
307std::unique_ptr<RActionBase>
308BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &meanV, const unsigned int nSlots,
309 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Median, const RColumnRegister &colRegister)
310{
311 using Helper_t = MedianHelper;
312 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
313 return std::make_unique<Action_t>(Helper_t(meanV, nSlots), bl, std::move(prevNode), colRegister);
314}
315
316using displayHelperArgs_t = std::pair<size_t, std::shared_ptr<ROOT::RDF::RDisplay>>;
317
318// Display action
319template <typename... ColTypes, typename PrevNodeType>
320std::unique_ptr<RActionBase>
321BuildAction(const ColumnNames_t &bl, const std::shared_ptr<displayHelperArgs_t> &helperArgs, const unsigned int,
322 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Display, const RColumnRegister &colRegister)
323{
324 using Helper_t = DisplayHelper<PrevNodeType>;
325 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
326 return std::make_unique<Action_t>(Helper_t(helperArgs->first, helperArgs->second, prevNode), bl, prevNode,
327 colRegister);
328}
329
330struct SnapshotHelperArgs {
331 std::string fFileName;
332 std::string fDirName;
333 std::string fTreeName;
334 std::vector<std::string> fOutputColNames;
336 ROOT::Detail::RDF::RLoopManager *fOutputLoopManager;
337 ROOT::Detail::RDF::RLoopManager *fInputLoopManager;
338 bool fToNTuple;
339 bool fIncludeVariations;
340};
341
342template <typename PrevNodeType>
343std::unique_ptr<RActionBase>
344BuildAction(const ColumnNames_t &colNames, const std::shared_ptr<SnapshotHelperArgs> &snapHelperArgs,
345 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode, const RColumnRegister &colRegister,
346 const std::vector<const std::type_info *> &colTypeIDs)
347{
348 const auto &filename = snapHelperArgs->fFileName;
349 const auto &dirname = snapHelperArgs->fDirName;
350 const auto &treename = snapHelperArgs->fTreeName;
351 const auto &outputColNames = snapHelperArgs->fOutputColNames;
352 const auto &options = snapHelperArgs->fOptions;
353 const auto &outputLM = snapHelperArgs->fOutputLoopManager;
354 const auto &inputLM = snapHelperArgs->fInputLoopManager;
355
356 auto sz = colNames.size();
357 std::vector<bool> isDefine(sz);
358 for (auto i = 0u; i < sz; ++i)
359 isDefine[i] = colRegister.IsDefineOrAlias(colNames[i]);
360
361 std::unique_ptr<RActionBase> actionPtr;
362 if (snapHelperArgs->fToNTuple) {
363 // We use the same helper for single- and multi-thread snapshot.
364 using Helper_t = UntypedSnapshotRNTupleHelper;
365 using Action_t = RActionSnapshot<Helper_t, PrevNodeType>;
366
367 actionPtr.reset(new Action_t(Helper_t(nSlots, filename, dirname, treename, colNames, outputColNames, options,
368 inputLM, outputLM, colTypeIDs),
369 colNames, colTypeIDs, prevNode, colRegister));
370 } else {
372 // single-thread snapshot
373 if (snapHelperArgs->fIncludeVariations) {
374 using Helper_t = SnapshotHelperWithVariations;
375 using Action_t = RActionSnapshot<Helper_t, PrevNodeType>;
376 actionPtr.reset(new Action_t(Helper_t(filename, dirname, treename, colNames, outputColNames, options,
377 std::move(isDefine), outputLM, inputLM, colTypeIDs),
378 colNames, colTypeIDs, prevNode, colRegister));
379 } else {
380 using Helper_t = UntypedSnapshotTTreeHelper;
381 using Action_t = RActionSnapshot<Helper_t, PrevNodeType>;
382 actionPtr.reset(new Action_t(Helper_t(filename, dirname, treename, colNames, outputColNames, options,
383 std::move(isDefine), outputLM, inputLM, colTypeIDs),
384 colNames, colTypeIDs, prevNode, colRegister));
385 }
386 } else {
387 if (snapHelperArgs->fIncludeVariations) {
388 throw std::invalid_argument("Multi-threaded snapshot with variations is not supported yet.");
389 }
390 // multi-thread snapshot
391 using Helper_t = UntypedSnapshotTTreeHelperMT;
392 using Action_t = RActionSnapshot<Helper_t, PrevNodeType>;
393 actionPtr.reset(new Action_t(Helper_t(nSlots, filename, dirname, treename, colNames, outputColNames, options,
394 std::move(isDefine), outputLM, inputLM, colTypeIDs),
395 colNames, colTypeIDs, prevNode, colRegister));
396 }
397 }
398
399 return actionPtr;
400}
401
402template <typename PrevNodeType>
403std::unique_ptr<RActionBase>
404BuildAction(const ColumnNames_t &colNames, const std::vector<const std::type_info *> &colTypeIDs,
405 const std::shared_ptr<ROOT::RVecF> &location, const std::vector<std::size_t> &vecSizes, float vecPadding,
406 std::shared_ptr<PrevNodeType> prevNode, const RColumnRegister &colRegister)
407{
410 return std::make_unique<Action_t>(Helper_t(location, colTypeIDs, vecSizes, vecPadding), colNames, colTypeIDs,
411 prevNode, colRegister);
412}
413
414// Book with custom helper type
415template <typename... ColTypes, typename PrevNodeType, typename Helper_t>
416std::unique_ptr<RActionBase>
417BuildAction(const ColumnNames_t &bl, const std::shared_ptr<Helper_t> &h, const unsigned int /*nSlots*/,
418 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Book, const RColumnRegister &colRegister)
419{
420 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
421 return std::make_unique<Action_t>(Helper_t(std::move(*h)), bl, std::move(prevNode), colRegister);
422}
423
424/****** end BuildAndBook ******/
425
426template <typename Filter>
427void CheckFilter(Filter &)
428{
429 using FilterRet_t = typename RDF::CallableTraits<Filter>::ret_type;
430 static_assert(std::is_convertible<FilterRet_t, bool>::value,
431 "filter expression returns a type that is not convertible to bool");
432}
433
434ColumnNames_t FilterArraySizeColNames(const ColumnNames_t &columnNames, const std::string &action);
435
436void CheckValidCppVarName(std::string_view var, const std::string &where);
437
438void CheckForRedefinition(const std::string &where, std::string_view definedCol, const RColumnRegister &colRegister,
439 const ColumnNames_t &dataSourceColumns);
440
441void CheckForDefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister,
442 const ColumnNames_t &dataSourceColumns);
443
444void CheckForNoVariations(const std::string &where, std::string_view definedColView,
445 const RColumnRegister &colRegister);
446
447std::string PrettyPrintAddr(const void *const addr);
448
449std::shared_ptr<RJittedFilter> BookFilterJit(std::shared_ptr<RNodeBase> prevNode, std::string_view name,
450 std::string_view expression, const RColumnRegister &colRegister,
451 TTree *tree, RDataSource *ds);
452
453std::shared_ptr<RJittedDefine> BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm,
454 RDataSource *ds, const RColumnRegister &colRegister);
455
456std::shared_ptr<RJittedDefine> BookDefinePerSampleJit(std::string_view name, std::string_view expression,
457 RLoopManager &lm, const RColumnRegister &colRegister);
458
459std::shared_ptr<RJittedVariation>
460BookVariationJit(const std::vector<std::string> &colNames, std::string_view variationName,
461 const std::vector<std::string> &variationTags, std::string_view expression, RLoopManager &lm,
462 RDataSource *ds, const RColumnRegister &colRegister, bool isSingleColumn,
463 const std::string &varyColType);
464
465std::string JitBuildAction(const ColumnNames_t &bl, const std::type_info &art, const std::type_info &at, TTree *tree,
466 const unsigned int nSlots, const RColumnRegister &colRegister, RDataSource *ds,
467 const bool vector2RVec = true);
468
469bool AtLeastOneEmptyString(const std::vector<std::string_view> strings);
470
471/// Take a shared_ptr<AnyNodeType> and return a shared_ptr<RNodeBase>.
472/// This works for RLoopManager nodes as well as filters and ranges.
473std::shared_ptr<RNodeBase> UpcastNode(std::shared_ptr<RNodeBase> ptr);
474
475ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns,
476 const RColumnRegister &validDefines, RDataSource *ds);
477
478std::vector<std::string> GetValidatedArgTypes(const ColumnNames_t &colNames, const RColumnRegister &colRegister,
479 TTree *tree, RDataSource *ds, const std::string &context,
480 bool vector2RVec);
481
482template <typename T>
483void AddDSColumnsHelper(const std::string &colName, RLoopManager &lm, RDataSource &ds, RColumnRegister &colRegister)
484{
485
486 if (colRegister.IsDefineOrAlias(colName))
487 return;
488
489 if (lm.HasDataSourceColumnReaders(colName, typeid(T)))
490 return;
491
492 if (!ds.HasColumn(colName) &&
494 return;
495
496 const auto nSlots = lm.GetNSlots();
497 std::vector<std::unique_ptr<RColumnReaderBase>> colReaders;
498 colReaders.reserve(nSlots);
499
500 const auto valuePtrs = ds.GetColumnReaders<T>(colName);
501 if (!valuePtrs.empty()) { // we are using the old GetColumnReaders mechanism in this RDataSource
502 for (auto *ptr : valuePtrs)
503 colReaders.emplace_back(new RDSColumnReader<T>(ptr));
504
505 } else { // using the new GetColumnReaders mechanism
506 // TODO consider changing the interface so we return all of these for all slots in one go
507 for (auto slot = 0u; slot < lm.GetNSlots(); ++slot)
508 colReaders.emplace_back(
509 ROOT::Internal::RDF::CreateColumnReader(ds, slot, colName, typeid(T), /*treeReader*/ nullptr));
510 }
511
512 lm.AddDataSourceColumnReaders(colName, std::move(colReaders), typeid(T));
513}
514
515/// Take list of column names that must be defined, current map of custom columns, current list of defined column names,
516/// and return a new map of custom columns (with the new datasource columns added to it)
517template <typename... ColumnTypes>
518void AddDSColumns(const std::vector<std::string> &requiredCols, RLoopManager &lm, RDataSource &ds,
519 TTraits::TypeList<ColumnTypes...>, RColumnRegister &colRegister)
520{
521 // hack to expand a template parameter pack without c++17 fold expressions.
522 using expander = int[];
523 int i = 0;
524 (void)expander{(AddDSColumnsHelper<ColumnTypes>(requiredCols[i], lm, ds, colRegister), ++i)..., 0};
525}
526
527void AddDSColumns(const std::vector<std::string> &requiredCols, ROOT::Detail::RDF::RLoopManager &lm,
528 ROOT::RDF::RDataSource &ds, const std::vector<const std::type_info *> &colTypeIDs,
530
531// this function is meant to be called by the jitted code generated by BookFilterJit
532template <typename F>
533void JitFilterHelper(F &&f, const ColumnNames_t &cols, RColumnRegister &colRegister,
535{
536 if (!jittedFilter) {
537 // The branch of the computation graph that needed this jitted code went out of scope between the type
538 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
539 return;
540 }
541
542 // mock Filter logic -- validity checks and Define-ition of RDataSource columns
543 using Callable_t = std::decay_t<F>;
544 auto prevNode = jittedFilter->MoveOutPrevNode();
545 using PrevNode_t = typename decltype(prevNode)::element_type;
547 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
548 constexpr auto nColumns = ColTypes_t::list_size;
549 CheckFilter(f);
550
551 auto ds = lm.GetDataSource();
552
553 if (ds != nullptr && !cols.empty())
554 AddDSColumns(cols, lm, *ds, ColTypes_t(), colRegister);
555
556 jittedFilter->SetFilter(
557 std::unique_ptr<RFilterBase>(new F_t(std::forward<F>(f), cols, prevNode, colRegister, jittedFilter->GetName())));
558}
559
560namespace DefineTypes {
561struct RDefineTag {};
562struct RDefinePerSampleTag {};
563}
564
565template <typename F>
566auto MakeDefineNode(DefineTypes::RDefineTag, std::string_view name, std::string_view dummyType, F &&f,
567 const ColumnNames_t &cols, RColumnRegister &colRegister, RLoopManager &lm)
568{
569 return std::unique_ptr<RDefineBase>(new RDefine<std::decay_t<F>, ExtraArgsForDefine::None>(
570 name, dummyType, std::forward<F>(f), cols, colRegister, lm));
571}
572
573template <typename F>
574auto MakeDefineNode(DefineTypes::RDefinePerSampleTag, std::string_view name, std::string_view dummyType, F &&f,
575 const ColumnNames_t &, RColumnRegister &, RLoopManager &lm)
576{
577 return std::unique_ptr<RDefineBase>(
578 new RDefinePerSample<std::decay_t<F>>(name, dummyType, std::forward<F>(f), lm));
579}
580
581// Build a RDefine or a RDefinePerSample object and attach it to an existing RJittedDefine
582// This function is meant to be called by jitted code right before starting the event loop.
583// If colsPtr is null, build a RDefinePerSample (it has no input columns), otherwise a RDefine.
584template <typename RDefineTypeTag, typename F>
585void JitDefineHelper(F &&f, const ColumnNames_t &cols, RColumnRegister &colRegister,
587{
588
589 if (!jittedDefine) {
590 // The branch of the computation graph that needed this jitted code went out of scope between the type
591 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
592 return;
593 }
594
595 using Callable_t = std::decay_t<F>;
596 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
597
598 auto ds = lm.GetDataSource();
599 if (ds != nullptr && !cols.empty())
600 AddDSColumns(cols, lm, *ds, ColTypes_t(), colRegister);
601
602 // will never actually be used (trumped by jittedDefine->GetTypeName()), but we set it to something meaningful
603 // to help devs debugging
604 const auto dummyType = "jittedCol_t";
605 // use unique_ptr<RDefineBase> instead of make_unique<NewCol_t> to reduce jit/compile-times
606 std::unique_ptr<RDefineBase> newCol{
607 MakeDefineNode(RDefineTypeTag{}, jittedDefine->GetName(), dummyType, std::forward<F>(f), cols, colRegister, lm)};
608 jittedDefine->SetDefine(std::move(newCol));
609}
610
611template <bool IsSingleColumn, typename F>
612void JitVariationHelper(F &&f, const ColumnNames_t &inputColNames, RColumnRegister &colRegister,
613 ROOT::Detail::RDF::RLoopManager &lm, RJittedVariation *jittedVariation,
614 const ColumnNames_t &variedColNames, const ColumnNames_t &variationTags) noexcept
615{
616
617 if (!jittedVariation) {
618 // The branch of the computation graph that needed this jitted variation went out of scope between the type
619 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
620 return;
621 }
622
623 using Callable_t = std::decay_t<F>;
624 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
625
626 auto ds = lm.GetDataSource();
627 if (ds != nullptr && !inputColNames.empty())
628 AddDSColumns(inputColNames, lm, *ds, ColTypes_t(), colRegister);
629
630 // use unique_ptr<RDefineBase> instead of make_unique<NewCol_t> to reduce jit/compile-times
631 std::unique_ptr<RVariationBase> newVariation{new RVariation<std::decay_t<F>, IsSingleColumn>(
632 variedColNames, jittedVariation->GetVariationName(), std::forward<F>(f), variationTags,
633 jittedVariation->GetTypeName(), colRegister, lm, inputColNames)};
634 jittedVariation->SetVariation(std::move(newVariation));
635}
636
637/// Convenience function invoked by jitted code to build action nodes at runtime
638template <typename ActionTag, typename... ColTypes, typename HelperArgType>
639void CallBuildAction(const ColumnNames_t &cols, RColumnRegister &colRegister, ROOT::Detail::RDF::RLoopManager &lm,
640 RJittedAction *jittedAction, unsigned int nSlots,
641 std::shared_ptr<HelperArgType> *helperArg) noexcept
642{
643 if (!jittedAction) {
644 // The branch of the computation graph that needed this jitted variation went out of scope between the type
645 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
646 return;
647 }
648
649 using ColTypes_t = TypeList<ColTypes...>;
650 constexpr auto nColumns = ColTypes_t::list_size;
651 auto ds = lm.GetDataSource();
652 if (ds != nullptr && !cols.empty())
653 AddDSColumns(cols, lm, *ds, ColTypes_t(), colRegister);
654
655 auto actionPtr =
656 BuildAction<ColTypes...>(cols, *helperArg, nSlots, jittedAction->MoveOutPrevNode(), ActionTag{}, colRegister);
657 jittedAction->SetAction(std::move(actionPtr));
658}
659
660/// The contained `type` alias is `double` if `T == RInferredType`, `U` if `T == std::container<U>`, `T` otherwise.
661template <typename T, bool Container = IsDataContainer<T>::value && !std::is_same<T, std::string>::value>
662struct RMinReturnType {
663 using type = T;
664};
665
666template <>
667struct RMinReturnType<RInferredType, false> {
668 using type = double;
669};
670
671template <typename T>
672struct RMinReturnType<T, true> {
673 using type = TTraits::TakeFirstParameter_t<T>;
674};
675
676// return wrapper around f that prepends an `unsigned int slot` parameter
677template <typename R, typename F, typename... Args>
678std::function<R(unsigned int, Args...)> AddSlotParameter(F &f, TypeList<Args...>)
679{
680 return [f](unsigned int, Args... a) mutable -> R { return f(a...); };
681}
682
683template <typename ColType, typename... Rest>
684struct RNeedJittingHelper {
685 static constexpr bool value = RNeedJittingHelper<Rest...>::value;
686};
687
688template <typename... Rest>
689struct RNeedJittingHelper<RInferredType, Rest...> {
690 static constexpr bool value = true;
691};
692
693template <typename T>
694struct RNeedJittingHelper<T> {
695 static constexpr bool value = false;
696};
697
698template <>
699struct RNeedJittingHelper<RInferredType> {
700 static constexpr bool value = true;
701};
702
703template <typename ...ColTypes>
704struct RNeedJitting {
705 static constexpr bool value = RNeedJittingHelper<ColTypes...>::value;
706};
707
708template <>
709struct RNeedJitting<> {
710 static constexpr bool value = false;
711};
712
713///////////////////////////////////////////////////////////////////////////////
714/// Check preconditions for RInterface::Aggregate:
715/// - the aggregator callable must have signature `U(U,T)` or `void(U&,T)`.
716/// - the merge callable must have signature `U(U,U)` or `void(std::vector<U>&)`
717template <typename R, typename Merge, typename U, typename T, typename decayedU = std::decay_t<U>,
718 typename mergeArgsNoDecay_t = typename CallableTraits<Merge>::arg_types_nodecay,
719 typename mergeArgs_t = typename CallableTraits<Merge>::arg_types,
720 typename mergeRet_t = typename CallableTraits<Merge>::ret_type>
721void CheckAggregate(TypeList<U, T>)
722{
723 constexpr bool isAggregatorOk =
724 (std::is_same<R, decayedU>::value) || (std::is_same<R, void>::value && std::is_lvalue_reference<U>::value);
725 static_assert(isAggregatorOk, "aggregator function must have signature `U(U,T)` or `void(U&,T)`");
726 constexpr bool isMergeOk =
727 (std::is_same<TypeList<decayedU, decayedU>, mergeArgs_t>::value && std::is_same<decayedU, mergeRet_t>::value) ||
728 (std::is_same<TypeList<std::vector<decayedU> &>, mergeArgsNoDecay_t>::value &&
729 std::is_same<void, mergeRet_t>::value);
730 static_assert(isMergeOk, "merge function must have signature `U(U,U)` or `void(std::vector<U>&)`");
731}
732
733///////////////////////////////////////////////////////////////////////////////
734/// This overload of CheckAggregate is called when the aggregator takes more than two arguments
735template <typename R, typename T>
736void CheckAggregate(T)
737{
738 static_assert(sizeof(T) == 0, "aggregator function must take exactly two arguments");
739}
740
741///////////////////////////////////////////////////////////////////////////////
742/// Check as many template parameters were passed as the number of column names, throw if this is not the case.
743void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames);
744
745/// Return local BranchNames or default BranchNames according to which one should be used
746const ColumnNames_t SelectColumns(unsigned int nArgs, const ColumnNames_t &bl, const ColumnNames_t &defBl);
747
748/// Check whether column names refer to a valid branch of a TTree or have been `Define`d. Return invalid column names.
749ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const RColumnRegister &definedCols,
750 const ColumnNames_t &dataSourceColumns);
751
752/// Returns the list of Filters defined in the whole graph
753std::vector<std::string> GetFilterNames(const std::shared_ptr<RLoopManager> &loopManager);
754
755/// Returns the list of Filters defined in the branch
756template <typename NodeType>
757std::vector<std::string> GetFilterNames(const std::shared_ptr<NodeType> &node)
758{
759 std::vector<std::string> filterNames;
760 node->AddFilterName(filterNames);
761 return filterNames;
762}
763
764struct ParsedTreePath {
765 std::string fTreeName;
766 std::string fDirName;
767};
768
769ParsedTreePath ParseTreePath(std::string_view fullTreeName);
770
771// Check if a condition is true for all types
772template <bool...>
773struct TBoolPack;
774
775template <bool... bs>
776using IsTrueForAllImpl_t = typename std::is_same<TBoolPack<bs..., true>, TBoolPack<true, bs...>>;
777
778template <bool... Conditions>
779struct TEvalAnd {
780 static constexpr bool value = IsTrueForAllImpl_t<Conditions...>::value;
781};
782
783// Check if a class is a specialisation of stl containers templates
784// clang-format off
785
786template <typename>
787struct IsList_t : std::false_type {};
788
789template <typename T>
790struct IsList_t<std::list<T>> : std::true_type {};
791
792template <typename>
793struct IsDeque_t : std::false_type {};
794
795template <typename T>
796struct IsDeque_t<std::deque<T>> : std::true_type {};
797// clang-format on
798
799void CheckForDuplicateSnapshotColumns(const ColumnNames_t &cols);
800
802
803template <typename T>
804struct InnerValueType {
805 using type = T; // fallback for when T is not a nested RVec
806};
807
808template <typename Elem>
809struct InnerValueType<ROOT::VecOps::RVec<ROOT::VecOps::RVec<Elem>>> {
810 using type = Elem;
811};
812
813template <typename T>
814using InnerValueType_t = typename InnerValueType<T>::type;
815
816std::pair<std::vector<std::string>, std::vector<std::string>>
817AddSizeBranches(ROOT::RDF::RDataSource *ds, std::vector<std::string> &&colsWithoutAliases,
818 std::vector<std::string> &&colsWithAliases);
819
820void RemoveDuplicates(ColumnNames_t &columnNames);
821void RemoveRNTupleSubfields(ColumnNames_t &columnNames);
822
823} // namespace RDF
824} // namespace Internal
825
826namespace Detail {
827namespace RDF {
828
829/// The aliased type is `double` if `T == RInferredType`, `U` if `T == container<U>`, `T` otherwise.
830template <typename T>
831using MinReturnType_t = typename RDFInternal::RMinReturnType<T>::type;
832
833template <typename T>
834using MaxReturnType_t = MinReturnType_t<T>;
835
836template <typename T>
837using SumReturnType_t = MinReturnType_t<T>;
838
839} // namespace RDF
840} // namespace Detail
841} // namespace ROOT
842
843/// \endcond
844
845#endif
#define f(i)
Definition RSha256.hxx:104
#define g(i)
Definition RSha256.hxx:105
#define a(i)
Definition RSha256.hxx:99
#define h(i)
Definition RSha256.hxx:106
#define R(a, b, c, d, e, f, g, h, i)
Definition RSha256.hxx:110
Int_t gErrorIgnoreLevel
errors with level below this value will be ignored. Default is kUnset.
Definition TError.cxx:33
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:142
std::string GetName() const
std::string GetName() const
A wrapper around a concrete RDefine, which forwards all calls to it RJittedDefine is a placeholder th...
void SetDefine(std::unique_ptr< RDefineBase > c)
A wrapper around a concrete RFilter, which forwards all calls to it RJittedFilter is the type of the ...
std::shared_ptr< RNodeBase > MoveOutPrevNode()
void SetFilter(std::unique_ptr< RFilterBase > f)
The head node of a RDF computation graph.
const std::set< std::string > & GetSuppressErrorsForMissingBranches() const
void AddDataSourceColumnReaders(std::string_view col, std::vector< std::unique_ptr< RColumnReaderBase > > &&readers, const std::type_info &ti)
RDataSource * GetDataSource() const
bool HasDataSourceColumnReaders(std::string_view col, const std::type_info &ti) const
Return true if AddDataSourceColumnReaders was called for column name col.
A histogram data structure to bin data along multiple dimensions.
A histogram for aggregation of data along multiple dimensions.
Definition RHist.hxx:66
A binder for user-defined columns, variations and aliases.
RDataSource defines an API that RDataFrame can use to read arbitrary data formats.
virtual bool HasColumn(std::string_view colName) const =0
Checks if the dataset has a certain column.
std::vector< T ** > GetColumnReaders(std::string_view columnName)
Called at most once per column by RDF.
The public interface to the RDataFrame federation of classes.
A "std::vector"-like collection of values implementing handy operation to analyse them.
Definition RVec.hxx:1509
A TTree represents a columnar dataset.
Definition TTree.h:95
const ColumnNames_t SelectColumns(unsigned int nRequiredNames, const ColumnNames_t &names, const ColumnNames_t &defaultNames)
Choose between local column names or default column names, throw in case of errors.
void CheckForNoVariations(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister)
Throw if the column has systematic variations attached.
ParsedTreePath ParseTreePath(std::string_view fullTreeName)
std::shared_ptr< RJittedDefine > BookDefinePerSampleJit(std::string_view name, std::string_view expression, RLoopManager &lm, const RColumnRegister &colRegister)
Book the jitting of a DefinePerSample call.
void CheckValidCppVarName(std::string_view var, const std::string &where)
void RemoveDuplicates(ColumnNames_t &columnNames)
ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns, const RColumnRegister &colRegister, RDataSource *ds)
Given the desired number of columns and the user-provided list of columns:
std::shared_ptr< RNodeBase > UpcastNode(std::shared_ptr< RNodeBase > ptr)
void CheckSnapshotOptionsFormatCompatibility(const ROOT::RDF::RSnapshotOptions &opts)
void CheckForDefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister, const ColumnNames_t &dataSourceColumns)
Throw if column definedColView is not already there.
std::vector< std::string > GetFilterNames(const std::shared_ptr< RLoopManager > &loopManager)
std::string PrettyPrintAddr(const void *const addr)
std::shared_ptr< RDFDetail::RJittedFilter > BookFilterJit(std::shared_ptr< RDFDetail::RNodeBase > prevNode, std::string_view name, std::string_view expression, const RColumnRegister &colRegister, TTree *tree, RDataSource *ds)
Book the jitting of a Filter call.
std::string JitBuildAction(const ColumnNames_t &cols, const std::type_info &helperArgType, const std::type_info &at, TTree *tree, const unsigned int nSlots, const RColumnRegister &colRegister, RDataSource *ds, const bool vector2RVec)
void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames)
std::string DemangleTypeIdName(const std::type_info &typeInfo)
bool AtLeastOneEmptyString(const std::vector< std::string_view > strings)
std::unique_ptr< ROOT::Detail::RDF::RColumnReaderBase > CreateColumnReader(ROOT::RDF::RDataSource &ds, unsigned int slot, std::string_view col, const std::type_info &tid, TTreeReader *treeReader)
Definition RDFUtils.cxx:708
std::pair< std::vector< std::string >, std::vector< std::string > > AddSizeBranches(ROOT::RDF::RDataSource *ds, std::vector< std::string > &&colsWithoutAliases, std::vector< std::string > &&colsWithAliases)
Return copies of colsWithoutAliases and colsWithAliases with size branches for variable-sized array b...
void RemoveRNTupleSubfields(ColumnNames_t &columnNames)
ColumnNames_t FilterArraySizeColNames(const ColumnNames_t &columnNames, const std::string &action)
Take a list of column names, return that list with entries starting by '#' filtered out.
std::vector< std::string > GetValidatedArgTypes(const ColumnNames_t &colNames, const RColumnRegister &colRegister, TTree *tree, RDataSource *ds, const std::string &context, bool vector2RVec)
void CheckForDuplicateSnapshotColumns(const ColumnNames_t &cols)
ColumnNames_t ConvertRegexToColumns(const ColumnNames_t &colNames, std::string_view columnNameRegexp, std::string_view callerName)
ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const RColumnRegister &definedCols, const ColumnNames_t &dataSourceColumns)
unsigned int & NThreadPerTH3()
Obtain or set the number of threads that will share a clone of a thread-safe 3D histogram.
Definition RDFUtils.cxx:76
void CheckForRedefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister, const ColumnNames_t &dataSourceColumns)
Throw if column definedColView is already there.
std::shared_ptr< RJittedDefine > BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm, RDataSource *ds, const RColumnRegister &colRegister)
Book the jitting of a Define call.
std::shared_ptr< RJittedVariation > BookVariationJit(const std::vector< std::string > &colNames, std::string_view variationName, const std::vector< std::string > &variationTags, std::string_view expression, RLoopManager &lm, RDataSource *ds, const RColumnRegister &colRegister, bool isSingleColumn, const std::string &varyColType)
Book the jitting of a Vary call.
ROOT type_traits extensions.
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition TROOT.cxx:673
A collection of options to steer the creation of the dataset on disk through Snapshot().
Lightweight storage for a collection of types.