Example #1
0
def main ():

    # Parse command-line arguments
    args = parser.parse_args()

    # Settings
    signals = ['RPV', 'Rhadron']
    variables = ['pt', 'prodR']
    histname = "IDPerformanceMon/LargeD0/basicPlot/SignalParticles/truth{var}"
    rebin = {
        'RPV':     2,
        'Rhadron': 1,
        }
    
    # Loop variables
    for var in variables:

        # Load histograms
        histograms = list()
        hn = histname.format(var=var)
        for signal in signals:
            f = ROOT.TFile(filename.format(signal=signal), 'READ')
            try:
                h = f.Get(hn)
                h.SetDirectory(0)
                if signal in rebin: h.Rebin(rebin[signal])
            except: # Plot doesn't exist for 'signal'
                print "Histogram '%s' does not exist for signal '%s'" % (hn, signal)
                h = None
                continue
            histograms.append(h)
            pass
        
        # Draw figure
        c = ap.canvas(batch=not args.show)
        for hist, signal, col in zip(histograms, signals, colours):
            c.hist(hist, label=signal_line(signal), linecolor=col, normalise=True)
            pass
        c.xlabel(displayNameUnit(var))
        c.ylabel("Fraction of signal particles")
        c.text(["MC truth"], qualifier=qualifier)
        c.legend()
        c.logy()
        if args.save: c.save('plots/distributions_{var}.pdf'.format(var=var))
        if args.show: c.show()
        pass

    return
Example #2
0
def main():

    # Parse command-line arguments
    args = parser.parse_args()

    # Initialise categories for which to plot distinct curved for each histogram
    algorithms = ['Standard', 'LargeD0']
    names = ['Standard', 'Large radius', 'Combined']
    types = ['', 'Primary', 'Secondary', 'Signal']
    signals = ['RPV', 'Rhadron']

    # Initialise variable versus which to plot the physics efficiency
    basic_vars = [
        'eta', 'phi', 'd0', 'z0', 'pt', 'R', 'Z', 'pt_low', 'pt_high'
    ]

    # Initialise list of histograms to be plotted
    base = 'IDPerformanceMon/LargeD0/'
    histname = base + 'EffPlots/{alg}Tracks/{t}trackeff_vs_{var}'

    # Read in and plot each histogram
    for fn, var, t, signal in itertools.product([filename], basic_vars, types,
                                                signals):

        # Generate list of (path, histname) pairs to plot
        pathHistnamePairs = zip([fn.format(signal=signal)] * len(algorithms), [
            histname.format(t=t + ('/' if t != '' else ''), alg=alg, var=var)
            for alg in algorithms
        ])

        # Load in histograms
        histograms = list()
        for path, hn in pathHistnamePairs:
            f = ROOT.TFile(path, 'READ')
            h = f.Get(hn)
            h.SetDirectory(0)
            if '_vs_R' in hn:
                if signal == 'Rhadron':
                    h.Rebin(2)
                else:
                    xbins = [
                        0., 10., 20., 30., 40., 50., 70., 90., 110., 130.,
                        150., 175., 200., 225., 250., 275., 300.
                    ]
                    h.Rebin(len(xbins) - 1, 'hnew', array('d', xbins))
                    h = ROOT.gDirectory.Get('hnew')
                    h.SetDirectory(0)
                pass
            histograms.append(h)
            f.Close()
            pass

        # Compute combined efficiency
        h0 = histograms[0]
        h1 = histograms[1]
        ax = h0.GetXaxis()
        combined_eff = h0.Clone(
            h0.GetName() + '_comb'
        )  # ROOT.TProfile(h0.GetName() + '_comb', "", ax.GetNbins(), ax.GetXmin(), ax.GetXmax())
        combined_eff.Reset()
        for bin in range(1, ax.GetNbins() + 1):
            num_total = int(h0.GetBinEntries(bin))
            num_pass1 = int(h0.GetBinContent(bin) * num_total)
            num_pass2 = int(h1.GetBinContent(bin) * num_total)
            num_pass = num_pass1 + num_pass2
            num_fail = num_total - num_pass
            x = combined_eff.GetBinCenter(bin)
            for _ in range(num_pass):
                combined_eff.Fill(x, 1)
            for _ in range(num_fail):
                combined_eff.Fill(x, 0)
            pass
        histograms.append(combined_eff)

        # Draw figure
        c = ap.canvas(batch=not args.show, size=(700, 500))
        for ihist, (hist, name,
                    col) in enumerate(zip(histograms, names, colours)):
            c.plot(hist,
                   linecolor=col,
                   markercolor=col,
                   linestyle=1 + ihist,
                   markerstyle=20 + ihist,
                   label=name + (" tracks" if name != "Combined" else ""),
                   legend_option='PL')
            pass
        c.text(
            [signal_line(signal)],
            # + ([t + " particles"] if t != '' else []),
            qualifier=qualifier)
        if ('Signal' in hn) and ('_vs_R' in hn):
            c.ylim(0, 1.6)
            pass
        c.xlabel(displayNameUnit(
            var))  # hist.GetXaxis().GetTitle().replace('prod.', 'prod'))
        c.ylabel("Reconstruction effiency")
        c.legend(width=0.28)

        # Radial locations of detector stuff
        if '_vs_R' in hn:
            """ Ugly vertical lines
            opts = {'linecolor': ROOT.kRed, 'linestyle': 3, 'text_horisontal': 'R', 'text_vertical': 'M'}
            c.xline( 33.25, **opts)
            c.xline( 50.5,  **opts)
            c.xline( 88.5,  **opts)
            c.xline(122.5,  **opts)

            opts['linecolor'] = ROOT.kBlue
            c.xline( 45.5, **opts)
            c.xline(242,   **opts)
            c.xline(255,   **opts)

            opts['linecolor'] = ROOT.kGreen
            c.xline( 229, **opts)
            """
            """ Pretty vertical lines
            opts = {'linecolor': ROOT.kRed, 'linestyle': 3, 'text_horisontal': 'R', 'text_vertical': 'M'}
            opts['linecolor'] = ROOT.kGray + 1
            c.xline( 33.25, text='IBL', **opts)
            c.xline( 50.5,  text='Pix. Layer 1', **opts)
            c.xline( 88.5,  text='Pix. Layer 2', **opts)
            if signal == 'Rhadron':
                opts['text_vertical'] = 'T'
                pass
            c.xline(122.5,  text='Pix. Layer 3', **opts)
            #c.xline(299.,   text='Layer 4', **opts)

            opts['linecolor'] = ROOT.kBlue
            opts['text_horisontal'] = 'L'
            opts['text_vertical'] = 'M'
            opts['linecolor'] = ROOT.kGray + 2
            c.xline( 45.5, text='Envelope 1', **opts)
            opts['text_vertical'] = 'T'
            c.xline(242,   text='Envelope 2', **opts)
            c.xline(255,   text='Envelope 3', **opts)

            opts['linecolor'] = ROOT.kGreen
            opts['linecolor'] = ROOT.kGray + 3
            c.xline( 229, text='Pixel tube', **opts)
            """

            #xlines = [33.25, 50.5, 88.5, 122.5, 299, # layers
            #          45.5, 242, 255, # envelopes
            #          ]
            #c.xlines(xlines, linecolor=ROOT.kRed - 4)
            pass

        # Show/save
        savename = '_'.join([signal] + histname.format(
            t=t +
            ('/' if t != '' else ''), alg='', var=var).split('/')[2:]) + '.pdf'
        if args.show: c.show()
        if args.save: c.save('plots/' + savename)
        pass

    return
Example #3
0
def main ():

    # Macro-specific styles
    ROOT.gROOT.GetStyle("AStyle").SetEndErrorSize(.5)

    # Parse command-line arguments
    args = parser.parse_args()

    # Initialise categories for which to plot distinct curves for each histogram
    algorithms = ['Standard', 'LargeD0']
    names      = ['Standard', 'Large radius']
    types      = ['Signal'] # ['All', 'Signal']
    signals = ['RPV', 'Rhadron'] 
    groups = ['R10mm_30mm/',
              'R30mm_100mm/',
              'R100mm_300mm/',
              ]
    #groups = ['R20mm_50mm/',
    #          'R100mm_150mm/',
    #          'R200mm_300mm/',
    #          ]

    group_names = [ '[%s]' % grp[1:-1].replace('_', ', ').replace('p', '.').replace('mm', ' mm') for grp in groups ]
    # @TEMP: Fix type in histogram names: 30mm_300mm -> 100mm_300mm
    #group_names = [gn.replace('30mm, 300mm', '100mm, 300mm') for gn in group_names]

    # Initialise list of histograms to be plotted 
    base = 'IDPerformanceMon/LargeD0/'
    histname = base + 'EffPlots/{alg}Tracks/{t}/{group}trackeff_vs_mu'

    edges = [0, 10, 15, 20, 25, 30, 40]

    # Loop all combinations of truth particle type and signal process
    for t, signal in itertools.product(types, signals):

        # Open file from which to read histograms.
        f = ROOT.TFile(filename.format(signal=signal), 'READ')
        ROOT.TH1.AddDirectory(False)
        ROOT.TH2.AddDirectory(False)
        
        # Get list of histograms tp plot, manually.
        histograms = list()

        # Get histograms
        for alg in algorithms:
            # Loop production radii groups
            for group in groups:
                h = f.Get(histname.format(alg=alg, t=t, group=group))
                h.SetDirectory(0) # Keep in memory after file is closed.
                #h.RebinX(2)
                newname = h.GetName() + "_rebinned_" + group + "_" + alg
                hn = h.Rebin(len(edges)-1, newname, array.array('d',edges))
                #histograms.append(h)
                histograms.append(hn)
                pass
            pass
        
        # Close file
        f.Close()


        # Efficiency of STD and LRT separately
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

        # Draw figure
        c = ap.canvas(batch=not args.show, size=(700, 500))
        for i, alg in enumerate(algorithms):
            N = len(group_names)
            N1, N2 = i * N, (i + 1) * N
            for hist, name, col in zip(histograms[N1:N2], group_names, colours):
                c.plot(hist, linecolor=col, markercolor=col, markerstyle=4*i+20, linewidth=2, linestyle=i+1, label=name if i == 0 else None)
                pass
            pass

        c.text([signal_line(signal)]
               + (["%s particles" % t] if t != 'Signal' else []),
               qualifier=qualifier)
        c.legend(header=displayName('r') + " in:", categories=[(name, {'linestyle': i+1, 'markerstyle': 4*i+20, 'option': 'PL', 'linewidth': 2}) for i, name in enumerate(names)], width=0.28)
        c.xlabel("#LT#mu#GT")
        c.ylabel("Reconstruction efficiency")
        c.ylim(0, 1.8)

        # Show/save
        savename = '_'.join([signal] + histname.format(alg='', t=t, group='').split('/')[2:]) + '.pdf'
        if args.show: c.show()
        if args.save: c.save('plots/' + savename)
    

        # Efficiency of STD and LRT combined
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

        # Compute combined efficiency
        comb_histograms = list()
        for h1, h2 in zip(histograms[:len(groups)], histograms[len(groups):]):
            # h1: standard | h2: large radius
            ax = h1.GetXaxis()
            h_comb = h1.Clone('h_comb')#ROOT.TProfile('h_comb', "", ax.GetNbins(), ax.GetXmin(), ax.GetXmax())
            h_comb.Reset()
            for bin in range(1, h1.GetXaxis().GetNbins() + 1):
                N_total = int(h1.GetBinEntries(bin)) # == h2.GetBinEntries(bin)
                N_1 = int(h1.GetBinContent(bin) * N_total)
                N_2 = int(h2.GetBinContent(bin) * N_total)
                mu = h1.GetBinCenter(bin)
                N_pass = N_1 + N_2
                N_fail = N_total - N_pass
                for _ in xrange(N_pass): h_comb.Fill(mu, True)
                for _ in xrange(N_fail): h_comb.Fill(mu, False)
                pass
            comb_histograms.append(h_comb)
            pass


        # Draw figure
        c = ap.canvas(batch=not args.show, size=(700, 500))
        for ihist, (hist, name, col) in enumerate(zip(comb_histograms, group_names, colours)):
            c.plot(hist, linecolor=col, markercolor=col, markerstyle=20+ihist, linestyle=1+ihist, linewidth=2, label=name)
            pass

        c.text([signal_line(signal)]
               + (["%s particles" % t] if t != 'Signal' else [])
               + ["Large radius and standard tracks"],
               qualifier=qualifier)
        c.legend(header=displayName('r') + " in:", width=0.28)
        c.xlabel("#LT#mu#GT")
        c.ylabel("Reconstruction efficiency")
        c.ylim(0, 1.8)

        # Show/save
        savename = '_'.join([signal] + histname.format(alg='Combined', t=t, group='').split('/')[2:]) + '.pdf'
        if args.show: c.show()
        if args.save: c.save('plots/' + savename)
        pass

    return
Example #4
0
def main():

    # Parse command-line arguments
    args = parser.parse_args()

    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Get signal file
    sig_DSID = get_signal_DSID(args.mass, tolerance=10)
    if sig_DSID is None:
        return
    sig_file = 'objdef_MC_{DSID:6d}.root'.format(DSID=sig_DSID)

    # Load data
    files = glob.glob(tf.config['base_path'] + 'objdef_MC_3610*.root') + [
        tf.config['base_path'] + sig_file
    ]

    if len(files) == 0:
        warning("No files found.")
        return

    data = loadData(files, tf.config['tree'], prefix=tf.config['prefix'])
    info = loadData(files, tf.config['outputtree'], stop=1)

    # Scaling by cross section
    xsec = loadXsec(tf.config['xsec_file'])

    # Append new DSID field # @TODO: Make more elegant?
    data = append_fields(data, 'DSID', np.zeros((data.size, )), dtypes=int)
    for idx in info['id']:
        msk = (
            data['id'] == idx
        )  # Get mask of all 'data' entries with same id, i.e. from same file
        DSID = info['DSID'][idx]  # Get DSID for this file
        data['weight'][msk] *= xsec[
            DSID]  # Scale by cross section x filter eff. for this DSID
        data['DSID'][msk] = DSID  # Store DSID
        pass
    data['weight'] *= tf.config['lumi']  # Scale all events (MC) by luminosity

    # Check output.
    if data.size == 0:
        warning("No data was loaded.")
        return

    # Compute new variables
    data = append_fields(data, 'logpt', np.log(data['pt']))

    # Separate out signal MC
    msk_sig = (data['DSID'] == sig_DSID)
    msk_data = ~msk_sig

    print "DATA STATISTICS:", np.sum(data[msk_data]['weight'])

    signal = data[msk_sig]
    if not args.inject:
        # If we're not injecting signal, explicitly remove it from the 'data' array
        data = data[~msk_sig]
        pass

    # Toys
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    if args.toys:

        # Get masks
        msk_pass = tf.config['pass'](data)
        msk_fail = ~msk_pass

        # Create histograms
        if args.inject:
            pdf_pass = get_histogram(data,
                                     tf.config['params'],
                                     tf.config['axes'],
                                     mask=msk_pass & ~msk_sig)
            pdf_fail = get_histogram(data,
                                     tf.config['params'],
                                     tf.config['axes'],
                                     mask=msk_fail & ~msk_sig)
        else:
            pdf_pass = get_histogram(data,
                                     tf.config['params'],
                                     tf.config['axes'],
                                     mask=msk_pass)
            pdf_fail = get_histogram(data,
                                     tf.config['params'],
                                     tf.config['axes'],
                                     mask=msk_fail)
            pass

        # Smooth (only leading background)
        for _ in range(2):
            pdf_pass.Smooth()
            pdf_fail.Smooth()
            pass

        # Inject afterwards
        if args.inject:
            pdf_pass.Add(
                get_histogram(data,
                              tf.config['params'],
                              tf.config['axes'],
                              mask=msk_pass & msk_sig))
            pdf_fail.Add(
                get_histogram(data,
                              tf.config['params'],
                              tf.config['axes'],
                              mask=msk_fail & msk_sig))

        # Create p.d.f.s
        # -- Define variables
        rhoDDT = ROOT.RooRealVar('rhoDDT', 'rhoDDT', tf.config['axes'][0][0],
                                 tf.config['axes'][0][-1])
        logpt = ROOT.RooRealVar('logpt', 'logpt', tf.config['axes'][1][0],
                                tf.config['axes'][1][-1])

        rhoDDT.setBins(len(tf.config['axes'][0]) - 1)
        logpt.setBins(len(tf.config['axes'][1]) - 1)

        # -- Define histograms
        rdh_pass = ROOT.RooDataHist('rdh_pass', 'rdh_pass',
                                    ROOT.RooArgList(rhoDDT, logpt), pdf_pass)
        rdh_fail = ROOT.RooDataHist('rdh_fail', 'rdh_fail',
                                    ROOT.RooArgList(rhoDDT, logpt), pdf_fail)

        # -- Turn histograms into pdf's
        rhp_pass = ROOT.RooHistPdf('rhp_pass', 'rhp_pass',
                                   ROOT.RooArgSet(rhoDDT, logpt), rdh_pass)
        rhp_fail = ROOT.RooHistPdf('rhp_fail', 'rhp_fail',
                                   ROOT.RooArgSet(rhoDDT, logpt), rdh_fail)

        # Generate toys
        mult = 1.
        N_pass = int(np.sum(data['weight'][msk_pass]) * mult)
        N_fail = int(np.sum(data['weight'][msk_fail]) * mult)

        dtype = ['rhoDDT', 'logpt', 'tau21DDT', 'pt', 'm', 'weight']
        dtype = [(var, 'f8') for var in dtype]
        toys_pass = np.zeros(N_pass, dtype=dtype)
        toys_fail = np.zeros(N_fail, dtype=dtype)

        print "Generating toys (pass: %d, fail: %d)" % (N_pass, N_fail)
        rds_pass = rhp_pass.generate(ROOT.RooArgSet(rhoDDT, logpt), N_pass,
                                     True, False)
        rds_fail = rhp_fail.generate(ROOT.RooArgSet(rhoDDT, logpt), N_fail,
                                     True, False)

        for idx in range(N_pass):
            toys_pass['rhoDDT'][idx] = rds_pass.get(idx).getRealValue('rhoDDT')
            toys_pass['logpt'][idx] = rds_pass.get(idx).getRealValue('logpt')
            toys_pass['pt'][idx] = np.exp(toys_pass['logpt'][idx])
            toys_pass['m'][idx] = np.sqrt(
                np.exp(toys_pass['rhoDDT'][idx]) * toys_pass['pt'][idx] * 1.)
            toys_pass['weight'][idx] = 1. / float(mult)
            toys_pass['tau21DDT'][idx] = 0.
            pass

        for idx in range(N_fail):
            toys_fail['rhoDDT'][idx] = rds_fail.get(idx).getRealValue('rhoDDT')
            toys_fail['logpt'][idx] = rds_fail.get(idx).getRealValue('logpt')
            toys_fail['pt'][idx] = np.exp(toys_fail['logpt'][idx])
            toys_fail['m'][idx] = np.sqrt(
                np.exp(toys_fail['rhoDDT'][idx]) * toys_fail['pt'][idx] * 1.)
            toys_fail['weight'][idx] = 1. / float(mult)
            toys_fail['tau21DDT'][idx] = 1.
            pass

        data = np.concatenate((toys_pass, toys_fail))  # ???
        pass

    # Transfer factor
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    calc = tf.calculator(data=data,
                         config=tf.config)  # Using default configuration
    calc.mass = args.mass
    calc.fullfit()

    # Pass/fail masks
    msk_data_pass = tf.config['pass'](data)
    msk_data_fail = ~msk_data_pass
    msk_sig_pass = tf.config['pass'](signal)
    msk_sig_fail = ~msk_sig_pass

    print "  -- Computing data weights"
    w_nom, w_up, w_down = calc.fullweights(data[msk_data_fail])
    print "  -- Computing signal weights"
    w_sig, _, _ = calc.fullweights(signal[msk_sig_fail])
    print "  -- Final fit done"
    if args.show or args.save:
        calc.plot(show=args.show,
                  save=args.save,
                  prefix='plots/new_signalinjection_%s%s_' %
                  ("toys_" if args.toys else "",
                   "injected" if args.inject else "notinjected"))

    # Performing signal injection test
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    if True or args.show or args.save:

        bestfit_mu = None

        for mu, fit, prefit, subtract in zip([0, 1, 1, None],
                                             [False, False, True, False],
                                             [True, True, True, False],
                                             [True, True, False, True]):

            if not prefit:
                mu = bestfit_mu[0]
                pass

            # Plotting
            # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

            c = ap.canvas(num_pads=2, batch=not args.show)
            p0, p1 = c.pads()

            # -- Histograms: Main pad
            bins = tf.config['massbins']

            h_bkg = c.hist(data['m'][msk_data_fail],
                           bins=bins,
                           weights=data['weight'][msk_data_fail] * w_nom,
                           display=False)
            h_bkg_up = c.hist(data['m'][msk_data_fail],
                              bins=bins,
                              weights=data['weight'][msk_data_fail] * w_up,
                              display=False)
            h_bkg_down = c.hist(data['m'][msk_data_fail],
                                bins=bins,
                                weights=data['weight'][msk_data_fail] * w_down,
                                display=False)

            h_sig = c.hist(signal['m'][msk_sig_pass],
                           bins=bins,
                           weights=signal['weight'][msk_sig_pass],
                           scale=mu,
                           display=False)
            h_sfl = c.hist(signal['m'][msk_sig_fail],
                           bins=bins,
                           weights=signal['weight'][msk_sig_fail] * w_sig,
                           scale=mu,
                           display=False)
            h_data = c.plot(data['m'][msk_data_pass],
                            bins=bins,
                            weights=data['weight'][msk_data_pass],
                            display=False)

            for bin in range(1, h_bkg.GetXaxis().GetNbins() + 1):
                width = float(h_bkg.GetBinWidth(bin))
                h_bkg.SetBinContent(bin, h_bkg.GetBinContent(bin) / width)
                h_bkg.SetBinError(bin, h_bkg.GetBinError(bin) / width)
                h_bkg_up.SetBinContent(bin,
                                       h_bkg_up.GetBinContent(bin) / width)
                h_bkg_up.SetBinError(bin, h_bkg_up.GetBinError(bin) / width)
                h_bkg_down.SetBinContent(bin,
                                         h_bkg_down.GetBinContent(bin) / width)
                h_bkg_down.SetBinError(bin,
                                       h_bkg_down.GetBinError(bin) / width)
                h_sig.SetBinContent(bin, h_sig.GetBinContent(bin) / width)
                h_sig.SetBinError(bin, h_sig.GetBinError(bin) / width)
                h_sfl.SetBinContent(bin, h_sfl.GetBinContent(bin) / width)
                h_sfl.SetBinError(bin, h_sfl.GetBinError(bin) / width)
                h_data.SetBinContent(bin, h_data.GetBinContent(bin) / width)
                h_data.SetBinError(bin, h_data.GetBinError(bin) / width)
                pass

            if not fit:
                h_bkg.Add(h_sfl, -1)  # Subtracting signal
                h_bkg_up.Add(h_sfl, -1)  # --
                h_bkg_down.Add(h_sfl, -1)  # --
                pass

            c.hist(
                h_bkg, option='HIST', linestyle=0, fillstyle=0, fillcolor=0
            )  # Staring with standard histogram, not THStack, just to get y-axis to coorperate
            h_bkg = c.stack(h_bkg,
                            fillcolor=ROOT.kAzure + 7,
                            label='Background pred.')
            h_sig = c.stack(h_sig,
                            fillcolor=ROOT.kRed - 4,
                            label="Z' (#mu = %s)" %
                            ("%.0f" % mu if prefit else "%.2f #pm %.2f" %
                             (mu, bestfit_mu[1])))

            h_sum = h_bkg
            h_sum = c.hist(h_sum,
                           fillstyle=3245,
                           fillcolor=ROOT.kGray + 3,
                           option='E2',
                           label='Stat. uncert.')

            h_bkg_up = c.hist(h_bkg_up,
                              linecolor=ROOT.kGreen + 1,
                              linestyle=2,
                              option='HIST',
                              label='Syst. uncert.')
            h_bkg_down = c.hist(h_bkg_down,
                                linecolor=ROOT.kGreen + 1,
                                linestyle=2,
                                option='HIST')

            h_data = c.plot(h_data, label='Pseudo-data')

            c.hist(h_bkg, option='AXIS')  # Re-draw axes

            # -- Histograms: Ratio pad
            c.ratio_plot((h_sig, h_sum), option='HIST', offset=1)
            c.ratio_plot((h_sum, h_sum), option='E2')
            c.ratio_plot((h_bkg_up, h_sum), option='HIST')
            c.ratio_plot((h_bkg_down, h_sum), option='HIST')
            c.ratio_plot((h_data, h_sum))

            # -- Axis labels
            c.xlabel('Large-#it{R} jet mass [GeV]')
            c.ylabel('Events / GeV')
            p1.ylabel('Data / Est.')

            # -- Axis limits
            c.ylim(1.0E+00, 1.0E+06)
            p1.ylim(0.80, 1.20)

            # -- Line(s)
            p1.yline(1.0)

            # -- Region(s)
            c.region("SR", 0.8 * args.mass, 1.2 * args.mass)

            # -- Text
            c.text(
                [
                    "#sqrt{s} = 13 TeV,  %s fb^{-1}" % tf.config['lumi'],
                    "Incl. #gamma Monte Carlo",
                    "Photon channel",
                    #("Signal" if args.inject else "No signal") + " injected",
                ] + (["Using toys"] if args.toys else []),
                qualifier='Simulation Internal')

            # -- Log
            c.log()

            # -- Legend
            c.legend()
            if args.save and not fit:
                c.save('plots/new_signalinjection_%s%dGeV_pm%d_%s_%s.pdf' %
                       ("toys_" if args.toys else "", args.mass, 20.,
                        ('prefit_mu%d' % mu if prefit else 'postfit'),
                        ('injected' if args.inject else 'notinjected')))
            if args.show and not fit: c.show()

            # Fitting
            # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

            if fit:

                bestfit_mu = list()

                hs_save = [
                    h_bkg_down.Clone('h_save_down'),
                    h_bkg.Clone('h_save_nom'),
                    h_bkg_up.Clone('h_save_up'),
                ]

                for variation in range(3):

                    print "Variation: " + ("Nominal" if variation == 1 else (
                        "Up" if variation == 0 else "Down"))

                    # Get correct histogram fore this variation
                    h_bkg_use = hs_save[variation]

                    # -- Define jet mass variable
                    mJ = ROOT.RooRealVar('mJ', 'mJ', 50, 300)
                    #mJ.setBins(50)
                    roobinning = ROOT.RooBinning(
                        len(tf.config['massbins']) - 1, tf.config['massbins'])
                    mJ.setBinning(roobinning)

                    # -- Define histograms
                    rdh_bkg = ROOT.RooDataHist('rdh_bkg', 'rdh_bkg',
                                               ROOT.RooArgList(mJ), h_bkg_use)
                    rdh_sig = ROOT.RooDataHist('rdh_sig', 'rdh_sig',
                                               ROOT.RooArgList(mJ), h_sig)
                    rdh_sfl = ROOT.RooDataHist('rdh_sfl', 'rdh_sfl',
                                               ROOT.RooArgList(mJ), h_sfl)

                    # -- Turn histograms into pdf's
                    rhp_bkg = ROOT.RooHistPdf('rhp_bkg', 'rhp_bkg',
                                              ROOT.RooArgSet(mJ), rdh_bkg)
                    rhp_sig = ROOT.RooHistPdf('rhp_sig', 'rhp_sig',
                                              ROOT.RooArgSet(mJ), rdh_sig)
                    rhp_sfl = ROOT.RooHistPdf('rhp_sfl', 'rhp_sfl',
                                              ROOT.RooArgSet(mJ), rdh_sfl)

                    # -- Define integrals as constants
                    n_bkg = ROOT.RooRealVar('n_bkg', 'n_bkg',
                                            h_bkg_use.Integral())
                    n_sig = ROOT.RooRealVar('n_sig', 'n_sig', h_sig.Integral())
                    n_sfl = ROOT.RooRealVar('n_sfl', 'n_sfl', h_sfl.Integral())

                    # -- Define signal strength and constant(s)
                    mu = ROOT.RooRealVar('mu', 'mu', 1, 0, 5)
                    neg1 = ROOT.RooRealVar('neg1', 'neg1', -1)

                    # -- Define fittable normalisation factors
                    c_bkg = ROOT.RooFormulaVar('c_bkg', 'c_bkg', '@0',
                                               ROOT.RooArgList(n_bkg))
                    c_sig = ROOT.RooFormulaVar('c_sig', 'c_sig', '@0 * @1',
                                               ROOT.RooArgList(mu, n_sig))
                    c_sfl = ROOT.RooFormulaVar(
                        'c_sfl', 'c_sfl', '@0 * @1 * @2',
                        ROOT.RooArgList(neg1, mu, n_sfl))

                    # -- Construct combined pdf
                    pdf = ROOT.RooAddPdf(
                        'pdf', 'pdf', ROOT.RooArgList(rhp_bkg, rhp_sig,
                                                      rhp_sfl),
                        ROOT.RooArgList(c_bkg, c_sig, c_sfl))

                    # -- Construct data histogram
                    rdh_data = ROOT.RooDataHist('rdh_data', 'rdh_data',
                                                ROOT.RooArgList(mJ), h_data)

                    # -- Fit pdf to data histogram
                    pdf.chi2FitTo(rdh_data, ROOT.RooLinkedList())

                    print "Best fit mu: %.3f +/- %.3f" % (mu.getValV(),
                                                          mu.getError())
                    bestfit_mu.append((mu.getValV(), mu.getError()))
                    pass

                bestfit_mu = bestfit_mu[1][0], np.sqrt(
                    np.power(
                        abs(bestfit_mu[0][0] - bestfit_mu[2][0]) / 2., 2.) +
                    np.power(bestfit_mu[1][1], 2.))
                pass

            pass

        pass

    return
Example #5
0
def main ():

    # Parse command-line arguments
    args = parser.parse_args()


    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Input file paths
    paths = {
        'bkg': glob.glob(tf.config['base_path'] + 'objdef_MC_3610*.root'),
        'WZ':  glob.glob(tf.config['base_path'] + 'objdef_MC_3054*.root'),
        }
    
    # Load data
    treename = tf.config['finaltree'].replace('Jet_tau21DDT', 'Blinding')
    prefix   = 'Jet_'
    bkg      = loadData(paths['bkg'], treename, prefix=prefix)
    WZ       = loadData(paths['WZ'],  treename, prefix=prefix)
    info_bkg = loadData(paths['bkg'], tf.config['outputtree'], stop=1)
    info_WZ  = loadData(paths['WZ'],  tf.config['outputtree'], stop=1)

    # Check output
    if bkg.size == 0 or WZ.size == 0:
        warning("No data was loaded.")
        return

    # Scaling by cross-section
    xsec = loadXsec(tf.config['xsec_file'])

    bkg = scale_weights(bkg, info_bkg, xsec, lumi=tf.config['lumi'])
    WZ  = scale_weights(WZ,  info_WZ,  xsec, lumi=tf.config['lumi'])


    # -- All events
    print "Number of background and W/Z events: {:9.1f} and {:9.1f} (all)".format(
        np.sum(bkg['weight']), np.sum(WZ['weight'])
        )

    # -- Impose mass window
    msk = (bkg['m'] > 68.) & (bkg['m'] < 102.)
    bkg = bkg[msk]
    msk = (WZ['m']  > 68.) & (WZ['m']  < 102.)
    WZ  = WZ[msk]

    print "Number of background and W/Z events: {:9.1f} and {:9.1f} (mass window)".format(
        np.sum(bkg['weight']), np.sum(WZ['weight'])
        )

    # -- Impose default tau21DDT cut
    msk = bkg['tau21DDT'] < 0.5
    bkg = bkg[msk]
    msk = WZ['tau21DDT'] < 0.5
    WZ  = WZ[msk]

    print "Number of background and W/Z events: {:9.1f} and {:9.1f} (def. tau21DDT)".format(
        np.sum(bkg['weight']), np.sum(WZ['weight'])
        )

    # -- Cut to reduce SM W/Z + jets yield by 70%
    def wpercentile (data, percents, weights=None):
        """ percents in units of 1%
        weights specifies the frequency (count) of data.
        From [https://stackoverflow.com/a/31539746]
        """
        if weights is None:
            return np.percentile(data, percents)
        ind = np.argsort(data)
        d = data[ind]
        w = weights[ind]
        p = 100. * w.cumsum() / w.sum()
        y = np.interp(percents, p, d)
        return y

    cut = wpercentile(WZ['tau21DDT'], 30, WZ['weight'])
    print "Percentile giving a 70% reduction in SM W/Z yield: {:.2f}".format(cut)

    msk_bkg = bkg['tau21DDT'] < cut
    msk_WZ  = WZ['tau21DDT']  < cut

    print "Number of background and W/Z events: {:9.1f} and {:9.1f} (70% red. W/Z)".format(
        np.sum(bkg['weight'][msk_bkg]), np.sum(WZ['weight'][msk_WZ])
        )


    # -- Reduce to CMS yeild, if ATLAS = 1.7 * CMS
    cut = wpercentile(WZ['tau21DDT'], 100. / 1.7, WZ['weight'])
    print "Percentile giving a 70% reduction in SM W/Z yield: {:.2f}".format(cut)

    msk_bkg = bkg['tau21DDT'] < cut
    msk_WZ  = WZ['tau21DDT']  < cut

    print "Number of background and W/Z events: {:9.1f} and {:9.1f} (1/170% red. W/Z)".format(
        np.sum(bkg['weight'][msk_bkg]), np.sum(WZ['weight'][msk_WZ])
        )


    # -- Cut to reduce background by 90%
    cut = wpercentile(bkg['tau21DDT'], 10, bkg['weight'])
    print "Percentile giving a 90% reduction in SM background yield: {:.2f}".format(cut)

    msk_bkg = bkg['tau21DDT'] < cut
    msk_WZ  = WZ['tau21DDT']  < cut

    print "Number of background and W/Z events: {:9.1f} and {:9.1f} (90% red. bkg.)".format(
        np.sum(bkg['weight'][msk_bkg]), np.sum(WZ['weight'][msk_WZ])
        )


    print bkg.shape

    



    return


    # Compute significance improvements
    # --------------------------------------------------------------------------

    # Loop tau21DDT bins
    cuts = np.linspace(axis['tau21DDT'][1], axis['tau21DDT'][2], 10 * axis['tau21DDT'][0] + 1, endpoint=True)
    bins = np.linspace(axis['m']       [1], axis['m']       [2],      axis['m']       [0] + 1, endpoint=True)
    significances = [list() for _ in range(len(set(sig['DSID'])))]
    plot_cut=36

    c_temp = ap.canvas(batch=True)
    for icut, cut in enumerate(cuts):
        print "Bin %2d: tau21DDT < %.3f" % (icut, cut)

        # Create histograms
        msk = bkg['tau21DDT'] < cut
        h_bkg = c_temp.hist(bkg['m'][msk], bins=bins, weights=bkg['weight'][msk], fillcolor=ROOT.kAzure+7, name='Background', display=(icut == plot_cut))
        h_sigs = list()
        for idx, (DSID, name) in enumerate(zip(sorted(list(set(sig['DSID']))), sig_names)):
            msk = (sig['DSID'] == DSID) & (sig['tau21DDT'] < cut)
            h_sigs.append(c_temp.hist(sig['m'][msk], bins=bins, weights=sig['weight'][msk], linestyle=1+idx, label=name, display=(icut == plot_cut)))
            pass

        # Fill histograms
        for i,h_sig in enumerate(h_sigs):
            print " -- Signal %d |" % (i + 1), 
            sign = 0.
            for bin in range(1, h_bkg.GetXaxis().GetNbins() + 1):
                s = h_sig.GetBinContent(bin)
                b = max(h_bkg.GetBinContent(bin), 0.5)
                if icut == 35:
                    print s,b
                    pass
                #sign += np.square(s/np.sqrt(b))
                sign += 2 * ((s + b) * np.log(1 + s/b) - s) # Slide 29 in [http://www2.warwick.ac.uk/fac/sci/physics/research/epp/events/seminars/cowan_warwick_2011.pdf] -- here using the _square_ of the per-bin significance, in order to add them in quadrature
                pass
            print "Significance:", sign
            sign = np.sqrt(sign)
            significances[i].append(sign)
            pass

        pass

    # Fix for icut == 35, isig == 2 # @TEMP!!!
    significances[2][35] = 0.5 * (significances[2][34] + significances[2][36])

    c_temp.xlabel("Large-#it{R} jet mass [GeV]")
    c_temp.logy()
    c_temp.legend()
    if args.save: c_temp.save("plots/cutoptimisation_massspectrum.pdf")

    # Compute significance improvements
    improvements     = [np.array(sign) / sign[-1] for sign in significances]
    improvements_avg = np.mean(improvements, axis=0)
    idx_max = np.argmax(improvements_avg)

    print "Optimal cut: %.2f (avg. improvement: %.3f)" % (cuts[idx_max], improvements_avg[idx_max])
    msk = bkg['tau21DDT'] < cuts[idx_max]
    print "Background efficiency: %.2f%%" % (np.sum(bkg['weight'][msk])/np.sum(bkg['weight']) * 100.)
    print "Signal efficiencies:"
    for name, DSID in zip(sig_names, sorted(list(set(sig['DSID'])))):
        msk_num = (sig['DSID'] == DSID) & (sig['tau21DDT'] < cuts[idx_max])
        msk_den = (sig['DSID'] == DSID)
        print "  %s: %.2f%%" % (name, np.sum(sig['weight'][msk_num])/np.sum(sig['weight'][msk_den]) * 100.)
        pass

    print ""
    cut_man = 0.50
    print "For manual cut: %.2f (avg. improvement: %.3f)" % (cut_man, float(improvements_avg[np.where(cuts == cut_man)]))
    msk = bkg['tau21DDT'] < cut_man
    print "Background efficiency: %.2f%%" % (np.sum(bkg['weight'][msk])/np.sum(bkg['weight']) * 100.)
    print "Signal efficiencies:"
    for name, DSID in zip(sig_names, sorted(list(set(sig['DSID'])))): 
        msk_num = (sig['DSID'] == DSID) & (sig['tau21DDT'] < cut_man)
        msk_den = (sig['DSID'] == DSID)
        print "  %s: %.2f%%" % (name, np.sum(sig['weight'][msk_num])/np.sum(sig['weight'][msk_den]) * 100.)
        pass


    # Plot improvements
    # --------------------------------------------------------------------------

    # Create canvas
    c = ap.canvas(batch=not args.show)

    bins = np.linspace(axis['tau21DDT'][1], axis['tau21DDT'][2], axis['tau21DDT'][0] + 1, endpoint=True)

    # Draw histograms
    msk = bkg['tau21DDT'] < cut
    h_bkg = c.hist(bkg['tau21DDT'][msk], bins=bins, weights=bkg['weight'][msk], fillcolor=ROOT.kAzure+7, name='Incl. #gamma MC', normalise=True)
    h_sigs = list()
    for idx, (DSID, name) in enumerate(zip(sorted(list(set(sig['DSID']))), sig_names)):
        msk = (sig['DSID'] == DSID) & (sig['tau21DDT'] < cut)
        h_sigs.append(c.hist(sig['tau21DDT'][msk], bins=bins, weights=sig['weight'][msk], linecolor=ROOT.kRed + idx, label=name, normalise=True))
        pass

    # Overlay
    o = ap.overlay(c, color=ROOT.kViolet)
    graphs = list()
    for idx, impr in enumerate(improvements):
        graphs.append(o.graph(impr, bins=cuts, display=None))
        pass
    gr = o.graph(improvements_avg, bins=cuts, linecolor=ROOT.kViolet, linewidth=2, markerstyle=0, option='L')
    o.padding(0.50)
    o.label("Average significance improvement")
    
    # Text
    c.padding(0.40)
    c.text(["#sqrt{s} = 13 TeV,  L = 36.1 fb^{-1}",
            "ISR #gamma selection",
            ], qualifier='Simulation Internal')

    c.xlabel('Signal jet #tau_{21}^{DDT}')
    c.ylabel('Events (normalised)')

    # Lines
    o.line(cuts[idx_max], 0, cuts[idx_max], improvements_avg[idx_max])

    # Legend
    c.legend(width=0.28)

    # Show
    if args.save: c.save('plots/cutoptimisation.pdf')
    if args.show: c.show()


    # Write output to file
    f = ROOT.TFile('output/hists_isrgamma_cutoptimisation.root', 'RECREATE')
    h_bkg.SetName('h_tau21DDT_bkg')
    h_bkg.Write()
    for idx in range(len(h_sigs)):
        name = sig_names[idx]
        m = re.search('\(([0-9]+) GeV\)', name)
        h_sigs[idx].SetName('h_tau21DDT_sig%s' % m.group(1))
        h_sigs[idx].Write()
        graphs[idx].SetName('gr_improvements_sig%s' % m.group(1))
        graphs[idx].Write()
        pass
    gr.SetName('gr_improvements_avg')
    gr.Write()
    f.Write()
    f.Close()

    return
Example #6
0
def main ():

    # Parse command-line arguments
    args = parser.parse_args()


    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

    # Load data
    files = glob.glob(tf.config['base_path'] + 'objdef_MC_30836*.root')

    if len(files) == 0:
        warning("No files found.")
        return

    masses = np.array([100, 130, 160, 190, 220], dtype=float)
    DSIDs  = [int(re.search('objdef_MC_(\d{6})\.root', f).group(1)) for f in files]

    # Plot acceptance, and acc x eff, with uncertainties versus signal mass point
    # --------------------------------------------------------------------------

    acceptance                = dict()
    acceptanceTimesEfficiency = dict()

    # Number of events relative to which the acceptance is computed
    base = {
        308363: 50000,
        308364: 48000,
        308365: 50000,
        308366: 50000,
        308367: 48000,
        }

    genfilteff = {
        308363: 2.9141e-01, 
        308364: 1.3795e-01, 
        308365: 7.5920e-02,
        308366: 4.5985e-02,
        308367: 2.9914e-02,
        }

    categories = dict()

    # Loop signal mass points
    for DSID, filename in zip(DSIDs, files):
        f = ROOT.TFile(filename, 'READ')

        # Get systematic variation categories
        f.cd("BoostedJet+ISRgamma")
        categories[DSID] = [e.GetName() for e in ROOT.gDirectory.GetListOfKeys()]
        
        acceptance               [DSID] = dict()
        acceptanceTimesEfficiency[DSID] = dict()

        # Loop categories
        for cat in categories[DSID]:
            precut  = f.Get('BoostedJet+ISRgamma/{cat}/EventSelection/Pass/Jet_tau21DDT/Precut' .format(cat=cat))
            postcut = f.Get('BoostedJet+ISRgamma/{cat}/EventSelection/Pass/Jet_tau21DDT/Postcut'.format(cat=cat))

            acceptance               [DSID][cat] = precut .GetEntries() / float(base[DSID]) * genfilteff[DSID]
            acceptanceTimesEfficiency[DSID][cat] = postcut.GetEntries() / float(base[DSID]) * genfilteff[DSID]
            pass
        pass

    acceptance_nominal                = {DSID: acceptance               [DSID]['Nominal'] for DSID in DSIDs}
    acceptanceTimesEfficiency_nominal = {DSID: acceptanceTimesEfficiency[DSID]['Nominal'] for DSID in DSIDs}

    acceptance_syst = dict()
    acceptance_stat = dict()
    acceptanceTimesEfficiency_syst = dict()
    acceptanceTimesEfficiency_stat = dict()
    for DSID in DSIDs:

        # Systematic variation groups
        groups = set(categories[DSID]) - set(['Nominal'])
        groups = sorted(list(set([grp.replace('__1up', '').replace('__1down', '') for grp in list(groups)])))

        # Acceptance
        # - - - - - - - - - - - - - - - - - - - - - - - - - - 
        f = acceptance_nominal[DSID]
        stat = 0 # np.sqrt( f * (1. - f) / base[DSID] ) # Only systematics

        syst = 0.
        nom = acceptance_nominal[DSID]
        for grp in groups:
            up   = acceptance[DSID][grp + '__1up']
            down = acceptance[DSID][grp + '__1down']
            diff = max(abs(up - nom), abs(down - nom))
            syst += np.square(diff)
            pass
        syst = np.sqrt(syst)

        acceptance_stat[DSID] = stat
        acceptance_syst[DSID] = syst

        # Acceptance x efficiency
        # - - - - - - - - - - - - - - - - - - - - - - - - - - 
        f = acceptanceTimesEfficiency_nominal[DSID]
        stat = 0 # np.sqrt( f * (1. - f) / base[DSID] ) # Only systematics!

        syst = 0.
        nom = acceptanceTimesEfficiency_nominal[DSID]
        for grp in groups:
            up   = acceptanceTimesEfficiency[DSID][grp + '__1up']
            down = acceptanceTimesEfficiency[DSID][grp + '__1down']
            diff = max(abs(up - nom), abs(down - nom))
            syst += np.square(diff)
            pass
        syst = np.sqrt(syst)

        acceptanceTimesEfficiency_stat[DSID] = stat
        acceptanceTimesEfficiency_syst[DSID] = syst        
        pass
    
    # Get total uncertainty
    acceptance_uncert                = np.array([np.sqrt( np.square(acceptance_stat               [DSID]) + np.square(acceptance_syst               [DSID])) for DSID in DSIDs], dtype=float)
    acceptanceTimesEfficiency_uncert = np.array([np.sqrt( np.square(acceptanceTimesEfficiency_stat[DSID]) + np.square(acceptanceTimesEfficiency_syst[DSID])) for DSID in DSIDs], dtype=float)

    # Produce acceptance graphs with errors
    graph_acceptance                = ROOT.TGraphErrors(len(DSIDs), 
                                                        masses, 
                                                        np.array([acceptance_nominal               [DSID] for DSID in DSIDs], dtype=float),
                                                        np.zeros_like(masses),
                                                        acceptance_uncert)

    graph_acceptanceTimesEfficiency = ROOT.TGraphErrors(len(DSIDs),
                                                        masses,
                                                        np.array([acceptanceTimesEfficiency_nominal[DSID] for DSID in DSIDs], dtype=float),
                                                        np.zeros_like(masses),
                                                        acceptanceTimesEfficiency_uncert)

    # Output histograms for harmonised plotting
    if args.save:
        f = ROOT.TFile('output/hists_isrgamma_acceptance.root', 'RECREATE')
        graph_acceptance.SetName('acc')
        graph_acceptance.Write()
        graph_acceptanceTimesEfficiency.SetName('acceff')
        graph_acceptanceTimesEfficiency.Write()
        f.Write()
        f.Close()
        pass

    return


    # Plot jet-level acceptance versus signal mass point
    # --------------------------------------------------------------------------

    counts = dict()
    labels = list()
    base_events = dict()
    for DSID, filename in zip(DSIDs, files):
        f = ROOT.TFile(filename, 'READ')
        cutflow = f.Get('BoostedJet+ISRgamma/Nominal/LargeRadiusJets/Nominal/Cutflow')
        ax = cutflow.GetXaxis()
        for bin in range(1, ax.GetNbins() + 1):
            label = ax.GetBinLabel(bin)
            if label not in counts: counts[label] = dict()
            if len(labels) < bin:   labels.append(label)
            counts[label][DSID] = cutflow.GetBinContent(bin)
            pass

        # Get number of events passing pre-selection
        cutflow = f.Get('BoostedJet+ISRgamma/Nominal/PreSelection/Nominal/Cutflow')
        base_events[DSID] = cutflow.GetBinContent(cutflow.GetXaxis().GetNbins())
        pass
    
    acceptances = {DSID: np.zeros((len(labels),)) for DSID in DSIDs}
    for idx, label in enumerate(labels):
        for DSID in DSIDs:
            acceptances[DSID][idx] = counts[label][DSID] / float(base_events[DSID]) #float(counts[labels[0]][DSID])
            pass
        pass

    c = ap.canvas(batch=not args.show)
    names = ["Pre-seleciton", "|#eta| < 2.0", "p_{T} > 200 GeV", "|#Delta#phi(#gamma,J)| > #pi/2", "p_{T} > 2 #times m", "#rho^{DDT} > 1.5"]
    for idx, (label, name) in enumerate(zip(labels, names)):
        acceptance_values = np.array([acceptances[DSID][idx] for DSID in DSIDs])
        acc = ROOT.TGraphErrors(len(DSIDs), masses, acceptance_values)
        c.graph(acc, linecolor=colours[idx], markercolor=colours[idx], linewidth=2, option=('A' if idx == 0 else '') + 'PL', label=name, legend_option='PL') 
        pass

    c.padding(0.5)
    c.xlabel("Signal mass point [GeV]")
    c.ylabel("#LTNum. large-#it{R} jets / event#GT")
    c.text(["#sqrt{s} = 13 TeV", "ISR #gamma channel", "Jet selection"], qualifier="Simulation Internal")
    c.legend()
    if args.save: c.save('plots/acceptance_jet.pdf')
    if args.show: c.show()


    # Plot event-level acceptance versus signal mass point
    # --------------------------------------------------------------------------
    
    treenames = ['BoostedJet+ISRgamma/Nominal/PreSelection/Nominal/HLT_g140_loose/Postcut',
                 tf.config['finaltree'].replace('Jet_tau21DDT', 'NumPhotons'), 
                 tf.config['finaltree'].replace('Jet_tau21DDT', 'NumLargeRadiusJets'), 
                 tf.config['finaltree']]
    data = {treename: loadData(files, treename, prefix=tf.config['prefix']) for treename in treenames}
    info = loadData(files, tf.config['outputtree'], stop=1)

    # Scaling by cross section
    xsec = loadXsec(tf.config['xsec_file'])
    
    # Append new DSID field # @TODO: Make more elegant?
    for key in data:
        data[key] = append_fields(data[key], 'DSID', np.zeros((data[key].size,)), dtypes=int)
        for idx in info['id']:    
            msk = (data[key]['id'] == idx) # Get mask of all 'data' entries with same id, i.e. from same file
            DSID = info['DSID'][idx]  # Get DSID for this file
            data[key]['weight'][msk] *= xsec[DSID] # Scale by cross section x filter eff. for this DSID
            data[key]['DSID']  [msk] = DSID        # Store DSID
            pass
        data[key]['weight'] *= tf.config['lumi'] # Scale all events (MC) by luminosity
        pass

    # Check output.
    if 0 in [data[key].size for key in data]:
        warning("No data was loaded.")
        return 

    base_events     = np.array([50000., 48000., 50000., 50000., 48000.], dtype=float)
    acceptances = list()

    for key in treenames:
        accepted_events = np.zeros_like(base_events)

        for idx, DSID in enumerate(DSIDs):
            accepted_events[idx] = np.sum(data[key]['DSID'] == DSID)
            pass

        acceptances.append(accepted_events / base_events)
        pass

    print "Mu scaling factors for full MC:"
    nsb = acceptances[-1] / acceptances[-2]
    for (mass, factor) in zip(masses, nsb):
        print "%3d GeV: %.3f" % (mass, factor)
        pass

    interpolation_masses = np.linspace(100, 220, (220 - 100) / 5 + 1, endpoint=True)
    nsb_interpolated = np.exp(np.interp(interpolation_masses, masses, np.log(nsb)))
    print "Mu scaling factors, logarithmically interpolated:"
    for m,n in zip(interpolation_masses, nsb_interpolated):
        print "%d GeV: %.3f" % (m,n)
        pass

    acc_interpolated = np.interp(interpolation_masses, masses, acceptances[-2])
    print "Signal acceptance up until tau21DDT cut, linearly interpolated:"
    for m,a in zip(interpolation_masses, acc_interpolated):
        print "%d GeV: %.3f" % (m,a)
        pass

    # Plot: Event-level ecceptance
    c = ap.canvas(batch=not args.show)
    names = ["Pre-selection", "= 1 #gamma", "#geq 1 jet", "#tau_{21}^{DDT} < 0.5"]
    for icut, (name, acceptance) in enumerate(zip(names,acceptances)):
        acc = ROOT.TGraphErrors(len(DSIDs), masses, acceptances[icut])
        c.graph(acc, linecolor=colours[icut], markercolor=colours[icut], linewidth=2, option=('A' if icut == 0 else '') + 'PL', label=name, legend_option='PL') 
        pass
    c.xlabel("Signal mass point [GeV]")
    c.ylabel("Acceptance (Z' #rightarrow large-#it{R} jet + #gamma)")
    c.text(["#sqrt{s} = 13 TeV", "ISR #gamma channel", "Event selection"], qualifier="Simulation Internal")
    c.legend()
    if args.save: c.save('plots/acceptance_event.pdf')
    if args.show: c.show()

    return
Example #7
0
def main():

    # Parse command-line arguments
    args = parser.parse_args()

    path = "/afs/cern.ch/user/a/asogaard/public/dijetisr/paperfigures/"

    compcolours = {
        'QCD': ROOT.kAzure + 7,
        'WHad': ROOT.kRed - 4,
        'ZHad': ROOT.kOrange + 4,
        'syst': ROOT.kGreen + 1,
    }

    qualifier = ""  # "Internal" # "Internal"

    # Setup
    # -- Limit the number of axis digits to 4 from 5, to reduce clutter
    ROOT.TGaxis.SetMaxDigits(4)

    # Tau21 decorrelation plots
    # --------------------------------------------------------------------------

    basedir = {
        'isrjet':
        '/eos/atlas/unpledged/group-wisc/users/lkaplan/dijetISR_all/dijetISR/plotsForNote/outputs/',
        'isrgamma': '/afs/cern.ch/user/a/asogaard/public/dijetisr/',
    }

    plottypes = ['correlation', 'decorrelation']
    for plottype in plottypes:

        if plottype == 'decorrelation':
            filenames = {
                'isrjet': 'hists_isrjet_decorrelation.root',
                'isrgamma': 'hists_isrgamma_decorrelation_tau21DDT_vs_m.root',
            }
        elif plottype == 'correlation':
            filenames = {
                'isrjet': 'hists_isrjet_correlation.root',
                'isrgamma': 'hists_isrgamma_decorrelation_tau21_vs_rhoDDT.root'
            }
        else:
            assert False
            pass

        for key, filename in filenames.iteritems():
            # Open file
            f = ROOT.TFile.Open(basedir[key] + filename)

            # Get list of profile names
            names = sorted(
                list(map(lambda tkey: tkey.GetName(), f.GetListOfKeys())))

            # Load profiles
            profiles = list()
            for name in names:

                # Load profie
                h = f.Get(name)
                h.SetDirectory(0)

                # Get pT range
                m = re.search('.*\_([\d]+)\_([\d]+)\_.*', name)
                pt = map(int, (m.group(1), m.group(2)))

                # Get signal status
                sig = ('sig' in name)
                profiles.append((h, sig, pt))
                pass

            # Create canvas
            c = ap.canvas(batch=not args.show)

            # Plot profiles
            colors = [ROOT.kBlack, compcolours['WHad'], compcolours['QCD']]
            for plot_signal in [False, True]:
                idx = 0
                for profile, sig, pt in profiles:
                    # Select desired class
                    if sig != plot_signal: continue

                    # Define style variables
                    color = colors[idx]
                    markerstyle = (24 if plot_signal else 20)

                    # Plot profile
                    c.plot(profile,
                           markerstyle=markerstyle,
                           markersize=1,
                           markercolor=color,
                           linecolor=color,
                           option='PE',
                           legend_option='PE',
                           label="p_{T} #in  [%d, %d] GeV" % (pt[0], pt[1]))

                    # Increment counter
                    idx += 1
                    pass

                # Draw class-specific header
                header = "Signal, Z'(160 GeV):" if plot_signal else "Background:"
                if plottype == 'decorrelation':
                    c.legend(header=header,
                             width=0.25,
                             ymax=0.38,
                             xmin=0.17 + 0.38 * plot_signal)
                elif plottype == 'correlation':
                    c.legend(header=header,
                             width=0.25,
                             ymax=0.38 + 0.35 * plot_signal,
                             xmin=0.17 + 0.38 * plot_signal)
                else:
                    assert False
                    pass
                pass

            # Re-draw axes on top
            c.pads()[0]._primitives[0].Draw('AXIS SAME')

            # Decorations
            c.ylim(0, 1)
            if plottype == 'decorrelation':
                c.xlim(50, 300)
                c.xlabel("Large-#it{R} jet mass [GeV]")
                c.ylabel("#LT#tau_{21}^{DDT}#GT")
            elif plottype == 'correlation':
                c.xlim(1, 6)
                c.xlabel("Large-#it{R} jet #rho^{DDT}")
                c.ylabel("#LT#tau_{21}#GT")
            else:
                assert False
                pass

            c.text([
                "#sqrt{s} = 13 TeV",
                "{} channel".format("Jet" if key == 'isrjet' else "Photon")
            ],
                   qualifier="Simulation")

            # Show/save
            if args.show:
                c.show()
                pass

            if args.save:
                c.save('plots/fig2_{}_{}.pdf'.format(plottype,
                                                     key.replace('isr', '')))
                pass
            pass
        pass

    # W/Z plots
    # --------------------------------------------------------------------------
    for isrjet in [True, False]:

        if isrjet:
            f = ROOT.TFile(path + "hists_isrjet_WZ.root")
        else:
            f = ROOT.TFile(path + "hists_isrgamma_WZ.root")
            pass

        names = ['QCD', 'QCD_up', 'QCD_down', 'data', 'WHad', 'ZHad']

        histograms = dict()
        for name in names:
            hist = f.Get('h_mJ_' + name)
            hist.SetDirectory(0)
            # Store histogram
            histograms[name] = hist
            pass

        f.Close()

        # Combine  W/Z component
        histograms['WZHad'] = histograms['WHad'].Clone(
            histograms['WHad'].GetName().replace('W', 'WZ'))
        histograms['WZHad'].Add(histograms['ZHad'])

        # Compute systematics band
        histograms['syst'] = histograms['QCD'].Clone("h_mJ_syst")
        for bin in range(1, histograms['syst'].GetXaxis().GetNbins() + 1):
            nom = histograms['QCD'].GetBinContent(bin)
            up = histograms['QCD_up'].GetBinContent(bin)
            down = histograms['QCD_down'].GetBinContent(bin)
            histograms['syst'].SetBinError(bin,
                                           max(abs(up - nom), abs(nom - down)))
            pass

        # -- canvas
        c = ap.canvas(num_pads=2, fraction=0.45, batch=not args.show)
        pads = c.pads()

        # -- main pad
        h_mc = c.stack(histograms['QCD'],
                       fillcolor=compcolours['QCD'],
                       label='Background est.')
        h_zhad = c.stack(histograms['ZHad'],
                         fillcolor=compcolours['ZHad'],
                         label='Z + %s' % ('jets' if isrjet else '#gamma'))
        h_whad = c.stack(histograms['WHad'],
                         fillcolor=compcolours['WHad'],
                         label='W + %s' % ('jets' if isrjet else '#gamma'))
        h_sum = c.hist(histograms['QCD'],
                       fillstyle=3245,
                       fillcolor=ROOT.kGray + 3,
                       option='E2',
                       label='Bkg. stat. uncert.')
        """ Using green dashed line to indicate syst error"
        h_bkg_up   = c.hist(histograms['QCD_up'],   linestyle=2, linecolor=compcolours['syst'], label='Syst. uncert.')
        h_bkg_down = c.hist(histograms['QCD_down'], linestyle=2, linecolor=compcolours['syst'])
        """
        h_syst = c.hist(histograms['syst'],
                        fillstyle=1001,
                        alpha=0.30,
                        fillcolor=ROOT.kGray + 3,
                        option='E2',
                        label='Bkg. syst. uncert.')

        h_data = c.plot(histograms['data'],
                        label='Data',
                        option='PE0X0',
                        legend_option='PE')

        # -- diff pad
        pads[1].hist(histograms['WZHad'],
                     fillcolor=compcolours['WHad'],
                     option='HIST')
        pads[1].hist(histograms['ZHad'],
                     fillcolor=compcolours['ZHad'],
                     option='HIST')
        #c.diff_plot((h_bkg_up,   histograms['QCD']), option='HIST')
        #c.diff_plot((h_bkg_down, histograms['QCD']), option='HIST')
        c.diff_plot((histograms['syst'], histograms['QCD']),
                    fillcolor=ROOT.kGray + 3,
                    alpha=0.30,
                    option='E2',
                    uncertainties=False)
        c.diff_plot((histograms['data'], histograms['QCD']), option='PE0X0')

        # -- statistical test
        h_mc.Add(h_zhad)
        h_mc.Add(h_whad)
        for bin in range(1, h_mc.GetXaxis().GetNbins()):
            stat = h_mc.GetBinError(bin)

            #nom  = h_sum     .GetBinContent(bin)
            #up   = h_bkg_up  .GetBinContent(bin)
            #down = h_bkg_down.GetBinContent(bin)
            #syst = max(abs(up-nom), abs(down-nom))
            syst = histograms['syst'].GetBinError(bin)

            h_mc.SetBinError(bin, np.sqrt(np.square(stat) + np.square(syst)))
            pass
        chi2 = h_data.Chi2Test(h_mc, "UW CHI2 P")
        KS = h_data.KolmogorovTest(h_mc)
        ndf = h_mc.GetXaxis().GetNbins() - 1

        # -- decorations
        c.text([
            "#sqrt{s} = 13 TeV,  36.1 fb^{-1}", "W/Z validation",
            "%s channel" % ('Jet' if isrjet else 'Photon')
        ],
               qualifier=qualifier)
        c.xlabel('Large-#it{R} jet mass [GeV]')
        c.ylabel('Events / 2 GeV')
        c.padding(0.47)  # (0.45)
        if isrjet: pads[1].ylim(-1000, 5000)
        else: pads[1].ylim(-140, 700)
        pads[1].ylabel('Data - background est.')
        pads[1].yline(0, linestyle=1, linecolor=ROOT.kBlack)
        c.region("SR", 0.8 * 85., 1.2 * 85.)
        c.legend(ymax=0.891)  # ..., sort=True)

        stats_string = "KS prob. = %.3f  |  #chi^{2}/N_{dof} (prob.) = %.1f/%d (%.3f)" % (
            KS, chi2, ndf, ROOT.TMath.Prob(chi2, ndf))
        #c.latex(stats_string, 0.95 , 0.96, NDC=True, align=31, textsize=16)

        if args.save:
            c.save('plots/paperplot_wz_%s.pdf' %
                   ('jet' if isrjet else 'gamma'))
        if args.show: c.show()
        pass

    # Search plots
    # --------------------------------------------------------------------------
    for isrjet, mass, log in itertools.product([True, False],
                                               [140, 150, 160, 220], [True]):

        if isrjet and mass == 140: continue  # Sample not available

        if isrjet:
            f = ROOT.TFile(path + "hists_isrjet_%d.root" % mass)
        else:
            try:
                # Try to get file with signal...
                f = ROOT.TFile(
                    path +
                    "hists_isrgamma_datadistributions_%dGeV_mu100.root" % mass)
            except:
                # ... otherwise, default to file without
                f = ROOT.TFile(path +
                               "hists_isrgamma_datadistributions_%dGeV.root" %
                               mass)
                pass
            pass

        names = ['QCD', 'QCD_up', 'QCD_down', 'data', 'WHad', 'ZHad', 'sig']

        def normalise(hist):
            """Divide histogram by binwidth."""
            for bin in range(1, hist.GetXaxis().GetNbins() + 1):
                hist.SetBinContent(
                    bin,
                    hist.GetBinContent(bin) / float(hist.GetBinWidth(bin)))
                hist.SetBinError(
                    bin,
                    hist.GetBinError(bin) / float(hist.GetBinWidth(bin)))
                pass
            return hist

        histograms = dict()
        for name in names:
            hist = f.Get('h_mJ_' + name)
            try:
                hist.SetDirectory(0)

                if not isrjet:
                    hist = normalise(hist)
                    pass
                histograms[name] = hist

            except:
                # This mass point doesn't have a signal shape
                warning("Mass point %d doesn't have a signal shape." % mass)

                # Try to access the interpolated signal
                interp_path = "/eos/atlas/user/a/asogaard/Analysis/2016/BoostedJetISR/StatsInputs/2017-08-06/"
                interp_filename = "{}_{:d}.root".format(
                    "sig" if isrjet else "ISRgamma_signal", mass)
                interp_f = ROOT.TFile(interp_path + interp_filename, "READ")
                interp_treename = ("Signal_ISRjet_{:d}" if isrjet else
                                   "SIGNAL_{:d}_Nominal").format(mass)
                interp_t = interp_f.Get(interp_treename)
                array = root_numpy.tree2array(interp_t)
                fields = list(array.dtype.names)

                # -- Fill new histogram for interpolated signal
                bins = tf.config['massbins']
                c = ap.canvas(batch=True)
                warning("Fields : [{}, {}]".format(*fields))
                h_interp = c.hist(array[fields[0]],
                                  bins=bins,
                                  weights=array[fields[1]],
                                  display=False)
                warning(
                    "  Setting interpolated histogram as '{}'".format(name))
                histograms[name] = normalise(h_interp)
                pass
            pass

        f.Close()

        # Divide by bins width
        """
        if not isrjet:
            for hist in histograms.itervalues():
                for bin in range(1, hist.GetXaxis().GetNbins() + 1):
                    hist.SetBinContent(bin, hist.GetBinContent(bin) / float(hist.GetBinWidth(bin)))
                    hist.SetBinError  (bin, hist.GetBinError  (bin) / float(hist.GetBinWidth(bin)))
                    pass
                pass
            pass
        #"""

        # Combine W/Z components
        histograms['WZHad'] = histograms['WHad'].Clone(
            histograms['WHad'].GetName().replace('W', 'WZ'))
        histograms['WZHad'].Add(histograms['ZHad'])

        # Add stat. and syst. uncert. in quadrature
        for bin in range(1, histograms['QCD'].GetXaxis().GetNbins() + 1):
            stat = histograms['QCD'].GetBinError(bin)
            nom = histograms['QCD'].GetBinContent(bin)
            up = histograms['QCD_up'].GetBinContent(bin)
            down = histograms['QCD_down'].GetBinContent(bin)
            syst = max(abs(up - nom), abs(down - nom))
            histograms['QCD_up'].SetBinContent(
                bin, nom + np.sqrt(np.square(stat) + np.square(syst)))
            histograms['QCD_down'].SetBinContent(
                bin, nom - np.sqrt(np.square(stat) + np.square(syst)))
            pass

        # Add W/Z component to background variations
        histograms['QCD_up'].Add(histograms['WZHad'])
        histograms['QCD_down'].Add(histograms['WZHad'])

        # -- canvas
        c = ap.canvas(num_pads=2, batch=not args.show)
        pads = c.pads()

        # -- main pad
        h_mc = c.stack(histograms['WZHad'],
                       fillcolor=compcolours['WHad'],
                       label='W/Z + %s' % ('jets' if isrjet else '#gamma'))
        h_qcd = c.stack(histograms['QCD'],
                        fillcolor=compcolours['QCD'],
                        label='Background est.')

        if 'sig' in histograms:
            c.hist(histograms['sig'],
                   linestyle=1,
                   linecolor=ROOT.kViolet + 2,
                   label="Z' (%d GeV)" % mass)
        else:
            warning("Key 'sig' not in `histograms`")
            pass

        h_sum = c.getStackSum()
        h_sum = c.hist(h_sum,
                       fillstyle=3245,
                       fillcolor=ROOT.kGray + 3,
                       option='E2',
                       label='Bkg. stat. uncert.')
        """ Using green dashed line to indicate stat + syst error"
        h_bkg_up   = c.hist(histograms['QCD_up'],   linestyle=2, linecolor=compcolours['syst'],
                            label='Stat. #oplus syst.')
        h_bkg_down = c.hist(histograms['QCD_down'], linestyle=2, linecolor=compcolours['syst'])
        """
        h_bkg_var = h_sum.Clone("h_bkg_var")
        for bin in range(1, h_bkg_var.GetXaxis().GetNbins() + 1):
            nom = h_sum.GetBinContent(bin)
            up = histograms['QCD_up'].GetBinContent(bin)
            down = histograms['QCD_down'].GetBinContent(bin)
            h_bkg_var.SetBinError(bin, max(abs(up - nom), abs(nom - down)))
            pass
        h_bkg_var = c.hist(h_bkg_var,
                           fillstyle=1001,
                           alpha=0.30,
                           fillcolor=ROOT.kGray + 3,
                           option='E2',
                           label='Bkg. stat. #oplus syst.')

        h_data = c.plot(histograms['data'],
                        label='Data',
                        option='PE0X0',
                        legend_option='PE')

        # -- diff pad
        if isrjet: pads[1].ylim(0.98, 1.02)
        else: pads[1].ylim(0.85, 1.15)

        pulls_stat_syst = c.ratio_plot((h_bkg_var, h_sum), option='E2')
        pulls_bkg_stat = c.ratio_plot((h_sum, h_sum), option='E2')
        pulls_data = c.ratio_plot((histograms['data'], h_sum),
                                  option='PE0X0',
                                  oob=True)

        # -- statistical test
        h_mc.Add(h_qcd)
        for bin in range(1, h_mc.GetXaxis().GetNbins()):
            nom = h_mc.GetBinContent(bin)
            #up   = h_bkg_up  .GetBinContent(bin)
            #down = h_bkg_down.GetBinContent(bin)
            #statPlusSyst = max(abs(up-nom), abs(down-nom))
            statPlusSyst = h_bkg_var.GetBinError(bin)

            # h_bkg_{up,down} are stats. oplus syst.
            h_mc.SetBinError(bin, statPlusSyst)
            pass
        chi2 = h_data.Chi2Test(h_mc, "UW CHI2 P")
        KS = h_data.KolmogorovTest(h_mc)
        ndf = h_mc.GetXaxis().GetNbins() - 1

        # -- decorations
        c.text([
            "#sqrt{s} = 13 TeV,  36.1 fb^{-1}",
            "%s channel" % ('Jet' if isrjet else 'Photon')
        ],
               qualifier=qualifier)
        c.xlabel('Large-#it{R} jet mass [GeV]')
        c.ylabel('Events / GeV')  # ... / 5 GeV

        if isrjet:
            c.ymin(150. / 5.)
        else:
            c.ymin(10. / 5.)
            pass

        if log:
            c.padding(0.42)  # 0.45 | 0.50
        else:
            c.padding(0.35)
            pass
        pads[1].ylabel('Data / est.')
        pads[1].yline(1, linestyle=1, linecolor=ROOT.kBlack)
        c.region("SR", 0.8 * mass, 1.2 * mass, offset=0.07
                 )  #, offset=(0.14 if (mass == 150 and not isrjet) else 0.07))
        c.legend(ymax=0.89)  # ..., sort=True)

        c.log(log)

        stats_string = "KS prob. = %.3f  |  #chi^{2}/N_{dof} (prob.) = %.1f/%d (%.3f)" % (
            KS, chi2, ndf, ROOT.TMath.Prob(chi2, ndf))

        if args.save:
            c.save('plots/paperplot_%s_%dGeV%s.pdf' %
                   ('jet' if isrjet else 'gamma', mass, '_log' if log else ''))
        if args.show: c.show()

        # Temp: Pre-fit pull plots for journal reviewer
        if mass not in [160, 220]: continue
        print "=" * 40
        print "isrjet: {}, mass: {}".format(isrjet, mass)
        pulls = list()
        diffs = list()
        errs = list()
        CRs = list()
        for ibin in range(1, pulls_stat_syst.GetXaxis().GetNbins() + 1):
            # @TODO: Only in signal region?
            CRs.append(
                abs(pulls_stat_syst.GetXaxis().GetBinCenter(ibin) - mass) /
                mass > 0.2)
            diff = pulls_data.GetBinContent(ibin) - 1.
            err_bkg = pulls_stat_syst.GetBinError(ibin)
            err_data = pulls_data.GetBinError(ibin)
            err = np.sqrt(err_bkg**2 + err_data**2)
            pull = diff / np.sqrt(err_bkg**2 + err_data**2)

            diffs.append(diff)
            errs.append(err)
            pulls.append(pull)
            pass
        pulls_cr = [pull for cr, pull in zip(CRs, pulls) if cr]

        print "CR: mean +/- rms (eom) of pulls: {} +/- {} ({})".format(
            np.mean(pulls_cr), np.std(pulls_cr),
            np.std(pulls_cr) / np.sqrt(len(pulls_cr)))
        c1 = ap.canvas(batch=not args.show)
        bins = np.linspace(-3, 3, 6 * 2 + 1, endpoint=True)
        h1 = c1.hist(pulls, bins=bins, linecolor=ROOT.kRed, label='All bins')
        h1_cr = c1.hist(pulls_cr,
                        bins=bins,
                        linecolor=ROOT.kBlue,
                        linestyle=2,
                        label='Only CR bins')

        print "==== FULL:"
        h1.Fit('gaus', 'V+')
        print "\n==== CR:"
        h1_cr.Fit('gaus', 'V+')

        c1.xlabel('Pre-fit pulls')
        c1.ylabel('Number of large-#it{R} jet mass bins')
        c1.text([
            "{} channel".format('Jet' if isrjet else 'Photon'),
            "Mass point: {} GeV".format(mass)
        ],
                qualifier='Internal')
        c1.legend()
        c1.legend()
        c1.save('plots/temp_pulls_{}_{}.pdf'.format(
            'jet' if isrjet else 'photon', mass))
        #c1.show()
        pass

    # tau21DDT cut optimisation
    # --------------------------------------------------------------------------
    mass = 160
    for isrjet in [True, False]:  # [True, False]:

        if isrjet:
            f = ROOT.TFile(path + "hists_isrjet_cutoptimisation.root")
        else:
            f = ROOT.TFile(path + "hists_isrgamma_cutoptimisation.root")
            pass

        if not isrjet:
            names = [
                'h_tau21DDT_bkg',
                'h_tau21DDT_sig%d' % mass,
                'gr_improvements_sig%d' % mass
            ]
        else:
            names = ['h_bkg_plot', 'h_sig_plot', 'Graph']
            pass

        histograms = dict()
        for name, title in zip(names, ['bkg', 'sig', 'impr']):
            hist = f.Get(name)
            try:
                hist.SetDirectory(0)
            except:
                # TGraph
                pass
            histograms[title] = hist
            pass

        f.Close()

        # Normalise graph
        gr = histograms['impr']
        N = gr.GetN()
        base, x, y = 0, ROOT.Double(0), ROOT.Double(-inf)
        gr.GetPoint(N - 1, x, y)
        base = float(y)
        for i in range(N):
            gr.GetPoint(i, x, y)
            gr.SetPoint(i, float(x), float(y) / base)
            pass

        # -- canvas
        c = ap.canvas(num_pads=1, batch=not args.show)
        pads = c.pads()

        # -- main pad
        c.hist(histograms['bkg'],
               fillcolor=compcolours['QCD'],
               label="Incl. #gamma MC" if not isrjet else "Multijet MC")
        c.hist(histograms['sig'],
               linecolor=compcolours['WHad'],
               label="Z' (%d GeV)" % mass)

        # -- overlay
        o = ap.overlay(c, color=ROOT.kViolet)
        o.graph(histograms['impr'],
                linecolor=ROOT.kViolet,
                linewidth=2,
                option='L')

        # Get point of maximum improvement
        gr = histograms['impr']
        N = gr.GetN()
        ymax, xmax, x, y = -inf, 0, ROOT.Double(0), ROOT.Double(-inf)
        for i in range(N):
            gr.GetPoint(i, x, y)
            if float(y) > ymax:
                ymax = float(y)
                xmax = float(x)
                pass
            pass
        o.line(xmax, 0, xmax, ymax)

        # -- decorations
        c.text([
            "#sqrt{s} = 13 TeV,  36.1 fb^{-1}",
            "%s channel" % ('Jet' if isrjet else 'Photon')
        ],
               qualifier="Simulation " + qualifier)
        c.xlabel("Large-#it{R} jet #tau_{21}^{DDT}")
        c.ylabel("Fraction of events")
        o.label("Relative improvement in significance")
        c.legend(width=0.26)

        if args.show: c.show()
        if args.save:
            c.save('plots/paperplot_%s_%dGeV_cutoptimisation.pdf' %
                   ('jet' if isrjet else 'gamma', mass))
        pass

    # Signal acceptance
    # --------------------------------------------------------------------------

    # Create canvas
    c = ap.canvas(batch=not args.show)

    for idx, isrjet in enumerate([False, True]):

        if isrjet:
            f = ROOT.TFile(path + "hists_isrjet_sigacc.root")
        else:
            f = ROOT.TFile(path + "hists_isrgamma_acceptance.root")
            pass

        if isrjet:
            acc = f.Get('g_ptj')
            acceff = f.Get('g_tau')
        else:
            acc = f.Get('acc')
            acceff = f.Get('acceff')
            pass

        print ""
        print "-" * 40
        print "ISR jet:", isrjet
        x, y = ROOT.Double(), ROOT.Double()
        print "Acceptance:"
        for i in range(acc.GetN()):
            acc.GetPoint(i, x, y)
            print "  (x,y) = ({},{})".format(x, y)
            pass
        print "Acceptance x efficiency:"
        for i in range(acceff.GetN()):
            acceff.GetPoint(i, x, y)
            print "  (x,y) = ({},{})".format(x, y)
            pass

        # -- Draw graphs
        opts = {
            'linecolor': colours[idx],
            'fillcolor': colours_light[idx],
            'markercolor': colours[idx],
            'linewidth': 2
        }
        c.graph(acc,
                option=('A' if idx == 0 else '') + '3',
                label="%s channel" % ('Photon' if not isrjet else 'Jet'),
                legend_option='L',
                **opts)
        c.graph(acc, option='LX', **opts)
        opts['fillcolor'] = colours[idx]
        c.graph(acceff, option='3L', fillstyle=3245, **opts)
        pass

    c.log()
    #c.padding(0.4)
    #c.ymin(1.0E-04)
    c.ylim(1E-04, 1E+00)
    c.xlabel("m_{Z'} [GeV]")
    c.ylabel(
        "Acceptance, acc. #times efficiency (Z' #rightarrow large-#it{R} jet + #gamma/jet)"
    )
    c.text(["#sqrt{s} = 13 TeV"], qualifier="Simulation " + qualifier)
    c.legend(categories=[
        ("Acceptance", {
            'fillcolor': ROOT.kGray,
            'option': 'LF'
        }),
        ("Acc. #times eff.", {
            'fillcolor': ROOT.kGray + 2,
            'fillstyle': 3245,
            'option': 'LF'
        }),
    ],
             reverse=True)  #, ymax=0.84)
    if args.save: c.save('plots/paperplot_acceptance.pdf')
    if args.show: c.show()

    # Tau21 distributions
    # --------------------------------------------------------------------------

    for isrjet, ddt in itertools.product([True, False], ['', 'DDT']):

        # Create canvas
        c = ap.canvas(batch=not args.show)

        if isrjet:
            f = ROOT.TFile(path + "hists_isrjet_tau21{ddt}slices.root".format(
                ddt=ddt))
        else:
            f = ROOT.TFile(
                path +
                "hists_isrgamma_tau21{ddt}distributions.root".format(ddt=ddt))
            pass

        if isrjet:
            slices = {
                'pt': [
                    (500, 700),
                    (700, 900),
                    (900, 1100),
                ],
                'm': [
                    (100, 150),
                    (150, 200),
                    (200, 250),
                ],
            }
        else:
            slices = {
                'pt': [
                    (200, 300),
                    (300, 500),
                    (500, 1000),
                ],
                'm': [
                    (100, 150),
                    (150, 200),
                    (200, 250),
                ],
            }
            pass

        if isrjet:
            histograms = [
                f.Get('h_%d_%d_%d_%d' %
                      (sl['pt'][0], sl['pt'][1], sl['m'][0], sl['m'][1]))
                for sl in dict_product(slices)
            ]
        else:
            histograms = [
                f.Get('h_m_%d_%d_pt_%d_%d' %
                      (sl['m'][0], sl['m'][1], sl['pt'][0], sl['pt'][1]))
                for sl in dict_product(slices)
            ]
            pass

        category_names = [
            "[%.0f, %.0f] GeV" % (slices['m'][i][0], slices['m'][i][1])
            for i in range(len(slices['m']))
        ]

        # Draw
        for i, hist in enumerate(histograms):
            name = hist.GetName()
            if isrjet:
                pt1, pt2 = int(name.split('_')[1]), int(name.split('_')[2])
            else:
                pt1, pt2 = int(name.split('_')[5]), int(name.split('_')[6])
                pass
            #print "--", hist.GetName()
            label = "[%.0f, %.0f] GeV" % (pt1, pt2)
            c.hist(hist,
                   fillstyle=0,
                   linecolor=ROOT.kRed + (i % 3) * 2,
                   linestyle=1 + (i // 3),
                   label=label if i < 3 else None,
                   normalise=True,
                   option='HIST')
            pass

        # Decorations
        c.xlabel('Signal jet #tau_{21}^{%s}' % (ddt.upper()))
        c.ylabel('Fraction of events')
        c.text([
            "#sqrt{s} = 13 TeV",
            "%s selection" % ('Jet' if isrjet else 'Photon')
        ],
               qualifier="Simulation " + qualifier)
        c.padding(0.50)

        ymax = 0.735
        c.legend(header='Jet p_{T} in:', ymax=ymax)
        c.legend(header='Jet mass in:',
                 categories=[(category_names[idx], {
                     'linestyle': 1 + idx
                 }) for idx in range(len(category_names))],
                 ymax=ymax,
                 xmin=0.19)

        if args.show: c.show()
        if args.save:
            c.save('plots/paperplot_%s_tau21%sdistribution.pdf' %
                   ('jet' if isrjet else 'gamma', ddt))
        pass

    return
Example #8
0
def main():

    # Macro-specific styles
    ROOT.gROOT.GetStyle("AStyle").SetEndErrorSize(.5)

    # Parse command-line arguments
    args = parser.parse_args()
    ap.canvas(batch=not args.show)

    # Initialise categories for which to plot distinct curves for each histogram
    algorithms = ['Standard', 'LargeD0']
    names = ['Standard', 'Large radius']
    types = ['Signal']  # ['All', 'Signal']
    signals = ['Rhadron', 'RPV']

    groups = {
        'Rhadron': [
            'Rprod_10mm_30mm/',
            'Rprod_30mm_100mm/',
            'Rprod_100mm_300mm/',
        ],
        'RPV': [
            'Rprod_10mm_30mm/',
            'Rprod_30mm_100mm/',
            'Rprod_100mm_300mm/',
        ],
    }

    ylabel = "Standard deviation of the error on %s"

    deps = ['mu', 'pt']

    group_names = {
        signal: [
            '[%s]' % grp[6:-1].replace('_', ', ').replace('p', '.').replace(
                'mm', ' mm') for grp in groups[signal]
        ]
        for signal in signals
    }

    # Initialise variable versus which to plot the physics efficiency
    basic_vars = ['theta', 'phi', 'd0', 'z0', 'qOverP']

    # Initialise list of histograms to be plotted
    base = 'IDPerformanceMon/LargeD0/'
    histname = base + 'ResolutionPlots/{alg}Tracks/{t}/{group}res{depdim}_{var}_vs_{dep}'

    # Accessor function to get the y-axis maximum
    def get_ymax(var):
        if var == 'theta': return 0.01 * 1
        if var == 'phi': return 0.01 * 1
        if var == 'd0': return 1.0 * 1
        if var == 'z0': return 2.0 * 1
        if var == 'qOverP': return 0.05 * 1
        return 0.01

    def get_ymax_comb(var):
        if var == 'theta': return 0.008 * 1
        if var == 'phi': return 0.007 * 1
        if var == 'd0': return 1.2  # 0.8
        if var == 'z0': return 1.2 * 1
        if var == 'qOverP': return 0.020
        return 0.01

    # pT-binned RMS profiles
    # --------------------------------------------------------------------------

    histograms = dict()

    ptgroups = [
        'pT_1GeV_3GeV/',
        'pT_10GeV_30GeV/',
    ]

    ptgroup_names = [
        '[%s]' %
        grp[3:-1].replace('_', ', ').replace('p', '.').replace('GeV', ' GeV')
        for grp in ptgroups
    ]

    f = ROOT.TFile(filename.format(signal='Rhadron'), 'READ')
    ROOT.TH2.AddDirectory(False)

    # Create canvas
    c = ap.canvas(batch=not args.show, size=(700, 500))
    c_temp = ap.canvas(batch=True)

    # Loop Rprod bins
    for igroup, (group, groupname) in enumerate(
            zip(groups['Rhadron'], group_names['Rhadron'])):
        print group, '(%s)' % groupname

        # Loop pT bins
        for ipt, (ptgroup,
                  ptgroupname) in enumerate(zip(ptgroups, ptgroup_names)):
            print "--", ptgroup, '(%s)' % ptgroup_names
            hist = None

            # Loop tracking algorithms; add
            for alg in algorithms:
                hn = base + 'ResolutionPlots/{alg}Tracks/Signal/{group}{ptgroup}res_d0_vs_mu'.format(
                    alg=alg, group=group, ptgroup=ptgroup)
                h = f.Get(hn)
                h.SetDirectory(0)
                if hist is None:
                    hist = h.Clone(h.GetName() + '_clone')
                else:
                    hist.Add(h)
                    pass
                pass

            # Define bin edges
            if igroup < 2:
                pairs = [
                    (1, 2),  #  5 - 10
                    (3, 3),  # 10 - 15
                    (4, 4),  # 15 - 20
                    (5, 5),  # 20 - 25
                    (6, 6),  # 25 - 30
                    (7, 8),  # 30 - 40
                ]
            else:
                pairs = [
                    (1, 3),  #  0 - 15
                    (4, 5),  # 15 - 25
                    (6, 8),  # 25 - 40
                ]
                pass

            # Initialise graph point lists
            xs, ys, xels, xehs, yes = list(), list(), list(), list(), list()

            # Loop edge pairs to get projection
            for ibin, pair in enumerate(pairs):

                # Get and fit projection
                proj = hist.ProjectionY('_py', *pair)
                ax = hist.GetXaxis()

                # Clean-up (?) -- overflow bins
                nx = proj.GetXaxis().GetNbins()
                proj.SetBinContent(0, 0)
                proj.SetBinContent(nx + 1, 0)

                # Rebin (?)
                #if igroup > 0:
                #    #proj.RebinX(2*igroup)
                #    pass

                # Get graph variables
                x = 0.5 * (ax.GetBinCenter(pair[0]) + ax.GetBinCenter(pair[1]))
                wl = (x - ax.GetBinLowEdge(pair[0]))
                wh = (ax.GetBinUpEdge(pair[1]) - x)

                # Get parameter RMS and assoc. error
                ROOT.TH1.StatOverflows(False)

                # Set number of sigmas to use in core RMS calculation
                sigma = 3

                par, err, fit = getCoreStd(proj, sigma=sigma, fix_mean=0)
                par2p5, _, _ = getCoreStd(proj, sigma=2.5, fix_mean=0)
                par2p0, _, _ = getCoreStd(proj, sigma=2.0, fix_mean=0)

                syst = max(abs(par2p5 - par), abs(par2p0 - par))

                print "==> err:", err, "| syst:", syst
                err = np.sqrt(np.square(err) + np.square(syst))

                # Store data point
                if par > 0.:
                    xs.append(x)
                    ys.append(par)
                    xels.append(wl)
                    xehs.append(wh)
                    yes.append(err)
                    pass

                # Projection slice
                c_proj = ap.canvas(batch=not args.show)
                rms2sig, err2sig, fit2 = getCoreStd(proj, sigma=2, fix_mean=0)
                rms3sig, err3sig, fit3 = getCoreStd(proj, sigma=3, fix_mean=0)
                c_proj.hist(proj)
                c_proj._bare().cd()
                fit2.SetLineColor(ROOT.kBlue)
                fit3.SetLineColor(ROOT.kGreen)
                c_proj.xline(-2 * rms2sig,
                             text='-2#sigma',
                             linecolor=ROOT.kBlue)
                c_proj.xline(+2 * rms2sig,
                             text='+2#sigma',
                             linecolor=ROOT.kBlue)
                c_proj.xline(-3 * rms3sig,
                             text='-3#sigma',
                             linecolor=ROOT.kGreen)
                c_proj.xline(+3 * rms3sig,
                             text='+3#sigma',
                             linecolor=ROOT.kGreen)
                fit2.Draw('SAME')
                fit3.Draw('SAME')
                c_proj.xlim(-8 * rms3sig, +8 * rms3sig)
                c_proj.xlabel(displayNameUnit('d0'))
                c_proj.ylabel("Tracks")
                c_proj.text([
                    displayName('r') + " #in  " +
                    group_names['Rhadron'][igroup],
                    displayName('pt') + " #in  " + ptgroup_names[ipt],
                    signal_line('Rhadron') + ' / ' +
                    'Large radius and standard tracks',
                ] + [
                    "%s #in  [%.1f, %.1f] %s" %
                    (displayName('mu'), ax.GetBinLowEdge(
                        pair[0]), ax.GetBinUpEdge(pair[1]), displayUnit('mu'))
                ] + [
                    "Tracks: %d (%d)" %
                    (proj.Integral(),
                     proj.Integral(0,
                                   proj.GetXaxis().GetNbins() + 1))
                ],
                            qualifier=qualifier)

                if args.save:
                    c_proj.save(
                        'plots/%s_RobustnessResolution_slice__%s_vs_%s__%s_%s_%d_%d.pdf'
                        % ('Signal', 'd0', 'mu', 'Both', ptgroup[:-1], igroup,
                           ibin))

                pass  # end: loop bins

            graph = ROOT.TGraphAsymmErrors(len(xs), array('d', xs),
                                           array('d', ys), array('d', xels),
                                           array('d', xehs), array('d', yes),
                                           array('d', yes))

            # Create x-axis for graph
            graph = c_temp.graph(graph)
            c_temp._bare().cd()
            ROOT.gPad.Update()

            # Draw graph with x-axis
            c.graph(graph,
                    linecolor=colours[igroup],
                    markercolor=colours[igroup],
                    markerstyle=4 * ipt + 20,
                    linewidth=2,
                    linestyle=ipt + 1,
                    label=groupname if ipt == 0 else None)

            pass

        pass

    c.text([signal_line('Rhadron'), "Large radius and standard tracks"],
           qualifier=qualifier)
    c.legend(header=displayName('r') + " in:", width=0.28, ymax=0.872)
    c.legend(header=displayName('pt') + " in:",
             categories=[(name, {
                 'linestyle': i + 1,
                 'markerstyle': 4 * i + 20,
                 'option': 'PL',
                 'linewidth': 2
             }) for i, name in enumerate(ptgroup_names)],
             width=0.28,
             ymax=0.65)
    c.padding(0.65)
    c.logy()
    c.xlim(0, 40)

    c.xlabel(displayNameUnit('mu'))
    c.ylabel(ylabel % displayNameUnit('d0'))

    # Show/save
    savename = 'Rhadron_ResolutionPlots_BothTracks_Signal_res_d0_vs_mu_pTbinned.pdf'
    if args.show: c.show()
    if args.save: c.save('plots/' + savename)

    # Regular stuff
    # --------------------------------------------------------------------------

    # Loop all combinations of track parameter, truth particle type, signal process, and dependency variable
    for var, t, dep in itertools.product(basic_vars, types, deps):

        combined_graphs = {signal: list() for signal in signals}

        # Loop signal separately, in order to (optionally) compare the two
        for signal in signals:

            # Open file from which to read histograms.
            f = ROOT.TFile(filename.format(signal=signal), 'READ')
            ROOT.TH1.AddDirectory(False)
            ROOT.TH2.AddDirectory(False)

            # Get list of histograms to plot, manually.
            histograms = list()
            comb_projs = dict()
            comb_xs = dict()
            #comb_ws = dict()
            comb_wls = dict()
            comb_whs = dict()

            # Get histograms
            bin_pairs = {
                'pt': list(),
                'mu': list(),
            }

            for alg in algorithms:

                for igroup, group in enumerate(groups[signal]):

                    h = f.Get(
                        histname.format(alg=alg,
                                        var=var,
                                        t=t,
                                        group=group,
                                        dep=dep,
                                        depdim='2D' if dep == 'pt' else ''))
                    if h is None:
                        pass
                    try:
                        h.SetDirectory(
                            0)  # Keep in memory after file is closed.
                    except AttributeError:
                        print "PROBLEM: '%s'" % histname.format(
                            alg=alg,
                            var=var,
                            t=t,
                            group=group,
                            dep=dep,
                            depdim='2D' if dep == 'pt' else '')
                        continue

                    #xs, ys, xes, yes = list(), list(), list(), list()
                    xs, ys, xels, xehs, yes = list(), list(), list(), list(
                    ), list()

                    # Allocate space if necessary
                    if not (group in comb_projs):
                        comb_projs[group] = list()
                        comb_xs[group] = list()
                        comb_wls[group] = list()
                        comb_whs[group] = list()
                        pass

                    # Dynamically choose binning
                    if dep == 'pt' and len(bin_pairs['pt']) <= igroup:
                        nx, ny = h.GetXaxis().GetNbins(), h.GetYaxis(
                        ).GetNbins()
                        if signal == 'Rhadron':
                            edges = np.logspace(np.log10(1),
                                                np.log10(50),
                                                8 - 2 * igroup + 1,
                                                endpoint=True)
                        else:
                            edges = np.linspace(0,
                                                400,
                                                max(8 - 4 * igroup + 1, 2),
                                                endpoint=True)
                            #edges -= 0.2 # @TEMP: FIX FOR NICE BIN EDGES
                            edges[0] = 1
                            pass

                        bin_pairs['pt'].append(zip(edges[:-1], edges[1:]))
                        ax = h.GetXaxis()
                        bin_pairs['pt'][igroup] = [
                            (ax.FindBin(pair[0]), ax.FindBin(pair[1]))
                            for pair in bin_pairs['pt'][igroup]
                        ]

                        # Ensure there is no overlap between bins
                        for idx in range(len(bin_pairs['pt'][igroup]) - 1):
                            if bin_pairs['pt'][igroup][idx][1] >= bin_pairs[
                                    'pt'][igroup][idx + 1][0]:
                                bin_pairs['pt'][igroup][idx + 1] = (
                                    bin_pairs['pt'][igroup][idx][1] + 1,
                                    bin_pairs['pt'][igroup][idx + 1][1])
                                pass
                            pass

                        if signal == 'RPV':
                            bin_pairs['pt'][igroup][-1] = (
                                bin_pairs['pt'][igroup][-1][0], nx)
                            pass
                        pass

                    if dep == 'mu' and len(bin_pairs['mu']) <= igroup:
                        if igroup < 2:
                            pairs = [
                                (1, 2),  #  5 - 10
                                (3, 3),  # 10 - 15
                                (4, 4),  # 15 - 20
                                (5, 5),  # 20 - 25
                                (6, 6),  # 25 - 30
                                (7, 8),  # 30 - 40
                            ]
                        else:
                            pairs = [
                                (1, 3),  #  0 - 15
                                (4, 5),  # 15 - 25
                                (6, 8),  # 25 - 40
                            ]
                            pass

                        bin_pairs['mu'].append(pairs)
                        pass

                    # Loop x-axis bins in 2D histogram
                    for ibin in range(len(bin_pairs[dep][igroup])):

                        pair = bin_pairs[dep][igroup][ibin]
                        ax = h.GetXaxis()

                        # Get and fit projection
                        proj = h.ProjectionY('_py', *pair)

                        # Clean-up (?)
                        if dep == 'mu':
                            # If highest bin content is larger than the average bin content in the remaining bins, remove it
                            nx = proj.GetXaxis().GetNbins()
                            proj.SetBinContent(0, 0)
                            proj.SetBinContent(nx + 1, 0)
                            pass

                        # Rebin (?)
                        if dep == 'mu' and igroup > 0:
                            proj.RebinX(2 * igroup)
                            pass

                        # Get graph variables
                        x = 0.5 * (ax.GetBinCenter(pair[0]) +
                                   ax.GetBinCenter(pair[1]))
                        wl = (x - ax.GetBinLowEdge(pair[0]))
                        wh = (ax.GetBinUpEdge(pair[1]) - x)

                        # Add projection to list of combined projections (LRT + STD)
                        if len(comb_projs[group]) > ibin:
                            comb_projs[group][ibin].Add(proj)
                        else:
                            comb_projs[group].append(proj)
                            comb_xs[group].append(x)
                            comb_wls[group].append(wl)
                            comb_whs[group].append(wh)
                            pass

                        # Get parameter RMS and assoc. error
                        ROOT.TH1.StatOverflows(False)

                        # Set number of sigmas to use in core RMS calculation
                        sigma = 3

                        par, err, fit = getCoreStd(proj,
                                                   sigma=sigma,
                                                   fix_mean=0)
                        par2p5, _, _ = getCoreStd(proj, sigma=2.5, fix_mean=0)
                        par2p0, _, _ = getCoreStd(proj, sigma=2.0, fix_mean=0)

                        syst = max(abs(par2p5 - par), abs(par2p0 - par))

                        if var == 'd0' and dep == 'mu':
                            print "==> err, syst:", err, syst
                            pass
                        err = np.sqrt(np.square(err) + np.square(syst))

                        # Store data point
                        if par > 0.:
                            xs.append(x)
                            ys.append(par)
                            xels.append(wl / 2.)
                            xehs.append(wh / 2.)
                            yes.append(err)
                            pass

                        # Easy access
                        ax = h.GetXaxis()
                        pair = bin_pairs[dep][igroup][ibin]

                        # Save projections slices
                        '''
                        c_proj = ap.canvas(batch=not args.show)
                        #rms2sig, err2sig, sigma2_min, sigma2_max = getCoreRMS(proj, sigma=2, fix_mean=0)
                        #rms3sig, err3sig, sigma3_min, sigma3_max = getCoreRMS(proj, sigma=3, fix_mean=0)
                        rms2sig, err2sig, fit2 = getCoreStd(proj, sigma=2, fix_mean=0)
                        rms3sig, err3sig, fit3 = getCoreStd(proj, sigma=3, fix_mean=0)
                        #fit.SetRange(-3*rms3sig,3*rms3sig)
                        c_proj.hist(proj)
                        c_proj._bare().cd()
                        fit2.SetLineColor(ROOT.kBlue)
                        fit3.SetLineColor(ROOT.kGreen)
                        c_proj.xline(-2 * rms2sig, text='-2#sigma', linecolor=ROOT.kBlue)
                        c_proj.xline(+2 * rms2sig, text='+2#sigma', linecolor=ROOT.kBlue)
                        c_proj.xline(-3 * rms3sig, text='-3#sigma', linecolor=ROOT.kGreen)
                        c_proj.xline(+3 * rms3sig, text='+3#sigma', linecolor=ROOT.kGreen)
                        fit2.Draw('SAME')
                        fit3.Draw('SAME')
                        c_proj.xlim(-8*rms3sig, +8*rms3sig)
                        c_proj.xlabel(displayNameUnit(var))
                        c_proj.ylabel("Tracks")
                        c_proj.text([displayName('r') + " #in  " + group_names[signal][igroup],
                                     signal_line(signal) + ' / ' + alg,
                                     ] +
                                    ["%s #in  [%.1f, %.1f] %s" % (displayName(dep), 
                                                                  ax.GetBinLowEdge(pair[0]),
                                                                  ax.GetBinUpEdge (pair[1]),
                                                                  displayUnit(dep))] +
                                    ["Tracks: %d (%d)" % (proj.Integral(), proj.Integral(0, proj.GetXaxis().GetNbins() + 1))],
                                    qualifier=qualifier)
                        
                        if args.save: c_proj.save('plots/%s_RobustnessResolution_slice__%s_vs_%s__%s_%d_%d.pdf' % (signal, var, dep, alg, igroup, ibin))
                        '''
                        pass

                    # Create profile graph from points
                    if len(xs) > 0:
                        graph = ROOT.TGraphAsymmErrors(len(xs), array('d', xs),
                                                       array('d', ys),
                                                       array('d', xels),
                                                       array('d', xehs),
                                                       array('d', yes),
                                                       array('d', yes))
                    else:
                        graph = ROOT.TGraphErrors()
                        pass
                    histograms.append(graph)
                    pass

                pass

            # Close file
            f.Close()

            # Profiles for STD and LRT separately
            # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

            # Draw figure
            c = ap.canvas(batch=not args.show, size=(700, 500))
            c_temp = ap.canvas(batch=True)
            for i, alg in enumerate(algorithms):
                N = len(group_names[signal])
                N1, N2 = i * N, (i + 1) * N
                for hist, name, col in zip(histograms[N1:N2],
                                           group_names[signal], colours):
                    # Create x-axis for graph
                    hist = c_temp.graph(hist)
                    c_temp._bare().cd()
                    ROOT.gPad.Update()
                    # Draw graph with x-axis
                    c.graph(hist,
                            linecolor=col,
                            markercolor=col,
                            markerstyle=4 * i + 20,
                            linewidth=2,
                            linestyle=i + 1,
                            label=name if i == 0 else None)
                    pass
                pass

            c.text([signal_line(signal)] +
                   (["%s particles" % t] if t != 'Signal' else []),
                   qualifier=qualifier)
            c.legend(header=displayName('r') + " in:",
                     categories=[(name, {
                         'linestyle': i + 1,
                         'markerstyle': 4 * i + 20,
                         'option': 'PL',
                         'linewidth': 2
                     }) for i, name in enumerate(names)],
                     width=0.28)
            c.padding(0.50)
            c.xlim(h.GetXaxis().GetBinLowEdge(bin_pairs[dep][0][0][0]),
                   h.GetXaxis().GetBinUpEdge(bin_pairs[dep][0][-1][1]))

            c.xlabel(displayNameUnit(dep))
            c.ylabel(ylabel % displayNameUnit(var))
            if dep == 'pt':
                c.logy()
                pass

            # Show/save
            savename = '_'.join([signal] + histname.format(
                alg='', var=var, t=t, group='', dep=dep, depdim='').split('/')
                                [2:]) + '.pdf'
            if args.show: c.show()
            if args.save: c.save('plots/' + savename)

            # Profile for STD and LRT combined
            # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

            # Compute combined plots.
            comb_histograms = list()

            for igroup, (group, name) in enumerate(
                    zip(groups[signal], group_names[signal])
            ):  # if signal == 'Rhadron' else groups[:-1]):
                projs = comb_projs[group]
                xs = comb_xs[group]
                wls = comb_wls[group]
                whs = comb_whs[group]
                xels = [w for w in wls]
                xehs = [w for w in whs]
                ys, yes, _ = zip(*[
                    getCoreStd(proj, sigma=sigma, fix_mean=0) for proj in projs
                ])

                ys2p5, _, _ = zip(*[
                    getCoreStd(proj, sigma=2.5, fix_mean=0) for proj in projs
                ])
                ys2p0, _, _ = zip(*[
                    getCoreStd(proj, sigma=2.0, fix_mean=0) for proj in projs
                ])

                syst = np.maximum(np.abs(np.array(ys2p5) - np.array(ys)),
                                  np.abs(np.array(ys2p0) - np.array(ys)))
                yes = np.sqrt(np.square(np.array(yes)) + np.square(syst))

                graph = ROOT.TGraphAsymmErrors(len(xs), array('d', xs),
                                               array('d', ys),
                                               array('d', xels),
                                               array('d',
                                                     xehs), array('d', yes),
                                               array('d', yes))

                combined_graphs[signal].append((name, graph))
                comb_histograms.append(graph)

                # Draw projection slice
                '''
                #for ibin, (proj, x, w) in enumerate(zip(projs, xs, ws)):
                for ibin, (proj, x, wl, wh) in enumerate(zip(projs, xs, wls, whs)):
                    c_proj = ap.canvas(batch=not args.show)
                    #rms2sig, err2sig, sigma2_min, sigma2_max = getCoreRMS(proj, sigma=2, fix_mean=0)
                    #rms3sig, err3sig, sigma3_min, sigma3_max = getCoreRMS(proj, sigma=3, fix_mean=0)
                    rms2sig, err2sig, fit2  = getCoreStd(proj, sigma=2, fix_mean=0)
                    rms3sig, err3sig, fit3 = getCoreStd(proj, sigma=3, fix_mean=0)
                    c_proj.hist(proj)
                    c_proj._bare().cd()
                    #fit.SetRange(-3*rms3sig,3*rms3sig)
                    fit2.SetLineColor(ROOT.kBlue)
                    fit3.SetLineColor(ROOT.kGreen)
                    #c_proj.xline(sigma2_min, text='-2#sigma', linecolor=ROOT.kBlue)
                    #c_proj.xline(sigma2_max, text='+2#sigma', linecolor=ROOT.kBlue)
                    #c_proj.xline(sigma3_min, text='-3#sigma', linecolor=ROOT.kGreen)
                    #c_proj.xline(sigma3_max, text='+3#sigma', linecolor=ROOT.kGreen)
                    c_proj.xline(-2 * rms2sig, text='-2#sigma', linecolor=ROOT.kBlue)
                    c_proj.xline(+2 * rms2sig, text='+2#sigma', linecolor=ROOT.kBlue)
                    c_proj.xline(-3 * rms3sig, text='-3#sigma', linecolor=ROOT.kGreen)
                    c_proj.xline(+3 * rms3sig, text='+3#sigma', linecolor=ROOT.kGreen)
                    fit2.Draw('SAME')
                    fit3.Draw('SAME')
                    c_proj.xlabel(displayNameUnit(var))
                    c_proj.ylabel("Tracks")
                    c_proj.xlim(-8*rms3sig, +8*rms3sig)
                    c_proj.text([displayName('r') + " #in  " + group_names[signal][igroup],
                                 signal_line(signal) + ' / Combined LRT and standard',
                                 ] +
                                ["%s #in  [%.1f, %.1f] %s" % (displayName(dep), 
                                                              #x - w/2.,
                                                              #x + w/2.,
                                                              x - wl,
                                                              x + wh,
                                                              displayUnit(dep))] +
                                ["Tracks: %d (%d)" % (proj.Integral(), proj.Integral(0, proj.GetXaxis().GetNbins() + 1))],
                                qualifier=qualifier)
                    
                    if args.save: c_proj.save('plots/%s_RobustnessResolution_slice__%s_vs_%s__%s_%d_%d.pdf' % (signal, var, dep, 'Combined', igroup, ibin))
                    pass
                    '''
                pass

            # Draw figure
            c = ap.canvas(batch=not args.show, size=(700, 500))
            for ihist, (hist, name, col) in enumerate(
                    zip(comb_histograms, group_names[signal], colours)):
                c.graph(hist,
                        linecolor=col,
                        markercolor=col,
                        linewidth=2,
                        markerstyle=20 + ihist,
                        linestyle=1 + ihist,
                        label=name)
                pass

            c.text([signal_line(signal), "Large radius and standard tracks"] +
                   (["%s particles" % t] if t != 'Signal' else []),
                   qualifier=qualifier)
            c.legend(header=displayName('r') + " in:", width=0.28)
            if dep == 'pt':
                c.padding(0.50)
            else:
                c.padding(0.60)
                pass
            c.xlim(h.GetXaxis().GetBinLowEdge(bin_pairs[dep][0][0][0]),
                   h.GetXaxis().GetBinUpEdge(bin_pairs[dep][0][-1][1]))

            c.xlabel(displayNameUnit(dep))
            c.ylabel(ylabel % displayNameUnit(var))
            if dep == 'pt':
                c.logy()
                pass

            # Show/save
            savename = '_'.join([signal] + histname.format(
                alg='Combined', var=var, t=t, group='', dep=dep,
                depdim='').split('/')[2:]) + '.pdf'
            if args.show: c.show()
            if args.save: c.save('plots/' + savename)

            pass  # end: loop signals

        # Profile for STD and LRT combined for both Rhadron and RPV
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        c = ap.canvas(batch=not args.show, size=(700, 500))
        for i, signal in enumerate(reversed(signals)):
            for (name, graph), col in zip(combined_graphs[signal], colours):
                c.graph(graph,
                        linecolor=col,
                        markercolor=col,
                        linewidth=2,
                        markerstyle=24 - 4 * i,
                        linestyle=2 - i,
                        label=name if i == 1 else None,
                        legend_option='L')
                pass
            pass

        c.text(["Large radius and standard tracks"], qualifier=qualifier)
        c.legend(header=displayName('r') + " in:",
                 width=0.28,
                 categories=[(signal_line(signal), {
                     'linestyle': 2 - i,
                     'markerstyle': 24 - 4 * i,
                     'option': 'PL'
                 }) for i, signal in enumerate(reversed(signals))])
        if dep == 'pt':
            c.padding(0.35)
        else:
            c.padding(0.45)
            pass

        if dep == 'pt':
            c.xlim(1., 400.)
        else:
            c.xlim(0., 40.)
            pass
        c.xlabel(displayNameUnit(dep))
        c.ylabel(ylabel % displayNameUnit(var))
        if dep == 'pt':
            c.logy()
            c.logx()
            pass

        # Show/save
        savename = '_'.join(['Both'] + histname.format(
            alg='Combined', var=var, t=t, group='', dep=dep, depdim='').split(
                '/')[2:]) + '.pdf'
        if args.show: c.show()
        if args.save: c.save('plots/' + savename)

        pass  # end: loop basic_vars, types, deps

    return
Example #9
0
def main ():

    # Parse command-line arguments
    args = parser.parse_args()


    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

    # Load data
    files = glob.glob(tf.config['base_path'] + 'objdef_data_*.root')

    if len(files) == 0:
        warning("No files found.")
        return

    data = loadData(files, tf.config['tree'], prefix=tf.config['prefix']) 
    info = loadData(files, tf.config['outputtree'], stop=1)
    
    # Check output.
    if data.size == 0:
        warning("No data was loaded. Exiting.")
        return 

    # Compute new variables
    data = append_fields(data, 'logpt', np.log(data['pt']))
    

    # Pass/fail masks
    msk_pass = tf.config['pass'](data)
    msk_fail = ~msk_pass
    
    
    # Validating transfer factor fit using toys
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    #for mass in [85] + list(np.linspace(100, 250, 15 + 1, endpoint=True)):
    for mass in list(np.linspace(110, 250, 14 + 1, endpoint=True)):

        print "-------- MASS: %d GeV" % mass
        
        # Set up transfer factor calculator instance
        calc = tf.calculator(data=data, config=tf.config, verbose=False) # Using default configuration
        calc.mass   = mass
        calc.window = 0.2 if (args.window is None) else args.window
        
        # Get nomnial best-fit theta
        calc.fit()
        theta = calc.theta()
        nominal_weights = calc.weights(data[msk_fail], shift=0), \
            calc.weights(data[msk_fail], shift=+1), \
            calc.weights(data[msk_fail], shift=-1)
        
        # "Throw toys" from TF profile, fit N times
        calc.toysfit(N=args.N, theta=theta)
        
        # Get weights for each toys experiment fit
        toys_weights = calc.toysweights(data[msk_fail])
        
        # Plot variations
        bins = tf.config['massbins']
        c = ap.canvas(num_pads=2, batch=not args.show)
        
        # -- Nominal background(s)
        hist_nom  = c.hist(data[msk_fail]['m'], bins=bins, weights=nominal_weights[0], fillcolor=ROOT.kAzure + 7, label='Nominal bkg.')
        h_sum = c.hist(hist_nom,
                       fillstyle=3245, fillcolor=ROOT.kGray + 2, linecolor=ROOT.kGray + 3, option='E2',
                       label='Stat. uncert.')
        
        
        # -- Toys backgrounds
        toys_hists = list()
        for idx, weights in enumerate(toys_weights):
            h = c.hist(data[msk_fail]['m'], bins=bins, weights=weights[0], fillstyle=0, linecolor=ROOT.kRed + idx % 5, linestyle = 1 + idx // 5, label='Toys %d' % (idx + 1) if idx < 5 else None)
            toys_hists.append(h)
            pass
        
        # -- Nominal variations
        hist_up   = c.hist(data[msk_fail]['m'], bins=bins, weights=nominal_weights[1], fillstyle=0, linecolor=ROOT.kGreen, linestyle=2, label='Syst. uncert.')
        hist_down = c.hist(data[msk_fail]['m'], bins=bins, weights=nominal_weights[2], fillstyle=0, linecolor=ROOT.kGreen, linestyle=2)
        
        
        # -- Data
        hist_data = c.plot(data[msk_pass]['m'], bins=bins, label='Data')
        
        # -- Ratio plots
        c.ratio_plot((h_sum,     hist_nom), option='E2')
        for idx, h in enumerate(toys_hists):
            c.ratio_plot((h, hist_nom), option='HIST')
            pass
        c.ratio_plot((hist_up,   hist_nom), option='HIST')
        c.ratio_plot((hist_down, hist_nom), option='HIST')
        c.ratio_plot((hist_data, hist_nom), oob=True)
        
        # -- Decorations
        c.xlabel('Large-#it{R} jet mass [GeV]')
        c.ylabel('Events / 5 GeV')
        c.pads()[1].ylabel('Ratio wrt. nominal')
        c.pads()[1].ylim(0.8, 1.2)
        c.pads()[1].yline(1.)
        c.text(["#sqrt{s} = 13 TeV,  L = 36.1 fb^{-1}",
                "Photon channel"],
                qualifier="Internal")

        c.region("SR", 0.8 * mass, 1.2*mass)
        
        c.legend()
        c.log()
        if args.show: c.show()
        if args.save: c.save('plots/validation_%dGeV_N%d.pdf' % (mass, args.N))

        pass
        
    return
Example #10
0
def main():

    # Parse command-line arguments
    args = parser.parse_args()

    new_pt = 450

    # W/Z MC
    # --------------------------------------------------------------------------

    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Load data (W/Z MC)
    files = glob.glob(tf.config['base_path'] + 'objdef_MC_3054*.root')

    if len(files) == 0:
        warning("No files found.")
        return

    data = loadData(files, tf.config['finaltree'], prefix=tf.config['prefix'])
    info = loadData(files, tf.config['outputtree'], stop=1)

    # Check output.
    if data.size == 0:
        warning("No data was loaded. Exiting.")
        return

    # Scale by cross-section, generator filter efficiency, and luminosity
    xsec = loadXsec(tf.config['xsec_file'])
    data = scale_weights(data, info, xsec)

    # Show normalised W/Z jet mass peak for different pT thresholds
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    msk = data['pt'] > new_pt

    # Create canvas
    c = ap.canvas(batch=not args.show)
    bins = np.linspace(50, 110, 30 + 1, endpoint=True)

    # Plot histograms
    h1 = c.hist(data['m'],
                bins=bins,
                weights=data['weight'],
                normalise=True,
                linecolor=ROOT.kRed - 4,
                label='p_{T} > 200 GeV')
    h2 = c.hist(data['m'][msk],
                bins=bins,
                weights=data['weight'][msk],
                normalise=True,
                linecolor=ROOT.kAzure + 7,
                label='p_{T} > %d GeV' % new_pt)

    # Decorations
    c.legend()
    c.xlabel("Large-radius jet mass [GeV]")
    c.ylabel("Jets / {:.0f} GeV (normalised)".format(np.diff(bins)[0]))

    c.text([
        "#sqrt{s} = 13 TeV,  L = %s fb^{-1}" % tf.config['lumi'],
        "Photon channel",
        "W/Z + #gamma Monte Carlo",
    ],
           qualifier='Internal')

    # Show/Save
    if args.show: c.show()
    if args.save: c.save('plots/masspeak_WZ.pdf')

    # Signal(220) MC
    # --------------------------------------------------------------------------

    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Load data (W/Z MC)
    files = [
        sorted(glob.glob(tf.config['base_path'] + 'objdef_MC_30836*.root'))[-1]
    ]

    if len(files) == 0:
        warning("No files found.")
        return

    data = loadData(files, tf.config['finaltree'], prefix=tf.config['prefix'])
    info = loadData(files, tf.config['outputtree'], stop=1)

    # Check output.
    if data.size == 0:
        warning("No data was loaded. Exiting.")
        return

    # Scale by cross-section, generator filter efficiency, and luminosity
    xsec = loadXsec(tf.config['xsec_file'])
    data = scale_weights(data, info, xsec)

    # Get jet channel plot
    path = '/afs/cern.ch/user/l/lkaplan/public/forAndreas/signals_fatjetunc/sig_220.root'
    f = ROOT.TFile(path, 'READ')
    t = f.Get('Signal_ISRjet')
    data_isrjet = tree2array(t)
    print data_isrjet, data_isrjet.shape

    # Show normalised signal jet mass peak for different pT thresholds
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    msk = data['pt'] > new_pt

    # Create canvas
    c = ap.canvas(batch=not args.show)
    bins = np.linspace(50, 300, 25 + 1, endpoint=True)

    # Plot histograms
    h0 = c.hist(data_isrjet['mJ'],
                bins=bins,
                weights=data_isrjet['weight'],
                normalise=True,
                linecolor=ROOT.kRed - 4,
                label='p_{T} > 450 GeV (jet ch.)')
    h0 = c.hist(h0, option='E2', fillcolor=ROOT.kRed - 4, alpha=0.3)

    h1 = c.hist(data['m'],
                bins=bins,
                weights=data['weight'],
                normalise=True,
                linecolor=ROOT.kAzure + 4,
                label='p_{T} > 200 GeV (#gamma ch.)')
    h1 = c.hist(h1, option='E2', fillcolor=ROOT.kAzure + 4, alpha=0.3)

    h2 = c.hist(data['m'][msk],
                bins=bins,
                weights=data['weight'][msk],
                normalise=True,
                linecolor=ROOT.kAzure + 7,
                label='p_{T} > %d GeV (#gamma ch.)' % new_pt)
    h2 = c.hist(h2, option='E2', fillcolor=ROOT.kAzure + 7, alpha=0.3)

    # Decorations
    c.legend(xmin=0.5)
    c.xlabel("Large-radius jet mass [GeV]")
    c.ylabel("Jets / {:.0f} GeV (normalised)".format(np.diff(bins)[0]))

    c.text([
        "#sqrt{s} = 13 TeV",
        "Z'(220 GeV) + #gamma/jet",
    ],
           qualifier='Internal')

    # Show/Save
    if args.show: c.show()
    if args.save: c.save('plots/masspeak_sig220.pdf')

    return
Example #11
0
def main():

    # Parse command-line arguments
    args = parser.parse_args()

    # Input paths
    #base_path = '/afs/cern.ch/user/a/asogaard/Qualification/validation-rel21-2017-01-24/run/'
    base_path = '/eos/atlas/user/a/asogaard/Qualification/validation/'
    paths = [
        #base_path + '2017-06-30/output_Rhadron0.root',
        #base_path + '2017-06-30/output_Rhadron4.root',
        #base_path + '2017-07-04/output_Rhadron4.root',
        #base_path + '2017-07-05/output_Rhadron0.root',
        #base_path + 'output_Rhadron0.root',
        base_path + '2017-06-30/output_Rhadron.root',
        base_path + '2017-07-05/output_Rhadron.root',
    ]

    # Histograms to be compared
    histogram_names = [
        'IDPerformanceMon/LargeD0/EffPlots/StandardTracks/Signal/trackeff_vs_R',
        'IDPerformanceMon/LargeD0/EffPlots/LargeD0Tracks/Signal/trackeff_vs_R',
        'IDPerformanceMon/LargeD0/EffPlots/AllTracks/Signal/trackeff_vs_R',
    ]

    # Read in histograms
    histograms = list()
    for path in paths:
        histograms.append(list())
        f = ROOT.TFile(path, 'READ')
        for name in histogram_names:
            h = f.Get(name)
            h.SetDirectory(0)
            h.RebinX(2)
            histograms[-1].append(h)
            pass
        f.Close()
        pass

    # Definitions
    names = ['Standard tracks', 'Large radius tracks', 'Combined']

    # Draw figure
    c = ap.canvas(batch=not args.show, size=(700, 500))
    for ihist, (hist, name,
                col) in enumerate(zip(histograms[0], names, colours)):
        c.plot(hist,
               linecolor=col,
               markercolor=col,
               linestyle=1,
               markerstyle=20,
               option='PE',
               label=name,
               legend_option='L')
        pass
    for ihist, (hist, name,
                col) in enumerate(zip(histograms[1], names, colours)):
        c.plot(hist,
               linecolor=col,
               markercolor=col,
               linestyle=2,
               markerstyle=24,
               option='PE')
        pass
    c.text([signal_line('Rhadron')], qualifier=qualifier)

    c.ylim(0, 1.6)

    c.xlabel(displayNameUnit('r'))
    c.ylabel("Reconstruction effiency")
    c.legend(width=0.28,
             categories=[
                 ('30/06/2017', {
                     'linestyle': 1,
                     'markerstyle': 20,
                     'option': 'PL'
                 }),
                 ('05/07/2017', {
                     'linestyle': 2,
                     'markerstyle': 24,
                     'option': 'PL'
                 }),
             ])

    # Show/save
    savename = 'comparison.pdf'
    if args.show: c.show()
    if args.save: c.save('plots/' + savename)
    pass

    return
Example #12
0
def main():

    # Parse command-line arguments
    args = parser.parse_args()

    # Comparing signal track resolution for LRT and STD tracks
    # --------------------------------------------------------------------------

    # Initialise categories for which to plot distinct curves for each histogram
    algorithms = ['Standard', 'LargeD0']
    names = ['Standard', 'Large radius']
    signals = ['RPV', 'Rhadron']
    rels = ['res', 'resRel', 'pull']

    # Initialise variable versus which to plot the physics efficiency
    basic_vars = ['theta', 'phi', 'd0', 'z0', 'qOverP']

    # Initialise list of histograms to be plotted
    base = 'IDPerformanceMon/LargeD0/'
    histname = base + 'ResolutionPlots/{alg}Tracks/Signal/{rel}_{var}'

    # Loop all combinations of track parameter, resolution type, and signal process.
    for var, rel, signal in itertools.product(basic_vars, rels, signals):

        # Open file from which to read histograms.
        f = ROOT.TFile(filename.format(signal=signal), 'READ')
        ROOT.TH1.AddDirectory(False)

        # Get list of histograms to plot
        histograms = list()

        for alg in algorithms:
            h = f.Get(histname.format(alg=alg, var=var, rel=rel))
            h.SetDirectory(0)  # Keep in memory after file is closed.
            h.GetXaxis().SetNdivisions(507)
            h.GetYaxis().SetNdivisions(507)
            ax = h.GetXaxis()
            rebin = 1
            if signal == 'Rhadron':
                rebin = 2
                pass
            h.Rebin(rebin)
            ax.SetRangeUser(ax.GetXmin() / 10., ax.GetXmax() / 10.)
            histograms.append(h)
            pass

        # Close file
        f.Close()

        # Draw figure
        c = ap.canvas(batch=not args.show, size=(700, 500))
        for ihist, (hist, name,
                    col) in enumerate(zip(histograms, names, colours)):
            c.hist(
                hist,
                linecolor=col,
                linewidth=3,
                linestyle=1 + ihist,
                normalise=True,
                option='HIST'
            )  #, label=name + " tracks", normalise=True, option='HIST E2')
            c.hist(hist,
                   linecolor=col,
                   fillcolor=col,
                   alpha=0.4,
                   normalise=True,
                   option='E2')
            pass
        c.text([signal_line(signal)], qualifier=qualifier)
        c.legend(
            width=0.28,
            categories=
            [(names[0] + " tracks", {
                'linecolor': colours[0],
                'linewidth': 3,
                'linestyle': 1,
                'fillcolor': colours[0],
                'alpha': 0.4,
                'option': 'FL'
            }),
             (names[1] + " tracks", {
                 'linecolor': colours[1],
                 'linewidth': 3,
                 'linestyle': 2,
                 'fillcolor': colours[1],
                 'alpha': 0.4,
                 'option': 'FL'
             })
             #('Statistical uncert.', {'fillcolor': ROOT.kGray, 'linecolor': ROOT.kGray + 1, 'option': 'F'})
             ])
        c.xlabel("%s^{reco.} - %s^{truth} [%s]" %
                 (displayName(var), displayName(var), displayUnit(var)))
        c.ylabel("Fraction of tracks")

        # Show/save
        savename = '_'.join([signal] + histname.format(
            alg='Combined', var=var, rel=rel).split('/')[2:]) + '.pdf'
        if args.show: c.show()
        if args.save: c.save('plots/' + savename)
        pass

    # Binned by matching probability
    # --------------------------------------------------------------------------

    # Initialise categories for which to plot distinct curves for each histogram
    algorithms = ['Standard', 'LargeD0']
    names = ['Standard', 'Large radius']
    types = ['All', 'Signal']
    signals = ['RPV', 'Rhadron']
    rels = ['res', 'resRel', 'pull']
    groups = [
        'prob_0p40_0p50/',
        'prob_0p50_0p60/',
        'prob_0p60_0p70/',
        'prob_0p70_0p80/',
        'prob_0p80_0p90/',
        'prob_0p90_1p00/',
    ]

    group_names = [
        '[%s]' % grp[5:-1].replace('_', ', ').replace('p', '.')
        for grp in groups
    ]

    # Initialise variable versus which to plot the physics efficiency
    basic_vars = ['theta', 'phi', 'd0', 'z0', 'qOverP']

    # Initialise list of histograms to be plotted
    base = 'IDPerformanceMon/LargeD0/'
    histname = base + 'ResolutionPlots/{alg}Tracks/{t}/{group}{rel}_{var}'

    # Loop all combinations of track parameter, tracking algorithm, truth particle type, resolution type, and signal process
    for var, (alg, name), t, rel, signal in itertools.product(
            basic_vars, zip(algorithms, names), types, rels, signals):

        # Open file from which to read histograms.
        f = ROOT.TFile(filename.format(signal=signal), 'READ')
        ROOT.TH1.AddDirectory(False)

        # Get list of histograms tp plot, manually.
        histograms = list()

        # Loop probability bins
        for igroup, group in enumerate(groups):
            h = f.Get(
                histname.format(alg=alg, var=var, t=t, rel=rel, group=group))
            h.SetDirectory(0)  # Keep in memory after file is closed.
            h.Rebin(10)  # 10
            histograms.append(h)
            pass

        # Close file
        f.Close()

        # Draw figure
        c = ap.canvas(batch=not args.show, size=(700, 500))
        for ihist, (hist, grp, col) in enumerate(
                zip(histograms, group_names, colours_pretty)):
            c.hist(hist,
                   linecolor=col,
                   linewidth=3,
                   linestyle=1 + ihist,
                   label=grp,
                   normalise=True)
            pass
        c.text([signal_line(signal), name + " tracks"] +
               (["%s particles" % t] if t != 'Signal' else []),
               qualifier=qualifier)
        c.legend(header="Match prob. in:", width=0.28, ymax=0.872)
        c.xlabel("%s^{reco.} - %s^{truth} [%s]" %
                 (displayName(var), displayName(var), displayUnit(var)))
        c.ylabel("Fraction of tracks")
        c.padding(0.40)
        c.log()

        # Show/save
        savename = '_'.join([signal] + histname.format(
            alg=alg, var=var, t=t, rel=rel, group='').split('/')[2:]) + '.pdf'
        if args.show: c.show()
        if args.save: c.save('plots/' + savename)
        pass

    return
def main ():

    # Parse command-line arguments
    args = parser.parse_args()

    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

    TF_DSID = int("100%03d" % (args.mass))
    signal_DSID = get_signal_DSID(args.mass)
    signal = bool(signal_DSID)

    # Load data
    files = {
        'data': glob.glob(tf.config['base_path'] + 'objdef_data_*.root'),
        'bkg':  glob.glob(tf.config['base_path'] + 'objdef_TF_%d.root' % TF_DSID),
        'gbs':  glob.glob(tf.config['base_path'] + 'objdef_GBS_400000.root'),
        'sig':  glob.glob(tf.config['base_path'] + 'objdef_MC_%d.root' % signal_DSID) if signal else [],
        'W':    glob.glob(tf.config['base_path'] + 'objdef_MC_30543*.root'),
        'Z':    glob.glob(tf.config['base_path'] + 'objdef_MC_30544*.root'),
        'sfl':  glob.glob(tf.config['base_path'] + 'objdef_TF_%d_signalfail.root' % TF_DSID),
        }

    #for key, arr in files.iteritems():
    #    print " -- %3s: %3d" % (key, len(arr))
    #    pass
    
    #if 0 in map(len, [files[key] for key in ['bkg', 'sig', 'W', 'Z']]) and signal: # ..., files.values()
    if 0 in map(len, files.values()) and signal: # ..., files.values()
        warning("Files not found for all categories in '%s':" % tf.config['base_path'])
        for key, arr in files.iteritems():
            warning("-- %-4s: %3d" % (key, len(arr)))
            pass
        return
    
    data      = {key: loadData(files[key], tf.config['finaltree'],                               prefix=tf.config['prefix']) for key in files}   
    data_up   = {key: loadData(files[key], tf.config['finaltree'].replace('Nominal', 'TF_UP'),   prefix=tf.config['prefix']) for key in ['bkg', 'sfl', 'gbs']} 
    data_down = {key: loadData(files[key], tf.config['finaltree'].replace('Nominal', 'TF_DOWN'), prefix=tf.config['prefix']) for key in ['bkg', 'sfl', 'gbs']} 
    info      = {key: loadData(files[key], tf.config['outputtree'], stop=1)                      for key in files}
    
    
    # Scaling by cross section
    xsec = loadXsec(tf.config['xsec_file'])
    
    # Append new DSID field # @TODO: Make more elegant?
    # Only needs to be done for 'signal', for 'nominal' syst. variation
    for comp in ['sig', 'W', 'Z']:
        if comp == 'sig' and not signal: continue
        data[comp] = scale_weights(data[comp], info[comp], xsec)
        #data[comp] = append_fields(data[comp], 'DSID', np.zeros((data[comp].size,)), dtypes=int)
        #for idx in info[comp]['id']:    
        #    msk = (data[comp]['id'] == idx) # Get mask of all 'data' entries with same id, i.e. from same file
        #    DSID = info[comp]['DSID'][idx]  # Get DSID for this file
        #    data[comp]['weight'][msk] *= xsec[DSID] # Scale by cross section x filter eff. for this DSID
        #    data[comp]['DSID']  [msk] = DSID        # Store DSID
        #    pass
        # @TODO: k-factors?
        pass
    
    # Failing signal component is scaled by cross section, but not luminosity
    for comp in ['sig', 'W', 'Z']: # 'sfl'
        if comp in ['sig', 'sfl'] and not signal: continue
        data[comp]['weight'] *= tf.config['lumi'] # Scale all events (MC) by luminosity
        pass
    
    # Check output.
    if data['data'].size == 0:
        warning("No data was loaded.")
        return 
    
    
    # Plotting
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    
    for mu, gbs, log in itertools.product([None, 0, 0.5, 1.], [False, True], [False, True]):
        
        signal = bool(signal_DSID) and bool(mu is not None)
        
        c = ap.canvas(num_pads=2, batch=not args.show)
        p0, p1 = c.pads()
        
        # -- Histograms: Main pad
        bins = tf.config['massbins']
        
        bkgvar = 'gbs' if gbs else 'bkg'
        h_bkg      = c.hist(data     [bkgvar]['m'], bins=bins, weights=data     [bkgvar]['weight'], display=False)
        h_bkg_up   = c.hist(data_up  [bkgvar]['m'], bins=bins, weights=data_up  [bkgvar]['weight'], display=False)
        h_bkg_down = c.hist(data_down[bkgvar]['m'], bins=bins, weights=data_down[bkgvar]['weight'], display=False)
        
        # -- Subtract failing signal component (if any)
        if signal:
            h_sig  = c.hist(data['sig']['m'], bins=bins, weights=data['sig']['weight'], scale=mu, display=False)
            pass


        h_Z = c.stack(data['Z']['m'], bins=bins, weights=data['Z']['weight'],
                      fillcolor=ROOT.kAzure + 3, 
                      label="Z + #gamma")
        
        h_W = c.stack(data['W']['m'], bins=bins, weights=data['W']['weight'],
                      fillcolor=ROOT.kAzure + 2, 
                      label="W + #gamma")
        
        # ---------------------------------------------------------------------
        # Saving output for harmonised paper plots
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        if (not gbs) and log:
            outfile = ROOT.TFile('output/hists_isrgamma_datadistributions_%dGeV%s.root' % (args.mass, '' if mu is None else '_mu%d' % (100 * mu)), 'RECREATE')
            h_bkg.SetName('h_mJ_QCD')
            h_bkg_up.SetName('h_mJ_QCD_up')
            h_bkg_down.SetName('h_mJ_QCD_down')
            h_data.SetName('h_mJ_data')
            h_W.SetName('h_mJ_WHad')
            h_Z.SetName('h_mJ_ZHad')
            if signal:
                h_sig.SetName('h_mJ_sig')
                pass
            for hist in [h_bkg, h_bkg_up, h_bkg_down, h_data, h_W, h_Z] + ([h_sig] if signal else []):
                hist.Write()
                pass
            outfile.Close()
            pass
        # ---------------------------------------------------------------------        

        # -- Subtract failing signal component (if any)
        if signal:
            h_sfl      = c.hist(data     ['sfl']['m'], bins=bins, weights=data     ['sfl']['weight'], scale=mu, display=False)
            h_sfl_up   = c.hist(data_up  ['sfl']['m'], bins=bins, weights=data_up  ['sfl']['weight'], scale=mu, display=False)
            h_sfl_down = c.hist(data_down['sfl']['m'], bins=bins, weights=data_down['sfl']['weight'], scale=mu, display=False)
            
            h_bkg     .Add(h_sfl, -1) # Subtracting signal
            h_bkg_up  .Add(h_sfl, -1) # --
            h_bkg_down.Add(h_sfl, -1) # --
            pass                    
        
        h_bkg = c.stack(h_bkg,
                        fillcolor=ROOT.kAzure + 7, 
                        label='Bkg. pred. (GBS)' if gbs else 'Background pred.')

        
        h_sum = c.getStackSum()
        
        if signal:
            h_sig = c.stack(h_sig,
                            fillcolor=ROOT.kRed - 4,
                            label="Z' (%d GeV) + #gamma" % args.mass)#  (#times #mu)")
            pass
        
        h_sum = c.hist(h_sum, 
                       fillstyle=3245, fillcolor=ROOT.kGray + 3, option='E2',
                       label='Stat. uncert.')

        # Add h_sum errors in quadrature to TF systematics (?)
        if True:
            for idx in range(1, h_sum.GetXaxis().GetNbins() + 1):
                nom       = h_bkg.GetBinContent(idx)
                s         = h_sum.GetBinContent(idx)
                stat      = h_sum.GetBinError  (idx)
                syst_up   = np.abs(h_bkg_up  .GetBinContent(idx) - nom)
                syst_down = np.abs(h_bkg_down.GetBinContent(idx) - nom)
                h_bkg_up  .SetBinContent(idx, s + np.sqrt(np.square(stat) + np.square(syst_up)))
                h_bkg_down.SetBinContent(idx, s - np.sqrt(np.square(stat) + np.square(syst_down)))
                pass
            pass
        
        h_bkg_up   = c.hist(h_bkg_up,
                            #linecolor=ROOT.kGreen + 1, linestyle=2, option='HIST',
                            linecolor=ROOT.kGray + 3, option='HIST', display=False)
                            #label='TF syst. uncert.') 
                            #label='Stat. #oplus syst.')
        c.hist(h_sum, linecolor=ROOT.kGray + 3, fillstyle=0, option='HIST',  label='Stat. #oplus syst.')
        c.hist(h_sum, linecolor=ROOT.kBlack,    fillstyle=0, option='HIST')
        
        h_bkg_down = c.hist(h_bkg_down,
                            #linecolor=ROOT.kGreen + 1, linestyle=2, option='HIST')
                            linecolor=ROOT.kGray + 3, option='HIST', display=False)
        
        h_data = c.plot(data['data']['m'], bins=bins, weights=data['data']['weight'],
                        label='Data')
        
        # -- Axis limits
        #c.padding(0.40) # 0.45
        p1.ylim(0.8, 1.2)
        
        # -- Histograms: Ratio pad
        if signal:
            c.ratio_plot((h_sig,      h_sum), option='HIST', offset=1)
            pass
        c.ratio_plot((h_sum,      h_sum), option='E2')
        c.ratio_plot((h_bkg_up,   h_sum), option='HIST')
        c.ratio_plot((h_bkg_down, h_sum), option='HIST')
        c.ratio_plot((h_data,     h_sum), oob=True)
        
        # -- Text
        c.text(["#sqrt{s} = 13 TeV,  L = %s fb^{-1}" % tf.config['lumi'],
                "Trimmed anti-k_{t}^{R=1.0} jets",
                "ISR #gamma selection",
                #"Window: %d GeV #pm %d %%" % (args.mass, 20.),
                ] + (["Pre-fit: #mu = %.2f" % mu] if signal else []), 
               qualifier='Internal')
        
        # -- Axis labels
        c.xlabel('Signal jet mass [GeV]')
        c.ylabel('Events')
        p1.ylabel('Data / Est.')
        
        # -- Line(s)
        p1.yline(1.0)
        
        # -- Region labels
        c.region("SR", 0.8 * args.mass, 1.2 * args.mass)
        
        c.log(log)
        c.legend()
        if args.show: c.show()
        if args.save: c.save('plots/datadistribution_%dGeV%s%s%s.pdf' % (args.mass, '_mu%d' % (mu * 100)if signal else '', '_gbs' if gbs else '', '_log' if log else ''))
        pass

    return
Example #14
0
def main():

    # Parse command-line arguments
    args = parser.parse_args()

    paths = {
        'incl': glob.glob(tf.config['base_path'] + 'objdef_MC_3610*.root'),
        'W': glob.glob(tf.config['base_path'] + 'objdef_MC_30543*.root'),
        'Z': glob.glob(tf.config['base_path'] + 'objdef_MC_30544*.root'),
        'sig': glob.glob(tf.config['base_path'] + 'objdef_MC_308365.root'),
    }

    # Load data
    xsec = loadXsec('../AnalysisTools/share/sampleInfo.csv')

    treenames = [
        'BoostedJet+ISRgamma/Nominal/LargeRadiusJets/Nominal/dPhiPhoton/Postcut',
        'BoostedJet+ISRgamma/Nominal/LargeRadiusJets/Nominal/BoostedRegime/Postcut',
        'BoostedJet+ISRgamma/Nominal/LargeRadiusJets/Nominal/rhoDDT/Postcut',
    ]

    # Standard definitions
    # -- Data
    prefix = ''
    getvars = ['m', 'pt', 'pt_ungroomed', 'tau21',
               'tau21_ungroomed']  # , 'tau21DDT']

    xvars = ['rho', 'rhoDDT', 'm']
    yvars = ['tau21', 'tau21DDT', 'tau21_ungroomed']
    axis = {
        'rho': (30, -9, 0),
        'rhoDDT': (30, -2, 7),
        'm': (30, 0, 300),
    }

    # -- Plotting
    colours = [ROOT.kRed + ((i * 2) % 5) for i in range(3)]

    qualifier = 'Simulation Internal'

    lines = [
        "#sqrt{s} = 13 TeV,  Incl. #gamma MC",
        "Trimmed anti-k_{t}^{R=1.0} jets",
    ]

    xmin, xmax, ymax = 0.57, 0.9, 0.85 - ROOT.gROOT.GetStyle(
        "AStyle").GetTextSize() * 1.45  # 1.4

    # Fitting transform
    # ----------------------------------------------------------------
    data = {
        key: loadDataFast(paths[key],
                          treenames[1], ['m', 'pt', 'tau21'],
                          prefix,
                          xsec,
                          quiet=True)
        for key in paths
    }

    # Compute new variables
    for key in data:
        data[key]['rho'] = np.log(
            np.square(data[key]['m']) / np.square(data[key]['pt']))
        data[key]['rhoDDT'] = np.log(
            np.square(data[key]['m']) / (data[key]['pt'] * 1.))
        pass

    # Compute profile
    xvar, yvar = 'rhoDDT', 'tau21'
    profile_before = get_profile(data['incl'],
                                 xvar,
                                 yvar,
                                 bins=(28, 0, axis[xvar][2]),
                                 weights=data['incl']['weight'])

    fit = ROOT.TF1('fit', 'pol1', 1.5, 7)
    fit.SetLineColor(ROOT.kGray + 3)
    fit.SetLineWidth(2)
    profile_before.Fit('fit', 'RQ0')

    print "Fit:"
    print "  ", fit.GetParameter(0), "+/-", fit.GetParError(0)
    print " ", fit.GetParameter(1), "+/-", fit.GetParError(1)

    for key in data:
        data[key]['tau21DDT'] = data[key]['tau21'] - (
            fit.GetParameter(1) * (data[key]['rhoDDT'] - 1.5))
        pass

    xvar, yvar = 'rhoDDT', 'tau21DDT'
    profile_after = get_profile(data['incl'],
                                xvar,
                                yvar,
                                bins=(28, 0, axis[xvar][2]),
                                weights=data['incl']['weight'])

    # Draw
    c = ap.canvas(batch=not args.show)

    c.plot(profile_before,
           linecolor=colours[0],
           markercolor=colours[0],
           label='Original, #tau_{21}',
           option='PE',
           legend_option='LP')
    c.plot(profile_after,
           linecolor=colours[1],
           markercolor=colours[1],
           label='Transformed, #tau_{21}^{DDT}',
           option='PE',
           legend_option='LP')
    fit.Draw('SAME')

    c.legend()
    c.xlabel('Large-#it{R} jet %s' % displayNameUnit(xvar))
    c.ylabel("#LT%s#GT" % displayName('tau21') +
             ", #LT%s#GT" % displayName(yvar))
    c.ylim(0, 1.2)

    c.text(lines + ["Jet p_{T} > 2 #times M, 200 GeV"], qualifier=qualifier)
    c.latex("Fit: %.3f + %s #times (%.4f)" %
            (fit.GetParameter(0), displayName(xvar), fit.GetParameter(1)),
            0.20,
            0.20,
            NDC=True,
            align=11)

    c.line(1.5,
           fit.Eval(1.5),
           axis[xvar][2],
           fit.Eval(1.5),
           linecolor=ROOT.kGray + 3,
           linestyle=2,
           linewidth=2)
    c.line(1.5,
           0.14,
           1.5,
           fit.Eval(1.5),
           linecolor=ROOT.kGray,
           linestyle=1,
           linewidth=1)
    c.line(1.5, 0.0, 1.5, 0.05, linecolor=ROOT.kGray, linestyle=1, linewidth=1)

    savename = 'plots/decorrelation_fit_%s_vs_%s.pdf' % ('tau21', xvar)
    if args.save: c.save(savename)
    if args.show: c.show()

    # Performing pT-slicing
    # --------------------------------------------------------------------------
    # Loop trees (succesive cuts)
    for itreename, treename in enumerate(treenames):

        data = {
            key: loadDataFast(paths[key],
                              treename,
                              getvars,
                              prefix,
                              xsec,
                              quiet=True)
            for key in paths
        }
        # Compute new variables
        for key in data:
            data[key]['rho'] = np.log(
                np.square(data[key]['m']) / np.square(data[key]['pt']))
            data[key]['rhoDDT'] = np.log(
                np.square(data[key]['m']) / (data[key]['pt'] * 1.))
            data[key]['tau21DDT'] = data[key]['tau21'] - (
                fit.GetParameter(1) * (data[key]['rhoDDT'] - 1.5))
            pass

        # Profile settings
        slices = {
            'pt': [
                (200, 300),
                (300, 500),
                (500, 1000),
            ],
        }

        # Compute profiles
        profiles = {
            key: {xvar: {yvar: []
                         for yvar in yvars}
                  for xvar in xvars}
            for key in data.keys()
        }

        for key, xvar, yvar in itertools.product(data.keys(), xvars, yvars):
            if key == 'sig':  # Restrict signal to +/- 20% of pole mass
                msk_sig = np.abs(data[key]['m'] - 160.) / 160. < 0.2
            else:
                msk_sig = np.ones_like(data[key][xvar]).astype(bool)
                pass
            for sl in slices['pt']:
                profile = get_profile(data[key],
                                      xvar,
                                      yvar,
                                      bins=axis[xvar],
                                      mask=(data[key]['pt'] > sl[0]) &
                                      (data[key]['pt'] < sl[1]) & msk_sig,
                                      weights=data[key]['weight'])
                profiles[key][xvar][yvar].append(profile)
                pass
            pass

        # Comparing groomed and un-groomed
        # ----------------------------------------------------------------------

        # Drawing options
        names = ['[%d, %d] GeV' % (sl[0], sl[1]) for sl in slices['pt']]

        # Loop xvars
        for xvar in xvars:
            yvar1, yvar2 = 'tau21', 'tau21_ungroomed'

            c = ap.canvas(num_pads=2, batch=not args.show)

            # -- main pad
            for i, (col, name, prof) in enumerate(
                    zip(colours, names, profiles['incl'][xvar][yvar1])):
                c.plot(prof,
                       linecolor=col,
                       markercolor=col,
                       markerstyle=20,
                       option='PE',
                       label=name,
                       legend_option='LP')
                pass
            for i, (col, name, prof) in enumerate(
                    zip(colours, names, profiles['incl'][xvar][yvar2])):
                c.plot(prof,
                       linecolor=col,
                       markercolor=col,
                       markerstyle=24,
                       option='PE')
                pass

            # -- ratio pad
            for prof1, prof2, col in zip(profiles['incl'][xvar][yvar1],
                                         profiles['incl'][xvar][yvar2],
                                         colours):
                r = c.ratio_plot((prof1, prof2),
                                 option='HIST ][',
                                 linecolor=col,
                                 default=0)
                pass

            # -- decorations
            c.xlabel('Large-#it{R} jet %s' % displayNameUnit(xvar))
            c.ylabel("#LT%s#GT" % displayName(yvar1) +
                     ", #LT%s#GT" % displayName(yvar2))
            c.pads()[1].ylabel("#LT%s#GT" % displayName(yvar1) +
                               " / #LT%s#GT" % displayName(yvar2))

            c.ylim(0, 1.4)  # if xvar == 'm' else 1.6)
            c.pads()[1].ylim(0, 1.5)

            c.legend(header='Jet p_{T} in:',
                     categories=[
                         ('Trimmed %s' % displayName('tau21'), {
                             'markerstyle': 20,
                             'markercolor': ROOT.kGray + 3,
                             'option': 'P'
                         }),
                         ('Un-trimmed %s' % displayName('tau21'), {
                             'markerstyle': 24,
                             'markercolor': ROOT.kGray + 3,
                             'option': 'P'
                         }),
                     ])
            c.text(lines +
                   (["Jet p_{T} > 2 #times M"] if itreename > 0 else []) +
                   (["Jet %s > 1.5" %
                     displayName('rhoDDT')] if itreename > 1 else []),
                   qualifier=qualifier)

            savename = 'plots/decorrelation_trimmed_untrimmed_%s_vs_%s_tree%d.pdf' % (
                yvar1, xvar, itreename)
            if args.save: c.save(savename)
            if args.show: c.show()
            pass

        # Only groomed
        # ----------------------------------------------------------------------

        # Loop xvars
        for xvar, yvar in itertools.product(xvars, yvars):

            c = ap.canvas(batch=not args.show)

            for i, (col, name, prof) in enumerate(
                    zip(colours, names, profiles['incl'][xvar][yvar])):
                c.plot(prof,
                       linecolor=col,
                       markercolor=col,
                       markerstyle=20,
                       label=name,
                       option='PE',
                       legend_option='LP')
                pass

            c.xlabel('Large-#it{R} jet %s' % displayNameUnit(xvar))
            c.ylabel("#LT%s#GT" % displayName(yvar))
            c.ylim(0, 1.4)  # if xvar == 'm' else 1.6)

            c.legend(header='Jet p_{T} in:')
            c.text(lines +
                   (["Jet p_{T} > 2 #times M"] if itreename > 0 else []) +
                   (["Jet %s > 1.5" %
                     displayName('rhoDDT')] if itreename > 1 else []),
                   qualifier=qualifier)

            savename = 'plots/decorrelation_%s_vs_%s_tree%d.pdf' % (yvar, xvar,
                                                                    itreename)
            if args.save: c.save(savename)
            if args.show: c.show()
            pass  # end: loop xvars, yvars

        # Comparing QCD and W/Z
        # ----------------------------------------------------------------------

        # Drawing options
        names = ['[%d, %d] GeV' % (sl[0], sl[1]) for sl in slices['pt']]

        # Loop xvars
        for xvar, yvar in itertools.product(xvars, yvars):

            # Save outputs for harmonised plotting
            if itreename == 2 and yvar.startswith('tau21') and xvar in [
                    'm', 'rhoDDT'
            ]:
                outfile = ROOT.TFile(
                    'hists_isrgamma_decorrelation_{}_vs_{}.root'.format(
                        yvar, xvar), 'RECREATE')
                profname = 'profile_{{name:s}}__{yvar:s}_vs_{xvar:s}__pT_{{ptmin:d}}_{{ptmax:d}}_GeV'
                profname = profname.format(yvar=yvar, xvar=xvar)
                print ">" * 80
                for prof, sl in zip(profiles['incl'][xvar][yvar],
                                    slices['pt']):
                    prof.SetName(
                        profname.format(name='inclphoton',
                                        ptmin=sl[0],
                                        ptmax=sl[1]))
                    print ">>>", prof.GetName()
                    prof.Write()
                    pass
                for prof, sl in zip(profiles['sig'][xvar][yvar], slices['pt']):
                    prof.SetName(
                        profname.format(name='sig160',
                                        ptmin=sl[0],
                                        ptmax=sl[1]))
                    print ">>>", prof.GetName()
                    prof.Write()
                    pass
                print ">" * 80
                outfile.Close()
                pass

            c = ap.canvas(batch=not args.show)

            # -- main pad
            for i, (col, name, prof) in enumerate(
                    zip(colours, names, profiles['incl'][xvar][yvar])):
                c.plot(prof,
                       linecolor=col,
                       markercolor=col,
                       markerstyle=20,
                       option='PE',
                       label=name,
                       legend_option='LP')
                pass
            for i, (col, name, prof) in enumerate(
                    zip(colours, names, profiles['sig'][xvar][yvar])):
                c.plot(prof,
                       linecolor=col,
                       markercolor=col,
                       markerstyle=24,
                       option='PE')
                pass

            # -- decorations
            c.xlabel('Large-#it{R} jet %s' % displayNameUnit(xvar))
            c.ylabel("#LT%s#GT" % displayName(yvar))

            c.ylim(0, 1.4)  # if xvar == 'm' else 1.6)

            c.legend(header='Jet p_{T} in:',
                     categories=[
                         ("Incl. #gamma MC", {
                             'markerstyle': 20,
                             'markercolor': ROOT.kGray + 3,
                             'option': 'P'
                         }),
                         ("Z'(160 GeV) + #gamma", {
                             'markerstyle': 24,
                             'markercolor': ROOT.kGray + 3,
                             'option': 'P'
                         }),
                     ])
            c.text(lines[:1] + [lines[1].replace(', Incl. #gamma', '')] +
                   (["Jet p_{T} > 2 #times M"] if itreename > 0 else []) +
                   (["Jet %s > 1.5" %
                     displayName('rhoDDT')] if itreename > 1 else []),
                   qualifier=qualifier)

            savename = 'plots/decorrelation_inclphoton_sig_%s_vs_%s_tree%d.pdf' % (
                yvar, xvar, itreename)
            if args.save: c.save(savename)
            if args.show: c.show()
            pass

        pass  # end: loop treenames

    return
def main ():

    # Parse command-line arguments
    args = parser.parse_args()

    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Input file paths
    paths = glob.glob(tf.config['base_path'] + 'objdef_MC_3610*.root')

    # Load data
    xsec = loadXsec(tf.config['xsec_file'])

    # Standard definitions
    axes = {
        'tau21':    (20,  0.0, 1.0),
        #'tau21DDT': (20,  0.0, 1.0), #  0.1, 1.1),
        }
        
    # Getting data
    data = loadData(paths, tf.config['tree'], prefix=tf.config['prefix'])
    info = loadData(paths, tf.config['outputtree'], stop=1)
    
    data = scale_weights(data, info, xsec, lumi=tf.config['lumi'])


    # Plotting tau21(DDT) profiles
    # ----------------------------------------------------------------
       
    slices = {
        'pt': [
            #( 200,  2000), # For inclusive distribution (test)
            ( 200,  300),
            ( 300,  500),
            ( 500, 1000),
            ],
        'm': [
            #(0,1000), # For inclusive distribution (test)
            #( 50, 100),
            (100, 150),
            (150, 200),
            (200, 250),
            ],
        #'rhoDDT': [
        #    (1.5, 2.5),
        #    (2.5, 4.0),
        #    (4.0, 5.5),
        #    ],
        }

    colours = [ROOT.kRed + i for i in np.arange(0,5,2)] # Overwriting

    keys = slices.keys()
    key = keys[0]
    category_names = ["[%.0f, %.0f] %s" % (slices[key][i][0], slices[key][i][1], displayUnit(key)) for i in range(len(slices[key]))]

    for xvar, axis in axes.iteritems():
        print "Plotting %s:" % xvar

        c = ap.canvas(batch=not args.show)
        bins = np.linspace(axis[1], axis[2], axis[0] + 1, endpoint=True)

        if xvar in ['tau21DDT', 'tau21'] and args.save:
            f = ROOT.TFile('output/hists_isrgamma_%sdistributions.root' % xvar, 'RECREATE')
        else:
            f = None
            pass

        # Fill sliced histograms
        histograms = list()
        for i, sl in enumerate(dict_product(slices)):
            print "  %d:" % i, sl

            # Create full mask for current slice
            msk = np.ones_like(data['weight']).astype(bool)
            for key, limits in sl.iteritems():
                msk &= (data[key] >= limits[0]) & (data[key] < limits[1])
                pass

            # Create distribution for current slice
            key = keys[1]
            label = "[%.0f, %.0f] %s" % (sl[key][0], sl[key][1], displayUnit(key))
            hist = c.hist(data[xvar][msk], bins=bins, weights=data['weight'][msk], linecolor=colours[i % 3], linestyle=1 + (i//3), label=label if i < 3 else None, normalise=True)
            if f:
                f.cd()
                hist.SetName('h_%s_%d_%d_%s_%d_%s' % (keys[0], sl[keys[0]][0], sl[keys[0]][1], keys[1], sl[keys[1]][0], sl[keys[1]][1]))
                #hist.Write()
                pass
            pass

        if f:
            f.Write()
            f.Close()
            pass

        # Decorations
        c.xlabel('Signal jet %s' % displayNameUnit(xvar))
        c.ylabel('Jets (a.u.)')
        c.text(["#sqrt{s} = 13 TeV", "ISR #gamma selection"], qualifier="Simulation Internal")
        c.padding(0.50)

        ymax = 0.735
        c.legend(header='Jet %s in:' % displayName(keys[1]),
                 ymax=ymax)
        c.legend(header='Jet %s in:' % displayName(keys[0]), categories=[
                (category_names[idx], {'linestyle': 1 + idx}) for idx in range(len(category_names))
                ],
                 ymax=ymax, xmin=0.19)

        if args.show: c.show()
        if args.save: c.save('plots/tau21distributions_%s__%s_x_%s.pdf' % (xvar, keys[0], keys[1]))
        pass
        
    return
Example #16
0
def main ():

    # Parse command-line arguments
    args = parser.parse_args()

    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Input file paths
    paths = glob.glob('/afs/cern.ch/user/a/asogaard/Analysis/2016/BoostedJetISR/AnalysisTools/outputObjdef/objdef_MC_30836*.root')

    base = 'BoostedJet+ISRgamma/Nominal/'
    trees = [
        'PreSelection/Nominal/GRL/Postcut',
        'PreSelection/Nominal/HLT_g140_loose/Postcut',
        'LargeRadiusJets/Nominal/eta/Postcut',
        'LargeRadiusJets/Nominal/pt/Postcut',
        'LargeRadiusJets/Nominal/dPhiPhoton/Postcut',
        'LargeRadiusJets/Nominal/BoostedRegime/Postcut',
        'LargeRadiusJets/Nominal/rhoDDT/Postcut',
        'EventSelection/Pass/NumPhotons/Postcut',
        'EventSelection/Pass/NumLargeRadiusJets/Postcut',
        'EventSelection/Pass/Jet_tau21DDT/Postcut'
        ]
    trees = [base + tree for tree in trees]

    names = [
        "GRL",
        "Trigger",
        "Jet eta",
        "Jet pT",
        "Jet dPhi(y)",
        "Jet pT > 2m",
        "Jet rhoDDT",
        "Photon pT",
        "(Jet count)",
        "Jet tau21DDT"
        ]

    DSIDs = [308363, 308364, 308365, 308366, 308367]

    basecounts = base = {
        308363: 50000,
        308364: 48000,
        308365: 50000,
        308366: 50000,
        308367: 48000,
        }

    genfilteff = {
        308363: 2.9141e-01,
        308364: 1.3795e-01,
        308365: 7.5920e-02,
        308366: 4.5985e-02,
        308367: 2.9914e-02,
        }

    for idx, DSID in enumerate(DSIDs):
        print "\nDSID: {}".format(DSID)

        passingEvents = None
        for name, tree in zip(names,trees):
            
            # Getting data
            data = loadData([paths[idx]], tree)
            
            if passingEvents is None:
                passingEvents = sorted(list(set(data['eventNumber'])))
                assert len(passingEvents) == data.shape[0]
            else:
                passingEvents = sorted(list(set(passingEvents) & set(data['eventNumber'])))
                pass
            print "    {:15s}: {:6d} | {:4.1f}% | {:4.1f}%".format(
                name, 
                len(passingEvents), 
                len(passingEvents) / float(basecounts[DSID]) * 100., 
                len(passingEvents) / float(basecounts[DSID]) * genfilteff[DSID] * 100., 
                )
            pass
        pass
    return 

    # Plotting tau21(DDT) profiles
    # ----------------------------------------------------------------
       
    slices = {
        'pt': [
            #( 200,  2000), # For inclusive distribution (test)
            ( 200,  300),
            ( 300,  500),
            ( 500, 1000),
            ],
        'm': [
            #(0,1000), # For inclusive distribution (test)
            #( 50, 100),
            (100, 150),
            (150, 200),
            (200, 250),
            ],
        #'rhoDDT': [
        #    (1.5, 2.5),
        #    (2.5, 4.0),
        #    (4.0, 5.5),
        #    ],
        }

    colours = [ROOT.kRed + i for i in np.arange(0,5,2)] # Overwriting

    keys = slices.keys()
    key = keys[0]
    category_names = ["[%.0f, %.0f] %s" % (slices[key][i][0], slices[key][i][1], displayUnit(key)) for i in range(len(slices[key]))]

    for xvar, axis in axes.iteritems():
        print "Plotting %s:" % xvar

        c = ap.canvas(batch=not args.show)
        bins = np.linspace(axis[1], axis[2], axis[0] + 1, endpoint=True)

        if xvar in ['tau21DDT/Postcut', 'tau21'] and args.save:
            f = ROOT.TFile('output/hists_isrgamma_%sdistributions.root' % xvar, 'RECREATE')
        else:
            f = None
            pass

        # Fill sliced histograms
        histograms = list()
        for i, sl in enumerate(dict_product(slices)):
            print "  %d:" % i, sl

            # Create full mask for current slice
            msk = np.ones_like(data['weight']).astype(bool)
            for key, limits in sl.iteritems():
                msk &= (data[key] >= limits[0]) & (data[key] < limits[1])
                pass

            # Create distribution for current slice
            key = keys[1]
            label = "[%.0f, %.0f] %s" % (sl[key][0], sl[key][1], displayUnit(key))
            hist = c.hist(data[xvar][msk], bins=bins, weights=data['weight'][msk], linecolor=colours[i % 3], linestyle=1 + (i//3), label=label if i < 3 else None, normalise=True)
            if f:
                f.cd()
                hist.SetName('h_%s_%d_%d_%s_%d_%s' % (keys[0], sl[keys[0]][0], sl[keys[0]][1], keys[1], sl[keys[1]][0], sl[keys[1]][1]))
                #hist.Write()
                pass
            pass

        if f:
            f.Write()
            f.Close()
            pass

        # Decorations
        c.xlabel('Signal jet %s' % displayNameUnit(xvar))
        c.ylabel('Jets (a.u.)')
        c.text(["#sqrt{s} = 13 TeV", "ISR #gamma selection"], qualifier="Simulation Internal")
        c.padding(0.50)

        ymax = 0.735
        c.legend(header='Jet %s in:' % displayName(keys[1]),
                 ymax=ymax)
        c.legend(header='Jet %s in:' % displayName(keys[0]), categories=[
                (category_names[idx], {'linestyle': 1 + idx}) for idx in range(len(category_names))
                ],
                 ymax=ymax, xmin=0.19)

        if args.show: c.show()
        if args.save: c.save('plots/tau21distributions_%s__%s_x_%s.pdf' % (xvar, keys[0], keys[1]))
        pass
        
    return
Example #17
0
def main():

    # Parse command-line arguments
    args = parser.parse_args()

    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Load data
    files = glob.glob(tf.config['base_path'] + 'objdef_MC_3610*.root')

    if len(files) == 0:
        warning("No files found.")
        return

    data = loadData(files, tf.config['tree'], prefix=tf.config['prefix'])
    info = loadData(files, tf.config['outputtree'], stop=1)

    # Scaling by cross section
    xsec = loadXsec(tf.config['xsec_file'])

    # Append new DSID field # @TODO: Make more elegant?
    data = append_fields(data, 'DSID', np.zeros((data.size, )), dtypes=int)
    for idx in info['id']:
        msk = (
            data['id'] == idx
        )  # Get mask of all 'data' entries with same id, i.e. from same file
        DSID = info['DSID'][idx]  # Get DSID for this file
        data['weight'][msk] *= xsec[
            DSID]  # Scale by cross section x filter eff. for this DSID
        data['DSID'][msk] = DSID  # Store DSID
        pass
    data['weight'] *= tf.config['lumi']  # Scale all events (MC) by luminosity

    # Check output.
    if data.size == 0:
        warning("No data was loaded.")
        return

    # Compute new variables
    data = append_fields(data, 'logpt', np.log(data['pt']))

    # Transfer factor
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Pass/fail masks
    msk_pass = tf.config['pass'](data)
    msk_fail = ~msk_pass

    # Transfer factor calculator instance
    calc = tf.calculator(data=data,
                         config=tf.config)  # Using default configuration
    calc.mass = args.mass
    calc.window = args.window
    # ... calc.partialbins, calc.emptybins, ...
    calc.fit()  # ...(theta=0.5)
    w_nom = calc.weights(data[msk_fail])
    w_up = calc.weights(data[msk_fail], shift=+1)
    w_down = calc.weights(data[msk_fail], shift=-1)
    if args.show or args.save:
        calc.plot(show=args.show, save=args.save, prefix='plots/new_closure_')

    # Comparing jet mass distrbutions (closure)
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    if args.show or args.save:

        c = ap.canvas(num_pads=2, batch=not args.show)
        p0, p1 = c.pads()

        bins = tf.config['massbins']

        h_bkg = c.hist(data['m'][msk_fail],
                       bins=bins,
                       weights=data['weight'][msk_fail] * w_nom,
                       display=False)
        h_up = c.hist(data['m'][msk_fail],
                      bins=bins,
                      weights=data['weight'][msk_fail] * w_up,
                      display=False)
        h_down = c.hist(data['m'][msk_fail],
                        bins=bins,
                        weights=data['weight'][msk_fail] * w_down,
                        display=False)
        h_data = c.plot(data['m'][msk_pass],
                        bins=bins,
                        weights=data['weight'][msk_pass],
                        display=False)

        for bin in range(1, h_bkg.GetXaxis().GetNbins() + 1):
            width = float(h_bkg.GetBinWidth(bin))
            h_bkg.SetBinContent(bin, h_bkg.GetBinContent(bin) / width)
            h_bkg.SetBinError(bin, h_bkg.GetBinError(bin) / width)
            h_up.SetBinContent(bin, h_up.GetBinContent(bin) / width)
            h_up.SetBinError(bin, h_up.GetBinError(bin) / width)
            h_down.SetBinContent(bin, h_down.GetBinContent(bin) / width)
            h_down.SetBinError(bin, h_down.GetBinError(bin) / width)
            h_data.SetBinContent(bin, h_data.GetBinContent(bin) / width)
            h_data.SetBinError(bin, h_data.GetBinError(bin) / width)
            pass

        h_bkg = c.hist(h_bkg,
                       fillcolor=ROOT.kAzure + 7,
                       label='Background est.')
        h_err = c.hist(h_bkg,
                       fillstyle=3245,
                       fillcolor=ROOT.kGray + 2,
                       linecolor=ROOT.kGray + 3,
                       label='Stat. uncert.',
                       option='E2')
        h_up = c.hist(h_up,
                      linecolor=ROOT.kGreen + 1,
                      linestyle=2,
                      option='HIST',
                      label='Syst. uncert.')
        h_down = c.hist(h_down,
                        linecolor=ROOT.kGreen + 1,
                        linestyle=2,
                        option='HIST')
        h_data = c.plot(h_data, label='Pseudo-data')

        c.ratio_plot((h_err, h_bkg), option='E2')
        c.ratio_plot((h_up, h_bkg), option='HIST')
        c.ratio_plot((h_down, h_bkg), option='HIST')
        c.ratio_plot((h_data, h_bkg))

        c.xlabel('Large-#it{R} jet mass [GeV]')
        c.ylabel('Events / GeV')
        p1.ylabel('Data / Est.')

        c.ylim(1E+00, 1E+06)
        p1.ylim(0.80, 1.20)
        p1.yline(1.0)
        c.region("SR", 0.8 * args.mass, 1.2 * args.mass)

        #for x in [args.mass * (1 - args.window), args.mass * (1 + args.window)]:
        #    p0.line(x, 1E+01, x, 2E+04)
        #    pass
        #p1.xlines([args.mass * (1 - args.window), args.mass * (1 + args.window)])

        c.text([
            "#sqrt{s} = 13 TeV,  %s fb^{-1}" % tf.config['lumi'],
            "Incl. #gamma Monte Carlo",
            "Photon channel",
        ],
               qualifier='Simulation Internal')

        c.log()
        c.legend()

        if args.save:
            c.save('plots/new_closure_%dGeV_pm%d.pdf' %
                   (args.mass, args.window * 100.))
        if args.show: c.show()
        pass

    return
Example #18
0
def main():

    # Parse command-line arguments
    args = parser.parse_args()

    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Input file paths
    paths = {
        'bkg': glob.glob(tf.config['base_path'] + 'objdef_MC_3610*.root'),
        'sig': glob.glob(tf.config['base_path'] + 'objdef_MC_30836*.root'),
    }

    sig_names = [
        "Z' + #gamma (100 GeV)",
        "Z' + #gamma (130 GeV)",
        "Z' + #gamma (160 GeV)",
        "Z' + #gamma (190 GeV)",
        "Z' + #gamma (220 GeV)",
    ]

    # Load data
    treename = 'BoostedJet+ISRgamma/Nominal/EventSelection/Pass/NumLargeRadiusJets/Postcut'

    # Standard definitions
    # -- Data
    prefix = 'Jet_'

    xvars = ['m']
    axis = {
        'm': (40, 50, 250),
        'tau21DDT': (20, 0, 1),
    }

    # Getting data
    bkg = loadData(paths['bkg'], treename, prefix=prefix)
    sig = loadData(paths['sig'], treename, prefix=prefix)
    info_bkg = loadData(paths['bkg'], tf.config['outputtree'], stop=1)
    info_sig = loadData(paths['sig'], tf.config['outputtree'], stop=1)

    # Check output
    if bkg.size == 0 or sig.size == 0:
        warning("No data was loaded.")
        return

    # Scaling by cross-section
    xsec = loadXsec(tf.config['xsec_file'])

    bkg = scale_weights(bkg, info_bkg, xsec, lumi=tf.config['lumi'])
    sig = scale_weights(sig,
                        info_sig,
                        xsec,
                        lumi=tf.config['lumi'],
                        verbose=True)

    # Compute significance improvements
    # --------------------------------------------------------------------------

    # Loop tau21DDT bins
    cuts = np.linspace(axis['tau21DDT'][1],
                       axis['tau21DDT'][2],
                       10 * axis['tau21DDT'][0] + 1,
                       endpoint=True)
    bins = np.linspace(axis['m'][1],
                       axis['m'][2],
                       axis['m'][0] + 1,
                       endpoint=True)
    significances = [list() for _ in range(len(set(sig['DSID'])))]
    plot_cut = 36

    c_temp = ap.canvas(batch=True)
    for icut, cut in enumerate(cuts):
        print "Bin %2d: tau21DDT < %.3f" % (icut, cut)

        # Create histograms
        msk = bkg['tau21DDT'] < cut
        h_bkg = c_temp.hist(bkg['m'][msk],
                            bins=bins,
                            weights=bkg['weight'][msk],
                            fillcolor=ROOT.kAzure + 7,
                            name='Background',
                            display=(icut == plot_cut))
        h_sigs = list()
        for idx, (DSID, name) in enumerate(
                zip(sorted(list(set(sig['DSID']))), sig_names)):
            msk = (sig['DSID'] == DSID) & (sig['tau21DDT'] < cut)
            h_sigs.append(
                c_temp.hist(sig['m'][msk],
                            bins=bins,
                            weights=sig['weight'][msk],
                            linestyle=1 + idx,
                            label=name,
                            display=(icut == plot_cut)))
            pass

        # Fill histograms
        for i, h_sig in enumerate(h_sigs):
            print " -- Signal %d |" % (i + 1),
            sign = 0.
            for bin in range(1, h_bkg.GetXaxis().GetNbins() + 1):
                s = h_sig.GetBinContent(bin)
                b = max(h_bkg.GetBinContent(bin), 0.5)
                if icut == 35:
                    print s, b
                    pass
                #sign += np.square(s/np.sqrt(b))
                sign += 2 * (
                    (s + b) * np.log(1 + s / b) - s
                )  # Slide 29 in [http://www2.warwick.ac.uk/fac/sci/physics/research/epp/events/seminars/cowan_warwick_2011.pdf] -- here using the _square_ of the per-bin significance, in order to add them in quadrature
                pass
            print "Significance:", sign
            sign = np.sqrt(sign)
            significances[i].append(sign)
            pass

        pass

    # Fix for icut == 35, isig == 2 # @TEMP!!!
    significances[2][35] = 0.5 * (significances[2][34] + significances[2][36])

    c_temp.xlabel("Large-#it{R} jet mass [GeV]")
    c_temp.logy()
    c_temp.legend()
    if args.save: c_temp.save("plots/cutoptimisation_massspectrum.pdf")

    # Compute significance improvements
    improvements = [np.array(sign) / sign[-1] for sign in significances]
    improvements_avg = np.mean(improvements, axis=0)
    idx_max = np.argmax(improvements_avg)

    print "Optimal cut: %.2f (avg. improvement: %.3f)" % (
        cuts[idx_max], improvements_avg[idx_max])
    msk = bkg['tau21DDT'] < cuts[idx_max]
    print "Background efficiency: %.2f%%" % (np.sum(bkg['weight'][msk]) /
                                             np.sum(bkg['weight']) * 100.)
    print "Signal efficiencies:"
    for name, DSID in zip(sig_names, sorted(list(set(sig['DSID'])))):
        msk_num = (sig['DSID'] == DSID) & (sig['tau21DDT'] < cuts[idx_max])
        msk_den = (sig['DSID'] == DSID)
        print "  %s: %.2f%%" % (name, np.sum(sig['weight'][msk_num]) /
                                np.sum(sig['weight'][msk_den]) * 100.)
        pass

    print ""
    cut_man = 0.50
    print "For manual cut: %.2f (avg. improvement: %.3f)" % (
        cut_man, float(improvements_avg[np.where(cuts == cut_man)]))
    msk = bkg['tau21DDT'] < cut_man
    print "Background efficiency: %.2f%%" % (np.sum(bkg['weight'][msk]) /
                                             np.sum(bkg['weight']) * 100.)
    print "Signal efficiencies:"
    for name, DSID in zip(sig_names, sorted(list(set(sig['DSID'])))):
        msk_num = (sig['DSID'] == DSID) & (sig['tau21DDT'] < cut_man)
        msk_den = (sig['DSID'] == DSID)
        print "  %s: %.2f%%" % (name, np.sum(sig['weight'][msk_num]) /
                                np.sum(sig['weight'][msk_den]) * 100.)
        pass

    # Plot improvements
    # --------------------------------------------------------------------------

    # Create canvas
    c = ap.canvas(batch=not args.show)

    bins = np.linspace(axis['tau21DDT'][1],
                       axis['tau21DDT'][2],
                       axis['tau21DDT'][0] + 1,
                       endpoint=True)

    # Draw histograms
    msk = bkg['tau21DDT'] < cut
    h_bkg = c.hist(bkg['tau21DDT'][msk],
                   bins=bins,
                   weights=bkg['weight'][msk],
                   fillcolor=ROOT.kAzure + 7,
                   name='Incl. #gamma MC',
                   normalise=True)
    h_sigs = list()
    for idx, (DSID,
              name) in enumerate(zip(sorted(list(set(sig['DSID']))),
                                     sig_names)):
        msk = (sig['DSID'] == DSID) & (sig['tau21DDT'] < cut)
        h_sigs.append(
            c.hist(sig['tau21DDT'][msk],
                   bins=bins,
                   weights=sig['weight'][msk],
                   linecolor=ROOT.kRed + idx,
                   label=name,
                   normalise=True))
        pass

    # Overlay
    o = ap.overlay(c, color=ROOT.kViolet)
    graphs = list()
    for idx, impr in enumerate(improvements):
        graphs.append(o.graph(impr, bins=cuts, display=None))
        pass
    gr = o.graph(improvements_avg,
                 bins=cuts,
                 linecolor=ROOT.kViolet,
                 linewidth=2,
                 markerstyle=0,
                 option='L')
    o.padding(0.50)
    o.label("Average significance improvement")

    # Text
    c.padding(0.40)
    c.text([
        "#sqrt{s} = 13 TeV,  L = 36.1 fb^{-1}",
        "ISR #gamma selection",
    ],
           qualifier='Simulation Internal')

    c.xlabel('Signal jet #tau_{21}^{DDT}')
    c.ylabel('Events (normalised)')

    # Lines
    o.line(cuts[idx_max], 0, cuts[idx_max], improvements_avg[idx_max])

    # Legend
    c.legend(width=0.28)

    # Show
    if args.save: c.save('plots/cutoptimisation.pdf')
    if args.show: c.show()

    # Write output to file
    f = ROOT.TFile('output/hists_isrgamma_cutoptimisation.root', 'RECREATE')
    h_bkg.SetName('h_tau21DDT_bkg')
    h_bkg.Write()
    for idx in range(len(h_sigs)):
        name = sig_names[idx]
        m = re.search('\(([0-9]+) GeV\)', name)
        h_sigs[idx].SetName('h_tau21DDT_sig%s' % m.group(1))
        h_sigs[idx].Write()
        graphs[idx].SetName('gr_improvements_sig%s' % m.group(1))
        graphs[idx].Write()
        pass
    gr.SetName('gr_improvements_avg')
    gr.Write()
    f.Write()
    f.Close()

    return
Example #19
0
def main ():

    # Parse command-line arguments
    args = parser.parse_args()

    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

    # Get files
    if not args.isrjet:
        files = glob.glob(tf.config['base_path'] + 'objdef_MC_30836*.root')
    else:
        #files = glob.glob('/afs/cern.ch/user/l/lkaplan/public/forAndreas/signals/sig_*.root')
        files = glob.glob('/afs/cern.ch/user/l/lkaplan/public/forAndreas/signals_fatjetunc/sig_*.root')
        pass

    if len(files) == 0:
        warning("No files found.")
        return

    # Get names of all available systematic variations
    f = ROOT.TFile(files[0], 'READ')
    if not args.isrjet:
        f.cd("BoostedJet+ISRgamma")
        pass
    variations = [key.GetName() for key in ROOT.gDirectory.GetListOfKeys()]
    f.Close()

    colours = [ROOT.kViolet + 7, ROOT.kAzure + 7, ROOT.kTeal, ROOT.kSpring - 2, ROOT.kOrange - 3, ROOT.kPink]

    # Load data
    if not args.isrjet:
        data = {var: loadData(files, tf.config['finaltree'] .replace('Nominal', var), prefix=tf.config['prefix']) for var in variations}
        info = {var: loadData(files, tf.config['outputtree'].replace('Nominal', var), stop=1) for var in variations}
        
        # Scaling by cross section
        xsec = loadXsec(tf.config['xsec_file'])
        
        # Append new DSID field # @TODO: Make more elegant?
        for var in variations:
            data[var] = append_fields(data[var], 'DSID', np.zeros((data[var].size,)), dtypes=int)
            for idx in info[var]['id']:    
                msk = (data[var]['id'] == idx) # Get mask of all 'data' entries with same id, i.e. from same file
                DSID = info[var]['DSID'][idx]  # Get DSID for this file
                data[var]['weight'][msk] *= xsec[DSID] # Scale by cross section x filter eff. for this DSID
                data[var]['DSID']  [msk] = DSID        # Store DSID
                pass
            data[var]['weight'] *= tf.config['lumi'] # Scale all events (MC) by luminosity
            pass

    else:
        data = {var: loadData(files, var) for var in variations}
        for var in variations:
            data[var] = append_fields(data[var], 'DSID', np.zeros((data[var].size,)), dtypes=int)
            for idx in list(set(data[var]['id'])):
                msk = (data[var]['id'] == idx) # Get mask of all 'data' entries with same id, i.e. from same file
                data[var]['DSID'][msk] = idx
                pass
            pass
        pass


    # Check output.
    if not args.isrjet and data['Nominal'].size == 0:
        warning("No data was loaded.")
        return 

    nominal = 'Nominal' if not args.isrjet else 'Signal_ISRjet'
    m       = 'm' if not args.isrjet else 'mJ'

    # Perform interpolation of signal mass peaks
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

    closure = True

    # Store mass points
    if closure:
        massPoints = np.array([100, 130,      190, 220])
    else:
        massPoints = np.array([100, 130, 160, 190, 220])
        pass
    massVec = ROOT.TVectorD(len(massPoints))
    for i in range(len(massPoints)):
        massVec[i] = massPoints[i]
        pass

    # Prepare workspaces
    workspace = ROOT.RooWorkspace()

    # Create variables
    mZ = workspace.factory('mZ[50,300]') # this is our continuous interpolation parameter

    mJ = workspace.factory('mJ[50,300]')
    mJ.setBins(50)
    frame = mJ.frame()


    # Create fit model
    for i in range(len(massPoints)):
        workspace.factory('Gaussian::signal{i}(mJ, mu_sig_{i}[{mean},0,300], sigma_sig_{i}[{width},0,50])'.format(i=i, mean=massPoints[i], width=massPoints[i]*0.1))
        if not args.isrjet:
            workspace.factory('Gaussian::background{i}(mJ, mu_bkg_{i}[0,0,0], sigma_bkg_{i}[100,50,500])'.format(i=i))
        else:
            workspace.factory('Exponential::background{i}(mJ, tau_bkg_{i}[-0.01,-100,0])'.format(i=i))
            pass

        workspace.factory('SUM::model{i}(norm_sig_{i}[2,0,10]*signal{i}, norm_bkg_{i}[1,1,1]*background{i})'.format(i=i))
        pass

    # Create p.d.f.s
    c = ap.canvas(batch=not args.show)
    bins = np.linspace(50, 300, 50 + 1, endpoint=True)

    pdfs = ROOT.RooArgList(*[workspace.pdf('model{i}'.format(i=i)) for i in range(len(massPoints))])
    integrals = np.zeros((len(massPoints),), dtype=float)
    events    = np.zeros((len(massPoints),), dtype=float)
    #for idx in range(len(massPoints)):
    for idx, mass in enumerate(massPoints):
        #DSID = idx + (308363 if not args.isrjet else 0)
        DSID = (mass - 100) / 30 + (308363 if not args.isrjet else 0)
        print "==> %d" % DSID

        # Create data histogram for fitting
        msk = (data[nominal]['DSID'] == DSID)        
        hist = c.hist(data[nominal][m][msk], bins=bins, weights=data[nominal]['weight'][msk], normalise=True, display=False)
        integrals[idx] = np.sum(data[nominal]['weight'][msk])
        events   [idx] = np.sum(msk)

        # Add minimal error to empty bins
        emax = np.finfo(float).max
        for bin in range(1, hist.GetXaxis().GetNbins() + 1):
            if hist.GetBinError(bin) == 0: hist.SetBinError(bin, emax)
            pass

        # Create RooFit histogram and p.d.f.
        rdh = ROOT.RooDataHist('rdh', 'rdh', ROOT.RooArgList(mJ), hist)
        rhp = ROOT.RooHistPdf ('rhp', 'rhp', ROOT.RooArgSet (mJ), rdh)

        # Fit data with model
        pdfs[idx].chi2FitTo(rdh, ROOT.RooLinkedList())

        # Plot data histogram and fit
        rhp      .plotOn(frame, ROOT.RooFit.LineColor(colours[idx]), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(3))
        pdfs[idx].plotOn(frame, ROOT.RooFit.LineColor(ROOT.kBlack), ROOT.RooFit.LineStyle(2))
        pass

    setting = ROOT.RooMomentMorph.Linear
    morph = ROOT.RooMomentMorph('morph', 'morph', mZ, ROOT.RooArgList(mJ), pdfs, massVec, setting)
    getattr(workspace,'import')(morph) # work around for morph = w.import(morph)
    morph.Print('v')

    # Make plots of interpolated p.d.f.s
    #interpolationMassPoints = np.linspace(100, 220, (220 - 100) / 10 + 1, endpoint=True)
    interpolationMassPoints = np.linspace(100, 220, (220 - 100) / 5 + 1, endpoint=True)
    interpolationMassPoints = sorted(list(set(interpolationMassPoints) - set(massPoints)))
    """ @TEMP: BEGIN """
    # -- Interpolate logarithmically between integrals
    interpolationIntegrals = np.exp(np.interp(interpolationMassPoints, massPoints, np.log(integrals)))
        
    # -- Interpolate linearly between event counts
    interpolationEvents    =        np.interp(interpolationMassPoints, massPoints, events).astype(int)   
    """ @TEMP: END """

    #for i, (n, integral, mass) in enumerate(zip(interpolationEvents, interpolationIntegrals, interpolationMassPoints)):
    for i, mass in enumerate(interpolationMassPoints):
        print "=" * 80
        mZ.setVal(mass)
        mZ.Print()
        morph.Print()
        morph.plotOn(frame, ROOT.RooFit.LineColor(ROOT.kRed - 4), ROOT.RooFit.LineStyle(2), ROOT.RooFit.LineWidth(1))
        pass

    # Interpolation closure
    if closure:

        # Get mass and DSID
        idx = 2
        mass = 100 + idx * 30
        DSID = idx + (308363 if not args.isrjet else 0)
        
        print "Performing closure test with %d" % DSID
        
        # Create data histogram for fitting
        msk = (data[nominal]['DSID'] == DSID)        
        hist = c.hist(data[nominal][m][msk], bins=bins, weights=data[nominal]['weight'][msk], normalise=True, display=False)
        
        # Add minimal error to empty bins
        emax = np.finfo(float).max
        for bin in range(1, hist.GetXaxis().GetNbins() + 1):
            if hist.GetBinError(bin) == 0: hist.SetBinError(bin, emax)
            pass
        
        # Create RooFit histogram and p.d.f.
        rdh = ROOT.RooDataHist('rdh', 'rdh', ROOT.RooArgList(mJ), hist)
        rhp = ROOT.RooHistPdf ('rhp', 'rhp', ROOT.RooArgSet (mJ), rdh)
        
        # Plot data histogram and fit
        rhp    .plotOn(frame, ROOT.RooFit.LineColor(1), ROOT.RooFit.LineStyle(1))

        # Plot morphed distribution
        mZ.setVal(mass)
        morph.plotOn(frame, ROOT.RooFit.LineColor(ROOT.kBlue - 4), ROOT.RooFit.LineStyle(2), ROOT.RooFit.LineWidth(3))
        
        # Get RooFit chi2 value
        workspace.factory('Gaussian::signal{i}(mJ, mu_sig_{i}[{mean},0,300], sigma_sig_{i}[{width},0,50])'.format(i=4, mean=mass, width=mass*0.1))
        if not args.isrjet:
            workspace.factory('Gaussian::background{i}(mJ, mu_bkg_{i}[0,0,0], sigma_bkg_{i}[100,50,500])'.format(i=4))
        else:
            workspace.factory('Exponential::background{i}(mJ, tau_bkg_{i}[-0.01,-100,0])'.format(i=4))
            pass

        workspace.factory('SUM::model{i}(norm_sig_{i}[2,0,10]*signal{i}, norm_bkg_{i}[1,1,1]*background{i})'.format(i=4))

        interp_pdf = workspace.pdf('model{i}'.format(i=4))
        interp_pdf.chi2FitTo(rdh, ROOT.RooLinkedList())

        # Compute chi2 for data histogram vs. interpolated one
        h_data = rhp       .createHistogram("h_data", mJ)
        h_est  = morph     .createHistogram("h_est",  mJ)
        h_fit  = interp_pdf.createHistogram("h_fit",  mJ)
        h_fit.Scale(1./h_fit.Integral())

        chi2 = 0.
        for bin in range(1, h_est.GetXaxis().GetNbins() + 1):
            o = h_fit.GetBinContent(bin) # Fitted
            p = h_est.GetBinContent(bin) # Interpolated
            chi2 += np.square(o - p) / o
            pass
        N = np.sum(msk)
        chi2 *= N
        ndf = h_est.GetXaxis().GetNbins() - 1

        prob = ROOT.TMath.Prob(chi2, ndf)
        print "Chi2 = %.2f | Ndf = %d | p = %.3f" % (chi2, ndf, prob)


        #for h in [h_data, h_est, h_fit]:
        #    print ">> %.3f" % h.Integral()
        #    pass

        #hist.Scale(h_est.Integral()/hist.Integral())
        #h_est.Scale(hist.Integral()/h_est.Integral())
        #h_fit.Scale(hist.Integral()/h_fit.Integral())
        #for bin in range(1, h_est.GetXaxis().GetNbins() + 1):
        #    h_est.SetBinError(bin, 0)
        #    pass

        h_fit.Scale(N)
        h_est.Scale(N)
        for bin in range(1, h_est.GetXaxis().GetNbins() + 1):
            h_fit.SetBinError(bin, np.sqrt(h_fit.GetBinContent(bin)))
            h_est.SetBinError(bin, np.sqrt(h_est.GetBinContent(bin)))
            pass

        print "Chi2 prob. = %.3f" % h_fit.Chi2Test(h_est, "WW P")
        print "KS prob.   = %.3e / %.3e" % (h_fit.KolmogorovTest(h_est), h_est.KolmogorovTest(h_fit))

        c = ap.canvas()
        c.hist(h_data, label='Data',          linecolor=ROOT.kBlack)
        c.hist(h_est,  label='Interpolation', linecolor=ROOT.kRed,  linestyle=2)
        c.hist(h_fit,  label='Fit',           linecolor=ROOT.kBlue, linestyle=2)
        c.legend()
        c.show()

        return

        chi2var = ROOT.RooChi2Var("chi2", "chi2", morph, rdh)
        chi2 = chi2var.getVal()
        print "(1) CHI2:", chi2 

        chi2var = ROOT.RooChi2Var("chi2", "chi2", morph, interp_pdf)
        chi2 = chi2var.getVal()
        print "(2) CHI2:", chi2 

        #for bin in range(1, hist.GetXaxis().GetNbins() + 1):
        #    print "-- %.1f :%.5f vs. %.5f / %.3f" % (hist.GetBinCenter(bin), hist.GetBinContent(bin), h_est.GetBinContent(bin), hist.GetBinContent(bin) / h_est.GetBinContent(bin))
        #    pass

        #hist.scale(1./hist.Integral())
        '''
        chi2 = 0.
        N = np.sum(msk)
        print "N = %.1f" % N
        O = 0
        P = 0
        for bin in range(1, hist.GetXaxis().GetNbins() + 1):
            mJ.setVal(hist.GetXaxis().GetBinCenter(bin))
            o = rhp  .getVal(ROOT.RooArgSet(mJ))
            p = morph.getVal(ROOT.RooArgSet(mJ))
            #print "  morph(%.1f) = %.5f vs. %.5f / %.3f" % (mJ.getVal(), o, p, o/p)
            chi2 += np.square(o * 5. - p * 5.) / (p * 5.)
            O += o
            P += p
            pass
        chi2 *= N
        ndf = hist.GetXaxis().GetNbins() - 1
        prob = ROOT.TMath.Prob(chi2, ndf)
        #print "O =", O
        #print "P =", P
        #print "Chi2 = %.2f | Ndf = %d | p = %.3f" % (chi2, ndf, prob)
        '''

        #for massval in np.linspace(135, 185, 9, endpoint=True):
        #    mZ.setVal(massval)
        #    morph.plotOn(frame, ROOT.RooFit.LineColor(ROOT.kBlue), ROOT.RooFit.LineStyle(2), ROOT.RooFit.LineWidth(3 if massval == 160 else 1))    
        #    pass

        # Compute chi2 value
        # ...
        pass

    # Draw frame
    if args.show or args.save:
        c = ap.canvas(batch=not args.show)
        c.pads()[0]._bare().cd()
        frame.Draw()
        frame.GetXaxis().SetTitle("Large-#it{R} jet mass [GeV]")
        frame.GetYaxis().SetTitle("Signal p.d.f.")
        frame.GetYaxis().SetRangeUser(0, 0.22)
        c.text(["#sqrt{s} = 13 TeV", "ISR %s channel" % ('#gamma' if not args.isrjet else 'jet')], qualifier="Simulation Internal")
        c.legend(header="Signal MC shape:",
                 categories= [ ("Z' (%d GeV)" % mass, {'linecolor': colours[idx], 'linewidth': 3, 'option': 'L'}) for idx, mass in enumerate(massPoints)]
                + [
                ("Fitted  shape",      {'linecolor': ROOT.kBlack,   'linestyle': 2, 'linewidth': 2, 'option': 'L'}),
                ("Interpolated shape", {'linecolor': ROOT.kRed - 4, 'linestyle': 2, 'linewidth': 1, 'option': 'L'}),
                ])
        c.ylim(0, 0.22)
        if args.save: c.save('plots/interpolation_frame_isr%s.pdf' % ('gamma' if not args.isrjet else 'jet'))
        if args.show: c.show()
        pass

    # Write outputs
    if args.save:
        check_make_dir('output')
        
        # -- Interpolate logarithmically between integrals
        interpolationIntegrals = np.exp(np.interp(interpolationMassPoints, massPoints, np.log(integrals)))
        
        # -- Interpolate linearly between event counts
        interpolationEvents    =        np.interp(interpolationMassPoints, massPoints, events).astype(int)
        
        mult = 100
        for n, integral, mass in zip(mult * interpolationEvents, interpolationIntegrals, interpolationMassPoints):
            
            # Generate mass- and weight dataset for interpolated mass point
            weight = integral / float(n)
            mZ.setVal(mass)
            dataset = morph.generate(ROOT.RooArgSet(mJ), n)
            vector_m = np.array([dataset.get(idx).getRealValue('mJ') for idx in range(n)])
            
            # Get closest mass points on either side
            idx1 = np.where(massPoints - mass < 0)[0][-1]
            idx2 = np.where(massPoints - mass > 0)[0][0]
            DSID1 = idx1 + (308363 if not args.isrjet else 0)
            DSID2 = idx2 + (308363 if not args.isrjet else 0)
            
            # Open output file
            DSID = int("200%03d" % mass)
            if not args.isrjet:
                filename = 'objdef_MC_{DSID:6d}.root'.format(DSID=DSID)
            else:
                filename = 'sig_%d.root' % mass
                pass
            outputdir = '/eos/atlas/user/a/asogaard/Analysis/2016/BoostedJetISR/StatsInputs/2017-08-06/'
            #output = ROOT.TFile('output/' + filename, 'RECREATE')
            output = ROOT.TFile(outputdir + filename, 'RECREATE')

            print "Writing %d events to file '%s'" % (n, output.GetName())
            ROOT.TH1.AddDirectory(0)
            
            # Get nominal histograms for each of the two closes mass points
            
            msk1 = data[nominal]['DSID'] == DSID1
            msk2 = data[nominal]['DSID'] == DSID2
            
            hist_nom1 = c.hist(data[nominal][m][msk1], bins=bins, weights=data[nominal]['weight'][msk1], display=False)
            hist_nom2 = c.hist(data[nominal][m][msk2], bins=bins, weights=data[nominal]['weight'][msk2], display=False)
            
            # Loop systematic variations
            for var in variations:

                # Reset for each variation!
                vector_w = np.ones((n,)) * weight
                
                print "  Writing arrays to file: %s" % var
                
                msk1 = data[var]['DSID'] == DSID1
                msk2 = data[var]['DSID'] == DSID2
                
                hist_var1 = c.hist(data[var][m][msk1], bins=bins, weights=data[var]['weight'][msk1], display=False)
                hist_var2 = c.hist(data[var][m][msk2], bins=bins, weights=data[var]['weight'][msk2], display=False)
                
                # Plot variations
                c2 = ap.canvas(num_pads=2, batch=not args.show)
                p0, p1 = c2.pads()
                c2.hist(vector_m, bins=bins, weights=vector_w, label="%d GeV (interp.)" % mass)
                c2.hist(hist_nom1, linecolor=ROOT.kRed,  label="%d GeV" % massPoints[idx1])
                c2.hist(hist_nom2, linecolor=ROOT.kBlue, label="%d GeV" % massPoints[idx2])
                c2.hist(hist_var1, linecolor=ROOT.kRed,  linestyle=2)
                c2.hist(hist_var2, linecolor=ROOT.kBlue, linestyle=2)
                
                # -- Get the variation/nominal ratio for each closest masspoint
                hist_rel1 = c2.ratio_plot((hist_var1, hist_nom1), linecolor=ROOT.kRed,  linestyle=1, option='HIST')
                hist_rel2 = c2.ratio_plot((hist_var2, hist_nom2), linecolor=ROOT.kBlue, linestyle=1, option='HIST')
                
                # -- Get the number of bins to shift the systematic variation of each closest masspoint
                binwidth = bins[1] - bins[0]
                shift1 = int(np.round((mass - massPoints[idx1]) / binwidth))
                shift2 = int(np.round((mass - massPoints[idx2]) / binwidth))
                arr_rel1 = hist2array(hist_rel1)
                arr_rel2 = hist2array(hist_rel2)
                
                # -- Shift the variations by the appropriate number of bins by _rolling_
                arr_relshift1 = np.roll(arr_rel1, shift1)
                arr_relshift2 = np.roll(arr_rel2, shift2)
                arr_relshift1[:shift1] = 1
                arr_relshift2[shift2:] = 1
                
                # -- Get weights for the averaging of the two shifted systematics
                w1 = 1. / float(abs(shift1))
                w2 = 1. / float(abs(shift2))
                
                # -- Take the weighted average
                arr_relshift = (w1 * arr_relshift1 + w2 * arr_relshift2) / (w1 + w2)
                
                hist_relshift1 = array2hist(arr_relshift1, hist_rel1.Clone("hist_relshift1"))
                hist_relshift2 = array2hist(arr_relshift2, hist_rel2.Clone("hist_relshift2"))
                hist_relshift  = array2hist(arr_relshift,  hist_rel1.Clone("hist_relshift"))
                
                p1.hist(hist_relshift1, linecolor=ROOT.kRed,   linestyle=2)
                p1.hist(hist_relshift2, linecolor=ROOT.kBlue,  linestyle=2)
                p1.hist(hist_relshift,  linecolor=ROOT.kBlack, linestyle=1)
                
                # -- Compute the jet-by-jet weights for the current variation
                vector_w_var = vector_w
                for bin in range(1, hist_relshift.GetXaxis().GetNbins() + 1):
                    # Get mask for all jet in 'bin'
                    msk = (vector_m >= hist_relshift.GetXaxis().GetBinLowEdge(bin)) & (vector_m < hist_relshift.GetXaxis().GetBinUpEdge(bin))
                    vector_w_var[msk] *= hist_relshift.GetBinContent(bin)
                    pass
                
                c2.hist(vector_m, bins=bins, weights=vector_w_var, linecolor=ROOT.kBlack, linestyle=2)
                
                p1.ylim(0.5, 1.5)
                p1.yline(1)
                c2.xlabel('Large-#it{R} jet mass [GeV]')
                c2.ylabel('Events / 5 GeV')
                p1.ylabel('Variation / nominal')
                c2.legend(header="Signal mass point:", categories=[
                        ('Nominal', {}),
                        (var,       {'linestyle': 2}),
                        ])
                c2.text(["#sqrt{s} = 13 TeV",
                         "ISR %s channel" % ('gamma' if not args.isrjet else 'jet'),
                         ], qualifier='Simulation Internal')
                if args.save: c2.save('plots/interpolation_shift_isr%s_%s_%dGeV.pdf' % ('gamma' if not args.isrjet else 'jet', var, mass))
                if args.show: c2.show()
                
                
                # Prepare DISD and isMC vectors
                vector_DSID = np.ones_like(vector_w_var) * DSID
                vector_isMC = np.ones_like(vector_w_var).astype(bool)
                
                jetmassname = (tf.config['prefix'] + 'm' if not args.isrjet else 'mJ')
                
                array1 = np.array(zip(vector_m, vector_w_var),
                                  dtype = [(jetmassname, np.float64),
                                           ('weight',    np.float64)])
                
                array2 = np.array(zip(vector_DSID, vector_isMC),
                                  dtype = [('DSID', np.uint32),
                                           ('isMC', np.bool_)])
                
                # Mass and weight branch
                if not args.isrjet:
                    treename1 = tf.config['finaltree'].replace('Nominal', var)
                else:
                    treename1 = var.replace('ISRjet', 'ISRjet_%d' % mass)
                    pass
                make_directories('/'.join(treename1.split('/')[:-1]), fromDir=output)
                tree1 = ROOT.TTree(treename1.split('/')[-1], "")
                array2tree(array1, tree=tree1)
                
                # outputTree
                if not args.isrjet:
                    treename2 = tf.config['outputtree'].replace('Nominal', var)
                    make_directories('/'.join(treename2.split('/')[:-1]), fromDir=output)
                    tree2 = ROOT.TTree(treename2.split('/')[-1], "")
                    array2tree(array2, tree=tree2)
                    pass
                
                output.Write()
                pass
            
            output.Close()
            pass

        pass

    return
Example #20
0
def main():

    # Parse command-line arguments
    args = parser.parse_args()

    # Set correct weighting
    ROOT.TH1.SetDefaultSumw2(True)

    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    signal_DSID = int("1%02d085" %
                      (0 if args.window is None else args.window * 100))

    # Load data
    files = {
        'data':
        glob.glob(tf.config['base_path'] + 'objdef_data_*.root'),
        'bkg':
        glob.glob(tf.config['base_path'] + 'objdef_TF_%d.root' % signal_DSID),
        #'sig':  glob.glob(tf.config['base_path'] + 'objdef_MC_3054*.root'),
        'W':
        glob.glob(tf.config['base_path'] + 'objdef_MC_30543*.root'),
        'Z':
        glob.glob(tf.config['base_path'] + 'objdef_MC_30544*.root'),
        'sfl':
        glob.glob(tf.config['base_path'] +
                  'objdef_TF_%d_signalfail.root' % signal_DSID),
    }

    if 0 in map(len, files.values()):
        warning("No files found.")
        return

    data = {
        key: loadData(files[key],
                      tf.config['finaltree'],
                      prefix=tf.config['prefix'])
        for key in files
    }
    data_up = {
        key: loadData(files[key],
                      tf.config['finaltree'].replace('Nominal', 'TF_UP'),
                      prefix=tf.config['prefix'])
        for key in ['bkg', 'sfl']
    }
    data_down = {
        key: loadData(files[key],
                      tf.config['finaltree'].replace('Nominal', 'TF_DOWN'),
                      prefix=tf.config['prefix'])
        for key in ['bkg', 'sfl']
    }
    info = {
        key: loadData(files[key], tf.config['outputtree'], stop=1)
        for key in files
    }

    # Scaling by cross section
    xsec = loadXsec(tf.config['xsec_file'])

    # Append new DSID field # @TODO: Make more elegant?
    # Only needs to be done for 'signal', for 'nominal' syst. variation
    for comp in ['W', 'Z']:  # 'sig'
        data[comp] = append_fields(data[comp],
                                   'DSID',
                                   np.zeros((data[comp].size, )),
                                   dtypes=int)
        for idx in info[comp]['id']:
            msk = (
                data[comp]['id'] == idx
            )  # Get mask of all 'data' entries with same id, i.e. from same file
            DSID = info[comp]['DSID'][idx]  # Get DSID for this file
            data[comp]['weight'][msk] *= xsec[
                DSID]  # Scale by cross section x filter eff. for this DSID
            data[comp]['DSID'][msk] = DSID  # Store DSID
            pass
        data[comp]['weight'] *= tf.config[
            'lumi']  # Scale all events (MC) by luminosity
        pass

    # Check output.
    if data['data'].size == 0:
        warning("No data was loaded.")
        return

    # k-factors
    kfactor = {'W': 0.7838, 'Z': 1.3160}

    data['W']['weight'] *= kfactor['W']
    data['Z']['weight'] *= kfactor['Z']
    data['sig'] = np.concatenate((data['W'], data['Z']))

    # Plotting pre-fit jet mass spectrum
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    bestfit_mu = None

    for mu, fit, prefit, subtract in zip([0, 1, 1, None],
                                         [False, False, True, False],
                                         [True, True, True, False],
                                         [True, True, False, True]):

        if not prefit:
            print "#" * 20, bestfit_mu, "#" * 20
            mu = bestfit_mu[0]
            pass

        # Plotting
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        c = ap.canvas(num_pads=2, batch=not args.show)
        p0, p1 = c.pads()

        # -- Histograms: Main pad
        bins = np.linspace(50, 112, 31 + 1,
                           endpoint=True)  # tf.config['massbins']

        h_bkg = c.hist(data['bkg']['m'],
                       bins=bins,
                       weights=data['bkg']['weight'],
                       display=False)
        h_bkg_up = c.hist(data_up['bkg']['m'],
                          bins=bins,
                          weights=data_up['bkg']['weight'],
                          display=False)
        h_bkg_down = c.hist(data_down['bkg']['m'],
                            bins=bins,
                            weights=data_down['bkg']['weight'],
                            display=False)

        h_sig = c.hist(data['sig']['m'],
                       bins=bins,
                       weights=data['sig']['weight'],
                       scale=mu,
                       display=False)

        h_sfl = c.hist(data['sfl']['m'],
                       bins=bins,
                       weights=data['sfl']['weight'],
                       scale=mu,
                       display=False)
        h_sfl_up = c.hist(data_up['sfl']['m'],
                          bins=bins,
                          weights=data_up['sfl']['weight'],
                          scale=mu,
                          display=False)
        h_sfl_down = c.hist(data_down['sfl']['m'],
                            bins=bins,
                            weights=data_down['sfl']['weight'],
                            scale=mu,
                            display=False)

        if not fit:
            h_bkg.Add(h_sfl, -1)  # Subtracting signal
            h_bkg_up.Add(h_sfl_up, -1)  # --
            h_bkg_down.Add(h_sfl_down, -1)  # --
            pass

        h_bkg = c.stack(h_bkg,
                        fillcolor=ROOT.kAzure + 7,
                        label='Background pred.')

        h_Z = c.stack(data['Z']['m'],
                      bins=bins,
                      weights=data['Z']['weight'],
                      scale=mu,
                      fillcolor=ROOT.kAzure + 3,
                      label="Z + #gamma  (#times #mu)")
        h_W = c.stack(data['W']['m'],
                      bins=bins,
                      weights=data['W']['weight'],
                      scale=mu,
                      fillcolor=ROOT.kAzure + 2,
                      label="W + #gamma (#times #mu)")

        h_sum = h_bkg
        h_sum = c.hist(h_sum,
                       fillstyle=3245,
                       fillcolor=ROOT.kGray + 2,
                       linecolor=ROOT.kGray + 3,
                       option='E2',
                       label='Stat. uncert.')

        h_bkg_up = c.hist(h_bkg_up,
                          linecolor=ROOT.kRed + 1,
                          linestyle=2,
                          option='HIST',
                          label='TF syst. uncert.')
        h_bkg_down = c.hist(h_bkg_down,
                            linecolor=ROOT.kGreen + 1,
                            linestyle=2,
                            option='HIST')

        h_data = c.plot(data['data']['m'],
                        bins=bins,
                        weights=data['data']['weight'],
                        label='Data')

        # Manuall check chi2 for nominal systematic
        """
        if not fit:
            chi2 = 0.
            chi2_data = 0.
            for ibin in range(1, h_data.GetXaxis().GetNbins() + 1):
                stat_data = h_data.GetBinError(ibin)
                cont_data = h_data.GetBinContent(ibin)
                cont_bkg  = h_bkg .GetBinContent(ibin)
                cont_sig  = h_sig .GetBinContent(ibin)
                diff = np.abs(cont_data - (cont_bkg + cont_sig))
                chi2 +=  np.square(diff / stat_data)
                pass
            print "[INFO] mu = {:.2f} | chi2 = {:.1f}".format(mu, chi2)
            pass
            """

        # -- Histograms: Ratio pad
        c.ratio_plot((h_sig, h_sum),
                     option='HIST',
                     offset=1,
                     fillcolor=ROOT.kAzure + 2)
        c.ratio_plot((h_Z, h_sum),
                     option='HIST',
                     offset=1,
                     fillcolor=ROOT.kAzure + 3)
        c.ratio_plot((h_sum, h_sum), option='E2')
        c.ratio_plot((h_bkg_up, h_sum), option='HIST')
        c.ratio_plot((h_bkg_down, h_sum), option='HIST')
        c.ratio_plot((h_data, h_sum))

        # -- Text
        c.text(
            [
                "#sqrt{s} = 13 TeV,  L = %s fb^{-1}" % tf.config['lumi'],
                "Trimmed anti-k_{t}^{R=1.0} jets",
                "ISR #gamma selection",
                "Window: %d GeV #pm %d %%" %
                (85, (0.2 if args.window is None else args.window) *
                 100.),  # @TODO: Improve
                "%s-fit: #mu = %s" % ("Pre" if prefit else "Post", "%.0f" %
                                      mu if prefit else "%.2f #pm %.2f" %
                                      (mu, bestfit_mu[1])),
            ],
            qualifier='Internal')

        # -- Axis labels
        c.xlabel('Signal jet mass [GeV]')
        c.ylabel('Events')
        p1.ylabel('Data / Est.')

        # -- Axis limits
        c.padding(0.45)

        p1.ylim(0.95, 1.15)

        # -- Line(s)
        p1.yline(1.0)

        # -- Region labels
        c.region("SR", 0.8 * 85, 1.2 * 85)
        if args.window is not None:
            c.region("VR", (1 - args.window) * 85, 0.8 * 85)
            c.region("VR", 1.2 * 85, (1 + args.window) * 85)
            pass

        #c.log()
        c.legend()
        if args.show and not fit: c.show()
        if args.save and not fit:
            c.save('plots/wzsearch_%s%s.pdf' %
                   ('' if args.window is None else 'pm%d_' %
                    (args.window * 100),
                    'prefit_mu%d' % mu if prefit else 'postfit'))

        # Saving output for harmonised paper plots
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        if not prefit:
            outfile = ROOT.TFile('output/hists_isrgamma_WZ.root', 'RECREATE')
            h_bkg.SetName('h_mJ_QCD')
            h_bkg_up.SetName('h_mJ_QCD_up')
            h_bkg_down.SetName('h_mJ_QCD_down')
            h_data.SetName('h_mJ_data')
            h_W.SetName('h_mJ_WHad')
            h_Z.SetName('h_mJ_ZHad')
            for hist in [h_bkg, h_bkg_up, h_bkg_down, h_data, h_W, h_Z]:
                hist.Write()
                pass
            outfile.Close()
            pass

        # Fitting
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        if fit:

            hs_save = [
                h_bkg_down.Clone('h_save_down'),
                h_bkg.Clone('h_save_nom'),
                h_bkg_up.Clone('h_save_up'),
            ]

            hdata_save = [
                h_data.Clone('hdata_save_down'),
                h_data.Clone('hdata_save_nom'),
                h_data.Clone('hdata_save_up'),
            ]

            hsfl_save = [
                h_sfl_down.Clone('h_sfl_down'),
                h_sfl.Clone('h_sfl_nom'),
                h_sfl_up.Clone('h_sfl_up'),
            ]

            bestfit_mu = list()

            for variation in range(3):

                print "Variation: " + ("Nominal" if variation == 1 else
                                       ("Down" if variation == 0 else "Up"))

                # Get correct histogram for this variation
                h_bkg_use = hs_save[variation]
                h_sfl_use = hsfl_save[variation]
                h_data_use = hdata_save[variation]

                # -- Define jet mass variable
                mJ = ROOT.RooRealVar('mJ', 'mJ', 50, 112)
                mJ.setBins(31)

                # -- Define histograms
                rdh_bkg = ROOT.RooDataHist('rdh_bkg', 'rdh_bkg',
                                           ROOT.RooArgList(mJ), h_bkg_use)
                rdh_sig = ROOT.RooDataHist('rdh_sig', 'rdh_sig',
                                           ROOT.RooArgList(mJ), h_sig)
                rdh_sfl = ROOT.RooDataHist('rdh_sfl', 'rdh_sfl',
                                           ROOT.RooArgList(mJ), h_sfl_use)

                # -- Turn histograms into pdf's
                rhp_bkg = ROOT.RooHistPdf('rhp_bkg', 'rhp_bkg',
                                          ROOT.RooArgSet(mJ), rdh_bkg)
                rhp_sig = ROOT.RooHistPdf('rhp_sig', 'rhp_sig',
                                          ROOT.RooArgSet(mJ), rdh_sig)
                rhp_sfl = ROOT.RooHistPdf('rhp_sfl', 'rhp_sfl',
                                          ROOT.RooArgSet(mJ), rdh_sfl)

                # -- Define integrals as constants
                n_bkg = ROOT.RooRealVar('n_bkg', 'n_bkg', h_bkg_use.Integral())
                n_sig = ROOT.RooRealVar('n_sig', 'n_sig', h_sig.Integral())
                n_sfl = ROOT.RooRealVar('n_sfl', 'n_sfl', h_sfl_use.Integral())

                # -- Define signal strength and constant(s)
                v_mu = ROOT.RooRealVar('v_mu', 'v_mu', 1, 0, 5)
                v_neg1 = ROOT.RooRealVar('v_neg1', 'v_neg1', -1)

                # -- Define fittable normalisation factors
                c_bkg = ROOT.RooFormulaVar('c_bkg', 'c_bkg', '@0',
                                           ROOT.RooArgList(n_bkg))
                c_sig = ROOT.RooFormulaVar('c_sig', 'c_sig', '@0 * @1',
                                           ROOT.RooArgList(v_mu, n_sig))
                c_sfl = ROOT.RooFormulaVar(
                    'c_sfl', 'c_sfl', '@0 * @1 * @2',
                    ROOT.RooArgList(v_neg1, v_mu, n_sfl))

                # -- Construct combined pdf
                pdf = ROOT.RooAddPdf(
                    'pdf', 'pdf', ROOT.RooArgList(rhp_bkg, rhp_sig, rhp_sfl),
                    ROOT.RooArgList(c_bkg, c_sig, c_sfl))

                # -- Construct data histogram
                rdh_data = ROOT.RooDataHist('rdh_data', 'rdh_data',
                                            ROOT.RooArgList(mJ), h_data_use)

                # -- Fit pdf to data histogram
                #pdf.fitTo(rdh_data)
                chi2Fit = ROOT.RooChi2Var("chi2", "chi2", pdf, rdh_data,
                                          ROOT.RooFit.Extended())
                minuit = ROOT.RooMinuit(chi2Fit)
                minuit.migrad()
                minuit.hesse()
                r2 = minuit.save()

                bestfit_mu.append((v_mu.getValV(), v_mu.getError()))
                pass

            print "(" * 10, bestfit_mu, ")" * 10
            bestfit_mu = bestfit_mu[1][0], np.sqrt(
                np.power(abs(bestfit_mu[0][0] - bestfit_mu[2][0]) / 2., 2.) +
                np.power(bestfit_mu[1][1], 2.))
            pass

        pass

    return
def main():

    # Parse command-line arguments
    args = parser.parse_args()

    DSID = int("100%03d" % args.mass)

    # Setup.
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Get signal file
    sig_DSID = get_signal_DSID(args.mass, tolerance=10)
    if sig_DSID is None:
        warning("No signal file was found")
        return
    sig_file = 'objdef_MC_{DSID:6d}.root'.format(DSID=sig_DSID)

    # Load data
    files = {
        'data': glob.glob(tf.config['base_path'] + 'objdef_MC_3610*.root'),
        'gbs': glob.glob(tf.config['base_path'] + 'objdef_GBSMC_400001.root'),
        'WZ': glob.glob(tf.config['base_path'] + 'objdef_MC_3054*.root')
    }
    if args.inject:
        files['sig'] = glob.glob(tf.config['base_path'] + sig_file)
        pass

    if len(files) == 0:
        warning("No files found. Try to run:")
        warning(" $ source getSomeData.sh")
        return

    data = loadData(files['data'],
                    tf.config['tree'],
                    prefix=tf.config['prefix'])
    gbs = loadData(files['gbs'],
                   tf.config['finaltree'],
                   prefix=tf.config['prefix'])
    WZ = loadData(files['WZ'], tf.config['tree'], prefix=tf.config['prefix'])
    if args.inject:
        signal = loadData(files['sig'],
                          tf.config['tree'],
                          prefix=tf.config['prefix'])
    else:
        signal = None
        pass
    info = {
        key: loadData(files[key], tf.config['outputtree'], stop=1)
        for key in files
    }

    # Scaling by cross section
    xsec = loadXsec(tf.config['xsec_file'])

    # Append new DSID field
    if args.inject:
        signal = append_fields(signal,
                               'DSID',
                               np.zeros((signal.size, )),
                               dtypes=int)
        for idx, id in enumerate(info['sig']['id']):
            msk = (
                signal['id'] == id
            )  # Get mask of all 'signal' entries with same id, i.e. from same file
            DSID = info['sig']['DSID'][idx]  # Get DSID for this file
            signal['weight'][msk] *= xsec[
                DSID]  # Scale by cross section x filter eff. for this DSID
            signal['DSID'][msk] = DSID  # Store DSID
            pass
        signal['weight'] *= tf.config['lumi']
        pass

    WZ = append_fields(WZ, 'DSID', np.zeros((WZ.size, )), dtypes=int)
    for idx, id in enumerate(info['WZ']['id']):
        msk = (
            WZ['id'] == id
        )  # Get mask of all 'WZ' entries with same id, i.e. from same file
        DSID = info['WZ']['DSID'][idx]  # Get DSID for this file
        WZ['weight'][msk] *= xsec[
            DSID]  # Scale by cross section x filter eff. for this DSID
        WZ['DSID'][msk] = DSID  # Store DSID
        pass
    WZ['weight'] *= tf.config['lumi']

    #if not args.data:
    data = append_fields(data, 'DSID', np.zeros((data.size, )), dtypes=int)
    for idx, id in enumerate(info['data']['id']):
        msk = (
            data['id'] == id
        )  # Get mask of all 'data' entries with same id, i.e. from same file
        DSID = info['data']['DSID'][idx]  # Get DSID for this file
        data['weight'][msk] *= xsec[
            DSID]  # Scale by cross section x filter eff. for this DSID
        data['DSID'][msk] = DSID  # Store DSID
        pass
    data['weight'] *= tf.config['lumi']
    #pass

    # Compute new variables
    data = append_fields(data, 'logpt', np.log(data['pt']))
    WZ = append_fields(WZ, 'logpt', np.log(WZ['pt']))
    if signal is not None:
        signal = append_fields(signal, 'logpt', np.log(signal['pt']))
        pass

    # Inject signal into data
    if args.inject:
        data = np.array(np.concatenate((data, signal)), dtype=data.dtype)
        pass
    #if not args.data:
    data = np.array(np.concatenate((data, WZ)), dtype=data.dtype)
    #pass
    """ @TODO: Not sure this script works for data input... But it's not used anyway. """

    # Transfer factor
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Pass/fail masks
    # -- Data (incl. signal)
    msk_pass = tf.config['pass'](data)
    msk_fail = ~msk_pass

    # -- W/Z
    msk_WZ_pass = tf.config['pass'](WZ)
    msk_WZ_fail = ~msk_WZ_pass

    # -- Signal
    if args.inject:
        msk_sig_pass = tf.config['pass'](signal)
        msk_sig_fail = ~msk_sig_pass
        pass

    # Transfer factor calculator instance
    calc = tf.calculator(data=data, config=tf.config, subtract=WZ)

    # Nominal fit
    calc.fit()
    w_nom = calc.weights(data[msk_fail])
    w_nom_WZ = calc.weights(WZ[msk_WZ_fail])
    if args.show or args.save:
        calc.plot(show=args.show,
                  save=args.save,
                  prefix='plots/globalbackground_%s_%s_' %
                  ('injected' if args.inject else 'notinjected',
                   'data' if args.data else 'MC'))

    # mass +/- 20% stripe fit
    calc.mass = args.mass
    calc.window = 0.2
    calc.fit()
    w_stripe = calc.weights(data[msk_fail])
    w_stripe_WZ = calc.weights(WZ[msk_WZ_fail])
    if args.inject:
        w_stripe_sig = calc.weights(signal[msk_sig_fail])
        pass

    # Plotting
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    bins = np.linspace(100, 250, 30 + 1, endpoint=True)

    # Setup canvas
    c = ap.canvas(num_pads=2, batch=not args.show)
    p0, p1 = c.pads()

    # Add stacked backgrounds
    h_bkg_nom = c.hist(data['m'][msk_fail],
                       bins=bins,
                       weights=data['weight'][msk_fail] * w_nom,
                       display=False)
    h_bkg_stripe = c.hist(data['m'][msk_fail],
                          bins=bins,
                          weights=data['weight'][msk_fail] * w_stripe,
                          display=False)
    h_WZfl_nom = c.hist(WZ['m'][msk_WZ_fail],
                        bins=bins,
                        weights=WZ['weight'][msk_WZ_fail] * w_nom_WZ,
                        display=False)
    h_WZfl_stripe = c.hist(WZ['m'][msk_WZ_fail],
                           bins=bins,
                           weights=WZ['weight'][msk_WZ_fail] * w_stripe_WZ,
                           display=False)
    if args.inject:
        h_sig = c.hist(signal['m'][msk_sig_pass],
                       bins=bins,
                       weights=signal['weight'][msk_sig_pass],
                       display=False)
        h_sfl = c.hist(signal['m'][msk_sig_fail],
                       bins=bins,
                       weights=signal['weight'][msk_sig_fail] * w_stripe_sig,
                       display=False)
        pass
    h_gbs = c.hist(gbs['m'], bins=bins, weights=gbs['weight'], display=False)

    # -- Subtract (opt.)
    if args.inject:
        h_bkg_stripe.Add(h_sfl, -1)
        h_gbs.Add(h_sfl, -1)
        pass
    h_bkg_nom.Add(h_WZfl_nom, -1)
    h_bkg_stripe.Add(h_WZfl_stripe, -1)

    # -- Actually draw
    #if not args.data:
    h_WZ = c.stack(WZ['m'][msk_WZ_pass],
                   bins=bins,
                   weights=WZ['weight'][msk_WZ_pass],
                   fillcolor=ROOT.kRed - 4,
                   label='W/Z + #gamma')
    #pass

    h_bkg_nom = c.stack(h_bkg_nom,
                        fillcolor=ROOT.kAzure + 7,
                        label="Bkg. (full)")
    h_sum = c.getStackSum()
    h_bkg_stripe.Add(h_WZ)
    h_gbs.Add(h_WZ)
    if args.inject:
        h_sig = c.stack(h_sig,
                        fillcolor=ROOT.kViolet - 4,
                        label="Z' (%d GeV)" % args.mass)
        pass
    h_bkg_stripe = c.hist(h_bkg_stripe,
                          linecolor=ROOT.kGreen + 1,
                          label="Bkg. (window)")  # % args.mass)
    h_gbs = c.hist(h_gbs, linecolor=ROOT.kViolet + 1, label="Bkg. (GBS)")

    # Draw stats. error of stacked sum
    h_sum = c.hist(h_sum,
                   fillstyle=3245,
                   fillcolor=ROOT.kGray + 2,
                   linecolor=ROOT.kGray + 3,
                   label='Stats. uncert.',
                   option='E2')

    # Add (pseudo-) data
    h_data = c.plot(data['m'][msk_pass],
                    bins=bins,
                    weights=data['weight'][msk_pass],
                    markersize=0.8,
                    label='Data' if args.data else 'Pseudo-data')

    # Axis limits
    p1.ylim(0.8, 1.2)
    c.padding(0.45)
    c.log(True)

    # Draw error- and ratio plots
    if args.inject:
        hr_sig = c.ratio_plot((h_sig, h_sum), option='HIST', offset=1)
        pass
    h_err = c.ratio_plot((h_sum, h_sum), option='E2')
    h_ratio = c.ratio_plot((h_data, h_sum), oob=True)
    h_rgbs = c.ratio_plot((h_gbs, h_sum),
                          linecolor=ROOT.kViolet + 1,
                          option='HIST ][')
    h_rgbs = c.ratio_plot((h_bkg_stripe, h_sum),
                          linecolor=ROOT.kGreen + 1,
                          option='HIST ][')

    # Add labels and text
    c.xlabel('Signal jet mass [GeV]')
    c.ylabel('Events')
    p1.ylabel('Data / Nom.')
    c.text([
        "#sqrt{s} = 13 TeV,  L = 36.1 fb^{-1}",
    ] + ([
        "Sherpa incl. #gamma MC",
    ] if not args.data else []) + [
        "Trimmed anti-k_{t}^{R=1.0} jets",
        "ISR #gamma selection",
    ] + (["Signal injected"] if args.inject else []),
           qualifier='%sInternal' % ("Simulation " if not args.data else ""))

    # Add line(s)
    p1.yline(1.0)

    # Draw legend
    c.legend()
    c.region("SR", 0.8 * args.mass, 1.2 * args.mass)

    # Save and show plot
    if args.save:
        c.save('plots/globalbackground_spectrum_%dGeV_%s_%s.pdf' %
               (args.mass, 'injected' if args.inject else 'notinjected',
                'data' if args.data else 'MC'))
    if args.show: c.show()

    # p0-plot
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # Setup canvas
    c2 = ap.canvas(batch=not args.show)

    p_local = h_data.Clone('p_local')
    p_global = h_data.Clone('p_global')

    for bin in range(1, h_data.GetXaxis().GetNbins() + 1):
        c_data = h_data.GetBinContent(bin)
        e_data = h_data.GetBinError(bin)
        c_loc = h_bkg_stripe.GetBinContent(bin)
        e_loc = h_bkg_stripe.GetBinError(bin)
        c_glb = h_gbs.GetBinContent(bin)
        e_glb = e_loc  # h_gbs    .GetBinError  (bin)

        z_loc = (c_data -
                 c_loc) / np.sqrt(np.square(e_data) + np.square(e_loc))
        z_glb = (c_data -
                 c_glb) / np.sqrt(np.square(e_data) +
                                  np.square(e_glb)) if c_glb > 0 else 0

        p_loc = min(ROOT.TMath.Erfc(z_loc / np.sqrt(2)), 1)
        p_glb = min(ROOT.TMath.Erfc(z_glb / np.sqrt(2)), 1)

        p_local.SetBinContent(bin, p_loc)
        p_global.SetBinContent(bin, p_glb)
        p_local.SetBinError(bin, 0)
        p_global.SetBinError(bin, 0)
        pass

    c2.plot(p_local,
            markercolor=ROOT.kGreen + 1,
            linecolor=ROOT.kGreen + 1,
            option='PL',
            label="Local (20% window)")
    c2.plot(p_global,
            markercolor=ROOT.kViolet + 1,
            linecolor=ROOT.kViolet + 1,
            option='PL',
            label="Global (GBS)")
    c2.xlabel("Signal jet mass [GeV]")
    c2.ylabel("p_{0}")
    c2.log()

    c2.ylim(1E-04, 1E+04)
    for sigma in range(4):
        c2.yline(ROOT.TMath.Erfc(sigma / np.sqrt(2)))
        pass

    c2.text([
        "#sqrt{s} = 13 TeV,  L = 36.1 fb^{-1}",
    ] + ([
        "Sherpa incl. #gamma MC",
    ] if not args.data else []) + [
        "Trimmed anti-k_{t}^{R=1.0} jets",
        "ISR #gamma selection",
        ("Signal" if args.inject else "No signal") + " injected" +
        (" at m = %d GeV" % args.mass if args.inject else ""),
    ],
            qualifier='Simulation Internal')

    c2.region("SR", 0.8 * args.mass, 1.2 * args.mass)
    c2.legend()
    if args.save:
        c2.save('plots/globalbackground_p0_%dGeV_%s_%s.pdf' %
                (args.mass, 'injected' if args.inject else 'notinjected',
                 'data' if args.data else 'MC'))
    if args.show: c2.show()

    return