/// \file /// \ingroup tutorial_multicore /// \notebook -draw /// Fill histograms in parallel with automatic binning. /// Illustrates use of power-of-two autobin algorithm /// /// \macro_code /// \macro_image /// /// \date November 2017 /// \author Gerardo Ganis // The number of workers const UInt_t nWorkers = 8U; // Reference boundaries // const Double_t xmiref = -1.; // const Double_t xmaref = 7.; Int_t mt304_fillHistos(UInt_t nNumbers = 1001) { // The first, fundamental operation to be performed in order to make ROOT // thread-aware. ROOT::EnableThreadSafety(); // Histograms to be filled in parallel // ROOT::TThreadedObject h1d("h1d", "1D test histogram", 64, 0., -1.); // ROOT::TThreadedObject h1dr("h1dr", "1D test histogram w/ ref boundaries", 64, xmiref, xmaref); TH2Poly h0; TH2Poly h0r; h0.Honeycomb(-15,-10,1,20,20); h0r.Honeycomb(-15,-10,0.5,40,40); ROOT::TThreadedObject h1d(h0); ROOT::TThreadedObject h1dr(h0r); RooWorkspace w("w0"); w.factory("PROD::model(Gaussian::xpdf(x[0,-10,10],m_x[0,-1,1],sigma_x[2,0.1,5]), Gaussian::ypdf(y[0,-10,10],m_y[0,-1,1],sigma_y[3,0.1,5]))"); w.writeToFile("tttxxx.root"); // We define our work item auto workItem = [&](UInt_t workerID) { // One generator, file and ntuple per worker // TRandom3 workerRndm(workerID); // Change the seed auto tt = std::to_string(workerID); auto tx = "_"+tt; auto wh1d = h1d.Get(); wh1d->SetBit(TH1::kAutoBinPTwo); auto wh1dr = h1dr.Get(); RooWorkspace w1(("wxx"+tx).c_str()); w1.import("tttxxx.root:w0:model",RooFit::RenameAllVariables(tt.c_str()),RooFit::RenameAllNodes(tt.c_str())); // w1.Print("v"); auto xvar = w1.var(("x"+tx).c_str()); auto yvar = w1.var(("y"+tx).c_str()); auto pdf = w1.pdf(("model"+tx).c_str()); // xvar->SetName(("x"+tx).c_str()); // yvar->SetName(("y"+tx).c_str()); // pdf->SetName(("model"+tx).c_str()); // xvar->Print("v"); // yvar->Print("v"); // pdf->Print("v"); auto data = pdf->generate(RooArgSet(*xvar,*yvar), nNumbers, RooFit::Name(("data_"+tt).c_str())); auto toy_obs = data->get(); auto toy_obs0 = dynamic_cast((*toy_obs)[0]); auto toy_obs1 = dynamic_cast((*toy_obs)[1]); for (UInt_t i = 0; i < nNumbers; ++i) { data->get(i); wh1d->Fill(toy_obs0->getVal(),toy_obs1->getVal()); wh1dr->Fill(toy_obs0->getVal(),toy_obs1->getVal()); } // auto wh1d = h1d.Get(); // wh1d->SetBit(TH1::kAutoBinPTwo); // auto wh1dr = h1dr.Get(); // // Double_t x; // for (UInt_t i = 0; i < nNumbers; ++i) { // x = workerRndm.Gaus(3.); // wh1d->Fill(x); // wh1dr->Fill(x); // } }; // Create the collection which will hold the threads, our "pool" std::vector workers; // Fill the "pool" with workers for (auto workerID : ROOT::TSeqI(nWorkers)) { workers.emplace_back(workItem, workerID); } // Now join them for (auto &&worker : workers) worker.join(); // Merge auto fh1d = h1d.Merge(); auto fh1dr = h1dr.Merge(); // Make the canvas auto c = new TCanvas("c", "c", 800, 800); c->Divide(1, 2); gStyle->SetOptStat(111110); c->cd(1); fh1d->DrawCopy(); c->cd(2); fh1dr->DrawCopy(); c->Update(); return 0; }