Mt 1 0 2_Read Ntuples Fill Histos And Fit

Read n-tuples in distinct workers, fill histograms, merge them and fit. Knowing that other facilities like TProcessExecutor might be more adequate for this operation, this tutorial complements mc101, reading and merging. We convey another message with this tutorial: the synergy of ROOT and STL algorithms is possible.

Author: Danilo Piparo
This notebook tutorial was automatically generated with ROOTBOOK-izer from the macro found in the ROOT repository on Wednesday, February 24, 2021 at 09:34 AM.

No nuisance for batch execution

In [1]:

Perform the operation sequentially ---------------------------------------

In [2]:
TChain inputChain("multiCore");
TH1F outHisto("outHisto", "Random Numbers", 128, -4, 4);
inputChain.Draw("r >> outHisto");
 FCN=131.373 FROM MIGRAD    STATUS=CONVERGED      55 CALLS          56 TOTAL
                     EDM=7.947e-10    STRATEGY= 1      ERROR MATRIX ACCURATE 
  EXT PARAMETER                                   STEP         FIRST   
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE 
   1  Constant     4.98626e+05   1.36735e+02   6.26274e-01  -3.17483e-08
   2  Mean        -1.22750e-04   2.23756e-04   1.25703e-06   1.77430e-01
   3  Sigma        1.00010e+00   1.58916e-04   4.42085e-07  -6.24272e-02
Info in <TCanvas::MakeDefCanvas>:  created default TCanvas with name c1

We now go mt! ------------------------------------------------------------

The first, fundamental operation to be performed in order to make root thread-aware.

In [3]:

We adapt our parallelisation to the number of input files

In [4]:
const auto nFiles = inputChain.GetListOfFiles()->GetEntries();

We define the histograms we'll fill

In [5]:
std::vector<TH1F> histograms;
auto workerIDs = ROOT::TSeqI(nFiles);
for (auto workerID : workerIDs) {
   histograms.emplace_back(TH1F(Form("outHisto_%u", workerID), "Random Numbers", 128, -4, 4));

We define our work item

In [6]:
auto workItem = [&histograms](UInt_t workerID) {
   TFile f(Form("mt101_multiCore_%u.root", workerID));
   auto ntuple = f.Get<TNtuple>("multiCore");
   auto &histo =;
   for (auto index : ROOT::TSeqL(ntuple->GetEntriesFast())) {

TH1F sumHistogram("SumHisto", "Random Numbers", 128, -4, 4);
input_line_146:2:20: error: 'histograms' cannot be captured because it does not have automatic storage duration
 auto workItem = [&histograms](UInt_t workerID) {
input_line_145:2:20: note: 'histograms' declared here
 std::vector<TH1F> histograms;

Create the collection which will hold the threads, our "pool"

In [7]:
std::vector<std::thread> workers;

Spawn workers Fill the "pool" with workers

In [8]:
for (auto workerID : workerIDs) {
   workers.emplace_back(workItem, workerID);
input_line_149:2:63: error: use of undeclared identifier 'workItem'
 (((*(std::vector<std::thread>*)0x7fb9ff324770)).emplace_back(workItem, ((*(int*)0x7fb9e5ff9dcc))))
Error in <HandleInterpreterException>: Error evaluating expression (((*(std::vector<std::thread>*)0x7fb9ff324770)).emplace_back(workItem, ((*(int*)0x7fb9e5ff9dcc)))).
Execution of your code was aborted.
Error in <TReentrantRWLock::WriteUnLock>: Write lock already released for 0x7fb9d18532c8

Now join them

In [9]:
for (auto &&worker : workers)

And reduce with a simple lambda

In [10]:
std::for_each(std::begin(histograms), std::end(histograms),
              [&sumHistogram](const TH1F &h) { sumHistogram.Add(&h); });

sumHistogram.Fit("gaus", 0);

return 0;
input_line_151:3:17: error: use of undeclared identifier 'sumHistogram'
              [&sumHistogram](const TH1F &h) { sumHistogram.Add(&h); });
input_line_151:3:48: error: use of undeclared identifier 'sumHistogram'
              [&sumHistogram](const TH1F &h) { sumHistogram.Add(&h); });
input_line_151:5:1: error: use of undeclared identifier 'sumHistogram'
sumHistogram.Fit("gaus", 0);

Draw all canvases

In [11]: