{ "cells": [ { "cell_type": "markdown", "id": "9aa72e71", "metadata": {}, "source": [ "# imt_parTreeProcessing\n", "Illustrate the usage of the TTreeProcessorMT::Process method.\n", "Such method provides an implicit parallelisation of the reading and processing of a TTree.\n", "In particular, when invoking Process, the user provides a function that iterates on a subrange\n", "of the tree via a TTreeReader. Multiple tasks will be spawned, one for each sub-range, so that\n", "the processing of the tree is parallelised. Since two invocations of the user function can\n", "potentially run in parallel, the function code must be thread safe.\n", "The example also introduces a new class, ROOT::TThreadedObject, which makes objects\n", "thread private. With the help of this class, histograms can be filled safely inside the\n", "user function and then merged at the end to get the final result.\n", "\n", "\n", "\n", "\n", "**Author:** Enric Tejedor \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:17 PM." ] }, { "cell_type": "markdown", "id": "d9acc0e0", "metadata": {}, "source": [ "First enable implicit multi-threading globally, so that the implicit parallelisation is on.\n", "The parameter of the call specifies the number of threads to use." ] }, { "cell_type": "code", "execution_count": 1, "id": "bdb10fa1", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:17:06.224838Z", "iopub.status.busy": "2026-05-19T20:17:06.224723Z", "iopub.status.idle": "2026-05-19T20:17:06.540133Z", "shell.execute_reply": "2026-05-19T20:17:06.539390Z" } }, "outputs": [], "source": [ "int nthreads = 4;\n", "ROOT::EnableImplicitMT(nthreads);" ] }, { "cell_type": "markdown", "id": "bdf4571b", "metadata": {}, "source": [ "Create one TThreadedObject per histogram to fill during the processing of the tree" ] }, { "cell_type": "code", "execution_count": 2, "id": "badb1da6", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:17:06.542248Z", "iopub.status.busy": "2026-05-19T20:17:06.542126Z", "iopub.status.idle": "2026-05-19T20:17:06.998901Z", "shell.execute_reply": "2026-05-19T20:17:06.998182Z" } }, "outputs": [], "source": [ "ROOT::TThreadedObject ptHist(\"pt_dist\", \"p_{T} Distribution;p_{T};dN/p_{T}dp_{T}\", 100, 0, 5);\n", "ROOT::TThreadedObject pzHist(\"pz_dist\", \"p_{Z} Distribution;p_{Z};dN/dp_{Z}\", 100, 0, 5);\n", "ROOT::TThreadedObject pxpyHist(\"px_py\", \"p_{X} vs p_{Y} Distribution;p_{X};p_{Y}\", 100, -5., 5., 100, -5., 5.);" ] }, { "cell_type": "markdown", "id": "9b4608f9", "metadata": {}, "source": [ "Create a TTreeProcessorMT: specify the file and the tree in it" ] }, { "cell_type": "code", "execution_count": 3, "id": "5cfab235", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:17:07.000732Z", "iopub.status.busy": "2026-05-19T20:17:07.000590Z", "iopub.status.idle": "2026-05-19T20:17:07.205184Z", "shell.execute_reply": "2026-05-19T20:17:07.204491Z" } }, "outputs": [], "source": [ "ROOT::TTreeProcessorMT tp(\"root://eospublic.cern.ch//eos/root-eos/testfiles/tp_process_imt.root\", \"events\");" ] }, { "cell_type": "markdown", "id": "74ce60aa", "metadata": {}, "source": [ "Define the function that will process a subrange of the tree.\n", "The function must receive only one parameter, a TTreeReader,\n", "and it must be thread safe. To enforce the latter requirement,\n", "TThreadedObject histograms will be used." ] }, { "cell_type": "code", "execution_count": 4, "id": "6f76dae2", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:17:07.207349Z", "iopub.status.busy": "2026-05-19T20:17:07.207229Z", "iopub.status.idle": "2026-05-19T20:17:07.409599Z", "shell.execute_reply": "2026-05-19T20:17:07.408872Z" } }, "outputs": [], "source": [ "auto myFunction = [&](TTreeReader &myReader) {\n", " TTreeReaderArray tracksRA(myReader, \"tracks\");\n", "\n", " // For performance reasons, a copy of the pointer associated to this thread on the\n", " // stack is used\n", " auto myPtHist = ptHist.Get();\n", " auto myPzHist = pzHist.Get();\n", " auto myPxPyHist = pxpyHist.Get();\n", "\n", " while (myReader.Next()) {\n", " for (auto &&track : tracksRA) {\n", " myPtHist->Fill(track.Pt(), 1. / track.Pt());\n", " myPxPyHist->Fill(track.Px(), track.Py());\n", "\n", " myPzHist->Fill(track.Pz());\n", " }\n", " }\n", "};" ] }, { "cell_type": "markdown", "id": "62205ab1", "metadata": {}, "source": [ "Launch the parallel processing of the tree" ] }, { "cell_type": "code", "execution_count": 5, "id": "5ce88ebc", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:17:07.411736Z", "iopub.status.busy": "2026-05-19T20:17:07.411599Z", "iopub.status.idle": "2026-05-19T20:17:10.891566Z", "shell.execute_reply": "2026-05-19T20:17:10.890693Z" } }, "outputs": [], "source": [ "tp.Process(myFunction);" ] }, { "cell_type": "markdown", "id": "5c074691", "metadata": {}, "source": [ "Use the TThreadedObject::Merge method to merge the thread private histograms\n", "into the final result" ] }, { "cell_type": "code", "execution_count": 6, "id": "8a1187c0", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:17:10.910453Z", "iopub.status.busy": "2026-05-19T20:17:10.910308Z", "iopub.status.idle": "2026-05-19T20:17:11.124875Z", "shell.execute_reply": "2026-05-19T20:17:11.124091Z" } }, "outputs": [], "source": [ "auto ptHistMerged = ptHist.Merge();\n", "auto pzHistMerged = pzHist.Merge();\n", "auto pxpyHistMerged = pxpyHist.Merge();\n", "\n", "return 0;" ] }, { "cell_type": "markdown", "id": "345c3a59", "metadata": {}, "source": [ "Draw all canvases " ] }, { "cell_type": "code", "execution_count": 7, "id": "33afaef2", "metadata": { "collapsed": false, "execution": { "iopub.execute_input": "2026-05-19T20:17:11.135387Z", "iopub.status.busy": "2026-05-19T20:17:11.135257Z", "iopub.status.idle": "2026-05-19T20:17:11.340517Z", "shell.execute_reply": "2026-05-19T20:17:11.339782Z" } }, "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 }