Fitting multiple subranges of RooDataSet?

I am trying to fit two subranges of the same 1D data. The critical block of code is:

  RooCmdArg    *lowfitrange  = new RooCmdArg("Range", 0, 0, LowerLimit-0.1, LowerLimit+0.1, 0, 0);
  RooFitResult *lowfitres    = lowBFG.fitTo(histo, *lowfitrange);                                 
  RooCmdArg    *highfitrange = new RooCmdArg("Range", 0, 0, UpperLimit-0.1, UpperLimit+0.1, 0, 0);
  RooFitResult *highfitres   = highBFG.fitTo(histo, *highfitrange);

where lowBFG and highBFG are RooBifurGauss instances.
If I comment out either the first or second pair of lines, the remaining pair works perfectly (a good fit in the correct range results). However, if I have all four lines active, the second fit appears correct, but the first one disappears (it is essentially off the chart, but a small wild fragment is visible.)

I’m not sure how these two things could be interacting, and would be grateful for any insight.

P.S. I noticed in the documentation that there is a simple Range(double, double) syntax for specifying subranges, but I couldn’t get this to work - is there a better way than using the full RooCmdArg() syntax to create such ranges?

Hi,

To answer your second question first: If you first do a ‘using namespace RooFit’ on your ROOT command line you can use the Range() command which will greatly simplify your syntax.

Concerning your first question fitting in multiple ranges, this works best by introducing named ranges. The Range command with a numeric range specification is meant for simple use cases and is not designed to handle >1 fit with different ranges. To do what you want you can do the following

// Assuming your observable is called x
x.setRange(“low”,LowerLimit-0.1, LowerLimit+0.1) ;
x.setRange(“high”,UpperLimit-0.1, UpperLimit+0.1) ;

// Fit low range
pdf.fitTo(data,Range(“low”),…) ;

// Fit high range
pdf.fitTo(data,Range(“high”),…) ;

// FIt low+high range simultanously.
pdf.fitTo(data,Range(“low,high”),…) ;

Wouter

1 Like

Many thanks - I’m all up and running now! :smiley:

I have a similar problem and the commands are probably working for me to, but I have a problem trying to obtain the projections: they are created for the “high” region only and the fit components are scaled in a wrong way.

How to fit two sidebands and create fit projections for the whole region?

thanks
rooTest.C (3.71 KB)

Hi ‘volpig’,

I just ran your macro.

The fit actually works OK. There are some issues with combination of plotting a component and plotting in a (composite) range that give some trouble, that I will investigate.

What you can do for now is to explicitly request that the plot is made on the full range by adding a RooFit::Range(“full”) to each plotOn call. (The drawn curve is still the result of a fit in the range(s) you specified)

Wouter

Hi Wouter,
specifying the “full” interval projecting the model the range and the normalization are ok.

about the results seems like the “high” range is not used in the likelihood definition, this because the background shape is not correctly evaluated by the fit.

To test it I tried to compare the binned fit result obtained using RooFit with a standard minimization performed by ROOT using a C++ function, with almost the same starting parameters and with the same exclusion range. The ROOT performance are better, with a good evaluation of the background shape.

is this expected?

cheers, Guido


rooTest.C (5.31 KB)

Hi,

That’s not expected. I’m debugging this now, I’ll get back to you a.s.a.p.

Wouter

Hi Guido,

I’ve run your macro with all RooFit debug options on and I see that fit runs in fact correctly using both sidebands. The only issue is (remains) the normalization of the plot projection, I’ll elaborate on this in a moment.

The easiest way to see that the fit is in facto correct this is to adjust the
normalization of the plot projection as follows

model_partial.plotOn(Mass_proj,RooFit::Range(“Full”),RooFit::Normalization(0.91));
model_partial.plotOn(Mass_proj,RooFit::Range(“Full”), RooFit::Components(sgn1),RooFit::LineStyle(kDashed),RooFit::Normalization(0.91));
model_partial.plotOn(Mass_proj,RooFit::Range(“Full”),
RooFit::Components(bkg),RooFit::FillStyle(1001),
RooFit::FillColor(kGray),RooFit::Normalization(0.91));

in which case the Roofit p.d.f. projection and ROOT function projection nearly overlap. The residual small difference may be explained by the fact that your ROOT fit is a chi^2 fit and the not a LL fit in the way you set up your macro.

The reason the normalization is off is that requesting a plot over the “full” range normalizes to the total number of events in data (you can clearly see that this is the case) instead of only to those areas to which was fitted. The factor 0.91 takes
into account this discrepance. The TF1 fit handles this automatically as its extra model parameter fits for this normalization. RooFit handles normalization correctly too (i.e. it only accounts for events in the fitted ranges) for a single fitted range, but not yet for multiple range, which brings us back to the original problem.

I will fix the multiple-range awareness of plotOn() a.s.a.p

Wouter


I have only a residual question: why the normalization has to be fixed at 0.91?

I also attempted to execute the standard ROOT fit using option “L”, to use likelihood, but the comparison didn’t change.

Hi Guido,

That corrects for a ratio of range integral fractions than plotOn doesn’t apply but should have (I calculated these manually for this plot).

I have meanwhile fixed all the code related to range plotting and will commit this to SVN this morning. This fix will take care of correct plotting and normalization when plotting one or multiple subranges, as well as handling of component plotting in combination with ranges. I’ve also improved the handling of the ‘default’ plotting range for p.d.f.s that have been fitted on one or more subranges so that the plot ranges automatically maps to those fitted range(s) [ was broken for multiple ranges ].

With this fix you should be able to do

pdf.fitTo(data,Range(“low,high”)) ;

pdf.plotOn(frame) ; // will plot ranges low and high by default

and get the correct result. You can still choose a different range to be plotted using the Range() command in plotting.

I’ll reply to this posting when the code is checked in.

Wouter

Hi,

The new range handling code has now been checked in to SVN.

To use the SVN head of ROOT do
unix> svn co root.cern.ch/svn/root/trunk root
unix> cd root
unix> ./configure linux --enable-roofit ## Check platform if not linux
unix> make -jX // Where X is number of parallel processes to use for build.

I’ve attached a modified (and simplified) macro that now does the correct thing and attached a plot with the result of the new macro.

Wouter

NB: I realized later that your C++ fit example was not entirely equivalent to the corresponding RooFit implementation as the C++ version is the equivalent of an extended ML fit whereas the RooFit version was unextended. This make a subtle difference on the RooFit end how normalizations are dealt with. I have changed your RooFit ML fit into an extended ML fit and the results are now identical.



rooTest.C (5.46 KB)

Thanks for all the work, and for the solution.

Guido