{
"cells": [
{
"cell_type": "markdown",
"id": "57bb4cb4",
"metadata": {},
"source": [
"# df018_customActions\n",
"Implement a custom action to fill THns.\n",
"\n",
"This tutorial shows how to implement a custom action.\n",
"As an example, we build a helper for filling THns.\n",
"\n",
"\n",
"\n",
"\n",
"**Author:** Enrico Guiraud, Danilo Piparo (CERN) \n",
"This notebook tutorial was automatically generated with ROOTBOOK-izer from the macro found in the ROOT repository on Tuesday, May 19, 2026 at 08:09 PM."
]
},
{
"cell_type": "markdown",
"id": "d143f96c",
"metadata": {},
"source": [
" This is a custom action which respects a well defined interface. It supports parallelism,\n",
"in the sense that it behaves correctly if implicit multi threading is enabled.\n",
"We template it on:\n",
"- The type of the internal THnT(s)\n",
"- The dimension of the internal T\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "9b079414",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:09:52.146034Z",
"iopub.status.busy": "2026-05-19T20:09:52.145896Z",
"iopub.status.idle": "2026-05-19T20:09:52.165038Z",
"shell.execute_reply": "2026-05-19T20:09:52.164291Z"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"input_line_44:1:5: error: use of undeclared identifier 's'\n",
"HnT(s)\n",
" ^\n"
]
}
],
"source": [
"%%cpp -d\n",
"HnT(s)\n",
"// Note the plural: in presence of a MT execution, internally more than a single THnT is created.\n",
"template \n",
"class THnHelper : public ROOT::Detail::RDF::RActionImpl> {\n",
"public:\n",
" /// This is a handy, expressive shortcut.\n",
" using THn_t = THnT;\n",
" /// This type is a requirement for every helper.\n",
" using Result_t = THn_t;\n",
"\n",
"private:\n",
" std::vector> fHistos; // one per data processing slot\n",
"\n",
"public:\n",
" /// This constructor takes all the parameters necessary to build the THnTs. In addition, it requires the names of\n",
" /// the columns which will be used.\n",
" THnHelper(std::string_view name, std::string_view title, std::array nbins, std::array xmins,\n",
" std::array xmax)\n",
" {\n",
" const auto nSlots = ROOT::IsImplicitMTEnabled() ? ROOT::GetThreadPoolSize() : 1;\n",
" for (auto i : ROOT::TSeqU(nSlots)) {\n",
" fHistos.emplace_back(std::make_shared(std::string(name).c_str(), std::string(title).c_str(),\n",
" NDIM, nbins.data(), xmins.data(), xmax.data()));\n",
" (void)i;\n",
" }\n",
" }\n",
" THnHelper(THnHelper &&) = default;\n",
" THnHelper(const THnHelper &) = delete;\n",
" std::shared_ptr GetResultPtr() const { return fHistos[0]; }\n",
" void Initialize() {}\n",
" void InitTask(TTreeReader *, unsigned int) {}\n",
" /// This is a method executed at every entry\n",
" template \n",
" void Exec(unsigned int slot, ColumnTypes... values)\n",
" {\n",
" // Since THnT::Fill expects a double*, we build it passing through a std::array.\n",
" std::array valuesArr{static_cast(values)...};\n",
" fHistos[slot]->Fill(valuesArr.data());\n",
" }\n",
" /// This method is called at the end of the event loop. It is used to merge all the internal THnTs which\n",
" /// were used in each of the data processing slots.\n",
" void Finalize()\n",
" {\n",
" auto &res = fHistos[0];\n",
" for (auto slot : ROOT::TSeqU(1, fHistos.size())) {\n",
" res->Add(fHistos[slot].get());\n",
" }\n",
" }\n",
"\n",
" std::string GetActionName(){\n",
" return \"THnHelper\";\n",
" }\n",
"};"
]
},
{
"cell_type": "markdown",
"id": "d987adee",
"metadata": {},
"source": [
"We enable implicit parallelism"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "73860af5",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:09:52.166780Z",
"iopub.status.busy": "2026-05-19T20:09:52.166540Z",
"iopub.status.idle": "2026-05-19T20:09:52.480291Z",
"shell.execute_reply": "2026-05-19T20:09:52.479366Z"
}
},
"outputs": [],
"source": [
"ROOT::EnableImplicitMT();"
]
},
{
"cell_type": "markdown",
"id": "60023df7",
"metadata": {},
"source": [
"We create an empty RDataFrame which contains 4 columns filled with random numbers.\n",
"The type of the numbers held by the columns are: double, double, float, int."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "c61b26f4",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:09:52.481874Z",
"iopub.status.busy": "2026-05-19T20:09:52.481747Z",
"iopub.status.idle": "2026-05-19T20:09:53.096185Z",
"shell.execute_reply": "2026-05-19T20:09:53.095753Z"
}
},
"outputs": [],
"source": [
"ROOT::RDataFrame d(128);\n",
"auto genD = []() { return gRandom->Uniform(-5, 5); };\n",
"auto genF = [&genD]() { return (float)genD(); };\n",
"auto genI = [&genD]() { return (int)genD(); };\n",
"auto dd = d.Define(\"x0\", genD).Define(\"x1\", genD).Define(\"x2\", genF).Define(\"x3\", genI);"
]
},
{
"cell_type": "markdown",
"id": "43019602",
"metadata": {},
"source": [
"Our Helper type: templated on the internal THnT type, the size, the types of the columns\n",
"we'll use to fill."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "ab867c51",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:09:53.098644Z",
"iopub.status.busy": "2026-05-19T20:09:53.098513Z",
"iopub.status.idle": "2026-05-19T20:09:53.302700Z",
"shell.execute_reply": "2026-05-19T20:09:53.302150Z"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"input_line_55:1:18: error: no template named 'THnHelper'\n",
"using Helper_t = THnHelper;void __cling_Un1Qu320(void* vpClingValue) {\n",
" ^\n",
"input_line_55:4:1: error: unknown type name 'Helper_t'\n",
"Helper_t helper{\"myThN\", // Name\n",
"^\n"
]
}
],
"source": [
"using Helper_t = THnHelper;\n",
"\n",
"Helper_t helper{\"myThN\", // Name\n",
" \"A THn with 4 dimensions\", // Title\n",
" {4, 4, 8, 2}, // NBins\n",
" {-10., -10, -4., -6.}, // Axes min values\n",
" {10., 10, 5., 7.}}; // Axes max values"
]
},
{
"cell_type": "markdown",
"id": "79d72dc2",
"metadata": {},
"source": [
"We book the action: it will be treated during the event loop."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "ebf67eb3",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:09:53.304421Z",
"iopub.status.busy": "2026-05-19T20:09:53.304310Z",
"iopub.status.idle": "2026-05-19T20:09:53.525932Z",
"shell.execute_reply": "2026-05-19T20:09:53.518352Z"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"input_line_56:2:16: error: cannot deduce 'auto' from unknown expression\n",
" auto myTHnT = dd.Book(std::move(helper), {\"x0\", \"x1\", \"x2\", \"x3\"});\n",
" ^\n"
]
}
],
"source": [
"auto myTHnT = dd.Book(std::move(helper), {\"x0\", \"x1\", \"x2\", \"x3\"});\n",
"\n",
"myTHnT->Print();"
]
},
{
"cell_type": "markdown",
"id": "45f74605",
"metadata": {},
"source": [
"Draw all canvases "
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "2c89b4c4",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:09:53.528466Z",
"iopub.status.busy": "2026-05-19T20:09:53.528345Z",
"iopub.status.idle": "2026-05-19T20:09:53.776658Z",
"shell.execute_reply": "2026-05-19T20:09:53.754672Z"
}
},
"outputs": [],
"source": [
"gROOT->GetListOfCanvases()->Draw()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "ROOT C++",
"language": "c++",
"name": "root"
},
"language_info": {
"codemirror_mode": "text/x-c++src",
"file_extension": ".C",
"mimetype": " text/x-c++src",
"name": "c++"
}
},
"nbformat": 4,
"nbformat_minor": 5
}