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 + ')')
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 + ')')