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-2022, 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"
21
22#include <Rtypes.h> // R__CLING_PTRCHECK
23#include <ROOT/TypeTraits.hxx>
24
25#include <algorithm>
26#include <array>
27#include <memory>
28#include <utility> // make_index_sequence
29#include <vector>
30
31namespace ROOT {
32namespace Internal {
33namespace RDF {
34
36
37/// Just like an RAction, but it has N action helpers (one per variation + nominal) and N previous nodes.
38template <typename Helper, typename PrevNode, typename ColumnTypes_t>
39class R__CLING_PTRCHECK(off) RVariedAction final : public RActionBase {
40 using TypeInd_t = std::make_index_sequence<ColumnTypes_t::list_size>;
41 // If the PrevNode is a RJittedFilter, our collection of previous nodes will have to use the RNodeBase type:
42 // we'll have a RJittedFilter for the nominal case, but the others will be concrete filters.
43 using PrevNodeType = std::conditional_t<std::is_same<PrevNode, RJittedFilter>::value, RFilterBase, PrevNode>;
44
45 std::vector<Helper> fHelpers; ///< Action helpers per variation.
46 /// Owning pointers to upstream nodes for each systematic variation (with the "nominal" at index 0).
47 std::vector<std::shared_ptr<PrevNodeType>> fPrevNodes;
48
49 /// Column readers per slot (outer dimension), per variation and per input column (inner dimension, std::array).
50 std::vector<std::vector<std::array<RColumnReaderBase *, ColumnTypes_t::list_size>>> fInputValues;
51
52 /// The nth flag signals whether the nth input column is a custom column or not.
53 std::array<bool, ColumnTypes_t::list_size> fIsDefine;
54
55 std::vector<std::shared_ptr<PrevNodeType>> MakePrevFilters(std::shared_ptr<PrevNode> nominal) const
56 {
57 const auto &variations = GetVariations();
58 std::vector<std::shared_ptr<PrevNodeType>> prevFilters;
59 prevFilters.reserve(variations.size());
60 if (static_cast<RNodeBase *>(nominal.get()) == fLoopManager) {
61 // just fill this with the RLoopManager N times
62 prevFilters.resize(variations.size(), nominal);
63 } else {
64 // create varied versions of the previous filter node
65 const auto &prevVariations = nominal->GetVariations();
66 for (const auto &variation : variations) {
67 if (IsStrInVec(variation, prevVariations)) {
68 prevFilters.emplace_back(std::static_pointer_cast<PrevNodeType>(nominal->GetVariedFilter(variation)));
69 } else {
70 prevFilters.emplace_back(nominal);
71 }
72 }
73 }
74
75 return prevFilters;
76 }
77
78public:
79 RVariedAction(std::vector<Helper> &&helpers, const ColumnNames_t &columns, std::shared_ptr<PrevNode> prevNode,
80 const RColumnRegister &colRegister)
81 : RActionBase(prevNode->GetLoopManagerUnchecked(), columns, colRegister, prevNode->GetVariations()),
82 fHelpers(std::move(helpers)), fPrevNodes(MakePrevFilters(prevNode)), fInputValues(GetNSlots())
83 {
84 fLoopManager->Register(this);
85
86 for (auto i = 0u; i < columns.size(); ++i) {
87 auto *define = colRegister.GetDefine(columns[i]);
88 fIsDefine[i] = define != nullptr;
89 if (fIsDefine[i])
90 define->MakeVariations(GetVariations());
91 }
92 }
93
94 RVariedAction(const RVariedAction &) = delete;
96
97 ~RVariedAction() { fLoopManager->Deregister(this); }
98
99 void Initialize() final
100 {
101 std::for_each(fHelpers.begin(), fHelpers.end(), [](Helper &h) { h.Initialize(); });
102 }
103
104 void InitSlot(TTreeReader *r, unsigned int slot) final
105 {
106 RDFInternal::RColumnReadersInfo info{GetColumnNames(), GetColRegister(), fIsDefine.data(), *fLoopManager};
107
108 // get readers for each systematic variation
109 for (const auto &variation : GetVariations())
110 fInputValues[slot].emplace_back(GetColumnReaders(slot, r, ColumnTypes_t{}, info, variation));
111
112 std::for_each(fHelpers.begin(), fHelpers.end(), [=](Helper &h) { h.InitTask(r, slot); });
113 }
114
115 template <typename... ColTypes, std::size_t... S>
116 void
117 CallExec(unsigned int slot, unsigned int varIdx, Long64_t entry, TypeList<ColTypes...>, std::index_sequence<S...>)
118 {
119 fHelpers[varIdx].Exec(slot, fInputValues[slot][varIdx][S]->template Get<ColTypes>(entry)...);
120 (void)entry;
121 }
122
123 void Run(unsigned int slot, Long64_t entry) final
124 {
125 for (auto varIdx = 0u; varIdx < GetVariations().size(); ++varIdx) {
126 if (fPrevNodes[varIdx]->CheckFilters(slot, entry))
127 CallExec(slot, varIdx, entry, ColumnTypes_t{}, TypeInd_t{});
128 }
129 }
130
132 {
133 std::for_each(fPrevNodes.begin(), fPrevNodes.end(), [](auto &f) { f->IncrChildrenCount(); });
134 }
135
136 /// Clean-up operations to be performed at the end of a task.
137 void FinalizeSlot(unsigned int slot) final
138 {
139 fInputValues[slot].clear();
140 std::for_each(fHelpers.begin(), fHelpers.end(), [=](Helper &h) { h.CallFinalizeTask(slot); });
141 }
142
143 /// Clean-up and finalize the action result (e.g. merging slot-local results).
144 /// It invokes the helper's Finalize method.
145 void Finalize() final
146 {
147 std::for_each(fHelpers.begin(), fHelpers.end(), [](Helper &h) { h.Finalize(); });
148 SetHasRun();
149 }
150
151 /// Return the partially-updated value connected to the nominal result.
152 void *PartialUpdate(unsigned int slot) final { return PartialUpdateImpl(slot); }
153
154 /// Return the per-sample callback connected to the nominal result.
155 ROOT::RDF::SampleCallback_t GetSampleCallback() final { return fHelpers[0].GetSampleCallback(); }
156
157 std::shared_ptr<RDFGraphDrawing::GraphNode>
158 GetGraph(std::unordered_map<void *, std::shared_ptr<RDFGraphDrawing::GraphNode>> &visitedMap) final
159 {
160 auto prevNode = fPrevNodes[0]->GetGraph(visitedMap);
161 const auto &prevColumns = prevNode->GetDefinedColumns();
162
163 // Action nodes do not need to go through CreateFilterNode: they are never common nodes between multiple branches
164 const auto nodeType = HasRun() ? RDFGraphDrawing::ENodeType::kUsedAction : RDFGraphDrawing::ENodeType::kAction;
165 auto thisNode = std::make_shared<RDFGraphDrawing::GraphNode>("Varied " + fHelpers[0].GetActionName(),
166 visitedMap.size(), nodeType);
167 visitedMap[(void *)this] = thisNode;
168
169 auto upmostNode = AddDefinesToGraph(thisNode, GetColRegister(), prevColumns, visitedMap);
170
171 thisNode->AddDefinedColumns(GetColRegister().GetNames());
172 upmostNode->SetPrevNode(prevNode);
173 return thisNode;
174 }
175
176 /**
177 Retrieve a container holding the names and values of the variations. It
178 knows how to merge with others of the same type.
179 */
180 std::unique_ptr<RMergeableValueBase> GetMergeableValue() const final
181 {
182 std::vector<std::string> keys{GetVariations()};
183
184 std::vector<std::unique_ptr<RDFDetail::RMergeableValueBase>> values;
185 values.reserve(fHelpers.size());
186 for (auto &&h : fHelpers)
187 values.emplace_back(h.GetMergeableValue());
188
189 return std::make_unique<RDFDetail::RMergeableVariationsBase>(std::move(keys), std::move(values));
190 }
191
192 [[noreturn]] std::unique_ptr<RActionBase> MakeVariedAction(std::vector<void *> &&) final
193 {
194 throw std::logic_error("Cannot produce a varied action from a varied action.");
195 }
196
197private:
198 // this overload is SFINAE'd out if Helper does not implement `PartialUpdate`
199 // the template parameter is required to defer instantiation of the method to SFINAE time
200 template <typename H = Helper>
201 auto PartialUpdateImpl(unsigned int slot) -> decltype(std::declval<H>().PartialUpdate(slot), (void *)(nullptr))
202 {
203 return &fHelpers[0].PartialUpdate(slot);
204 }
205
206 // this one is always available but has lower precedence thanks to `...`
207 void *PartialUpdateImpl(...) { throw std::runtime_error("This action does not support callbacks!"); }
208};
209
210} // namespace RDF
211} // namespace Internal
212} // namespace ROOT
213
214#endif // ROOT_RVARIEDACTION
#define f(i)
Definition RSha256.hxx:104
#define h(i)
Definition RSha256.hxx:106
long long Long64_t
Definition RtypesCore.h:80
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 r
virtual void MakeVariations(const std::vector< std::string > &variations)=0
Create clones of this Define that work with values in varied "universes".
Base class for non-leaf nodes of the computational graph.
Definition RNodeBase.hxx:43
A binder for user-defined columns, variations and aliases.
RDFDetail::RDefineBase * GetDefine(const std::string &colName) const
Return the RDefine for the requested column name, or nullptr.
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).
std::unique_ptr< RMergeableValueBase > GetMergeableValue() const final
Retrieve a container holding the names and values of the variations.
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::vector< std::vector< std::array< RColumnReaderBase *, ColumnTypes_t::list_size > > > fInputValues
Column readers per slot (outer dimension), per variation and per input column (inner dimension,...
std::vector< Helper > fHelpers
Action helpers per variation.
RVariedAction & operator=(const RVariedAction &)=delete
void InitSlot(TTreeReader *r, unsigned int slot) final
std::conditional_t< std::is_same< PrevNode, RJittedFilter >::value, RFilterBase, PrevNode > PrevNodeType
std::shared_ptr< RDFGraphDrawing::GraphNode > GetGraph(std::unordered_map< void *, std::shared_ptr< RDFGraphDrawing::GraphNode > > &visitedMap) final
std::array< bool, ColumnTypes_t::list_size > fIsDefine
The nth flag signals whether the nth input column is a custom column or not.
void * PartialUpdate(unsigned int slot) final
Return the partially-updated value connected to the nominal result.
std::unique_ptr< RActionBase > MakeVariedAction(std::vector< void * > &&) final
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:283
bool IsStrInVec(const std::string &str, const std::vector< std::string > &vec)
Definition RDFUtils.cxx:417
std::array< RDFDetail::RColumnReaderBase *, sizeof...(ColTypes)> GetColumnReaders(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
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....
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
This type aggregates some of the arguments passed to GetColumnReaders.
Lightweight storage for a collection of types.