Dear RooFit experts,
I am trying to implement a fit with the sum of 3 Gaussians with a 10% resolution uncertainty expressed through a single nuisance parameter (the way the resolution uncertainty is implemented is taken from the internal documentation of H→µµ analysis at CMS).
Below is my Python implementation of the model in RooFit:
# Initialize workspace and the observable variable
w = ROOT.RooWorkspace("w", False)
var = ROOT.RooRealVar("mass","",110,135)
getattr(ROOT.RooWorkspace, 'import')(w, var)
# Mean values of the Gaussians
w.factory("mean1 [125., 120., 130.]")
w.factory("mean2 [125., 120., 130.]")
w.factory("mean3 [125., 120., 130.]")
# Define the value of the uncertainty
w.factory("mu_res_unc [0.1, 0.1, 0.1]")
w.var("mu_res_unc").setConstant(True)
# Gaussian nuisance to be set in the datacard (the value is released after fit)
w.factory("mu_res_beta [0, 0, 0]")
# Width parameters with resolution uncertainty
w.factory("EXPR::width1_times_nuis('width1*(1 + mu_res_unc*mu_res_beta)',{width1[1.0, 0.5, 5.0],mu_res_unc, mu_res_beta})")
w.factory("EXPR::width2_times_nuis('width2*(1 + mu_res_unc*mu_res_beta)',{width2[5.0, 2.0, 10.],mu_res_unc, mu_res_beta})")
w.factory("EXPR::width3_times_nuis('width3*(1 + mu_res_unc*mu_res_beta)',{width3[5.0, 1.0, 10.],mu_res_unc, mu_res_beta})")
# Taking into account shift between mean values of Gaussians
w.factory("expr::deltaM21('mean2-mean1',{mean2, mean1})")
w.factory("expr::deltaM31('mean3-mean1',{mean3, mean1})")
w.factory("EXPR::mean2_final('mean2 + mu_res_unc*mu_res_beta*deltaM21',{mean2, mu_res_unc, mu_res_beta, deltaM21})")
w.factory("EXPR::mean3_final('mean3 + mu_res_unc*mu_res_beta*deltaM31',{mean3, mu_res_unc, mu_res_beta, deltaM31})")
# Gaussians
w.factory("Gaussian::gaus1(mass, mean1, width1_times_nuis)")
w.factory("Gaussian::gaus2(mass, mean2_final, width2_times_nuis)")
w.factory("Gaussian::gaus3(mass, mean3_final, width3_times_nuis)")
gaus1 = w.pdf("gaus1")
gaus2 = w.pdf("gaus2")
gaus3 = w.pdf("gaus3")
# Mixing parameters
w.factory("mix1 [0.5, 0.0, 1.0]")
w.factory("mix2 [0.5, 0.0, 1.0]")
mix1 = w.var("mix1")
mix2 = w.var("mix2")
# Summation
smodel = ROOT.RooAddPdf('smodel', 'smodel', ROOT.RooArgList(gaus1, gaus2, gaus3) , ROOT.RooArgList(mix1, mix2), ROOT.kTRUE)
# Fit the data
smodel.fitTo(data, ROOT.RooFit.Range("full"),ROOT.RooFit.Save(), ROOT.RooFit.Verbose(False))
# Fix the post-fit values of the parameters
for par in ["mean1", "mean2", "mean3", "width1", "width2", "width3", "mix1", "mix2"]:
w.var(par).setConstant(True)
# Release the nuisance parameter
w.var("mu_res_beta").setRange(-5, 5)
w.var("mu_res_beta").setVal(0)
My question is about the summation of the Gaussians:
# Summation
smodel = ROOT.RooAddPdf('smodel', 'smodel', ROOT.RooArgList(gaus1, gaus2, gaus3) , ROOT.RooArgList(mix1, mix2), ROOT.kTRUE)
According to the RooAddPdf
documentation (https://root.cern.ch/doc/master/classRooAddPdf.html), the last parameter recursiveFraction
defines whether the mixing parameters are interpreted as recursive fraction (and converted into RooRecursiveFraction), or not.
I have tried both setting recursiveFractions=ROOT.kTRUE
and recursiveFractions=ROOT.kFALSE
and I get slightly different fits: on the attached plot the red line corresponds to kTRUE
and the blue line corresponds to kFALSE
.
Can you please explain why these two options give different fits, and which option is recommended in this case?
Thanks,
Dmitry