Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RFilter.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_RFILTER
12 #define ROOT_RFILTER
13 
16 #include "ROOT/RDF/NodesUtils.hxx"
17 #include "ROOT/RDF/Utils.hxx"
18 #include "ROOT/RDF/RFilterBase.hxx"
21 #include "ROOT/TypeTraits.hxx"
22 #include "RtypesCore.h"
23 
24 #include <algorithm>
25 #include <memory>
26 #include <string>
27 #include <vector>
28 
29 namespace ROOT {
30 
31 namespace Internal {
32 namespace RDF {
33 using namespace ROOT::Detail::RDF;
34 
35 // fwd decl for RFilter
36 namespace GraphDrawing {
37 std::shared_ptr<GraphNode> CreateFilterNode(const RFilterBase *filterPtr);
38 
39 bool CheckIfDefaultOrDSColumn(const std::string &name, const std::shared_ptr<RCustomColumnBase> &column);
40 
41 std::shared_ptr<GraphNode>
42 CreateDefineNode(const std::string &columnName, const RDFDetail::RCustomColumnBase *columnPtr);
43 } // ns GraphDrawing
44 
45 } // ns RDF
46 } // ns Internal
47 
48 namespace Detail {
49 namespace RDF {
50 using namespace ROOT::TypeTraits;
51 namespace RDFGraphDrawing = ROOT::Internal::RDF::GraphDrawing;
52 
53 template <typename FilterF, typename PrevDataFrame>
54 class RFilter final : public RFilterBase {
55  using ColumnTypes_t = typename CallableTraits<FilterF>::arg_types;
56  using TypeInd_t = std::make_index_sequence<ColumnTypes_t::list_size>;
57 
58  FilterF fFilter;
59  const ColumnNames_t fColumnNames;
60  const std::shared_ptr<PrevDataFrame> fPrevDataPtr;
61  PrevDataFrame &fPrevData;
62  std::vector<RDFInternal::RDFValueTuple_t<ColumnTypes_t>> fValues;
63  /// The nth flag signals whether the nth input column is a custom column or not.
64  std::array<bool, ColumnTypes_t::list_size> fIsCustomColumn;
65 
66 public:
67  RFilter(FilterF &&f, const ColumnNames_t &columns, std::shared_ptr<PrevDataFrame> pd,
68  const RDFInternal::RBookedCustomColumns &customColumns, std::string_view name = "")
69  : RFilterBase(pd->GetLoopManagerUnchecked(), name, pd->GetLoopManagerUnchecked()->GetNSlots(), customColumns),
70  fFilter(std::forward<FilterF>(f)), fColumnNames(columns), fPrevDataPtr(std::move(pd)), fPrevData(*fPrevDataPtr),
71  fValues(fNSlots), fIsCustomColumn()
72  {
73  const auto nColumns = fColumnNames.size();
74  for (auto i = 0u; i < nColumns; ++i)
75  fIsCustomColumn[i] = fCustomColumns.HasName(fColumnNames[i]);
76  }
77 
78  RFilter(const RFilter &) = delete;
79  RFilter &operator=(const RFilter &) = delete;
80  // must call Deregister here, before fPrevDataFrame is destroyed,
81  // otherwise if fPrevDataFrame is fLoopManager we get a use after delete
82  ~RFilter() { fLoopManager->Deregister(this); }
83 
84  bool CheckFilters(unsigned int slot, Long64_t entry) final
85  {
86  if (entry != fLastCheckedEntry[slot]) {
87  if (!fPrevData.CheckFilters(slot, entry)) {
88  // a filter upstream returned false, cache the result
89  fLastResult[slot] = false;
90  } else {
91  // evaluate this filter, cache the result
92  auto passed = CheckFilterHelper(slot, entry, TypeInd_t());
93  passed ? ++fAccepted[slot] : ++fRejected[slot];
94  fLastResult[slot] = passed;
95  }
96  fLastCheckedEntry[slot] = entry;
97  }
98  return fLastResult[slot];
99  }
100 
101  template <std::size_t... S>
102  bool CheckFilterHelper(unsigned int slot, Long64_t entry, std::index_sequence<S...>)
103  {
104  // silence "unused parameter" warnings in gcc
105  (void)slot;
106  (void)entry;
107  return fFilter(std::get<S>(fValues[slot]).Get(entry)...);
108  }
109 
110  void InitSlot(TTreeReader *r, unsigned int slot) final
111  {
112  for (auto &bookedBranch : fCustomColumns.GetColumns())
113  bookedBranch.second->InitSlot(r, slot);
114  RDFInternal::InitRDFValues(slot, fValues[slot], r, fColumnNames, fCustomColumns, TypeInd_t(), fIsCustomColumn);
115  }
116 
117  // recursive chain of `Report`s
118  void Report(ROOT::RDF::RCutFlowReport &rep) const final { PartialReport(rep); }
119 
120  void PartialReport(ROOT::RDF::RCutFlowReport &rep) const final
121  {
122  fPrevData.PartialReport(rep);
123  FillReport(rep);
124  }
125 
126  void StopProcessing() final
127  {
128  ++fNStopsReceived;
129  if (fNStopsReceived == fNChildren)
130  fPrevData.StopProcessing();
131  }
132 
133  void IncrChildrenCount() final
134  {
135  ++fNChildren;
136  // propagate "children activation" upstream. named filters do the propagation via `TriggerChildrenCount`.
137  if (fNChildren == 1 && fName.empty())
138  fPrevData.IncrChildrenCount();
139  }
140 
141  void TriggerChildrenCount() final
142  {
143  R__ASSERT(!fName.empty()); // this method is to only be called on named filters
144  fPrevData.IncrChildrenCount();
145  }
146 
147  virtual void ClearValueReaders(unsigned int slot) final
148  {
149  RDFInternal::ResetRDFValueTuple(fValues[slot], TypeInd_t());
150  }
151 
152  void AddFilterName(std::vector<std::string> &filters)
153  {
154  fPrevData.AddFilterName(filters);
155  auto name = (HasName() ? fName : "Unnamed Filter");
156  filters.push_back(name);
157  }
158 
159  virtual void ClearTask(unsigned int slot) final
160  {
161  for (auto &column : fCustomColumns.GetColumns()) {
162  column.second->ClearValueReaders(slot);
163  }
164 
165  ClearValueReaders(slot);
166  }
167 
168  std::shared_ptr<RDFGraphDrawing::GraphNode> GetGraph()
169  {
170  // Recursively call for the previous node.
171  auto prevNode = fPrevData.GetGraph();
172  auto prevColumns = prevNode->GetDefinedColumns();
173 
174  auto thisNode = RDFGraphDrawing::CreateFilterNode(this);
175 
176  /* If the returned node is not new, there is no need to perform any other operation.
177  * This is a likely scenario when building the entire graph in which branches share
178  * some nodes. */
179  if (!thisNode->GetIsNew()) {
180  return thisNode;
181  }
182 
183  auto evaluatedNode = thisNode;
184  /* Each column that this node has but the previous hadn't has been defined in between,
185  * so it has to be built and appended. */
186 
187  for (auto &column : fCustomColumns.GetColumns()) {
188  // Even if treated as custom columns by the Dataframe, datasource columns must not be in the graph.
189  if (RDFGraphDrawing::CheckIfDefaultOrDSColumn(column.first, column.second))
190  continue;
191  if (std::find(prevColumns.begin(), prevColumns.end(), column.first) == prevColumns.end()) {
192  auto defineNode = RDFGraphDrawing::CreateDefineNode(column.first, column.second.get());
193  evaluatedNode->SetPrevNode(defineNode);
194  evaluatedNode = defineNode;
195  }
196  }
197 
198  // Keep track of the columns defined up to this point.
199  thisNode->AddDefinedColumns(fCustomColumns.GetNames());
200 
201  evaluatedNode->SetPrevNode(prevNode);
202  return thisNode;
203  }
204 };
205 
206 } // ns RDF
207 } // ns Detail
208 } // ns ROOT
209 
210 #endif // ROOT_RFILTER