After doing a fit, I want to extract s-weights. I’ve noticed that when I apply the SPlot class it changes my yields; usually, the yields change very slightly and all is well. However, if I call model.fixCoefRange('fitrange')
, the yields change dramatically and the s-weights no longer sum to 1. This is true even if the range boundaries equal that of the fit parameter.
Is there a workaround? Details below.
Here is the relevant output of a fit to 10,000 entries:
Without calling fixCoefRange
:
before SPlot:
nsig 9366.58311447
nbkg 633.425339991
after SPlot:
nsig 9366.60780824
nbkg 633.41932735
sum of s-weights for first ten entries:
1.00000294826
1.00000869212
1.00000924234
1.0000043644
1.00001065619
0.999890137275
1.00000837543
1.0000104364
1.00001060384
1.00001060553
With calling fixCoefRange
:
before SPlot:
nsig 9366.58311447
nbkg 633.425339991
after SPlot:
nsig 9899.999999
nbkg 200.00000003
sum of s-weights for first ten entries:
1.02608764932
1.03625250977
1.03716515952
1.0289045259
1.03948865788
0.585594274615
1.03572505786
1.03912948497
1.03940316514
1.03940593361
The relevant code snippets, modeled on rs301_splot.C
:
# declare fit variable
ws.factory('RooRealVar::m(5000, 6000, "MeV")')
fitvar = ws.var('m')
fitvar.setRange('fitrange', 5000, 6000)
# declare other observables
for b in coordbranches:
ws.factory('RooRealVar::{0}({1}, {2}, {3})'.format(
b.uniquenm, b.loBin, b.hiBin, b.units)
)
# get dataset (created and saved separately)
wsdata = ROOT.TFile.Open('filename').Get('myWS')
data = wsdata.data('data')
# add fit model
ws.factory('SUM::model(nsig[]..., nbkg[]...)'
ws.pdf('model').fixCoefRange('fitrange') # THIS IS THE LINE THAT MAKES THE CHANGE
# do fit
model = ws.pdf('model')
r = model.fitTo(data, RooFit.Extended(), RooFit.NumCPU(8), RooFit.Save(), RooFit.SumW2Error(True), RooFit.Range('fitrange'))
# do SPlot
nsig = ws.var('nsig')
nbkg = ws.var('nbkg')
yields = ROOT.RooArgList(nsig, nbkg)
ROOT.RooMsgService.instance().setSilentMode(True)
sData = ROOT.RooStats.SPlot('sData', 'An SPlot', data, model, yields)
ROOT.RooMsgService.instance().setSilentMode(False)