TTree::Draw integral depends on number bins (bug?)

Hello,

I am using TTree::Draw to make histograms and I found that the integral of the histogram that is produced changes depending on the number of bins in the histogram. Here is an example of what I see:

root [38] nominal->Draw("mtw>>hist1(1,0,200e3)","3.21e3*weight_btag_77*weight_pileup*weight_mc*weight_lept_eff/AMI")
(Long64_t) 3698629
root [39] nominal->Draw("mtw>>hist10(10,0,200e3)","3.21e3*weight_btag_77*weight_pileup*weight_mc*weight_lept_eff/AMI")
(Long64_t) 3698629
root [40] nominal->Draw("mtw>>hist100(100,0,200e3)","3.21e3*weight_btag_77*weight_pileup*weight_mc*weight_lept_eff/AMI")
(Long64_t) 3698629
root [41] cout<<hist1->Integral()<<endl;
588.132
root [42] cout<<hist10->Integral()<<endl;
589.498
root [43] cout<<hist100->Integral()<<endl;
589.464

What is even stranger is that the relative behavior changes if I change the weights. Here I include the additional weights XSection*FilterEff*KFactor, all of which are the same value for all events:

root [44] nominal->Draw("mtw>>hb1(1,0,200e3)","3.21e3*weight_btag_77*weight_pileup*weight_mc*weight_lept_eff*XSection*FilterEff*KFactor/AMI")
(Long64_t) 3698629
root [45] nominal->Draw("mtw>>hb10(10,0,200e3)","3.21e3*weight_btag_77*weight_pileup*weight_mc*weight_lept_eff*XSection*FilterEff*KFactor/AMI")
(Long64_t) 3698629
root [46] nominal->Draw("mtw>>hb100(100,0,200e3)","3.21e3*weight_btag_77*weight_pileup*weight_mc*weight_lept_eff*XSection*FilterEff*KFactor/AMI")
(Long64_t) 3698629
root [47] cout<<hb1->Integral()<<endl;
266867
root [48] cout<<hb10->Integral()<<endl;
266213
root [49] cout<<hb100->Integral()<<endl;
266240

Any idea what is happening and how I can fix it so that I get the correct normalization for every case?

Thanks.
~Joe

Oops, I see that the bug report should go to JIRA. Submitting this to JIRA now … ROOT-8201

Try to create your histograms in advance (and then, when drawing, do NOT specify new histogram binning):

TH1D *hist1 = new TH1D("hist1", "hist1", 1, 0, 200e3);
TH1D *hist10 = new TH1D("hist10", "hist10", 10, 0, 200e3);
TH1D *hist100 = new TH1D("hist100", "hist100", 100, 0, 200e3);
TH1D *hb1 = new TH1D("hb1", "hb1", 1, 0, 200e3);
TH1D *hb10 = new TH1D("hb10", "hb10", 10, 0, 200e3);
TH1D *hb100 = new TH1D("hb100", "hb100", 100, 0, 200e3);

Thanks for the quick feedback. I actually tried that, too, but it didn’t change anything. (I was hoping that using TH1D may be the solution, but the results were identical).

Cheers.
~Joe

How about sharing the ROOT file with your tree?

Hi,

the file in my example is 3.3GB, so I don’t want to upload it, but I will put it in my public lxplus afs space:
~jhaley/public/ttbar_inclu_pre.root

There is similar behavior with other files, but this is the one I was testing, so probably best to stick with it.

Thanks.
~Joe

{
  TDirectory *cwd = gDirectory; // we create histograms "here"
  TH1D *hist1 = new TH1D("hist1", "hist1", 1, 0, 200e3);
  TH1D *hist10 = new TH1D("hist10", "hist10", 10, 0, 200e3);
  TH1D *hist100 = new TH1D("hist100", "hist100", 100, 0, 200e3);
  TH1D *hb1 = new TH1D("hb1", "hb1", 1, 0, 200e3);
  TH1D *hb10 = new TH1D("hb10", "hb10", 10, 0, 200e3);
  TH1D *hb100 = new TH1D("hb100", "hb100", 100, 0, 200e3);
  
  TFile *f = TFile::Open("ttbar_inclu_pre.root");
  TTree *nominal; f->GetObject("nominal", nominal);
  
  cwd->cd(); // go to the directory where histograms are
  
  TCanvas *c = new TCanvas("c", "c");
  c->Divide(3, 2);
  
  TString hist_cut("3.21e3*weight_btag_77*weight_pileup*weight_mc*weight_lept_eff/AMI");
  c->cd(1); nominal->Draw("mtw>>hist1", hist_cut);
  c->cd(2); nominal->Draw("mtw>>hist10", hist_cut);
  c->cd(3), nominal->Draw("mtw>>hist100", hist_cut);
  
  std::cout << hist1->Integral() << std::endl;
  std::cout << hist10->Integral() << std::endl;
  std::cout << hist100->Integral() << std::endl;
  
  TString hb_cut("3.21e3*weight_btag_77*weight_pileup*weight_mc*weight_lept_eff*XSection*FilterEff*KFactor/AMI");
  c->cd(4); nominal->Draw("mtw>>hb1", hb_cut);
  c->cd(5); nominal->Draw("mtw>>hb10", hb_cut);
  c->cd(6); nominal->Draw("mtw>>hb100", hb_cut);
  
  std::cout << hb1->Integral() << std::endl;
  std::cout << hb10->Integral() << std::endl;
  std::cout << hb100->Integral() << std::endl;
  
  c->cd(0);
}

Hi,

Thanks, that does indeed give consistent integrals. I will try up update my code to use this approach and let you know if it still has issues.

For my information, do you know why what I was doing did not work??

Thanks.
~Joe

I have no wildest idea what you were doing.

Note: if you do not need to draw these histograms, you can use:
nominal->Project("some_existing_histo", "mtw", "some_cut");

Oh, so you were not able to reproduce the results I was getting?
Thanks.
~Joe

You can easily “reproduce” the numbers, that you show in your first post here, if you take my macro again and replace all “TH1D” with “TH1F” (histograms created by TTree::Draw are always TH1F).

I see. Thanks a lot!