コード例 #1
0
def StorageLifetime(ex):
    print('\nAnalyzing TCN' + ex['TCN'])

    if len(ex['start']) == 0:
        print('Found no cycles with run numbers {0}!'.format(ex['runs']))
        return

    ex['li6backgroundrate'], ex['li6backgroundrateerr'] = UCN.BackgroundRate(
        ex['li6background'], ex['backgroundduration'])
    print('Li6 detector background rate: {0} +/- {1} 1/s'.format(
        ex['li6backgroundrate'], ex['li6backgroundrateerr']))
    beam = [numpy.mean(cur) for cur in ex['beamcurrent']
            ], [numpy.std(cur) for cur in ex['beamcurrent']]
    ex['li6irradiationrate'], ex[
        'li6irradiationrateerr'] = UCN.SubtractBackgroundAndNormalizeRate(
            ex['li6irradiation'], ex['irradiationduration'], 'li6', beam[0],
            beam[1])

    # report average monitor counts, range of beam current, range of He-II temperature
    monitoravg = numpy.average(ex['monitorcounts'], None,
                               [1. / m for m in ex['monitorcounts']], True)
    print 'Monitor counts: {0} +/- {1}'.format(monitoravg[0],
                                               1. / math.sqrt(monitoravg[1]))
    print('Beam current from {0} to {1} uA'.format(
        min(min(c) for c in ex['beamcurrent']),
        max(max(c) for c in ex['beamcurrent'])))
    print 'Temperatures from {0} to {1} K'.format(min(ex['mintemperature']),
                                                  max(ex['maxtemperature']))

    x = ex['storageduration']
    xerr = [0. for _ in ex['storageduration']]

    y, yerr = UCN.SubtractBackgroundAndNormalize(
        ex['li6counts'], ex['countduration'], 'li6', ex['monitorcounts'],
        [math.sqrt(m) for m in ex['monitorcounts']])

    # plot normalized, background corrected counts vs storage time
    graph = ROOT.TGraphErrors(len(x), numpy.array(x), numpy.array(y),
                              numpy.array(xerr), numpy.array(yerr))
    graph.SetTitle(
        'TCN{0} (single exponential fit, with background subtracted, normalized to monitor detector)'
        .format(ex['TCN']))
    graph.GetXaxis().SetTitle('Storage time (s)')
    graph.GetYaxis().SetTitle('UCN-count-to-monitor ratio')
    #  graph.SetMarkerStyle(20)

    # do single exponential fit
    f = graph.Fit(UCN.SingleExpo(), 'SQB', '', 0., 1000.)

    canvas = ROOT.TCanvas('c', 'c')
    canvas.SetLogy()
    graph.Draw('AP')
    pdf = 'TCN{0}.pdf'.format(ex['TCN'])
    canvas.Print(pdf + '(')
    ex['tau'] = f.GetParams()[1]
    ex['tauerr'] = f.GetErrors()[1]
    print(
        '{0} +/- {1} (single exponential fit, with background subtracted, normalized to monitor detector)'
        .format(ex['tau'], ex['tauerr']))

    #do single exponential fit with data point at 0 excluded
    f = graph.Fit(UCN.SingleExpo(), 'SQB', '', 1., 1000.)
    graph.SetTitle(
        'TCN{0} (single exponential fit, with background subtracted, normalized to monitor detector, 0s excluded)'
        .format(ex['TCN']))
    graph.Draw('AP')
    canvas.Print(pdf)

    # do double exponential fit
    graph.SetTitle(
        'TCN{0} (double exponential fit, with background subtracted, normalized to monitor detector)'
        .format(ex['TCN']))
    f = graph.Fit(UCN.DoubleExpo(), 'SQB')
    graph.Draw('AP')
    canvas.Print(pdf)
    print(
        '{0} +/- {1}, {2} +/- {3} (double exponential fit, with background subtracted, normalized to monitor detector)'
        .format(f.GetParams()[1],
                f.GetErrors()[1],
                f.GetParams()[3],
                f.GetErrors()[3]))

    # plot uncorrected UCN counts
    y = [float(c) for c in ex['li6counts']]
    yerr = [math.sqrt(c) for c in ex['li6counts']]
    graph = ROOT.TGraphErrors(len(x), numpy.array(x), numpy.array(y),
                              numpy.array(xerr), numpy.array(yerr))
    graph.SetTitle(
        'TCN{0} (single exponential fit + background, unnormalized)'.format(
            ex['TCN']))
    graph.GetXaxis().SetTitle('Storage time (s)')
    graph.GetYaxis().SetTitle('UCN count')
    # do single exponential fit with background
    f = graph.Fit(UCN.SingleExpoWithBackground(), 'SQB')
    graph.Draw('AP')
    canvas.Print(pdf)
    print(
        '{0} +/- {1} (single exponential fit with {2} +/- {3} background, unnormalized)'
        .format(f.GetParams()[1],
                f.GetErrors()[1],
                f.GetParams()[2],
                f.GetErrors()[2]))

    mtau = []
    mtauerr = []
    for he3rate, m, s in zip(ex['he3rate'], ex['monitorduration'],
                             ex['storageduration']):
        fitstart = m + 5
        fitend = m + s
        if fitend > fitstart + 10 and he3rate.Integral(
                he3rate.FindBin(fitstart), he3rate.FindBin(fitend)) > 0:
            f = he3rate.Fit(UCN.SingleExpo(), 'SQB', '', fitstart, fitend)
            he3rate.Draw()
            canvas.Print(pdf)  # print fitted He3 rate to pdf
            mtau.append(f.GetParams()[1])
            mtauerr.append(f.GetErrors()[1])

    # print average storage lifetime from He3 fits to pdf
    canvas = ROOT.TCanvas('c', 'c')
    if len(mtau) > 0:
        tauavg = numpy.average(mtau, None, [1. / dt**2 for dt in mtauerr],
                               True)
        label = ROOT.TLatex(0.1, 0.6, 'Average lifetime from He3 data:')
        label.Draw()
        label2 = ROOT.TLatex(
            0.1, 0.5, '#tau = {0} +/- {1} s'.format(tauavg[0],
                                                    1. / tauavg[1]**2))
        label2.Draw()
        print(
            '{0} +/- {1} (single exponential fit to rate in monitor detector during storage period)'
            .format(tauavg[0], 1. / tauavg[1]**2))
    canvas.Print(pdf + ')')
コード例 #2
0
def StorageLifetime(ex, FitResult=None):
    print('\nAnalyzing TCN{0} in runs {1}'.format(ex['TCN'], ex['runs']))

    if len(ex['start']) == 0:
        print('Found no cycles with run numbers {0}!'.format(ex['runs']))
        return

    # report start time
    print(datetime.datetime.fromtimestamp(min(ex['start'])))

    # report range of beam current
    print('Beam current from {0:.3} to {1:.3} uA'.format(
        min(min(c) for c in ex['beamcurrent']),
        max(max(c) for c in ex['beamcurrent'])))

    # report range of temperature and vapor pressure
    print('Temperatures from {0:.3} to {1:.3} K'.format(
        min(ex['mintemperature']), max(ex['maxtemperature'])))
    print('Vapor pressure from {0:.3} to {1:.3} torr'.format(
        min(ex['minvaporpressure']), max(ex['maxvaporpressure'])))

    beam = [numpy.mean(cur) for cur in ex['beamcurrent']
            ], [numpy.std(cur) for cur in ex['beamcurrent']]
    canvas = ROOT.TCanvas('c1', 'c1')
    canvas.SetLogy()
    for det in ['li6', 'he3']:
        ex[det +
           'backgroundrate'], ex[det +
                                 'backgroundrateerr'] = UCN.BackgroundRate(
                                     ex[det + 'background'],
                                     ex['backgroundduration'])
        ex[det + 'irradiationrate'], ex[
            det +
            'irradiationrateerr'] = UCN.SubtractBackgroundAndNormalizeRate(
                ex[det + 'irradiation'], ex['irradiationduration'], det,
                beam[0], beam[1])
        print(det + ' detector background rate: {0:.4} +/- {1:.2} 1/s'.format(
            ex[det + 'backgroundrate'], ex[det + 'backgroundrateerr']))

        x = numpy.array(ex['storageduration'])
        xerr = numpy.array([0. for _ in x])
        # subtract background from UCN counts
        ex[det + 'counts_normalized'], ex[
            det +
            'counts_normalized_err'] = UCN.SubtractBackgroundAndNormalize(
                ex[det + 'counts'], ex['countduration'], det, beam[0], beam[1])
        y = numpy.array(ex[det + 'counts_normalized'])
        yerr = numpy.array(ex[det + 'counts_normalized_err'])

        # plot normalized Li6 counts vs storage time
        graph = ROOT.TGraphErrors(len(x), x, y, xerr, yerr)
        graph.SetTitle(
            'TCN{0} ({1} detector, single exponential fit, background subtracted, normalized to beam current)'
            .format(ex['TCN'], det))
        graph.GetXaxis().SetTitle('Storage time (s)')
        graph.GetYaxis().SetTitle('UCN count (#muA^{-1})')
        #    graph.SetMarkerStyle(20)
        # do single exponential fit
        f = graph.Fit(UCN.SingleExpo(), 'SQB')
        if sum(y) > 0 and f.Error(1) < 5.:
            ex[det + 'tau'] = f.Parameter(1)
            ex[det + 'tauerr'] = f.Error(1) * max(f.Chi2() / f.Ndf(), 1.)
        else:
            print(
                'SKIPPING lifetime measurement from {0} detector in run(s) {1} because there were no counts detected or the error is larger than 5 s.'
                .format(det, ex['runs']))
            ex[det + 'tau'] = 0.
            ex[det + 'tauerr'] = 0.
        print(
            '{0:.4} +/- {1:.2} ({2} detector, single exponential fit, background subtracted, normalized to beam current)'
            .format(ex[det + 'tau'], ex[det + 'tauerr'], det))
        graph.Draw('AP')
        pdf = 'TCN{0}_{1}.pdf'.format(ex['TCN'], ex['runs'][0])
        if det == 'li6':
            canvas.Print(pdf + '(')
        else:
            canvas.Print(pdf)

    if FitResult:
        r = DoCombinedFit([ex], pdf, FitResult)
        print('{0:.4} +/- {1:.2} (wall-storage lifetime from combined fit)'.
              format(ex['tau_wall'], ex['tau_wallerr']))

    canvas.SetLogy(0)

    UCN.PrintTemperatureVsCycle(ex, pdf)

    ex['channels'].Draw()
    canvas.Print(pdf + ')')

    # return result from primary detector
    if max(ex['li6counts']) > max(ex['he3counts']):
        ex['tau'] = ex['li6tau']
        ex['tauerr'] = ex['li6tauerr']
    else:
        ex['tau'] = ex['he3tau']
        ex['tauerr'] = ex['he3tauerr']
コード例 #3
0
def Transmission(ex):
    print('\nAnalyzing TCN{0}'.format(ex['TCN']))

    if len(ex['start']) == 0:
        print('Found no cycles with run numbers {0}!'.format(ex['runs']))
        return

    ex['li6backgroundrate'], ex['li6backgroundrateerr'] = UCN.BackgroundRate(
        ex['li6background'], ex['backgroundduration'])
    ex['li6irradiationrate'], ex['li6irradiationrateerr'] = UCN.SubtractBackgroundAndNormalizeRate(ex['li6irradiation'], ex['irradiationduration'], 'li6', \
                                                                                                   [numpy.mean(cur) for cur in ex['beamcurrent']], [numpy.std(cur) for cur in ex['beamcurrent']])
    print('Li6 background rate: {0} +/- {1} 1/s'.format(
        ex['li6backgroundrate'], ex['li6backgroundrateerr']))

    # report average monitor counts
    monitoravg = numpy.average(ex['monitorcounts'], None,
                               [1. / m for m in ex['monitorcounts']], True)
    print('Monitor counts: {0} +/- {1}'.format(monitoravg[0],
                                               1. / math.sqrt(monitoravg[1])))

    # report range of beam current
    print('Beam current from {0} to {1} uA'.format(
        min(min(c) for c in ex['beamcurrent']),
        max(max(c) for c in ex['beamcurrent'])))

    # report He-II temperature range
    print('Temperatures from {0} to {1} K'.format(min(ex['mintemperature']),
                                                  max(ex['maxtemperature'])))

    canvas = ROOT.TCanvas('c', 'c')
    pdf = 'TCN{0}.pdf'.format(ex['TCN'])

    # plot ratio of background-corrected counts to monitor counts during counting
    y, yerr = UCN.SubtractBackgroundAndNormalize(
        ex['li6counts'], ex['countduration'], 'li6', ex['monitorcounts'],
        [math.sqrt(c) for c in ex['monitorcounts']])
    graph = ROOT.TGraphErrors(len(y), numpy.array(ex['cyclenumber']),
                              numpy.array(y),
                              numpy.array([0. for _ in ex['cyclenumber']]),
                              numpy.array(yerr))
    graph.SetTitle('TCN{0}, normalized during counting'.format(ex['TCN']))
    graph.GetXaxis().SetTitle('Cycle')
    graph.GetXaxis().SetLimits(0., max(ex['cyclenumber']))
    graph.GetYaxis().SetTitle('UCN-count-to-monitor ratio')
    graph.SetMarkerStyle(20)
    transfit = ROOT.TF1('transfit', 'pol0', 0, 100)
    transfit.SetParName(0, '#bar{R}_{c}')
    f = graph.Fit(transfit, 'QS')
    graph.Draw('AP')
    canvas.Print(pdf + '(')

    ex['transmission'] = f.GetParams()[0]
    ex['transmissionerr'] = f.GetErrors()[0] * max(f.Chi2() / f.Ndf(), 1.)
    print('Li6-to-He3 ratio during counting: {0} +/- {1}'.format(
        ex['transmission'], ex['transmissionerr']))

    if min(ex['monitorcounts2']) > 0:
        # plot ratio of background-corrected counts to monitor counts during irradiation
        y, yerr = UCN.SubtractBackgroundAndNormalize(
            ex['li6counts2'], ex['countduration2'], 'li6',
            ex['monitorcounts2'], [math.sqrt(c) for c in ex['monitorcounts2']])
        graph = ROOT.TGraphErrors(len(y), numpy.array(ex['cyclenumber']),
                                  numpy.array(y),
                                  numpy.array([0. for _ in ex['cyclenumber']]),
                                  numpy.array(yerr))
        graph.SetTitle('TCN{0}, normalized during irradiation'.format(
            ex['TCN']))
        graph.GetXaxis().SetTitle('Cycle')
        graph.GetXaxis().SetLimits(0., max(ex['cyclenumber']))
        graph.GetYaxis().SetTitle('UCN-count-to-monitor ratio')
        graph.SetMarkerStyle(20)
        transfit.SetParName(0, '#bar{R}_{i}')
        f = graph.Fit(transfit, 'QS')
        graph.Draw('AP')
        canvas.Print(pdf)

        ex['transmission2'] = f.GetParams()[0]
        ex['transmission2err'] = f.GetErrors()[0] * max(f.Chi2() / f.Ndf(), 1.)
        print('Li6-to-He3 ratio during irradiation: {0} +/- {1}\n'.format(
            ex['transmission2'], ex['transmission2err']))

    UCN.PrintTemperatureVsCycle(ex, pdf)

    he3axis = ex['He3rate'][0].GetXaxis()
    he3rate = ROOT.TH1D('TCN{0}_He3'.format(ex['TCN']),
                        ';Time (s); He3 rate (1/s)', he3axis.GetNbins(),
                        he3axis.GetXmin(), he3axis.GetXmax())
    he3rate.SetDirectory(0)
    for he3 in ex['He3rate']:
        he3rate.Add(he3)
    satfit = ROOT.TF1(
        'satfit',
        '[0]*(erfc(sqrt([1]/x)-sqrt(x/[2]))-exp(4*sqrt([1]/[2]))*erfc(sqrt([1]/x)+sqrt(x/[2])))',
        0, 60)
    for i, p in enumerate(
            zip([500., 12., 30.], [10000., 100., 100.],
                ['p_{0}', '#tau_{d}', '#tau'])):
        satfit.SetParameter(i, p[0])
        satfit.SetParName(i, p[2])
    fit = he3rate.Fit(satfit, 'MRSQ')
    he3rate.Draw()
    canvas.Print(pdf)

    li6fit = ROOT.TF1(
        'li6fit',
        '(x<60 + [0]?0:[1])*(1 - exp(-(x - 60 - [0])/[2]))*(exp(-(x - 60 - [0])/[3]) + [4]*exp(-(x - 60 - [0])/[5]) +[6]*exp(-(x - 60 - [0])/[7])) + [8]',
        60, 180)
    li6axis = ex['Li6rate'][0].GetXaxis()
    binwidth = li6axis.GetBinWidth(1)
    li6rate = ROOT.TH1D('TCN{0}_Li6'.format(ex['TCN']),
                        ';Time (s); Li6 rate (1/{0}s)'.format(binwidth),
                        li6axis.GetNbins(), li6axis.GetXmin(),
                        li6axis.GetXmax())
    li6rate.SetDirectory(0)
    for h in ex['Li6rate']:
        li6rate.Add(h)
    li6fit.SetNpx(li6rate.GetNbinsX())
    li6fit.SetParameters(1.5, 1000., 0.2, 1.5, 1., 14., 0.1, 30.)
    for i, p in enumerate(
            zip([5, 1e5, 5., 10., 10, 30., 10., 100.], [
                't_{d}', 'p_{0}', '#tau_{rise}', '#tau_{1}', 'N_{2}',
                '#tau_{2}', 'N_{3}', '#tau_{3}'
            ])):
        li6fit.SetParLimits(i, 0., p[0])
        li6fit.SetParName(i, p[1])
    li6fit.FixParameter(8, UCN.DetectorBackground['li6'][0] * binwidth)
    li6fit.SetParError(8, UCN.DetectorBackground['li6'][1] * binwidth)
    li6rate.Fit(li6fit, 'MRSQL', '')
    #  canvas.SetLogy()
    li6rate.Draw()
    canvas.Print(pdf)
    #  canvas.SetLogy(0)

    li6background = ROOT.TH1D(
        'Li6background',
        ';Time (s); Li6 background rate (1/{0}s)'.format(binwidth),
        li6axis.GetNbins(), li6axis.GetXmin(), li6axis.GetXmax())
    li6background.SetDirectory(0)
    for b in range(li6background.GetNbinsX()):
        li6background.SetBinContent(
            b, UCN.DetectorBackground['li6'][0] * li6background.GetBinWidth(b))
        li6background.SetBinError(
            b, UCN.DetectorBackground['li6'][1] * li6background.GetBinWidth(b))
    li6background.Sumw2()

    li6norm = ROOT.TH1D(
        'TCN{0}_Li6_norm'.format(ex['TCN']),
        ';Time (s);Li6 rate normalized during counting (1/{0}s)'.format(
            binwidth), int(li6axis.GetNbins() / 4.), li6axis.GetXmin(),
        li6axis.GetXmax())
    li6norm.SetDirectory(0)
    for li6, m in zip(ex['Li6rate'], ex['monitorcounts']):
        li6copy = li6.Clone()
        li6copy.Add(li6background, -1.)
        li6copy.Rebin(4)
        normhist = ROOT.TH1D('normhist', ';Time (s);Normalization factor',
                             int(li6axis.GetNbins() / 4.), li6axis.GetXmin(),
                             li6axis.GetXmax())
        for b in range(normhist.GetNbinsX()):
            normhist.SetBinContent(b, m)
            normhist.SetBinError(b, math.sqrt(m))
        normhist.Sumw2()
        li6copy.Divide(normhist)
        li6copy.SetBit(ROOT.TH1.kIsAverage)
        li6norm.Add(li6copy)
        li6norm.SetBit(ROOT.TH1.kIsAverage)
    li6norm.Draw()
    canvas.Print(pdf)
    ex['Li6rate_normalized'] = li6norm

    li6norm2 = ROOT.TH1D(
        'TCN{0}_Li6_norm'.format(ex['TCN']),
        ';Time (s);Li6 rate normalized during irradiation (1/{0}s)'.format(
            binwidth), int(li6axis.GetNbins() / 4.), li6axis.GetXmin(),
        li6axis.GetXmax())
    li6norm2.SetDirectory(0)
    for li6, m in zip(ex['Li6rate'], ex['monitorcounts2']):
        li6copy = li6.Clone()
        li6copy.Add(li6background, -1.)
        li6copy.Rebin(4)
        normhist2 = ROOT.TH1D('normhist', ';Time (s);Normalization factor',
                              int(li6axis.GetNbins() / 4.), li6axis.GetXmin(),
                              li6axis.GetXmax())
        for b in range(normhist2.GetNbinsX()):
            normhist2.SetBinContent(b, m)
            normhist2.SetBinError(b, math.sqrt(m))
        normhist2.Sumw2()
        li6copy.Divide(normhist2)
        li6copy.SetBit(ROOT.TH1.kIsAverage)
        li6norm2.Add(li6copy)
        li6norm2.SetBit(ROOT.TH1.kIsAverage)
    li6norm2.Draw()
    canvas.Print(pdf)
    ex['Li6rate_normalized2'] = li6norm2

    li6rate.SetStats(False)
    li6rate.GetYaxis().SetTitle('Ratio of cumulated rates')
    li6rate.Add(li6background, -len(ex['Li6rate']))
    li6rate.Rebin(int(1. / binwidth))
    li6rate.Divide(he3rate)
    li6rate.Draw('HIST')
    canvas.Print(pdf)

    rateratio = ROOT.TH1D('TCN{0}_ratio'.format(ex['TCN']),
                          ';Time (s);Average rate ratio',
                          int(he3axis.GetNbins() / 10.), he3axis.GetXmin(),
                          he3axis.GetXmax())
    rateratio.SetDirectory(0)
    for li6, he3 in zip(ex['Li6rate'], ex['He3rate']):
        li6.Add(li6background, -1)
        li6.Rebin(int(10. / binwidth))
        he3.Rebin(10)
        li6.Divide(he3)
        #    li6.Draw()
        #    canvas.Print(pdf)
        li6.SetBit(ROOT.TH1.kIsAverage)
        rateratio.Add(li6)
        rateratio.SetBit(ROOT.TH1.kIsAverage)
    rateratio.Draw()
    canvas.Print(pdf)

    ex['channels'].Draw()
    canvas.Print(pdf)

    window = ROOT.TH1I('li6window',
                       'Li6 window;Time after valve opened (s);Frequency', 100,
                       0., 5.)
    for w in ex['li6window']:
        window.Fill(w[0])
    window.Draw()
    canvas.Print(pdf + ')')
コード例 #4
0
def StorageLifetime(ex):
  print('\nAnalyzing TCN' + ex['TCN'])
  
  if len(ex['start']) == 0:
    print('Found no cycles with run numbers {0}!'.format(ex['runs']))
    return

  canvas = ROOT.TCanvas('c', 'c')
  pdf = 'TCN{0}.pdf'.format(ex['TCN'])

  # subtract background from Li6 counts and normalize to monitor counts
  y, yerr = UCN.SubtractBackgroundAndNormalize(ex['li6counts'], ex['countduration'], 'li6', ex['monitorcounts2'], [math.sqrt(m) for m in ex['monitorcounts2']])

  x = ex['storageduration']
  xerr = [0. for _ in ex['storageduration']]  

  # plot normalized, background corrected counts vs storage time
  graph = ROOT.TGraphErrors(len(x), numpy.array(x), numpy.array(y), numpy.array(xerr), numpy.array(yerr))
  graph.SetTitle('TCN{0} (single exponential fit, with background subtracted, normalized to monitor detector)'.format(ex['TCN']))
  graph.GetXaxis().SetTitle('Storage time (s)')
  graph.GetYaxis().SetTitle('UCN-count-to-monitor ratio')
  graph.SetMarkerStyle(20)

  canvas.SetLogy()

  #do single exponential fit with data point at 0 excluded
  f = graph.Fit(UCN.SingleExpo(), 'SQB', '', 1., 1000.)
  graph.SetTitle('TCN{0} (single exponential fit, with background subtracted, normalized to monitor detector, 0s excluded)'.format(ex['TCN']))
  graph.Draw('AP')
  canvas.Print(pdf + '(')
  ex['tau'] = f.GetParams()[1]
  ex['tauerr'] = f.GetErrors()[1]*max(math.sqrt(f.Chi2()/f.Ndf()), 1.0)

  # do double exponential fit
  graph.SetTitle('TCN{0} (double exponential fit, with background subtracted, normalized to monitor detector, 0s excluded)'.format(ex['TCN']))
  f = graph.Fit(UCN.DoubleExpo(), 'SQB', '', 1., 1000.)
  graph.Draw('AP')
  canvas.Print(pdf)
  print('{0} +/- {1}, {2} +/- {3} (double exponential fit, with background subtracted, normalized to monitor detector, 0s excluded)'.format(f.GetParams()[1], f.GetErrors()[1], f.GetParams()[3], f.GetErrors()[3]))
  
  # plot uncorrected UCN counts
#  y = [float(c) for c in ex['li6counts']]
#  yerr = [math.sqrt(c) for c in ex['li6counts']]
#  graph = ROOT.TGraphErrors(len(x), numpy.array(x), numpy.array(y), numpy.array(xerr), numpy.array(yerr))
#  graph.SetTitle('TCN{0} (single exponential fit + background, unnormalized)'.format(ex['TCN']))
#  graph.GetXaxis().SetTitle('Storage time (s)')
#  graph.GetYaxis().SetTitle('UCN count')
  # do single exponential fit with background
#  f = graph.Fit(UCN.SingleExpoWithBackground(), 'SQB')
#  graph.Draw('AP')
#  canvas.Print(pdf)
#  print('{0} +/- {1} (single exponential fit with {2} +/- {3} background, unnormalized)'.format(f.GetParams()[1], f.GetErrors()[1], f.GetParams()[2], f.GetErrors()[2]))

  # draw plot of temperature during each cycle
  UCN.PrintTemperatureVsCycle(ex, pdf)

  mtau = []
  mtauerr = []
  # fit single exponential to He3 count-rate histogram during storage period (pinhole method)
  for he3rate, m, s, c in zip(ex['he3rate'], ex['monitorduration'], ex['storageduration'], ex['countduration']):
    fitstart = m + 5
    fitend = m + s
#    if not ex['pinhole']:
#      fitend = fitend + c
    if fitend > fitstart + 10 and he3rate.Integral(he3rate.FindBin(fitstart), he3rate.FindBin(fitend)) > 0:
      f = he3rate.Fit(UCN.SingleExpo(), 'SQB', '', fitstart, fitend)
      he3rate.SetTitle('TCN{0} (He3 rate)'.format(ex['TCN']))
      he3rate.Draw()
      canvas.Print(pdf) # print fitted He3 rate to pdf
      mtau.append(f.GetParams()[1])
      mtauerr.append(f.GetErrors()[1]*max(math.sqrt(f.Chi2()/f.Ndf()), 1.0))
	  
  # print average storage lifetime from He3 fits to pdf
  canvas = ROOT.TCanvas('c','c')
  if len(mtau) > 0:
    he3tau = ROOT.TGraphErrors(len(mtau), numpy.array(ex['cyclenumber']), numpy.array(mtau), numpy.array([0. for _ in mtau]), numpy.array(mtauerr))
    fit = he3tau.Fit('pol0', 'SQ')
    ex['pinholetau'] = fit.Parameter(0)
    ex['pinholetauerr'] = fit.ParError(0)*max(math.sqrt(f.Chi2()/f.Ndf()), 1.0)
    he3tau.SetMarkerStyle(20)
    he3tau.GetXaxis().SetTitle('Cycle')
    he3tau.GetYaxis().SetTitle('Pinhole storage lifetime (s)')
    he3tau.SetTitle('')
    he3tau.Draw('AP')
    print('{0} +/- {1} (single exponential fit to rate in monitor detector during storage period)'.format(fit.Parameter(0), fit.ParError(0)))
  else:
    ex['pinholetau'] = 0.
    ex['pinholetauerr'] = 0.
  canvas.Print(pdf)

  # draw plot of Li6 background rate during each cycle
  ex['li6backgroundrate'], ex['li6backgroundrateerr'] = UCN.PrintBackgroundVsCycle(ex, pdf, 'li6')
  print('Li6 detector background rate: {0} +/- {1} 1/s'.format(ex['li6backgroundrate'], ex['li6backgroundrateerr']))
  beam = [numpy.mean(cur) for cur in ex['beamcurrent']], [numpy.std(cur) for cur in ex['beamcurrent']]
  # subtract background from Li6 counts during irradiation and normalize to beam current, draw plot for each cycle
  ex['li6irradiationrate'], ex['li6irradiationrateerr'] = UCN.SubtractBackgroundAndNormalizeRate(ex['li6irradiation'], ex['irradiationduration'], 'li6', beam[0], beam[1])
  UCN.PrintIrradiationBackgroundVsCycle(ex, pdf, 'li6')

  # report average monitor counts, range of beam current, range of He-II temperature
  monitoravg = numpy.average(ex['monitorcounts2'], None, [1./m for m in ex['monitorcounts2']], True)
  print('Monitor counts: {0} +/- {1}'.format(monitoravg[0], 1./math.sqrt(monitoravg[1])))
  print('Beam current from {0} to {1} uA'.format(min(min(c) for c in ex['beamcurrent']), max(max(c) for c in ex['beamcurrent'])))
  print('Temperatures from {0} to {1} K'.format(min(ex['mintemperature']), max(ex['maxtemperature'])))

  # draw Li6 channel histogram
  ex['channels'].Draw()
  canvas.Print(pdf + ')')