Normalization on a side band fit

Hello,
I’m trying to fit the side band region of a 2D data set. The region of the data distribution is at x[-10,10] and y[-10,10]. The side band is defined to be -10<x<10 and -10<y<0 using

  x.setRange("SB1",-10,+10) ;
  y.setRange("SB1",-10,0) ;

The result of the fit is correct. But when I tried to plot out the data with the pdf model withNormRange("SB1"), the normalization of the model seems to be totally wrong. How should I plot the result of a side band fit with the correct normalization?
See the attachment:



using namespace RooFit ;


void sideBandEx()
{

  // C r e a t e   2 D   p d f   a n d   d a t a 
  // -------------------------------------------

  // Define observables x,y
  RooRealVar x("x","x",-10,10) ;
  RooRealVar y("y","y",-10,10) ;

  // Construct the signal pdf gauss(x)*gauss(y)
  RooRealVar mx("mx","mx",1,-10,10) ;
  RooRealVar my("my","my",1,-10,10) ;

  RooGaussian gx("gx","gx",x,mx,RooConst(1)) ;
  RooGaussian gy("gy","gy",y,my,RooConst(1)) ;

  RooProdPdf sig("sig","sig",gx,gy) ;

  // Construct the background pdf (flat in x,y)
  RooPolynomial px("px","px",x) ;
  RooPolynomial py("py","py",y) ;
  RooProdPdf bkg("bkg","bkg",px,py) ;

  // Construct the composite model sig+bkg
  RooRealVar f("f","f",0.,1.) ;
  RooAddPdf model("model","model",RooArgList(sig,bkg),f) ;

  // Sample 10000 events in (x,y) from the model
  RooDataSet* modelData = model.generate(RooArgSet(x,y),10000) ;

  x.setRange("SB1",-10,+10) ;
  y.setRange("SB1",-10,0) ;

  RooFitResult* r_sb12 = model.fitTo(*modelData,Range("SB1"),Save()) ;

  // Plot the results
  RooPlot* frame01 = x.frame(Title("x"));
  modelData->plotOn(frame01,CutRange("SB1"));
  model.plotOn(frame01,LineColor(1),LineWidth(2),ProjectionRange("SB1"),NormRange("SB1"));
  
  RooPlot* frame02 = y.frame(Title("y"));
  modelData->plotOn(frame02,CutRange("SB1"));
  model.plotOn(frame02,LineColor(1),LineWidth(2),ProjectionRange("SB1"),NormRange("SB1"));
  

  TCanvas *c1 = new TCanvas("c1","",1);
  frame01->Draw();
  TCanvas *c2 = new TCanvas("c2","",1);
  frame02->Draw();


  r_sb12->Print() ;
  

}

The plots:

The output messages:

[#1] INFO:Minization -- RooMinimizer::optimizeConst: deactivating const optimization
[#1] INFO:Plotting -- RooTreeData::plotOn: plotting 3335 events out of 10000 total events
[#1] INFO:Plotting -- RooAbsPdf::plotOn(model) p.d.f was fitted in range and no explicit plot range was specified, using fit range as default
[#1] INFO:Plotting -- RooAbsPdf::plotOn(model) only plotting range 'fit_nll_model_modelData,fit_nll_model_modelData'
[#1] INFO:Plotting -- RooAbsPdf::plotOn(model) p.d.f. curve is normalized using explicit choice of ranges 'SB1'
[#0] WARNING:Plotting -- RooHist::getFitRangeNEvt() WARNING: Number of normalization events associated to histogram is not equal to number of events in histogram
                           due cut made in RooAbsData::plotOn() call. Automatic normalization over sub-range of plot variable assumes
                           that the effect of that cut is uniform across the plot, which may be an incorrect assumption. To be sure of
                           correct normalization explicit pass normalization information to RooAbsPdf::plotOn() call using Normalization()
[#1] INFO:Plotting -- RooAbsReal::plotOn(model) plot on x integrates over variables (y) in range SB1
[#0] ERROR:InputArguments -- RooArgSet::checkForDup: ERROR argument with name model_Int[x,y|fit_nll_model_modelData]_Norm[x,y] is already in this set
[#1] INFO:Plotting -- RooAbsReal::plotOn(model) plot on x integrates over variables (y) in range SB1
[#0] ERROR:InputArguments -- RooArgSet::checkForDup: ERROR argument with name model_Int[x,y|fit_nll_model_modelData]_Norm[x,y] is already in this set
[#1] INFO:Plotting -- RooTreeData::plotOn: plotting 3335 events out of 10000 total events
[#1] INFO:Plotting -- RooAbsPdf::plotOn(model) p.d.f was fitted in range and no explicit plot range was specified, using fit range as default
[#1] INFO:Plotting -- RooAbsPdf::plotOn(model) only plotting range 'fit_nll_model_modelData,fit_nll_model_modelData'
[#1] INFO:Plotting -- RooAbsPdf::plotOn(model) p.d.f. curve is normalized using explicit choice of ranges 'SB1'
[#0] WARNING:Plotting -- RooHist::getFitRangeNEvt() WARNING: Number of normalization events associated to histogram is not equal to number of events in histogram
                           due cut made in RooAbsData::plotOn() call. Automatic normalization over sub-range of plot variable assumes
                           that the effect of that cut is uniform across the plot, which may be an incorrect assumption. To be sure of
                           correct normalization explicit pass normalization information to RooAbsPdf::plotOn() call using Normalization()
[#1] INFO:Plotting -- RooAbsReal::plotOn(model) plot on y integrates over variables (x) in range SB1
[#0] ERROR:InputArguments -- RooArgSet::checkForDup: ERROR argument with name model_Int[x,y|fit_nll_model_modelData]_Norm[x,y] is already in this set
[#1] INFO:Plotting -- RooAbsReal::plotOn(model) plot on y integrates over variables (x) in range SB1
[#0] ERROR:InputArguments -- RooArgSet::checkForDup: ERROR argument with name model_Int[x,y|fit_nll_model_modelData]_Norm[x,y] is already in this set

Hi @andychin912,

did you try to simply use Range(...)? It should set the plotting and the norm range to the range given in (...). Maybe this is not what you want because you want to see the function in the other regions, as well.

In this case, the warning message that you posted is probably interesting:

As you can see, RooFit warns that plotting only a part of the data can lead to surprising results, because the histogram knows that it originated from N events, but it only contains M < N events. This could be the reason for the odd normalisation.

The message also tells you how to fix this.

Thank you @StephanH,

Normalization(M,  RooAbsReal::NumEvent)

solves the problem when there is only one side band.
I’m trying to define two segments of side band with

  x.setRange("SB1",-10,+10) ;
  y.setRange("SB1",-10,0) ;
  x.setRange("SB2",-10,+10) ;
  y.setRange("SB2",4,10) ;

and fit them with:

 RooFitResult* r_sb12 = model.fitTo(*modelData,Range("SB1,SB2"),Save()) ;

Then the normalization on the x dimension becomes incorrect.
Do you know what might cause this to happen?


How did you normalise this one? Explicitly or did you try to use automatic normalisation?

I guess that here you basically have to do the same trick, but instead of
M = NumEvent(SB1),
you have to use
M+N = NumEvent(SB1) + NumEvent(SB2)

Yes, I used

model.plotOn(frame,LineColor(1),LineWidth(2),ProjectionRange("SB1,SB2"),Normalization(4841,RooAbsReal::NumEvent));//In this case N+M = NumEvent(SB1) + NumEvent(SB2) = 4841

And for the x dimension the normalization failed.

I wonder if it would work without ProjectionRange. Can you try?

Nope, I removed the ProjectionRange("SB1,SB2"). It doesn’t work.

EDIT:
I just saw that we already were at this step. In dealing with other questions, I forgot that we already tried this. I will give it another try tomorrow.

Hi @andychin912,

I ran your script again and found this:

[#0] WARNING:Plotting -- RooHist::getFitRangeNEvt() WARNING: Number of normalization events associated to histogram is not equal to number of events in histogram
                           due cut made in RooAbsData::plotOn() call. Automatic normalization over sub-range of plot variable assumes
                           that the effect of that cut is uniform across the plot, which may be an incorrect assumption. To be sure of
                           correct normalization explicit pass normalization information to RooAbsPdf::plotOn() call using Normalization()

As the warning says, the automatic computation of normalisation cannot work out the number of data events. Like this I got it to work:

  // Plot the results
  RooPlot* frame01 = x.frame(Title("x"));
  modelData->plotOn(frame01,CutRange("SB1"));
  const double nData = modelData->sumEntries("", "SB1");

  // Make clear that the target normalisation is nData. The enumerator NumEvent
  // is needed to switch between relative and absolute scaling.
  model.plotOn(frame01,LineColor(1),LineWidth(2), Normalization(nData, RooAbsReal::NumEvent),
    ProjectionRange("SB1"));

  RooPlot* frame02 = y.frame(Title("y"));
  modelData->plotOn(frame02);
  
  // Here, all data are plotted. It is therefore not necessary to adapt the normalisation
  model.plotOn(frame02,LineColor(1),LineWidth(2),Range("SB1"), NormRange("SB1"));

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