-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathdf018_customActions.C
100 lines (90 loc) · 3.91 KB
/
df018_customActions.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/// \file
/// \ingroup tutorial_dataframe
/// \notebook
/// Implement a custom action to fill THns.
///
/// This tutorial shows how to implement a custom action.
/// As an example, we build a helper for filling THns.
///
/// \macro_code
/// \macro_output
///
/// \date April 2018
/// \authors Enrico Guiraud, Danilo Piparo (CERN)
// This is a custom action which respects a well defined interface. It supports parallelism,
// in the sense that it behaves correctly if implicit multi threading is enabled.
// We template it on:
// - The type of the internal THnT(s)
// - The dimension of the internal THnT(s)
// Note the plural: in presence of a MT execution, internally more than a single THnT is created.
template <typename T, unsigned int NDIM>
class THnHelper : public ROOT::Detail::RDF::RActionImpl<THnHelper<T, NDIM>> {
public:
/// This is a handy, expressive shortcut.
using THn_t = THnT<T>;
/// This type is a requirement for every helper.
using Result_t = THn_t;
private:
std::vector<std::shared_ptr<THn_t>> fHistos; // one per data processing slot
public:
/// This constructor takes all the parameters necessary to build the THnTs. In addition, it requires the names of
/// the columns which will be used.
THnHelper(std::string_view name, std::string_view title, std::array<int, NDIM> nbins, std::array<double, NDIM> xmins,
std::array<double, NDIM> xmax)
{
const auto nSlots = ROOT::IsImplicitMTEnabled() ? ROOT::GetThreadPoolSize() : 1;
for (auto i : ROOT::TSeqU(nSlots)) {
fHistos.emplace_back(std::make_shared<THn_t>(std::string(name).c_str(), std::string(title).c_str(),
NDIM, nbins.data(), xmins.data(), xmax.data()));
(void)i;
}
}
THnHelper(THnHelper &&) = default;
THnHelper(const THnHelper &) = delete;
std::shared_ptr<THn_t> GetResultPtr() const { return fHistos[0]; }
void Initialize() {}
void InitTask(TTreeReader *, unsigned int) {}
/// This is a method executed at every entry
template <typename... ColumnTypes>
void Exec(unsigned int slot, ColumnTypes... values)
{
// Since THnT<T>::Fill expects a double*, we build it passing through a std::array.
std::array<double, sizeof...(ColumnTypes)> valuesArr{static_cast<double>(values)...};
fHistos[slot]->Fill(valuesArr.data());
}
/// This method is called at the end of the event loop. It is used to merge all the internal THnTs which
/// were used in each of the data processing slots.
void Finalize()
{
auto &res = fHistos[0];
for (auto slot : ROOT::TSeqU(1, fHistos.size())) {
res->Add(fHistos[slot].get());
}
}
std::string GetActionName(){
return "THnHelper";
}
};
void df018_customActions()
{
// We enable implicit parallelism
ROOT::EnableImplicitMT();
// We create an empty RDataFrame which contains 4 columns filled with random numbers.
// The type of the numbers held by the columns are: double, double, float, int.
ROOT::RDataFrame d(128);
auto genD = []() { return gRandom->Uniform(-5, 5); };
auto genF = [&genD]() { return (float)genD(); };
auto genI = [&genD]() { return (int)genD(); };
auto dd = d.Define("x0", genD).Define("x1", genD).Define("x2", genF).Define("x3", genI);
// Our Helper type: templated on the internal THnT type, the size, the types of the columns
// we'll use to fill.
using Helper_t = THnHelper<float, 4>;
Helper_t helper{"myThN", // Name
"A THn with 4 dimensions", // Title
{4, 4, 8, 2}, // NBins
{-10., -10, -4., -6.}, // Axes min values
{10., 10, 5., 7.}}; // Axes max values
// We book the action: it will be treated during the event loop.
auto myTHnT = dd.Book<double, double, float, int>(std::move(helper), {"x0", "x1", "x2", "x3"});
myTHnT->Print();
}