Example #1
0
    def _get_mctruth_scale_and_resolution(self):
        ## Enlarge the range of the observable to get vanishing tails for
        ## the photon energy scale resolution
        # savrange = (self.phoERes.getMin(), self.phoERes.getMax())
        # self.phoERes.setRange(savrange[0] - 10, savrange[1] + 10)

        ## Build the model for the photon energy resolution.
        self.phoEResPdf = ParametrizedKeysPdf('phoEResPdf', 'phoEResPdf',
                                              self.phoERes, self.s, self.r,
                                              self.data,
                                              ROOT.RooKeysPdf.NoMirror,
                                              self.rho)
        # self.phoERes.setRange(*savrange)
        ## Set sensible initial values
        self.s.setVal(self.phoEResPdf.shapemode)
        self.r.setVal(self.phoEResPdf.shapewidth)

        ## Extract the MC truth scale and resolution from MC
        self.fitresult_mctruth = self.phoEResPdf.fitTo(
            self.data, roo.PrintLevel(self.printlevel), roo.SumW2Error(False),
            roo.Range(-50, 50), roo.Save(), roo.Strategy(2))
        self.w.Import(self.fitresult_mctruth)

        ## Store the MC truth scale and resolution
        for source, target in zip([self.s, self.r], [self.s0, self.r0]):
            target.setVal(source.getVal())
            target.setError(source.getError())
            target.setAsymError(source.getErrorLo(), source.getErrorHi())
        # self.s0.setVal(self.s.getVal())
        # self.r0.setVal(self.r.getVal())
        self.w.saveSnapshot('sr_mctruth', self.sr)
        self.w.saveSnapshot('sr0_mctruth', self.sr0)
        self.s0.setConstant(True)
        self.r0.setConstant(True)
Example #2
0
def loop_over_smearings():
    "Extract scale and resolution for mass and energy."
    ## Set initial value for the mode calculation of the phoERes shape.
    phoERes.setVal(0)
    ## Set initial value for the mode calculation of the mmgMass shape.
    mmgMass.setVal(91.2)
    ## Define then nominal model for the photon energy smearing function.
    phoEResPdf = ParametrizedKeysPdf('phoEResPdf_nominal',
                                     'phoEResPdf_nominal', phoERes,
                                     phoScale, phoRes, data,
                                     ROOT.RooKeysPdf.NoMirror, 1.5)
    ## Define the nominal mmg mass model.
    mmgMassPdf = ParametrizedKeysPdf('mmgMassPdf_nominal',
                                     'mmgMassPdf_nominal', mmgMass,
                                     massPeak, massWidth, data,
                                     ROOT.RooKeysPdf.NoMirror, 1.5)
    w.Import(phoEResPdf)
    w.Import(mmgMassPdf)
    w.Import(phoEResPdf.shape)
    w.Import(mmgMassPdf.shape)
    for i, (s, r) in enumerate(zip(stargets, rtargets)):
        ## Get the smeared data.
        phoScaleTarget.setVal(s)
        phoResTarget.setVal(r)
        sdata = calibrator.get_smeared_data(s, r)
        ## Save the smeared data in the workspace.
        sdata.SetName('sdata_%d' % i)
        sdata.SetTitle('smeared mmg data %d' % i)
        w.Import(sdata)
        ## Build the energy and mass models for each smearing since the
        ## shapes may have changed.
        ## Guess the right values of the fit parameters.
        phoScale.setVal(s)
        phoRes.setVal(phoEResPdf.shapewidth)
        massScale.setVal(100 * (mmgMassPdf.shapemode / mZ.getVal() - 1))
        massRes.setVal(100 * mmgMassPdf.shapewidth / mmgMassPdf.shapemode)
        ## Fit the models.
        phoFit = phoEResPdf.fitTo(sdata,
                                  roo.Range(-50, 50),
                                  # roo.Range(s - 5*r, s + 5*r),
                                  # roo.PrintLevel(-1),
                                  roo.Save())
        massFit = mmgMassPdf.fitTo(sdata,
                                   roo.Range(60, 120),
                                   # roo.PrintLevel(-1),
                                   roo.Save())
        ## Store results in the workspace.
        w.Import(phoFit)
        w.Import(massFit)
        w.saveSnapshot('smear_%d' % i, params, True)
Example #3
0
def plot_mmgmass_with_fit_for_multiple_smearings(name, stargets, rtargets,
                                                 colors, plotrange=(60, 105)):
    """Plot the smeared mmg mass for a number of different smearings."""
    canvases.next(name).SetGrid()
    mmgMass.setRange('plot', *plotrange)
    plot = mmgMass.frame(roo.Range('plot'))
    plot.SetTitle("")
    slabels = []
    rlabels = []
    ## Loop over the various smearings.
    for starget, rtarget, color in zip(stargets, rtargets, colors):
        mydata = calibrator.get_smeared_data(starget, rtarget)
        model = ParametrizedKeysPdf('model',
                                    'model',
                                    mmgMass, mmgMassSmearPeak,
                                    mmgMassSmearWidth, mydata,
                                    ROOT.RooKeysPdf.NoMirror, 1.5)
        model.fitTo(mydata, roo.PrintLevel(-1), roo.Range(60, 120),
                    roo.SumW2Error(False))
        mydata.plotOn(plot, roo.LineColor(color), roo.MarkerColor(color))
        model.plotOn(plot, roo.LineColor(color), roo.Range('plot'),
                     roo.NormRange('plot'))
        slabels.append([
            's\' = % 3.f %%,  ' % starget +
            '#Delta m_{#mu#mu#gamma} = %.2f #pm %.2f %%' % (
                100 * (mmgMassSmearPeak.getVal() / 91.2 - 1.),
                100 * mmgMassSmearPeak.getError() / 91.2
                ),
            ])
        rlabels.append([
            'r\' = %.1f %%,  ' % rtarget +
            '#sigma_{eff}/#mu(m_{\mu\mu\gamma}) = % .2f #pm %.2f %%' % (
                100 * mmgMassSmearWidth.getVal() / mmgMassSmearPeak.getVal(),
                100 * mmgMassSmearWidth.getError() / mmgMassSmearPeak.getVal(),
                ),
            ])
    ## End of loop over the various smearings.
    plot.Draw()
    for i, (labels, color) in enumerate(zip(slabels, colors)):
        latex = Latex(labels, position=(0.18, 0.85 - i*0.055))
        latex.SetTextColor(color)
        latex.draw()
    for i, (labels, color) in enumerate(zip(rlabels, colors)):
        latex = Latex(labels,
                      position=(0.18, 0.85 - (len(slabels)+1) * 0.055 - i*0.055))
        latex.SetTextColor(color)
        latex.draw()
Example #4
0
def plot_nominal_mmgmass_with_shape_and_fit():
    """Plot the nominal MC mmg mass data overlayed with the pdf shape and
    fit."""
    canvases.next('NominalMmgMassWithShapeAndFit')
    plot = mmgMass.frame(roo.Range(75, 105))
    plot.SetTitle("m(#mu#mu#gamma) overlayed with PDF shape (blue) "
                  "and it's parametrized fit (dashed red)")
    data.plotOn(plot)
    ## Define the mmg mass model.
    mmgMassPdf = ParametrizedKeysPdf('mmgMassPdf', 'mmgMassPdf', mmgMass,
                                     massPeak, massWidth, data,
                                     ROOT.RooKeysPdf.NoMirror, 1.5)
    ## PDF shape
    mmgMassPdf.shape.plotOn(plot)
    ## Parametrized fit of the PDF shape
    mmgMassPdf.fitTo(data, roo.Range(60, 120), roo.PrintLevel(-1))
    mmgMassPdf.plotOn(plot, roo.LineColor(ROOT.kRed),
                      roo.LineStyle(ROOT.kDashed))
    plot.Draw()
    sshape = 100 * (mmgMassPdf.shapemode / mZ.getVal() - 1)
    rshape = 100 * mmgMassPdf.shapewidth / mmgMassPdf.shapemode
    Latex([
        's_{shape}: %.3f %%' % sshape,
        's_{fit}: %.3f #pm %.3f %%' %
        (massScale.getVal(), massScale.getError()),
        's_{fit} - s_{shape}: %.4f #pm %.4f %%' %
        (massScale.getVal() - sshape, massScale.getError()),
        'r_{shape}: %.3f %%' % rshape,
        'r_{fit}: %.3f #pm %.3f %%' % (massRes.getVal(), massRes.getError()),
        'r_{fit} - r_{shape}: %.4f #pm %.4f %%' %
        (massRes.getVal() - rshape, massRes.getError()),
        'r_{fit}/r_{shape}: %.4f #pm %.4f' %
        (massRes.getVal() / rshape, massRes.getError() / rshape),
    ],
          position=(0.2, 0.8)).draw()
Example #5
0
def plot_nominal_mmgmass_with_shape_and_fit():
    """Plot the nominal MC mmg mass data overlayed with the pdf shape and
    fit."""
    canvases.next('NominalMmgMassWithShapeAndFit')
    plot = mmgMass.frame(roo.Range(75, 105))
    plot.SetTitle("m(#mu#mu#gamma) overlayed with PDF shape (blue) "
                  "and it's parametrized fit (dashed red)")
    data.plotOn(plot)
    ## Define the mmg mass model.
    mmgMassPdf = ParametrizedKeysPdf('mmgMassPdf', 'mmgMassPdf', mmgMass,
                                     massPeak, massWidth, data,
                                     ROOT.RooKeysPdf.NoMirror, 1.5)
    ## PDF shape
    mmgMassPdf.shape.plotOn(plot)
    ## Parametrized fit of the PDF shape
    mmgMassPdf.fitTo(data, roo.Range(60, 120), roo.PrintLevel(-1))
    mmgMassPdf.plotOn(plot, roo.LineColor(ROOT.kRed),
                      roo.LineStyle(ROOT.kDashed))
    plot.Draw()
    sshape = 100 * (mmgMassPdf.shapemode / mZ.getVal() - 1)
    rshape = 100 * mmgMassPdf.shapewidth / mmgMassPdf.shapemode
    Latex([
        's_{shape}: %.3f %%' % sshape,
        's_{fit}: %.3f #pm %.3f %%' % (massScale.getVal(),
                                       massScale.getError()),
        's_{fit} - s_{shape}: %.4f #pm %.4f %%' % (
            massScale.getVal() - sshape,
            massScale.getError()
            ),
        'r_{shape}: %.3f %%' % rshape,
        'r_{fit}: %.3f #pm %.3f %%' % (
            massRes.getVal(), massRes.getError()
            ),
        'r_{fit} - r_{shape}: %.4f #pm %.4f %%' % (
            massRes.getVal() - rshape,
            massRes.getError()),
        'r_{fit}/r_{shape}: %.4f #pm %.4f' % (
            massRes.getVal() / rshape,
            massRes.getError() / rshape),
        ], position=(0.2, 0.8)).draw()
Example #6
0
def plot_training_phoeres_with_shape_and_fit():
    """Plot the nominal MC photon energy smearing overlayed with the pdf shape
    and fit."""
    canvases.next('TrainingPhoEResWithShapeAndFit')
    plot = phoERes.frame(roo.Range(-7.5, 5))
    plot.SetTitle("Photon energy smearing overlayed with PDF shape (blue) "
                  "and it's parametrized fit (dashed red)")
    data.plotOn(plot)
    ## Define model for the photon energy smearing function Ereco/Etrue - 1.
    phoEResPdf = ParametrizedKeysPdf('phoEResPdf', 'phoEResPdf', phoERes,
                                     phoScale, phoRes, data,
                                     ROOT.RooKeysPdf.NoMirror, 1.5)
    ## PDF shape
    phoEResPdf.shape.plotOn(plot)
    ## Parametrized fit of the PDF shape
    phoEResPdf.fitTo(data, roo.Range(-50, 50), roo.PrintLevel(-1))
    phoEResPdf.plotOn(plot, roo.LineColor(ROOT.kRed),
                      roo.LineStyle(ROOT.kDashed))
    plot.Draw()
    Latex([
        's_{shape}: %.3f %%' % phoEResPdf.shapemode,
        's_{fit}: %.3f #pm %.3f %%' % (phoScale.getVal(), phoScale.getError()),
        's_{fit} - s_{shape}: %.4f #pm %.4f %%' %
        (phoScale.getVal() - phoEResPdf.shapemode, phoScale.getError()),
        'r_{shape}: %.3f %%' % phoEResPdf.shapewidth,
        'r_{fit}: %.3f #pm %.3f %%' % (phoRes.getVal(), phoRes.getError()),
        'r_{fit} - r_{shape}: %.4f #pm %.4f %%' %
        (phoRes.getVal() - phoEResPdf.shapewidth, phoRes.getError()),
        'r_{fit}/r_{shape}: %.4f #pm %.4f' %
        (phoRes.getVal() / phoEResPdf.shapewidth,
         phoRes.getError() / phoEResPdf.shapewidth),
    ],
          position=(0.2, 0.8)).draw()
Example #7
0
def plot_training_phoeres_with_shape_and_fit():
    """Plot the nominal MC photon energy smearing overlayed with the pdf shape
    and fit."""
    canvases.next('TrainingPhoEResWithShapeAndFit')
    plot = phoERes.frame(roo.Range(-7.5, 5))
    plot.SetTitle("Photon energy smearing overlayed with PDF shape (blue) "
                  "and it's parametrized fit (dashed red)")
    data.plotOn(plot)
    ## Define model for the photon energy smearing function Ereco/Etrue - 1.
    phoEResPdf = ParametrizedKeysPdf('phoEResPdf', 'phoEResPdf', phoERes,
                                     phoScale, phoRes, data,
                                     ROOT.RooKeysPdf.NoMirror, 1.5)
    ## PDF shape
    phoEResPdf.shape.plotOn(plot)
    ## Parametrized fit of the PDF shape
    phoEResPdf.fitTo(data, roo.Range(-50, 50), roo.PrintLevel(-1))
    phoEResPdf.plotOn(plot, roo.LineColor(ROOT.kRed),
                      roo.LineStyle(ROOT.kDashed))
    plot.Draw()
    Latex([
        's_{shape}: %.3f %%' % phoEResPdf.shapemode,
        's_{fit}: %.3f #pm %.3f %%' % (phoScale.getVal(),
                                       phoScale.getError()),
        's_{fit} - s_{shape}: %.4f #pm %.4f %%' % (
            phoScale.getVal() - phoEResPdf.shapemode,
            phoScale.getError()
            ),
        'r_{shape}: %.3f %%' % phoEResPdf.shapewidth,
        'r_{fit}: %.3f #pm %.3f %%' % (phoRes.getVal(), phoRes.getError()),
        'r_{fit} - r_{shape}: %.4f #pm %.4f %%' % (
            phoRes.getVal() - phoEResPdf.shapewidth,
            phoRes.getError()),
        'r_{fit}/r_{shape}: %.4f #pm %.4f' % (
            phoRes.getVal() / phoEResPdf.shapewidth,
            phoRes.getError() / phoEResPdf.shapewidth),
        ], position=(0.2, 0.8)).draw()
Example #8
0
def loop_over_smearings():
    "Extract scale and resolution for mass and energy."
    ## Set initial value for the mode calculation of the phoERes shape.
    phoERes.setVal(0)
    ## Set initial value for the mode calculation of the mmgMass shape.
    mmgMass.setVal(91.2)
    ## Define then nominal model for the photon energy smearing function.
    phoEResPdf = ParametrizedKeysPdf('phoEResPdf_nominal',
                                     'phoEResPdf_nominal', phoERes, phoScale,
                                     phoRes, data, ROOT.RooKeysPdf.NoMirror,
                                     1.5)
    ## Define the nominal mmg mass model.
    mmgMassPdf = ParametrizedKeysPdf('mmgMassPdf_nominal',
                                     'mmgMassPdf_nominal', mmgMass, massPeak,
                                     massWidth, data, ROOT.RooKeysPdf.NoMirror,
                                     1.5)
    w.Import(phoEResPdf)
    w.Import(mmgMassPdf)
    w.Import(phoEResPdf.shape)
    w.Import(mmgMassPdf.shape)
    for i, (s, r) in enumerate(zip(stargets, rtargets)):
        ## Get the smeared data.
        phoScaleTarget.setVal(s)
        phoResTarget.setVal(r)
        sdata = calibrator.get_smeared_data(s, r)
        ## Save the smeared data in the workspace.
        sdata.SetName('sdata_%d' % i)
        sdata.SetTitle('smeared mmg data %d' % i)
        w.Import(sdata)
        ## Build the energy and mass models for each smearing since the
        ## shapes may have changed.
        ## Guess the right values of the fit parameters.
        phoScale.setVal(s)
        phoRes.setVal(phoEResPdf.shapewidth)
        massScale.setVal(100 * (mmgMassPdf.shapemode / mZ.getVal() - 1))
        massRes.setVal(100 * mmgMassPdf.shapewidth / mmgMassPdf.shapemode)
        ## Fit the models.
        phoFit = phoEResPdf.fitTo(
            sdata,
            roo.Range(-50, 50),
            # roo.Range(s - 5*r, s + 5*r),
            # roo.PrintLevel(-1),
            roo.Save())
        massFit = mmgMassPdf.fitTo(
            sdata,
            roo.Range(60, 120),
            # roo.PrintLevel(-1),
            roo.Save())
        ## Store results in the workspace.
        w.Import(phoFit)
        w.Import(massFit)
        w.saveSnapshot('smear_%d' % i, params, True)
Example #9
0
    def _get_mctruth_scale_and_resolution(self):
        ## Enlarge the range of the observable to get vanishing tails for
        ## the photon energy scale resolution
        # savrange = (self.phoERes.getMin(), self.phoERes.getMax())
        # self.phoERes.setRange(savrange[0] - 10, savrange[1] + 10)

        ## Build the model for the photon energy resolution.
        self.phoEResPdf = ParametrizedKeysPdf(
            "phoEResPdf", "phoEResPdf", self.phoERes, self.s, self.r, self.data, ROOT.RooKeysPdf.NoMirror, self.rho
        )
        # self.phoERes.setRange(*savrange)
        ## Set sensible initial values
        self.s.setVal(self.phoEResPdf.shapemode)
        self.r.setVal(self.phoEResPdf.shapewidth)

        ## Extract the MC truth scale and resolution from MC
        self.fitresult_mctruth = self.phoEResPdf.fitTo(
            self.data,
            roo.PrintLevel(self.printlevel),
            roo.SumW2Error(False),
            roo.Range(-50, 50),
            roo.Save(),
            roo.Strategy(2),
        )
        self.w.Import(self.fitresult_mctruth)

        ## Store the MC truth scale and resolution
        for source, target in zip([self.s, self.r], [self.s0, self.r0]):
            target.setVal(source.getVal())
            target.setError(source.getError())
            target.setAsymError(source.getErrorLo(), source.getErrorHi())
        # self.s0.setVal(self.s.getVal())
        # self.r0.setVal(self.r.getVal())
        self.w.saveSnapshot("sr_mctruth", self.sr)
        self.w.saveSnapshot("sr0_mctruth", self.sr0)
        self.s0.setConstant(True)
        self.r0.setConstant(True)
Example #10
0
t1xt2func.SetName('t1xt2func')
tfunc.SetName('t')
data.addColumn(tfunc)
tfunc.SetName('tfunc')
t1xt2vtdata = data.reduce(ROOT.RooArgSet(t, t1xt2))
data = data.reduce(ROOT.RooArgSet(mmgMass, mmMass, phoERes, mmgMassPhoGenE))

##------------------------------------------------------------------------------
## Build the model fT1(t1) for log(mmgMassPhoGenE^2 - mmMass^2)
t.setRange(5, 10)
# t.setVal(8.3)
nomirror = ROOT.RooKeysPdf.NoMirror
## t1pdf = ROOT.RooKeysPdf('t1pdf', 't1pdf', t, t1data, nomirror, 1.5)
t1mode = w.factory('t1mode[8.3,5,10]')
t1width = w.factory('t1width[0.2,0.01,5]')
t1pdf = ParametrizedKeysPdf('t1pdf', 't1pdf', t, t1mode, t1width, t1data,
                            nomirror, 1.5)
t1pdf.fitTo(t1data)
t1mode.setConstant(True)
t1width.setConstant(True)
## TODO: use parametrized KEYS PDF with forced ranges and fit it to data.

## Build the model fT2(t2|s,r) for log(Ereco/Egen) ft2(t2|r,s)
t.setRange(-1, 1)
t.setVal(0)
t2pdf = LogPhoeresKeysPdf('t2pdf', 't2pdf', phoERes, t, phoScale, phoRes, data,
                          rho=1.5)

## Build the model for fT(t|s,r) = fT1(t1) * fT2(t2|s,r)
t.setRange(5, 10)
t.setBins(1000, "cache")
tpdf = ROOT.RooFFTConvPdf('tpdf', 'tpdf', t, t1pdf, t2pdf)
Example #11
0
data = dataset.get(tree=tree, weight=weight, cuts=cuts,
                   variables=[mmgMass, mmMass, phoERes,])

## Give the titles the original meaning
phoERes.SetTitle('E_{reco}^{#gamma}/E_{gen}^{#gamma} - 1')
phoERes.setUnit('%')

##------------------------------------------------------------------------------
## Build model
phoScale = w.factory('phoScale[0,-50,50]')
phoRes = w.factory('phoRes[5,0.01,50]')
range_save = (phoERes.getMin(), phoERes.getMax())
## Enlarge the range of the observable to get vanishing tails.
phoERes.setRange(-90, 150)
phoEResPdf = ParametrizedKeysPdf('phoEResPdf', 'phoEResPdf',
                                 phoERes, phoScale, phoRes, data,
                                 ROOT.RooKeysPdf.NoMirror, 1.5)
phoERes.setRange(*range_save)

##------------------------------------------------------------------------------
## Plot the phoEResPdf for various values of the scale
canvases.next('ShapeScaleScan').SetGrid()
phoRes.setVal(1)
plot = phoERes.frame(roo.Range(-10, 10))
latexlabels = []
for i, color in enumerate('Red Yellow Green Blue Black'.split()):
    scale = -4 + 2*i
    phoScale.setVal(scale)
    phoEResPdf.plotOn(plot, roo.LineColor(getattr(ROOT, 'k' + color)))
    label = Latex(['s: %d %%' % scale,],
                  position=(0.8, 0.75 - (i+1) * 0.055))
Example #12
0
    def __init__(self, name, title, mass, phos, phor, data, workspace, 
                 phostarget, phortargets, rho=1.5,
                 mirror=ROOT.RooKeysPdf.NoMirror,
                 mrangetrain=(40,140), mrangenorm=(50,130), mrangefit=(60,120)):
        '''PhosphorModel4(str name, str title, RooRealVar mass, RooRealVar phos,
            RooRealVar phor, RooDataSet data, float phostarget,
            [float] phortargets, float rho=1.5,
            int mirror=ROOT.RooKeysPdf.NoMirror)
        name - PDF name
        title - PDF title
        mass - mumugamma invariant mass (GeV), observable
        phos - photon energy scale (%), parameter
        phor - photon energy resolution (%), paramter
        data - (mmMass, mmgMass, phoERes = 100*(phoEreco/phoEgen - 1), dataset
            on which the shapes of reference PDFs are trained.
        phostarget - target reference value of the photon energy scale at which
            the model is being trained
        phortargetss - a list of target photon energy resolution values for the
            moment morphing
        rho - passed to trained RooKeysPdfs
        mirror - passed to trained RooKeysPdfs        
        '''
        ## Attach args.
        self._name = name
        self._title = title
        self._mass = mass
        self._phos = phos
        self._phor = phor
        self._data = data
        self._phostarget = phostarget
        self._phortargets = phortargets[:]
        self._rho = rho
        self._mirror = mirror
        ## Attach other attributes.
        self._massrange = (mass.getMin(), mass.getMax())
        self._sdata_list = []
        self._phostrue_list = []
        self._phortrue_list = []
        self._dlogm_dphos_list = []
        self._msubs_list = []
        self._keys_pdfs = []
        self._keys_modes = []
        self._keys_effsigmas = []
        self._keys_fitresults = []
        self._pdfs = []
        self._custs = []
        self._pdfrefs = []
        self._mrefs = []
        self._workspace = workspace
        ## self._workspace = ROOT.RooWorkspace(name + '_workspace',
        ##                                     title + ' workspace')
        w = self._workspace
        self.w = w
        ## Import important args in workspace.
        # w.Import(ROOT.RooArgSet(mass, phos, phor))
        w.Import(mass)
        w.Import(phos)
        w.Import(phor)
        w.Import(self._data)
        w.factory(
            'ConstVar::{name}_phostarget({value})'.format(
                name=name, value=self._phostarget
                )
            )
        ## Define the morphing parameter. This an identity with the
        ## photon resolution for now.
        mpar = self._mpar = w.factory(            
            'expr::{name}_mpar("{phor}", {{{phor}}})'.format(
            ## 'expr::{name}_mpar("sqrt(3^2 + {phor}^2)", {{{phor}}})'.format(
            ## 'expr::{name}_mpar("2.325+sqrt(0.4571 + (0.1608*{phor})^2)", {{{phor}}})'.format(
                name=name, phor=phor.GetName()
                )
            )
        ## Define the formula for dlog(m)/dphos.
        self._dlogm_dphos_func = w.factory('''
            expr::dlogm_dphos_func("0.5 * (1 - mmMass^2 / mmgMass^2) * mmgMass",
                                   {mmMass, mmgMass})
            ''')
        ## Get the calibrator.
        self._calibrator = MonteCarloCalibrator(self._data)
        ## Loop over target reference photon energy resolutions in phortargets.
        for index, phortarget in enumerate(self._phortargets):
            ## Store the target photon resolution value.
            w.factory(
                'ConstVar::{name}_phortarget_{index}({value})'.format(
                    name=name, index=index, value=phortarget
                    )
                )

            ## Get the corresponding smeared RooDataSet sdata named
            ##     {name}_sdata_{index} and attach it to self._sdata
            sdata = self._calibrator.get_smeared_data(
                self._phostarget, phortarget, name + '_sdata_%d' % index,
                title + ' sdata %d' % index,
                ## Get the true scale and resolution with errors. (This can be
                ##     added to the calibrator and snapshots of
                ##     self._calibrator.s and self._calibrator.r stored as
                ##     {name}_sdata_{index}_sr in self._calibrator.w)
                dofit=True
                )
            self._sdata_list.append(sdata)
            w.Import(sdata)
            phostrue = ROOT.RooRealVar(self._calibrator.s,
                                       name + '_phostrue_%d' % index)
            phortrue = ROOT.RooRealVar(self._calibrator.r,
                                       name + '_phortrue_%d' % index)
            phostrue.setConstant(True)
            phortrue.setConstant(True)
            self._phostrue_list.append(phostrue)
            self._phortrue_list.append(phortrue)
            w.Import(phostrue)
            w.Import(phortrue)            

            ## Calculate the dlogm/dphos {name}_dlogm_dphos_{index}
            ##     for the smeared dataset.
            sdata.addColumn(self._dlogm_dphos_func)
            dlogm_dphos = w.factory(
                '''
                {name}_dlogm_dphos_{index}[{mean}, 0, 1]
                '''.format(name=name, index=index,
                           mean=sdata.mean(sdata.get()['dlogm_dphos_func']))
                )
            dlogm_dphos.setConstant(True)
            self._dlogm_dphos_list.append(dlogm_dphos)

            ## Define the mass scaling {name}_msubs{i} introducing
            ##     the dependence on phos. This needs self._calibrator.s and
            ##     dlogm_dphos.
            ## msubs = w.factory(
            ##     '''
            ##     cexpr::{msubs}(
            ##         "{mass}*(1 - 0.01 * {dlogm_dphos} * ({phos} - {phostrue}))",
            ##         {{ {mass}, {dlogm_dphos}, {phos}, {phostrue} }}
            ##         )
            ##     '''.format(msubs = name + '_msubs_%d' % index,
            ##                mass = self._mass.GetName(),
            ##                dlogm_dphos = dlogm_dphos.GetName(),
            ##                phos = self._phos.GetName(),
            ##                phostrue = phostrue.GetName())
            ## )
            ## msubs = w.factory(
            ##     '''
            ##     LinearVar::{msubs}(
            ##         {mass},
            ##         expr::{slope}(
            ##             "(1 - 0.01 * {dlogm_dphos} * ({phos} - {phostrue}))",
            ##             {{ {dlogm_dphos}, {phos}, {phostrue} }}
            ##             ),
            ##         0
            ##         )
            ##     '''.format(msubs = name + '_msubs_%d' % index,
            ##                slope = name + '_msubs_slope_%d' % index,
            ##                mass = self._mass.GetName(),
            ##                dlogm_dphos = dlogm_dphos.GetName(),
            ##                phos = self._phos.GetName(),
            ##                phostrue = phostrue.GetName())
            ## )
            msubs = w.factory(
                '''
                LinearVar::{msubs}(
                    {mass}, 1,
                    expr::{offset}(
                        "- 0.01 * {dlogm_dphos} * ({phos} - {phostrue})",
                        {{ {dlogm_dphos}, {phos}, {phostrue} }}
                        )
                    )
                '''.format(msubs = name + '_msubs_%d' % index,
                           offset = name + '_msubs_offset_%d' % index,
                           mass = self._mass.GetName(),
                           dlogm_dphos = dlogm_dphos.GetName(),
                           phos = self._phos.GetName(),
                           phostrue = phostrue.GetName())
            )
            self._msubs_list.append(msubs)
            
            ## Build the corresponding parametrized KEYS PDF {name}_kyes_{index}
            ##     with {name}_keys_mode_{index} and
            ##     {name}_keys_effsigma_{index}.
            keys_mode = w.factory(
                '{name}_keys_mode_{index}[91.2, 60, 120]'.format(
                    name=name, index=index
                    )
                )
            keys_effsigma = w.factory(
                '{name}_keys_effsigma_{index}[3, 0.1, 60]'.format(
                    name=name, index=index
                    )
                )
            mass.setRange(*mrangetrain)
            keys_pdf = ParametrizedKeysPdf(name + '_keys_pdf_%d' % index,
                                           name + '_keys_pdf_%d' % index,
                                           mass, keys_mode, keys_effsigma,
                                           sdata)
            self._keys_modes.append(keys_mode)
            self._keys_effsigmas.append(keys_effsigma)
            self._keys_pdfs.append(keys_pdf)
                                       
            ## Fit the KEYS PDF to the training data and save the result
            ##     {name}_keys_fitresult_{index} and parameter snapshots
            ##     {name}_keys_mctrue_{index}.
            mass.setRange(*mrangenorm)
            keys_fitresult = keys_pdf.fitTo(sdata, roo.Range(*mrangefit),
                                            roo.Strategy(2), roo.NumCPU(8),
                                            roo.Save(True))
            self._keys_fitresults.append(keys_fitresult)
            w.Import(keys_fitresult, name + '_keys_fitresult_%d' % index)
            w.saveSnapshot(name + '_mctrue_%d' % index,
                           ','.join([phostrue.GetName(),
                                     phortrue.GetName(),
                                     keys_mode.GetName(),
                                     keys_effsigma.GetName()]))
            
            ## Sample the fitted KEYS PDF to a histogram {name}_hist_{index}.
            mass.setRange(*mrangetrain)
            hist = keys_pdf.createHistogram(name + '_hist_%d' % index,
                                            mass, roo.Binning(1000))

            ## Build a RooDataHist {name}_dhist{index} of the sampled histogram.
            dhist = ROOT.RooDataHist(name + '_dhist_%d' % index,
                                     name + '_dhist_%d' % index,
                                     ROOT.RooArgList(mass), hist)
            w.Import(dhist)
            
            ## Build a RooHistPdf {name}_pdf_{index} using the dhist and msubs.
            ## pdf = w.factory(
            ##     'HistPdf::{name}({{{msubs}}}, {{{mass}}}, {dhist}, 1)'.format(
            ##         name = name + '_pdf_%d' % index, msubs = msubs.GetName(),
            ##         mass = mass.GetName(), dhist = dhist.GetName()
            ##         )
            ##     )
            pdf = w.factory(
                'HistPdf::{name}({{{mass}}}, {dhist}, 1)'.format(
                    name = name + '_pdf_%d' % index, msubs = msubs.GetName(),
                    mass = mass.GetName(), dhist = dhist.GetName()
                    )
                )
            self._pdfs.append(pdf)
            mass.setRange(*self._massrange)

            ## Supstitute for mass using customizer.
            cust = ROOT.RooCustomizer(pdf, 'msubs_%d' % index)
            self._custs.append(cust)
            cust.replaceArg(mass, msubs)
            pdfref = cust.build()
            pdfref.addOwnedComponents(ROOT.RooArgSet(msubs))
            pdfref.SetName(name + '_pdfref_%d' % index)
            pdfref.SetTitle(name + '_pdfref_%d' % index)
            w.Import(pdfref)
            self._pdfrefs.append(pdfref)
            
            ## Calculate morphing parameter reference values float mref[index].
            phorval = phor.getVal()
            phor.setVal(phortrue.getVal())
            self._mrefs.append(mpar.getVal())
            phor.setVal(phorval)
        ## End of loop over target phortargets

        ## Define the RooMomentMorph model.
        model = w.factory(
            '''
            MomentMorph::{name}({mpar}, {{{mass}}}, {{{pdfs}}}, {{{mrefs}}})
            '''.format(name=name, mpar=mpar.GetName(), mass=mass.GetName(),
                       pdfs=','.join([f.GetName() for f in self._pdfs]),
                       # pdfs=','.join([f.GetName() for f in self._pdfrefs]),
                       mrefs=','.join([str(m) for m in self._mrefs]))
            )
        
        ## Quick hack to make things work.
        cust = ROOT.RooCustomizer(model, 'msub')
        cust.replaceArg(mass, self._msubs_list[0])
        model2 = cust.build()
        
        ROOT.RooMomentMorph.__init__(self, model2)
        self.SetName(name)
        self.SetTitle(title)
Example #13
0
##------------------------------------------------------------------------------
init()
get_data()

fitdata = calibrator.get_smeared_data(sfit, rfit)
traindata = calibrator.get_smeared_data(strain, rtrain)

## Get x
traindata.addColumn(xfunc)
xmean.setVal(traindata.mean(traindata.get()['xfunc']))
xmean.setConstant()

mmgMassPdf = ParametrizedKeysPdf('mmgMassPdf', 'mmgMassPdf',
                                 mmgMass, mmgMassPeak,
                                 mmgMassWidth, traindata,
                                 ROOT.RooKeysPdf.NoMirror, 1.5,
                                 forcerange=True)

calibrator.phoEResPdf.fitTo(traindata, roo.Range(-50, 50), roo.Strategy(2),
                            roo.SumW2Error(True))

mmgMass.setRange(50, 130)
mmgMassPdf.fitTo(data, roo.Range(60,120), roo.SumW2Error(True))

phoEResPdf = ParametrizedKeysPdf('phoEResPdf', 'phoEResPdf',
                                 phoERes, phoScaleTrue, phoResTrue, data,
                                 ROOT.RooKeysPdf.NoMirror, 1.5)

phoEResPdf2 = ParametrizedNDKeysPdf('phoEResPdf2', 'phoEResPdf2',
                                    phoERes, phoScaleTrue, phoResTrue, data,
Example #14
0
class MonteCarloCalibrator:
    def __init__(self, data, printlevel=-1, rho=1.5):
        self.w = ROOT.RooWorkspace('mccworkspace',
                                   'MonteCarloCalibrator Workspace')
        self.datarow = ROOT.RooArgSet()
        for x in 'mmMass mmgMass phoERes'.split():
            setattr(self, x, data.get()[x])
            self.datarow.add(data.get()[x])
            # self.w.Import(getattr(self, x))
        self.data = data.reduce(self.datarow)
        self.data.SetName('data')
        self.rho = rho
        self.w.Import(data)

        self.printlevel = printlevel

        ## Define reference (0) and target scale (s) and resolution (r)
        self.s0 = self.w.factory('s0[0, -50, 50]')
        self.r0 = self.w.factory('r0[1, 0.01, 50]')
        self.s = self.w.factory('s[0, -50, 50]')
        self.r = self.w.factory('r[1, 0.01, 50]')
        for x in 's0 r0 s r'.split():
            getattr(self, x).setUnit('%')

        ## Define a set of the fit and reference parameters,
        ## store them in the workspace.
        self.sr = ROOT.RooArgSet(self.s, self.r)
        self.sr0 = ROOT.RooArgSet(self.s0, self.r0)
        self.w.defineSet('fit', self.sr)
        self.w.defineSet('ref', self.sr0)
        self.w.saveSnapshot('sr_init', self.sr, True)
        self.w.saveSnapshot('sr0_init', self.sr0, True)

        self._get_mctruth_scale_and_resolution()
        self._define_smearing_functions()

    ## end of __init__

    def _get_mctruth_scale_and_resolution(self):
        ## Enlarge the range of the observable to get vanishing tails for
        ## the photon energy scale resolution
        # savrange = (self.phoERes.getMin(), self.phoERes.getMax())
        # self.phoERes.setRange(savrange[0] - 10, savrange[1] + 10)

        ## Build the model for the photon energy resolution.
        self.phoEResPdf = ParametrizedKeysPdf('phoEResPdf', 'phoEResPdf',
                                              self.phoERes, self.s, self.r,
                                              self.data,
                                              ROOT.RooKeysPdf.NoMirror,
                                              self.rho)
        # self.phoERes.setRange(*savrange)
        ## Set sensible initial values
        self.s.setVal(self.phoEResPdf.shapemode)
        self.r.setVal(self.phoEResPdf.shapewidth)

        ## Extract the MC truth scale and resolution from MC
        self.fitresult_mctruth = self.phoEResPdf.fitTo(
            self.data, roo.PrintLevel(self.printlevel), roo.SumW2Error(False),
            roo.Range(-50, 50), roo.Save(), roo.Strategy(2))
        self.w.Import(self.fitresult_mctruth)

        ## Store the MC truth scale and resolution
        for source, target in zip([self.s, self.r], [self.s0, self.r0]):
            target.setVal(source.getVal())
            target.setError(source.getError())
            target.setAsymError(source.getErrorLo(), source.getErrorHi())
        # self.s0.setVal(self.s.getVal())
        # self.r0.setVal(self.r.getVal())
        self.w.saveSnapshot('sr_mctruth', self.sr)
        self.w.saveSnapshot('sr0_mctruth', self.sr0)
        self.s0.setConstant(True)
        self.r0.setConstant(True)

    ## end of _get_mctruth_scale_and_resolution

    def _define_smearing_functions(self):
        ## Define the smearing formulas for photon energy and mmg invariant mass
        # self.phoEResSmear = w.factory('phoEResSmear[-100,200]')
        self.phoEResSmear = self.w.factory('''expr::phoEResSmear(
            "s + r * (phoERes - s0) / r0",
            {phoERes, s, r, s0, r0}
            )''')

        # self.mmgMassSmear = w.factory('mmgMassSmear[0, 200]')
        self.mmgMassSmear = self.w.factory('''expr::mmgMassSmear(
            "sqrt({m2} + (1 + 0.01 * {f}) / (1 + 0.01 * {f0}) * ({M2} - {m2}))",
            {{{m}, {M}, {f}, {f0}}}
            )'''.format(m='mmMass',
                        m2='mmMass*mmMass',
                        M='mmgMass',
                        M2='mmgMass*mmgMass',
                        f='phoEResSmear',
                        f0='phoERes'))

    ## end of _define_smearing_functions

    def _reduce_and_rename(self, oldname, newname):
        ## Remove the ranges from the oldvar.
        oldvar = self.data.get()[oldname]
        oldvar.removeMin()
        oldvar.removeMax()
        ## Drop everything except the oldvar.
        newdata = self.data.reduce(ROOT.RooArgSet(oldvar))
        ## Define the renaming identity newvar = oldvar
        newfunc = ROOT.RooFormulaVar(newname, newname, oldname,
                                     ROOT.RooArgList(oldvar))
        ## Add a column with the identical values but with the new name
        newvar = newdata.addColumn(newfunc)
        ## New data now contains two columns of identical values, one labeled
        ## with the old name and the other with the new name. Keep only the one
        ## with the new name.
        return newdata.reduce(ROOT.RooArgSet(newvar))

    ## end of _reduce_and_rename

    def _fit_smeared_data(self, name):
        'Fit the current smeared data to get the smeared s and r.'
        self.fitresult_sdata = self.phoEResPdf.fitTo(
            self.sdata, roo.PrintLevel(self.printlevel), roo.SumW2Error(False),
            roo.Range(-50, 50), roo.Save(), roo.Strategy(2))
        self.w.saveSnapshot(name + '_sr', self.sr)
        self.w.Import(self.fitresult_sdata, name + '_fitresult')

    ## end of _fit_smeared_data()

    def get_smeared_data(self,
                         starget,
                         rtarget,
                         name='default',
                         title='default',
                         dofit=False):
        if name == 'default':
            name = self.data.GetName() + '_smeared'
        if title == 'default':
            title = self.data.GetTitle() + ' smeared'
        ## Make sure that the reference scale and resolution
        ## are equal to the MC truth.
        self.w.loadSnapshot('sr0_mctruth')
        ## Check if any of the parameters is to be set to the nominal values.
        if starget == 'nominal':
            starget = self.s0.getVal()
        if rtarget == 'nominal':
            rtarget = self.r0.getVal()
        self.s.setVal(starget)
        self.r.setVal(rtarget)
        ## Make sure that the reference scale and resolution
        ## are equal to the MC truth.
        self.w.loadSnapshot('sr0_mctruth')
        ## Calculate the smeared photon energy resolution and mmg mass.
        self.data.addColumn(self.phoEResSmear)
        self.data.addColumn(self.mmgMassSmear)
        ## Build a new dataset with the smeared data
        self.sdata = self.data.reduce(ROOT.RooArgSet(self.mmMass))
        self.sdata.merge(self._reduce_and_rename('phoEResSmear', 'phoERes'))
        self.sdata.merge(self._reduce_and_rename('mmgMassSmear', 'mmgMass'))
        ## Drop the smearing variables from the nominal data
        self.data = self.data.reduce(
            ROOT.RooArgSet(self.mmgMass, self.mmMass, self.phoERes))
        ## Set the name and title of the smeared data.
        self.sdata.SetName(name)
        self.sdata.SetTitle(title)
        ## Fit the smeared data
        if dofit:
            self._fit_smeared_data(name)
        ## Return the smeared data
        return self.sdata
Example #15
0
## Give the titles the original meaning
phoERes.SetTitle('E_{reco}^{#gamma}/E_{gen}^{#gamma} - 1')
phoERes.setUnit('%')

##------------------------------------------------------------------------------
## Build model
phoScale = w.factory('phoScale[0,-50,50]')
phoRes = w.factory('phoRes[5,0.01,50]')

for x in [phoScale, phoRes]:
    x.setUnit('%')

range_save = (phoERes.getMin(), phoERes.getMax())
## Enlarge the range of the observable to get vanishing tails.
phoERes.setRange(-90, 150)
phoEResPdf = ParametrizedKeysPdf('phoEResPdf', 'phoEResPdf', phoERes, phoScale,
                                 phoRes, data, ROOT.RooKeysPdf.NoMirror, 1.5)
phoERes.setRange(*range_save)

##------------------------------------------------------------------------------
## Extract the MC truth scale and resolution from MC
phoEResPdf.fitTo(data, roo.PrintLevel(-1), roo.SumW2Error(False))
phoScaleRef = phoScale.getVal()
phoResRef = phoRes.getVal()

##------------------------------------------------------------------------------
## Define the smearing formulas for photon energy and mmg invariant mass
phoEResSmear = w.factory('phoEResSmear[-100,200]')
phoEResSmearFunc = w.factory('''expr::phoEResSmearFunc(
    "{m} + {s} * ({x} - {m0}) / {s0}",
    {{{x}}}
    )'''.format(x='phoERes',
Example #16
0
phoERes.setRange(*range_save)

## Get the smeared data
sdata = calibrator.get_smeared_data(targets, targetr)

## Get the parametrized model for the photon energy resolution
phoEResPdf = calibrator.phoEResPdf
phoScale = calibrator.s
phoRes = calibrator.r
calibrator.w.loadSnapshot('sr0_mctruth')
phoScaleRef = calibrator.s0.getVal()
phoResRef = calibrator.r0.getVal()

## Get the parametrized model for the mmg mass
mmgMassPdf = ParametrizedKeysPdf('mmgMassPdf', 'mmgMassPdf',
                                 mmgMass, mmgMassPeak,
                                 mmgMassWidth, data,
                                 ROOT.RooKeysPdf.NoMirror, 1.5)
mmgMassPdf.fitTo(data, roo.Range(60,120), roo.SumW2Error(False))

## Get the parametrized model for the smeared mmg mass
mmgMass.Print()
mmgMassSmearPdf = ParametrizedKeysPdf('mmgMassSmearPdf', 'mmgMassSmearPdf',
                                      mmgMass, mmgMassSmearPeak,
                                      mmgMassSmearWidth, sdata,
                                      ROOT.RooKeysPdf.NoMirror, 1.5)
mmgMassSmearPdf.fitTo(sdata, roo.Range(60,120), roo.SumW2Error(False))

##------------------------------------------------------------------------------
def plot_training_phoeres_with_shape_and_fit():
    """Plot the nominal MC data overlayed with the pdf shape and fit."""
    canvases.next('TrainingSampleWithShapeAndFit')
Example #17
0
    canvases.update()
    sw.Stop()
    print 'CPU time:', sw.CpuTime(), 's, real time:', sw.RealTime(), 's'


## End of main()

##------------------------------------------------------------------------------
sw = ROOT.TStopwatch()
sw.Start()

init()
get_data()

phoEResPdf = ParametrizedKeysPdf('phoEResPdf', 'phoEResPdf', phoERes, phoScale,
                                 phoRes, data, ROOT.RooKeysPdf.NoMirror, 1.5)

phoEResPdf.fitTo(data, roo.Range(-50, 50))

canvases.next('phoEResPdf').SetGrid()
plot = phoERes.frame(roo.Range(-10, 10))
data.plotOn(plot)
phoEResPdf.plotOn(plot)
phoEResPdf.paramOn(plot)
plot.Draw()

t = w.factory('t[0,-1,1]')
t.SetTitle('log(E_{reco}^{#gamma}/E_{gen}^{#gamma})')
tfunc = w.factory('expr::tfunc("log(0.01 * phoERes + 1)", {phoERes})')
tfunc.SetName('t')
data.addColumn(tfunc)
Example #18
0
    def __init__(self,
                 name,
                 title,
                 mass,
                 phos,
                 phor,
                 data,
                 workspace,
                 phostarget,
                 phortargets,
                 rho=1.5,
                 mirror=ROOT.RooKeysPdf.NoMirror,
                 mrangetrain=(40, 140),
                 mrangenorm=(50, 130),
                 mrangefit=(60, 120)):
        '''PhosphorModel4(str name, str title, RooRealVar mass, RooRealVar phos,
            RooRealVar phor, RooDataSet data, float phostarget,
            [float] phortargets, float rho=1.5,
            int mirror=ROOT.RooKeysPdf.NoMirror)
        name - PDF name
        title - PDF title
        mass - mumugamma invariant mass (GeV), observable
        phos - photon energy scale (%), parameter
        phor - photon energy resolution (%), paramter
        data - (mmMass, mmgMass, phoERes = 100*(phoEreco/phoEgen - 1), dataset
            on which the shapes of reference PDFs are trained.
        phostarget - target reference value of the photon energy scale at which
            the model is being trained
        phortargetss - a list of target photon energy resolution values for the
            moment morphing
        rho - passed to trained RooKeysPdfs
        mirror - passed to trained RooKeysPdfs        
        '''
        ## Attach args.
        self._name = name
        self._title = title
        self._mass = mass
        self._phos = phos
        self._phor = phor
        self._data = data
        self._phostarget = phostarget
        self._phortargets = phortargets[:]
        self._rho = rho
        self._mirror = mirror
        ## Attach other attributes.
        self._massrange = (mass.getMin(), mass.getMax())
        self._sdata_list = []
        self._phostrue_list = []
        self._phortrue_list = []
        self._dm_dphos_list = []
        self._msubs_list = []
        self._keys_pdfs = []
        self._keys_modes = []
        self._keys_effsigmas = []
        self._keys_fitresults = []
        self._pdfs = []
        self._custs = []
        # self._pdfrefs = []
        self._mrefs = []
        self._phormorphs = []
        self._phorhists = []
        self._workspace = workspace
        ## self._workspace = ROOT.RooWorkspace(name + '_workspace',
        ##                                     title + ' workspace')
        w = self._workspace
        self.w = w
        ## Import important args in workspace.
        # w.Import(ROOT.RooArgSet(mass, phos, phor))
        w.Import(mass)
        w.Import(phos)
        w.Import(phor)
        w.Import(self._data)
        w.factory('ConstVar::{name}_phostarget({value})'.format(
            name=name, value=self._phostarget))
        ## Define the morphing parameter. This an identity with the
        ## photon resolution for now.
        mpar = self._mpar = w.factory(
            'expr::{name}_mpar("{phor}", {{{phor}}})'.format(
                ## 'expr::{name}_mpar("2 + sqrt(0.5^2 + 0.05 * {phor}^2)", {{{phor}}})'.format(
                ## 'expr::{name}_mpar("2.325+sqrt(0.4571 + (0.1608*{phor})^2)", {{{phor}}})'.format(
                name=name,
                phor=phor.GetName()))
        ## Define the formula for dlog(m)/dphos.
        self._dm_dphos_func = w.factory('''
            expr::dm_dphos_func("0.5 * (1 - mmMass^2 / mmgMass^2) * mmgMass",
                                   {mmMass, mmgMass})
            ''')
        ## Get the calibrator.
        self._calibrator = MonteCarloCalibrator(self._data)
        ## Loop over target reference photon energy resolutions in phortargets.
        for index, phortarget in enumerate(self._phortargets):
            ## Store the target photon resolution value.
            w.factory('ConstVar::{name}_phortarget_{index}({value})'.format(
                name=name, index=index, value=phortarget))

            ## Get the corresponding smeared RooDataSet sdata named
            ##     {name}_sdata_{index} and attach it to self._sdata
            sdata = self._calibrator.get_smeared_data(
                self._phostarget,
                phortarget,
                name + '_sdata_%d' % index,
                title + ' sdata %d' % index,
                ## Get the true scale and resolution with errors. (This can be
                ##     added to the calibrator and snapshots of
                ##     self._calibrator.s and self._calibrator.r stored as
                ##     {name}_sdata_{index}_sr in self._calibrator.w)
                dofit=True)
            self._sdata_list.append(sdata)
            w.Import(sdata)
            phostrue = ROOT.RooRealVar(self._calibrator.s,
                                       name + '_phostrue_%d' % index)
            phortrue = ROOT.RooRealVar(self._calibrator.r,
                                       name + '_phortrue_%d' % index)
            phostrue.setConstant(True)
            phortrue.setConstant(True)
            self._phostrue_list.append(phostrue)
            self._phortrue_list.append(phortrue)
            w.Import(phostrue)
            w.Import(phortrue)

            ## Calculate the dlogm/dphos {name}_dm_dphos_{index}
            ##     for the smeared dataset.
            sdata.addColumn(self._dm_dphos_func)
            dm_dphos = w.factory('''
                {name}_dm_dphos_{index}[{mean}, 0, 1]
                '''.format(name=name,
                           index=index,
                           mean=sdata.mean(sdata.get()['dm_dphos_func'])))
            dm_dphos.setConstant(True)
            self._dm_dphos_list.append(dm_dphos)

            ## Define the mass scaling {name}_msubs{i} introducing
            ##     the dependence on phos. This needs self._calibrator.s and
            ##     dm_dphos.
            ## msubs = w.factory(
            ##     '''
            ##     LinearVar::{msubs}(
            ##         {mass}, 1,
            ##         expr::{offset}(
            ##             "- 0.01 * {dm_dphos} * ({phos} - {phostrue})",
            ##             {{ {dm_dphos}, {phos}, {phostrue} }}
            ##             )
            ##         )
            ##     '''.format(msubs = name + '_msubs_%d' % index,
            ##                offset = name + '_msubs_offset_%d' % index,
            ##                mass = self._mass.GetName(),
            ##                dm_dphos = dm_dphos.GetName(),
            ##                phos = self._phos.GetName(),
            ##                phostrue = phostrue.GetName())
            ## )
            ## LinearVar cannot be persisted.
            msubs = w.factory('''
                expr::{msubs}(
                     "{mass} - 0.01 * {dm_dphos} * ({phos} - {phostrue})",
                     {{ {mass}, {dm_dphos}, {phos}, {phostrue} }}
                     )
                '''.format(msubs=name + '_msubs_%d' % index,
                           mass=self._mass.GetName(),
                           dm_dphos=dm_dphos.GetName(),
                           phos=self._phos.GetName(),
                           phostrue=phostrue.GetName()))
            self._msubs_list.append(msubs)

            ## Build the corresponding parametrized KEYS PDF {name}_kyes_{index}
            ##     with {name}_keys_mode_{index} and
            ##     {name}_keys_effsigma_{index}.
            keys_mode = w.factory(
                '{name}_keys_mode_{index}[91.2, 60, 120]'.format(name=name,
                                                                 index=index))
            keys_effsigma = w.factory(
                '{name}_keys_effsigma_{index}[3, 0.1, 60]'.format(name=name,
                                                                  index=index))
            mass.setRange(*mrangetrain)
            keys_pdf = ParametrizedKeysPdf(name + '_keys_pdf_%d' % index,
                                           name + '_keys_pdf_%d' % index,
                                           mass,
                                           keys_mode,
                                           keys_effsigma,
                                           sdata,
                                           rho=self._rho)
            self._keys_modes.append(keys_mode)
            self._keys_effsigmas.append(keys_effsigma)
            self._keys_pdfs.append(keys_pdf)

            ## Fit the KEYS PDF to the training data and save the result
            ##     {name}_keys_fitresult_{index} and parameter snapshots
            ##     {name}_keys_mctrue_{index}.
            mass.setRange(*mrangenorm)
            keys_fitresult = keys_pdf.fitTo(sdata, roo.Range(*mrangefit),
                                            roo.Strategy(2), roo.NumCPU(8),
                                            roo.Save(True))
            self._keys_fitresults.append(keys_fitresult)
            w.Import(keys_fitresult, name + '_keys_fitresult_%d' % index)
            w.saveSnapshot(
                name + '_mctrue_%d' % index, ','.join([
                    phostrue.GetName(),
                    phortrue.GetName(),
                    keys_mode.GetName(),
                    keys_effsigma.GetName()
                ]))

            ## Sample the fitted KEYS PDF to a histogram {name}_hist_{index}.
            mass.setRange(*mrangetrain)
            hist = keys_pdf.createHistogram(name + '_hist_%d' % index, mass,
                                            roo.Binning('cache'))

            ## Build a RooDataHist {name}_dhist{index} of the sampled histogram.
            dhist = ROOT.RooDataHist(name + '_dhist_%d' % index,
                                     name + '_dhist_%d' % index,
                                     ROOT.RooArgList(mass), hist)
            w.Import(dhist)

            ## Build a RooHistPdf {name}_pdf_{index} using the dhist and msubs.
            ## pdf = w.factory(
            pdf = w.factory('HistPdf::{name}({{{mass}}}, {dhist}, 1)'.format(
                name=name + '_pdf_%d' % index,
                msubs=msubs.GetName(),
                mass=mass.GetName(),
                dhist=dhist.GetName()))
            self._pdfs.append(pdf)
            mass.setRange(*self._massrange)

            ## Calculate morphing parameter reference values float mref[index].
            phorval = phor.getVal()
            phor.setVal(phortrue.getVal())
            self._mrefs.append(mpar.getVal())
            phor.setVal(phorval)
        ## End of loop over target phortargets

        ## Make the reference and cache binnings in phor
        self._check_phor_ranges()
        partitions = self._partition_binning(self._phor, 'cache', 'reference')

        ## Loop over phor reference bins and define pairwise RooMomentMorphs.
        for ilo in range(len(self._mrefs) - 1):
            ihi = ilo + 1
            mlo = self._mrefs[ilo]
            mhi = self._mrefs[ihi]
            pdflo = self._pdfs[ilo]
            pdfhi = self._pdfs[ihi]
            phormorph = w.factory('''
                MomentMorph::{name}_phormorph_{ilo}to{ihi}(
                    {mpar}, {{{mass}}}, {{{pdfs}}}, {{{mrefs}}}
                    )
                '''.format(name=name,
                           ilo=ilo,
                           ihi=ihi,
                           mpar=mpar.GetName(),
                           mass=mass.GetName(),
                           pdfs='%s, %s' % (pdflo.GetName(), pdfhi.GetName()),
                           mrefs='%f, %f' % (mlo, mhi)))
            self._phormorphs.append(phormorph)
            ## Sample the morph in a 2D histogram in mass and phor.
            phorhist = phormorph.createHistogram(
                name + '_phorhist_%dto%d' % (ilo, ihi), mass,
                roo.Binning('cache'),
                roo.YVar(phor, roo.Binning(partitions[ilo])))
            self._phorhists.append(phorhist)
        ## End of loop over phor reference bins.
        self._stitch_phorhists()
        self._phor_dhist = phor_dhist = ROOT.RooDataHist(
            name + '_phor_dhist', name + '_phor_dhist',
            ROOT.RooArgList(mass, phor), self._phorhist)

        average_index = (len(self._msubs_list) + 1) / 2
        msubs = self._msubs_list[average_index]

        ## self._model = model = ROOT.RooHistPdf(
        ##     name + '_phor_histpdf', name + '_phor_histpdf',
        ##     ROOT.RooArgList(msubs, phor), ROOT.RooArgList(mass, phor), phor_dhist, 2
        ##     )
        ## self._model = model = ROOT.RooPhosphorPdf(
        ##     name + '_phor_histpdf', name + '_phor_histpdf', mass, msubs, phor, phor_dhist, 2
        ##     )

        ## ## Quick hack to make things work.
        ## self._customizer = customizer = ROOT.RooCustomizer(model, 'msub')
        ## customizer.replaceArg(mass, msubs)
        ## model = customizer.build()

        # ROOT.RooHistPdf.__init__(self, model)
        ROOT.RooPhosphorPdf.__init__(self, name, title, mass, msubs, phos,
                                     phor, phor_dhist, 2)
        self.SetName(name)
        self.SetTitle(title)
Example #19
0
    canvases.update()
    sw.Stop()
    print 'CPU time:', sw.CpuTime(), 's, real time:', sw.RealTime(), 's'
## End of main()    


##------------------------------------------------------------------------------
sw = ROOT.TStopwatch()
sw.Start()

init()
get_data()

phoEResPdf = ParametrizedKeysPdf(
    'phoEResPdf', 'phoEResPdf', phoERes, phoScale, phoRes, data,
    ROOT.RooKeysPdf.NoMirror, 1.5
    )

phoEResPdf.fitTo(data, roo.Range(-50, 50))

canvases.next('phoEResPdf').SetGrid()
plot = phoERes.frame(roo.Range(-10, 10))
data.plotOn(plot)
phoEResPdf.plotOn(plot)
phoEResPdf.paramOn(plot)
plot.Draw()

t = w.factory('t[0,-1,1]')
t.SetTitle('log(E_{reco}^{#gamma}/E_{gen}^{#gamma})')
tfunc = w.factory('expr::tfunc("log(0.01 * phoERes + 1)", {phoERes})')
tfunc.SetName('t')
Example #20
0
class MonteCarloCalibrator:
    def __init__(self, data, printlevel=-1, rho=1.5):
        self.w = ROOT.RooWorkspace("mccworkspace", "MonteCarloCalibrator Workspace")
        self.datarow = ROOT.RooArgSet()
        for x in "mmMass mmgMass phoERes".split():
            setattr(self, x, data.get()[x])
            self.datarow.add(data.get()[x])
            # self.w.Import(getattr(self, x))
        self.data = data.reduce(self.datarow)
        self.data.SetName("data")
        self.rho = rho
        self.w.Import(data)

        self.printlevel = printlevel

        ## Define reference (0) and target scale (s) and resolution (r)
        self.s0 = self.w.factory("s0[0, -50, 50]")
        self.r0 = self.w.factory("r0[1, 0.01, 50]")
        self.s = self.w.factory("s[0, -50, 50]")
        self.r = self.w.factory("r[1, 0.01, 50]")
        for x in "s0 r0 s r".split():
            getattr(self, x).setUnit("%")

        ## Define a set of the fit and reference parameters,
        ## store them in the workspace.
        self.sr = ROOT.RooArgSet(self.s, self.r)
        self.sr0 = ROOT.RooArgSet(self.s0, self.r0)
        self.w.defineSet("fit", self.sr)
        self.w.defineSet("ref", self.sr0)
        self.w.saveSnapshot("sr_init", self.sr, True)
        self.w.saveSnapshot("sr0_init", self.sr0, True)

        self._get_mctruth_scale_and_resolution()
        self._define_smearing_functions()

    ## end of __init__

    def _get_mctruth_scale_and_resolution(self):
        ## Enlarge the range of the observable to get vanishing tails for
        ## the photon energy scale resolution
        # savrange = (self.phoERes.getMin(), self.phoERes.getMax())
        # self.phoERes.setRange(savrange[0] - 10, savrange[1] + 10)

        ## Build the model for the photon energy resolution.
        self.phoEResPdf = ParametrizedKeysPdf(
            "phoEResPdf", "phoEResPdf", self.phoERes, self.s, self.r, self.data, ROOT.RooKeysPdf.NoMirror, self.rho
        )
        # self.phoERes.setRange(*savrange)
        ## Set sensible initial values
        self.s.setVal(self.phoEResPdf.shapemode)
        self.r.setVal(self.phoEResPdf.shapewidth)

        ## Extract the MC truth scale and resolution from MC
        self.fitresult_mctruth = self.phoEResPdf.fitTo(
            self.data,
            roo.PrintLevel(self.printlevel),
            roo.SumW2Error(False),
            roo.Range(-50, 50),
            roo.Save(),
            roo.Strategy(2),
        )
        self.w.Import(self.fitresult_mctruth)

        ## Store the MC truth scale and resolution
        for source, target in zip([self.s, self.r], [self.s0, self.r0]):
            target.setVal(source.getVal())
            target.setError(source.getError())
            target.setAsymError(source.getErrorLo(), source.getErrorHi())
        # self.s0.setVal(self.s.getVal())
        # self.r0.setVal(self.r.getVal())
        self.w.saveSnapshot("sr_mctruth", self.sr)
        self.w.saveSnapshot("sr0_mctruth", self.sr0)
        self.s0.setConstant(True)
        self.r0.setConstant(True)

    ## end of _get_mctruth_scale_and_resolution

    def _define_smearing_functions(self):
        ## Define the smearing formulas for photon energy and mmg invariant mass
        # self.phoEResSmear = w.factory('phoEResSmear[-100,200]')
        self.phoEResSmear = self.w.factory(
            """expr::phoEResSmear(
            "s + r * (phoERes - s0) / r0",
            {phoERes, s, r, s0, r0}
            )"""
        )

        # self.mmgMassSmear = w.factory('mmgMassSmear[0, 200]')
        self.mmgMassSmear = self.w.factory(
            """expr::mmgMassSmear(
            "sqrt({m2} + (1 + 0.01 * {f}) / (1 + 0.01 * {f0}) * ({M2} - {m2}))",
            {{{m}, {M}, {f}, {f0}}}
            )""".format(
                m="mmMass", m2="mmMass*mmMass", M="mmgMass", M2="mmgMass*mmgMass", f="phoEResSmear", f0="phoERes"
            )
        )

    ## end of _define_smearing_functions

    def _reduce_and_rename(self, oldname, newname):
        ## Remove the ranges from the oldvar.
        oldvar = self.data.get()[oldname]
        oldvar.removeMin()
        oldvar.removeMax()
        ## Drop everything except the oldvar.
        newdata = self.data.reduce(ROOT.RooArgSet(oldvar))
        ## Define the renaming identity newvar = oldvar
        newfunc = ROOT.RooFormulaVar(newname, newname, oldname, ROOT.RooArgList(oldvar))
        ## Add a column with the identical values but with the new name
        newvar = newdata.addColumn(newfunc)
        ## New data now contains two columns of identical values, one labeled
        ## with the old name and the other with the new name. Keep only the one
        ## with the new name.
        return newdata.reduce(ROOT.RooArgSet(newvar))

    ## end of _reduce_and_rename

    def _fit_smeared_data(self, name):
        "Fit the current smeared data to get the smeared s and r."
        self.fitresult_sdata = self.phoEResPdf.fitTo(
            self.sdata,
            roo.PrintLevel(self.printlevel),
            roo.SumW2Error(False),
            roo.Range(-50, 50),
            roo.Save(),
            roo.Strategy(2),
        )
        self.w.saveSnapshot(name + "_sr", self.sr)
        self.w.Import(self.fitresult_sdata, name + "_fitresult")

    ## end of _fit_smeared_data()

    def get_smeared_data(self, starget, rtarget, name="default", title="default", dofit=False):
        if name == "default":
            name = self.data.GetName() + "_smeared"
        if title == "default":
            title = self.data.GetTitle() + " smeared"
        ## Make sure that the reference scale and resolution
        ## are equal to the MC truth.
        self.w.loadSnapshot("sr0_mctruth")
        ## Check if any of the parameters is to be set to the nominal values.
        if starget == "nominal":
            starget = self.s0.getVal()
        if rtarget == "nominal":
            rtarget = self.r0.getVal()
        self.s.setVal(starget)
        self.r.setVal(rtarget)
        ## Make sure that the reference scale and resolution
        ## are equal to the MC truth.
        self.w.loadSnapshot("sr0_mctruth")
        ## Calculate the smeared photon energy resolution and mmg mass.
        self.data.addColumn(self.phoEResSmear)
        self.data.addColumn(self.mmgMassSmear)
        ## Build a new dataset with the smeared data
        self.sdata = self.data.reduce(ROOT.RooArgSet(self.mmMass))
        self.sdata.merge(self._reduce_and_rename("phoEResSmear", "phoERes"))
        self.sdata.merge(self._reduce_and_rename("mmgMassSmear", "mmgMass"))
        ## Drop the smearing variables from the nominal data
        self.data = self.data.reduce(ROOT.RooArgSet(self.mmgMass, self.mmMass, self.phoERes))
        ## Set the name and title of the smeared data.
        self.sdata.SetName(name)
        self.sdata.SetTitle(title)
        ## Fit the smeared data
        if dofit:
            self._fit_smeared_data(name)
        ## Return the smeared data
        return self.sdata
Example #21
0
    sdata.SetName(dataname)
    w.Import(sdata)

    pdfname = '_'.join(['mmgMassPdf', name, bintag])
    pdfname = pdfname.replace('-', 'to')
    ## KEYS PDF Dilemma: RooKeysPdf is deprecated,
    ## RooNDKeysPdf cannot be stored in a workspace,
    ## RooMomentMorph constructor works in workspace factory only
    ## pdf = ROOT.RooNDKeysPdf(pdfname, pdfname,
    ##                         ROOT.RooArgList(mmgMass), sdata, "a", 1.5)
    ## -> Stick to deprecated RooKeysPdf for now.
    ## mmgMass.setRange(40, 140)
    peak = w.factory('%s_mode[91.2, 60, 120]' % pdfname)
    width = w.factory('%s_effsigma[3, 0.1, 20]' % pdfname)
    pdf = ParametrizedKeysPdf(pdfname + '_pkeys', pdfname + '_pkyes', mmgMass,
                              peak, width, sdata, ROOT.RooKeysPdf.NoMirror,
                              1.5)
    savrange = (mmgMass.getMin(), mmgMass.getMax())
    normrange = (40, 130)
    fitrange = (60, 120)
    mmgMass.setRange(*fitrange)
    peak.setVal(pdf.shapemode)
    width.setVal(pdf.shapewidth)
    pdf.fitTo(sdata, roo.Range(*fitrange), roo.Strategy(2))
    w.Import(pdf)
    ## peak.setConstant()
    ## width.setConstant()

    hist = pdf.createHistogram(pdfname + '_hist', mmgMass, roo.Binning(1000))
    dhist = ROOT.RooDataHist(pdfname + '_dhist', pdfname + '_hist',
                             ROOT.RooArgList(mmgMass), hist)
Example #22
0
data.addColumn(t1xt2func)
t1xt2func.SetName('t1xt2func')
tfunc.SetName('t')
data.addColumn(tfunc)
tfunc.SetName('tfunc')
t1xt2vtdata = data.reduce(ROOT.RooArgSet(t, t1xt2))
data = data.reduce(ROOT.RooArgSet(mmgMass, mmMass, phoERes, mmgMassPhoGenE))

## Build the model fT1(t1) for log(mmgMassPhoGenE^2 - mmMass^2)
t.setRange(5, 10)
# t.setVal(8.3)
nomirror = ROOT.RooKeysPdf.NoMirror
## t1pdf = ROOT.RooKeysPdf('t1pdf', 't1pdf', t, t1data, nomirror, 1.5)
t1mode = w.factory('t1mode[8.3,5,10]')
t1width = w.factory('t1width[0.2,0.01,5]')
t1pdf = ParametrizedKeysPdf('t1pdf', 't1pdf', t, t1mode, t1width, t1data,
                            nomirror, 1.5)
t1pdf.fitTo(t1data)
t1mode.setConstant(True)
t1width.setConstant(True)
## TODO: use parametrized KEYS PDF with forced ranges and fit it to data.

## Build the model fT2(t2|s,r) for log(Ereco/Egen) ft2(t2|r,s)
t.setRange(-1, 1)
t.setVal(0)
t2pdf = LogPhoeresKeysPdf('t2pdf',
                          't2pdf',
                          phoERes,
                          t,
                          phoScale,
                          phoRes,
                          data,
Example #23
0
    sdata.SetName(dataname)
    w.Import(sdata)

    pdfname = '_'.join(['mmgMassPdf', name, bintag])
    pdfname = pdfname.replace('-', 'to')
    ## KEYS PDF Dilemma: RooKeysPdf is deprecated,
    ## RooNDKeysPdf cannot be stored in a workspace,
    ## RooMomentMorph constructor works in workspace factory only
    ## pdf = ROOT.RooNDKeysPdf(pdfname, pdfname,
    ##                         ROOT.RooArgList(mmgMass), sdata, "a", 1.5)
    ## -> Stick to deprecated RooKeysPdf for now.
    ## mmgMass.setRange(40, 140)
    peak = w.factory('%s_mode[91.2, 60, 120]' % pdfname)
    width = w.factory('%s_effsigma[3, 0.1, 20]' % pdfname)
    pdf = ParametrizedKeysPdf(pdfname + '_pkeys', pdfname + '_pkyes',
                              mmgMass, peak, width, sdata,
                              ROOT.RooKeysPdf.NoMirror, 1.5)
    savrange = (mmgMass.getMin(), mmgMass.getMax())
    normrange = (40, 130)
    fitrange = (60, 120)
    mmgMass.setRange(*fitrange)
    peak.setVal(pdf.shapemode)
    width.setVal(pdf.shapewidth)
    pdf.fitTo(sdata, roo.Range(*fitrange), roo.Strategy(2))
    w.Import(pdf)
    ## peak.setConstant()
    ## width.setConstant()

    hist = pdf.createHistogram(pdfname + '_hist', mmgMass, roo.Binning(1000))
    dhist = ROOT.RooDataHist(pdfname + '_dhist', pdfname + '_hist',
                             ROOT.RooArgList(mmgMass), hist)
Example #24
0
init()
get_data()

sdata4 = calibrator.get_smeared_data('nominal', 4)
sdata6 = calibrator.get_smeared_data('nominal', 5)
sdata8 = calibrator.get_smeared_data('nominal', 6)

mirror = ROOT.RooKeysPdf.NoMirror

mode4 = w.factory('mode4[91,60,120]')
mode8 = w.factory('mode8[91,60,120]')

seff4 = w.factory('seff4[4,0.1,50]')
seff8 = w.factory('seff8[4,0.1,50]')

pdf4 = ParametrizedKeysPdf('pdf4', 'pdf4', mmgMass, mode4, seff4,
                           sdata4, mirror, 1.5)
pdf8 = ParametrizedKeysPdf('pdf8', 'pdf8', mmgMass, mode8, seff8,
                           sdata8, mirror, 1.5)

mmgMass.setRange(50, 130)

pdf4.fitTo(sdata4, roo.Range(60, 120))
h4 = pdf4.createHistogram('h4', mmgMass, roo.Binning(1000))

pdf8.fitTo(sdata8, roo.Range(60, 120))
h8 = pdf8.createHistogram('h8', mmgMass, roo.Binning(1000))

d4 = ROOT.RooDataHist('d4', 'd4', ROOT.RooArgList(mmgMass), h4)
d8 = ROOT.RooDataHist('d8', 'd8', ROOT.RooArgList(mmgMass), h8)

f4 = ROOT.RooHistPdf('f4', 'f4', ROOT.RooArgSet(mmgMass), d4, 1)