Changing the bin size of a the RooFit result

I have a template that’s made out of two datasets combined with RooAddPdf which then are fitted with another dataset as seen in this previous question. My issue is that the resulting histogram has 90 bins, and I would like it to have 30.

I’ve tried adding “RooFit::Binning(30)” to the line

totshape->plotOn(xframe,RooFit::Binning(30)); 

But that seems to do nothing, the option is completely ignored.

I considered that the bin size of the result maybe has something to do with the bin size of the two datasets used in the template, but those were created using binnedClone() on the the datasets and I didn’t find anything in the documentation regarding an option for the ammount of bins.

Here is the full code:

#include "RooFormulaVar.h"
#include "RooRealVar.h"
#include "RooDataSet.h"
#include "RooDataHist.h"
#include "RooAddPdf.h"
#include "TCanvas.h"
#include "RooPlot.h"
#include "TH1D.h"


void PtFitter()
{
  // INPUT FILE
  TString flatfile = "DATA_Upsilon_HLTDoubleMu4Acop_Run2011A_invm-8p2-140p0_EXCLSEL_nET-0_ptpair.txt";
  TString signal = "Signal1.txt";
  TString background = "Background.txt";

  // CREATING VARIABLES
  RooRealVar* PtPair = new RooRealVar("PtPair","p_{T}(#mu^{+}#mu^{-})",0.0,3.0,"GeV");
  RooRealVar* coef1 = new RooRealVar("coef1","PtPair p0",11.2,-150.0,150.0);
  RooRealVar* coef2 = new RooRealVar("coef2","PtPair p1",-20.0,-200.0,200.0);

  // CREATING DATASETS
  RooDataSet *datatmp = 0;
  RooDataSet *dataSignal = 0;
  RooDataSet *dataBackground = 0;

  // READING FILES
  datatmp = RooDataSet::read(flatfile,RooArgList(*PtPair));
  dataSignal = RooDataSet::read(signal,RooArgList(*PtPair));
  dataBackground = RooDataSet::read(background,RooArgList(*PtPair));
 
  // REMOVING BlindedState
  RooDataSet * dataSignalReduced = static_cast<RooDataSet*>(dataSignal->reduce(RooFit::SelectVars(*PtPair)));
  RooDataSet * dataBackgroundReduced = static_cast<RooDataSet*>(dataBackground->reduce(RooFit::SelectVars(*PtPair)));

  // CONVERTING HIST TO PDF
  RooDataHist *hist1 = dataSignalReduced->binnedClone();
  RooHistPdf histpdf1("histpdf1", "histpdf1", *PtPair, *hist1, 0);

  RooDataHist *hist2 = dataBackgroundReduced->binnedClone();
  RooHistPdf histpdf2("histpdf2", "histpdf2", *PtPair, *hist2, 0);

  // AddPDF
  RooAddPdf* totshape = new RooAddPdf("totshape","combined shapes",RooArgList(histpdf1,histpdf2), RooArgList(*coef1), 0);

  // FIT
  RooFitResult *fitres = totshape->fitTo(*datatmp,RooFit::FitOptions("MHTER"));
  
  // DEFINE HISTOGRAM
  TH1D* h1 = new TH1D("h1", "Signal", 30, 0, 3);
  TH1D* h2 = new TH1D("h2", "Background", 30, 0, 3);

  // FILL HISTOGRAMS WITH DATA
  ifstream infile;
  infile.open(signal);
  double tmp;
  while (infile>>tmp){
    h1->Fill(tmp);
  } 
  
  ifstream infile2;
  infile2.open(background);
  double tmp2;
  while (infile2>>tmp2){
    h2->Fill(tmp2);
  }
  
  h1->SetLineColor(2);
  h2->SetLineColor(3);
  h1->SetLineWidth(4);
  h2->SetLineWidth(4);
  
  // DRAW:
  TCanvas *c = new TCanvas("Dilepton signal","Dilepton signal",2000,1200);
  RooPlot* xframe = PtPair->frame() ;
  datatmp->plotOn(xframe,RooFit::Binning(30));
  totshape->plotOn(xframe,RooFit::Binning(30));  //RooFit option doesn't work
  
  xframe->addTH1(h2);
  xframe->addTH1(h1);
  xframe->Draw();
  
  c->SaveAs("SigPlusBGFit.png");
}

Hi @Kim_Enghusen ,

sorry for the high latency, we need @jonas 's help here, let’s ping him.

Cheers,
Enrico

Here is the plot that results from the code. The blue line is the one that I can’t seem to change the bin size. I’ve uploaded the three datasets for testing.

DATA_Upsilon_HLTDoubleMu4Acop_Run2011A_invm-8p2-140p0_EXCLSEL_nET-0_ptpair.txt (47.0 KB)
Signal1.txt (31.1 KB)
Background.txt (68.9 KB)

Hello @Kim_Enghusen,

you are right, there is no way to pass the number of bins to binnedClone(), and there is also no way to change the binning of a binned PDF a posteriori in the call to plotOn().

So what you are left to do is to create your model twice: once for the regular binning you’re using for fitting, and once for the alternative binning that you’re using for the plot. You can do this for example by using clones of the PtPair variable for building the template histograms:

#include "RooFormulaVar.h"
#include "RooRealVar.h"
#include "RooDataSet.h"
#include "RooDataHist.h"
#include "RooAddPdf.h"
#include "TCanvas.h"
#include "RooPlot.h"
#include "TH1D.h"


RooAddPdf* createShape(RooRealVar const& ptPair,
                       RooDataSet & dataSignal,
                       RooDataSet & dataBackground,
                       RooRealVar const& coef,
                       int numBins)
{
  // Create a variable clone with different binning
  auto ptPairClone = std::make_unique<RooRealVar>(ptPair);
  ptPairClone->setBins(numBins);

  // REMOVING BlindedState
  auto dataSignalReduced = static_cast<RooDataSet*>(dataSignal.reduce(RooFit::SelectVars(ptPair)));
  auto dataBackgroundReduced = static_cast<RooDataSet*>(dataBackground.reduce(RooFit::SelectVars(ptPair)));

  // CONVERTING HIST TO PDF
  auto hist1 = new RooDataHist(dataSignal.GetName(), dataSignal.GetTitle(), *ptPairClone);
  hist1->add(*dataSignalReduced);
  auto histpdf1 = new RooHistPdf("histpdf1", "histpdf1", ptPair, *hist1, 0);

  auto hist2 = new RooDataHist(dataBackground.GetName(), dataBackground.GetTitle(), *ptPairClone);
  hist2->add(*dataBackgroundReduced);
  auto histpdf2 = new RooHistPdf("histpdf2", "histpdf2", ptPair, *hist2, 0);

  RooArgList histpdfs{*histpdf1,*histpdf2};

  // AddPDF
  auto totshape = new RooAddPdf("totshape","combined shapes", histpdfs, RooArgList(coef), 0);

  totshape->addOwnedComponents(RooArgList{*ptPairClone, *histpdf1,*histpdf2});

  return totshape;
}


void PtFitter()
{
  // INPUT FILE
  TString flatfile = "DATA_Upsilon_HLTDoubleMu4Acop_Run2011A_invm-8p2-140p0_EXCLSEL_nET-0_ptpair.txt";
  TString signal = "Signal1.txt";
  TString background = "Background.txt";

  // CREATING VARIABLES
  RooRealVar* PtPair = new RooRealVar("PtPair","p_{T}(#mu^{+}#mu^{-})",0.0,3.0,"GeV");
  RooRealVar* coef1 = new RooRealVar("coef1","PtPair p0",11.2,-150.0,150.0);
  RooRealVar* coef2 = new RooRealVar("coef2","PtPair p1",-20.0,-200.0,200.0);

  // CREATING DATASETS
  RooDataSet *datatmp = 0;
  RooDataSet *dataSignal = 0;
  RooDataSet *dataBackground = 0;

  // READING FILES
  datatmp = RooDataSet::read(flatfile,RooArgList(*PtPair));
  dataSignal = RooDataSet::read(signal,RooArgList(*PtPair));
  dataBackground = RooDataSet::read(background,RooArgList(*PtPair));

  RooAddPdf* totshape = createShape(*PtPair, *dataSignal, *dataBackground, *coef1, PtPair->numBins());
  RooAddPdf* totshape30 = createShape(*PtPair, *dataSignal, *dataBackground, *coef1, 30);

  // FIT
  RooFitResult *fitres = totshape->fitTo(*datatmp,RooFit::FitOptions("MHTER"));

  // DEFINE HISTOGRAM
  TH1D* h1 = new TH1D("h1", "Signal", 30, 0, 3);
  TH1D* h2 = new TH1D("h2", "Background", 30, 0, 3);

  // FILL HISTOGRAMS WITH DATA
  ifstream infile;
  infile.open(signal);
  double tmp;
  while (infile>>tmp){
    h1->Fill(tmp);
  }

  ifstream infile2;
  infile2.open(background);
  double tmp2;
  while (infile2>>tmp2){
    h2->Fill(tmp2);
  }

  h1->SetLineColor(2);
  h2->SetLineColor(3);
  h1->SetLineWidth(4);
  h2->SetLineWidth(4);

  // DRAW:
  TCanvas *c = new TCanvas("Dilepton signal","Dilepton signal",2000,1200);
  RooPlot* xframe = PtPair->frame() ;
  datatmp->plotOn(xframe,RooFit::Binning(30));
  totshape30->plotOn(xframe);

  xframe->addTH1(h2);
  xframe->addTH1(h1);
  xframe->Draw();

  c->SaveAs("SigPlusBGFit.png");
}

Of course, this would all simplify a lot if you want to use 30 bins both for fitting and plotting. Then you can just to PtPair->setBins(30) at the beginning of your script.

Hope that gives you some ideas, let me know if you have more questions!

Jonas

1 Like

Thank you! That’s exacly what I wanted to do. Thank you for answering.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.