Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RDFHelpers.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// This header contains helper free functions that slim down RDataFrame's programming model
12
13#ifndef ROOT_RDF_HELPERS
14#define ROOT_RDF_HELPERS
15
16#include <ROOT/RDataFrame.hxx>
20#include <ROOT/TypeTraits.hxx>
21
22#include <algorithm> // std::transform
23#include <functional>
24#include <type_traits>
25#include <vector>
26#include <memory>
27#include <fstream>
28#include <iostream>
29
30namespace ROOT {
31namespace Internal {
32namespace RDF {
33template <typename... ArgTypes, typename F>
35{
36 return std::function<bool(ArgTypes...)>([=](ArgTypes... args) mutable { return !f(args...); });
37}
38
39template <typename... ArgTypes, typename Ret, typename... Args>
40std::function<bool(ArgTypes...)> NotHelper(ROOT::TypeTraits::TypeList<ArgTypes...>, Ret (*f)(Args...))
41{
42 return std::function<bool(ArgTypes...)>([=](ArgTypes... args) mutable { return !f(args...); });
43}
44
45template <typename I, typename T, typename F>
47
48template <std::size_t... N, typename T, typename F>
49class PassAsVecHelper<std::index_sequence<N...>, T, F> {
50 template <std::size_t Idx>
51 using AlwaysT = T;
52 typename std::decay<F>::type fFunc;
53
54public:
55 PassAsVecHelper(F &&f) : fFunc(std::forward<F>(f)) {}
56 auto operator()(AlwaysT<N>... args) -> decltype(fFunc({args...})) { return fFunc({args...}); }
57};
58
59template <std::size_t N, typename T, typename F>
61{
62 return PassAsVecHelper<std::make_index_sequence<N>, T, F>(std::forward<F>(f));
63}
64
65} // namespace RDF
66} // namespace Internal
67
68namespace RDF {
70
71
72// clag-format off
73/// Given a callable with signature bool(T1, T2, ...) return a callable with same signature that returns the negated result
74///
75/// The callable must have one single non-template definition of operator(). This is a limitation with respect to
76/// std::not_fn, required for interoperability with RDataFrame.
77// clang-format on
78template <typename F,
79 typename Args = typename ROOT::TypeTraits::CallableTraits<typename std::decay<F>::type>::arg_types_nodecay,
80 typename Ret = typename ROOT::TypeTraits::CallableTraits<typename std::decay<F>::type>::ret_type>
81auto Not(F &&f) -> decltype(RDFInternal::NotHelper(Args(), std::forward<F>(f)))
82{
83 static_assert(std::is_same<Ret, bool>::value, "RDF::Not requires a callable that returns a bool.");
84 return RDFInternal::NotHelper(Args(), std::forward<F>(f));
85}
86
87// clang-format off
88/// PassAsVec is a callable generator that allows passing N variables of type T to a function as a single collection.
89///
90/// PassAsVec<N, T>(func) returns a callable that takes N arguments of type T, passes them down to function `func` as
91/// an initializer list `{t1, t2, t3,..., tN}` and returns whatever f({t1, t2, t3, ..., tN}) returns.
92///
93/// Note that for this to work with RDataFrame the type of all columns that the callable is applied to must be exactly T.
94/// Example usage together with RDataFrame ("varX" columns must all be `float` variables):
95/// \code
96/// bool myVecFunc(std::vector<float> args);
97/// df.Filter(PassAsVec<3, float>(myVecFunc), {"var1", "var2", "var3"});
98/// \endcode
99// clang-format on
100template <std::size_t N, typename T, typename F>
102{
104}
105
106// clang-format off
107/// Create a graphviz representation of the dataframe computation graph, return it as a string.
108/// \param[in] node any node of the graph. Called on the head (first) node, it prints the entire graph. Otherwise, only the branch the node belongs to.
109///
110/// The output can be displayed with a command akin to `dot -Tpng output.dot > output.png && open output.png`.
111///
112/// Note that "hanging" Defines, i.e. Defines without downstream nodes, will not be displayed by SaveGraph as they are
113/// effectively optimized away from the computation graph.
114///
115/// Note that SaveGraph is not thread-safe and must not be called concurrently from different threads.
116// clang-format on
117template <typename NodeType>
118std::string SaveGraph(NodeType node)
119{
121 return helper(node);
122}
123
124// clang-format off
125/// Create a graphviz representation of the dataframe computation graph, write it to the specified file.
126/// \param[in] node any node of the graph. Called on the head (first) node, it prints the entire graph. Otherwise, only the branch the node belongs to.
127/// \param[in] outputFile file where to save the representation.
128///
129/// The output can be displayed with a command akin to `dot -Tpng output.dot > output.png && open output.png`.
130///
131/// Note that "hanging" Defines, i.e. Defines without downstream nodes, will not be displayed by SaveGraph as they are
132/// effectively optimized away from the computation graph.
133///
134/// Note that SaveGraph is not thread-safe and must not be called concurrently from different threads.
135// clang-format on
136template <typename NodeType>
137void SaveGraph(NodeType node, const std::string &outputFile)
138{
140 std::string dotGraph = helper(node);
141
142 std::ofstream out(outputFile);
143 if (!out.is_open()) {
144 throw std::runtime_error("Could not open output file \"" + outputFile + "\"for reading");
145 }
146
147 out << dotGraph;
148 out.close();
149}
150
151// clang-format off
152/// Cast a RDataFrame node to the common type ROOT::RDF::RNode
153/// \param[in] node Any node of a RDataFrame graph
154// clang-format on
155template <typename NodeType>
156RNode AsRNode(NodeType node)
157{
158 return node;
159}
160
161// clang-format off
162/// Trigger the event loop of multiple RDataFrames concurrently
163/// \param[in] handles A vector of RResultHandles
164///
165/// This function triggers the event loop of all computation graphs which relate to the
166/// given RResultHandles. The advantage compared to running the event loop implicitly by accessing the
167/// RResultPtr is that the event loops will run concurrently. Therefore, the overall
168/// computation of all results is generally more efficient.
169/// It should be noted that user-defined operations (e.g., Filters and Defines) of the different RDataFrame graphs are assumed to be safe to call concurrently.
170///
171/// ~~~{.cpp}
172/// ROOT::RDataFrame df1("tree1", "file1.root");
173/// auto r1 = df1.Histo1D("var1");
174///
175/// ROOT::RDataFrame df2("tree2", "file2.root");
176/// auto r2 = df2.Sum("var2");
177///
178/// // RResultPtr -> RResultHandle conversion is automatic
179/// ROOT::RDF::RunGraphs({r1, r2});
180/// ~~~
181// clang-format on
182void RunGraphs(std::vector<RResultHandle> handles);
183
184} // namespace RDF
185} // namespace ROOT
186#endif
#define f(i)
Definition RSha256.hxx:104
#define N
TRObject operator()(const T1 &t1) const
The public interface to the RDataFrame federation of classes.
#define F(x, y, z)
std::function< bool(ArgTypes...)> NotHelper(ROOT::TypeTraits::TypeList< ArgTypes... >, F &&f)
auto PassAsVec(F &&f) -> PassAsVecHelper< std::make_index_sequence< N >, T, F >
auto Not(F &&f) -> decltype(RDFInternal::NotHelper(Args(), std::forward< F >(f)))
Given a callable with signature bool(T1, T2, ...) return a callable with same signature that returns ...
std::string SaveGraph(NodeType node)
Create a graphviz representation of the dataframe computation graph, return it as a string.
RNode AsRNode(NodeType node)
Cast a RDataFrame node to the common type ROOT::RDF::RNode.
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Lightweight storage for a collection of types.