The idea is that one has a distribution coming either from data or Monte Carlo (called "reality" in the macro) and a nominal model that is not sufficiently flexible to take into account the real distribution. One wants to take into account the systematic associated with this imperfect modeling by augmenting the nominal model with some correction term (in this case a polynomial). The BernsteinCorrection utility will import into your workspace a corrected model given by nominal(x) * poly_N(x), where poly_N is an n-th order polynomial in the Bernstein basis. The degree N of the polynomial is chosen by specifying the tolerance one has in adding an extra term to the polynomial. The Bernstein basis is nice because it only has positive-definite terms and works well with PDFs. Finally, the macro makes a plot of:
[#0] WARNING:InputArguments -- The parameter 'sigma' with range [0, 10] of the RooGaussian 'nominal' exceeds the safe range of (0, inf). Advise to limit its range.
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing dataset realityData
[#1] INFO:ObjectHandling -- RooWorkSpace::import(myWorksspace) changing name of dataset from realityData to data
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooRealVar::x
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooGaussian::nominal
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooConstVar::0
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooRealVar::sigma
[#0] PROGRESS:Eval -- BernsteinCorrection::ImportCorrectedPdf - Doing initial Fit with nominal model
[#1] INFO:Fitting -- RooAbsPdf::fitTo(nominal_over_nominal_Int[x]) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- using generic CPU library compiled with no vectorizations
[#1] INFO:Fitting -- Creation of NLL object took 8.47406 ms
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_nominal_over_nominal_Int[x]_data) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only
[#1] INFO:Fitting -- RooAbsPdf::fitTo(corrected_over_corrected_Int[x]) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- Creation of NLL object took 189.18 μs
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_corrected_over_corrected_Int[x]_data) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only
[#1] INFO:FastEvaluations -- The class RooEffProd does not implement the faster batch evaluation interface. Consider requesting or implementing it to benefit from a speed up.
[#1] INFO:NumericIntegration -- RooRealIntegral::init(corrected_Int[x]) using numeric integrator RooIntegrator1D to calculate Int(x)
[#1] INFO:Fitting -- RooAbsPdf::fitTo(corrected_over_corrected_Int[x]) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- Creation of NLL object took 150.11 μs
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_corrected_over_corrected_Int[x]_data) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only
[#1] INFO:NumericIntegration -- RooRealIntegral::init(corrected_Int[x]) using numeric integrator RooIntegrator1D to calculate Int(x)
[#1] INFO:Fitting -- RooAbsPdf::fitTo(corrected_over_corrected_Int[x]) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- Creation of NLL object took 141.779 μs
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_corrected_over_corrected_Int[x]_data) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only
[#1] INFO:NumericIntegration -- RooRealIntegral::init(corrected_Int[x]) using numeric integrator RooIntegrator1D to calculate Int(x)
[#1] INFO:Fitting -- RooAbsPdf::fitTo(corrected_over_corrected_Int[x]) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- Creation of NLL object took 160.77 μs
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_corrected_over_corrected_Int[x]_data) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only
[#1] INFO:NumericIntegration -- RooRealIntegral::init(corrected_Int[x]) using numeric integrator RooIntegrator1D to calculate Int(x)
[#1] INFO:Fitting -- RooAbsPdf::fitTo(corrected_over_corrected_Int[x]) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- Creation of NLL object took 167.849 μs
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_corrected_over_corrected_Int[x]_data) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only
[#1] INFO:NumericIntegration -- RooRealIntegral::init(corrected_Int[x]) using numeric integrator RooIntegrator1D to calculate Int(x)
[#1] INFO:Fitting -- RooAbsPdf::fitTo(corrected_over_corrected_Int[x]) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- Creation of NLL object took 171.38 μs
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_corrected_over_corrected_Int[x]_data) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only
[#1] INFO:NumericIntegration -- RooRealIntegral::init(corrected_Int[x]) using numeric integrator RooIntegrator1D to calculate Int(x)
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooEffProd::corrected
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooBernstein::poly
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooRealVar::c_0
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooRealVar::c_1
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooRealVar::c_2
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooRealVar::c_3
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooRealVar::c_4
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooRealVar::c_5
[#1] INFO:ObjectHandling -- RooWorkspace::import(myWorksspace) importing RooRealVar::c_6
[#1] INFO:Eval -- ------ Begin Bernstein Correction Log --------
degree = 1 -log L(0) = 1216.78 -log L(1) = 1208.89 q = 15.7692 P(chi^2_1 > q) = 7.1557e-05
degree = 2 -log L(1) = 1208.89 -log L(2) = 1203.21 q = 11.3692 P(chi^2_1 > q) = 0.000746732
degree = 3 -log L(2) = 1203.21 -log L(3) = 1198.85 q = 8.72171 P(chi^2_1 > q) = 0.00314444
degree = 4 -log L(3) = 1198.85 -log L(4) = 1190.16 q = 17.3777 P(chi^2_1 > q) = 3.06393e-05
degree = 5 -log L(4) = 1190.16 -log L(5) = 1183.56 q = 13.1965 P(chi^2_1 > q) = 0.00028048
degree = 6 -log L(5) = 1183.56 -log L(6) = 1182.57 q = 1.98352 P(chi^2_1 > q) = 0.15902
------ End Bernstein Correction Log --------
Correction based on Bernstein Poly of degree 6
[#1] INFO:Fitting -- RooAbsPdf::fitTo(nominal_over_nominal_Int[x]) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- Creation of NLL object took 208.069 μs
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_nominal_over_nominal_Int[x]_realityData) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only
Minuit2Minimizer: Minimize with max-calls 500 convergence for edm < 1 strategy 1
Minuit2Minimizer : Valid minimum - status = 0
FVAL = 1216.7779341626624
Edm = 4.16187387343553302e-07
Nfcn = 19
sigma = 1.18138 +/- 0.0315451 (limited)
[#1] INFO:Fitting -- RooAbsPdf::fitTo(corrected_over_corrected_Int[x]) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- Creation of NLL object took 288.16 μs
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_corrected_over_corrected_Int[x]_realityData) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- [fitFCN] No discrete parameters, performing continuous minimization only
Minuit2Minimizer: Minimize with max-calls 3500 convergence for edm < 1 strategy 1
[#1] INFO:NumericIntegration -- RooRealIntegral::init(corrected_Int[x]) using numeric integrator RooIntegrator1D to calculate Int(x)
Minuit2Minimizer : Valid minimum - status = 0
FVAL = 1182.56856182780302
Edm = 0.000132215715224251684
Nfcn = 185
c_1 = 3.18345 +/- 0.786801 (limited)
c_2 = 4.72304e-06 +/- 3.10565 (limited)
c_3 = 1.09972e-06 +/- 1.5183 (limited)
c_4 = 0.966532 +/- 2.16598 (limited)
c_5 = 0.216431 +/- 67.8269 (limited)
c_6 = 10.4411 +/- 20.7056 (limited)
sigma = 1.26669 +/- 0.2109 (limited)
[#1] INFO:NumericIntegration -- RooRealIntegral::init(corrected_Int[x]) using numeric integrator RooIntegrator1D to calculate Int(x)
import sys
import ROOT
lowRange = -1
highRange = 5
x = ROOT.RooRealVar("x", "x", lowRange, highRange)
narrow = ROOT.RooGaussian("narrow", "", x, ROOT.RooFit.RooConst(0.0), ROOT.RooFit.RooConst(0.8))
wide = ROOT.RooGaussian("wide", "", x, ROOT.RooFit.RooConst(0.0), ROOT.RooFit.RooConst(2.0))
reality = ROOT.RooAddPdf("reality", "", [narrow, wide], ROOT.RooFit.RooConst(0.8))
data = reality.generate(x, 1000)
sigma = ROOT.RooRealVar("sigma", "", 1.0, 0, 10)
nominal = ROOT.RooGaussian("nominal", "", x, ROOT.RooFit.RooConst(0.0), sigma)
wks = ROOT.RooWorkspace("myWorksspace")
wks.Import(data, Rename="data")
wks.Import(nominal)
if ROOT.TClass.GetClass("ROOT::Minuit2::Minuit2Minimizer"):
tolerance = 0.05
bernsteinCorrection = ROOT.RooStats.BernsteinCorrection(tolerance)
degree = bernsteinCorrection.ImportCorrectedPdf(wks, "nominal", "x", "data")
if degree < 0:
ROOT.Error("rs_bernsteinCorrection", "Bernstein correction failed !")
sys.exit()
print("Correction based on Bernstein Poly of degree ", degree)
frame = x.frame()
data.plotOn(frame)
nominal.fitTo(data, PrintLevel=0)
nominal.plotOn(frame)
corrected = wks["corrected"]
if not corrected:
sys.exit()
corrected.fitTo(data, PrintLevel=0)
corrected.plotOn(frame, LineColor="r")
poly = wks["poly"]
if poly:
poly.plotOn(frame, LineColor="g", LineStyle="--")
checkSamplingDist = True
numToyMC = 20
c1 = ROOT.TCanvas()
if checkSamplingDist:
c1.Divide(1, 2)
c1.cd(1)
frame.Draw()
ROOT.gPad.Update()
if checkSamplingDist:
samplingDist = ROOT.TH1F("samplingDist", "", 20, 0, 10)
samplingDistExtra = ROOT.TH1F("samplingDistExtra", "", 20, 0, 10)
bernsteinCorrection.CreateQSamplingDist(
wks, "nominal", "x", "data", samplingDist, samplingDistExtra, degree, numToyMC
)
c1.cd(2)
samplingDistExtra.SetLineColor("kRed")
samplingDistExtra.Draw()
samplingDist.Draw("same")
c1.SaveAs("rs_bernsteinCorrection.png")
static void SetDefaultMinimizer(const char *type, const char *algo=nullptr)
Set the default Minimizer type and corresponding algorithms.
static void SetDefaultPrintLevel(int level)
Set the default Print Level.