{ "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 }