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, April 17, 2024 at 11:15 AM.
No nuisance for batch execution
gROOT->SetBatch();
Perform the operation sequentially ---------------------------------------
TChain inputChain("multiCore");
inputChain.Add("mt101_multiCore_*.root");
TH1F outHisto("outHisto", "Random Numbers", 128, -4, 4);
inputChain.Draw("r >> outHisto");
outHisto.Fit("gaus");
Warning in <Fit>: Fit data is empty
We now go MT! ------------------------------------------------------------
The first, fundamental operation to be performed in order to make ROOT thread-aware.
ROOT::EnableThreadSafety();
We adapt our parallelisation to the number of input files
const auto nFiles = inputChain.GetListOfFiles()->GetEntries();
We define the histograms we'll fill
std::vector<TH1F> histograms;
auto workerIDs = ROOT::TSeqI(nFiles);
histograms.reserve(nFiles);
for (auto workerID : workerIDs) {
histograms.emplace_back(TH1F(Form("outHisto_%u", workerID), "Random Numbers", 128, -4, 4));
}
We define our work item
auto workItem = [&histograms](UInt_t workerID) {
TFile f(Form("mt101_multiCore_%u.root", workerID));
auto ntuple = f.Get<TNtuple>("multiCore");
auto &histo = histograms.at(workerID);
for (auto index : ROOT::TSeqL(ntuple->GetEntriesFast())) {
ntuple->GetEntry(index);
histo.Fill(ntuple->GetArgs()[0]);
}
};
TH1F sumHistogram("SumHisto", "Random Numbers", 128, -4, 4);
input_line_105:2:20: error: 'histograms' cannot be captured because it does not have automatic storage duration auto workItem = [&histograms](UInt_t workerID) { ^ input_line_104:2:20: note: 'histograms' declared here std::vector<TH1F> histograms; ^
Create the collection which will hold the threads, our "pool"
std::vector<std::thread> workers;
In module 'Core': /home/sftnight/build/workspace/root-makedoc-master/rootspi/rdoc/src/master.build/include/ROOT/TSeq.hxx:79:7: warning: inline function 'ROOT::TSeq<long>::TSeq' is not defined [-Wundefined-inline] TSeq(T theEnd): fBegin(), fEnd(theEnd), fStep(1) { ^ input_line_105: note: used here In module 'Core': /home/sftnight/build/workspace/root-makedoc-master/rootspi/rdoc/src/master.build/include/ROOT/TSeq.hxx:172:16: warning: inline function 'ROOT::TSeq<long>::begin' is not defined [-Wundefined-inline] iterator begin() const { ^ input_line_105: note: used here In module 'Core': /home/sftnight/build/workspace/root-makedoc-master/rootspi/rdoc/src/master.build/include/ROOT/TSeq.hxx:175:16: warning: inline function 'ROOT::TSeq<long>::end' is not defined [-Wundefined-inline] iterator end() const { ^ input_line_105: note: used here In module 'Core': /home/sftnight/build/workspace/root-makedoc-master/rootspi/rdoc/src/master.build/include/ROOT/TSeq.hxx:109:15: warning: inline function 'ROOT::TSeq<long>::iterator::operator!=' is not defined [-Wundefined-inline] bool operator!=(const iterator &other) const { ^ input_line_105: note: used here In module 'Core': /home/sftnight/build/workspace/root-makedoc-master/rootspi/rdoc/src/master.build/include/ROOT/TSeq.hxx:125:20: warning: inline function 'ROOT::TSeq<long>::iterator::operator++' is not defined [-Wundefined-inline] iterator &operator++() { ^ input_line_105: note: used here In module 'Core': /home/sftnight/build/workspace/root-makedoc-master/rootspi/rdoc/src/master.build/include/ROOT/TSeq.hxx:101:12: warning: inline function 'ROOT::TSeq<long>::iterator::operator*' is not defined [-Wundefined-inline] T operator*() const { ^ input_line_105: note: used here In module 'Core': /home/sftnight/build/workspace/root-makedoc-master/rootspi/rdoc/src/master.build/include/ROOT/TSeq.hxx:69:12: warning: inline function 'ROOT::TSeq<long>::checkIntegralType' is not defined [-Wundefined-inline] void checkIntegralType() { ^ /home/sftnight/build/workspace/root-makedoc-master/rootspi/rdoc/src/master.build/include/ROOT/TSeq.hxx:80:10: note: used here checkIntegralType(); ^ /home/sftnight/build/workspace/root-makedoc-master/rootspi/rdoc/src/master.build/include/ROOT/TSeq.hxx:100:10: warning: inline function 'ROOT::TSeq<long>::iterator::iterator' is not defined [-Wundefined-inline] iterator(T start, T step): fCounter(start), fStep(step) {} ^ /home/sftnight/build/workspace/root-makedoc-master/rootspi/rdoc/src/master.build/include/ROOT/TSeq.hxx:173:17: note: used here return iterator(fBegin, fStep); ^
Spawn workers Fill the "pool" with workers
for (auto workerID : workerIDs) {
workers.emplace_back(workItem, workerID);
}
Now join them
for (auto &&worker : workers)
worker.join();
And reduce with a simple lambda
std::for_each(std::begin(histograms), std::end(histograms),
[&sumHistogram](const TH1F &h) { sumHistogram.Add(&h); });
sumHistogram.Fit("gaus", 0);
return 0;
input_line_109:3:17: error: use of undeclared identifier 'sumHistogram' [&sumHistogram](const TH1F &h) { sumHistogram.Add(&h); }); ^ input_line_109:3:48: error: use of undeclared identifier 'sumHistogram' [&sumHistogram](const TH1F &h) { sumHistogram.Add(&h); }); ^ input_line_109:5:1: error: use of undeclared identifier 'sumHistogram' sumHistogram.Fit("gaus", 0); ^
Draw all canvases
gROOT->GetListOfCanvases()->Draw()