def compare_by_eta_pu_bins(graphs_list,
                               file_identifier,
                               pu_labels,
                               title,
                               oDir,
                               ylim=None,
                               lowpt_zoom=True):
        """Compare graphs for each (eta, PU) bin.

        Parameters
        ----------
        graphs_list : list[list[Contribution]]
            List of list of contributions, so you can any
            number of sets of contributions on a graph.
        file_identifier : str
            String to be inserted into resultant plot filename.
        title : str
            Title to put on plots
        oDir : str
            Output directory for plots
        ylim : list, optional
            Set y axis range
        lowpt_zoom : bool, optional
            Zoom in on low pt range
        """
        for (eta_min, eta_max) in pairwise(binning.eta_bins):
            rename_dict = dict(eta_min=eta_min, eta_max=eta_max)
            new_graphs_list = [
                setup_new_graphs(g, rename_dict) for g in graphs_list
            ]

            if not ylim:
                ylim = [0.5, 3.5] if eta_min > 2 else [0.5, 4]
            for i, pu_label in enumerate(pu_labels):
                rename_dict['pu_label'] = pu_label
                p = Plot(contributions=[ng[i] for ng in new_graphs_list],
                         what="graph",
                         xtitle="<p_{T}^{L1}>",
                         ytitle="Correction value (= 1/response)",
                         title=title.format(**rename_dict),
                         ylim=ylim)
                p.plot()
                p.save(
                    os.path.join(
                        oDir, "compare_%s_eta_%g_%g_%s.pdf" %
                        (file_identifier, eta_min, eta_max, pu_label)))
                if lowpt_zoom:
                    # zoom in on low pT
                    p = Plot(contributions=[ng[i] for ng in new_graphs_list],
                             what="graph",
                             xtitle="<p_{T}^{L1}>",
                             ytitle="Correction value (= 1/response)",
                             title=title.format(**rename_dict),
                             xlim=zoom_pt,
                             ylim=ylim)
                    p.plot()
                    p.save(
                        os.path.join(
                            oDir, "compare_%s_eta_%g_%g_%s_pTzoomed.pdf" %
                            (file_identifier, eta_min, eta_max, pu_label)))
def make_plot_eta_binned(input_filename, output_filename, title=''):
    f = cu.open_root_file(input_filename)
    tree = cu.get_from_file(f, 'valid')

    hists = []

    eta_bins = binning.eta_bins
    # eta_bins = [0, 3, 5]
    for i, (eta_min, eta_max) in enumerate(binning.pairwise(eta_bins)):
        hname = "h_%g_%g" % (eta_min, eta_max)
        h = ROOT.TH1D(hname, title + " PU15 - 25;response;p.d.f", 30, 0, 3)
        tree.Draw("rsp>>%s" % hname, "%g < TMath::Abs(eta) && TMath::Abs(eta) < %g && numPUVertices<25 && numPUVertices >15" % (eta_min, eta_max))
        h.SetLineColor(binning.eta_bin_colors[i])
        h.SetLineWidth(2)
        h.Scale(1. / h.Integral())
        hists.append(h)

    canv = ROOT.TCanvas("c", "", 600, 600)
    canv.SetTicks(1, 1)
    hstack = ROOT.THStack("hst", title + " PU15 - 25;response;p.d.f")
    leg = ROOT.TLegend(0.6, 0.6, 0.88, 0.88)
    for i, h in enumerate(hists):
        hstack.Add(h)
        leg.AddEntry(h, '%g < |#eta| < %g' % (eta_bins[i], eta_bins[i + 1]), 'L')

    hstack.Draw("NOSTACK HIST")
    leg.Draw()
    canv.SaveAs(output_filename)
def calc_new_corr_mapping(pt_orig, corr_orig, new_pt_mapping):
    """Calculate new corrections using new compressed pT mapping

    Parameters
    ----------

    Returns
    -------
    OrderedDict
        Map of {pt: new correction}
    """
    if len(pt_orig) != len(corr_orig):
        raise IndexError('Different lengths for pt_orig, corr_orig')
    # hold correction mapping
    new_corr_mapping = {p: c for p, c in zip(pt_orig, corr_orig)}
    new_corr_mapping[0] = 0.
    new_corr_mapping = OrderedDict(sorted(new_corr_mapping.items(), key=lambda t: t))

    # Get indices of locations of new pt bins
    compr_pt = list(new_pt_mapping.values())
    unique_pt = sorted(list(set(compr_pt)))  # sets are unordered!
    indices = [compr_pt.index(upt) for upt in unique_pt] + [len(corr_orig)]

    # Need to calculate new mean correction for each pt bin
    for i_low, i_high in pairwise(indices):
        mean_corr = corr_orig[i_low:i_high].mean()
        for j in xrange(i_low, i_high):
            new_corr_mapping[pt_orig[j]] = mean_corr

    return new_corr_mapping
    def compare_scenarios_by_pu_eta_bins(eta_bins, pu_labels, graph_lists, title, oDir, ylim=None, lowpt_zoom=False):
        for eta_min, eta_max in pairwise(eta_bins):
            for pu_ind, pu_label in enumerate(pu_labels):
                pu_graphs = [x[pu_ind] for x in graph_lists]
                # tweak names and colors
                for i, contr in enumerate(pu_graphs):
                    contr.line_color = colors[i]
                    contr.marker_color = colors[i]
                    contr.obj_name = "eta_%g_%g/resRefRef_%g_%g_diff" % (eta_min, eta_max, eta_min, eta_max)

                fmt_dict = dict(eta_min=eta_min, eta_max=eta_max, pu_label=pu_label)
                plt_title = title.format(**fmt_dict)
                p = Plot(contributions=pu_graphs, what='graph', xtitle=pt_ref_str,
                         ytitle=res_ref_str, title=plt_title, ylim=[0, 0.7], xlim=[0, 500])
                p.legend.SetX1(0.4)
                p.plot()
                filename = 'compare_fall15_dummyLayer1_newLayer1_withJEC_eta_%g_%g_%s.pdf' % (eta_min, eta_max, pu_label)
                p.save(os.path.join(oDir, filename))
                if lowpt_zoom:
                    p = Plot(contributions=pu_graphs, what='graph', xtitle=pt_ref_str,
                             ytitle=res_ref_str, title=plt_title, ylim=[0, 0.7], xlim=zoom_pt)
                    p.legend.SetX1(0.4)
                    p.plot()
                    filename = 'compare_fall15_dummyLayer1_newLayer1_withJEC_eta_%g_%g_%s_ptZoomed.pdf' % (eta_min, eta_max, pu_label)
                    p.save(os.path.join(oDir, filename))
def make_comparisons():
    """Do all the comparisons"""

    s2_mc_withJEC = '/hdfs/L1JEC/CMSSW_8_0_2/L1JetEnergyCorrections/Stage2_HF_QCDFall15_16Mar_int-v14_layer1_noL1JEC_jst4_RAWONLY/check/'
    f_PU0to10_check_mc_withJEC = os.path.join(s2_mc_withJEC, 'check_QCDFlatFall15PU0to50NzshcalRaw_MP_ak4_ref10to5000_l10to5000_dr0p4_fall15JEC_PU0to10_maxPt1022.root')
    f_PU15to25_check_mc_withJEC = os.path.join(s2_mc_withJEC, 'check_QCDFlatFall15PU0to50NzshcalRaw_MP_ak4_ref10to5000_l10to5000_dr0p4_fall15JEC_PU15to25_maxPt1022.root')
    mc_PU0to10_label = 'MC QCD Fall15, with L1JEC (PU 0-10)'
    mc_PU0to10_colour = ROOT.kBlue
    mc_PU15to25_label = 'MC QCD Fall15, with L1JEC (PU 15-25)'
    mc_PU15to25_colour = ROOT.kRed

    s2_data_run273301 = '/hdfs/L1JEC/L1JetEnergyCorrections/crab_Collision2016-RECO-l1t-integration-v53p1-CMSSW-807__273301_SingleMuon/check/'
    f_check_data_run273301_SingleMu_clean = os.path.join(s2_data_run273301, 'check_SingleMu_ak4_ref10to5000_l10to5000_dr0p4_cleanTIGHTLEPVETO_maxPt1022.root')
    data_label = 'Data (run 273301, TightLepVeto cleaning)'
    data_color = ROOT.kBlack

    oDir = '/users/ra12451/L1JEC/integration/CMSSW_8_0_7/src/L1Trigger/L1JetEnergyCorrections/crab_Collision2016-RECO-l1t-integration-v53p1-CMSSW-807__273301_SingleMuon/check/data_mc_cleanTightLepVeto'

    for pt_var in ['pt', 'ptRef']:
        filelist_30_40 = []
        filelist_60_80 = []
        filelist_100_300 = []
        for eta_min, eta_max in pairwise(binning.eta_bins):
            filename_list = []
            for pt_bin in binning.check_pt_bins:
                pt_lo, pt_hi = pt_bin
                hist_name = 'eta_0_3/Histograms/hrsp_eta_%g_%g_%s_%d_%d' % (eta_min, eta_max, pt_var, pt_lo, pt_hi)
                hists = [
                    Contribution(file_name=f_check_data_run273301_SingleMu_clean, obj_name=hist_name, label=data_label, line_color=data_color, marker_color=data_color),
                    Contribution(file_name=f_PU0to10_check_mc_withJEC, obj_name=hist_name, label=mc_PU0to10_label, line_color=mc_PU0to10_colour, marker_color=mc_PU0to10_colour),
                    Contribution(file_name=f_PU15to25_check_mc_withJEC, obj_name=hist_name, label=mc_PU15to25_label, line_color=mc_PU15to25_colour, marker_color=mc_PU15to25_colour)
                ]
                pt_str = 'p_{T}^{L1}' if pt_var == 'pt' else 'p_{T}^{Ref}'
                title = 'Data vs MC, %g < #eta^{L1} < %g, %d < %s < %d' % (eta_min, eta_max, pt_lo, pt_str, pt_hi)
                p = Plot(contributions=hists,
                         xtitle="Response (L1/REF)", ytitle="AU",
                         title=title, normalise=True, xlim=[0,4])
                p.legend.SetX1(0.45)
                p.legend.SetY1(0.6)
                if p.plot('HISTE NOSTACK'):
                    filename = 'compare_eta_%g_%g_%s_%d_%d.png' % (eta_min, eta_max, pt_var, pt_lo, pt_hi)
                    p.save(os.path.join(oDir, filename))
                    filename_list.append(filename)
                    if pt_lo == 30:
                        filelist_30_40.append(filename)
                    if pt_lo == 60:
                        filelist_60_80.append(filename)
                    if pt_lo == 100:
                        filelist_100_300.append(filename)

            write_gif_list_file(filename_list, os.path.join(oDir, 'list_eta_%g_%g_%s.txt' % (eta_min, eta_max, pt_var)))

        write_gif_list_file(filelist_30_40, os.path.join(oDir, 'list_%s_30_40.txt' % (pt_var)))
        write_gif_list_file(filelist_60_80, os.path.join(oDir, 'list_%s_60_80.txt' % (pt_var)))
        write_gif_list_file(filelist_100_300, os.path.join(oDir, 'list_%s_100_300.txt' % (pt_var)))
def plot_corr_results(in_name):
    """Puts correction plots from ROOT file in one pdf.

    Parameters
    ----------
    in_name : str
        Name of ROOT file to process (output from runCalibration.py)
    """
    print "Opening", in_name
    in_stem = os.path.basename(in_name).replace(".root", "")
    input_file = cu.open_root_file(in_name)

    # Setup output directory & filenames
    odir = os.path.join(os.path.dirname(os.path.abspath(in_name)), in_stem)
    cu.check_dir_exists_create(odir)

    out_name = os.path.join(odir, in_stem + ".pdf")
    out_stem = out_name.replace(".pdf", "")
    print "Writing to", out_name

    # Start beamer file - make main tex file
    # Use template - change title, subtitle, include file
    frontpage_title = "Correction value plots, binned by $|\eta|$"
    sub = in_stem.replace("output_", "").replace("_", "\_").replace("_ak", r"\\_ak")
    subtitle = "{\\tt " + sub + "}"
    main_file = out_stem + ".tex"
    slides_file = out_stem + "_slides.tex"
    make_main_tex_file(frontpage_title, subtitle, AUTHOR, main_file, slides_file)

    # Now make the slides file to be included in main file
    with open(slides_file, "w") as slides:
        titles = []
        plotnames = []
        etaBins = binning.eta_bins
        for i, (eta_min, eta_max) in enumerate(binning.pairwise(etaBins)):
            plotname = "l1corr_eta_%g_%g" % (eta_min, eta_max)
            bin_title = "%g <  |\eta^{L1}| < %g" % (eta_min, eta_max)
            xtitle = "<p_{T}^{L1}> [GeV]"
            ytitle = "Correction = 1/<p_{T}^{L1}/p_{T}^{Ref}>"
            output_plots = [os.path.join(odir, plotname + ext) for ext in ['.tex', '.pdf']]
            if plot_to_file(input_file, plotname, output_plots,
                            xtitle=xtitle, ytitle=ytitle, title="",
                            drawfit=True, extend_fit=True):
                titles.append("$%s$" % bin_title)
                plotnames.append(os.path.join(odir, plotname + ".tex"))
            # When we have 4 plots, or reached the end, write to a slide
            if (((i + 1) % 4 == 0) and (i != 0)) or (i == len(etaBins) - 2):
                print "Writing slide"
                slidetitle = "Correction value"
                slides.write(bst.make_slide(bst.four_plot_slide, titles, plotnames, slidetitle))
                titles = []
                plotnames = []

    compile_pdf(main_file, out_name, odir, 1)
def plot_corr_results(in_name):
    """Puts correction plots from ROOT file in one pdf.

    Parameters
    ----------
    in_name : str
        Name of ROOT file to process (output from runCalibration.py)
    """
    print "Opening", in_name
    in_stem = os.path.basename(in_name).replace(".root", "")
    input_file = cu.open_root_file(in_name)

    # Setup output directory & filenames
    odir = os.path.join(os.path.dirname(os.path.abspath(in_name)), in_stem)
    cu.check_dir_exists_create(odir)

    out_name = os.path.join(odir, in_stem + ".pdf")
    out_stem = out_name.replace(".pdf", "")
    print "Writing to", out_name

    # Start beamer file - make main tex file
    # Use template - change title, subtitle, include file
    frontpage_title = "Correction value plots, binned by $|\eta|$"
    sub = in_stem.replace("output_", "").replace("_", "\_").replace("_ak", r"\\_ak")
    subtitle = "{\\tt " + sub + "}"
    main_file = out_stem + ".tex"
    slides_file = out_stem + "_slides.tex"
    make_main_tex_file(frontpage_title, subtitle, AUTHOR, main_file, slides_file)

    # Now make the slides file to be included in main file
    with open(slides_file, "w") as slides:
        titles = []
        plotnames = []
        etaBins = binning.eta_bins
        for i, (eta_min, eta_max) in enumerate(binning.pairwise(etaBins)):
            plotname = "l1corr_eta_%g_%g" % (eta_min, eta_max)
            bin_title = "%g <  |\eta^{L1}| < %g" % (eta_min, eta_max)
            xtitle = "<p_{T}^{L1}> [GeV]"
            ytitle = "Correction = 1/<p_{T}^{L1}/p_{T}^{Ref}>"
            output_plots = [os.path.join(odir, plotname + ext) for ext in ['.tex', '.pdf']]
            if plot_to_file(input_file, plotname, output_plots,
                            xtitle=xtitle, ytitle=ytitle, title="",
                            drawfit=True, extend_fit=True):
                titles.append("$%s$" % bin_title)
                plotnames.append(os.path.join(odir, plotname + ".tex"))
            # When we have 4 plots, or reached the end, write to a slide
            if (((i + 1) % 4 == 0) and (i != 0)) or (i == len(etaBins) - 2):
                print "Writing slide"
                slidetitle = "Correction value"
                slides.write(bst.make_slide(bst.four_plot_slide, titles, plotnames, slidetitle))
                titles = []
                plotnames = []

    compile_pdf(main_file, out_name, odir, 1)
    def compare_PU_by_eta_bins(graphs,
                               title,
                               oDir,
                               ylim=None,
                               lowpt_zoom=True):
        """Plot graph contributions, with a different plot for each eta bin.

        Parameters
        ----------
        graphs : list[Contribution]
            List of Contribution objects to be included on any one plot.
        title : str
            Title to put on plots
        oDir : str
            Output directory for plots
        ylim : list, optional
            Set y axis range
        lowpt_zoom : bool, optional
            Zoom in on low pt range
        """
        for i, (eta_min, eta_max) in enumerate(pairwise(binning.eta_bins)):
            rename_dict = dict(eta_min=eta_min, eta_max=eta_max)
            # make a copy as we have to change the graph names
            new_graphs = setup_new_graphs(graphs, rename_dict)

            if not ylim:
                ylim = [0.5, 3.5] if eta_min > 2 else [0.5, 4]
            p = Plot(contributions=new_graphs,
                     what="graph",
                     xtitle="<p_{T}^{L1}>",
                     ytitle="Correction value (= 1/response)",
                     title=title.format(**rename_dict),
                     ylim=ylim)
            p.plot()
            p.save(
                os.path.join(oDir,
                             "compare_PU_eta_%g_%g.pdf" % (eta_min, eta_max)))

            if lowpt_zoom:
                # zoom in on low pT
                p = Plot(contributions=new_graphs,
                         what="graph",
                         xtitle="<p_{T}^{L1}>",
                         ytitle="Correction value (= 1/response)",
                         title=title.format(**rename_dict),
                         xlim=zoom_pt,
                         ylim=ylim)
                p.plot()
                p.save(
                    os.path.join(
                        oDir, "compare_PU_eta_%g_%g_pTzoomed.pdf" %
                        (eta_min, eta_max)))
def process_file(filename, eta_bins=binning.eta_bins_forward):
    """Process a ROOT file with graphs, print a mean & mean histogram for each.

    Parameters
    ----------
    filename : str
        Name of ROOT file to process (from runCalibration.py)
    eta_bins : list[[float, float]]
        Eta bin edges.
    """
    f = cu.open_root_file(filename)

    for eta_min, eta_max in binning.pairwise(eta_bins):
        gr = cu.get_from_file(f, generate_eta_graph_name(eta_min, eta_max))
        if not gr:
            raise RuntimeError("Can't get graph")

        xarr, yarr = cu.get_xy(gr)
        xarr, yarr = np.array(xarr), np.array(
            yarr)  # use numpy array for easy slicing

        # Loop over all possible subgraphs, and calculate a mean for each
        end = len(yarr)
        means = []
        while end > 0:
            start = 0
            while start < end:
                means.append(yarr[start:end].mean())
                start += 1
            end -= 1

        # Jackknife means
        jack_means = [np.delete(yarr, i).mean() for i in range(len(yarr))]

        # Do plotting & peak finding in both ROOT and MPL...not sure which is better?
        # peak = plot_find_peak_mpl(means, eta_min, eta_max, os.path.dirname(os.path.realpath(filename)))
        peak = plot_find_peak_root(means, eta_min, eta_max,
                                   os.path.dirname(os.path.realpath(filename)))
        jackpeak = plot_jacknife_root(
            jack_means, eta_min, eta_max,
            os.path.dirname(os.path.realpath(filename)))
        print 'Eta bin:', eta_min, '-', eta_max
        print peak
        print 'jackknife mean:'
        print np.array(jack_means).mean()

    f.Close()
def compare_eta_by_pu_bins(graphs, pu_labels, title, oDir, ylim=None, lowpt_zoom=True):
    """Compare eta bins for graphs for a given PU bin. Does central, fowrad, and central+forward.

    Parameters
    ----------
    graphs : list[Contribution]
        Contributions corresponding to eta bins (0PU, PU0to10, 15to25, 30to40)
    title : str
        Title to put on plots
    oDir : str
        Output directory for plots
    ylim : list, optional
        Set y axis range
    lowpt_zoom : bool, optional
        Zoom in on low pt range
    """
    cu.check_dir_exists_create(oDir)
    eta_scenarios = [binning.eta_bins_central, binning.eta_bins_forward, binning.eta_bins]
    eta_scenario_labels = ['central', 'forward', 'all']
    for eta_bins, eta_label in izip(eta_scenarios, eta_scenario_labels):
        for pu_ind, pu_label in enumerate(pu_labels):
            new_graphs = []
            rename_dict = dict(pu_label=pu_label)
            for eta_ind, (eta_min, eta_max) in enumerate(pairwise(eta_bins)):
                rename_dict['eta_min'] = eta_min
                rename_dict['eta_max'] = eta_max
                contr = deepcopy(graphs[pu_ind])
                contr.obj_name = graphs[pu_ind].obj_name.format(**rename_dict)
                contr.line_color = colors[eta_ind]
                contr.marker_color = colors[eta_ind]
                contr.label = "%g < |#eta^{L1}| < %g" % (eta_min, eta_max)
                new_graphs.append(contr)
            if not ylim:
                ylim = [0.5, 4]
            p = Plot(contributions=new_graphs, what='graph',
                     xtitle="<p_{T}^{L1}>", ytitle="Correction value (= 1/response)",
                     title=title.format(**rename_dict), ylim=ylim)
            p.plot()
            p.save(os.path.join(oDir, 'compare_%sEta_%s.pdf' % (eta_label, pu_label)))

            if lowpt_zoom:
                p = Plot(contributions=new_graphs, what='graph',
                         xtitle="<p_{T}^{L1}>", ytitle="Correction value (= 1/response)",
                         title=title.format(**rename_dict), xlim=zoom_pt, ylim=ylim)
                p.plot()
                p.save(os.path.join(oDir, 'compare_%sEta_%s_pTzoomed.pdf' % (eta_label, pu_label)))
def compare_by_eta_pu_bins(graphs_list, file_identifier, pu_labels, title, oDir, ylim=None, lowpt_zoom=True):
    """Compare graphs for each (eta, PU) bin.

    Parameters
    ----------
    graphs_list : list[list[Contribution]]
        List of list of contributions, so you can any
        number of sets of contributions on a graph.
    file_identifier : str
        String to be inserted into resultant plot filename.
    title : str
        Title to put on plots
    oDir : str
        Output directory for plots
    ylim : list, optional
        Set y axis range
    lowpt_zoom : bool, optional
        Zoom in on low pt range
    """
    cu.check_dir_exists_create(oDir)
    for (eta_min, eta_max) in pairwise(binning.eta_bins):
        rename_dict = dict(eta_min=eta_min, eta_max=eta_max)
        eta_min_str = '{:g}'.format(eta_min).replace('.', 'p')
        eta_max_str = '{:g}'.format(eta_max).replace('.', 'p')
        new_graphs_list = [setup_new_graphs(g, rename_dict) for g in graphs_list]

        if not ylim:
            ylim = [0.5, 3.5] if eta_min > 2 else [0.5, 4]
        for i, pu_label in enumerate(pu_labels):
            rename_dict['pu_label'] = pu_label
            p = Plot(contributions=[ng[i] for ng in new_graphs_list], what="graph",
                     xtitle="<p_{T}^{L1}>", ytitle="Correction value (= 1/response)",
                     title=title.format(**rename_dict), ylim=ylim)
            p.plot()
            p.legend.SetX1(0.5)
            p.save(os.path.join(oDir, "compare_%s_eta_%s_%s_%s.pdf" % (file_identifier, eta_min_str, eta_max_str, pu_label)))
            if lowpt_zoom:
                # zoom in on low pT
                p = Plot(contributions=[ng[i] for ng in new_graphs_list], what="graph",
                         xtitle="<p_{T}^{L1}>", ytitle="Correction value (= 1/response)",
                         title=title.format(**rename_dict), xlim=zoom_pt, ylim=ylim)
                p.plot()
                p.legend.SetX1(0.5)
                p.save(os.path.join(oDir, "compare_%s_eta_%s_%s_%s_pTzoomed.pdf" % (file_identifier, eta_min_str, eta_max_str, pu_label)))
def process_file(filename, eta_bins=binning.eta_bins_forward):
    """Process a ROOT file with graphs, print a mean & mean histogram for each.

    Parameters
    ----------
    filename : str
        Name of ROOT file to process (from runCalibration.py)
    eta_bins : list[[float, float]]
        Eta bin edges.
    """
    f = cu.open_root_file(filename)

    for eta_min, eta_max in binning.pairwise(eta_bins):
        gr = cu.get_from_file(f, generate_eta_graph_name(eta_min, eta_max))
        if not gr:
            raise RuntimeError("Can't get graph")

        xarr, yarr = cu.get_xy(gr)
        xarr, yarr = np.array(xarr), np.array(yarr)  # use numpy array for easy slicing

        # Loop over all possible subgraphs, and calculate a mean for each
        end = len(yarr)
        means = []
        while end > 0:
            start = 0
            while start < end:
                means.append(yarr[start:end].mean())
                start += 1
            end -= 1

        # Jackknife means
        jack_means = [np.delete(yarr, i).mean() for i in range(len(yarr))]

        # Do plotting & peak finding in both ROOT and MPL...not sure which is better?
        # peak = plot_find_peak_mpl(means, eta_min, eta_max, os.path.dirname(os.path.realpath(filename)))
        peak = plot_find_peak_root(means, eta_min, eta_max, os.path.dirname(os.path.realpath(filename)))
        jackpeak = plot_jacknife_root(jack_means, eta_min, eta_max, os.path.dirname(os.path.realpath(filename)))
        print 'Eta bin:', eta_min, '-', eta_max
        print peak
        print 'jackknife mean:'
        print np.array(jack_means).mean()

    f.Close()
示例#13
0
def compare_PU_by_eta_bins(graphs, title, oDir, ylim=None, lowpt_zoom=True):
    """Plot graph contributions, with a different plot for each eta bin.
    Relies on each Contribution.obj_name in graphs being templated with the
    variables `eta_min` and `eta_max`.
    Parameters
    ----------
    graphs : list[Contribution]
        List of Contribution objects to be included on any one plot.
    title : str
        Title to put on plots
    oDir : str
        Output directory for plots
    ylim : list, optional
        Set y axis range
    lowpt_zoom : bool, optional
        Zoom in on low pt range
    """

    cu.check_dir_exists_create(oDir)
    for i, (eta_min, eta_max) in enumerate(pairwise(binning.eta_bins)):
        rename_dict = dict(eta_min=eta_min, eta_max=eta_max)
        eta_min_str = '{:g}'.format(eta_min).replace('.', 'p')
        eta_max_str = '{:g}'.format(eta_max).replace('.', 'p')

        # make a copy as we have to change the graph names
        new_graphs = setup_new_graphs(graphs, rename_dict)

        if not ylim:
            ylim = [0.5, 2] if eta_min > 2 else [0.5, 2.5]
        p = Plot(contributions=new_graphs, what="graph", xtitle="<p_{T}^{L1}>",
                 ytitle="Correction value (= 1/response)",
                 title=title.format(**rename_dict), ylim=ylim)
        p.plot()
        p.save(os.path.join(oDir, "compare_PU_eta_%s_%s.pdf" % (eta_min_str, eta_max_str)))

        if lowpt_zoom:
            # zoom in on low pT
            p = Plot(contributions=new_graphs, what="graph", xtitle="<p_{T}^{L1}>",
                     ytitle="Correction value (= 1/response)",
                     title=title.format(**rename_dict), xlim=zoom_pt, ylim=ylim)
            p.plot()
            p.save(os.path.join(oDir, "compare_PU_eta_%s_%s_pTzoomed.pdf" % (eta_min_str, eta_max_str)))
def compare_PU_by_eta_bins(graphs, title, oDir, ylim=None, lowpt_zoom=True):
    """Plot graph contributions, with a different plot for each eta bin.
    Relies on each Contribution.obj_name in graphs being templated with the
    variables `eta_min` and `eta_max`.

    Parameters
    ----------
    graphs : list[Contribution]
        List of Contribution objects to be included on any one plot.
    title : str
        Title to put on plots
    oDir : str
        Output directory for plots
    ylim : list, optional
        Set y axis range
    lowpt_zoom : bool, optional
        Zoom in on low pt range
    """
    cu.check_dir_exists_create(oDir)
    for i, (eta_min, eta_max) in enumerate(pairwise(binning.eta_bins)):
        rename_dict = dict(eta_min=eta_min, eta_max=eta_max)
        eta_min_str = '{:g}'.format(eta_min).replace('.', 'p')
        eta_max_str = '{:g}'.format(eta_max).replace('.', 'p')

        # make a copy as we have to change the graph names
        new_graphs = setup_new_graphs(graphs, rename_dict)

        if not ylim:
            ylim = [0.5, 3] if eta_min > 2 else [0.5, 3]
        p = Plot(contributions=new_graphs, what="graph", xtitle="<p_{T}^{L1}>",
                 ytitle="Correction value (= 1/response)",
                 title=title.format(**rename_dict), ylim=ylim)
        p.plot()
        p.save(os.path.join(oDir, "compare_PU_eta_%s_%s.pdf" % (eta_min_str, eta_max_str)))

        if lowpt_zoom:
            # zoom in on low pT
            p = Plot(contributions=new_graphs, what="graph", xtitle="<p_{T}^{L1}>",
                     ytitle="Correction value (= 1/response)",
                     title=title.format(**rename_dict), xlim=zoom_pt, ylim=ylim)
            p.plot()
            p.save(os.path.join(oDir, "compare_PU_eta_%s_%s_pTzoomed.pdf" % (eta_min_str, eta_max_str)))
    def compare_PU_by_eta_bins(graphs, title, oDir, ylim=None, lowpt_zoom=True):
        """Plot graph contributions, with a different plot for each eta bin.

        Parameters
        ----------
        graphs : list[Contribution]
            List of Contribution objects to be included on any one plot.
        title : str
            Title to put on plots
        oDir : str
            Output directory for plots
        ylim : list, optional
            Set y axis range
        lowpt_zoom : bool, optional
            Zoom in on low pt range
        """
        for i, (eta_min, eta_max) in enumerate(pairwise(binning.eta_bins)):
            rename_dict = dict(eta_min=eta_min, eta_max=eta_max)
            # make a copy as we have to change the graph names
            new_graphs = setup_new_graphs(graphs, rename_dict)

            if not ylim:
                ylim = [0.5, 3.5] if eta_min > 2 else [0.5, 4]
            p = Plot(contributions=new_graphs, what="graph", xtitle="<p_{T}^{L1}>",
                     ytitle="Correction value (= 1/response)",
                     title=title.format(**rename_dict), ylim=ylim)
            p.plot()
            p.save(os.path.join(oDir, "compare_PU_eta_%g_%g.pdf" % (eta_min, eta_max)))

            if lowpt_zoom:
                # zoom in on low pT
                p = Plot(contributions=new_graphs, what="graph", xtitle="<p_{T}^{L1}>",
                         ytitle="Correction value (= 1/response)",
                         title=title.format(**rename_dict), xlim=zoom_pt, ylim=ylim)
                p.plot()
                p.save(os.path.join(oDir, "compare_PU_eta_%g_%g_pTzoomed.pdf" % (eta_min, eta_max)))
示例#16
0
def submit_runCalib_dag(pairs_file,
                        log_dir,
                        append,
                        pu_bins,
                        eta_bins,
                        common_input_files,
                        force_submit=False):
    """Submit one runCalibration DAG for one pairs file.

    This will run runCalibration over exclusive and inclusive eta bins,
    and then finally hadd the results together.

    Parameters
    ----------
    pairs_files : str, optional
        Pairs file to process. Must be full path.

    log_dir : str, optional
        Directory for STDOUT/STDERR/LOG files. Should be on /storage.

    append : str, optional
        String to append to filenames to track various settings (e.g. PU bin).

    pu_bins : list[list[int, int]], optional
        List of PU bin edges.

    eta_bins : list[float], optional
        List of eta bin edges, including upper edge of last bin.

    force_submit : bool, optional
        If True, forces job submission even if proposed output files
        already exists.
        Oherwise, program quits before submission.

    """
    cc.check_file_exists(pairs_file)

    # Setup output directory for output* files
    # e.g. if pairs file in DATASET/pairs/pairs.root
    # then output goes in DATASET/output/
    out_dir = os.path.dirname(os.path.dirname(pairs_file))
    out_dir = os.path.join(out_dir, 'output')
    cc.check_create_dir(out_dir, info=True)

    # Stem for output filename
    out_stem = os.path.splitext(os.path.basename(pairs_file))[0]
    out_stem = out_stem.replace("pairs_", "output_")

    # Loop over PU bins
    # ---------------------------------------------------------------------
    pu_bins = pu_bins or [[-99, 999]]  # set ridiculous limits if no cut on PU
    status_files = []
    for (pu_min, pu_max) in pu_bins:
        log.info('**** Doing PU bin %g - %g', pu_min, pu_max)

        log_stem = 'runCalib.$(cluster).$(process)'
        runCalib_jobs = ht.JobSet(exe='python',
                                  copy_exe=False,
                                  filename='submit_runCalib.condor',
                                  setup_script='worker_setup.sh',
                                  share_exe_setup=True,
                                  out_dir=log_dir,
                                  out_file=log_stem + '.out',
                                  err_dir=log_dir,
                                  err_file=log_stem + '.err',
                                  log_dir=log_dir,
                                  log_file=log_stem + '.log',
                                  cpus=1,
                                  memory='100MB',
                                  disk='100MB',
                                  transfer_hdfs_input=False,
                                  common_input_files=common_input_files,
                                  hdfs_store=out_dir)

        # For creating filenames later
        fmt_dict = dict(puMin=pu_min, puMax=pu_max)

        # Hold all output filenames
        calib_output_files = []

        # Add exclusive eta bins to this JobSet
        for ind, (eta_min, eta_max) in enumerate(pairwise(eta_bins)):
            out_file = out_stem + "_%d" % ind + append.format(
                **fmt_dict) + '.root'
            out_file = os.path.join(out_dir, out_file)
            calib_output_files.append(out_file)

            job_args = [
                'runCalibration.py', pairs_file, out_file, "--no-genjet-plots",
                '--stage2', '--no-correction-fit', '--PUmin', pu_min,
                '--PUmax', pu_max, '--etaInd', ind
            ]

            calib_job = ht.Job(name='calib_%d' % ind,
                               args=job_args,
                               input_files=[pairs_file],
                               output_files=[out_file])

            runCalib_jobs.add_job(calib_job)

        # Add hadd jobs
        # ---------------------------------------------------------------------
        log_stem = 'runCalibHadd.$(cluster).$(process)'

        hadd_jobs = ht.JobSet(exe='hadd',
                              copy_exe=False,
                              share_exe_setup=True,
                              filename='haddSmall.condor',
                              setup_script="cmssw_setup.sh",
                              out_dir=log_dir,
                              out_file=log_stem + '.out',
                              err_dir=log_dir,
                              err_file=log_stem + '.err',
                              log_dir=log_dir,
                              log_file=log_stem + '.log',
                              cpus=1,
                              memory='100MB',
                              disk='20MB',
                              transfer_hdfs_input=False,
                              hdfs_store=out_dir)

        # Construct final hadded file name
        final_file = os.path.join(
            out_dir, out_stem + append.format(**fmt_dict) + '.root')
        hadd_output = [final_file]
        hadd_args = hadd_output + calib_output_files

        hadder = ht.Job(name='haddRunCalib',
                        args=hadd_args,
                        input_files=calib_output_files,
                        output_files=hadd_output)

        hadd_jobs.add_job(hadder)

        # Add all jobs to DAG, with necessary dependencies
        # ---------------------------------------------------------------------
        stem = 'runCalib_%s_%s' % (strftime("%H%M%S"), cc.rand_str(3))
        calib_dag = ht.DAGMan(filename=os.path.join(log_dir, '%s.dag' % stem),
                              status_file=os.path.join(log_dir,
                                                       '%s.status' % stem))
        for job in runCalib_jobs:
            calib_dag.add_job(job)

        calib_dag.add_job(hadder, requires=[j for j in runCalib_jobs])

        # Check if any of the output files already exists - maybe we mucked up?
        # ---------------------------------------------------------------------
        if not force_submit:
            for f in [final_file] + calib_output_files:
                if os.path.isfile(f):
                    print 'ERROR: output file already exists - not submitting'
                    print 'FILE:', f
                    return 1

        # calib_dag.write()
        calib_dag.submit()
        status_files.append(calib_dag.status_file)

    print 'For all statuses:'
    print 'DAGstatus.py', ' '.join(status_files)
    return status_files
def main(in_args=sys.argv[1:]):
    parser = argparse.ArgumentParser(description=__doc__, formatter_class=cu.CustomFormatter)
    parser.add_argument("input", help="input ROOT filename")
    parser.add_argument("output", help="output ROOT filename")
    parser.add_argument("--no-genjet-plots", action='store_false',
                        help="Don't do genjet plots for each pt/eta bin")
    parser.add_argument("--no-correction-fit", action='store_false',
                        help="Don't do fits for correction functions")
    parser.add_argument("--redo-correction-fit", action='store_true',
                        help="Redo fits for correction functions")
    parser.add_argument("--inherit-params", action='store_true',
                        help='Use previous eta bins function parameters as starting point. '
                        'Helpful when fits not converging.')
    parser.add_argument("--burr", action='store_true',
                        help='Do Burr type 3 fit for response histograms instead of Gaus')
    parser.add_argument("--gct", action='store_true',
                        help="Load legacy GCT specifics e.g. fit defaults.")
    parser.add_argument("--stage1", action='store_true',
                        help="Load stage 1 specifics e.g. fit defaults.")
    parser.add_argument("--stage2", action='store_true',
                        help="Load stage 2 specifics e.g. fit defaults, pt bins.")
    parser.add_argument("--central", action='store_true',
                        help="Do central eta bins only (eta <= 3)")
    parser.add_argument("--forward", action='store_true',
                        help="Do forward eta bins only (eta >= 3)")
    parser.add_argument("--PUmin", type=float, default=-100,
                        help="Minimum number of PU vertices (refers to *actual* "
                        "number of PU vertices in the event, not the centre "
                        "of of the Poisson distribution)")
    parser.add_argument("--PUmax", type=float, default=1200,
                        help="Maximum number of PU vertices (refers to *actual* "
                        "number of PU vertices in the event, not the centre "
                        "of of the Poisson distribution)")
    parser.add_argument("--etaInd", nargs="+",
                        help="list of eta bin INDICES to run over - "
                        "if unspecified will do all. "
                        "This overrides --central/--forward. "
                        "Handy for batch mode. "
                        "IMPORTANT: MUST PUT AT VERY END")
    args = parser.parse_args(args=in_args)
    print args

    if args.stage2:
        print "Running with Stage2 defaults"
    elif args.stage1:
        print "Running with Stage1 defaults"
    elif args.gct:
        print "Running with GCT defaults"
    else:
        raise RuntimeError("You need to specify defaults: --gct/--stage1/--stage2")

    # Turn off gen plots if you don't want them - they slow things down,
    # and don't affect determination of correction fn
    do_genjet_plots = args.no_genjet_plots
    if not do_genjet_plots:
        print "Not producing genjet plots"

    # Turn off if you don't want to fit to the correction curve
    # e.g. if you're testing your calibrations, since it'll waste time
    do_correction_fit = args.no_correction_fit
    if not do_correction_fit:
        print "Not fitting correction curves"

    if args.burr:
        print 'Using Burr Type3 for response hist fits'

    # Open input & output files, check
    print "IN:", args.input
    print "OUT:", args.output
    if (args.redo_correction_fit and
        os.path.realpath(args.input) == os.path.realpath(args.output)):
        input_file = cu.open_root_file(args.input, "UPDATE")
        output_file = input_file
    else:
        input_file = cu.open_root_file(args.input, "READ")
        output_file = cu.open_root_file(args.output, "RECREATE")

    # Figure out which eta bins the user wants to run over
    etaBins = binning.eta_bins
    if args.etaInd:
        args.etaInd.append(int(args.etaInd[-1]) + 1)  # need upper eta bin edge
        etaBins = [etaBins[int(x)] for x in args.etaInd]
    elif args.central:
        etaBins = [eta for eta in etaBins if eta < 3.1]
    elif args.forward:
        etaBins = [eta for eta in etaBins if eta > 2.9]
    print "Running over eta bins:", etaBins

    # Store last set of fit params if the user is doing --inherit-param
    previous_fit_params = []

    # Do plots & fitting to get calib consts
    for i, (eta_min, eta_max) in enumerate(pairwise(etaBins)):
        print "Doing eta bin: %g - %g" % (eta_min, eta_max)

        # whether we're doing a central or forward bin (.01 is for rounding err)
        forward_bin = eta_max > 3.01

        # setup pt bins, wider ones for forward region
        # ptBins = binning.pt_bins if not forward_bin else binning.pt_bins_wide
        ptBins = binning.pt_bins_stage2 if not forward_bin else binning.pt_bins_stage2_hf

        # Load fit function & starting params - important as wrong starting params
        # can cause fit failures
        default_params = []
        if args.stage2:
            default_params =STAGE2_DEFAULT_PARAMS_SELECT # this is selected around line 90
        elif args.stage1:
            default_params = STAGE1_DEFAULT_PARAMS
        elif args.gct:
            default_params = GCT_DEFAULT_PARAMS

        # Ignore the genric fit defaults and use the last fit params instead
        if args.inherit_params and previous_fit_params != []:
            print "Inheriting params from last fit"
            default_params = previous_fit_params[:]

        fitfunc = central_fit_select # this is selected around line 90
        set_fit_params(fitfunc, default_params)

        # Actually do the graph making and/or fitting!
        if args.redo_correction_fit:
            fit_params = redo_correction_fit(input_file, output_file, eta_min, eta_max, fitfunc)
        else:
            fit_params = make_correction_curves(input_file, output_file, ptBins, eta_min, eta_max,
                                                fitfunc, do_genjet_plots, do_correction_fit,
                                                args.PUmin, args.PUmax, args.burr)
        # Save successful fit params
        if fit_params != []:
            previous_fit_params = fit_params[:]

    input_file.Close()
    output_file.Close()
    return 0
def submit_runCalib_dag(pairs_file, log_dir, append, pu_bins, eta_bins, common_input_files,
                        force_submit=False):
    """Submit one runCalibration DAG for one pairs file.

    This will run runCalibration over exclusive and inclusive eta bins,
    and then finally hadd the results together.

    Parameters
    ----------
    pairs_files : str, optional
        Pairs file to process. Must be full path.

    log_dir : str, optional
        Directory for STDOUT/STDERR/LOG files. Should be on /storage.

    append : str, optional
        String to append to filenames to track various settings (e.g. PU bin).

    pu_bins : list[list[int, int]], optional
        List of PU bin edges.

    eta_bins : list[float], optional
        List of eta bin edges, including upper edge of last bin.

    force_submit : bool, optional
        If True, forces job submission even if proposed output files
        already exists.
        Oherwise, program quits before submission.

    """
    cc.check_file_exists(pairs_file)

    # Setup output directory for output* files
    # e.g. if pairs file in DATASET/pairs/pairs.root
    # then output goes in DATASET/output/
    out_dir = os.path.dirname(os.path.dirname(pairs_file))
    out_dir = os.path.join(out_dir, 'output')
    cc.check_create_dir(out_dir, info=True)

    # Stem for output filename
    out_stem = os.path.splitext(os.path.basename(pairs_file))[0]
    out_stem = out_stem.replace("pairs_", "output_")

    # Loop over PU bins
    # ---------------------------------------------------------------------
    pu_bins = pu_bins or [[-99, 999]]  # set ridiculous limits if no cut on PU
    status_files = []
    for (pu_min, pu_max) in pu_bins:
        log.info('**** Doing PU bin %g - %g', pu_min, pu_max)

        log_stem = 'runCalib.$(cluster).$(process)'
        runCalib_jobs = ht.JobSet(exe='python',
                                  copy_exe=False,
                                  filename=os.path.join(log_dir, 'submit_runCalib.condor'),
                                  setup_script='worker_setup.sh',
                                  share_exe_setup=True,
                                  out_dir=log_dir, out_file=log_stem + '.out',
                                  err_dir=log_dir, err_file=log_stem + '.err',
                                  log_dir=log_dir, log_file=log_stem + '.log',
                                  cpus=1, memory='100MB', disk='100MB',
                                  transfer_hdfs_input=False,
                                  common_input_files=common_input_files,
                                  hdfs_store=out_dir)

        # For creating filenames later
        fmt_dict = dict(puMin=pu_min, puMax=pu_max)

        # Hold all output filenames
        calib_output_files = []

        # Add exclusive eta bins to this JobSet
        for ind, (eta_min, eta_max) in enumerate(pairwise(eta_bins)):
            out_file = out_stem + "_%d" % ind + append.format(**fmt_dict) + '.root'
            out_file = os.path.join(out_dir, out_file)
            calib_output_files.append(out_file)

            job_args = ['runCalibration.py', pairs_file, out_file,
                        "--no-genjet-plots", '--stage2',
                        '--no-correction-fit',
                        '--PUmin', pu_min, '--PUmax', pu_max,
                        '--etaInd', ind]

            calib_job = ht.Job(name='calib_%d' % ind,
                               args=job_args,
                               input_files=[pairs_file],
                               output_files=[out_file])

            runCalib_jobs.add_job(calib_job)

        # Add hadd jobs
        # ---------------------------------------------------------------------
        log_stem = 'runCalibHadd.$(cluster).$(process)'

        hadd_jobs = ht.JobSet(exe='hadd',
                              copy_exe=False,
                              share_exe_setup=True,
                              filename=os.path.join(log_dir, 'haddSmall.condor'),
                              setup_script="cmssw_setup.sh",
                              out_dir=log_dir, out_file=log_stem + '.out',
                              err_dir=log_dir, err_file=log_stem + '.err',
                              log_dir=log_dir, log_file=log_stem + '.log',
                              cpus=1, memory='100MB', disk='20MB',
                              transfer_hdfs_input=False,
                              hdfs_store=out_dir)

        # Construct final hadded file name
        final_file = os.path.join(out_dir, out_stem + append.format(**fmt_dict) + '.root')
        hadd_output = [final_file]
        hadd_args = hadd_output + calib_output_files

        hadder = ht.Job(name='haddRunCalib',
                        args=hadd_args,
                        input_files=calib_output_files,
                        output_files=hadd_output)

        hadd_jobs.add_job(hadder)

        # Add all jobs to DAG, with necessary dependencies
        # ---------------------------------------------------------------------
        stem = 'runCalib_%s_%s' % (strftime("%H%M%S"), cc.rand_str(3))
        calib_dag = ht.DAGMan(filename=os.path.join(log_dir, '%s.dag' % stem),
                              status_file=os.path.join(log_dir, '%s.status' % stem))
        for job in runCalib_jobs:
            calib_dag.add_job(job)

        calib_dag.add_job(hadder, requires=[j for j in runCalib_jobs])

        # Check if any of the output files already exists - maybe we mucked up?
        # ---------------------------------------------------------------------
        if not force_submit:
            for f in [final_file] + calib_output_files:
                if os.path.isfile(f):
                    raise RuntimeError('Output file already exists - not submitting.'
                   '\nTo bypass, use -f flag. \nFILE: %s' % f)

        # calib_dag.write()
        calib_dag.submit()
        status_files.append(calib_dag.status_file)

    print 'For all statuses:'
    print 'DAGstatus.py', ' '.join(status_files)
    return status_files
示例#19
0
def main(in_args=sys.argv[1:]):
    print in_args
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("input", help="input ROOT filename")
    parser.add_argument("output", help="output ROOT filename")
    parser.add_argument("--incl",
                        action="store_true",
                        help="Do inclusive eta plots")
    parser.add_argument("--excl",
                        action="store_true",
                        help="Do exclusive eta plots")
    parser.add_argument("--central",
                        action='store_true',
                        help="Do central eta bins only (eta <= 3)")
    parser.add_argument("--forward",
                        action='store_true',
                        help="Do forward eta bins only (eta >= 3)")
    parser.add_argument("--etaInd", nargs="+",
                        help="list of eta bin INDICES to run over - " \
                        "if unspecified will do all. " \
                        "This overrides --central/--forward. " \
                        "Handy for batch mode. " \
                        "IMPORTANT: MUST PUT AT VERY END")
    args = parser.parse_args(args=in_args)

    inputf = ROOT.TFile(args.input, "READ")
    outputf = ROOT.TFile(args.output, "RECREATE")
    print "Reading from", args.input
    print "Writing to", args.output

    if not inputf or not outputf:
        raise Exception("Couldn't open input or output files")

    # Setup eta bins
    etaBins = binning.eta_bins[:]
    if args.etaInd:
        args.etaInd.append(int(args.etaInd[-1]) + 1)  # need upper eta bin edge
        # check eta bins are ok
        etaBins = [etaBins[int(x)] for x in args.etaInd]
    elif args.central:
        etaBins = binning.eta_bins_central
    elif args.forward:
        etaBins = binning.eta_bins_forward
    print "Running over eta bins:", etaBins

    # Do plots for individual eta bins
    if args.excl:
        print "Doing individual eta bins"
        for i, (eta_min, eta_max) in enumerate(pairwise(etaBins)):

            # whether we're doing a central or forward bin (.1 is for rounding err)
            forward_bin = eta_max > 3.1

            # setup pt bins, wider ones for forward region
            # ptBins = binning.pt_bins_8 if not forward_bin else binning.pt_bins_8_wide
            ptBins = binning.pt_bins if not forward_bin else binning.pt_bins_wide

            plot_resolution(inputf, outputf, ptBins[4:], eta_min, eta_max)

    # Do plots for inclusive eta
    # Skip if doing exlcusive and only 2 bins, or if only 1 bin
    if args.incl and ((not args.excl and len(etaBins) >= 2) or
                      (args.excl and len(etaBins) > 2)):
        print "Doing inclusive eta"
        # ptBins = binning.pt_bins if not etaBins[0] > 2.9 else binning.pt_bins_wide
        plot_resolution(inputf, outputf, binning.pt_bins[4:], etaBins[0],
                        etaBins[-1])

    if not args.incl and not args.excl:
        print "Not doing inclusive or exclusive - you must specify at least one!"
        return 1

    inputf.Close()
    outputf.Close()
    return 0
def main(in_args=sys.argv[1:]):
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("input", help="input ROOT filename")
    parser.add_argument("output", help="output ROOT filename")
    parser.add_argument("--no-genjet-plots",
                        action='store_false',
                        help="Don't do genjet plots for each pt/eta bin")
    parser.add_argument("--no-correction-fit",
                        action='store_false',
                        help="Don't do fits for correction functions")
    parser.add_argument("--redo-correction-fit",
                        action='store_true',
                        help="Redo fits for correction functions")
    parser.add_argument(
        "--inherit-params",
        action='store_true',
        help='Use previous eta bins function parameters as starting point. '
        'Helpful when fits not converging.')
    parser.add_argument(
        "--burr",
        action='store_true',
        help='Do Burr type 3 fit for response histograms instead of Gaus')
    parser.add_argument("--gct",
                        action='store_true',
                        help="Load legacy GCT specifics e.g. fit defaults.")
    parser.add_argument("--stage1",
                        action='store_true',
                        help="Load stage 1 specifics e.g. fit defaults.")
    parser.add_argument(
        "--stage2",
        action='store_true',
        help="Load stage 2 specifics e.g. fit defaults, pt bins.")
    parser.add_argument("--central",
                        action='store_true',
                        help="Do central eta bins only (eta <= 3)")
    parser.add_argument("--forward",
                        action='store_true',
                        help="Do forward eta bins only (eta >= 3)")
    parser.add_argument(
        "--PUmin",
        type=float,
        default=-100,
        help="Minimum number of PU vertices (refers to *actual* "
        "number of PU vertices in the event, not the centre "
        "of of the Poisson distribution)")
    parser.add_argument(
        "--PUmax",
        type=float,
        default=1200,
        help="Maximum number of PU vertices (refers to *actual* "
        "number of PU vertices in the event, not the centre "
        "of of the Poisson distribution)")
    parser.add_argument("--etaInd",
                        nargs="+",
                        help="list of eta bin INDICES to run over - "
                        "if unspecified will do all. "
                        "This overrides --central/--forward. "
                        "Handy for batch mode. "
                        "IMPORTANT: MUST PUT AT VERY END")
    args = parser.parse_args(args=in_args)
    print args

    if args.stage2:
        print "Running with Stage2 defaults"
    elif args.stage1:
        print "Running with Stage1 defaults"
    elif args.gct:
        print "Running with GCT defaults"
    else:
        raise RuntimeError(
            "You need to specify defaults: --gct/--stage1/--stage2")

    # Turn off gen plots if you don't want them - they slow things down,
    # and don't affect determination of correction fn
    do_genjet_plots = args.no_genjet_plots
    if not do_genjet_plots:
        print "Not producing genjet plots"

    # Turn off if you don't want to fit to the correction curve
    # e.g. if you're testing your calibrations, since it'll waste time
    do_correction_fit = args.no_correction_fit
    if not do_correction_fit:
        print "Not fitting correction curves"

    if args.burr:
        print 'Using Burr Type3 for response hist fits'

    # Open input & output files, check
    print "IN:", args.input
    print "OUT:", args.output
    if (args.redo_correction_fit
            and os.path.realpath(args.input) == os.path.realpath(args.output)):
        input_file = cu.open_root_file(args.input, "UPDATE")
        output_file = input_file
    else:
        input_file = cu.open_root_file(args.input, "READ")
        output_file = cu.open_root_file(args.output, "RECREATE")

    # Figure out which eta bins the user wants to run over
    etaBins = binning.eta_bins
    if args.etaInd:
        args.etaInd.append(int(args.etaInd[-1]) + 1)  # need upper eta bin edge
        etaBins = [etaBins[int(x)] for x in args.etaInd]
    elif args.central:
        etaBins = [eta for eta in etaBins if eta < 3.1]
    elif args.forward:
        etaBins = [eta for eta in etaBins if eta > 2.9]
    print "Running over eta bins:", etaBins

    # Store last set of fit params if the user is doing --inherit-param
    previous_fit_params = []

    # Do plots & fitting to get calib consts
    for i, (eta_min, eta_max) in enumerate(pairwise(etaBins)):
        print "Doing eta bin: %g - %g" % (eta_min, eta_max)

        # whether we're doing a central or forward bin (.01 is for rounding err)
        forward_bin = eta_max > 3.01

        # setup pt bins, wider ones for forward region
        # ptBins = binning.pt_bins if not forward_bin else binning.pt_bins_wide
        ptBins = binning.pt_bins_stage2 if not forward_bin else binning.pt_bins_stage2_hf

        # Load fit function & starting params - important as wrong starting params
        # can cause fit failures
        default_params = []
        if args.stage2:
            default_params = STAGE2_DEFAULT_PARAMS_SELECT  # this is selected around line 90
        elif args.stage1:
            default_params = STAGE1_DEFAULT_PARAMS
        elif args.gct:
            default_params = GCT_DEFAULT_PARAMS

        # Ignore the genric fit defaults and use the last fit params instead
        if args.inherit_params and previous_fit_params != []:
            print "Inheriting params from last fit"
            default_params = previous_fit_params[:]

        fitfunc = central_fit_select  # this is selected around line 90
        set_fit_params(fitfunc, default_params)

        # Actually do the graph making and/or fitting!
        if args.redo_correction_fit:
            fit_params = redo_correction_fit(input_file, output_file, eta_min,
                                             eta_max, fitfunc)
        else:
            fit_params = make_correction_curves(input_file, output_file,
                                                ptBins, eta_min, eta_max,
                                                fitfunc, do_genjet_plots,
                                                do_correction_fit, args.PUmin,
                                                args.PUmax, args.burr)
        # Save successful fit params
        if fit_params != []:
            previous_fit_params = fit_params[:]

    input_file.Close()
    output_file.Close()
    return 0
def main(in_args=sys.argv[1:]):
    print in_args
    parser = argparse.ArgumentParser(description=__doc__, formatter_class=cu.CustomFormatter)
    parser.add_argument("input", help="input ROOT filename")
    parser.add_argument("output", help="output ROOT filename")
    parser.add_argument("--incl", action="store_true", help="Do inclusive eta plots")
    parser.add_argument("--excl", action="store_true", help="Do exclusive eta plots")
    parser.add_argument("--central", action='store_true',
                        help="Do central eta bins only (eta <= 3)")
    parser.add_argument("--forward", action='store_true',
                        help="Do forward eta bins only (eta >= 3)")
    parser.add_argument("--etaInd", nargs="+",
                        help="list of eta bin INDICES to run over - "
                        "if unspecified will do all. "
                        "This overrides --central/--forward. "
                        "Handy for batch mode. "
                        "IMPORTANT: MUST PUT AT VERY END")
    parser.add_argument("--maxPt", default=500, type=float,
                        help="Maximum pT for L1 Jets")
    parser.add_argument("--PUmin", default=-99, type=float,
                        help="Minimum number of PU vertices (refers to *actual* "
                             "number of PU vertices in the event, not the centre "
                             "of of the distribution)")
    parser.add_argument("--PUmax", default=999, type=float,
                        help="Maximum number of PU vertices (refers to *actual* "
                             "number of PU vertices in the event, not the centre "
                             "of of the distribution)")
    args = parser.parse_args(args=in_args)

    inputf = cu.open_root_file(args.input, "READ")
    outputf = cu.open_root_file(args.output, "RECREATE")
    print "Reading from", args.input
    print "Writing to", args.output

    if not inputf or not outputf:
        raise Exception("Couldn't open input or output files")

    # Setup eta bins
    etaBins = binning.eta_bins[:]
    if args.etaInd:
        args.etaInd.append(int(args.etaInd[-1])+1) # need upper eta bin edge
        # check eta bins are ok
        etaBins = [etaBins[int(x)] for x in args.etaInd]
    elif args.central:
        etaBins = binning.eta_bins_central
    elif args.forward:
        etaBins = binning.eta_bins_forward
    print "Running over eta bins:", etaBins

    # Do plots for individual eta bins
    if args.excl:
        print "Doing individual eta bins"
        for i, (eta_min, eta_max) in enumerate(pairwise(etaBins)):

            # whether we're doing a central or forward bin (.1 is for rounding err)
            forward_bin = eta_max > 3.1

            # setup pt bins, wider ones for forward region
            ptBins = binning.pt_bins_stage2_8 if not forward_bin else binning.pt_bins_stage2_8_wide
            # ptBins = binning.pt_bins_stage2 if not forward_bin else binning.pt_bins_stage2_hf

            plot_resolution(inputf, outputf, ptBins, eta_min, eta_max, args.maxPt, args.PUmin, args.PUmax)

    # Do plots for inclusive eta
    # Skip if doing exlcusive and only 2 bins, or if only 1 bin
    if args.incl and ((not args.excl and len(etaBins) >= 2) or (args.excl and len(etaBins)>2)):
        print "Doing inclusive eta"
        # ptBins = binning.pt_bins_stage2_hf if etaBins[0] > 2.9 else binning.pt_bins_stage2
        ptBins = binning.pt_bins_stage2_8_wide if etaBins[0] > 2.9 else binning.pt_bins_stage2_8
        plot_resolution(inputf, outputf, ptBins, etaBins[0], etaBins[-1], args.maxPt, args.PUmin, args.PUmax)

    if not args.incl and not args.excl:
        print "Not doing inclusive or exclusive - you must specify at least one!"
        return 1

    inputf.Close()
    outputf.Close()
    return 0
def main(in_args=sys.argv[1:]):
    print in_args
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("input", help="input ROOT filename")
    parser.add_argument("output", help="output ROOT filename")
    parser.add_argument("--incl", action="store_true", help="Do inclusive eta plots")
    parser.add_argument("--excl", action="store_true", help="Do exclusive eta plots")
    parser.add_argument("--central", action='store_true',
                        help="Do central eta bins only (eta <= 3)")
    parser.add_argument("--forward", action='store_true',
                        help="Do forward eta bins only (eta >= 3)")
    parser.add_argument("--etaInd", nargs="+",
                        help="list of eta bin INDICES to run over - " \
                        "if unspecified will do all. " \
                        "This overrides --central/--forward. " \
                        "Handy for batch mode. " \
                        "IMPORTANT: MUST PUT AT VERY END")
    args = parser.parse_args(args=in_args)

    inputf = ROOT.TFile(args.input, "READ")
    outputf = ROOT.TFile(args.output, "RECREATE")
    print "Reading from", args.input
    print "Writing to", args.output

    if not inputf or not outputf:
        raise Exception("Couldn't open input or output files")

    # Setup eta bins
    etaBins = binning.eta_bins[:]
    if args.etaInd:
        args.etaInd.append(int(args.etaInd[-1])+1) # need upper eta bin edge
        # check eta bins are ok
        etaBins = [etaBins[int(x)] for x in args.etaInd]
    elif args.central:
        etaBins = binning.eta_bins_central
    elif args.forward:
        etaBins = binning.eta_bins_forward
    print "Running over eta bins:", etaBins

    # Do plots for individual eta bins
    if args.excl:
        print "Doing individual eta bins"
        for i, (eta_min, eta_max) in enumerate(pairwise(etaBins)):

            # whether we're doing a central or forward bin (.1 is for rounding err)
            forward_bin = eta_max > 3.1

            # setup pt bins, wider ones for forward region
            # ptBins = binning.pt_bins_8 if not forward_bin else binning.pt_bins_8_wide
            ptBins = binning.pt_bins if not forward_bin else binning.pt_bins_wide

            plot_resolution(inputf, outputf, ptBins[4:], eta_min, eta_max)

    # Do plots for inclusive eta
    # Skip if doing exlcusive and only 2 bins, or if only 1 bin
    if args.incl and ((not args.excl and len(etaBins) >= 2) or (args.excl and len(etaBins)>2)):
        print "Doing inclusive eta"
        # ptBins = binning.pt_bins if not etaBins[0] > 2.9 else binning.pt_bins_wide
        plot_resolution(inputf, outputf, binning.pt_bins[4:], etaBins[0], etaBins[-1])

    if not args.incl and not args.excl:
        print "Not doing inclusive or exclusive - you must specify at least one!"
        return 1

    inputf.Close()
    outputf.Close()
    return 0
def submit_resolution_dag(pairs_file,
                          max_l1_pt,
                          log_dir,
                          append,
                          pu_bins,
                          eta_bins,
                          common_input_files,
                          force_submit=False):
    """Submit one makeResolutionPlots DAG for one pairs file.

    This will run makeResolutionPlots over exclusive and inclusive eta bins,
    and then finally hadd the results together.

    Parameters
    ----------
    pairs_files : str, optional
        Pairs file to process. Must be full path.

    max_l1_pt : int, optional
        Maximum L1 pt to consider when making plots.

    log_dir : str, optional
        Directory for STDOUT/STDERR/LOG files. Should be on /storage.

    append : str, optional
        String to append to filenames to track various settings (e.g. PU bin).

    pu_bins : list[list[int, int]], optional
        List of PU bin edges.

    eta_bins : list[float], optional
        List of eta bin edges, including upper edge of last bin.

    force_submit : bool, optional
        If True, forces job submission even if proposed output files
        already exists.
        Oherwise, program quits before submission.

    """
    cc.check_file_exists(pairs_file)

    # Setup output directory for res* files
    # e.g. if pairs file in DATASET/pairs/pairs.root
    # then output goes in DATASET/resolution/
    out_dir = os.path.dirname(os.path.dirname(pairs_file))
    out_dir = os.path.join(out_dir, 'resolution')
    cc.check_create_dir(out_dir, info=True)

    # Stem for output filename
    out_stem = os.path.splitext(os.path.basename(pairs_file))[0]
    out_stem = out_stem.replace("pairs_", "res_")

    # Loop over PU bins
    # ---------------------------------------------------------------------
    pu_bins = pu_bins or [[-99, 999]]  # set ridiculous limits if no cut on PU
    status_files = []
    for (pu_min, pu_max) in pu_bins:

        log_stem = 'res.$(cluster).$(process)'
        res_jobs = ht.JobSet(exe='python',
                             copy_exe=False,
                             filename='submit_resolution.condor',
                             setup_script='worker_setup.sh',
                             share_exe_setup=True,
                             out_dir=log_dir,
                             out_file=log_stem + '.out',
                             err_dir=log_dir,
                             err_file=log_stem + '.err',
                             log_dir=log_dir,
                             log_file=log_stem + '.log',
                             cpus=1,
                             memory='100MB',
                             disk='100MB',
                             transfer_hdfs_input=False,
                             common_input_files=common_input_files,
                             hdfs_store=out_dir)

        # For creating filenames later
        fmt_dict = dict(puMin=pu_min, puMax=pu_max, maxL1Pt=max_l1_pt)

        # Hold all output filenames
        res_output_files = []

        # Add exclusive eta bins to this JobSet
        for ind, (eta_min, eta_max) in enumerate(pairwise(eta_bins)):
            out_file = out_stem + "_%d" % ind + append.format(
                **fmt_dict) + '.root'
            out_file = os.path.join(out_dir, out_file)
            res_output_files.append(out_file)

            job_args = [
                'makeResolutionPlots.py',
                pairs_file,
                out_file,
                '--excl',  #'--maxPt', max_l1_pt,
                #'--PUmin', pu_min, '--PUmax', pu_max,
                '--etaInd',
                ind
            ]

            res_job = ht.Job(name='res_%d' % ind,
                             args=job_args,
                             input_files=[pairs_file],
                             output_files=[out_file])

            res_jobs.add_job(res_job)

        # Add inclusive bins (central, forward, all)
        # remove the [0:1] to do all - currently central only 'cos HF broke
        for incl in ['central', 'forward', 'all'][0:1]:
            out_file = out_stem + "_%s" % incl + append.format(
                **fmt_dict) + '.root'
            out_file = os.path.join(out_dir, out_file)
            res_output_files.append(out_file)

            job_args = [
                'makeResolutionPlots.py', pairs_file, out_file, '--incl'
            ]  #, '--maxPt', max_l1_pt,
            # '--PUmin', pu_min, '--PUmax', pu_max]
            if incl != 'all':
                job_args.append('--%s' % incl)

            res_job = ht.Job(name='res_%s' % incl,
                             args=job_args,
                             input_files=[pairs_file],
                             output_files=[out_file])

            res_jobs.add_job(res_job)

        # Add hadd jobs
        # ---------------------------------------------------------------------
        log_stem = 'resHadd.$(cluster).$(process)'

        hadd_jobs = ht.JobSet(exe='hadd',
                              copy_exe=False,
                              filename='haddSmall.condor',
                              setup_script="cmssw_setup.sh",
                              share_exe_setup=True,
                              out_dir=log_dir,
                              out_file=log_stem + '.out',
                              err_dir=log_dir,
                              err_file=log_stem + '.err',
                              log_dir=log_dir,
                              log_file=log_stem + '.log',
                              cpus=1,
                              memory='100MB',
                              disk='20MB',
                              transfer_hdfs_input=False,
                              hdfs_store=out_dir)

        # Construct final hadded file name
        final_file = os.path.join(
            out_dir, out_stem + append.format(**fmt_dict) + '.root')
        hadd_output = [final_file]
        hadd_args = hadd_output + res_output_files

        hadder = ht.Job(name='haddRes',
                        args=hadd_args,
                        input_files=res_output_files,
                        output_files=hadd_output)

        hadd_jobs.add_job(hadder)

        # Add all jobs to DAG, with necessary dependencies
        # ---------------------------------------------------------------------
        stem = 'res_%s_%s' % (strftime("%H%M%S"), cc.rand_str(3))
        res_dag = ht.DAGMan(filename='%s.dag' % stem,
                            status_file='%s.status' % stem)
        for job in res_jobs:
            res_dag.add_job(job)

        res_dag.add_job(hadder, requires=[j for j in res_jobs])

        # Check if any of the output files already exists - maybe we mucked up?
        # ---------------------------------------------------------------------
        if not force_submit:
            for f in [final_file] + res_output_files:
                if os.path.isfile(f):
                    print 'ERROR: output file already exists - not submitting'
                    print 'FILE:', f
                    return 1

        # res_dag.write()
        res_dag.submit()
        status_files.append(res_dag.status_file)

    print 'For all statuses:'
    print 'DAGstatus.py', ' '.join(status_files)
def main(in_args=sys.argv[1:]):
    print in_args
    parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("--pairs",
                        help="input ROOT file with matched pairs from RunMatcher")

    parser.add_argument("--res",
                        help="input ROOT file with resolution plots from makeResolutionPlots.py")

    parser.add_argument("--checkcal",
                        help="input ROOT file with calibration check plots from checkCalibration.py")

    parser.add_argument("--calib",
                        help="input ROOT file from output of runCalibration.py")

    parser.add_argument("--oDir",
                        help="Directory to save plots. Default is in same location as ROOT file.")
    parser.add_argument("--detail",
                        help="Plot all the individual component hists for each eta bin. There are a lot!",
                        action='store_true')
    parser.add_argument("--format",
                        help="Format for plots (PDF, png, etc). Note that 2D correlation plots will "
                             "always be PNGs to avoid large files.",
                        default="pdf")
    parser.add_argument("--title",
                        help="Title for plots.")
    parser.add_argument('--zip',
                        help="Zip filename for zipping up all plots. Don't include extension")

    # FIXME
    # parser.add_argument("--etaInd",
                        # help="list of eta bin index/indices to run over")
    parser.add_argument("--gifs",
                        help="Make GIFs (only applicable if --detail is also used)",
                        action='store_true')
    parser.add_argument("--gifexe",
                        help='Convert executable to use. Default is result of `which convert`')
    args = parser.parse_args(args=in_args)

    print args

    if args.detail:
        print "Warning: producing all component hists. This could take a while..."

    if args.gifs:
        if args.detail:
            print "Making animated graphs from fit plots."
        else:
            print "To use the --gifs flag, you also need --detail"

    if not args.gifexe:
        args.gifexe = find_executable('convert')
        if not args.gifexe:
            print 'Cannot find convert exe, not making gifs'
            args.gif = False
        else:
            print 'Using %s to make GIFs' % args.gifexe

    # customise titles
    # note the use of global keyword
    if args.title:
        global plot_title
        plot_title = args.title

    if args.oDir == os.getcwd():
        print "Warning: plots will be made in $PWD!"

    # auto determine output directory
    if not args.oDir:
        filename, stem = '', ''
        if args.pairs:
            filename, stem = args.pairs, 'pairs_'
        elif args.checkcal:
            filename, stem = args.checkcal, 'check_'
        elif args.res:
            filename, stem = args.res, 'res_'
        elif args.calib:
            filename, stem = args.calib, 'output_'
        new_dir = os.path.basename(filename).replace(".root", '').replace(stem, 'showoff_')

        args.oDir = os.path.join(os.path.dirname(os.path.abspath(filename)), new_dir)

    cu.check_dir_exists_create(args.oDir)
    print "Output directory:", args.oDir


    # Choose eta
    ptBins = binning.pt_bins_stage2

    # Do plots with output from RunMatcher
    # ------------------------------------------------------------------------
    if args.pairs:
        pairs_file = cu.open_root_file(args.pairs)
        pairs_tree = cu.get_from_file(pairs_file, "valid")

        # eta binned
        for emin, emax in pairwise(binning.eta_bins):
            plot_dR(pairs_tree, eta_min=emin, eta_max=emax, cut="1", oDir=args.oDir)
            plot_pt_both(pairs_tree, eta_min=emin, eta_max=emax, cut="1", oDir=args.oDir)

        # plot_dR(pairs_tree, eta_min=0, eta_max=5, cut="1", oDir=args.oDir)  # all eta
        # plot_pt_both(pairs_tree, eta_min=0, eta_max=5, cut="1", oDir=args.oDir)  # all eta
        plot_eta_both(pairs_tree, oDir=args.oDir)  # all eta

        plot_dR(pairs_tree, eta_min=0, eta_max=3, cut="1", oDir=args.oDir)  # central
        plot_pt_both(pairs_tree, eta_min=0, eta_max=3, cut="1", oDir=args.oDir)  # central

        plot_dR(pairs_tree, eta_min=3, eta_max=5, cut="1", oDir=args.oDir)  # forward
        plot_pt_both(pairs_tree, eta_min=3, eta_max=5, cut="1", oDir=args.oDir)  # forward

        pairs_file.Close()

    # Do plots with output from makeResolutionPlots.py
    # ------------------------------------------------------------------------
    if args.res:
        res_file = cu.open_root_file(args.res)

        # exclusive eta graphs
        for eta_min, eta_max in pairwise(binning.eta_bins):
            print eta_min, eta_max

            plot_res_all_pt(res_file, eta_min, eta_max, args.oDir, args.format)

            if args.detail:
                list_dir = os.path.join(args.oDir, 'eta_%g_%g' % (eta_min, eta_max))
                cu.check_dir_exists_create(list_dir)

                pt_diff_filenames = []

                ptBins = binning.pt_bins_stage2_8 if eta_min < 2.9 else binning.pt_bins_stage2_8_wide
                for pt_min, pt_max in pairwise(ptBins):
                    pt_diff_fname = plot_pt_diff(res_file, eta_min, eta_max, pt_min, pt_max, args.oDir, 'png')
                    pt_diff_filenames.append(pt_diff_fname)

                pt_diff_filenames_file = os.path.join(list_dir, 'list_pt_diff.txt')
                write_filelist(pt_diff_filenames, pt_diff_filenames_file)

                if args.gifs:
                    make_gif(pt_diff_filenames_file, pt_diff_filenames_file.replace('.txt', '.gif'), args.gifexe)

        # inclusive eta graphs
        for (eta_min, eta_max) in [[0, 3], [3, 5]]:
            print eta_min, eta_max
            plot_res_all_pt(res_file, eta_min, eta_max, args.oDir, args.format)
            plot_ptDiff_Vs_pt(res_file, eta_min, eta_max, args.oDir, args.format)

            if args.detail:
                list_dir = os.path.join(args.oDir, 'eta_%g_%g' % (eta_min, eta_max))
                cu.check_dir_exists_create(list_dir)

                pt_diff_filenames = []

                ptBins = binning.pt_bins_stage2_8 if eta_min < 2.9 else binning.pt_bins_stage2_8_wide
                for pt_min, pt_max in pairwise(ptBins):
                    pt_diff_fname = plot_pt_diff(res_file, eta_min, eta_max, pt_min, pt_max, args.oDir, 'png')
                    pt_diff_filenames.append(pt_diff_fname)

                pt_diff_filenames_file = os.path.join(list_dir, 'list_pt_diff.txt')
                write_filelist(pt_diff_filenames, pt_diff_filenames_file)

                if args.gifs:
                    make_gif(pt_diff_filenames_file, pt_diff_filenames_file.replace('.txt', '.gif'), args.gifexe)

        # plot_eta_pt_rsp_2d(res_file, binning.eta_bins, binning.pt_bins[4:], args.oDir, args.format)

        # components of these:
        # if args.detail:
        #     ptBins = binning.pt_bins_stage2_8 if not forward_bin else binning.pt_bins_stage2_8_wide
        #     for pt_min, pt_max in pairwise(ptBins):
        #         plot_pt_diff(res_file, 0, 3, pt_min, pt_max, args.oDir, args.format)
                # plot_pt_diff(res_file, 0, 5, pt_min, pt_max, args.oDir, args.format)
                # plot_pt_diff(res_file, 3, 5, pt_min, pt_max, args.oDir, args.format)

        res_file.Close()

    # Do plots with output from checkCalibration.py
    # ------------------------------------------------------------------------
    if args.checkcal:

        etaBins = binning.eta_bins
        check_file = cu.open_root_file(args.checkcal)

        # ptBinsWide = list(np.arange(10, 250, 8))

        # indiviudal eta bins
        for eta_min, eta_max in pairwise(etaBins):
            for (normX, logZ) in product([True, False], [True, False]):
                plot_l1_Vs_ref(check_file, eta_min, eta_max, logZ, args.oDir, 'png')
                plot_rsp_Vs_l1(check_file, eta_min, eta_max, normX, logZ, args.oDir, 'png')
                plot_rsp_Vs_ref(check_file, eta_min, eta_max, normX, logZ, args.oDir, 'png')
                plot_rsp_Vs_pt_candle_violin(check_file, eta_min, eta_max, "l1", args.oDir, 'png')
                plot_rsp_Vs_pt_candle_violin(check_file, eta_min, eta_max, "gen", args.oDir, 'png')

            if args.detail:
                list_dir = os.path.join(args.oDir, 'eta_%g_%g' % (eta_min, eta_max))
                cu.check_dir_exists_create(list_dir)

                # print individual histograms, and make a list suitable for imagemagick to turn into a GIF
                pt_plot_filenames = plot_rsp_pt_hists(check_file, eta_min, eta_max, ptBins, "pt", args.oDir, 'png')
                pt_plot_filenames_file = os.path.join(list_dir, 'list_pt.txt')
                write_filelist(pt_plot_filenames, pt_plot_filenames_file)

                # print individual histograms, and make a list suitable for imagemagick to turn into a GIF
                ptRef_plot_filenames = plot_rsp_pt_hists(check_file, eta_min, eta_max, ptBins, "ptRef", args.oDir, 'png')
                ptRef_plot_filenames_file = os.path.join(list_dir, 'list_ptRef.txt')
                write_filelist(ptRef_plot_filenames, ptRef_plot_filenames_file)

                # make dem GIFs
                if args.gifs:
                    for inf in [pt_plot_filenames_file, ptRef_plot_filenames_file]:
                        make_gif(inf, inf.replace('.txt', '.gif'), args.gifexe)

        # Graph of response vs pt, but in bins of eta
        x_range = [0, 150]  # for zoomed-in low pt
        x_range = None
        plot_rsp_pt_binned_graph(check_file, etaBins, "pt", args.oDir, args.format, x_range=x_range)
        plot_rsp_pt_binned_graph(check_file, etaBins, "ptRef", args.oDir, args.format, x_range=x_range)

        all_rsp_pt_plot_filenames = []
        all_rsp_ptRef_plot_filenames = []

        # Loop over central/forward eta, do 2D plots, and graphs, and component hists
        for (eta_min, eta_max) in [[0, 3], [3, 5]]:
            print eta_min, eta_max

            for (normX, logZ) in product([True, False], [True, False]):
                plot_l1_Vs_ref(check_file, eta_min, eta_max, logZ, args.oDir, 'png')
                plot_rsp_Vs_l1(check_file, eta_min, eta_max, normX, logZ, args.oDir, 'png')
                plot_rsp_Vs_ref(check_file, eta_min, eta_max, normX, logZ, args.oDir, 'png')

            if args.detail:
                plot_rsp_pt_hists(check_file, eta_min, eta_max, ptBins, "pt", args.oDir, 'png')
                plot_rsp_pt_hists(check_file, eta_min, eta_max, ptBins, "ptRef", args.oDir, 'png')

            # graphs
            plot_rsp_eta_exclusive_graph(check_file, eta_min, eta_max, binning.check_pt_bins, 'pt', args.oDir, args.format)
            plot_rsp_eta_exclusive_graph(check_file, eta_min, eta_max, binning.check_pt_bins, 'ptRef', args.oDir, args.format)

            plot_rsp_pt_graph(check_file, eta_min, eta_max, args.oDir, args.format, x_range)
            plot_rsp_ptRef_graph(check_file, eta_min, eta_max, args.oDir, args.format, x_range)

            for etamin, etamax in pairwise(etaBins):
                if etamin < eta_min or etamax > eta_max:
                    continue
                print etamin, etamax
                this_rsp_pt_plot_filenames = []
                this_rsp_ptRef_plot_filenames = []
                # component hists/fits for the eta graphs, binned by pt
                for pt_min, pt_max in binning.check_pt_bins:
                    pt_filename = plot_rsp_eta_bin_pt(check_file, etamin, etamax, 'pt', pt_min, pt_max, args.oDir, 'png')
                    this_rsp_pt_plot_filenames.append(pt_filename)
                    ptRef_filename = plot_rsp_eta_bin_pt(check_file, etamin, etamax, 'ptRef', pt_min, pt_max, args.oDir, 'png')
                    this_rsp_ptRef_plot_filenames.append(ptRef_filename)

                pt_list_file = os.path.join(args.oDir, 'list_pt_eta_%g_%g.txt' % (etamin, etamax))
                write_filelist(this_rsp_pt_plot_filenames, pt_list_file)
                if args.gifs:
                    make_gif(pt_list_file, pt_list_file.replace('.txt', '.gif'), args.gifexe)

                ptRef_list_file = os.path.join(args.oDir, 'list_ptRef_eta_%g_%g.txt' % (etamin, etamax))
                write_filelist(this_rsp_ptRef_plot_filenames, ptRef_list_file)
                if args.gifs:
                    make_gif(ptRef_list_file, ptRef_list_file.replace('.txt', '.gif'), args.gifexe)

                all_rsp_pt_plot_filenames.extend(this_rsp_pt_plot_filenames)
                all_rsp_ptRef_plot_filenames.extend(this_rsp_ptRef_plot_filenames)

        pt_list_file = os.path.join(args.oDir, 'list_pt_eta_%g_%g.txt' % (etaBins[0], etaBins[-1]))
        write_filelist(all_rsp_pt_plot_filenames, pt_list_file)
        if args.gifs:
            make_gif(pt_list_file, pt_list_file.replace('.txt', '.gif'), args.gifexe)

        ptRef_list_file = os.path.join(args.oDir, 'list_ptRef_eta_%g_%g.txt' % (etaBins[0], etaBins[-1]))
        write_filelist(all_rsp_ptRef_plot_filenames, ptRef_list_file)
        if args.gifs:
            make_gif(ptRef_list_file, ptRef_list_file.replace('.txt', '.gif'), args.gifexe)

        check_file.Close()

    # Do plots with output from runCalibration.py
    # ------------------------------------------------------------------------
    if args.calib:

        calib_file = cu.open_root_file(args.calib)

        for eta_min, eta_max in pairwise(binning.eta_bins[:-1]):

            print eta_min, eta_max

            # 2D correlation heat maps
            for (normX, logZ) in product([True, False], [True, False]):
                plot_rsp_Vs_ref(calib_file, eta_min, eta_max, normX, logZ, args.oDir, 'png')
                plot_rsp_Vs_l1(calib_file, eta_min, eta_max, normX, logZ, args.oDir, 'png')

            # individual fit histograms for each pt bin
            if args.detail:

                list_dir = os.path.join(args.oDir, 'eta_%g_%g' % (eta_min, eta_max))
                cu.check_dir_exists_create(list_dir)

                if eta_min > 2.9:
                    ptBins = binning.pt_bins_stage2_hf

                rsp_plot_filenames = []
                pt_plot_filenames = []

                for pt_min, pt_max in pairwise(ptBins):
                    rsp_name = plot_rsp_eta_pt_bin(calib_file, eta_min, eta_max, pt_min, pt_max, args.oDir, 'png')
                    rsp_plot_filenames.append(rsp_name)
                    pt_name = plot_pt_bin(calib_file, eta_min, eta_max, pt_min, pt_max, args.oDir, 'png')
                    pt_plot_filenames.append(pt_name)

                # print individual histograms, and make a list suitable for imagemagick to turn into a GIF
                rsp_plot_filenames_file = os.path.join(list_dir, 'list_rsp.txt')
                write_filelist(rsp_plot_filenames, rsp_plot_filenames_file)

                # print individual histograms, and make a list suitable for imagemagick to turn into a GIF
                pt_plot_filenames_file = os.path.join(list_dir, 'list_pt.txt')
                write_filelist(pt_plot_filenames, pt_plot_filenames_file)

                # make dem gifs
                if args.gifs:
                    for inf in [pt_plot_filenames_file, rsp_plot_filenames_file]:
                        make_gif(inf, inf.replace('.txt', '.gif'), args.gifexe)
                else:
                    print "To make animated gif from PNGs using a plot list:"
                    print "convert -dispose Background -delay 50 -loop 0 @%s "\
                        "pt_eta_%g_%g.gif" % (pt_plot_filenames_file, eta_min, eta_max)

            # the correction curve graph
            plot_correction_graph(calib_file, eta_min, eta_max, args.oDir, args.format)

        calib_file.Close()

    if args.zip:
        print 'Zipping up files'
        zip_filename = os.path.basename(args.zip.split('.')[0])
        make_archive(zip_filename, 'gztar', args.oDir)
def plot_rsp_pt(inputfile, outputfile, absetamin, absetamax, pt_bins, pt_var, pt_max, pu_min, pu_max):
    """Make a graph of response Vs pt for given eta bin

    pt_var allows the user to specify which pT to bin in & plot against.
    Should be the name of a variable in the tree
    pt_max is a cut on maxmimum value of pt (applied to l1 pt to
        avoid including saturation effects)
    """

    # Input tree
    tree_raw = inputfile.Get("valid")

    # Output folders
    output_f = outputfile.GetDirectory('eta_%g_%g' % (absetamin, absetamax))
    output_f_hists = None
    if not output_f:
        output_f = outputfile.mkdir('eta_%g_%g' % (absetamin, absetamax))
        output_f_hists = output_f.mkdir("Histograms")
    else:
        output_f_hists = output_f.GetDirectory("Histograms")

    gr_rsp_pt = ROOT.TGraphErrors()

    # Cut strings
    eta_cutStr = "TMath::Abs(eta) < %f && TMath::Abs(eta) > %f" % (absetamax, absetamin)
    # keep the pt < pt_max to safeguard against staurated L1 jets
    pt_cutStr = "%s < %g && pt < %g" % (pt_var, pt_bins[-1], pt_max)
    pu_cutStr = "numPUVertices <= %f && numPUVertices >= %f" % (pu_max, pu_min)
    cutStr = " && ".join([eta_cutStr, pt_cutStr, pu_cutStr])

    n_rsp_bins = 100
    rsp_min = 0
    rsp_max = 5

    pt_array = array('d', pt_bins)

    # First make a 2D plot
    h2d_rsp_pt = ROOT.TH2D("h2d_rsp_%s_%g_%g" % (pt_var, absetamin, absetamax),
                           "%g < |#eta| < %g;p_{T};response" % (absetamin, absetamax),
                           len(pt_bins) - 1, pt_array,
                           n_rsp_bins, rsp_min, rsp_max)
    tree_raw.Draw("rsp:%s>>h2d_rsp_%s_%g_%g" % (pt_var, pt_var, absetamin, absetamax), cutStr)

    output_f_hists.WriteTObject(h2d_rsp_pt)

    # Now for each pt bin, do a projection on 1D hist of response and fit a Gaussian
    print pt_bins
    for i, (pt_min, pt_max) in enumerate(pairwise(pt_bins)):
        h_rsp = h2d_rsp_pt.ProjectionY("rsp_%s_%g_%g" % (pt_var, pt_min, pt_max), i + 1, i + 1)
        print i, pt_min, pt_max

        if h_rsp.Integral() <= 0:
            print "No entries - skipping"
            continue

        # Fit with Gaussian
        mean = h_rsp.GetMean()
        err = h_rsp.GetMeanError()

        peak = h_rsp.GetBinCenter(h_rsp.GetMaximumBin())
        # if h_rsp.GetRMS() < 0.2:
        #    fit_result = h_rsp.Fit("gaus", "QER", "", peak - h_rsp.GetRMS(), peak + h_rsp.GetRMS())
        # else:
        # fit_result = h_rsp.Fit("gaus", "QER", "", peak - 0.5*h_rsp.GetRMS(), peak + 0.5*h_rsp.GetRMS())
        fit_result = h_rsp.Fit("gaus", "QER", "", peak - h_rsp.GetRMS(), peak + h_rsp.GetRMS())
        # fit_result = h_rsp.Fit("gaus", "QER", "", mean - h_rsp.GetRMS(), mean + h_rsp.GetRMS())

        output_f_hists.WriteTObject(h_rsp)

        # TODO: better check against Gaussian fit - are peaks ~ similar?
        # if int(fit_result) == 0 and check_gaus_fit(h_rsp):
        if int(fit_result) == 0 and abs(h_rsp.GetFunction("gaus").GetParameter(1) - peak) / peak < 0.1:
            mean = h_rsp.GetFunction("gaus").GetParameter(1)
            err = h_rsp.GetFunction("gaus").GetParError(1)
            # Add the Gaussian to the total graph
            N = gr_rsp_pt.GetN()
            gr_rsp_pt.SetPoint(N, 0.5 * (pt_min + pt_max), mean)
            gr_rsp_pt.SetPointError(N, 0.5 * (pt_max - pt_min), err)
        else:
            print "Cannot fit Gaussian in plot_rsp_pt, using raw mean instead"

    # Save the graph
    gr_rsp_pt.SetTitle("%g < |#eta^{L1}| < %g;p_{T}; <response> = <p_{T}^{L1}/p_{T}^{Ref}>" % (absetamin, absetamax))
    gr_rsp_pt.SetName("gr_rsp_%s_eta_%g_%g" % (pt_var, absetamin, absetamax))

    output_f.WriteTObject(gr_rsp_pt)
    def compare_eta_by_pu_bins(graphs,
                               pu_labels,
                               title,
                               oDir,
                               ylim=None,
                               lowpt_zoom=True):
        """Compare eta bins for graphs for a given PU bin. Does central, fowrad, and central+forward.

        Parameters
        ----------
        graphs : list[Contribution]
            Contributions corresponding to eta bins (0PU, PU0to10, 15to25, 30to40)
        title : str
            Title to put on plots
        oDir : str
            Output directory for plots
        ylim : list, optional
            Set y axis range
        lowpt_zoom : bool, optional
            Zoom in on low pt range
        """
        eta_scenarios = [
            binning.eta_bins_central, binning.eta_bins_forward,
            binning.eta_bins
        ]
        eta_scenario_labels = ['central', 'forward', 'all']
        for eta_bins, eta_label in izip(eta_scenarios, eta_scenario_labels):
            for pu_ind, pu_label in enumerate(pu_labels):
                new_graphs = []
                rename_dict = dict(pu_label=pu_label)
                for eta_ind, (eta_min,
                              eta_max) in enumerate(pairwise(eta_bins)):
                    rename_dict['eta_min'] = eta_min
                    rename_dict['eta_max'] = eta_max
                    contr = deepcopy(graphs[pu_ind])
                    contr.obj_name = graphs[pu_ind].obj_name.format(
                        **rename_dict)
                    contr.line_color = colors[eta_ind]
                    contr.marker_color = colors[eta_ind]
                    contr.label = "%g < |#eta^{L1}| < %g" % (eta_min, eta_max)
                    new_graphs.append(contr)
                if not ylim:
                    ylim = [0.5, 4]
                p = Plot(contributions=new_graphs,
                         what='graph',
                         xtitle="<p_{T}^{L1}>",
                         ytitle="Correction value (= 1/response)",
                         title=title.format(**rename_dict),
                         ylim=ylim)
                p.plot()
                p.save(
                    os.path.join(
                        oDir, 'compare_%sEta_%s.pdf' % (eta_label, pu_label)))

                if lowpt_zoom:
                    p = Plot(contributions=new_graphs,
                             what='graph',
                             xtitle="<p_{T}^{L1}>",
                             ytitle="Correction value (= 1/response)",
                             title=title.format(**rename_dict),
                             xlim=zoom_pt,
                             ylim=ylim)
                    p.plot()
                    p.save(
                        os.path.join(
                            oDir, 'compare_%sEta_%s_pTzoomed.pdf' %
                            (eta_label, pu_label)))
def plot_rsp_pt(inputfile, outputfile, absetamin, absetamax, pt_bins, pt_var,
                pt_max, pu_min, pu_max):
    """Make a graph of response Vs pt for given eta bin

    pt_var allows the user to specify which pT to bin in & plot against.
    Should be the name of a variable in the tree
    pt_max is a cut on maxmimum value of pt (applied to l1 pt to
        avoid including saturation effects)
    """

    # Input tree
    tree_raw = inputfile.Get("valid")

    # Output folders
    output_f = outputfile.GetDirectory('eta_%g_%g' % (absetamin, absetamax))
    output_f_hists = None
    if not output_f:
        output_f = outputfile.mkdir('eta_%g_%g' % (absetamin, absetamax))
        output_f_hists = output_f.mkdir("Histograms")
    else:
        output_f_hists = output_f.GetDirectory("Histograms")

    gr_rsp_pt = ROOT.TGraphErrors()

    # Cut strings
    eta_cutStr = "TMath::Abs(eta) < %f && TMath::Abs(eta) > %f" % (absetamax,
                                                                   absetamin)
    # keep the pt < pt_max to safeguard against staurated L1 jets
    pt_cutStr = "%s < %g && pt < %g" % (pt_var, pt_bins[-1], pt_max)
    pu_cutStr = "numPUVertices <= %f && numPUVertices >= %f" % (pu_max, pu_min)
    avoidSaturation_cut = "pt < 1023.1"
    cutStr = " && ".join(
        [eta_cutStr, pt_cutStr, pu_cutStr, avoidSaturation_cut])

    n_rsp_bins = 100
    rsp_min = 0
    rsp_max = 5

    pt_array = array('d', pt_bins)

    # First make a 2D plot
    h2d_rsp_pt = ROOT.TH2D(
        "h2d_rsp_%s_%g_%g" % (pt_var, absetamin, absetamax),
        "%g < |#eta| < %g;p_{T};response" % (absetamin, absetamax),
        len(pt_bins) - 1, pt_array, n_rsp_bins, rsp_min, rsp_max)
    tree_raw.Draw(
        "rsp:%s>>h2d_rsp_%s_%g_%g" % (pt_var, pt_var, absetamin, absetamax),
        cutStr)

    output_f_hists.WriteTObject(h2d_rsp_pt)

    # Now for each pt bin, do a projection on 1D hist of response and fit a Gaussian
    print pt_bins
    for i, (pt_min, pt_max) in enumerate(pairwise(pt_bins)):
        h_rsp = h2d_rsp_pt.ProjectionY(
            "rsp_%s_%g_%g" % (pt_var, pt_min, pt_max), i + 1, i + 1)
        print i, pt_min, pt_max

        if h_rsp.Integral() <= 0:
            print "No entries - skipping"
            continue

        # Fit with Gaussian
        mean = h_rsp.GetMean()
        err = h_rsp.GetMeanError()

        peak = h_rsp.GetBinCenter(h_rsp.GetMaximumBin())
        # if h_rsp.GetRMS() < 0.2:
        #    fit_result = h_rsp.Fit("gaus", "QER", "", peak - h_rsp.GetRMS(), peak + h_rsp.GetRMS())
        # else:
        # fit_result = h_rsp.Fit("gaus", "QER", "", peak - 0.5*h_rsp.GetRMS(), peak + 0.5*h_rsp.GetRMS())
        fit_result = h_rsp.Fit("gaus", "QER", "", peak - h_rsp.GetRMS(),
                               peak + h_rsp.GetRMS())
        # fit_result = h_rsp.Fit("gaus", "QER", "", mean - h_rsp.GetRMS(), mean + h_rsp.GetRMS())

        output_f_hists.WriteTObject(h_rsp)

        # TODO: better check against Gaussian fit - are peaks ~ similar?
        # if int(fit_result) == 0 and check_gaus_fit(h_rsp):
        if int(fit_result) == 0 and abs(
                h_rsp.GetFunction("gaus").GetParameter(1) - peak) / peak < 0.1:
            mean = h_rsp.GetFunction("gaus").GetParameter(1)
            err = h_rsp.GetFunction("gaus").GetParError(1)
            # Add the Gaussian to the total graph
            N = gr_rsp_pt.GetN()
            gr_rsp_pt.SetPoint(N, 0.5 * (pt_min + pt_max), mean)
            gr_rsp_pt.SetPointError(N, 0.5 * (pt_max - pt_min), err)
        else:
            print "Cannot fit Gaussian in plot_rsp_pt, using raw mean instead"

    # Save the graph
    gr_rsp_pt.SetTitle(
        "%g < |#eta^{L1}| < %g;p_{T}; <response> = <p_{T}^{L1}/p_{T}^{Ref}>" %
        (absetamin, absetamax))
    gr_rsp_pt.SetName("gr_rsp_%s_eta_%g_%g" % (pt_var, absetamin, absetamax))

    output_f.WriteTObject(gr_rsp_pt)
def submit_resolution_dag(pairs_file, max_l1_pt, log_dir, append,
                          pu_bins, eta_bins, common_input_files,
                          force_submit=False):
    """Submit one makeResolutionPlots DAG for one pairs file.

    This will run makeResolutionPlots over exclusive and inclusive eta bins,
    and then finally hadd the results together.

    Parameters
    ----------
    pairs_files : str, optional
        Pairs file to process. Must be full path.

    max_l1_pt : int, optional
        Maximum L1 pt to consider when making plots.

    log_dir : str, optional
        Directory for STDOUT/STDERR/LOG files. Should be on /storage.

    append : str, optional
        String to append to filenames to track various settings (e.g. PU bin).

    pu_bins : list[list[int, int]], optional
        List of PU bin edges.

    eta_bins : list[float], optional
        List of eta bin edges, including upper edge of last bin.

    force_submit : bool, optional
        If True, forces job submission even if proposed output files
        already exists.
        Oherwise, program quits before submission.

    """
    cc.check_file_exists(pairs_file)

    # Setup output directory for res* files
    # e.g. if pairs file in DATASET/pairs/pairs.root
    # then output goes in DATASET/resolution/
    out_dir = os.path.dirname(os.path.dirname(pairs_file))
    out_dir = os.path.join(out_dir, 'resolution')
    cc.check_create_dir(out_dir, info=True)

    # Stem for output filename
    out_stem = os.path.splitext(os.path.basename(pairs_file))[0]
    out_stem = out_stem.replace("pairs_", "res_")

    # Loop over PU bins
    # ---------------------------------------------------------------------
    pu_bins = pu_bins or [[-99, 999]]  # set ridiculous limits if no cut on PU
    status_files = []
    for (pu_min, pu_max) in pu_bins:

        log_stem = 'res.$(cluster).$(process)'
        res_jobs = ht.JobSet(exe='python',
                             copy_exe=False,
                             filename='submit_resolution.condor',
                             setup_script='worker_setup.sh',
                             share_exe_setup=True,
                             out_dir=log_dir, out_file=log_stem + '.out',
                             err_dir=log_dir, err_file=log_stem + '.err',
                             log_dir=log_dir, log_file=log_stem + '.log',
                             cpus=1, memory='100MB', disk='100MB',
                             transfer_hdfs_input=False,
                             common_input_files=common_input_files,
                             hdfs_store=out_dir)

        # For creating filenames later
        fmt_dict = dict(puMin=pu_min, puMax=pu_max, maxL1Pt=max_l1_pt)

        # Hold all output filenames
        res_output_files = []

        # Add exclusive eta bins to this JobSet
        for ind, (eta_min, eta_max) in enumerate(pairwise(eta_bins)):
            out_file = out_stem + "_%d" % ind + append.format(**fmt_dict) + '.root'
            out_file = os.path.join(out_dir, out_file)
            res_output_files.append(out_file)

            job_args = ['makeResolutionPlots.py', pairs_file, out_file,
                        '--excl', #'--maxPt', max_l1_pt,
                        #'--PUmin', pu_min, '--PUmax', pu_max,
                        '--etaInd', ind]

            res_job = ht.Job(name='res_%d' % ind,
                             args=job_args,
                             input_files=[pairs_file],
                             output_files=[out_file])

            res_jobs.add_job(res_job)

        # Add inclusive bins (central, forward, all)
        # remove the [0:1] to do all - currently central only 'cos HF broke
        for incl in ['central', 'forward', 'all'][0:1]:
            out_file = out_stem + "_%s" % incl + append.format(**fmt_dict) + '.root'
            out_file = os.path.join(out_dir, out_file)
            res_output_files.append(out_file)

            job_args = ['makeResolutionPlots.py', pairs_file, out_file,
                        '--incl'] #, '--maxPt', max_l1_pt,
                        # '--PUmin', pu_min, '--PUmax', pu_max]
            if incl != 'all':
                job_args.append('--%s' % incl)

            res_job = ht.Job(name='res_%s' % incl,
                             args=job_args,
                             input_files=[pairs_file],
                             output_files=[out_file])

            res_jobs.add_job(res_job)

        # Add hadd jobs
        # ---------------------------------------------------------------------
        log_stem = 'resHadd.$(cluster).$(process)'

        hadd_jobs = ht.JobSet(exe='hadd',
                              copy_exe=False,
                              filename='haddSmall.condor',
                              setup_script="cmssw_setup.sh",
                              share_exe_setup=True,
                              out_dir=log_dir, out_file=log_stem + '.out',
                              err_dir=log_dir, err_file=log_stem + '.err',
                              log_dir=log_dir, log_file=log_stem + '.log',
                              cpus=1, memory='100MB', disk='20MB',
                              transfer_hdfs_input=False,
                              hdfs_store=out_dir)

        # Construct final hadded file name
        final_file = os.path.join(out_dir, out_stem + append.format(**fmt_dict) + '.root')
        hadd_output = [final_file]
        hadd_args = hadd_output + res_output_files

        hadder = ht.Job(name='haddRes',
                        args=hadd_args,
                        input_files=res_output_files,
                        output_files=hadd_output)

        hadd_jobs.add_job(hadder)

        # Add all jobs to DAG, with necessary dependencies
        # ---------------------------------------------------------------------
        stem = 'res_%s_%s' % (strftime("%H%M%S"), cc.rand_str(3))
        res_dag = ht.DAGMan(filename='%s.dag' % stem,
                            status_file='%s.status' % stem)
        for job in res_jobs:
            res_dag.add_job(job)

        res_dag.add_job(hadder, requires=[j for j in res_jobs])

        # Check if any of the output files already exists - maybe we mucked up?
        # ---------------------------------------------------------------------
        if not force_submit:
            for f in [final_file] + res_output_files:
                if os.path.isfile(f):
                    print 'ERROR: output file already exists - not submitting'
                    print 'FILE:', f
                    return 1

        # res_dag.write()
        res_dag.submit()
        status_files.append(res_dag.status_file)

    print 'For all statuses:'
    print 'DAGstatus.py', ' '.join(status_files)
def plot_resolution(inputfile, outputfile, ptBins, absetamin, absetamax, max_pt, pu_min, pu_max):
    """Do various resolution plots for given eta bin, for all pT bins

    max_pt : maximum pt cut on L1 pT, to avoid including saturated jets.

    pu_min, pu_max : PU bins
    """

    print "Doing eta bin: %g - %g" % (absetamin, absetamax)
    print "Doing pt bins:", ptBins

    # Input tree
    tree_raw = inputfile.Get("valid")

    # Output folders
    output_f = outputfile.mkdir('eta_%g_%g' % (absetamin, absetamax))
    output_f_hists = output_f.mkdir("Histograms")

    # Eta cut string
    eta_cutStr = " TMath::Abs(eta)<%g && TMath::Abs(eta) > %g " % (absetamax, absetamin)
    # Pt cut string
    pt_cutStr = "pt < %g" % max_pt
    # PU cut string
    pu_cutStr = "numPUVertices <= %f && numPUVertices >= %f" % (pu_max, pu_min)
    cutStr = " && ".join([eta_cutStr, pt_cutStr, pu_cutStr])
    print cutStr

    title = "%g < |#eta^{L1}| < %g" % (absetamin, absetamax)

    # First make 2D plots of pt difference and resolution Vs Et,
    # then we can project them for individual Et bins
    # This is *much* faster than just making all the plots individually
    diff_min = -200
    diff_max = 200
    nbins_diff = 200

    pt_bin_min = ptBins[0]
    pt_bin_min = 0
    pt_bin_max = ptBins[-1]
    nbins_et = 4 * (pt_bin_max - pt_bin_min)

    # Ref jet pt from tree - old ones don't store ptRef, so construct from pt/rsp
    # - or should it be pt * rsp for old style rsp?
    ptRef = "ptRef" if check_var_stored(tree_raw, "ptRef") else "(pt/rsp)"

    # 1D plot of ptDifference
    # tree_raw.Draw("ptDiff>>ptDiff(%d, %g, %g)" % (nbins_diff, diff_min, diff_max), cutStr)
    # ptDiff = ROOT.gROOT.FindObject("ptDiff")

    # 2d plots of pt difference vs L1 pt
    var = "ptDiff" if check_var_stored(tree_raw, "ptDiff") else "(pt-%s)" % ptRef
    tree_raw.Draw("%s:pt>>ptDiff_l1_2d(%d, %g, %g, %d, %g, %g)" % (var, nbins_et, pt_bin_min, pt_bin_max, nbins_diff, diff_min, diff_max), cutStr)
    ptDiff_l1_2d = ROOT.gROOT.FindObject("ptDiff_l1_2d")
    ptDiff_l1_2d.SetTitle("%s;E_{T}^{L1} [GeV];E_{T}^{L1} - E_{T}^{Ref} [GeV]" % title)
    output_f_hists.WriteTObject(ptDiff_l1_2d)

    # 1D plot of ptDiff
    ptDiff = ptDiff_l1_2d.ProjectionY("ptDiff")
    ptDiff.SetTitle(";E_{T}^{L1} - E_{T}^{Ref} [GeV];N")
    fit_res = ptDiff.Fit("gaus", "QESR", "R", ptDiff.GetMean() - 1. * ptDiff.GetRMS(), ptDiff.GetMean() + 1. * ptDiff.GetRMS())
    output_f_hists.WriteTObject(ptDiff)

    # 1D plot of L1 pt
    ptL1 = ptDiff_l1_2d.ProjectionX("pt")
    ptL1.SetTitle(";E_{T}^{L1}[GeV];N")
    fit_res = ptL1.Fit("gaus", "QESR", "R", ptL1.GetMean() - 1. * ptL1.GetRMS(), ptL1.GetMean() + 1. * ptL1.GetRMS())
    output_f_hists.WriteTObject(ptL1)

    # 2d plots of pt difference vs ref pt
    tree_raw.Draw("%s:%s>>ptDiff_ref_2d(%d, %g, %g, %d, %g, %g)" % (var, ptRef, nbins_et, pt_bin_min, pt_bin_max, nbins_diff, diff_min, diff_max), cutStr)
    ptDiff_ref_2d = ROOT.gROOT.FindObject("ptDiff_ref_2d")
    ptDiff_ref_2d.SetTitle("%s;E_{T}^{Ref} [GeV];E_{T}^{L1} - E_{T}^{Ref} [GeV]" % title)
    output_f_hists.WriteTObject(ptDiff_ref_2d)

    res_min = -5
    res_max = 2
    nbins_res = 210

    # 2D plot of L1-Ref/L1 VS L1
    var = "resL1" if check_var_stored(tree_raw, "resL1") else "(pt-%s)/pt" % (ptRef)  # for old pair files
    tree_raw.Draw("%s:pt>>res_l1_2d(%d, %g, %g, %d, %g, %g)" % (var, nbins_et, pt_bin_min, pt_bin_max, nbins_res, res_min, res_max), cutStr)
    res_l1_2d = ROOT.gROOT.FindObject("res_l1_2d")
    res_l1_2d.SetTitle("%s;E_{T}^{L1} [GeV];(E_{T}^{L1} - E_{T}^{Ref})/E_{T}^{L1}" % title)
    output_f_hists.WriteTObject(res_l1_2d)

    # 1D plot of L1-ref/L1
    res_l1 = res_l1_2d.ProjectionY("res_l1")
    res_l1.SetTitle(";E_{T}^{L1} - E_{T}^{Ref}/E_{T}^{L1};N")
    fit_res = res_l1.Fit("gaus", "QESR", "R", res_l1.GetMean() - 1. * res_l1.GetRMS(), res_l1.GetMean() + 1. * res_l1.GetRMS())
    output_f_hists.WriteTObject(res_l1)

    # 2D plot of L1-Ref/Ref VS L1
    var = "resRef" if check_var_stored(tree_raw, "resRef") else "(pt-%s)/%s" % (ptRef, ptRef)
    res_min = -2
    nbins_res = 120
    tree_raw.Draw("%s:pt>>res_refVsl1_2d(%d, %g, %g, %d, %g, %g)" % (var, nbins_et, pt_bin_min, pt_bin_max, nbins_res, res_min, res_max), cutStr)
    res_refVsl1_2d = ROOT.gROOT.FindObject("res_refVsl1_2d")
    res_refVsl1_2d.SetTitle("%s;E_{T}^{L1} [GeV];(E_{T}^{L1} - E_{T}^{Ref})/E_{T}^{Ref}" % title)
    output_f_hists.WriteTObject(res_refVsl1_2d)

    # 1D plot of L1-ref/ref
    res_ref = res_refVsl1_2d.ProjectionY("res_ref")
    res_ref.SetTitle(";E_{T}^{L1} - E_{T}^{Ref}/E_{T}^{L1};N")
    fit_res = res_ref.Fit("gaus", "QESR", "R", res_ref.GetMean() - 1. * res_ref.GetRMS(), res_ref.GetMean() + 1. * res_ref.GetRMS())
    output_f_hists.WriteTObject(res_ref)

    # 2D plot of L1-Ref/Ref VS Ref
    var = "resRef" if check_var_stored(tree_raw, "resRef") else "(pt-%s)/%s" % (ptRef, ptRef)
    tree_raw.Draw("%s:%s>>res_refVsref_2d(%d, %g, %g, %d, %g, %g)" % (var, ptRef, nbins_et, pt_bin_min, pt_bin_max, nbins_res, res_min, res_max), cutStr)
    res_refVsref_2d = ROOT.gROOT.FindObject("res_refVsref_2d")
    res_refVsref_2d.SetTitle("%s;E_{T}^{Ref} [GeV];(E_{T}^{L1} - E_{T}^{Ref})/E_{T}^{Ref}" % title)
    output_f_hists.WriteTObject(res_refVsref_2d)

    # Graphs to hold resolution for all pt bins
    res_graph_l1 = ROOT.TGraphErrors()
    res_graph_l1.SetNameTitle("resL1_%g_%g" % (absetamin, absetamax), "%s;E_{T}^{L1} [GeV];#sigma(E_{T}^{L1} - E_{T}^{Ref}/E_{T}^{L1})" % title)

    res_graph_l1_diff = ROOT.TGraphErrors() #binned in l1 pt.  this fits to L1-ref, then divides by average L1 pT
    res_graph_l1_diff.SetNameTitle("resL1_%g_%g_diff" % (absetamin, absetamax), "%s;E_{T}^{L1} [GeV];#sigma(E_{T}^{L1} - E_{T}^{Ref})/<E_{T}^{L1}>" % title)

    res_graph_refVsl1 = ROOT.TGraphErrors() # binned in l1 pt
    res_graph_refVsl1.SetNameTitle("resRefL1_%g_%g" % (absetamin, absetamax), "%s;E_{T}^{L1} [GeV];#sigma(E_{T}^{L1} - E_{T}^{Ref}/E_{T}^{Ref})" % title)

    res_graph_refVsref = ROOT.TGraphErrors() # binned in ref pt
    res_graph_refVsref.SetNameTitle("resRefRef_%g_%g" % (absetamin, absetamax), "%s;E_{T}^{Ref} [GeV];#sigma(E_{T}^{L1} - E_{T}^{Ref}/E_{T}^{Ref})" % title)

    res_graph_refVsref_diff = ROOT.TGraphErrors() # fit to L1 - ref pT, divide by ref pT, binned in ref pt
    res_graph_refVsref_diff.SetNameTitle("resRefRef_%g_%g_diff" % (absetamin, absetamax), "%s;E_{T}^{Ref} [GeV];#sigma(E_{T}^{L1} - E_{T}^{Ref})/<E_{T}^{Ref}>" % title)

    # res_graph_refVsl1_diff = ROOT.TGraphErrors() # fit to L1 - ref pT, divide by ref pT, binned in L1 pt
    # res_graph_refVsl1_diff.SetNameTitle("resRefL1_%g_%g_diff" % (absetamin, absetamax), "%s;E_{T}^{Ref} [GeV];#sigma(E_{T}^{L1} - E_{T}^{Ref})/<E_{T}^{Ref}>" % title)

    # Now go through pt bins, and plot resolution for each, fit with gaussian,
    # and add width to graph
    for i, (ptmin, ptmax) in enumerate(pairwise(ptBins)):
        # pt_cut = "pt < %g && pt > %g" % (ptmax, ptmin)
        # pt_cut_ref = "%s < %g && %s > %g" % (ptRef, ptmax, ptRef, ptmin)
        print "    Doing pt bin: %g - %g" % (ptmin, ptmax)

        l1_bin_title = title + ", %g < p_{T}^{L1} < %g" % (ptmin, ptmax)
        ref_bin_title = title + ", %g < p_{T}^{Ref} < %g" % (ptmin, ptmax)

        # Plot difference in L1 pT and Ref pT (in bin of L1 pt)
        plot_bin_fit(ptDiff_l1_2d, ptmin, ptmax,
            "%s;E_{T}^{L1} - E_{T}^{Ref} [GeV];N" % l1_bin_title,
            "ptDiff_l1_%g_%g" % (ptmin, ptmax), res_graph_l1_diff, output_f_hists, divide=True)

        # Plot difference in L1 pT and Ref pT (in bin of ref pt)
        plot_bin_fit(ptDiff_ref_2d, ptmin, ptmax,
            "%s;E_{T}^{L1} - E_{T}^{Ref} [GeV];N" % ref_bin_title,
            "ptDiff_ref_%g_%g" % (ptmin, ptmax), res_graph_refVsref_diff, output_f_hists, divide=True)

        # Plot resolution wrt L1 pT & fit
        plot_bin_fit(res_l1_2d, ptmin, ptmax,
            "%s;(E_{T}^{L1} - E_{T}^{Ref})/E_{T}^{L1};N" % l1_bin_title,
            "res_l1_%g_%g" % (ptmin, ptmax), res_graph_l1, output_f_hists)

        # Plot ref resolution wrt L1 pT & fit
        plot_bin_fit(res_refVsl1_2d, ptmin, ptmax,
            "%s;(E_{T}^{L1} - E_{T}^{Ref})/E_{T}^{Ref};N" % l1_bin_title,
            "res_ref_l1_%g_%g" % (ptmin, ptmax), res_graph_refVsl1, output_f_hists)

        # Plot ref resolution Vs ref pt
        plot_bin_fit(res_refVsref_2d, ptmin, ptmax,
            "%s;(E_{T}^{L1} - E_{T}^{Ref})/E_{T}^{Ref};N" % ref_bin_title,
            "res_ref_ref_%g_%g" % (ptmin, ptmax), res_graph_refVsref, output_f_hists)

    output_f.WriteTObject(res_graph_l1)
    output_f.WriteTObject(res_graph_l1_diff)
    output_f.WriteTObject(res_graph_refVsl1)
    output_f.WriteTObject(res_graph_refVsref)
    output_f.WriteTObject(res_graph_refVsref_diff)