Logo ROOT   6.18/05
Reference Guide
RAction.hxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, Danilo Piparo CERN 09/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_RACTION
12#define ROOT_RACTION
13
16#include "ROOT/RDF/NodesUtils.hxx" // InitRDFValues
17#include "ROOT/RDF/Utils.hxx" // ColumnNames_t
20
21#include <cstddef> // std::size_t
22#include <memory>
23#include <string>
24#include <vector>
25
26namespace ROOT {
27namespace Internal {
28namespace RDF {
29
32
33// fwd declarations for RActionCRTP
34namespace GraphDrawing {
35std::shared_ptr<GraphNode> CreateDefineNode(const std::string &colName, const RDFDetail::RCustomColumnBase *columnPtr);
36bool CheckIfDefaultOrDSColumn(const std::string &name, const std::shared_ptr<RDFDetail::RCustomColumnBase> &column);
37} // ns GraphDrawing
38
39/// Unused, not instantiatable. Only the partial specialization RActionCRTP<RAction<...>> can be used.
40template <typename Dummy>
42 static_assert(sizeof(Dummy) < 0, "The unspecialized version of RActionCRTP should never be instantiated");
43};
44
45/// A type-erasing wrapper around RColumnValue.
46/// Used to reduce compile time by avoiding instantiation of very large tuples and/or (std::get<N>...) fold expressions.
48 std::shared_ptr<void> fPtr; // shared_ptr correctly deletes the type-erased object
49
50public:
51 template <typename T>
52 RTypeErasedColumnValue(std::unique_ptr<RColumnValue<T>> v) : fPtr(std::move(v))
53 {
54 }
55
56 template <typename T>
58 {
59 return std::static_pointer_cast<RColumnValue<T>>(fPtr)->Get(e);
60 }
61
62 template <typename T>
64 {
65 return static_cast<RColumnValue<T> *>(fPtr.get());
66 }
67};
68
69/// This overload is specialized to act on RTypeErasedColumnValues instead of RColumnValues.
70template <std::size_t... S, typename... ColTypes>
71void InitRDFValues(unsigned int slot, std::vector<RTypeErasedColumnValue> &values, TTreeReader *r,
72 const ColumnNames_t &bn, const RBookedCustomColumns &customCols, std::index_sequence<S...>,
73 ROOT::TypeTraits::TypeList<ColTypes...>, const std::array<bool, sizeof...(S)> &isTmpColumn)
74{
75 using expander = int[];
76 (void)expander{(values.emplace_back(std::make_unique<RColumnValue<ColTypes>>()), 0)..., 0};
77 (void)expander{(isTmpColumn[S]
78 ? values[S].Cast<ColTypes>()->SetTmpColumn(slot, customCols.GetColumns().at(bn.at(S)).get())
79 : values[S].Cast<ColTypes>()->MakeProxy(r, bn.at(S)),
80 0)...,
81 0};
82}
83
84/// This overload is specialized to act on RTypeErasedColumnValues instead of RColumnValues.
85template <std::size_t... S, typename... ColTypes>
86void ResetRDFValueTuple(std::vector<RTypeErasedColumnValue> &values, std::index_sequence<S...>,
88{
89 using expander = int[];
90 (void)expander{(values[S].Cast<ColTypes>()->Reset(), 0)...};
91}
92
93// fwd decl for RActionCRTP
94template <typename Helper, typename PrevDataFrame, typename ColumnTypes_t>
95class RAction;
96
97/// A common template base class for all RActions. Avoids code repetition for specializations of RActions
98/// for different helpers, implementing all of the common logic.
99template <typename Helper, typename PrevDataFrame, typename ColumnTypes_t>
100class RActionCRTP<RAction<Helper, PrevDataFrame, ColumnTypes_t>> : public RActionBase {
102
103 Helper fHelper;
104 const std::shared_ptr<PrevDataFrame> fPrevDataPtr;
105 PrevDataFrame &fPrevData;
106
107protected:
108 /// The nth flag signals whether the nth input column is a custom column or not.
109 std::array<bool, ColumnTypes_t::list_size> fIsCustomColumn;
110
111public:
112 using TypeInd_t = std::make_index_sequence<ColumnTypes_t::list_size>;
113
114 RActionCRTP(Helper &&h, const ColumnNames_t &columns, std::shared_ptr<PrevDataFrame> pd,
115 RBookedCustomColumns &&customColumns)
116 : RActionBase(pd->GetLoopManagerUnchecked(), columns, std::move(customColumns)), fHelper(std::forward<Helper>(h)),
117 fPrevDataPtr(std::move(pd)), fPrevData(*fPrevDataPtr), fIsCustomColumn()
118 {
119 const auto nColumns = columns.size();
120 const auto &customCols = GetCustomColumns();
121 for (auto i = 0u; i < nColumns; ++i)
122 fIsCustomColumn[i] = customCols.HasName(columns[i]);
123 }
124
125 RActionCRTP(const RActionCRTP &) = delete;
127 // must call Deregister here, before fPrevDataFrame is destroyed,
128 // otherwise if fPrevDataFrame is fLoopManager we get a use after delete
129 ~RActionCRTP() { fLoopManager->Deregister(this); }
130
131 Helper &GetHelper() { return fHelper; }
132
133 void Initialize() final { fHelper.Initialize(); }
134
135 void InitSlot(TTreeReader *r, unsigned int slot) final
136 {
137 for (auto &bookedBranch : GetCustomColumns().GetColumns())
138 bookedBranch.second->InitSlot(r, slot);
139 static_cast<Action_t *>(this)->InitColumnValues(r, slot);
140 fHelper.InitTask(r, slot);
141 }
142
143 void Run(unsigned int slot, Long64_t entry) final
144 {
145 // check if entry passes all filters
146 if (fPrevData.CheckFilters(slot, entry))
147 static_cast<Action_t *>(this)->Exec(slot, entry, TypeInd_t());
148 }
149
150 void TriggerChildrenCount() final { fPrevData.IncrChildrenCount(); }
151
152 void FinalizeSlot(unsigned int slot) final
153 {
154 ClearValueReaders(slot);
155 for (auto &column : GetCustomColumns().GetColumns()) {
156 column.second->ClearValueReaders(slot);
157 }
158 fHelper.CallFinalizeTask(slot);
159 }
160
161 void ClearValueReaders(unsigned int slot) { static_cast<Action_t *>(this)->ResetColumnValues(slot, TypeInd_t()); }
162
163 void Finalize() final
164 {
165 fHelper.Finalize();
166 SetHasRun();
167 }
168
169 std::shared_ptr<RDFGraphDrawing::GraphNode> GetGraph()
170 {
171 auto prevNode = fPrevData.GetGraph();
172 auto prevColumns = prevNode->GetDefinedColumns();
173
174 // Action nodes do not need to ask an helper to create the graph nodes. They are never common nodes between
175 // multiple branches
176 auto thisNode = std::make_shared<RDFGraphDrawing::GraphNode>(fHelper.GetActionName());
177 auto evaluatedNode = thisNode;
178 for (auto &column : GetCustomColumns().GetColumns()) {
179 /* Each column that this node has but the previous hadn't has been defined in between,
180 * so it has to be built and appended. */
181 if (RDFGraphDrawing::CheckIfDefaultOrDSColumn(column.first, column.second))
182 continue;
183 if (std::find(prevColumns.begin(), prevColumns.end(), column.first) == prevColumns.end()) {
184 auto defineNode = RDFGraphDrawing::CreateDefineNode(column.first, column.second.get());
185 evaluatedNode->SetPrevNode(defineNode);
186 evaluatedNode = defineNode;
187 }
188 }
189
190 thisNode->AddDefinedColumns(GetCustomColumns().GetNames());
191 thisNode->SetAction(HasRun());
192 evaluatedNode->SetPrevNode(prevNode);
193 return thisNode;
194 }
195
196 /// This method is invoked to update a partial result during the event loop, right before passing the result to a
197 /// user-defined callback registered via RResultPtr::RegisterCallback
198 void *PartialUpdate(unsigned int slot) final { return PartialUpdateImpl(slot); }
199
200private:
201 // this overload is SFINAE'd out if Helper does not implement `PartialUpdate`
202 // the template parameter is required to defer instantiation of the method to SFINAE time
203 template <typename H = Helper>
204 auto PartialUpdateImpl(unsigned int slot) -> decltype(std::declval<H>().PartialUpdate(slot), (void *)(nullptr))
205 {
206 return &fHelper.PartialUpdate(slot);
207 }
208
209 // this one is always available but has lower precedence thanks to `...`
210 void *PartialUpdateImpl(...) { throw std::runtime_error("This action does not support callbacks!"); }
211};
212
213/// An action node in a RDF computation graph.
214template <typename Helper, typename PrevDataFrame, typename ColumnTypes_t = typename Helper::ColumnTypes_t>
215class RAction final : public RActionCRTP<RAction<Helper, PrevDataFrame, ColumnTypes_t>> {
216 std::vector<RDFValueTuple_t<ColumnTypes_t>> fValues;
217
218public:
220
221 RAction(Helper &&h, const ColumnNames_t &bl, std::shared_ptr<PrevDataFrame> pd,
222 RBookedCustomColumns &&customColumns)
223 : ActionCRTP_t(std::forward<Helper>(h), bl, std::move(pd), std::move(customColumns)), fValues(GetNSlots()) { }
224
225 void InitColumnValues(TTreeReader *r, unsigned int slot)
226 {
229 }
230
231 template <std::size_t... S>
232 void Exec(unsigned int slot, Long64_t entry, std::index_sequence<S...>)
233 {
234 (void)entry; // avoid bogus 'unused parameter' warning in gcc4.9
235 ActionCRTP_t::GetHelper().Exec(slot, std::get<S>(fValues[slot]).Get(entry)...);
236 }
237
238 template <std::size_t... S>
239 void ResetColumnValues(unsigned int slot, std::index_sequence<S...> s)
240 {
242 }
243};
244
245// These specializations let RAction<SnapshotHelper[MT]> type-erase their column values, for (presumably) a small hit in
246// performance (which hopefully be completely swallowed by the cost of I/O during the event loop) and a large,
247// measurable gain in compile time and therefore jitting time.
248// Snapshot is the action that most suffers from long compilation times because it happens to be called with dozens
249// if not with a few hundred template parameters, which pretty much never happens for other actions.
250
251// fwd decl
252template <typename... BranchTypes>
254
255template <typename... BranchTypes>
257
258template <typename PrevDataFrame, typename... ColTypes>
259class RAction<SnapshotHelper<ColTypes...>, PrevDataFrame, ROOT::TypeTraits::TypeList<ColTypes...>> final
260 : public RActionCRTP<RAction<SnapshotHelper<ColTypes...>, PrevDataFrame, ROOT::TypeTraits::TypeList<ColTypes...>>> {
261
263 RActionCRTP<RAction<SnapshotHelper<ColTypes...>, PrevDataFrame, ROOT::TypeTraits::TypeList<ColTypes...>>>;
264 using ColumnTypes_t = typename SnapshotHelper<ColTypes...>::ColumnTypes_t;
265
266 std::vector<std::vector<RTypeErasedColumnValue>> fValues;
267
268public:
269 RAction(SnapshotHelper<ColTypes...> &&h, const ColumnNames_t &bl, std::shared_ptr<PrevDataFrame> pd,
270 RBookedCustomColumns &&customColumns)
271 : ActionCRTP_t(std::forward<SnapshotHelper<ColTypes...>>(h), bl, std::move(pd), std::move(customColumns)),
273 {
274 }
275
276 void InitColumnValues(TTreeReader *r, unsigned int slot)
277 {
280 }
281
282 template <std::size_t... S>
283 void Exec(unsigned int slot, Long64_t entry, std::index_sequence<S...>)
284 {
285 (void)entry; // avoid bogus 'unused parameter' warning in gcc4.9
286 ActionCRTP_t::GetHelper().Exec(slot, fValues[slot][S].template Get<ColTypes>(entry)...);
287 }
288
289 template <std::size_t... S>
290 void ResetColumnValues(unsigned int slot, std::index_sequence<S...> s)
291 {
293 }
294};
295
296// Same exact code as above, but for SnapshotHelperMT. I don't know how to avoid repeating this code
297template <typename PrevDataFrame, typename... ColTypes>
298class RAction<SnapshotHelperMT<ColTypes...>, PrevDataFrame, ROOT::TypeTraits::TypeList<ColTypes...>> final
299 : public RActionCRTP<
300 RAction<SnapshotHelperMT<ColTypes...>, PrevDataFrame, ROOT::TypeTraits::TypeList<ColTypes...>>> {
301
303 RActionCRTP<RAction<SnapshotHelperMT<ColTypes...>, PrevDataFrame, ROOT::TypeTraits::TypeList<ColTypes...>>>;
304 using ColumnTypes_t = typename SnapshotHelperMT<ColTypes...>::ColumnTypes_t;
305
306 std::vector<std::vector<RTypeErasedColumnValue>> fValues;
307
308public:
309 RAction(SnapshotHelperMT<ColTypes...> &&h, const ColumnNames_t &bl, std::shared_ptr<PrevDataFrame> pd,
310 RBookedCustomColumns &&customColumns)
311 : ActionCRTP_t(std::forward<SnapshotHelperMT<ColTypes...>>(h), bl, std::move(pd), std::move(customColumns)),
313 {
314 }
315
316 void InitColumnValues(TTreeReader *r, unsigned int slot)
317 {
320 }
321
322 template <std::size_t... S>
323 void Exec(unsigned int slot, Long64_t entry, std::index_sequence<S...>)
324 {
325 (void)entry; // avoid bogus 'unused parameter' warning in gcc4.9
326 ActionCRTP_t::GetHelper().Exec(slot, fValues[slot][S].template Get<ColTypes>(entry)...);
327 }
328
329 template <std::size_t... S>
330 void ResetColumnValues(unsigned int slot, std::index_sequence<S...> s)
331 {
333 }
334};
335
336} // ns RDF
337} // ns Internal
338} // ns ROOT
339
340#endif // ROOT_RACTION
SVector< double, 2 > v
Definition: Dict.h:5
ROOT::R::TRInterface & r
Definition: Object.C:4
#define h(i)
Definition: RSha256.hxx:106
#define e(i)
Definition: RSha256.hxx:103
long long Long64_t
Definition: RtypesCore.h:69
unsigned long long ULong64_t
Definition: RtypesCore.h:70
char name[80]
Definition: TGX11.cxx:109
typedef void((*Func_t)())
const ColumnNames_t & GetColumnNames() const
Definition: RActionBase.hxx:63
RBookedCustomColumns & GetCustomColumns()
Definition: RActionBase.hxx:64
std::array< bool, ColumnTypes_t::list_size > fIsCustomColumn
The nth flag signals whether the nth input column is a custom column or not.
Definition: RAction.hxx:109
std::make_index_sequence< ColumnTypes_t::list_size > TypeInd_t
Definition: RAction.hxx:112
void * PartialUpdate(unsigned int slot) final
This method is invoked to update a partial result during the event loop, right before passing the res...
Definition: RAction.hxx:198
RActionCRTP(Helper &&h, const ColumnNames_t &columns, std::shared_ptr< PrevDataFrame > pd, RBookedCustomColumns &&customColumns)
Definition: RAction.hxx:114
auto PartialUpdateImpl(unsigned int slot) -> decltype(std::declval< H >().PartialUpdate(slot),(void *)(nullptr))
Definition: RAction.hxx:204
Unused, not instantiatable. Only the partial specialization RActionCRTP<RAction<.....
Definition: RAction.hxx:41
RAction(SnapshotHelperMT< ColTypes... > &&h, const ColumnNames_t &bl, std::shared_ptr< PrevDataFrame > pd, RBookedCustomColumns &&customColumns)
Definition: RAction.hxx:309
RAction(SnapshotHelper< ColTypes... > &&h, const ColumnNames_t &bl, std::shared_ptr< PrevDataFrame > pd, RBookedCustomColumns &&customColumns)
Definition: RAction.hxx:269
An action node in a RDF computation graph.
Definition: RAction.hxx:215
void InitColumnValues(TTreeReader *r, unsigned int slot)
Definition: RAction.hxx:225
void ResetColumnValues(unsigned int slot, std::index_sequence< S... > s)
Definition: RAction.hxx:239
void Exec(unsigned int slot, Long64_t entry, std::index_sequence< S... >)
Definition: RAction.hxx:232
std::vector< RDFValueTuple_t< ColumnTypes_t > > fValues
Definition: RAction.hxx:216
RAction(Helper &&h, const ColumnNames_t &bl, std::shared_ptr< PrevDataFrame > pd, RBookedCustomColumns &&customColumns)
Definition: RAction.hxx:221
Encapsulates the columns defined by the user.
bool HasName(std::string_view name) const
Check if the provided name is tracked in the names list.
const RCustomColumnBasePtrMap_t & GetColumns() const
Returns the list of the pointers to the defined columns.
Helper class that updates and returns TTree branches as well as RDataFrame temporary columns.
A type-erasing wrapper around RColumnValue.
Definition: RAction.hxx:47
RTypeErasedColumnValue(std::unique_ptr< RColumnValue< T > > v)
Definition: RAction.hxx:52
A simple, robust and fast interface to read values from ROOT columnar datasets such as TTree,...
Definition: TTreeReader.h:44
bool CheckIfDefaultOrDSColumn(const std::string &name, const std::shared_ptr< ROOT::Detail::RDF::RCustomColumnBase > &column)
std::shared_ptr< GraphNode > CreateDefineNode(const std::string &columnName, const ROOT::Detail::RDF::RCustomColumnBase *columnPtr)
void InitRDFValues(unsigned int slot, RDFValueTuple &valueTuple, TTreeReader *r, const ColumnNames_t &bn, const RBookedCustomColumns &customCols, std::index_sequence< S... >, const std::array< bool, sizeof...(S)> &isCustomColumn)
Initialize a tuple of RColumnValues.
Definition: NodesUtils.hxx:54
unsigned int GetNSlots()
Definition: RDFUtils.cxx:257
void ResetRDFValueTuple(std::vector< RTypeErasedColumnValue > &values, std::index_sequence< S... >, ROOT::TypeTraits::TypeList< ColTypes... >)
This overload is specialized to act on RTypeErasedColumnValues instead of RColumnValues.
Definition: RAction.hxx:86
double T(double x)
Definition: ChebyshevPol.h:34
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
ROOT::Detail::RDF::ColumnNames_t ColumnNames_t
Definition: RDataFrame.cxx:788
RooArgSet S(const RooAbsArg &v1)
static constexpr double s
void forward(const LAYERDATA &prevLayerData, LAYERDATA &currLayerData)
apply the weights (and functions) in forward direction of the DNN
Definition: NeuralNet.icc:544
Lightweight storage for a collection of types.
Definition: TypeTraits.hxx:27