38 using RNTupleReader = ROOT::Experimental::RNTupleReader;
39 using RNTupleWriter = ROOT::Experimental::RNTupleWriter;
40 using RNTupleDS = ROOT::Experimental::RNTupleDS;
42 constexpr
char const* kTreeFileName =
"http://root.cern.ch/files/NanoAOD_DoubleMuon_CMS2011OpenData.root";
43 constexpr
char const* kNTupleFileName =
"ntpl004_dimuon.root";
46 using ColNames_t = std::vector<std::string>;
51 template <
typename... ColumnTypes_t>
52 class RNTupleHelper :
public ROOT::Detail::RDF::RActionImpl<RNTupleHelper<ColumnTypes_t...>> {
54 using Result_t = RNTupleWriter;
56 using ColumnValues_t = std::tuple<std::shared_ptr<ColumnTypes_t>...>;
58 std::string fNTupleName;
59 std::string fRootFile;
61 ColumnValues_t fColumnValues;
62 static constexpr
const auto fNColumns = std::tuple_size<ColumnValues_t>::value;
63 std::shared_ptr<RNTupleWriter> fNTuple;
66 template<std::size_t... S>
67 void InitializeImpl(std::index_sequence<S...>) {
68 auto eventModel = ROOT::Experimental::RNTupleModel::Create();
70 std::initializer_list<int> expander{
71 (std::get<S>(fColumnValues) = eventModel->MakeField<ColumnTypes_t>(fColNames[S]), 0)...};
72 fNTuple = std::move(RNTupleWriter::Recreate(std::move(eventModel), fNTupleName, fRootFile));
75 template<std::size_t... S>
76 void ExecImpl(std::index_sequence<S...>, ColumnTypes_t... values) {
79 std::initializer_list<int> expander{(*std::get<S>(fColumnValues) = values, 0)...};
83 RNTupleHelper(std::string_view ntupleName, std::string_view rootFile,
const ColNames_t& colNames)
84 : fNTupleName(ntupleName), fRootFile(rootFile), fColNames(colNames)
86 InitializeImpl(std::make_index_sequence<fNColumns>());
89 RNTupleHelper(RNTupleHelper&&) =
default;
90 RNTupleHelper(
const RNTupleHelper&) =
delete;
91 std::shared_ptr<RNTupleWriter> GetResultPtr()
const {
return fNTuple; }
98 void InitTask(TTreeReader *,
unsigned int) {}
101 void Exec(
unsigned int slot, ColumnTypes_t... values)
104 ExecImpl(std::make_index_sequence<fNColumns>(), values...);
106 if (++fCounter % 100000 == 0)
107 std::cout <<
"Wrote " << fCounter <<
" entries" << std::endl;
112 fNTuple->CommitCluster();
115 std::string GetActionName() {
return "RNTuple Writer"; }
120 template <
typename T>
121 T InvariantMassStdVector(std::vector<T>& pt, std::vector<T>& eta, std::vector<T>& phi, std::vector<T>& mass)
123 assert(pt.size() == 2 && eta.size() == 2 && phi.size() == 2 && mass.size() == 2);
126 ROOT::RVec<float> rvPt(pt);
127 ROOT::RVec<float> rvEta(eta);
128 ROOT::RVec<float> rvPhi(phi);
129 ROOT::RVec<float> rvMass(mass);
131 return InvariantMass(rvPt, rvEta, rvPhi, rvMass);
138 ROOT::RDataFrame df(
"Events", kTreeFileName);
141 std::string typeList =
"<";
142 std::string columnList =
"{";
143 auto columnNames = df.GetColumnNames();
144 for (
auto name : columnNames) {
145 auto typeName = df.GetColumnType(name);
147 if (typeName ==
"ULong64_t")
continue;
148 columnList +=
"\"" + name +
"\",";
149 typeList += typeName +
",";
151 *columnList.rbegin() =
'}';
152 *typeList.rbegin() =
'>';
154 std::string code =
"{";
156 code +=
"auto df = std::make_unique<ROOT::RDataFrame>(\"Events\", \"" + std::string(kTreeFileName)
157 +
"\")->Range(0, 4000000);";
158 code +=
"ColNames_t colNames = " + columnList +
";";
159 code +=
"RNTupleHelper" + typeList +
" helper{\"Events\", \"" + std::string(kNTupleFileName) +
"\", colNames};";
160 code +=
"*df.Book" + typeList +
"(std::move(helper), colNames);";
163 gInterpreter->ProcessLine(code.c_str());
167 void ntpl004_dimuon() {
172 ROOT::EnableImplicitMT();
174 auto df = ROOT::Experimental::MakeNTupleDataFrame(
"Events", kNTupleFileName);
180 auto df_2mu = df.Filter(
"nMuon == 2",
"Events with exactly two muons");
181 auto df_os = df_2mu.Filter(
"Muon_charge[0] != Muon_charge[1]",
"Muons with opposite charge");
184 auto df_mass = df_os.Define(
"Dimuon_mass", InvariantMassStdVector<float>, {
"Muon_pt",
"Muon_eta",
"Muon_phi",
"Muon_mass"});
185 auto df_size = df_os.Define(
"eta_size",
"Muon_mass.size()");
188 auto h = df_mass.Histo1D({
"Dimuon_mass",
"Dimuon_mass", 30000, 0.25, 300},
"Dimuon_mass");
191 auto report = df_mass.Report();
194 gStyle->SetOptStat(0); gStyle->SetTextFont(42);
195 auto c =
new TCanvas(
"c",
"", 800, 700);
196 c->SetLogx(); c->SetLogy();
199 h->GetXaxis()->SetTitle(
"m_{#mu#mu} (GeV)"); h->GetXaxis()->SetTitleSize(0.04);
200 h->GetYaxis()->SetTitle(
"N_{Events}"); h->GetYaxis()->SetTitleSize(0.04);
203 TLatex label; label.SetNDC(
true);
204 label.DrawLatex(0.175, 0.740,
"#eta");
205 label.DrawLatex(0.205, 0.775,
"#rho,#omega");
206 label.DrawLatex(0.270, 0.740,
"#phi");
207 label.DrawLatex(0.400, 0.800,
"J/#psi");
208 label.DrawLatex(0.415, 0.670,
"#psi'");
209 label.DrawLatex(0.485, 0.700,
"Y(1,2,3S)");
210 label.DrawLatex(0.755, 0.680,
"Z");
211 label.SetTextSize(0.040); label.DrawLatex(0.100, 0.920,
"#bf{CMS Open Data}");
212 label.SetTextSize(0.030); label.DrawLatex(0.630, 0.920,
"#sqrt{s} = 8 TeV, L_{int} = 11.6 fb^{-1}");