Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RVariedAction.hxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, CERN 11/2021
2
3/*************************************************************************
4 * Copyright (C) 1995-2021, 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_RVARIEDACTION
12#define ROOT_RVARIEDACTION
13
14#include "ColumnReaderUtils.hxx"
15#include "GraphNode.hxx"
16#include "RActionBase.hxx"
17#include "RColumnReaderBase.hxx"
18#include "RLoopManager.hxx"
19#include "RJittedFilter.hxx"
20
21#include <Rtypes.h> // R__CLING_PTRCHECK
22#include <ROOT/TypeTraits.hxx>
23
24#include <algorithm>
25#include <array>
26#include <memory>
27#include <utility> // make_index_sequence
28#include <vector>
29
30namespace ROOT {
31namespace Internal {
32namespace RDF {
33
35
36/// Just like an RAction, but it has N action helpers (one per variation + nominal) and N previous nodes.
37template <typename Helper, typename PrevNode, typename ColumnTypes_t>
38class R__CLING_PTRCHECK(off) RVariedAction final : public RActionBase {
39 using TypeInd_t = std::make_index_sequence<ColumnTypes_t::list_size>;
40 // If the PrevNode is a RJittedFilter, our collection of previous nodes will have to use the RNodeBase type:
41 // we'll have a RJittedFilter for the nominal case, but the others will be concrete filters.
42 using PrevNodeType = std::conditional_t<std::is_same<PrevNode, RJittedFilter>::value, RFilterBase, PrevNode>;
43
44 std::vector<Helper> fHelpers; ///< Action helpers per variation.
45 /// Owning pointers to upstream nodes for each systematic variation (with the "nominal" at index 0).
46 std::vector<std::shared_ptr<PrevNodeType>> fPrevNodes;
47
48 /// Column readers per slot (outer dimension), per variation and per input column (inner dimension, std::array).
49 std::vector<std::vector<std::array<std::unique_ptr<RColumnReaderBase>, ColumnTypes_t::list_size>>> fInputValues;
50
51 /// The nth flag signals whether the nth input column is a custom column or not.
52 std::array<bool, ColumnTypes_t::list_size> fIsDefine;
53
54 std::vector<std::shared_ptr<PrevNodeType>> MakePrevFilters(std::shared_ptr<PrevNode> nominal) const
55 {
56 const auto &variations = GetVariations();
57 std::vector<std::shared_ptr<PrevNodeType>> prevFilters;
58 prevFilters.reserve(variations.size());
59 if (static_cast<RNodeBase *>(nominal.get()) == fLoopManager) {
60 // just fill this with the RLoopManager N times
61 prevFilters.resize(variations.size(), nominal);
62 } else {
63 // create varied versions of the previous filter node
64 const auto &prevVariations = nominal->GetVariations();
65 for (const auto &variation : variations) {
66 if (IsStrInVec(variation, prevVariations)) {
67 prevFilters.emplace_back(std::static_pointer_cast<PrevNodeType>(nominal->GetVariedFilter(variation)));
68 } else {
69 prevFilters.emplace_back(nominal);
70 }
71 }
72 }
73
74 return prevFilters;
75 }
76
77public:
78 RVariedAction(std::vector<Helper> &&helpers, const ColumnNames_t &columns, std::shared_ptr<PrevNode> prevNode,
79 const RColumnRegister &colRegister)
80 : RActionBase(prevNode->GetLoopManagerUnchecked(), columns, colRegister, prevNode->GetVariations()),
81 fHelpers(std::move(helpers)), fPrevNodes(MakePrevFilters(prevNode)), fInputValues(GetNSlots())
82 {
83 fLoopManager->Book(this);
84
85 const auto &defines = colRegister.GetColumns();
86 for (auto i = 0u; i < columns.size(); ++i) {
87 auto it = defines.find(columns[i]);
88 fIsDefine[i] = it != defines.end();
89 if (fIsDefine[i])
90 (it->second)->MakeVariations(GetVariations());
91 }
92 }
93
94 RVariedAction(const RVariedAction &) = delete;
97 {
98 // must Deregister objects from the RLoopManager here, before the fPrevDataFrame data member is destroyed:
99 // otherwise if fPrevDataFrame is the RLoopManager, it will be destroyed before the calls to Deregister happen.
100 RActionBase::GetColRegister().Clear(); // triggers RDefine deregistration
101 fLoopManager->Deregister(this);
102 }
103
104 void Initialize() final
105 {
106 std::for_each(fHelpers.begin(), fHelpers.end(), [](Helper &h) { h.Initialize(); });
107 }
108
109 void InitSlot(TTreeReader *r, unsigned int slot) final
110 {
111 RDFInternal::RColumnReadersInfo info{GetColumnNames(), GetColRegister(), fIsDefine.data(),
112 fLoopManager->GetDSValuePtrs(), fLoopManager->GetDataSource()};
113
114 // get readers for each systematic variation
115 for (const auto &variation : GetVariations())
116 fInputValues[slot].emplace_back(MakeColumnReaders(slot, r, ColumnTypes_t{}, info, variation));
117
118 std::for_each(fHelpers.begin(), fHelpers.end(), [=](Helper &h) { h.InitTask(r, slot); });
119 }
120
121 template <typename... ColTypes, std::size_t... S>
122 void
123 CallExec(unsigned int slot, unsigned int varIdx, Long64_t entry, TypeList<ColTypes...>, std::index_sequence<S...>)
124 {
125 fHelpers[varIdx].Exec(slot, fInputValues[slot][varIdx][S]->template Get<ColTypes>(entry)...);
126 (void)entry;
127 }
128
129 void Run(unsigned int slot, Long64_t entry) final
130 {
131 for (auto varIdx = 0u; varIdx < GetVariations().size(); ++varIdx) {
132 if (fPrevNodes[varIdx]->CheckFilters(slot, entry))
133 CallExec(slot, varIdx, entry, ColumnTypes_t{}, TypeInd_t{});
134 }
135 }
136
138 {
139 std::for_each(fPrevNodes.begin(), fPrevNodes.end(), [](auto &f) { f->IncrChildrenCount(); });
140 }
141
142 /// Clean-up operations to be performed at the end of a task.
143 void FinalizeSlot(unsigned int slot) final
144 {
145 fInputValues[slot].clear();
146 std::for_each(fHelpers.begin(), fHelpers.end(), [=](Helper &h) { h.CallFinalizeTask(slot); });
147 }
148
149 /// Clean-up and finalize the action result (e.g. merging slot-local results).
150 /// It invokes the helper's Finalize method.
151 void Finalize() final
152 {
153 std::for_each(fHelpers.begin(), fHelpers.end(), [](Helper &h) { h.Finalize(); });
154 SetHasRun();
155 }
156
157 /// Return the partially-updated value connected to the nominal result.
158 void *PartialUpdate(unsigned int slot) final { return PartialUpdateImpl(slot); }
159
160 /// Return the per-sample callback connected to the nominal result.
161 ROOT::RDF::SampleCallback_t GetSampleCallback() final { return fHelpers[0].GetSampleCallback(); }
162
163 std::shared_ptr<ROOT::Internal::RDF::GraphDrawing::GraphNode> GetGraph() final
164 {
165 auto prevNode = fPrevNodes[0]->GetGraph();
166 auto prevColumns = prevNode->GetDefinedColumns();
167
168 // Action nodes do not need to go through CreateFilterNode: they are never common nodes between multiple branches
169 auto thisNode = std::make_shared<RDFGraphDrawing::GraphNode>("Varied " + fHelpers[0].GetActionName());
170
171 auto upmostNode = AddDefinesToGraph(thisNode, GetColRegister(), prevColumns);
172
173 thisNode->AddDefinedColumns(GetColRegister().GetNames());
174 thisNode->SetAction(HasRun());
175 upmostNode->SetPrevNode(prevNode);
176 return thisNode;
177 }
178
179 [[noreturn]] std::unique_ptr<RMergeableValueBase> GetMergeableValue() const
180 {
181 throw std::logic_error("Varied actions cannot provide mergeable values");
182 }
183
184 [[noreturn]] std::unique_ptr<RActionBase> MakeVariedAction(std::vector<void *> &&)
185 {
186 throw std::logic_error("Cannot produce a varied action from a varied action.");
187 }
188
189private:
190 // this overload is SFINAE'd out if Helper does not implement `PartialUpdate`
191 // the template parameter is required to defer instantiation of the method to SFINAE time
192 template <typename H = Helper>
193 auto PartialUpdateImpl(unsigned int slot) -> decltype(std::declval<H>().PartialUpdate(slot), (void *)(nullptr))
194 {
195 return &fHelpers[0].PartialUpdate(slot);
196 }
197
198 // this one is always available but has lower precedence thanks to `...`
199 void *PartialUpdateImpl(...) { throw std::runtime_error("This action does not support callbacks!"); }
200};
201
202} // namespace RDF
203} // namespace Internal
204} // namespace ROOT
205
206#endif // ROOT_RVARIEDACTION
typedef void(GLAPIENTRYP _GLUfuncptr)(void)
ROOT::R::TRInterface & r
Definition Object.C:4
#define f(i)
Definition RSha256.hxx:104
#define h(i)
Definition RSha256.hxx:106
long long Long64_t
Definition RtypesCore.h:80
Base class for non-leaf nodes of the computational graph.
Definition RNodeBase.hxx:42
A binder for user-defined columns and aliases.
const DefinesMap_t & GetColumns() const
Returns a map of pointers to the defined columns.
Just like an RAction, but it has N action helpers (one per variation + nominal) and N previous nodes.
void Finalize() final
Clean-up and finalize the action result (e.g.
void Run(unsigned int slot, Long64_t entry) final
std::vector< std::shared_ptr< PrevNodeType > > fPrevNodes
Owning pointers to upstream nodes for each systematic variation (with the "nominal" at index 0).
RVariedAction(std::vector< Helper > &&helpers, const ColumnNames_t &columns, std::shared_ptr< PrevNode > prevNode, const RColumnRegister &colRegister)
void CallExec(unsigned int slot, unsigned int varIdx, Long64_t entry, TypeList< ColTypes... >, std::index_sequence< S... >)
auto PartialUpdateImpl(unsigned int slot) -> decltype(std::declval< H >().PartialUpdate(slot),(void *)(nullptr))
ROOT::RDF::SampleCallback_t GetSampleCallback() final
Return the per-sample callback connected to the nominal result.
void FinalizeSlot(unsigned int slot) final
Clean-up operations to be performed at the end of a task.
std::vector< std::shared_ptr< PrevNodeType > > MakePrevFilters(std::shared_ptr< PrevNode > nominal) const
std::make_index_sequence< ColumnTypes_t::list_size > TypeInd_t
std::unique_ptr< RActionBase > MakeVariedAction(std::vector< void * > &&)
std::vector< Helper > fHelpers
Action helpers per variation.
RVariedAction & operator=(const RVariedAction &)=delete
void InitSlot(TTreeReader *r, unsigned int slot) final
std::unique_ptr< RMergeableValueBase > GetMergeableValue() const
Retrieve a wrapper to the result of the action that knows how to merge with others of the same type.
std::conditional_t< std::is_same< PrevNode, RJittedFilter >::value, RFilterBase, PrevNode > PrevNodeType
std::shared_ptr< ROOT::Internal::RDF::GraphDrawing::GraphNode > GetGraph() final
std::array< bool, ColumnTypes_t::list_size > fIsDefine
The nth flag signals whether the nth input column is a custom column or not.
std::vector< std::vector< std::array< std::unique_ptr< RColumnReaderBase >, ColumnTypes_t::list_size > > > fInputValues
Column readers per slot (outer dimension), per variation and per input column (inner dimension,...
void * PartialUpdate(unsigned int slot) final
Return the partially-updated value connected to the nominal result.
RVariedAction(const RVariedAction &)=delete
A simple, robust and fast interface to read values from ROOT columnar datasets such as TTree,...
Definition TTreeReader.h:44
unsigned int GetNSlots()
Definition RDFUtils.cxx:285
bool IsStrInVec(const std::string &str, const std::vector< std::string > &vec)
Definition RDFUtils.cxx:419
std::array< std::unique_ptr< RDFDetail::RColumnReaderBase >, sizeof...(ColTypes)> MakeColumnReaders(unsigned int slot, TTreeReader *r, TypeList< ColTypes... >, const RColumnReadersInfo &colInfo, const std::string &variationName="nominal")
Create a group of column readers, one per type in the parameter pack.
std::vector< std::string > ColumnNames_t
Definition Utils.hxx:35
std::function< void(unsigned int, const ROOT::RDF::RSampleInfo &)> SampleCallback_t
The type of a data-block callback, registered with a RDataFrame computation graph via e....
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
This type aggregates some of the arguments passed to MakeColumnReaders.
Lightweight storage for a collection of types.