def checkOnMC(unfolding, method):
    global bins, nbins
    RooUnfold.SVD_n_toy = 1000
    pulls = []
    for sub in range(1,9):
        inputFile2 = File('../data/unfolding_merged_sub%d.root' % sub, 'read')
        h_data = asrootpy(inputFile2.unfoldingAnalyserElectronChannel.measured.Rebin(nbins, 'measured', bins))
        nEvents = inputFile2.EventFilter.EventCounter.GetBinContent(1)
        lumiweight = 164.5 * 5050 / nEvents
#        print sub, nEvents
        h_data.Scale(lumiweight)
        doUnfoldingSequence(unfolding, h_data, method, '_sub%d' %sub)
        pull = unfolding.pull_inputErrorOnly()
#        unfolding.printTable()
        pulls.append(pull)
        unfolding.Reset()
    allpulls = []

    for pull in pulls:
        allpulls.extend(pull)
    h_allpulls = Hist(100,-30,30)
    filling = h_allpulls.Fill
    for entry in allpulls:
        filling(entry)
    fit = h_allpulls.Fit('gaus', 'WWS')
    h_fit = asrootpy(h_allpulls.GetFunction("gaus").GetHistogram())
    canvas = Canvas(width=1600, height=1000)
    canvas.SetLeftMargin(0.15)
    canvas.SetBottomMargin(0.15)
    canvas.SetTopMargin(0.10)
    canvas.SetRightMargin(0.05)
    h_allpulls.Draw()
    fit.Draw('same')
    canvas.SaveAs('plots/Pull_allBins_withFit.png')
    
    
    
    plt.figure(figsize=(16, 10), dpi=100)
    rplt.errorbar(h_allpulls, label=r'Pull distribution for all bins',  emptybins=False)
    rplt.hist(h_fit, label=r'fit')
    plt.xlabel('(unfolded-true)/error', CMS.x_axis_title)
    plt.ylabel('entries', CMS.y_axis_title)
    plt.title('Pull distribution for all bins', CMS.title)
    plt.tick_params(**CMS.axis_label_major)
    plt.tick_params(**CMS.axis_label_minor)
    plt.legend(numpoints=1)
    plt.savefig('plots/Pull_allBins.png')
    
    #individual bins
    for bin_i in range(nbins):
        h_pull = Hist(100,-30,30)
        for pull in pulls:
            h_pull.Fill(pull[bin_i])
        plt.figure(figsize=(16, 10), dpi=100)
        rplt.errorbar(h_pull, label=r'Pull distribution for bin %d' % (bin_i + 1), emptybins=False)
        plt.xlabel('(unfolded-true)/error', CMS.x_axis_title)
        plt.ylabel('entries', CMS.y_axis_title)
        plt.title('Pull distribution for  bin %d' % (bin_i + 1), CMS.title)
        plt.savefig('Pull_bin_%d.png' % (bin_i + 1))
Beispiel #2
0
def mpe_fitting(filename, run, num_photons, use_ideal=True):

    run_number = int(run)

    if filename[-5:] == '.root':
        filename = filename[:-5]

    s_data_path = './data/%s.p' % filename

    if filename[:5] == 'nerix':
        file_identifier = filename
    else:
        file_identifier = filename[-9:]

    a_integral = pickle.load((open(s_data_path, 'r')))

    # max_num_events used to limit amplitudes
    max_num_events = len(a_integral)

    s_path_to_save = './results/%s/' % (file_identifier)
    l_colors = [4, 2, 8, 7, 5, 9] + [4, 2, 8, 7, 5, 9]

    d_mpe_fit = {}

    if file_identifier == '0062_0061':
        d_mpe_fit['settings'] = [250, -1e6, 2e7]

        d_mpe_fit['bkg_mean_low'] = -1e6
        d_mpe_fit['bkg_mean_high'] = 2e6
        d_mpe_fit['bkg_width_low'] = 1e4
        d_mpe_fit['bkg_width_high'] = 1e6
        d_mpe_fit['spe_mean_low'] = 3.5e6
        d_mpe_fit['spe_mean_high'] = 1e7
        d_mpe_fit['spe_width_low'] = 8e5
        d_mpe_fit['spe_width_high'] = 3e6
        d_mpe_fit['ua_mean_low'] = 1e5
        d_mpe_fit['ua_mean_high'] = 5e6
        d_mpe_fit['ua_width_low'] = 1e4
        d_mpe_fit['ua_width_high'] = 1e6

        d_mpe_fit['spe_mean_guess'] = 6e6
        d_mpe_fit['spe_width_guess'] = 1.9e6
    
    elif file_identifier == '0066_0065':
        d_mpe_fit['settings'] = [250, -1e6, 1.2e7]

        d_mpe_fit['bkg_mean_low'] = -1e6
        d_mpe_fit['bkg_mean_high'] = 2e6
        d_mpe_fit['bkg_width_low'] = 1e4
        d_mpe_fit['bkg_width_high'] = 1e6
        d_mpe_fit['spe_mean_low'] = 2e6
        d_mpe_fit['spe_mean_high'] = 6e6
        d_mpe_fit['spe_width_low'] = 8e5
        d_mpe_fit['spe_width_high'] = 3e6
        d_mpe_fit['ua_mean_low'] = 1e5
        d_mpe_fit['ua_mean_high'] = 5e6
        d_mpe_fit['ua_width_low'] = 1e4
        d_mpe_fit['ua_width_high'] = 1e6

        d_mpe_fit['spe_mean_guess'] = 3.6e6
        d_mpe_fit['spe_width_guess'] = 1.1e6

    elif file_identifier == '0067_0068':
        d_mpe_fit['settings'] = [250, -1e6, 7.5e6]

        d_mpe_fit['bkg_mean_low'] = -5e5
        d_mpe_fit['bkg_mean_high'] = 5e5
        d_mpe_fit['bkg_width_low'] = 1e4
        d_mpe_fit['bkg_width_high'] = 1e6
        d_mpe_fit['spe_mean_low'] = 1.2e6
        d_mpe_fit['spe_mean_high'] = 3.5e6
        d_mpe_fit['spe_width_low'] = 3e5
        d_mpe_fit['spe_width_high'] = 1e6
        d_mpe_fit['ua_mean_low'] = 1e5
        d_mpe_fit['ua_mean_high'] = 1.5e6
        d_mpe_fit['ua_width_low'] = 1e4
        d_mpe_fit['ua_width_high'] = 1e6

        d_mpe_fit['spe_mean_guess'] = 2.1e6
        d_mpe_fit['spe_width_guess'] = 6.6e5

    elif file_identifier == '0071_0072':
        d_mpe_fit['settings'] = [250, -1e6, 3.4e7]

        d_mpe_fit['bkg_mean_low'] = -1e6
        d_mpe_fit['bkg_mean_high'] = 2e6
        d_mpe_fit['bkg_width_low'] = 1e4
        d_mpe_fit['bkg_width_high'] = 1e6
        d_mpe_fit['spe_mean_low'] = 7.5e6
        d_mpe_fit['spe_mean_high'] = 1.4e7
        d_mpe_fit['spe_width_low'] = 1e6
        d_mpe_fit['spe_width_high'] = 3.5e6
        d_mpe_fit['ua_mean_low'] = 1e5
        d_mpe_fit['ua_mean_high'] = 5e6
        d_mpe_fit['ua_width_low'] = 1e4
        d_mpe_fit['ua_width_high'] = 1e6

        d_mpe_fit['spe_mean_guess'] = 9.5e6
        d_mpe_fit['spe_width_guess'] = 2.9e6

    elif file_identifier == '0073_0074':
        d_mpe_fit['settings'] = [50, -1e6, 4.2e7]

        d_mpe_fit['bkg_mean_low'] = -1e6
        d_mpe_fit['bkg_mean_high'] = 2e6
        d_mpe_fit['bkg_width_low'] = 1e5
        d_mpe_fit['bkg_width_high'] = 2e6
        d_mpe_fit['spe_mean_low'] = 8.5e6
        d_mpe_fit['spe_mean_high'] = 1.4e7
        d_mpe_fit['spe_width_low'] = 1.5e6
        d_mpe_fit['spe_width_high'] = 4.5e6
        d_mpe_fit['ua_mean_low'] = 5e5
        d_mpe_fit['ua_mean_high'] = 4e6
        d_mpe_fit['ua_width_low'] = 0.5e6
        d_mpe_fit['ua_width_high'] = 1e6

        d_mpe_fit['spe_mean_guess'] = 9.5e6
        d_mpe_fit['spe_width_guess'] = 2.9e6

    elif file_identifier == 'nerix_160418_1523':
        d_mpe_fit['settings'] = [50, -5e5, 3.e6]
        
        d_mpe_fit['bkg_mean_low'] = -5e5
        d_mpe_fit['bkg_mean_high'] = 5e5
        d_mpe_fit['bkg_width_low'] = 1e4
        d_mpe_fit['bkg_width_high'] = 5e5
        d_mpe_fit['spe_mean_low'] = 6e5
        d_mpe_fit['spe_mean_high'] = 11e5
        d_mpe_fit['spe_width_low'] = 3e5
        d_mpe_fit['spe_width_high'] = 9e5
        d_mpe_fit['ua_mean_low'] = 1e3
        d_mpe_fit['ua_mean_high'] = 5e5
        d_mpe_fit['ua_width_low'] = 1e4
        d_mpe_fit['ua_width_high'] = 5e5

    elif file_identifier == 'nerix_160418_1531':
        d_mpe_fit['settings'] = [50, -5e5, 4.e6]
        
        d_mpe_fit['bkg_mean_low'] = -5e5
        d_mpe_fit['bkg_mean_high'] = 5e5
        d_mpe_fit['bkg_width_low'] = 1e4
        d_mpe_fit['bkg_width_high'] = 5e5
        d_mpe_fit['spe_mean_low'] = 6e5
        d_mpe_fit['spe_mean_high'] = 11e5
        d_mpe_fit['spe_width_low'] = 3e5
        d_mpe_fit['spe_width_high'] = 9e5
        d_mpe_fit['ua_mean_low'] = 1e3
        d_mpe_fit['ua_mean_high'] = 5e5
        d_mpe_fit['ua_width_low'] = 1e4
        d_mpe_fit['ua_width_high'] = 5e5

    else:
        print '\n\nSettings do not exist for given setup: %s\n\n' % (file_identifier)
        sys.exit()

    l_plots = ['plots', file_identifier]


    par_names = ['p0_ampl', 'mean_bkg', 'width_bkg', 'mean_spe', 'width_spe'] + ['p%d_ampl' % (i + 1) for i in xrange(num_photons)]




    a_integral = pickle.load((open(s_data_path, 'r')))

    if use_ideal:
        l_mpe_fit_func = ['[5]/(2*3.14*%d*[4]**2.)**0.5*TMath::Poisson(%d, [0])*exp(-0.5/%.1f*((x - %.1f*[3])/[4])**2)' % (iElectron, iElectron, iElectron, iElectron) for iElectron in xrange(1, num_photons + 1)]
    else:
        l_mpe_fit_func = ['[5]/(2*3.14*([2]**2. + %d*[4]**2.))**0.5*TMath::Poisson(%d, [0])*exp(-0.5*((x - %.1f*[3] - [1])/(%.1f*[4]**2 + [2]**2)**0.5)**2)' % (iElectron, iElectron, iElectron, iElectron) for iElectron in xrange(1, num_photons + 1)]

    h_mpe_spec = Hist(*d_mpe_fit['settings'], name='h_mpe_spec', title='MPE Spectrum with Gaussian Fit - %s' % filename)
    h_mpe_spec.SetMarkerSize(0)
    h_mpe_spec.fill_array(a_integral)

    c1 = Canvas()

    h_mpe_spec.Draw()

    s_bkg = '[5]/(2*3.14*[2]**2.)**0.5*TMath::Poisson(0, [0])*exp(-0.5*((x - [1])/[2])**2)'
    s_under_amplified = '[6]/(2*3.14*[8]**2.)**0.5*exp(-0.5*((x - [7])/[8])**2)'
    s_fit_mpe = '(%s) + (%s) + (%s)' % (s_bkg, s_under_amplified, ' + '.join(l_mpe_fit_func))
    s_fit_mpe = '(%s)*([1] < [3] ? 1. : 0.)*([1] < [7] ? 1. : 0.)*([7] < [3] ? 1. : 0.)' % (s_fit_mpe)
    fit_mpe = root.TF1('fit_mpe', s_fit_mpe, *d_mpe_fit['settings'][1:])
    fit_mpe.SetLineColor(46)
    fit_mpe.SetLineStyle(2)
    fit_mpe.SetLineWidth(3)

    h_mpe_spec.GetXaxis().SetTitle('Integrated Charge [e-]')
    h_mpe_spec.GetYaxis().SetTitle('Counts')
    h_mpe_spec.GetYaxis().SetTitleOffset(1.4)
    h_mpe_spec.SetStats(0)

    c1.SetLogy()


    fit_mpe.SetParLimits(0, 0.9, 2.5)
    fit_mpe.SetParameter(0, 1.3)
    fit_mpe.SetParLimits(1, d_mpe_fit['bkg_mean_low'], d_mpe_fit['bkg_mean_high'])
    fit_mpe.SetParameter(1, (d_mpe_fit['bkg_mean_low']+d_mpe_fit['bkg_mean_high'])/2.)
    fit_mpe.SetParLimits(2, d_mpe_fit['bkg_width_low'], d_mpe_fit['bkg_width_high'])
    fit_mpe.SetParameter(2, (d_mpe_fit['bkg_width_low']+d_mpe_fit['bkg_width_high'])/2.)
    fit_mpe.SetParLimits(3, d_mpe_fit['spe_mean_low'], d_mpe_fit['spe_mean_high'])
    fit_mpe.SetParameter(3, d_mpe_fit['spe_mean_guess'])
    fit_mpe.SetParLimits(4, d_mpe_fit['spe_width_low'], d_mpe_fit['spe_width_high'])
    fit_mpe.SetParameter(4, d_mpe_fit['spe_width_guess'])
    fit_mpe.SetParLimits(5, 10, max_num_events*1e6)
    fit_mpe.SetParameter(5, (10+max_num_events*1e6)/2.)
    fit_mpe.SetParLimits(6, 10, max_num_events*1e6)
    fit_mpe.SetParameter(6, (10+max_num_events*1e6)/2.)
    fit_mpe.SetParLimits(7, d_mpe_fit['ua_mean_low'], d_mpe_fit['ua_mean_high'])
    fit_mpe.SetParameter(7, (d_mpe_fit['ua_mean_low']+d_mpe_fit['ua_mean_high'])/2.)
    fit_mpe.SetParLimits(8, d_mpe_fit['ua_width_low'], d_mpe_fit['ua_width_high'])
    fit_mpe.SetParameter(8, (d_mpe_fit['ua_width_low']+d_mpe_fit['ua_width_high'])/2.)


    """
    for i, guess in enumerate(mpe_par_guesses):
        fit_mpe.SetParameter(i, guess)

    for i in xrange(len(par_names)):
        fit_mpe.SetParName(i, par_names[i])


    for photon in xrange(num_photons):
        fit_mpe.SetParLimits(5 + photon, 0, max_num_events)
    """

    fitResult = h_mpe_spec.Fit('fit_mpe', 'MILES')



    # draw individual peaks
    s_gaussian = '[0]*exp(-0.5/%.1f*((x - %.1f*[1])/[2])**2)'
    l_functions = []
    l_individual_integrals = [0. for i in xrange(num_photons+2)]
    for i in xrange(num_photons + 2):
        l_functions.append(root.TF1('peak_%d' % i, '[0]*exp(-0.5*((x - [1])/[2])**2)', *d_mpe_fit['settings'][1:]))

        # set parameters
        if i == 0:
            ampl = fit_mpe.GetParameter(5)*root.TMath.Poisson(0, fit_mpe.GetParameter(0))
            mean = fit_mpe.GetParameter(1)
            width = fit_mpe.GetParameter(2)
            if width > 0:
                ampl /= (2*3.14*width**2.)**0.5
            l_functions[i].SetParameters(ampl, mean, width)
            
        # under amplified peak
        elif i == (num_photons + 1):
            ampl = fit_mpe.GetParameter(6)
            mean = fit_mpe.GetParameter(7)
            width = fit_mpe.GetParameter(8)
            if width > 0:
                ampl /= (2*3.14*width**2.)**0.5
            l_functions[i].SetParameters(ampl, mean, width)

        else:
            ampl = fit_mpe.GetParameter(5)*root.TMath.Poisson(i, fit_mpe.GetParameter(0))
            if use_ideal:
                mean = fit_mpe.GetParameter(3) * i
                width = fit_mpe.GetParameter(4)*i**0.5
            else:
                mean = fit_mpe.GetParameter(3)*i + fit_mpe.GetParameter(1)
                width = (fit_mpe.GetParameter(4)**2*i + fit_mpe.GetParameter(2)**2)**0.5

            if width > 0:
                ampl /= (2*3.14*width**2.)**0.5

            l_functions[i].SetParameters(ampl, mean, width)



        l_individual_integrals[i] = ampl*width*(2*3.1415)**0.5
        l_functions[i].SetLineColor(l_colors[i])
        l_functions[i].Draw('same')




    c1.Update()


    fitStatus = fitResult.CovMatrixStatus()
    if fitStatus != 3:
        neriX_analysis.failure_message('Fit failed, please adjust guesses and try again.')
        fit_successful = False
    else:
        neriX_analysis.success_message('Fit successful, please copy output to appropriate files.')
        fit_successful = True

    #if not os.path.exists(sPathToSaveOutput):
    #    os.makedirs(sPathToSaveOutput)

    fitter = root.TVirtualFitter.Fitter(fit_mpe)
    #fitter = root.TVirtualFitter.GetFitter()
    amin = np.asarray([0], dtype=np.float64)
    dum1 = np.asarray([0], dtype=np.float64)
    dum2 = np.asarray([0], dtype=np.float64)
    dum3 = np.asarray([0], dtype=np.int32)
    dum4 = np.asarray([0], dtype=np.int32)

    fitter.GetStats(amin, dum1, dum2, dum3, dum4)


    print '\n\namin for %d photons: %f' % (num_photons, amin)
    print 'fAmin for %d photons: %f\n\n' % (num_photons, root.gMinuit.fAmin)
    print fit_mpe.GetChisquare()


    # draw tpavetext
    tpt_mpe = root.TPaveText(.55,.75,.85,.85,'blNDC')
    tpt_mpe.AddText('#mu_{SPE} = %.2e #pm %.2e' % (fit_mpe.GetParameter(3), fit_mpe.GetParError(3)))
    tpt_mpe.AddText('#sigma_{SPE} = %.2e #pm %.2e' % (fit_mpe.GetParameter(4), fit_mpe.GetParError(4)))
    tpt_mpe.Draw('same')

    tpt_mpe.SetTextColor(root.kBlack)
    tpt_mpe.SetFillStyle(0)
    tpt_mpe.SetBorderSize(0)

    c1.Update()


    neriX_analysis.save_plot(l_plots, c1, 'mpe_poisson_gaussian_fit_%s' % (file_identifier))


    return (0,0,0)
Beispiel #3
0
            'amplitude*TMath::Gaus(x, mean, width)',
            'amplitude[100, 0, 1000], mean[1, 0, 2], width[0.5, 0, 2]', [0, 2])
        if args.conly:
            failing.Fill(cval, failed)
        else:
            failing.Fill(cval, lval, failed)
        xb = cbias.xaxis.find_bin(cval)
        if not args.conly:
            yb = cbias.yaxis.find_bin(lval)

        if args.usemean:
            bias = ufloat(csf.GetMean(), 0)
        elif args.asimov:
            bias = ufloat(csf, 0)
        else:
            csf.Fit(fcn, 'LQN0')
            bias = ufloat(fcn['mean'].value, fcn['mean'].error)
        bias -= cval
        bias /= cval
        bin = cbias[xb] if args.conly else cbias[xb, yb]
        bin.value = bias.nominal_value
        bin.error = bias.std_dev

        if not args.conly:
            if args.usemean:
                bias = ufloat(lsf.GetMean(), 0)
            elif args.asimov:
                bias = ufloat(lsf, 0)
            else:
                lsf.Fit(fcn, 'LQN0')
                bias = ufloat(fcn['mean'].value, fcn['mean'].error)
def unfolding_toy_diagnostics(indir, variable):

    plotter = BasePlotter(defaults={
        'clone': False,
        'name_canvas': True,
        'show_title': True,
        'save': {
            'png': True,
            'pdf': False
        }
    }, )
    styles = {
        'dots': {
            'linestyle': 0,
            'markerstyle': 21,
            'markercolor': 1
        },
        'compare': {
            'linesstyle': [1, 0],
            'markerstyle': [0, 21],
            'markercolor': [2, 1],
            'linecolor': [2, 1],
            'drawstyle': ['hist', 'pe'],
            'legendstyle': ['l', 'p']
        }
    }

    xaxislabel = set_pretty_label(variable)

    true_distribution = None

    curdir = os.getcwd()
    os.chdir(indir)
    toydirs = get_immediate_subdirectories(".")

    methods = []
    pulls_lists = {}
    pull_means_lists = {}
    pull_mean_errors_lists = {}
    pull_sums_lists = {}
    pull_sigmas_lists = {}
    pull_sigma_errors_lists = {}
    deltas_lists = {}
    delta_means_lists = {}
    delta_mean_errors_lists = {}
    delta_sigmas_lists = {}
    delta_sigma_errors_lists = {}
    ratio_sums_lists = {}
    nneg_bins_lists = {}
    unfoldeds_lists = {}
    unfolded_sigmas_lists = {}
    taus_lists = {}

    histos_created = False
    lists_created = False
    idir = 0
    true_distro = None
    #loop over toys
    for directory in toydirs:
        if not directory.startswith('toy_'): continue
        os.chdir(directory)
        log.debug('Inspecting toy %s' % directory)
        idir = idir + 1
        i = 0
        if not os.path.isfile("result_unfolding.root"):
            raise ValueError('root file not found in %s' % os.getcwd())
        with io.root_open("result_unfolding.root") as inputfile:
            log.debug('Iteration %s over the file' % i)
            i = i + 1
            if not methods:
                keys = [i.name for i in inputfile.keys()]
                for key in keys:
                    if hasattr(getattr(inputfile, key), "hdata_unfolded"):
                        methods.append(key)

            unfolded_hists = [
                inputfile.get('%s/hdata_unfolded' % i) for i in methods
            ]
            unfolded_wps_hists = [
                inputfile.get('%s/hdata_unfolded_ps_corrected' % i)
                for i in methods
            ]
            for unf, unfps, method in zip(unfolded_hists, unfolded_wps_hists,
                                          methods):
                unf.name = method
                unfps.name = method
            if true_distro is None:
                true_distribution = inputfile.true_distribution
                ROOT.TH1.AddDirectory(False)
                true_distro = true_distribution.Clone()
            taus = prettyjson.loads(inputfile.best_taus.GetTitle())
            if len(taus_lists) == 0:
                taus_lists = dict((i, []) for i in taus)
            for i, t in taus.iteritems():
                taus_lists[i].append(t)

            for histo in unfolded_hists:
                #create pull/delta containers during first iteration
                name = histo.name
                nbins = histo.nbins()
                log.debug("name = %s, n bins = %s" % (name, nbins))
                if not lists_created:
                    for ibin in range(1, nbins + 1):
                        outname = "pull_" + name + "_bin" + str(ibin)
                        pulls_lists[outname] = []
                        outname = "delta_" + name + "_bin" + str(ibin)
                        deltas_lists[outname] = []
                        outname = "unfolded_" + name + "_bin" + str(ibin)
                        unfoldeds_lists[outname] = []
                        unfolded_sigmas_lists[outname] = []
                    outname = "pull_" + name
                    pull_means_lists[outname] = {}
                    pull_mean_errors_lists[outname] = {}
                    pull_sigmas_lists[outname] = {}
                    pull_sigma_errors_lists[outname] = {}

                    outname = "delta_" + name
                    delta_means_lists[outname] = {}
                    delta_mean_errors_lists[outname] = {}
                    delta_sigmas_lists[outname] = {}
                    delta_sigma_errors_lists[outname] = {}

                for ibin in range(1, nbins + 1):
                    outname = "pull_" + name + "_bin" + str(ibin)
                    unfolded_bin_content = histo.GetBinContent(ibin)
                    unfolded_bin_error = histo.GetBinError(ibin)
                    true_bin_content = true_distro.GetBinContent(ibin)
                    true_bin_error = true_distro.GetBinError(ibin)
                    total_bin_error = math.sqrt(unfolded_bin_error**2)  #???
                    if (total_bin_error != 0):
                        pull = (unfolded_bin_content -
                                true_bin_content) / total_bin_error
                    else:
                        pull = 9999
                    log.debug(
                        'unfolded bin content %s +/- %s, true bin content %s, pull %s'
                        % (unfolded_bin_content, unfolded_bin_error,
                           true_bin_content, pull))
                    pulls_lists[outname].append(pull)
                    outname = "delta_" + name + "_bin" + str(ibin)
                    delta = unfolded_bin_content - true_bin_content
                    log.debug(
                        'unfolded bin content %s +/- %s, true bin content %s, delta %s'
                        % (unfolded_bin_content, unfolded_bin_error,
                           true_bin_content, delta))
                    deltas_lists[outname].append(delta)
                    outname = "unfolded_" + name + "_bin" + str(ibin)
                    unfoldeds_lists[outname].append(unfolded_bin_content)
                    unfolded_sigmas_lists[outname].append(unfolded_bin_error)

            nneg_bins_hists = [
                i for i in inputfile.keys()
                if i.GetName().startswith("nneg_bins")
            ]
            nneg_bins_hists = [asrootpy(i.ReadObj()) for i in nneg_bins_hists]
            for histo in nneg_bins_hists:
                #create pull/delta containers during first iteration
                name = histo.name
                nbins = histo.nbins()
                log.debug("name = %s, n bins = %s" % (name, nbins))
                if not lists_created:
                    outname = name
                    nneg_bins_lists[outname] = []
                outname = name
                nneg_bins_lists[outname].append(histo.GetBinContent(1))

            pull_sums_hists = [
                i for i in inputfile.keys()
                if i.GetName().startswith("sum_of_pulls")
            ]
            pull_sums_hists = [asrootpy(i.ReadObj()) for i in pull_sums_hists]
            for histo in pull_sums_hists:
                #create pull/delta containers during first iteration
                name = histo.name
                nbins = histo.nbins()
                log.debug("name = %s, n bins = %s" % (name, nbins))
                if not lists_created:
                    outname = name
                    pull_sums_lists[outname] = []
                outname = name
                pull_sums_lists[outname].append(histo.GetBinContent(1))

            ratio_sums_hists = [
                i for i in inputfile.keys()
                if i.GetName().startswith("sum_of_ratios")
            ]
            ratio_sums_hists = [
                asrootpy(i.ReadObj()) for i in ratio_sums_hists
            ]
            for histo in ratio_sums_hists:
                #create ratio/delta containers during first iteration
                name = histo.name
                nbins = histo.nbins()
                log.debug("name = %s, n bins = %s" % (name, nbins))
                if not lists_created:
                    outname = name
                    ratio_sums_lists[outname] = []
                outname = name
                ratio_sums_lists[outname].append(histo.GetBinContent(1))

            #after the first iteration on the file all the lists are created
            lists_created = True

        os.chdir("..")

    #create histograms
    #histo containers
    taus = {}
    for name, vals in taus_lists.iteritems():
        ROOT.TH1.AddDirectory(False)  #repeat, you never know
        val_min = min(vals)
        val_min = 0.8 * val_min if val_min > 0 else 1.2 * val_min
        val_max = max(vals)
        val_max = 0.8 * val_max if val_max < 0 else 1.2 * val_max
        if val_min == val_max:
            if tau_nbins % 2:  #if odd
                val_min, val_max = val_min - 0.01, val_min + 0.01
            else:
                brange = 0.02
                bwidth = brange / tau_nbins
                val_min, val_max = val_min - 0.01 + bwidth / 2., val_min + 0.01 + bwidth / 2.
        title = '#tau choice - %s ;#tau;N_{toys}' % (name)
        histo = Hist(tau_nbins, val_min, val_max, name=name, title=title)
        for val in vals:
            histo.Fill(val)
        taus[name] = histo

    pulls = {}
    for name, vals in pulls_lists.iteritems():
        ROOT.TH1.AddDirectory(False)  #repeat, you never know
        val_min = min(vals)
        val_min = 0.8 * val_min if val_min > 0 else 1.2 * val_min
        val_max = max(vals)
        val_max = 0.8 * val_max if val_max < 0 else 1.2 * val_max
        abs_max = max(abs(val_min), abs(val_max))
        if 'L_curve' in name:
            method = 'L_curve'
            binno = name.split('_')[-1]
        else:
            _, method, binno = tuple(name.split('_'))
        title = 'Pulls - %s - %s ;Pull;N_{toys}' % (binno, method)
        histo = Hist(pull_nbins, -abs_max, abs_max, name=name, title=title)
        for val in vals:
            histo.Fill(val)
        pulls[name] = histo

    deltas = {}
    for name, vals in deltas_lists.iteritems():
        ROOT.TH1.AddDirectory(False)  #repeat, you never know
        val_min = min(vals)
        val_min = 0.8 * val_min if val_min > 0 else 1.2 * val_min
        val_max = max(vals)
        val_max = 0.8 * val_max if val_max < 0 else 1.2 * val_max
        if 'L_curve' in name:
            method = 'L_curve'
            binno = name.split('_')[-1]
        else:
            _, method, binno = tuple(name.split('_'))
        title = 'Deltas - %s - %s ;Delta;N_{toys}' % (binno, method)
        histo = Hist(delta_nbins, val_min, val_max, name=name, title=title)
        for val in vals:
            histo.Fill(val)
        deltas[name] = histo

    unfoldeds = {}
    for name, vals in unfoldeds_lists.iteritems():
        ROOT.TH1.AddDirectory(False)  #repeat, you never know
        val_min = min(vals)
        val_min = 0.8 * val_min if val_min > 0 else 1.2 * val_min
        val_max = max(vals)
        val_max = 0.8 * val_max if val_max < 0 else 1.2 * val_max
        if 'L_curve' in name:
            method = 'L_curve'
            binno = name.split('_')[-1]
        else:
            _, method, binno = tuple(name.split('_'))
        title = 'Unfoldeds - %s - %s ;Unfolded;N_{toys}' % (binno, method)
        histo = Hist(unfolded_nbins, val_min, val_max, name=name, title=title)
        for val in vals:
            histo.Fill(val)
        unfoldeds[name] = histo

    nneg_bins = {}
    for name, vals, in nneg_bins_lists.iteritems():
        ROOT.TH1.AddDirectory(False)  #repeat, you never know
        val_min = min(vals)
        val_min = 0 if val_min > 0 else val_min - 1
        val_max = max(vals)
        val_max = 0 if val_max < 0 else val_max + 1
        if 'L_curve' in name:
            method = 'L_curve'
        else:
            set_trace()
            _, method, _ = tuple(name.split('_'))
        title = 'N of negative bins - %s ;N. neg bins;N_{toys}' % method
        histo = Hist(int(val_max - val_min + 1),
                     val_min,
                     val_max,
                     name=name,
                     title=title)
        for val in vals:
            histo.Fill(val)
        nneg_bins[name] = histo

    pull_sums = {}
    for name, vals in pull_sums_lists.iteritems():
        ROOT.TH1.AddDirectory(False)  #repeat, you never know
        val_min = min(vals)
        val_min = 0.8 * val_min if val_min > 0 else 1.2 * val_min
        val_max = max(vals)
        val_max = 0.8 * val_max if val_max < 0 else 1.2 * val_max
        if 'L_curve' in name:
            method = 'L_curve'
        else:
            set_trace()
            _, _, _, _, _, method = tuple(name.split('_'))
        title = 'Pull sums - %s ;#Sigma(pull)/N_{bins};N_{toys}' % method
        histo = Hist(unfolded_nbins, val_min, val_max, name=name, title=title)
        for val in vals:
            histo.Fill(val)
        pull_sums[name] = histo

    ratio_sums = {}
    for name, vals in ratio_sums_lists.iteritems():
        ROOT.TH1.AddDirectory(False)  #repeat, you never know
        val_min = min(vals)
        val_min = 0.8 * val_min if val_min > 0 else 1.2 * val_min
        val_max = max(vals)
        val_max = 0.8 * val_max if val_max < 0 else 1.2 * val_max
        if 'L_curve' in name:
            method = 'L_curve'
            binno = name.split('_')[-1]
        else:
            set_trace()
            _, _, _, _, _, method = tuple(name.split('_'))
        title = 'Ratio sums - %s;#Sigma(ratio)/N_{bins};N_{toys}' % method
        histo = Hist(unfolded_nbins, val_min, val_max, name=name, title=title)
        for val in vals:
            histo.Fill(val)
        ratio_sums[name] = histo

    unfolded_sigmas = {}
    for name, vals in unfolded_sigmas_lists.iteritems():
        ROOT.TH1.AddDirectory(False)  #repeat, you never know
        val_min = min(vals)
        val_min = 0.8 * val_min if val_min > 0 else 1.2 * val_min
        val_max = max(vals)
        val_max = 0.8 * val_max if val_max < 0 else 1.2 * val_max
        if 'L_curve' in name:
            method = 'L_curve'
            binno = name.split('_')[-1]
        else:
            _, method, binno = tuple(name.split('_'))
        title = 'Unfolded uncertainties - %s - %s ;Uncertainty;N_{toys}' % (
            binno, method)
        histo = Hist(unfolded_nbins, val_min, val_max, name=name, title=title)
        for val in vals:
            histo.Fill(val)
        unfolded_sigmas[name] = histo

    for name, histo in pulls.iteritems():
        log.debug("name is %s and object type is %s" % (name, type(histo)))
        histo.Fit("gaus", 'Q')
        if not histo.GetFunction("gaus"):
            log.warning("Function not found for histogram %s" % name)
            continue
        mean = histo.GetFunction("gaus").GetParameter(1)
        meanError = histo.GetFunction("gaus").GetParError(1)
        sigma = histo.GetFunction("gaus").GetParameter(2)
        sigmaError = histo.GetFunction("gaus").GetParError(2)

        general_name, idx = tuple(name.split('_bin'))
        idx = int(idx)

        pull_means_lists[general_name][idx] = mean
        pull_mean_errors_lists[general_name][idx] = meanError
        pull_sigmas_lists[general_name][idx] = sigma
        pull_sigma_errors_lists[general_name][idx] = sigmaError

    for name, histo in deltas.iteritems():
        log.debug("name is %s and object type is %s" % (name, type(histo)))
        histo.Fit("gaus", 'Q')
        if not histo.GetFunction("gaus"):
            log.warning("Function not found for histogram %s" % name)
            continue
        mean = histo.GetFunction("gaus").GetParameter(1)
        meanError = histo.GetFunction("gaus").GetParError(1)
        sigma = histo.GetFunction("gaus").GetParameter(2)
        sigmaError = histo.GetFunction("gaus").GetParError(2)

        general_name, idx = tuple(name.split('_bin'))
        idx = int(idx)

        delta_means_lists[general_name][idx] = mean
        delta_mean_errors_lists[general_name][idx] = meanError
        delta_sigmas_lists[general_name][idx] = sigma
        delta_sigma_errors_lists[general_name][idx] = sigmaError

    outfile = rootpy.io.File("unfolding_diagnostics.root", "RECREATE")
    outfile.cd()

    pull_means = {}
    pull_sigmas = {}
    pull_means_summary = {}
    pull_sigmas_summary = {}
    delta_means = {}
    delta_sigmas = {}
    delta_means_summary = {}
    delta_sigmas_summary = {}

    for outname, pmeans in pull_means_lists.iteritems():
        outname_mean = outname + "_mean"
        outtitle = "Pull means - " + outname + ";Pull mean; N_{toys}"
        pull_mean_min = min(pmeans.values())
        pull_mean_max = max(pmeans.values())
        pull_mean_newmin = pull_mean_min - (pull_mean_max -
                                            pull_mean_min) * 0.5
        pull_mean_newmax = pull_mean_max + (pull_mean_max -
                                            pull_mean_min) * 0.5
        pull_means[outname] = plotting.Hist(pull_mean_nbins,
                                            pull_mean_newmin,
                                            pull_mean_newmax,
                                            name=outname_mean,
                                            title=outtitle)

        outname_mean_summary = outname + "_mean_summary"
        outtitle_mean_summary = "Pull mean summary - " + outname
        histocloned = true_distro.Clone(outname_mean_summary)
        histocloned.Reset()
        histocloned.xaxis.title = xaxislabel
        histocloned.yaxis.title = 'Pull mean'
        histocloned.title = outtitle_mean_summary
        pull_means_summary[outname] = histocloned

        for idx, pmean in pmeans.iteritems():
            pull_means[outname].Fill(pmean)
            histocloned[idx].value = pmean
            histocloned[idx].error = pull_mean_errors_lists[outname][idx]
        histocloned.yaxis.SetRangeUser(min(pmeans.values()),
                                       max(pmeans.values()))

    for outname, psigmas in pull_sigmas_lists.iteritems():
        outname_sigma = outname + "_sigma"
        outtitle_sigma = "Pull #sigma's - " + outname + ";Pull #sigma; N_{toys}"
        pull_sigma_min = min(psigmas.values())
        pull_sigma_max = max(psigmas.values())
        pull_sigma_newmin = pull_sigma_min - (pull_sigma_max -
                                              pull_sigma_min) * 0.5
        pull_sigma_newmax = pull_sigma_max + (pull_sigma_max -
                                              pull_sigma_min) * 0.5
        pull_sigmas[outname] = plotting.Hist(pull_sigma_nbins,
                                             pull_sigma_newmin,
                                             pull_sigma_newmax,
                                             name=outname_sigma,
                                             title=outtitle_sigma)

        outname_sigma_summary = outname + "_sigma_summary"
        outtitle_sigma_summary = "Pull #sigma summary - " + outname
        histocloned = true_distro.Clone(outname_sigma_summary)
        histocloned.Reset()
        histocloned.xaxis.title = xaxislabel
        histocloned.yaxis.title = 'Pull #sigma'
        histocloned.title = outtitle_sigma_summary
        pull_sigmas_summary[outname] = histocloned

        for idx, psigma in psigmas.iteritems():
            pull_sigmas[outname].Fill(psigma)
            histocloned[idx].value = psigma
            histocloned[idx].error = pull_sigma_errors_lists[outname][idx]
        histocloned.yaxis.SetRangeUser(min(psigmas.values()),
                                       max(psigmas.values()))

    for outname, dmeans in delta_means_lists.iteritems():
        outname_mean = outname + "_mean"
        outtitle = "Delta means - " + outname + ";Delta mean; N_{toys}"
        delta_mean_min = min(dmeans.values())
        delta_mean_max = max(dmeans.values())
        delta_mean_newmin = delta_mean_min - (delta_mean_max -
                                              delta_mean_min) * 0.5
        delta_mean_newmax = delta_mean_max + (delta_mean_max -
                                              delta_mean_min) * 0.5
        delta_means[outname] = plotting.Hist(delta_mean_nbins,
                                             delta_mean_newmin,
                                             delta_mean_newmax,
                                             name=outname_mean,
                                             title=outtitle)

        outname_mean_summary = outname + "_mean_summary"
        outtitle_mean_summary = "Delta mean summary - " + outname
        histocloned = true_distro.Clone(outname_mean_summary)
        histocloned.Reset()
        histocloned.xaxis.title = xaxislabel
        histocloned.yaxis.title = 'Delta mean'
        histocloned.title = outtitle_mean_summary
        delta_means_summary[outname] = histocloned

        for idx, dmean in dmeans.iteritems():
            delta_means[outname].Fill(dmean)
            histocloned[idx].value = dmean
            histocloned[idx].error = delta_mean_errors_lists[outname][idx]
        histocloned.yaxis.SetRangeUser(min(dmeans.values()),
                                       max(dmeans.values()))

    for outname, dsigmas in delta_sigmas_lists.iteritems():
        outname_sigma = outname + "_sigma"
        outtitle_sigma = "Delta #sigma's - " + outname + ";Delta #sigma; N_{toys}"
        delta_sigma_min = min(dsigmas.values())
        delta_sigma_max = max(dsigmas.values())
        delta_sigma_newmin = delta_sigma_min - (delta_sigma_max -
                                                delta_sigma_min) * 0.5
        delta_sigma_newmax = delta_sigma_max + (delta_sigma_max -
                                                delta_sigma_min) * 0.5
        delta_sigmas[outname] = plotting.Hist(delta_sigma_nbins,
                                              delta_sigma_newmin,
                                              delta_sigma_newmax,
                                              name=outname_sigma,
                                              title=outtitle_sigma)

        outname_sigma_summary = outname + "_sigma_summary"
        outtitle_sigma_summary = "Delta #sigma summary - " + outname
        histocloned = true_distro.Clone(outname_sigma_summary)
        histocloned.Reset()
        histocloned.xaxis.title = xaxislabel
        histocloned.yaxis.title = 'Delta #sigma'
        histocloned.title = outtitle_sigma_summary
        delta_sigmas_summary[outname] = histocloned

        for idx, dsigma in dsigmas.iteritems():
            delta_sigmas[outname].Fill(dsigma)
            histocloned[idx].value = dsigma
            histocloned[idx].error = delta_sigma_errors_lists[outname][idx]
        histocloned.yaxis.SetRangeUser(min(dsigmas.values()),
                                       max(dsigmas.values()))

    unfolded_summary = {}
    unfolded_average = {}
    unfolded_envelope = {}
    for name, histo in unfoldeds.iteritems():
        log.debug("name is %s and object type is %s" % (name, type(histo)))
        histo.Fit("gaus", 'Q')
        if not histo.GetFunction("gaus"):
            log.warning("Function not found for histogram %s" % name)
            continue
        mean = histo.GetFunction("gaus").GetParameter(1)
        meanError = histo.GetFunction("gaus").GetParError(1)
        sigma = histo.GetFunction("gaus").GetParameter(2)
        sigmaError = histo.GetFunction("gaus").GetParError(2)

        general_name, idx = tuple(name.split('_bin'))
        idx = int(idx)

        if general_name not in unfolded_summary:
            histo = true_distro.Clone("%s_unfolded_summary" % general_name)
            outtitle_unfolded_summary = "Unfolded summary - " + general_name
            histo.Reset()
            histo.xaxis.title = xaxislabel
            histo.yaxis.title = 'N_{events}'
            histo.title = outtitle_unfolded_summary
            unfolded_summary[general_name] = histo

            unfolded_envelope[general_name] = histo.Clone(
                "%s_unfolded_envelope" % general_name)
            unfolded_average[general_name] = histo.Clone(
                "%s_unfolded_average" % general_name)

        unfolded_summary[general_name][idx].value = mean
        unfolded_summary[general_name][idx].error = meanError

        unfolded_envelope[general_name][idx].value = mean
        unfolded_envelope[general_name][idx].error = sigma

        unfolded_average[general_name][idx].value = mean
        unfolded_average[general_name][idx].error = \
           unfolded_sigmas['%s_bin%i' % (general_name, idx)].GetMean()

    plotter.set_subdir('taus')
    for name, histo in taus.iteritems():
        #canvas = plotter.create_and_write_canvas_single(0, 21, 1, False, False, histo, write=False)
        plotter.canvas.cd()
        histo = plotter.plot(histo, **styles['dots'])
        histo.SetStats(True)

        info = plotter.make_text_box(
            'mode #tau = %.5f' % histo[histo.GetMaximumBin()].x.center,
            position=(plotter.pad.GetLeftMargin(), plotter.pad.GetTopMargin(),
                      0.3, 0.025))
        info.Draw()

        plotter.save()
        histo.Write()
        plotter.canvas.Write()

    plotter.set_subdir('pulls')
    for name, histo in pulls.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        histo.SetStats(True)
        plotter.save()
        histo.Write()
        plotter.canvas.Write()
    for name, histo in pull_means.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        histo.Write()
        plotter.save()
    for name, histo in pull_sigmas.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        histo.Write()
        plotter.save()

    plotter.set_subdir('pull_summaries')
    for name, histo in pull_means_summary.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        #histo.SetStats(True)
        line = ROOT.TLine(histo.GetBinLowEdge(1), 0,
                          histo.GetBinLowEdge(histo.GetNbinsX() + 1), 0)
        line.Draw("same")
        plotter.save()
        histo.Write()
        plotter.canvas.Write()
    for name, histo in pull_sigmas_summary.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        #histo.SetStats(True)
        line = ROOT.TLine(histo.GetBinLowEdge(1), 1,
                          histo.GetBinLowEdge(histo.GetNbinsX() + 1), 1)
        line.Draw("same")
        plotter.save()
        histo.Write()
        plotter.canvas.Write()

    plotter.set_subdir('deltas')
    for name, histo in deltas.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        histo.SetStats(True)
        plotter.save()
        histo.Write()
        plotter.canvas.Write()
    for name, histo in delta_means.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        histo.Write()
        plotter.save()
    for name, histo in delta_sigmas.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        histo.Write()
        plotter.save()

    plotter.set_subdir('delta_summaries')
    for name, histo in delta_means_summary.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        #histo.SetStats(True)
        plotter.save()
        histo.Write()
        plotter.canvas.Write()
    for name, histo in delta_sigmas_summary.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        #histo.SetStats(True)
        plotter.save()
        histo.Write()
        plotter.canvas.Write()

    plotter.set_subdir('unfolding_unc')
    for name, histo in unfolded_sigmas.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        histo.SetStats(True)
        plotter.save()
        histo.Write()
        plotter.canvas.Write()

    plotter.set_subdir('unfolded')
    for name, histo in unfoldeds.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        histo.SetStats(True)
        plotter.save()
        histo.Write()
        plotter.canvas.Write()

    plotter.set_subdir('unfolded_summaries')
    for name, histo in unfolded_summary.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        histo.SetStats(True)
        plotter.save()
        histo.Write()
        plotter.canvas.Write()

    for name, histo in unfolded_summary.iteritems():
        leg = LegendDefinition("Unfolding comparison",
                               'NE',
                               labels=['Truth', 'Unfolded'])
        plotter.overlay_and_compare([true_distro],
                                    histo,
                                    legend_def=leg,
                                    **styles['compare'])
        plotter.canvas.name = 'Pull_' + name
        plotter.save()
        plotter.canvas.Write()
        plotter.overlay_and_compare([true_distro],
                                    histo,
                                    legend_def=leg,
                                    method='ratio',
                                    **styles['compare'])
        plotter.canvas.name = 'Ratio_' + name
        plotter.save()
        plotter.canvas.Write()

    plotter.set_subdir('unfolded_average')
    for name, histo in unfolded_average.iteritems():
        leg = LegendDefinition("Unfolding comparison",
                               'NE',
                               labels=['Truth', 'Unfolded'])
        #set_trace()
        plotter.overlay_and_compare([true_distro],
                                    histo,
                                    legend_def=leg,
                                    **styles['compare'])
        plotter.canvas.name = 'Pull_' + name
        plotter.save()
        plotter.canvas.Write()
        plotter.overlay_and_compare([true_distro],
                                    histo,
                                    legend_def=leg,
                                    method='ratio',
                                    **styles['compare'])
        plotter.canvas.name = 'Ratio_' + name
        plotter.save()
        plotter.canvas.Write()

    plotter.set_subdir('unfolded_envelope')
    for name, histo in unfolded_envelope.iteritems():
        leg = LegendDefinition("Unfolding comparison",
                               'NE',
                               labels=['Truth', 'Unfolded'])
        plotter.overlay_and_compare([true_distro],
                                    histo,
                                    legend_def=leg,
                                    **styles['compare'])
        plotter.canvas.name = 'Pull_' + name
        plotter.save()
        plotter.canvas.Write()
        plotter.overlay_and_compare([true_distro],
                                    histo,
                                    legend_def=leg,
                                    method='ratio',
                                    **styles['compare'])
        plotter.canvas.name = 'Ratio_' + name
        plotter.save()
        plotter.canvas.Write()

    plotter.set_subdir('figures_of_merit')
    for name, histo in nneg_bins.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        histo.SetStats(True)
        plotter.save()
        histo.Write()
        plotter.canvas.Write()
    for name, histo in pull_sums.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        histo.SetStats(True)
        plotter.save()
        histo.Write()
        plotter.canvas.Write()
    for name, histo in ratio_sums.iteritems():
        histo = plotter.plot(histo, **styles['dots'])
        histo.SetStats(True)
        plotter.save()
        histo.Write()
        plotter.canvas.Write()

    outfile.close()
    os.chdir(curdir)